Skip to content

Commit dac557b

Browse files
committed
feat(settings): add new LLMParam components
This commit adds new LLMParam components to the LLMSettingsComponent. The new components include a text field, a password field, and a combo box. These components allow users to input and select different settings for the LLM feature. The components are created using the Reactive delegate, which allows for easy updating of the component values.
1 parent a0f16e9 commit dac557b

File tree

11 files changed

+548
-16
lines changed

11 files changed

+548
-16
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package cc.unitmesh.devti.llms.palm2
2+
3+
import cc.unitmesh.devti.llms.LLMProvider
4+
import cc.unitmesh.devti.llms.custom.CustomRequest
5+
import cc.unitmesh.devti.settings.AutoDevSettingsState
6+
import com.intellij.openapi.components.Service
7+
import com.intellij.openapi.project.Project
8+
import kotlinx.serialization.Serializable
9+
import kotlinx.serialization.encodeToString
10+
import kotlinx.serialization.json.Json
11+
import okhttp3.MediaType.Companion.toMediaTypeOrNull
12+
import okhttp3.OkHttpClient
13+
import okhttp3.Request
14+
import okhttp3.RequestBody
15+
import okhttp3.RequestBody.Companion.toRequestBody
16+
17+
@Serializable
18+
data class PaLM2Request(val prompt: String, val input: String)
19+
20+
@Service(Service.Level.PROJECT)
21+
class PaLM2Provider(val project: Project) : LLMProvider {
22+
private val key: String
23+
get() {
24+
return AutoDevSettingsState.getInstance().openAiKey
25+
}
26+
override fun prompt(input: String): String {
27+
// val requestContent = Json.encodeToString(CustomRequest(input, input))
28+
// val body = requestContent.toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())
29+
// val builder = Request.Builder()
30+
// .url("https://generativelanguage.googleapis.com/v1beta2/models/text-bison-001:generateText?key=$key")
31+
// .post(body)
32+
// OkHttpClient().newCall(builder.build()).execute().use { response ->
33+
// if (!response.isSuccessful) throw Exception("Unexpected code $response")
34+
// return response.body!!.string()
35+
// }
36+
TODO()
37+
}
38+
}

