From 5b0c18c3f5f0b3a2d44bee25047a2ea987d8eb32 Mon Sep 17 00:00:00 2001 From: qianlifeng Date: Mon, 24 Jun 2024 20:26:08 +0800 Subject: [PATCH] Improve AI Commands plugin --- Wox.UI.Flutter/wox/lib/api/wox_api.dart | 5 + .../wox_setting_plugin_select_view.dart | 1 - .../wox_setting_plugin_table_update_view.dart | 201 +++++++++++------- .../plugin/wox_setting_plugin_table_view.dart | 19 +- .../setting/wox_plugin_setting_select.dart | 2 + .../setting/wox_plugin_setting_table.dart | 1 + Wox.UI.Flutter/wox/lib/entity/wox_ai.dart | 18 ++ .../setting/views/wox_setting_ai_view.dart | 9 +- .../views/wox_setting_plugin_view.dart | 7 + .../setting/wox_setting_controller.dart | 4 +- .../wox/lib/utils/entity_factory.dart | 3 + Wox/ai/instance.go | 1 - Wox/plugin/system/ai_command.go | 85 ++------ Wox/plugin/system/menus_darwin.go | 22 +- Wox/setting/definition/definition_table.go | 13 +- Wox/ui/http.go | 13 +- Wox/ui/router.go | 30 +++ 17 files changed, 253 insertions(+), 181 deletions(-) create mode 100644 Wox.UI.Flutter/wox/lib/entity/wox_ai.dart delete mode 100644 Wox/ai/instance.go diff --git a/Wox.UI.Flutter/wox/lib/api/wox_api.dart b/Wox.UI.Flutter/wox/lib/api/wox_api.dart index fc39fb0c8..d2fc886f0 100644 --- a/Wox.UI.Flutter/wox/lib/api/wox_api.dart +++ b/Wox.UI.Flutter/wox/lib/api/wox_api.dart @@ -1,5 +1,6 @@ import 'dart:core'; +import 'package:wox/entity/wox_ai.dart'; import 'package:wox/entity/wox_image.dart'; import 'package:wox/entity/wox_plugin.dart'; import 'package:wox/entity/wox_query.dart'; @@ -104,4 +105,8 @@ class WoxApi { "arguments": arguments, }); } + + Future> findAIModels() async { + return await WoxHttpUtil.instance.postData("/ai/models", null); + } } diff --git a/Wox.UI.Flutter/wox/lib/components/plugin/wox_setting_plugin_select_view.dart b/Wox.UI.Flutter/wox/lib/components/plugin/wox_setting_plugin_select_view.dart index 6a68c1d82..b4595ea03 100644 --- a/Wox.UI.Flutter/wox/lib/components/plugin/wox_setting_plugin_select_view.dart +++ b/Wox.UI.Flutter/wox/lib/components/plugin/wox_setting_plugin_select_view.dart @@ -1,7 +1,6 @@ import 'package:fluent_ui/fluent_ui.dart'; import 'package:wox/components/wox_tooltip_view.dart'; import 'package:wox/entity/setting/wox_plugin_setting_select.dart'; -import 'package:wox/entity/setting/wox_plugin_setting_textbox.dart'; import 'wox_setting_plugin_item_view.dart'; diff --git a/Wox.UI.Flutter/wox/lib/components/plugin/wox_setting_plugin_table_update_view.dart b/Wox.UI.Flutter/wox/lib/components/plugin/wox_setting_plugin_table_update_view.dart index de6ea503d..52f964eb2 100644 --- a/Wox.UI.Flutter/wox/lib/components/plugin/wox_setting_plugin_table_update_view.dart +++ b/Wox.UI.Flutter/wox/lib/components/plugin/wox_setting_plugin_table_update_view.dart @@ -1,7 +1,10 @@ +import 'dart:convert'; + import 'package:fluent_ui/fluent_ui.dart'; -import 'package:fluent_ui/l10n/generated/fluent_localizations_en.dart'; import 'package:uuid/v4.dart'; +import 'package:wox/api/wox_api.dart'; import 'package:wox/components/wox_hotkey_recorder_view.dart'; +import 'package:wox/entity/setting/wox_plugin_setting_select.dart'; import 'package:wox/entity/setting/wox_plugin_setting_table.dart'; import 'package:wox/entity/wox_hotkey.dart'; import 'package:wox/utils/picker.dart'; @@ -111,6 +114,13 @@ class _WoxSettingPluginTableUpdateState extends State 0 ? max : 100; } + Future> getSelectionAIModelOptions() async { + final models = await WoxApi.instance.findAIModels(); + return models.map((e) { + return PluginSettingValueSelectOption(value: jsonEncode(e), label: "${e.provider} - ${e.name}"); + }).toList(); + } + Widget buildColumn(PluginSettingValueTableColumn column) { switch (column.type) { case PluginSettingValueType.pluginSettingValueTableColumnTypeText: @@ -201,6 +211,7 @@ class _WoxSettingPluginTableUpdateState extends State( + value: getValue(column.key), + onChanged: (value) { + updateValue(column.key, value); + setState(() {}); + }, + items: snapshot.data?.map((e) { + return ComboBoxItem( + value: e.value, + child: Text(e.label), + ); + }).toList(), + ); + } else { + return const SizedBox(); + } + }, + ), + ); case PluginSettingValueType.pluginSettingValueTableColumnTypeWoxImage: return Text("wox image..."); case PluginSettingValueType.pluginSettingValueTableColumnTypeTextList: @@ -321,100 +357,103 @@ class _WoxSettingPluginTableUpdateState extends State Navigator.pop(context), ), - ]), - ), - actions: [ - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Button( - child: const Text('Cancel'), - onPressed: () => Navigator.pop(context), - ), - const SizedBox(width: 16), - FilledButton( - child: const Text('Confirm'), - onPressed: () { - // validate - for (var column in columns) { - if (column.validators.isNotEmpty) { - for (var element in column.validators) { - var errMsg = element.validator.validate(getValue(column.key)); - if (errMsg != "") { - fieldValidationErrors[column.key] = errMsg; - } else { - fieldValidationErrors.remove(column.key); + const SizedBox(width: 16), + FilledButton( + child: const Text('Confirm'), + onPressed: () { + // validate + for (var column in columns) { + if (column.validators.isNotEmpty) { + for (var element in column.validators) { + var errMsg = element.validator.validate(getValue(column.key)); + if (errMsg != "") { + fieldValidationErrors[column.key] = errMsg; + } else { + fieldValidationErrors.remove(column.key); + } } } } - } - if (fieldValidationErrors.isNotEmpty) { - setState(() {}); - return; - } + if (fieldValidationErrors.isNotEmpty) { + setState(() {}); + return; + } - // remove empty text list - for (var column in columns) { - if (column.type == PluginSettingValueType.pluginSettingValueTableColumnTypeTextList) { - var columnValues = getValue(column.key); - if (columnValues is List) { - columnValues.removeWhere((element) => element == ""); + // remove empty text list + for (var column in columns) { + if (column.type == PluginSettingValueType.pluginSettingValueTableColumnTypeTextList) { + var columnValues = getValue(column.key); + if (columnValues is List) { + columnValues.removeWhere((element) => element == ""); + } } } - } - widget.onUpdate(widget.item.key, values); + widget.onUpdate(widget.item.key, values); - Navigator.pop(context); - }, - ), - ], - ) - ], + Navigator.pop(context); + }, + ), + ], + ) + ], + ), ); } } diff --git a/Wox.UI.Flutter/wox/lib/components/plugin/wox_setting_plugin_table_view.dart b/Wox.UI.Flutter/wox/lib/components/plugin/wox_setting_plugin_table_view.dart index 17f736f46..56f02cfc2 100644 --- a/Wox.UI.Flutter/wox/lib/components/plugin/wox_setting_plugin_table_view.dart +++ b/Wox.UI.Flutter/wox/lib/components/plugin/wox_setting_plugin_table_view.dart @@ -7,6 +7,7 @@ import 'package:wox/components/wox_image_view.dart'; import 'package:wox/components/wox_tooltip_view.dart'; import 'package:wox/entity/setting/wox_plugin_setting_select.dart'; import 'package:wox/entity/setting/wox_plugin_setting_table.dart'; +import 'package:wox/entity/wox_ai.dart'; import 'package:wox/entity/wox_image.dart'; import 'package:flutter/material.dart' as material; @@ -16,12 +17,12 @@ import 'wox_setting_plugin_table_update_view.dart'; class WoxSettingPluginTable extends WoxSettingPluginItem { final PluginSettingValueTable item; static const String rowUniqueIdKey = "wox_table_row_id"; - final tableWidth = 650.0; + final double tableWidth; final operationWidth = 75.0; final columnSpacing = 10.0; final columnTooltipWidth = 20.0; - const WoxSettingPluginTable({super.key, required this.item, required super.value, required super.onUpdate}); + const WoxSettingPluginTable({super.key, required this.item, required super.value, required super.onUpdate, this.tableWidth = 650.0}); double calculateColumnWidthForZeroWidth(PluginSettingValueTableColumn column) { // if there are multiple columns which have width set to 0, we will set the max width to 100 for each column @@ -186,6 +187,20 @@ class WoxSettingPluginTable extends WoxSettingPluginItem { ), ); } + if (column.type == PluginSettingValueType.pluginSettingValueTableColumnTypeSelectAIModel) { + var model = AIModel.fromJson(json.decode(value)); + return columnWidth( + column: column, + isHeader: false, + isOperation: false, + child: Text( + "${model.provider} - ${model.name}", + style: const TextStyle( + overflow: TextOverflow.ellipsis, + ), + ), + ); + } return Text("Unknown column type: ${column.type}"); } diff --git a/Wox.UI.Flutter/wox/lib/entity/setting/wox_plugin_setting_select.dart b/Wox.UI.Flutter/wox/lib/entity/setting/wox_plugin_setting_select.dart index aaa52546d..bb5ed1ca5 100644 --- a/Wox.UI.Flutter/wox/lib/entity/setting/wox_plugin_setting_select.dart +++ b/Wox.UI.Flutter/wox/lib/entity/setting/wox_plugin_setting_select.dart @@ -42,6 +42,8 @@ class PluginSettingValueSelectOption { late String label; late String value; + PluginSettingValueSelectOption({required this.label, required this.value}); + PluginSettingValueSelectOption.fromJson(Map json) { label = json['Label']; value = json['Value']; diff --git a/Wox.UI.Flutter/wox/lib/entity/setting/wox_plugin_setting_table.dart b/Wox.UI.Flutter/wox/lib/entity/setting/wox_plugin_setting_table.dart index 51a2f3e04..b9fbf3543 100644 --- a/Wox.UI.Flutter/wox/lib/entity/setting/wox_plugin_setting_table.dart +++ b/Wox.UI.Flutter/wox/lib/entity/setting/wox_plugin_setting_table.dart @@ -40,6 +40,7 @@ class PluginSettingValueType { static const pluginSettingValueTableColumnTypeCheckbox = "checkbox"; static const pluginSettingValueTableColumnTypeDirPath = "dirPath"; static const pluginSettingValueTableColumnTypeSelect = "select"; + static const pluginSettingValueTableColumnTypeSelectAIModel = "selectAIModel"; static const pluginSettingValueTableColumnTypeWoxImage = "woxImage"; static const pluginSettingValueTableColumnTypeHotkey = "hotkey"; } diff --git a/Wox.UI.Flutter/wox/lib/entity/wox_ai.dart b/Wox.UI.Flutter/wox/lib/entity/wox_ai.dart new file mode 100644 index 000000000..ce8cc968b --- /dev/null +++ b/Wox.UI.Flutter/wox/lib/entity/wox_ai.dart @@ -0,0 +1,18 @@ +class AIModel { + late String name; + late String provider; + + AIModel({required this.name, required this.provider}); + + AIModel.fromJson(Map json) { + name = json['Name']; + provider = json['Provider']; + } + + Map toJson() { + final Map data = {}; + data['Name'] = name; + data['Provider'] = provider; + return data; + } +} diff --git a/Wox.UI.Flutter/wox/lib/modules/setting/views/wox_setting_ai_view.dart b/Wox.UI.Flutter/wox/lib/modules/setting/views/wox_setting_ai_view.dart index da3f14222..133f8fae7 100644 --- a/Wox.UI.Flutter/wox/lib/modules/setting/views/wox_setting_ai_view.dart +++ b/Wox.UI.Flutter/wox/lib/modules/setting/views/wox_setting_ai_view.dart @@ -68,6 +68,7 @@ class WoxSettingAIView extends GetView { child: Obx(() { return WoxSettingPluginTable( value: json.encode(controller.woxSetting.value.aiProviders), + tableWidth: 750, item: PluginSettingValueTable.fromJson({ "Key": "AIProviders", "Columns": [ @@ -98,7 +99,13 @@ class WoxSettingAIView extends GetView { {"Type": "not_empty"} ], }, - {"Key": "Host", "Label": "Host", "Tooltip": "The host of the AI provider.", "Width": 60, "Type": "text"} + { + "Key": "Host", + "Label": "Host", + "Tooltip": "The host of the AI provider.", + "Width": 200, + "Type": "text", + } ], "SortColumnKey": "Name" }), diff --git a/Wox.UI.Flutter/wox/lib/modules/setting/views/wox_setting_plugin_view.dart b/Wox.UI.Flutter/wox/lib/modules/setting/views/wox_setting_plugin_view.dart index 091d1c303..f9e117bda 100644 --- a/Wox.UI.Flutter/wox/lib/modules/setting/views/wox_setting_plugin_view.dart +++ b/Wox.UI.Flutter/wox/lib/modules/setting/views/wox_setting_plugin_view.dart @@ -492,6 +492,13 @@ class WoxSettingPluginView extends GetView { 'E.g. you are using google chrome to view webpages, you activate Wox and this plugin will get the active window name as "Google Chrome"', ); } + if (e == "requireActiveWindowPid") { + return privacyItem( + material.Icons.window, + 'Active window process id', + 'E.g. you are using google chrome to view webpages, you activate Wox and this plugin will get the active window process id as "1234"', + ); + } if (e == "requireActiveBrowserUrl") { return privacyItem( material.Icons.web_sharp, diff --git a/Wox.UI.Flutter/wox/lib/modules/setting/wox_setting_controller.dart b/Wox.UI.Flutter/wox/lib/modules/setting/wox_setting_controller.dart index 37372b1ce..b910ad878 100644 --- a/Wox.UI.Flutter/wox/lib/modules/setting/wox_setting_controller.dart +++ b/Wox.UI.Flutter/wox/lib/modules/setting/wox_setting_controller.dart @@ -72,7 +72,7 @@ class WoxSettingController extends GetxController { } Future switchToPluginList(bool isStorePlugin) async { - activePaneIndex.value = isStorePlugin ? 2 : 3; + activePaneIndex.value = isStorePlugin ? 3 : 4; isStorePluginList.value = isStorePlugin; activePluginDetail.value = PluginDetail.empty(); filterPluginKeywordController.text = ""; @@ -203,7 +203,7 @@ class WoxSettingController extends GetxController { } Future switchToThemeList(bool isStoreTheme) async { - activePaneIndex.value = isStoreTheme ? 5 : 6; + activePaneIndex.value = isStoreTheme ? 6 : 7; isStoreThemeList.value = isStoreTheme; activeTheme.value = WoxSettingTheme.empty(); await refreshThemeList(); diff --git a/Wox.UI.Flutter/wox/lib/utils/entity_factory.dart b/Wox.UI.Flutter/wox/lib/utils/entity_factory.dart index 79655fdc5..0acb9bbff 100644 --- a/Wox.UI.Flutter/wox/lib/utils/entity_factory.dart +++ b/Wox.UI.Flutter/wox/lib/utils/entity_factory.dart @@ -1,3 +1,4 @@ +import 'package:wox/entity/wox_ai.dart'; import 'package:wox/entity/wox_image.dart'; import 'package:wox/entity/wox_plugin.dart'; import 'package:wox/entity/wox_preview.dart'; @@ -19,6 +20,8 @@ class EntityFactory { return (json as List).map((e) => PluginDetail.fromJson(e)).toList() as T; } else if (T.toString() == "List") { return (json as List).map((e) => WoxSettingTheme.fromJson(e)).toList() as T; + } else if (T.toString() == "List") { + return (json as List).map((e) => AIModel.fromJson(e)).toList() as T; } else { return json as T; } diff --git a/Wox/ai/instance.go b/Wox/ai/instance.go deleted file mode 100644 index 3831891f0..000000000 --- a/Wox/ai/instance.go +++ /dev/null @@ -1 +0,0 @@ -package ai diff --git a/Wox/plugin/system/ai_command.go b/Wox/plugin/system/ai_command.go index d05ebcb33..0911767c9 100644 --- a/Wox/plugin/system/ai_command.go +++ b/Wox/plugin/system/ai_command.go @@ -21,18 +21,19 @@ var aiCommandIcon = plugin.NewWoxImageBase64(`data:image/png;base64,iVBORw0KGgoA var aiCommandLabelWidth = 60 type commandSetting struct { - Name string `json:"name"` - Command string `json:"command"` - Model string `json:"model"` - Provider string `json:"provider"` - Prompt string `json:"prompt"` + Name string `json:"name"` + Command string `json:"command"` + Model string `json:"model"` + Prompt string `json:"prompt"` } -func (c *commandSetting) AIModel() ai.Model { - return ai.Model{ - Name: c.Model, - Provider: ai.ProviderName(c.Provider), +func (c *commandSetting) AIModel() (model ai.Model) { + err := json.Unmarshal([]byte(c.Model), &model) + if err != nil { + return ai.Model{} } + + return model } func init() { @@ -64,62 +65,6 @@ func (c *Plugin) GetMetadata() plugin.Metadata { "Linux", }, SettingDefinitions: definition.PluginSettingDefinitions{ - { - Type: definition.PluginSettingDefinitionTypeSelect, - Value: &definition.PluginSettingValueSelect{ - Key: "provider", - Label: "Provider", - Tooltip: "The LLM service provider", - DefaultValue: string(ai.ProviderNameOpenAI), - Options: []definition.PluginSettingValueSelectOption{ - { - Label: "OpenAI", - Value: string(ai.ProviderNameOpenAI), - }, - { - Label: "Google", - Value: string(ai.ProviderNameGoogle), - }, - { - Label: "Ollama", - Value: string(ai.ProviderNameOllama), - }, - { - Label: "Groq", - Value: string(ai.ProviderNameGroq), - }, - }, - Style: definition.PluginSettingValueStyle{ - LabelWidth: aiCommandLabelWidth, - }, - }, - }, - { - Type: definition.PluginSettingDefinitionTypeNewLine, - Value: &definition.PluginSettingValueNewLine{}, - }, - { - Type: definition.PluginSettingDefinitionTypeDynamic, - Value: &definition.PluginSettingValueDynamic{ - Key: "dynamic_models", - }, - }, - { - Type: definition.PluginSettingDefinitionTypeNewLine, - Value: &definition.PluginSettingValueNewLine{}, - }, - { - Type: definition.PluginSettingDefinitionTypeDynamic, - Value: &definition.PluginSettingValueDynamic{ - Key: "dynamic_host", - }, - }, - { - Type: definition.PluginSettingDefinitionTypeDynamic, - Value: &definition.PluginSettingValueDynamic{ - Key: "dynamic_api_key", - }, - }, { Type: definition.PluginSettingDefinitionTypeTable, Value: &definition.PluginSettingValueTable{ @@ -142,9 +87,11 @@ func (c *Plugin) GetMetadata() plugin.Metadata { Tooltip: "The command to run. E.g. `translate`, user will type `ai translate` to run this command", }, { - Key: "model", - Label: "Model", - Type: definition.PluginSettingValueTableColumnTypeSelect, + Key: "model", + Label: "Model", + Type: definition.PluginSettingValueTableColumnTypeSelectAIModel, + Width: 100, + Tooltip: "The ai model to use.", }, { Key: "prompt", @@ -373,7 +320,7 @@ func (c *Plugin) queryCommand(ctx context.Context, query plugin.Query) []plugin. return []plugin.QueryResult{{ Title: fmt.Sprintf("Chat with %s", aiCommandSetting.Name), - SubTitle: fmt.Sprintf("%s - %s", aiCommandSetting.Provider, aiCommandSetting.Model), + SubTitle: fmt.Sprintf("%s - %s", aiCommandSetting.AIModel().Provider, aiCommandSetting.AIModel().Name), Preview: plugin.WoxPreview{PreviewType: plugin.WoxPreviewTypeMarkdown, PreviewData: ""}, Icon: aiCommandIcon, RefreshInterval: 100, diff --git a/Wox/plugin/system/menus_darwin.go b/Wox/plugin/system/menus_darwin.go index 4a38758a1..90727aacb 100644 --- a/Wox/plugin/system/menus_darwin.go +++ b/Wox/plugin/system/menus_darwin.go @@ -7,7 +7,7 @@ import ( "wox/util/menus" ) -var menusIcon = plugin.NewWoxImageSvg(``) +var menusIcon = plugin.NewWoxImageSvg(``) func init() { plugin.AllSystemPlugin = append(plugin.AllSystemPlugin, &MenusPlugin{}) @@ -30,7 +30,7 @@ func (i *MenusPlugin) GetMetadata() plugin.Metadata { Icon: menusIcon.String(), Entry: "", TriggerKeywords: []string{ - "*", + "menus", }, SupportedOS: []string{ "Macos", @@ -57,13 +57,8 @@ func (i *MenusPlugin) Query(ctx context.Context, query plugin.Query) []plugin.Qu } if query.Env.ActiveWindowPid == 0 { - return []plugin.QueryResult{ - { - Title: "No active window", - SubTitle: "No active window found", - Icon: icon, - }, - } + i.api.Log(ctx, plugin.LogLevelError, "Active window pid is not available") + return []plugin.QueryResult{} } menuNames, err := menus.GetAppMenuTitles(query.Env.ActiveWindowPid) @@ -73,15 +68,14 @@ func (i *MenusPlugin) Query(ctx context.Context, query plugin.Query) []plugin.Qu } filteredMenus := lo.Filter(menuNames, func(menu string, _ int) bool { - match, score := IsStringMatchScore(ctx, menu, query.Search) - return match && score > 0 + match, _ := IsStringMatchScore(ctx, menu, query.Search) + return match || query.Search == "" }) return lo.Map(filteredMenus, func(menu string, _ int) plugin.QueryResult { return plugin.QueryResult{ - Title: menu, - SubTitle: "Press Enter to execute", - Icon: icon, + Title: menu, + Icon: icon, Actions: []plugin.QueryResultAction{ { Name: "Execute", diff --git a/Wox/setting/definition/definition_table.go b/Wox/setting/definition/definition_table.go index 1481b346a..63264c3e5 100644 --- a/Wox/setting/definition/definition_table.go +++ b/Wox/setting/definition/definition_table.go @@ -8,12 +8,13 @@ import ( type PluginSettingValueTableColumnType = string const ( - PluginSettingValueTableColumnTypeText PluginSettingValueTableColumnType = "text" - PluginSettingValueTableColumnTypeTextList PluginSettingValueTableColumnType = "textList" - PluginSettingValueTableColumnTypeCheckbox PluginSettingValueTableColumnType = "checkbox" - PluginSettingValueTableColumnTypeDirPath PluginSettingValueTableColumnType = "dirPath" - PluginSettingValueTableColumnTypeSelect PluginSettingValueTableColumnType = "select" - PluginSettingValueTableColumnTypeWoxImage PluginSettingValueTableColumnType = "woxImage" + PluginSettingValueTableColumnTypeText PluginSettingValueTableColumnType = "text" + PluginSettingValueTableColumnTypeTextList PluginSettingValueTableColumnType = "textList" + PluginSettingValueTableColumnTypeCheckbox PluginSettingValueTableColumnType = "checkbox" + PluginSettingValueTableColumnTypeDirPath PluginSettingValueTableColumnType = "dirPath" + PluginSettingValueTableColumnTypeSelect PluginSettingValueTableColumnType = "select" + PluginSettingValueTableColumnTypeSelectAIModel PluginSettingValueTableColumnType = "selectAIModel" + PluginSettingValueTableColumnTypeWoxImage PluginSettingValueTableColumnType = "woxImage" ) const ( diff --git a/Wox/ui/http.go b/Wox/ui/http.go index 59d97981d..a77ad61d2 100644 --- a/Wox/ui/http.go +++ b/Wox/ui/http.go @@ -178,17 +178,22 @@ func convertPluginDto(ctx context.Context, pluginDto dto.PluginDto, pluginInstan var removedKeys []string for i, settingDefinition := range pluginDto.SettingDefinitions { if settingDefinition.Type == definition.PluginSettingDefinitionTypeDynamic { + replaced := false for _, callback := range pluginInstance.DynamicSettingCallbacks { newSettingDefinition := callback(settingDefinition.Value.GetKey()) if newSettingDefinition.Value != nil && newSettingDefinition.Type != definition.PluginSettingDefinitionTypeDynamic { logger.Debug(ctx, fmt.Sprintf("dynamic setting replaced: %s(%s) -> %s(%s)", settingDefinition.Value.GetKey(), settingDefinition.Type, newSettingDefinition.Value.GetKey(), newSettingDefinition.Type)) pluginDto.SettingDefinitions[i] = newSettingDefinition - } else { - logger.Error(ctx, fmt.Sprintf("dynamic setting not valid: %+v", newSettingDefinition)) - //remove invalid dynamic setting - removedKeys = append(removedKeys, settingDefinition.Value.GetKey()) + replaced = true + break } } + + if !replaced { + logger.Error(ctx, "dynamic setting not replaced") + //remove invalid dynamic setting + removedKeys = append(removedKeys, settingDefinition.Value.GetKey()) + } } } diff --git a/Wox/ui/router.go b/Wox/ui/router.go index b128e3e1e..de76345e9 100644 --- a/Wox/ui/router.go +++ b/Wox/ui/router.go @@ -10,6 +10,7 @@ import ( "net/http" "os" "strings" + "wox/ai" "wox/i18n" "wox/plugin" "wox/setting" @@ -50,6 +51,9 @@ var routers = map[string]func(w http.ResponseWriter, r *http.Request){ "/lang/change": handleLangChange, "/lang/json": handleLangJson, + // ai + "/ai/models": handleAIModels, + // others "/": handleHome, "/show": handleShow, @@ -750,3 +754,29 @@ func handleDeeplink(w http.ResponseWriter, r *http.Request) { writeSuccessResponse(w, "") } + +func handleAIModels(w http.ResponseWriter, r *http.Request) { + ctx := util.NewTraceContext() + + var results []ai.Model + woxSetting := setting.GetSettingManager().GetWoxSetting(ctx) + for _, providerSetting := range woxSetting.AIProviders { + provider, err := ai.NewProvider(ctx, providerSetting) + if err != nil { + logger.Error(ctx, fmt.Sprintf("failed to new ai provider: %s", err.Error())) + continue + } + + models, modelsErr := provider.Models(ctx) + if modelsErr != nil { + logger.Error(ctx, fmt.Sprintf("failed to get models for provider %s: %s", providerSetting.Name, modelsErr.Error())) + continue + } + + for i := range models { + results = append(results, models[i]) + } + } + + writeSuccessResponse(w, results) +}