Skip to content

Commit 81e7665

Browse files
committed
feat(azure-open-ai): add Azure OpenAI
1 parent 9ef4e3a commit 81e7665

File tree

13 files changed

+246
-7
lines changed

13 files changed

+246
-7
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## [Unreleased]
44

5+
### Added
6+
7+
- Support for Azure OpenAI.
8+
59
## [2.4.1] - 2024-09-19
610

711
### Fixed

build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ dependencies {
107107
implementation("dev.langchain4j:langchain4j-qianfan")
108108
implementation("dev.langchain4j:langchain4j-vertex-ai-gemini")
109109
implementation("dev.langchain4j:langchain4j-anthropic")
110+
implementation("dev.langchain4j:langchain4j-azure-open-ai")
110111

111112
// tests
112113
testImplementation("org.junit.jupiter:junit-jupiter-params:5.11.0")

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ object Icons {
99
val QIANFAN = IconLoader.getIcon("/icons/qianfan.png", javaClass)
1010
val GEMINI = IconLoader.getIcon("/icons/gemini.png", javaClass)
1111
val ANTHROPIC = IconLoader.getIcon("/icons/anthropic.svg", javaClass)
12+
val AZURE_OPEN_AI = IconLoader.getIcon("/icons/azureOpenAi.svg", javaClass)
1213
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.github.blarc.ai.commits.intellij.plugin.notifications.Notification
66
import com.github.blarc.ai.commits.intellij.plugin.notifications.sendNotification
77
import com.github.blarc.ai.commits.intellij.plugin.settings.clients.LLMClientConfiguration
88
import com.github.blarc.ai.commits.intellij.plugin.settings.clients.anthropic.AnthropicClientConfiguration
9+
import com.github.blarc.ai.commits.intellij.plugin.settings.clients.azureOpenAi.AzureOpenAiClientConfiguration
910
import com.github.blarc.ai.commits.intellij.plugin.settings.clients.gemini.GeminiClientConfiguration
1011
import com.github.blarc.ai.commits.intellij.plugin.settings.clients.ollama.OllamaClientConfiguration
1112
import com.github.blarc.ai.commits.intellij.plugin.settings.clients.openAi.OpenAiClientConfiguration
@@ -56,6 +57,7 @@ class AppSettings2 : PersistentStateComponent<AppSettings2> {
5657
QianfanClientConfiguration::class,
5758
GeminiClientConfiguration::class,
5859
AnthropicClientConfiguration::class,
60+
AzureOpenAiClientConfiguration::class
5961
],
6062
style = XCollection.Style.v2
6163
)

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ abstract class LLMClientPanel(
3939
}
4040
}
4141

