Skip to content

Commit 81d623d

Browse files
committed
feat(providers): create AIProvider interface and OpenAIProvider that implements it
1 parent a3510b4 commit 81d623d

File tree

11 files changed

+163
-104
lines changed

11 files changed

+163
-104
lines changed

src/main/kotlin/com/github/blarc/ai/commits/intellij/plugin/AICommitAction.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class AICommitAction : AnAction(), DumbAware {
5454
val openAIService = OpenAIService.instance
5555
runBlocking(Dispatchers.Main) {
5656
try {
57-
val generatedCommitMessage = openAIService.generateCommitMessage(prompt, 1)
57+
val generatedCommitMessage = openAIService.generateCommitMessage(prompt)
5858
commitMessage.setCommitMessage(generatedCommitMessage)
5959
AppSettings.instance.recordHit()
6060
} catch (e: Exception) {
Lines changed: 5 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,9 @@
11
package com.github.blarc.ai.commits.intellij.plugin
22

33
import com.aallam.openai.api.chat.*
4-
import com.aallam.openai.api.http.Timeout
5-
import com.aallam.openai.api.model.ModelId
6-
import com.aallam.openai.client.OpenAI
7-
import com.aallam.openai.client.OpenAIConfig
8-
import com.aallam.openai.client.OpenAIHost
9-
import com.aallam.openai.client.ProxyConfig
104
import com.github.blarc.ai.commits.intellij.plugin.settings.AppSettings
115
import com.intellij.openapi.application.ApplicationManager
126
import com.intellij.openapi.components.Service
13-
import kotlin.time.Duration.Companion.seconds
147

158

169
@Service(Service.Level.APP)
@@ -21,44 +14,16 @@ class OpenAIService {
2114
get() = ApplicationManager.getApplication().getService(OpenAIService::class.java)
2215
}
2316

24-
suspend fun generateCommitMessage(prompt: String, completions: Int): String {
25-
val openAI = OpenAI(AppSettings.instance.getOpenAIConfig())
26-
27-
val chatCompletionRequest = ChatCompletionRequest(
28-
ModelId(AppSettings.instance.openAIModelId),
29-
listOf(
30-
ChatMessage(
31-
role = ChatRole.User,
32-
content = prompt
33-
)
34-
),
35-
temperature = AppSettings.instance.openAITemperature.toDouble(),
36-
topP = 1.0,
37-
frequencyPenalty = 0.0,
38-
presencePenalty = 0.0,
39-
maxTokens = 200,
40-
n = completions
41-
)
42-
43-
val completion: ChatCompletion = openAI.chatCompletion(chatCompletionRequest)
44-
return completion.choices[0].message.content ?: "API returned an empty response."
17+
suspend fun generateCommitMessage(prompt: String): String {
18+
return AppSettings.instance.AIProvider.generateCommitMessage(prompt)
4519
}
4620

4721
suspend fun refreshOpenAIModelIds() {
48-
val openAI = OpenAI(AppSettings.instance.getOpenAIConfig())
49-
AppSettings.instance.openAIModelIds=openAI.models().map { it.id.id }
22+
AppSettings.instance.AIProvider.refreshModels()
5023
}
5124

5225
@Throws(Exception::class)
53-
suspend fun verifyOpenAIConfiguration(host: String, token: String, proxy: String?, socketTimeout: String){
54-
55-
val config = OpenAIConfig(
56-
token,
57-
host = host.takeIf { it.isNotBlank() }?.let { OpenAIHost(it) } ?: OpenAIHost.OpenAI,
58-
proxy = proxy?.takeIf { it.isNotBlank() }?.let { ProxyConfig.Http(it) },
59-
timeout = Timeout(socket = socketTimeout.toInt().seconds)
60-
)
61-
val openAI = OpenAI(config)
62-
openAI.models()
26+
suspend fun verifyOpenAIConfiguration(host: String, proxy: String?, timeout: String, token: String){
27+
AppSettings.instance.AIProvider.verifyConfiguration(host, proxy, timeout, token)
6328
}
6429
}

src/main/kotlin/com/github/blarc/ai/commits/intellij/plugin/settings/AppSettings.kt

Lines changed: 6 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,38 @@
11
package com.github.blarc.ai.commits.intellij.plugin.settings
22

3-
import com.aallam.openai.api.http.Timeout
4-
import com.aallam.openai.client.OpenAIConfig
5-
import com.aallam.openai.client.OpenAIHost
6-
import com.aallam.openai.client.ProxyConfig
73
import com.github.blarc.ai.commits.intellij.plugin.AICommitsUtils
84
import com.github.blarc.ai.commits.intellij.plugin.notifications.Notification
95
import com.github.blarc.ai.commits.intellij.plugin.notifications.sendNotification
10-
import com.github.blarc.ai.commits.intellij.plugin.settings.prompt.DefaultPrompts
11-
import com.intellij.credentialStore.CredentialAttributes
12-
import com.intellij.credentialStore.Credentials
13-
import com.intellij.ide.passwordSafe.PasswordSafe
6+
import com.github.blarc.ai.commits.intellij.plugin.settings.prompts.DefaultPrompts
7+
import com.github.blarc.ai.commits.intellij.plugin.settings.providers.OpenAIProvider
148
import com.intellij.openapi.application.ApplicationManager
159
import com.intellij.openapi.components.PersistentStateComponent
1610
import com.intellij.openapi.components.State
1711
import com.intellij.openapi.components.Storage
1812
import com.intellij.util.xmlb.Converter
1913
import com.intellij.util.xmlb.XmlSerializerUtil
2014
import com.intellij.util.xmlb.annotations.OptionTag
21-
import org.jetbrains.kotlin.idea.gradleTooling.get
2215
import java.util.*
23-
import kotlin.time.Duration.Companion.seconds
2416

2517
@State(
2618
name = AppSettings.SERVICE_NAME,
2719
storages = [Storage("AICommit.xml")]
2820
)
2921
class AppSettings : PersistentStateComponent<AppSettings> {
3022

31-
private val openAITokenTitle = "OpenAIToken"
3223
private var hits = 0
24+
var requestSupport = true
25+
var lastVersion: String? = null
3326

3427
@OptionTag(converter = LocaleConverter::class)
3528
var locale: Locale = Locale.ENGLISH
3629

37-
var requestSupport = true
38-
var lastVersion: String? = null
39-
var openAIHost = OpenAIHost.OpenAI.baseUrl
40-
var openAIHosts = mutableSetOf(OpenAIHost.OpenAI.baseUrl)
41-
var openAISocketTimeout = "30"
42-
var proxyUrl: String? = null
30+
var AIProvider = OpenAIProvider.instance
31+
var AIProviders = setOf(OpenAIProvider.instance)
4332

4433
var prompts = DefaultPrompts.toPromptsMap()
4534
var currentPrompt = prompts["basic"]!!
4635

47-
var openAIModelId = "gpt-3.5-turbo"
48-
var openAIModelIds = listOf("gpt-3.5-turbo", "gpt-4")
49-
var openAITemperature = "0.7"
50-
5136
var appExclusions: Set<String> = setOf()
5237

5338
companion object {
@@ -56,39 +41,6 @@ class AppSettings : PersistentStateComponent<AppSettings> {
5641
get() = ApplicationManager.getApplication().getService(AppSettings::class.java)
5742
}
5843

59-
fun saveOpenAIToken(token: String) {
60-
try {
61-
PasswordSafe.instance.setPassword(getCredentialAttributes(openAITokenTitle), token)
62-
} catch (e: Exception) {
63-
sendNotification(Notification.unableToSaveToken())
64-
}
65-
}
66-
67-
fun getOpenAIConfig(): OpenAIConfig {
68-
val token = getOpenAIToken() ?: throw Exception("OpenAI Token is not set.")
69-
return OpenAIConfig(
70-
token,
71-
host = openAIHost.takeIf { it.isNotBlank() }?.let { OpenAIHost(it) } ?: OpenAIHost.OpenAI,
72-
proxy = proxyUrl?.takeIf { it.isNotBlank() }?.let { ProxyConfig.Http(it) },
73-
timeout = Timeout(socket = openAISocketTimeout.toInt().seconds)
74-
)
75-
}
76-
77-
fun getOpenAIToken(): String? {
78-
val credentialAttributes = getCredentialAttributes(openAITokenTitle)
79-
val credentials: Credentials = PasswordSafe.instance.get(credentialAttributes) ?: return null
80-
return credentials.getPasswordAsString()
81-
}
82-
83-
private fun getCredentialAttributes(title: String): CredentialAttributes {
84-
return CredentialAttributes(
85-
title,
86-
null,
87-
this.javaClass,
88-
false
89-
)
90-
}
91-
9244
override fun getState() = this
9345

9446
override fun loadState(state: AppSettings) {

src/main/kotlin/com/github/blarc/ai/commits/intellij/plugin/settings/AppSettingsConfigurable.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ package com.github.blarc.ai.commits.intellij.plugin.settings
33
import com.aallam.openai.api.exception.OpenAIAPIException
44
import com.github.blarc.ai.commits.intellij.plugin.*
55
import com.github.blarc.ai.commits.intellij.plugin.AICommitsBundle.message
6-
import com.github.blarc.ai.commits.intellij.plugin.settings.prompt.Prompt
7-
import com.github.blarc.ai.commits.intellij.plugin.settings.prompt.PromptTable
6+
import com.github.blarc.ai.commits.intellij.plugin.settings.prompts.Prompt
7+
import com.github.blarc.ai.commits.intellij.plugin.settings.prompts.PromptTable
88
import com.intellij.icons.AllIcons
99
import com.intellij.openapi.options.BoundConfigurable
1010
import com.intellij.openapi.progress.runBackgroundableTask
@@ -65,7 +65,7 @@ class AppSettingsConfigurable : BoundConfigurable(message("settings.general.grou
6565
row {
6666
label(message("settings.openAISocketTimeout")).widthGroup("label")
6767
cell(socketTimeoutTextField)
68-
.bindText(AppSettings.instance::openAISocketTimeout)
68+
.bindIntText(AppSettings.instance::openAISocketTimeout)
6969
.applyToComponent { minimumWidth = 400 }
7070
.resizableColumn()
7171
.widthGroup("input")

src/main/kotlin/com/github/blarc/ai/commits/intellij/plugin/settings/AppSettingsListCellRenderer.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.github.blarc.ai.commits.intellij.plugin.settings
22

33
import com.aallam.openai.api.model.ModelId
4-
import com.github.blarc.ai.commits.intellij.plugin.settings.prompt.Prompt
4+
import com.github.blarc.ai.commits.intellij.plugin.settings.prompts.Prompt
55
import java.awt.Component
66
import java.util.*
77
import javax.swing.DefaultListCellRenderer
@@ -27,4 +27,4 @@ class AppSettingsListCellRenderer : DefaultListCellRenderer() {
2727
}
2828
return component
2929
}
30-
}
30+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.github.blarc.ai.commits.intellij.plugin.settings.prompt
1+
package com.github.blarc.ai.commits.intellij.plugin.settings.prompts
22

33
enum class DefaultPrompts(val title: String, val description: String, val content: String) {
44

src/main/kotlin/com/github/blarc/ai/commits/intellij/plugin/settings/prompt/Prompt.kt renamed to src/main/kotlin/com/github/blarc/ai/commits/intellij/plugin/settings/prompts/Prompt.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.github.blarc.ai.commits.intellij.plugin.settings.prompt
1+
package com.github.blarc.ai.commits.intellij.plugin.settings.prompts
22

33
data class Prompt(
44
var name: String = "",
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.github.blarc.ai.commits.intellij.plugin.settings.prompt
1+
package com.github.blarc.ai.commits.intellij.plugin.settings.prompts
22

33
import ai.grazie.utils.applyIf
44
import com.github.blarc.ai.commits.intellij.plugin.AICommitsBundle.message
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package com.github.blarc.ai.commits.intellij.plugin.settings.providers
2+
3+
import com.github.blarc.ai.commits.intellij.plugin.notifications.Notification
4+
import com.github.blarc.ai.commits.intellij.plugin.notifications.sendNotification
5+
import com.intellij.credentialStore.CredentialAttributes
6+
import com.intellij.credentialStore.Credentials
7+
import com.intellij.ide.passwordSafe.PasswordSafe
8+
9+
interface AIProvider {
10+
11+
var host: String
12+
var hosts: Set<String>
13+
var proxyUrl: String?
14+
var timeout: Int
15+
var modelId: String
16+
var modelIds: List<String>
17+
var temperature: String
18+
var token: String
19+
get() { return getToken() }
20+
set(token) { saveToken(token) }
21+
22+
fun displayName(): String
23+
24+
suspend fun generateCommitMessage(prompt: String): String
25+
26+
suspend fun refreshModels()
27+
28+
@Throws(Exception::class)
29+
suspend fun verifyConfiguration(
30+
newHost: String,
31+
newProxy: String?,
32+
newTimeout: String,
33+
newToken: String
34+
)
35+
36+
private fun saveToken(token: String) {
37+
try {
38+
PasswordSafe.instance.setPassword(getCredentialAttributes(displayName()), token)
39+
} catch (e: Exception) {
40+
sendNotification(Notification.unableToSaveToken())
41+
}
42+
}
43+
44+
private fun getToken(): String {
45+
val credentials: Credentials? = PasswordSafe.instance.get(getCredentialAttributes(displayName()))
46+
return credentials?.getPasswordAsString() ?: throw Exception("${displayName()} token is not set.")
47+
}
48+
49+
private fun getCredentialAttributes(title: String): CredentialAttributes {
50+
return CredentialAttributes(
51+
title,
52+
null,
53+
this.javaClass,
54+
false
55+
)
56+
}
57+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package com.github.blarc.ai.commits.intellij.plugin.settings.providers
2+
3+
import com.aallam.openai.api.chat.ChatCompletion
4+
import com.aallam.openai.api.chat.ChatCompletionRequest
5+
import com.aallam.openai.api.chat.ChatMessage
6+
import com.aallam.openai.api.chat.ChatRole
7+
import com.aallam.openai.api.http.Timeout
8+
import com.aallam.openai.api.model.ModelId
9+
import com.aallam.openai.client.OpenAI
10+
import com.aallam.openai.client.OpenAIConfig
11+
import com.aallam.openai.client.OpenAIHost
12+
import com.aallam.openai.client.ProxyConfig
13+
import kotlin.time.Duration.Companion.seconds
14+
15+
class OpenAIProvider(
16+
override var host: String = OpenAIHost.OpenAI.baseUrl,
17+
override var hosts: Set<String> = setOf(OpenAIHost.OpenAI.baseUrl),
18+
override var proxyUrl: String? = null,
19+
override var timeout: Int = 30,
20+
override var modelId: String = "gpt-3.5-turbo",
21+
override var modelIds: List<String> = listOf("gpt-3.5-turbo", "gpt-4"),
22+
override var temperature: String = "0.7"
23+
) : AIProvider {
24+
25+
companion object {
26+
val instance = OpenAIProvider()
27+
}
28+
29+
override fun displayName() = "OpenAI"
30+
31+
override suspend fun generateCommitMessage(
32+
prompt: String
33+
): String {
34+
35+
val openAI = OpenAI(openAIConfig())
36+
val chatCompletionRequest = ChatCompletionRequest(
37+
ModelId(modelId),
38+
listOf(
39+
ChatMessage(
40+
role = ChatRole.User,
41+
content = prompt
42+
)
43+
),
44+
temperature = temperature.toDouble(),
45+
topP = 1.0,
46+
frequencyPenalty = 0.0,
47+
presencePenalty = 0.0,
48+
maxTokens = 200,
49+
n = 1
50+
)
51+
52+
val completion: ChatCompletion = openAI.chatCompletion(chatCompletionRequest)
53+
return completion.choices[0].message.content ?: "API returned an empty response."
54+
}
55+
56+
override suspend fun refreshModels() {
57+
val openAI = OpenAI(openAIConfig())
58+
modelIds = openAI.models().map { it.id.id }
59+
}
60+
61+
@Throws(Exception::class)
62+
override suspend fun verifyConfiguration(
63+
newHost: String,
64+
newProxy: String?,
65+
newTimeout: String,
66+
newToken: String
67+
) {
68+
69+
val newConfig = OpenAIConfig(
70+
newToken,
71+
host = newHost.takeIf { it.isNotBlank() }?.let { OpenAIHost(it) } ?: OpenAIHost.OpenAI,
72+
proxy = newProxy?.takeIf { it.isNotBlank() }?.let { ProxyConfig.Http(it) },
73+
timeout = Timeout(socket = newTimeout.toInt().seconds)
74+
)
75+
val openAI = OpenAI(newConfig)
76+
openAI.models()
77+
}
78+
79+
private fun openAIConfig() = OpenAIConfig(
80+
token,
81+
host = host.takeIf { it.isNotBlank() }?.let { OpenAIHost(it) } ?: OpenAIHost.OpenAI,
82+
proxy = proxyUrl?.takeIf { it.isNotBlank() }?.let { ProxyConfig.Http(it) },
83+
timeout = Timeout(socket = timeout.seconds)
84+
)
85+
}

0 commit comments

Comments
 (0)