src/main/kotlin/cc/unitmesh/devti/llms/xianghuo/XingHuoProvider.kt

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import javax.crypto.spec.SecretKeySpec
2525
class XingHuoProvider(val project: Project) : LLMProvider {
2626
private val autoDevSettingsState = AutoDevSettingsState.getInstance()
2727
private val secrectKey: String
28-
get() = autoDevSettingsState.xingHuoSecrectKey
28+
get() = autoDevSettingsState.xingHuoApiSecrect
2929

3030

3131
private val appid: String
@@ -75,7 +75,6 @@ class XingHuoProvider(val project: Project) : LLMProvider {
7575
private var sockedOpen = false
7676
override fun onOpen(webSocket: WebSocket, response: Response) {
7777
webSocket.onSocketOpend()
78-
producerScope.trySend("WebSocket connected\n")
7978
sockedOpen = true
8079
}
8180

@@ -97,7 +96,7 @@ class XingHuoProvider(val project: Project) : LLMProvider {
9796
}
9897

9998
override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
100-
producerScope.close()
99+
webSocket.onSocketClosed()
101100
}
102101

103102
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
@@ -119,10 +118,8 @@ class XingHuoProvider(val project: Project) : LLMProvider {
119118
|GET /v1.1/chat HTTP/1.1
120119
""".trimMargin()
121120
val signature = hmacsha256.doFinal(header.toByteArray()).encodeBase64()
122-
System.err.println(signature)
123121
val authorization =
124122
"""api_key="$apikey", algorithm="hmac-sha256", headers="host date request-line", signature="$signature""""
125-
System.err.println(authorization)
126123

127124
val params = mapOf(
128125
"authorization" to authorization.toByteArray().encodeBase64(),
@@ -134,7 +131,6 @@ class XingHuoProvider(val project: Project) : LLMProvider {
134131
urlBuilder.addQueryParameter(it.key, it.value)
135132
}
136133
val url = urlBuilder.build().toString().replace("https://", "wss://")
137-
println(url)
138134
return Request.Builder().url(url).build()
139135
}
140136

src/main/kotlin/cc/unitmesh/devti/settings/AppSettingsComponent.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ class AppSettingsComponent(settings: AutoDevSettingsState) {
242242
settings.maxTokenLength != getMaxTokenLength() ||
243243
settings.xingHuoAppId != getXingHuoAppId() ||
244244
settings.xingHuoApiKey != getXingHuoApiKey() ||
245-
settings.xingHuoSecrectKey != getXingHuoAppSecret()
245+
settings.xingHuoApiSecrect != getXingHuoAppSecret()
246246

247247
}
248248

@@ -264,7 +264,7 @@ class AppSettingsComponent(settings: AutoDevSettingsState) {
264264
maxTokenLength = getMaxTokenLength()
265265
xingHuoAppId = getXingHuoAppId()
266266
xingHuoApiKey = getXingHuoApiKey()
267-
xingHuoSecrectKey = getXingHuoAppSecret()
267+
xingHuoApiSecrect = getXingHuoAppSecret()
268268
}
269269
}
270270

@@ -286,7 +286,7 @@ class AppSettingsComponent(settings: AutoDevSettingsState) {
286286
setMaxTokenLength(it.maxTokenLength)
287287
setXingHuoAppId(it.xingHuoAppId)
288288
setXingHuoAppKey(it.xingHuoApiKey)
289-
setXingHuoApiSecret(it.xingHuoSecrectKey)
289+
setXingHuoApiSecret(it.xingHuoApiSecrect)
290290
}
291291
}
292292
}

src/main/kotlin/cc/unitmesh/devti/settings/AutoDevSettingsConfigurable.kt

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,19 @@ import org.jetbrains.annotations.Nullable
66
import javax.swing.JComponent
77

88
class AutoDevSettingsConfigurable : Configurable {
9-
private lateinit var component: AppSettingsComponent
9+
private val component: LLMSettingComponent = LLMSettingComponent(AutoDevSettingsState.getInstance())
1010

1111
@Nls(capitalization = Nls.Capitalization.Title)
1212
override fun getDisplayName(): String {
1313
return "AutoDev"
1414
}
1515

16-
override fun getPreferredFocusedComponent(): JComponent {
17-
return component.preferredFocusedComponent
16+
override fun getPreferredFocusedComponent(): JComponent? {
17+
return null
1818
}
1919

2020
@Nullable
2121
override fun createComponent(): JComponent {
22-
component = AppSettingsComponent(AutoDevSettingsState.getInstance())
2322
return component.panel
2423
}
2524

@@ -29,7 +28,7 @@ class AutoDevSettingsConfigurable : Configurable {
2928
}
3029

3130
override fun apply() {
32-
component.exportSettings(target = AutoDevSettingsState.getInstance())
31+
component.exportSettings(AutoDevSettingsState.getInstance())
3332
}
3433

3534
override fun reset() {

src/main/kotlin/cc/unitmesh/devti/settings/AutoDevSettingsState.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class AutoDevSettingsState : PersistentStateComponent<AutoDevSettingsState> {
1919
var customPrompts = ""
2020

2121
var xingHuoAppId = ""
22-
var xingHuoSecrectKey = ""
22+
var xingHuoApiSecrect = ""
2323
var xingHuoApiKey = ""
2424

2525
/**

src/main/kotlin/cc/unitmesh/devti/settings/Constants.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ package cc.unitmesh.devti.settings
22

33
val OPENAI_MODEL = arrayOf("gpt-3.5-turbo","gpt-3.5-turbo-16k", "gpt-4")
44
val AI_ENGINES = arrayOf("OpenAI", "Custom", "Azure", "XingHuo")
5+
6+
enum class AIEngines {
7+
OpenAI, Custom, Azure, XingHuo
8+
}
9+
510
val DEFAULT_AI_ENGINE = AI_ENGINES[0]
611

712
val HUMAN_LANGUAGES = arrayOf("English", "中文")
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
package cc.unitmesh.devti.settings
2+
3+
import cc.unitmesh.devti.AutoDevBundle
4+
import com.intellij.openapi.ui.ComboBox
5+
import com.intellij.ui.components.JBPasswordField
6+
import com.intellij.ui.components.JBTextField
7+
import java.awt.event.ItemEvent
8+
import kotlin.properties.PropertyDelegateProvider
9+
import kotlin.properties.ReadOnlyProperty
10+
import kotlin.reflect.KProperty
11+
12+
13+
/**
14+
* A simple version of reactive delegate
15+
*
16+
* ```kotlin
17+
* var s by Reactive("hello") {
18+
* println("s changed to $it")
19+
* }
20+
* s = "world" // println "s changed to world"
21+
* ```
22+
*/
23+
class Reactive<V>(var value: V, val onChange: (V) -> Unit)
24+
25+
operator fun <V> Reactive<V>.setValue(thisRef: Any?, property: KProperty<*>, value: V) {
26+
if (this.value == value) return
27+
this.value = value
28+
onChange(value)
29+
}
30+
31+
operator fun <V> Reactive<V>.getValue(thisRef: Any?, property: KProperty<*>): V {
32+
return this.value
33+
}
34+
35+
fun ReactiveTextField(param: LLMParam, initBlock: JBTextField.(LLMParam) -> Unit = {}): JBTextField {
36+
val component = JBTextField(param.value)
37+
val reactive by Reactive(param) {
38+
component.text = param.value
39+
}
40+
41+
component.initBlock(reactive)
42+
43+
component.document.addUndoableEditListener {
44+
param.value = component.text
45+
}
46+
return component
47+
}
48+
49+
fun ReactivePasswordField(param: LLMParam, initBlock: JBPasswordField.(LLMParam) -> Unit = {}): JBPasswordField {
50+
val component = JBPasswordField().apply {
51+
text = param.value
52+
}
53+
val reactive = Reactive(param) {
54+
component.text = it.value
55+
}
56+
57+
component.initBlock(reactive.value)
58+
component.document.addUndoableEditListener {
59+
if (component.text == param.value) return@addUndoableEditListener
60+
reactive.value.value = component.text
61+
}
62+
63+
return component
64+
}
65+
66+
fun ReactiveComboBox(param: LLMParam, initBlock: ComboBox<String>.(LLMParam) -> Unit = {}): ComboBox<String> {
67+
val component = ComboBox(param.items.toTypedArray()).apply {
68+
selectedItem = param.value
69+
}
70+
val reactive by Reactive(param) {
71+
component.selectedItem = it.value
72+
}
73+
74+
component.initBlock(reactive)
75+
component.addItemListener {
76+
if (it.stateChange == ItemEvent.SELECTED) {
77+
println("item changed to ${component.selectedItem}")
78+
reactive.value = component.selectedItem as String
79+
}
80+
}
81+
return component
82+
}
83+
84+
85+
/**
86+
*
87+
* A LLMParam is a setting for the LLMSettingsComponent.
88+
*
89+
* Adding a LLM Param:
90+
*
91+
* - Step 1. add label to [AutoDevBundle] with key `settings.<yourName>`
92+
* - Step 2. define a variable named yourName. in this example, it's `openAIKey`
93+
* in the `creating` block, you can use one of the factory functions:
94+
* [LLMParam.Editable], [LLMParam.Password], [LLMParam.ComboBox]
95+
* ```kotlin
96+
* val openAIKey by LLMParam.creating {
97+
* Editable(service.getOpenAIKey())
98+
* }
99+
* ```
100+
*
101+
*
102+
* @param label the label of the setting, will automatically get from bundle resource [AutoDevBundle], named by `settings.${property.name}`
103+
* @param value the value of the setting, default from bundle resource [AutoDevBundle], named `settings.${property.name}.default`
104+
* @param type the type of the setting, default is [ParamType.Text], can be [ParamType.Password] or [ParamType.ComboBox]
105+
* @param isEditable whether the setting is editable, if is not editable, user can't change the value on UI
106+
* @param items if [type] is [ParamType.ComboBox], this field will be used to set the items of the combo box
107+
*/
108+
class LLMParam(
109+
value: String = "",
110+
var label: String = "",
111+
val isEditable: Boolean = true,
112+
val type: ParamType = ParamType.Text,
113+
var items: List<String> = emptyList(),
114+
var visible: Boolean = true,
115+
) {
116+
enum class ParamType {
117+
Text, Password, ComboBox, Separator
118+
}
119+
120+
121+
private var onChange: (LLMParam.(String) -> Unit)? = null
122+
123+
124+
var value: String = value
125+
set(newValue) {
126+
val changed = field != newValue
127+
field = newValue
128+
if (changed) {
129+
println("value changed $newValue $value")
130+
onChange?.invoke(this, newValue)
131+
}
132+
}
133+
134+
companion object {
135+
private val bundle = AutoDevBundle
136+
137+
/**
138+
* @param block a block to create a LLMParam, will be called only once
139+
*
140+
* will set [label] and [value] to the value defined in config file [AutoDevBundle] if they are empty
141+
*/
142+
fun creating(onChange: LLMParam.(String) -> Unit = {}, block: Companion.() -> LLMParam) =
143+
PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, LLMParam>> { _, _ ->
144+
object : ReadOnlyProperty<Any?, LLMParam> {
145+
private var param: LLMParam? = null
146+
override fun getValue(thisRef: Any?, property: KProperty<*>): LLMParam {
147+
return param ?: this@Companion.block().apply {
148+
if (label.isEmpty()) {
149+
val key = "settings.${property.name}"
150+
label = runCatching { bundle.getMessage(key) }.getOrElse {
151+
"WARNNING-KEY:add key: settings.$key to AutoDevBundle.properties"
152+
}
153+
}
154+
155+
this.onChange = onChange
156+
param = this
157+
}
158+
}
159+
}
160+
}
161+
162+
// factory functions to create LLMParam
163+
fun Editable(value: String = "") = LLMParam(value = value)
164+
fun Password(password: String = "") = LLMParam(value = password, type = ParamType.Password)
165+
166+
fun ComboBox(value: String, items: List<String>) =
167+
LLMParam(value = value, type = ParamType.ComboBox, items = items.toList())
168+
169+
fun Separator() = LLMParam(type = ParamType.Separator)
170+
}
171+
}
172+

0 commit comments

Comments
 (0)