42-
open fun Panel.hostRow(property: MutableProperty<String?>) {
42+
open fun Panel.hostRow(property: MutableProperty<String?>, labelKey: String = "settings.llmClient.host") {
4343
row {
4444
label(message("settings.llmClient.host"))
4545
.widthGroup("label")
@@ -64,9 +64,9 @@ abstract class LLMClientPanel(
6464
}
6565
}
6666

67-
open fun Panel.modelIdRow() {
67+
open fun Panel.modelIdRow(labelKey: String = "settings.llmClient.modelId") {
6868
row {
69-
label(message("settings.llmClient.modelId"))
69+
label(message(labelKey))
7070
.widthGroup("label")
7171

7272
cell(modelComboBox)
@@ -75,12 +75,12 @@ abstract class LLMClientPanel(
7575
}
7676
.bindItem({ clientConfiguration.modelId }, {
7777
if (it != null) {
78+
clientConfiguration.addModelId(modelComboBox.item)
7879
clientConfiguration.modelId = it
7980
}
8081
})
8182
.align(Align.FILL)
8283
.resizableColumn()
83-
.onApply { clientConfiguration.addModelId(modelComboBox.item) }
8484

8585
clientConfiguration.getRefreshModelsFunction()?.let { f ->
8686
button(message("settings.refreshModels")) {

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.github.blarc.ai.commits.intellij.plugin.AICommitsBundle.message
44
import com.github.blarc.ai.commits.intellij.plugin.createColumn
55
import com.github.blarc.ai.commits.intellij.plugin.settings.AppSettings2
66
import com.github.blarc.ai.commits.intellij.plugin.settings.clients.anthropic.AnthropicClientConfiguration
7+
import com.github.blarc.ai.commits.intellij.plugin.settings.clients.azureOpenAi.AzureOpenAiClientConfiguration
78
import com.github.blarc.ai.commits.intellij.plugin.settings.clients.gemini.GeminiClientConfiguration
89
import com.github.blarc.ai.commits.intellij.plugin.settings.clients.ollama.OllamaClientConfiguration
910
import com.github.blarc.ai.commits.intellij.plugin.settings.clients.openAi.OpenAiClientConfiguration
@@ -145,7 +146,8 @@ class LLMClientTable {
145146
OllamaClientConfiguration(),
146147
QianfanClientConfiguration(),
147148
GeminiClientConfiguration(),
148-
AnthropicClientConfiguration()
149+
AnthropicClientConfiguration(),
150+
AzureOpenAiClientConfiguration()
149151
)
150152
} else {
151153
listOf(newLLMClientConfiguration)

src/main/kotlin/com/github/blarc/ai/commits/intellij/plugin/settings/clients/anthropic/AnthropicClientConfiguration.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ class AnthropicClientConfiguration : LLMClientConfiguration(
2222
var tokenIsStored: Boolean = false
2323
@Transient
2424
var token: String? = null
25-
@Transient
25+
@Attribute
2626
var version: String? = null
27-
@Transient
27+
@Attribute
2828
var beta: String? = null
2929
@Attribute
3030
var timeout: Int = 30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package com.github.blarc.ai.commits.intellij.plugin.settings.clients.azureOpenAi;
2+
3+
import com.github.blarc.ai.commits.intellij.plugin.Icons
4+
import com.github.blarc.ai.commits.intellij.plugin.settings.clients.LLMClientConfiguration
5+
import com.github.blarc.ai.commits.intellij.plugin.settings.clients.LLMClientSharedState
6+
import com.intellij.openapi.project.Project
7+
import com.intellij.openapi.vcs.ui.CommitMessage
8+
import com.intellij.util.xmlb.annotations.Attribute
9+
import com.intellij.util.xmlb.annotations.Transient
10+
import com.intellij.vcs.commit.AbstractCommitWorkflowHandler
11+
import javax.swing.Icon
12+
13+
class AzureOpenAiClientConfiguration : LLMClientConfiguration(
14+
CLIENT_NAME,
15+
"",
16+
"0.7"
17+
) {
18+
19+
@Attribute
20+
var host: String = ""
21+
@Attribute
22+
var timeout: Int = 30
23+
@Attribute
24+
var tokenIsStored: Boolean = false
25+
@Transient
26+
var token: String? = null
27+
28+
companion object {
29+
const val CLIENT_NAME = "Azure OpenAI"
30+
}
31+
32+
override fun getClientName(): String {
33+
return CLIENT_NAME
34+
}
35+
36+
override fun getClientIcon(): Icon {
37+
return Icons.AZURE_OPEN_AI
38+
}
39+
40+
override fun getSharedState(): LLMClientSharedState {
41+
return AzureOpenAiClientSharedState.getInstance()
42+
}
43+
44+
override fun generateCommitMessage(commitWorkflowHandler: AbstractCommitWorkflowHandler<*, *>, commitMessage: CommitMessage, project: Project) {
45+
return AzureOpenAiClientService.getInstance().generateCommitMessage(this, commitWorkflowHandler, commitMessage, project)
46+
}
47+
48+
// Model names are retrieved from Enum and do not need to be refreshed.
49+
override fun getRefreshModelsFunction() = null
50+
51+
override fun clone(): LLMClientConfiguration {
52+
val copy = AzureOpenAiClientConfiguration()
53+
copy.id = id
54+
copy.name = name
55+
copy.modelId = modelId
56+
copy.temperature = temperature
57+
copy.host = host
58+
copy.timeout = timeout
59+
copy.tokenIsStored = tokenIsStored
60+
return copy
61+
}
62+
63+
override fun panel() = AzureOpenAiClientPanel(this)
64+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.github.blarc.ai.commits.intellij.plugin.settings.clients.azureOpenAi;
2+
3+
import com.github.blarc.ai.commits.intellij.plugin.AICommitsBundle.message
4+
import com.github.blarc.ai.commits.intellij.plugin.emptyText
5+
import com.github.blarc.ai.commits.intellij.plugin.settings.clients.LLMClientPanel
6+
import com.intellij.ui.components.JBPasswordField
7+
import com.intellij.ui.dsl.builder.*
8+
9+
class AzureOpenAiClientPanel private constructor(
10+
private val clientConfiguration: AzureOpenAiClientConfiguration,
11+
val service: AzureOpenAiClientService
12+
) : LLMClientPanel(clientConfiguration) {
13+
14+
private val tokenPasswordField = JBPasswordField()
15+
16+
constructor(configuration: AzureOpenAiClientConfiguration) : this(configuration, AzureOpenAiClientService.getInstance())
17+
18+
override fun create() = panel {
19+
nameRow()
20+
hostRow(clientConfiguration::host.toNullableProperty(), "settings.azureOpenAi.host")
21+
timeoutRow(clientConfiguration::timeout)
22+
tokenRow()
23+
modelIdRow("settings.azureOpenAi.modelId")
24+
temperatureRow()
25+
verifyRow()
26+
27+
}
28+
29+
private fun Panel.tokenRow() {
30+
row {
31+
label(message("settings.azureOpenAi.token"))
32+
.widthGroup("label")
33+
cell(tokenPasswordField)
34+
.bindText(getter = { "" }, setter = {
35+
AzureOpenAiClientService.getInstance().saveToken(clientConfiguration, it)
36+
})
37+
.emptyText(if (clientConfiguration.tokenIsStored) message("settings.llmClient.token.stored") else message("settings.azureOpenAi.token.example"))
38+
.resizableColumn()
39+
.align(Align.FILL)
40+
// maxLineLength was eye-balled, but prevents the dialog getting wider
41+
.comment(message("settings.azureOpenAi.token.comment"), 50)
42+
}
43+
}
44+
45+
override fun verifyConfiguration() {
46+
// Configuration passed to panel is already a copy of the original or a new configuration
47+
clientConfiguration.modelId = modelComboBox.item
48+
clientConfiguration.temperature = temperatureTextField.text
49+
clientConfiguration.host = hostComboBox.item
50+
clientConfiguration.timeout = socketTimeoutTextField.text.toInt()
51+
clientConfiguration.token = String(tokenPasswordField.password)
52+
53+
service.verifyConfiguration(clientConfiguration, verifyLabel)
54+
}
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.github.blarc.ai.commits.intellij.plugin.settings.clients.azureOpenAi;
2+
3+
import com.github.blarc.ai.commits.intellij.plugin.AICommitsUtils.getCredentialAttributes
4+
import com.github.blarc.ai.commits.intellij.plugin.AICommitsUtils.retrieveToken
5+
import com.github.blarc.ai.commits.intellij.plugin.notifications.Notification
6+
import com.github.blarc.ai.commits.intellij.plugin.notifications.sendNotification
7+
import com.github.blarc.ai.commits.intellij.plugin.settings.clients.LLMClientService
8+
import com.intellij.ide.passwordSafe.PasswordSafe
9+
import com.intellij.openapi.components.Service
10+
import com.intellij.openapi.components.service
11+
import com.intellij.util.text.nullize
12+
import dev.langchain4j.model.azure.AzureOpenAiChatModel
13+
import dev.langchain4j.model.chat.ChatLanguageModel
14+
import kotlinx.coroutines.CoroutineScope
15+
import kotlinx.coroutines.Dispatchers
16+
import kotlinx.coroutines.launch
17+
import java.time.Duration
18+
19+
20+
@Service(Service.Level.APP)
21+
class AzureOpenAiClientService(private val cs: CoroutineScope) : LLMClientService<AzureOpenAiClientConfiguration>(cs) {
22+
23+
companion object {
24+
@JvmStatic
25+
fun getInstance(): AzureOpenAiClientService = service()
26+
}
27+
28+
override suspend fun buildChatModel(client: AzureOpenAiClientConfiguration): ChatLanguageModel {
29+
val token = client.token.nullize(true) ?: retrieveToken(client.id)?.toString(true)
30+
return AzureOpenAiChatModel.builder()
31+
.deploymentName(client.modelId)
32+
.temperature(client.temperature.toDouble())
33+
.timeout(Duration.ofSeconds(client.timeout.toLong()))
34+
.endpoint(client.host)
35+
.apiKey(token ?: "")
36+
.build()
37+
}
38+
39+
fun saveToken(client: AzureOpenAiClientConfiguration, token: String) {
40+
cs.launch(Dispatchers.Default) {
41+
try {
42+
PasswordSafe.instance.setPassword(getCredentialAttributes(client.id), token)
43+
client.tokenIsStored = true
44+
} catch (e: Exception) {
45+
sendNotification(Notification.unableToSaveToken(e.message))
46+
}
47+
}
48+
}
49+
}

0 commit comments

Comments
 (0)