From 4f4f73c7d74daf459c3ab203729c64b847c48fb4 Mon Sep 17 00:00:00 2001 From: tisfeng Date: Fri, 5 Apr 2024 22:26:00 +0800 Subject: [PATCH 01/11] perf: adjust file structure --- Easydict.xcodeproj/project.pbxproj | 32 ++++++++++++------- .../AliService+ConfigurableService.swift | 0 .../BingService+ConfigurableService.swift | 0 .../CaiyunService+ConfigurableService.swift | 0 ...tomOpenAIService+ConfigurableService.swift | 0 .../DeepLTranslate+ConfigurableService.swift | 0 .../GeminiService+ConfigurableService.swift | 0 ...iuTransTranslate+ConfigurableService.swift | 0 .../OpenAIService+ConfigurableService.swift | 3 ++ .../TencentService+ConfigurableService.swift | 0 .../SecureTextField.swift | 0 .../ServiceConfigurationCells.swift | 0 ...erviceConfigurationSecretSectionView.swift | 0 .../ServiceConfigurationSection.swift | 0 .../Tabs/{ => TabView}/AboutTab.swift | 0 .../Tabs/{ => TabView}/AdvancedTab.swift | 0 .../Tabs/{ => TabView}/DisabledAppTab.swift | 0 .../Tabs/{ => TabView}/GeneralTab.swift | 0 .../Tabs/{ => TabView}/PrivacyTab.swift | 0 .../Tabs/{ => TabView}/ServiceTab.swift | 0 .../Tabs/{ => TabView}/ShortcutTab.swift | 0 21 files changed, 23 insertions(+), 12 deletions(-) rename Easydict/Swift/{Utility/Extensions => View/SettingView/Tabs/ServiceConfigurationView}/QueryService+ConfigurableService/AliService+ConfigurableService.swift (100%) rename Easydict/Swift/{Utility/Extensions => View/SettingView/Tabs/ServiceConfigurationView}/QueryService+ConfigurableService/BingService+ConfigurableService.swift (100%) rename Easydict/Swift/{Utility/Extensions => View/SettingView/Tabs/ServiceConfigurationView}/QueryService+ConfigurableService/CaiyunService+ConfigurableService.swift (100%) rename Easydict/Swift/{Utility/Extensions => View/SettingView/Tabs/ServiceConfigurationView}/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift (100%) rename Easydict/Swift/{Utility/Extensions => View/SettingView/Tabs/ServiceConfigurationView}/QueryService+ConfigurableService/DeepLTranslate+ConfigurableService.swift (100%) rename Easydict/Swift/{Utility/Extensions => View/SettingView/Tabs/ServiceConfigurationView}/QueryService+ConfigurableService/GeminiService+ConfigurableService.swift (100%) rename Easydict/Swift/{Utility/Extensions => View/SettingView/Tabs/ServiceConfigurationView}/QueryService+ConfigurableService/NiuTransTranslate+ConfigurableService.swift (100%) rename Easydict/Swift/{Utility/Extensions => View/SettingView/Tabs/ServiceConfigurationView}/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift (98%) rename Easydict/Swift/{Utility/Extensions => View/SettingView/Tabs/ServiceConfigurationView}/QueryService+ConfigurableService/TencentService+ConfigurableService.swift (100%) rename Easydict/Swift/View/SettingView/Tabs/{ServiceConfiguration => ServiceConfigurationView}/SecureTextField.swift (100%) rename Easydict/Swift/View/SettingView/Tabs/{ServiceConfiguration => ServiceConfigurationView}/ServiceConfigurationCells.swift (100%) rename Easydict/Swift/View/SettingView/Tabs/{ServiceConfiguration => ServiceConfigurationView}/ServiceConfigurationSecretSectionView.swift (100%) rename Easydict/Swift/View/SettingView/Tabs/{ServiceConfiguration => ServiceConfigurationView}/ServiceConfigurationSection.swift (100%) rename Easydict/Swift/View/SettingView/Tabs/{ => TabView}/AboutTab.swift (100%) rename Easydict/Swift/View/SettingView/Tabs/{ => TabView}/AdvancedTab.swift (100%) rename Easydict/Swift/View/SettingView/Tabs/{ => TabView}/DisabledAppTab.swift (100%) rename Easydict/Swift/View/SettingView/Tabs/{ => TabView}/GeneralTab.swift (100%) rename Easydict/Swift/View/SettingView/Tabs/{ => TabView}/PrivacyTab.swift (100%) rename Easydict/Swift/View/SettingView/Tabs/{ => TabView}/ServiceTab.swift (100%) rename Easydict/Swift/View/SettingView/Tabs/{ => TabView}/ShortcutTab.swift (100%) diff --git a/Easydict.xcodeproj/project.pbxproj b/Easydict.xcodeproj/project.pbxproj index def065d20..4a4ec6d69 100644 --- a/Easydict.xcodeproj/project.pbxproj +++ b/Easydict.xcodeproj/project.pbxproj @@ -958,6 +958,20 @@ path = AppleScript; sourceTree = ""; }; + 03071E1B2BC03ADE0042CD38 /* TabView */ = { + isa = PBXGroup; + children = ( + 278540332B3DE04F004E9488 /* GeneralTab.swift */, + 0A057D6C2B499A000025C51D /* ServiceTab.swift */, + 0A8685C72B552A590022534F /* DisabledAppTab.swift */, + 276742042B3DC230002A2C75 /* PrivacyTab.swift */, + 276742052B3DC230002A2C75 /* AboutTab.swift */, + 96099AE12B5D40330055C4DD /* ShortcutTab.swift */, + 03832F532B5F6BE200D0DC64 /* AdvancedTab.swift */, + ); + path = TabView; + sourceTree = ""; + }; 0309E1EA292B437C00AFB76A /* TextView */ = { isa = PBXGroup; children = ( @@ -2229,15 +2243,9 @@ 27FE980C2B3DD749000AD654 /* Tabs */ = { isa = PBXGroup; children = ( + 03071E1B2BC03ADE0042CD38 /* TabView */, 9627F9332B59956800B1E999 /* View */, - EAED41EA2B54A4900005FE0A /* ServiceConfiguration */, - 278540332B3DE04F004E9488 /* GeneralTab.swift */, - 0A057D6C2B499A000025C51D /* ServiceTab.swift */, - 0A8685C72B552A590022534F /* DisabledAppTab.swift */, - 276742042B3DC230002A2C75 /* PrivacyTab.swift */, - 276742052B3DC230002A2C75 /* AboutTab.swift */, - 96099AE12B5D40330055C4DD /* ShortcutTab.swift */, - 03832F532B5F6BE200D0DC64 /* AdvancedTab.swift */, + EAED41EA2B54A4900005FE0A /* ServiceConfigurationView */, ); path = Tabs; sourceTree = ""; @@ -2471,7 +2479,6 @@ 038F1F8D2BAD835500CD2F65 /* AppKit */, EA1013412B5DBDA5005E43F9 /* Defaults */, 038A723E2B62C07B004995E3 /* String */, - EAED41F02B54B1A60005FE0A /* QueryService+ConfigurableService */, EA9943E72B534D8900EE7B97 /* LanguageDetectOptimizeExtensions.swift */, EA9943ED2B5353AB00EE7B97 /* WindowTypeExtensions.swift */, EA9943EF2B5354C400EE7B97 /* ShowWindowPositionExtensions.swift */, @@ -2480,15 +2487,16 @@ path = Extensions; sourceTree = ""; }; - EAED41EA2B54A4900005FE0A /* ServiceConfiguration */ = { + EAED41EA2B54A4900005FE0A /* ServiceConfigurationView */ = { isa = PBXGroup; children = ( + EAED41F02B54B1A60005FE0A /* QueryService+ConfigurableService */, 0AC8A83C2B6685EE006DA5CC /* SecureTextField.swift */, EAED41EB2B54AA920005FE0A /* ServiceConfigurationSection.swift */, 0AC8A8462B6A4E3F006DA5CC /* ServiceConfigurationSecretSectionView.swift */, 0AC8A8442B6A4D97006DA5CC /* ServiceConfigurationCells.swift */, ); - path = ServiceConfiguration; + path = ServiceConfigurationView; sourceTree = ""; }; EAED41ED2B54B1390005FE0A /* Protocol */ = { @@ -2504,6 +2512,7 @@ isa = PBXGroup; children = ( EAED41F12B54B39D0005FE0A /* OpenAIService+ConfigurableService.swift */, + 0A318F3A2B8CCCCD0005EF77 /* CustomOpenAIService+ConfigurableService.swift */, 0AC8A8402B695480006DA5CC /* DeepLTranslate+ConfigurableService.swift */, 0AC8A8342B6641A7006DA5CC /* TencentService+ConfigurableService.swift */, 0AC8A8362B6659A8006DA5CC /* NiuTransTranslate+ConfigurableService.swift */, @@ -2511,7 +2520,6 @@ 0AC8A83A2B6682D4006DA5CC /* AliService+ConfigurableService.swift */, 0AC8A8422B6957B0006DA5CC /* BingService+ConfigurableService.swift */, 0AC8A84A2B6A629D006DA5CC /* GeminiService+ConfigurableService.swift */, - 0A318F3A2B8CCCCD0005EF77 /* CustomOpenAIService+ConfigurableService.swift */, ); path = "QueryService+ConfigurableService"; sourceTree = ""; diff --git a/Easydict/Swift/Utility/Extensions/QueryService+ConfigurableService/AliService+ConfigurableService.swift b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/AliService+ConfigurableService.swift similarity index 100% rename from Easydict/Swift/Utility/Extensions/QueryService+ConfigurableService/AliService+ConfigurableService.swift rename to Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/AliService+ConfigurableService.swift diff --git a/Easydict/Swift/Utility/Extensions/QueryService+ConfigurableService/BingService+ConfigurableService.swift b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/BingService+ConfigurableService.swift similarity index 100% rename from Easydict/Swift/Utility/Extensions/QueryService+ConfigurableService/BingService+ConfigurableService.swift rename to Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/BingService+ConfigurableService.swift diff --git a/Easydict/Swift/Utility/Extensions/QueryService+ConfigurableService/CaiyunService+ConfigurableService.swift b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CaiyunService+ConfigurableService.swift similarity index 100% rename from Easydict/Swift/Utility/Extensions/QueryService+ConfigurableService/CaiyunService+ConfigurableService.swift rename to Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CaiyunService+ConfigurableService.swift diff --git a/Easydict/Swift/Utility/Extensions/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift similarity index 100% rename from Easydict/Swift/Utility/Extensions/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift rename to Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift diff --git a/Easydict/Swift/Utility/Extensions/QueryService+ConfigurableService/DeepLTranslate+ConfigurableService.swift b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/DeepLTranslate+ConfigurableService.swift similarity index 100% rename from Easydict/Swift/Utility/Extensions/QueryService+ConfigurableService/DeepLTranslate+ConfigurableService.swift rename to Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/DeepLTranslate+ConfigurableService.swift diff --git a/Easydict/Swift/Utility/Extensions/QueryService+ConfigurableService/GeminiService+ConfigurableService.swift b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/GeminiService+ConfigurableService.swift similarity index 100% rename from Easydict/Swift/Utility/Extensions/QueryService+ConfigurableService/GeminiService+ConfigurableService.swift rename to Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/GeminiService+ConfigurableService.swift diff --git a/Easydict/Swift/Utility/Extensions/QueryService+ConfigurableService/NiuTransTranslate+ConfigurableService.swift b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/NiuTransTranslate+ConfigurableService.swift similarity index 100% rename from Easydict/Swift/Utility/Extensions/QueryService+ConfigurableService/NiuTransTranslate+ConfigurableService.swift rename to Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/NiuTransTranslate+ConfigurableService.swift diff --git a/Easydict/Swift/Utility/Extensions/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift similarity index 98% rename from Easydict/Swift/Utility/Extensions/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift rename to Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift index 7060645a8..cb5180eb7 100644 --- a/Easydict/Swift/Utility/Extensions/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift +++ b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift @@ -56,6 +56,7 @@ private struct OpenAIServiceConfigurationView: View { key: .openAIModel, values: OpenAIModel.allCases ) + ServiceConfigurationToggleCell( titleKey: "service.configuration.openai.translation.title", key: .openAITranslation @@ -137,6 +138,8 @@ protocol EnumLocalizedStringConvertible { enum OpenAIModel: String, CaseIterable { case gpt3_5_turbo_0125 = "gpt-3.5-turbo-0125" case gpt4_0125_preview = "gpt-4-0125-preview" + case gpt3_5_turbo = "gpt-3.5-turbo" + case gpt4_turbo_preview = "gpt-4-turbo-preview" } // MARK: EnumLocalizedStringConvertible diff --git a/Easydict/Swift/Utility/Extensions/QueryService+ConfigurableService/TencentService+ConfigurableService.swift b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/TencentService+ConfigurableService.swift similarity index 100% rename from Easydict/Swift/Utility/Extensions/QueryService+ConfigurableService/TencentService+ConfigurableService.swift rename to Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/TencentService+ConfigurableService.swift diff --git a/Easydict/Swift/View/SettingView/Tabs/ServiceConfiguration/SecureTextField.swift b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/SecureTextField.swift similarity index 100% rename from Easydict/Swift/View/SettingView/Tabs/ServiceConfiguration/SecureTextField.swift rename to Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/SecureTextField.swift diff --git a/Easydict/Swift/View/SettingView/Tabs/ServiceConfiguration/ServiceConfigurationCells.swift b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/ServiceConfigurationCells.swift similarity index 100% rename from Easydict/Swift/View/SettingView/Tabs/ServiceConfiguration/ServiceConfigurationCells.swift rename to Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/ServiceConfigurationCells.swift diff --git a/Easydict/Swift/View/SettingView/Tabs/ServiceConfiguration/ServiceConfigurationSecretSectionView.swift b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/ServiceConfigurationSecretSectionView.swift similarity index 100% rename from Easydict/Swift/View/SettingView/Tabs/ServiceConfiguration/ServiceConfigurationSecretSectionView.swift rename to Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/ServiceConfigurationSecretSectionView.swift diff --git a/Easydict/Swift/View/SettingView/Tabs/ServiceConfiguration/ServiceConfigurationSection.swift b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/ServiceConfigurationSection.swift similarity index 100% rename from Easydict/Swift/View/SettingView/Tabs/ServiceConfiguration/ServiceConfigurationSection.swift rename to Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/ServiceConfigurationSection.swift diff --git a/Easydict/Swift/View/SettingView/Tabs/AboutTab.swift b/Easydict/Swift/View/SettingView/Tabs/TabView/AboutTab.swift similarity index 100% rename from Easydict/Swift/View/SettingView/Tabs/AboutTab.swift rename to Easydict/Swift/View/SettingView/Tabs/TabView/AboutTab.swift diff --git a/Easydict/Swift/View/SettingView/Tabs/AdvancedTab.swift b/Easydict/Swift/View/SettingView/Tabs/TabView/AdvancedTab.swift similarity index 100% rename from Easydict/Swift/View/SettingView/Tabs/AdvancedTab.swift rename to Easydict/Swift/View/SettingView/Tabs/TabView/AdvancedTab.swift diff --git a/Easydict/Swift/View/SettingView/Tabs/DisabledAppTab.swift b/Easydict/Swift/View/SettingView/Tabs/TabView/DisabledAppTab.swift similarity index 100% rename from Easydict/Swift/View/SettingView/Tabs/DisabledAppTab.swift rename to Easydict/Swift/View/SettingView/Tabs/TabView/DisabledAppTab.swift diff --git a/Easydict/Swift/View/SettingView/Tabs/GeneralTab.swift b/Easydict/Swift/View/SettingView/Tabs/TabView/GeneralTab.swift similarity index 100% rename from Easydict/Swift/View/SettingView/Tabs/GeneralTab.swift rename to Easydict/Swift/View/SettingView/Tabs/TabView/GeneralTab.swift diff --git a/Easydict/Swift/View/SettingView/Tabs/PrivacyTab.swift b/Easydict/Swift/View/SettingView/Tabs/TabView/PrivacyTab.swift similarity index 100% rename from Easydict/Swift/View/SettingView/Tabs/PrivacyTab.swift rename to Easydict/Swift/View/SettingView/Tabs/TabView/PrivacyTab.swift diff --git a/Easydict/Swift/View/SettingView/Tabs/ServiceTab.swift b/Easydict/Swift/View/SettingView/Tabs/TabView/ServiceTab.swift similarity index 100% rename from Easydict/Swift/View/SettingView/Tabs/ServiceTab.swift rename to Easydict/Swift/View/SettingView/Tabs/TabView/ServiceTab.swift diff --git a/Easydict/Swift/View/SettingView/Tabs/ShortcutTab.swift b/Easydict/Swift/View/SettingView/Tabs/TabView/ShortcutTab.swift similarity index 100% rename from Easydict/Swift/View/SettingView/Tabs/ShortcutTab.swift rename to Easydict/Swift/View/SettingView/Tabs/TabView/ShortcutTab.swift From e71e7f3835b49476c20d1c2d12826999a7cafc8b Mon Sep 17 00:00:00 2001 From: tisfeng Date: Sat, 6 Apr 2024 00:10:05 +0800 Subject: [PATCH 02/11] perf: enable customize OpenAI models --- .../Configuration+Defaults.swift | 11 ++-- .../Service/OpenAI/BaseOpenAIService.swift | 17 +++--- ...tomOpenAIService+ConfigurableService.swift | 3 +- .../OpenAIService+ConfigurableService.swift | 54 +++++++++++++++---- .../ServiceConfigurationCells.swift | 7 ++- 5 files changed, 65 insertions(+), 27 deletions(-) diff --git a/Easydict/Swift/Feature/Configuration/Configuration+Defaults.swift b/Easydict/Swift/Feature/Configuration/Configuration+Defaults.swift index f1fd3a349..70a3d6921 100644 --- a/Easydict/Swift/Feature/Configuration/Configuration+Defaults.swift +++ b/Easydict/Swift/Feature/Configuration/Configuration+Defaults.swift @@ -201,7 +201,11 @@ extension Defaults.Keys { default: OpenAIUsageStats.default ) static let openAIEndPoint = Key(EZOpenAIEndPointKey) - static let openAIModel = Key(EZOpenAIModelKey, default: .gpt3_5_turbo_0125) + static let openAIModel = Key(EZOpenAIModelKey, default: OpenAIModel.gpt3_5_turbo.rawValue) + static let openAIAvailableModels = Key( + "EZOpenAIAvailableModelsKey", + default: OpenAIModel.allCases.map { $0.rawValue }.joined(separator: ",") + ) // Custom OpenAI static let customOpenAINameKey = Key( @@ -218,10 +222,7 @@ extension Defaults.Keys { ) static let customOpenAIEndPoint = Key(EZCustomOpenAIEndPointKey, default: "") static let customOpenAIModel = Key(EZCustomOpenAIModelKey, default: "") - static let customOpenAIModelsAvailable = Key( - EZCustomOpenAIModelssAvailableKey, - default: "" - ) + static let customOpenAIModelsAvailable = Key(EZCustomOpenAIModelssAvailableKey, default: "") // DeepL static let deepLAuth = Key(EZDeepLAuthKey) diff --git a/Easydict/Swift/Service/OpenAI/BaseOpenAIService.swift b/Easydict/Swift/Service/OpenAI/BaseOpenAIService.swift index 8eb0e6f47..69faa4f37 100644 --- a/Easydict/Swift/Service/OpenAI/BaseOpenAIService.swift +++ b/Easydict/Swift/Service/OpenAI/BaseOpenAIService.swift @@ -123,11 +123,17 @@ public class BaseOpenAIService: QueryService { // MARK: Internal + var availableModels: [String] { + let models = Defaults[.openAIAvailableModels] + guard let models, !models.isEmpty else { return [] } + return models.components(separatedBy: ",").filter { !$0.isEmpty } + } + var model: String { get { - var model = Defaults[.openAIModel].rawValue + var model = Defaults[.openAIModel] if model.isEmpty { - model = availableModels.first ?? OpenAIModel.gpt3_5_turbo_0125.rawValue + model = availableModels.first ?? OpenAIModel.gpt3_5_turbo.rawValue } return model } @@ -135,8 +141,7 @@ public class BaseOpenAIService: QueryService { set { // easydict://writeKeyValue?EZOpenAIModelKey=gpt-3.5-turbo - let mode = OpenAIModel(rawValue: newValue) ?? .gpt3_5_turbo_0125 - Defaults[.openAIModel] = mode + Defaults[.openAIModel] = newValue } } @@ -166,10 +171,6 @@ public class BaseOpenAIService: QueryService { return endPoint } - var availableModels: [String] { - OpenAIModel.allCases.map { $0.rawValue } - } - // MARK: Private private func queryTextType(text: String, from: Language, to _: Language) -> EZQueryTextType { diff --git a/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift index 6803e95c6..6e7f71351 100644 --- a/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift +++ b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift @@ -57,7 +57,8 @@ private struct CustomOpenAIServiceConfigurationView: View { key: .customOpenAIEndPoint, placeholder: "service.configuration.openai.endpoint.placeholder" ) - // model + + // supported models TextField( "service.configuration.custom_openai.supported_models.title", text: viewModel.$availableModels ?? "", diff --git a/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift index cb5180eb7..7a72432c2 100644 --- a/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift +++ b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift @@ -37,7 +37,7 @@ private struct OpenAIServiceConfigurationView: View { var body: some View { ServiceConfigurationSecretSectionView( - service: service, observeKeys: [.openAIAPIKey] + service: service, observeKeys: [.openAIAPIKey, .openAIEndPoint, .openAIAvailableModels] ) { ServiceConfigurationSecureInputCell( textFieldTitleKey: "service.configuration.openai.api_key.title", @@ -50,12 +50,23 @@ private struct OpenAIServiceConfigurationView: View { key: .openAIEndPoint, placeholder: "service.configuration.openai.endpoint.placeholder" ) + // model - ServiceConfigurationPickerCell( - titleKey: "service.configuration.openai.model.title", - key: .openAIModel, - values: OpenAIModel.allCases + TextField( + "service.configuration.custom_openai.supported_models.title", + text: viewModel.$availableModels ?? "", + prompt: Text("service.configuration.custom_openai.model.placeholder") ) + .padding(10.0) + Picker( + "service.configuration.openai.model.title", + selection: viewModel.$model + ) { + ForEach(viewModel.validModels, id: \.self) { value in + Text(value) + } + } + .padding(10.0) ServiceConfigurationToggleCell( titleKey: "service.configuration.openai.translation.title", @@ -99,6 +110,13 @@ private class OpenAIServiceViewModel: ObservableObject { self.serviceConfigChanged() } ) + cancellables.append( + Defaults.publisher(.openAIAvailableModels) + .removeDuplicates() + .sink { _ in + self.modelsTextChanged() + } + ) } // MARK: Internal @@ -106,6 +124,9 @@ private class OpenAIServiceViewModel: ObservableObject { let service: OpenAIService @Default(.openAIModel) var model + @Default(.openAIAvailableModels) var availableModels + + @Published var validModels: [String] = [] func invalidate() { cancellables.forEach { $0.cancel() } @@ -116,7 +137,22 @@ private class OpenAIServiceViewModel: ObservableObject { private var cancellables: [AnyCancellable] = [] + private func modelsTextChanged() { + guard let availableModels else { return } + if availableModels.isEmpty { + model = "" + validModels = [] + return + } + validModels = availableModels.components(separatedBy: ",").filter { !$0.isEmpty } + if validModels.count == 1 || !validModels.contains(model) { + model = validModels[0] + } + } + private func serviceConfigChanged() { + objectWillChange.send() + let userInfo: [String: Any] = [ EZWindowTypeKey: service.windowType.rawValue, EZServiceTypeKey: service.serviceType().rawValue, @@ -136,10 +172,10 @@ protocol EnumLocalizedStringConvertible { // swiftlint:disable identifier_name enum OpenAIModel: String, CaseIterable { - case gpt3_5_turbo_0125 = "gpt-3.5-turbo-0125" - case gpt4_0125_preview = "gpt-4-0125-preview" - case gpt3_5_turbo = "gpt-3.5-turbo" - case gpt4_turbo_preview = "gpt-4-turbo-preview" + // Docs: https://platform.openai.com/docs/models/gpt-3-5-turbo + + case gpt3_5_turbo = "gpt-3.5-turbo" // Currently points to gpt-3.5-turbo-0125. + case gpt4_turbo_preview = "gpt-4-turbo-preview" // Currently points to gpt-4-0125-preview. } // MARK: EnumLocalizedStringConvertible diff --git a/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/ServiceConfigurationCells.swift b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/ServiceConfigurationCells.swift index ed31c5fd4..efdc6545d 100644 --- a/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/ServiceConfigurationCells.swift +++ b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/ServiceConfigurationCells.swift @@ -137,11 +137,10 @@ struct ServiceConfigurationToggleCell: View { placeholder: "service.configuration.openai.endpoint.placeholder" ) - // model ServiceConfigurationPickerCell( - titleKey: "service.configuration.openai.model.title", - key: .openAIModel, - values: OpenAIModel.allCases + titleKey: "service.configuration.openai.usage_status.title", + key: .openAIServiceUsageStatus, + values: OpenAIUsageStats.allCases ) ServiceConfigurationToggleCell( From 10e3a69a41c66776898143dde1a93190cc5aa650 Mon Sep 17 00:00:00 2001 From: tisfeng Date: Sat, 6 Apr 2024 11:16:01 +0800 Subject: [PATCH 03/11] perf: update Localizable.xcstrings --- Easydict/App/Localizable.xcstrings | 4 ++-- .../CustomOpenAIService+ConfigurableService.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Easydict/App/Localizable.xcstrings b/Easydict/App/Localizable.xcstrings index 113cff573..e794fffbb 100644 --- a/Easydict/App/Localizable.xcstrings +++ b/Easydict/App/Localizable.xcstrings @@ -3000,13 +3000,13 @@ "en" : { "stringUnit" : { "state" : "translated", - "value" : "Model" + "value" : "Use Model" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "模型" + "value" : "使用模型" } } } diff --git a/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift index 6e7f71351..67a2ddc18 100644 --- a/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift +++ b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift @@ -57,7 +57,7 @@ private struct CustomOpenAIServiceConfigurationView: View { key: .customOpenAIEndPoint, placeholder: "service.configuration.openai.endpoint.placeholder" ) - + // supported models TextField( "service.configuration.custom_openai.supported_models.title", From 6db0e4cfbc0096738da8e010c92fe8567bdf6404 Mon Sep 17 00:00:00 2001 From: tisfeng Date: Sat, 6 Apr 2024 22:49:35 +0800 Subject: [PATCH 04/11] fix: show model menu position is incorrect --- Easydict/objc/ViewController/View/ResultView/EZResultView.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Easydict/objc/ViewController/View/ResultView/EZResultView.m b/Easydict/objc/ViewController/View/ResultView/EZResultView.m index 812e5d81f..14219ab0f 100644 --- a/Easydict/objc/ViewController/View/ResultView/EZResultView.m +++ b/Easydict/objc/ViewController/View/ResultView/EZResultView.m @@ -271,7 +271,7 @@ - (void)setResult:(EZQueryResult *)result { EZBaseOpenAIService *service = (EZBaseOpenAIService *)result.service; self.serviceModelButton.title = service.model; mm_weakify(self); - [self.serviceModelButton setMouseUpBlock:^(EZButton *_Nonnull button) { + [self.serviceModelButton setClickBlock:^(EZButton *_Nonnull button) { mm_strongify(self); [self showModelSelectionMenu:button]; }]; @@ -415,7 +415,7 @@ - (void)updateServiceModelLabel { } - (void)showModelSelectionMenu:(EZButton *)sender { - EZBaseOpenAIService *service = (EZBaseOpenAIService *)self.result.service; + EZBaseOpenAIService *service = (EZBaseOpenAIService *)self.result.service; NSMenu *menu = [[NSMenu alloc] initWithTitle:@"Menu"]; for (NSString *model in service.availableModels) { NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:model action:@selector(modelDidSelected:) keyEquivalent:@""]; From 7e6c58d69b74eae99b062f9b33f8d1f47f449653 Mon Sep 17 00:00:00 2001 From: tisfeng Date: Sat, 6 Apr 2024 23:27:56 +0800 Subject: [PATCH 05/11] perf: enable user to write OpenAI models using URL scheme --- .../Swift/Feature/Configuration/Configuration+Defaults.swift | 2 +- Easydict/objc/Service/Model/EZConstKey.h | 4 ++-- Easydict/objc/Utility/EZLinkParser/EZSchemeParser.m | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Easydict/Swift/Feature/Configuration/Configuration+Defaults.swift b/Easydict/Swift/Feature/Configuration/Configuration+Defaults.swift index 70a3d6921..02003148e 100644 --- a/Easydict/Swift/Feature/Configuration/Configuration+Defaults.swift +++ b/Easydict/Swift/Feature/Configuration/Configuration+Defaults.swift @@ -203,7 +203,7 @@ extension Defaults.Keys { static let openAIEndPoint = Key(EZOpenAIEndPointKey) static let openAIModel = Key(EZOpenAIModelKey, default: OpenAIModel.gpt3_5_turbo.rawValue) static let openAIAvailableModels = Key( - "EZOpenAIAvailableModelsKey", + EZOpenAIAvailableModelsKey, default: OpenAIModel.allCases.map { $0.rawValue }.joined(separator: ",") ) diff --git a/Easydict/objc/Service/Model/EZConstKey.h b/Easydict/objc/Service/Model/EZConstKey.h index 31e7fca84..b2fbf1c6f 100644 --- a/Easydict/objc/Service/Model/EZConstKey.h +++ b/Easydict/objc/Service/Model/EZConstKey.h @@ -20,10 +20,10 @@ static NSString *const EZOpenAIEndPointKey = @"EZOpenAIEndPointKey"; static NSString *const EZOpenAITranslationKey = @"EZOpenAITranslationKey"; static NSString *const EZOpenAIDictionaryKey = @"EZOpenAIDictionaryKey"; static NSString *const EZOpenAISentenceKey = @"EZOpenAISentenceKey"; - static NSString *const EZOpenAIServiceUsageStatusKey = @"EZOpenAIServiceUsageStatusKey"; - static NSString *const EZOpenAIModelKey = @"EZOpenAIModelKey"; +static NSString *const EZOpenAIAvailableModelsKey = @"EZOpenAIAvailableModelsKey"; + static NSString *const EZCustomOpenAINameKey = @"EZCustomOpenAINameKey"; static NSString *const EZCustomOpenAIEndPointKey = @"EZCustomOpenAIEndPointKey"; diff --git a/Easydict/objc/Utility/EZLinkParser/EZSchemeParser.m b/Easydict/objc/Utility/EZLinkParser/EZSchemeParser.m index a29ef482b..72ca12805 100644 --- a/Easydict/objc/Utility/EZLinkParser/EZSchemeParser.m +++ b/Easydict/objc/Utility/EZLinkParser/EZSchemeParser.m @@ -199,6 +199,7 @@ - (NSArray *)allowedReadWriteKeys { EZOpenAISentenceKey, EZOpenAIServiceUsageStatusKey, EZOpenAIModelKey, + EZOpenAIAvailableModelsKey, EZCustomOpenAINameKey, EZCustomOpenAIEndPointKey, From 4458d2e9de7ad0c5c96cfd45255e3f8559c90dd9 Mon Sep 17 00:00:00 2001 From: tisfeng Date: Sun, 7 Apr 2024 00:22:52 +0800 Subject: [PATCH 06/11] perf: trim model white space --- Easydict/Swift/Service/OpenAI/BaseOpenAIService.swift | 3 ++- .../OpenAIService+ConfigurableService.swift | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Easydict/Swift/Service/OpenAI/BaseOpenAIService.swift b/Easydict/Swift/Service/OpenAI/BaseOpenAIService.swift index 69faa4f37..688fe5b67 100644 --- a/Easydict/Swift/Service/OpenAI/BaseOpenAIService.swift +++ b/Easydict/Swift/Service/OpenAI/BaseOpenAIService.swift @@ -126,7 +126,8 @@ public class BaseOpenAIService: QueryService { var availableModels: [String] { let models = Defaults[.openAIAvailableModels] guard let models, !models.isEmpty else { return [] } - return models.components(separatedBy: ",").filter { !$0.isEmpty } + return models.components(separatedBy: ",").map { $0.trimmingCharacters(in: .whitespacesAndNewlines) } + .filter { !$0.isEmpty } } var model: String { diff --git a/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift index 7a72432c2..b81972cfa 100644 --- a/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift +++ b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift @@ -144,7 +144,8 @@ private class OpenAIServiceViewModel: ObservableObject { validModels = [] return } - validModels = availableModels.components(separatedBy: ",").filter { !$0.isEmpty } + validModels = availableModels.components(separatedBy: ",") + .map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }.filter { !$0.isEmpty } if validModels.count == 1 || !validModels.contains(model) { model = validModels[0] } From 9d514ae8c21e3b5c3cedb1fc188fc43b27e9a363 Mon Sep 17 00:00:00 2001 From: tisfeng Date: Sun, 7 Apr 2024 00:33:16 +0800 Subject: [PATCH 07/11] perf: improve code, store openAIVaildModels in Defaults --- .../Feature/Configuration/Configuration+Defaults.swift | 8 ++++++++ .../Swift/Service/CustomOpenAI/CustomOpenAIService.swift | 4 +--- Easydict/Swift/Service/OpenAI/BaseOpenAIService.swift | 5 +---- .../CustomOpenAIService+ConfigurableService.swift | 5 ++++- .../OpenAIService+ConfigurableService.swift | 2 ++ 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Easydict/Swift/Feature/Configuration/Configuration+Defaults.swift b/Easydict/Swift/Feature/Configuration/Configuration+Defaults.swift index 02003148e..752cb596d 100644 --- a/Easydict/Swift/Feature/Configuration/Configuration+Defaults.swift +++ b/Easydict/Swift/Feature/Configuration/Configuration+Defaults.swift @@ -206,6 +206,10 @@ extension Defaults.Keys { EZOpenAIAvailableModelsKey, default: OpenAIModel.allCases.map { $0.rawValue }.joined(separator: ",") ) + static let openAIVaildModels = Key( + "EZOpenAIValidModelsKey", + default: OpenAIModel.allCases.map { $0.rawValue } + ) // Custom OpenAI static let customOpenAINameKey = Key( @@ -223,6 +227,10 @@ extension Defaults.Keys { static let customOpenAIEndPoint = Key(EZCustomOpenAIEndPointKey, default: "") static let customOpenAIModel = Key(EZCustomOpenAIModelKey, default: "") static let customOpenAIModelsAvailable = Key(EZCustomOpenAIModelssAvailableKey, default: "") + static let customOpenAIVaildModels = Key( + "EZCustomOpenAIValidModelsKey", + default: [""] + ) // DeepL static let deepLAuth = Key(EZDeepLAuthKey) diff --git a/Easydict/Swift/Service/CustomOpenAI/CustomOpenAIService.swift b/Easydict/Swift/Service/CustomOpenAI/CustomOpenAIService.swift index abafaa320..eea956b6f 100644 --- a/Easydict/Swift/Service/CustomOpenAI/CustomOpenAIService.swift +++ b/Easydict/Swift/Service/CustomOpenAI/CustomOpenAIService.swift @@ -50,9 +50,7 @@ class CustomOpenAIService: BaseOpenAIService { } override var availableModels: [String] { - let models = Defaults[.customOpenAIModelsAvailable] - guard let models, !models.isEmpty else { return [] } - return models.components(separatedBy: ",").filter { !$0.isEmpty } + Defaults[.customOpenAIVaildModels] } override func serviceType() -> ServiceType { diff --git a/Easydict/Swift/Service/OpenAI/BaseOpenAIService.swift b/Easydict/Swift/Service/OpenAI/BaseOpenAIService.swift index 688fe5b67..11d7f4e35 100644 --- a/Easydict/Swift/Service/OpenAI/BaseOpenAIService.swift +++ b/Easydict/Swift/Service/OpenAI/BaseOpenAIService.swift @@ -124,10 +124,7 @@ public class BaseOpenAIService: QueryService { // MARK: Internal var availableModels: [String] { - let models = Defaults[.openAIAvailableModels] - guard let models, !models.isEmpty else { return [] } - return models.components(separatedBy: ",").map { $0.trimmingCharacters(in: .whitespacesAndNewlines) } - .filter { !$0.isEmpty } + Defaults[.openAIVaildModels] } var model: String { diff --git a/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift index 67a2ddc18..7bc42dd88 100644 --- a/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift +++ b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift @@ -158,10 +158,13 @@ private class CustomOpenAIViewModel: ObservableObject { validModels = [] return } - validModels = availableModels.components(separatedBy: ",").filter { !$0.isEmpty } + validModels = availableModels.components(separatedBy: ",") + .map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }.filter { !$0.isEmpty } if validModels.count == 1 || !validModels.contains(model) { model = validModels[0] } + + Defaults[.customOpenAIVaildModels] = validModels } private func serviceConfigChanged() { diff --git a/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift index b81972cfa..aa5837f03 100644 --- a/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift +++ b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift @@ -149,6 +149,8 @@ private class OpenAIServiceViewModel: ObservableObject { if validModels.count == 1 || !validModels.contains(model) { model = validModels[0] } + + Defaults[.openAIVaildModels] = validModels } private func serviceConfigChanged() { From 614c44e1c7679bb0892ec0e36b604eab373b143e Mon Sep 17 00:00:00 2001 From: tisfeng Date: Sun, 7 Apr 2024 10:37:54 +0800 Subject: [PATCH 08/11] perf: add EZOpenAIValidModelsKey to EZConstKey file --- .../Configuration/Configuration+Defaults.swift | 4 ++-- Easydict/objc/Service/Model/EZConstKey.h | 12 +++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Easydict/Swift/Feature/Configuration/Configuration+Defaults.swift b/Easydict/Swift/Feature/Configuration/Configuration+Defaults.swift index 752cb596d..248961966 100644 --- a/Easydict/Swift/Feature/Configuration/Configuration+Defaults.swift +++ b/Easydict/Swift/Feature/Configuration/Configuration+Defaults.swift @@ -207,7 +207,7 @@ extension Defaults.Keys { default: OpenAIModel.allCases.map { $0.rawValue }.joined(separator: ",") ) static let openAIVaildModels = Key( - "EZOpenAIValidModelsKey", + EZOpenAIValidModelsKey, default: OpenAIModel.allCases.map { $0.rawValue } ) @@ -228,7 +228,7 @@ extension Defaults.Keys { static let customOpenAIModel = Key(EZCustomOpenAIModelKey, default: "") static let customOpenAIModelsAvailable = Key(EZCustomOpenAIModelssAvailableKey, default: "") static let customOpenAIVaildModels = Key( - "EZCustomOpenAIValidModelsKey", + EZCustomOpenAIValidModelsKey, default: [""] ) diff --git a/Easydict/objc/Service/Model/EZConstKey.h b/Easydict/objc/Service/Model/EZConstKey.h index b2fbf1c6f..6d2de3344 100644 --- a/Easydict/objc/Service/Model/EZConstKey.h +++ b/Easydict/objc/Service/Model/EZConstKey.h @@ -15,6 +15,7 @@ static NSString *const EZBetaFeatureKey = @"EZBetaFeatureKey"; static NSString *const EZDictionaryKey = @"Dictionary"; +// OpenAI static NSString *const EZOpenAIAPIKey = @"EZOpenAIAPIKey"; static NSString *const EZOpenAIEndPointKey = @"EZOpenAIEndPointKey"; static NSString *const EZOpenAITranslationKey = @"EZOpenAITranslationKey"; @@ -23,19 +24,20 @@ static NSString *const EZOpenAISentenceKey = @"EZOpenAISentenceKey"; static NSString *const EZOpenAIServiceUsageStatusKey = @"EZOpenAIServiceUsageStatusKey"; static NSString *const EZOpenAIModelKey = @"EZOpenAIModelKey"; static NSString *const EZOpenAIAvailableModelsKey = @"EZOpenAIAvailableModelsKey"; +static NSString *const EZOpenAIValidModelsKey = @"EZOpenAIValidModelsKey"; - +// Custom OpenAI static NSString *const EZCustomOpenAINameKey = @"EZCustomOpenAINameKey"; static NSString *const EZCustomOpenAIEndPointKey = @"EZCustomOpenAIEndPointKey"; static NSString *const EZCustomOpenAIAPIKey = @"EZCustomOpenAIAPIKey"; - -static NSString *const EZCustomOpenAIModelssAvailableKey = @"EZCustomOpenAIModelssAvailableKey"; -static NSString *const EZCustomOpenAIModelKey = @"EZCustomOpenAIModelKey"; - static NSString *const EZCustomOpenAITranslationKey = @"EZCustomOpenAITranslationKey"; static NSString *const EZCustomOpenAIDictionaryKey = @"EZCustomOpenAIDictionaryKey"; static NSString *const EZCustomOpenAISentenceKey = @"EZCustomOpenAISentenceKey"; static NSString *const EZCustomOpenAIServiceUsageStatusKey = @"EZCustomOpenAIServiceUsageStatusKey"; +static NSString *const EZCustomOpenAIModelssAvailableKey = @"EZCustomOpenAIModelssAvailableKey"; +static NSString *const EZCustomOpenAIModelKey = @"EZCustomOpenAIModelKey"; +static NSString *const EZCustomOpenAIValidModelsKey = @"EZCustomOpenAIValidModelsKey"; + static NSString *const EZDeepLAuthKey = @"EZDeepLAuthKey"; static NSString *const EZDeepLTranslateEndPointKey = @"EZDeepLTranslateEndPointKey"; From 91a80eabf79ff240a9994c9a1906664e8f25ce93 Mon Sep 17 00:00:00 2001 From: tisfeng Date: Sun, 7 Apr 2024 11:39:03 +0800 Subject: [PATCH 09/11] perf: improve the way user change model using URL scheme --- .../CustomOpenAIService+ConfigurableService.swift | 4 ++++ .../OpenAIService+ConfigurableService.swift | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift index 7bc42dd88..a1a7ce33a 100644 --- a/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift +++ b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift @@ -168,6 +168,10 @@ private class CustomOpenAIViewModel: ObservableObject { } private func serviceConfigChanged() { + if !validModels.contains(model) { + Defaults[.customOpenAIModelsAvailable] = "\(model), " + (availableModels ?? "") + } + // looks like Defaults changed but View not update in this case objectWillChange.send() let userInfo: [String: Any] = [ diff --git a/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift index aa5837f03..0cd2abb38 100644 --- a/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift +++ b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift @@ -154,6 +154,13 @@ private class OpenAIServiceViewModel: ObservableObject { } private func serviceConfigChanged() { + // Currently, user of low os versions may change OpenAI model using URL scheme, like easydict://writeKeyValue?EZOpenAIModelKey=gpt-4 + // In this case, model may not be included in validModels, we need to handle it. + + if !validModels.contains(model) { + Defaults[.openAIAvailableModels] = "\(model), " + (availableModels ?? "") + } + objectWillChange.send() let userInfo: [String: Any] = [ From 7e07ff62c6800c0192a68c1fc7f504db272fad8e Mon Sep 17 00:00:00 2001 From: tisfeng Date: Sun, 7 Apr 2024 11:42:14 +0800 Subject: [PATCH 10/11] perf: rename to EZCustomOpenAIAvailableModelsKey --- .../Feature/Configuration/Configuration+Defaults.swift | 2 +- .../CustomOpenAIService+ConfigurableService.swift | 8 ++++---- Easydict/objc/Service/Model/EZConstKey.h | 2 +- Easydict/objc/Utility/EZLinkParser/EZSchemeParser.m | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Easydict/Swift/Feature/Configuration/Configuration+Defaults.swift b/Easydict/Swift/Feature/Configuration/Configuration+Defaults.swift index 248961966..301251c8f 100644 --- a/Easydict/Swift/Feature/Configuration/Configuration+Defaults.swift +++ b/Easydict/Swift/Feature/Configuration/Configuration+Defaults.swift @@ -226,7 +226,7 @@ extension Defaults.Keys { ) static let customOpenAIEndPoint = Key(EZCustomOpenAIEndPointKey, default: "") static let customOpenAIModel = Key(EZCustomOpenAIModelKey, default: "") - static let customOpenAIModelsAvailable = Key(EZCustomOpenAIModelssAvailableKey, default: "") + static let customOpenAIAvailableModels = Key(EZCustomOpenAIAvailableModelsKey, default: "") static let customOpenAIVaildModels = Key( EZCustomOpenAIValidModelsKey, default: [""] diff --git a/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift index a1a7ce33a..980755b7b 100644 --- a/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift +++ b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift @@ -38,7 +38,7 @@ private struct CustomOpenAIServiceConfigurationView: View { var body: some View { ServiceConfigurationSecretSectionView( service: service, - observeKeys: [.customOpenAIAPIKey, .customOpenAIEndPoint, .customOpenAIModelsAvailable] + observeKeys: [.customOpenAIAPIKey, .customOpenAIEndPoint, .customOpenAIAvailableModels] ) { // title ServiceConfigurationInputCell( @@ -125,7 +125,7 @@ private class CustomOpenAIViewModel: ObservableObject { } ) cancellables.append( - Defaults.publisher(.customOpenAIModelsAvailable) + Defaults.publisher(.customOpenAIAvailableModels) .removeDuplicates() .sink { _ in self.modelsTextChanged() @@ -138,7 +138,7 @@ private class CustomOpenAIViewModel: ObservableObject { let service: CustomOpenAIService @Default(.customOpenAIModel) var model - @Default(.customOpenAIModelsAvailable) var availableModels + @Default(.customOpenAIAvailableModels) var availableModels @Published var validModels: [String] = [] @@ -169,7 +169,7 @@ private class CustomOpenAIViewModel: ObservableObject { private func serviceConfigChanged() { if !validModels.contains(model) { - Defaults[.customOpenAIModelsAvailable] = "\(model), " + (availableModels ?? "") + Defaults[.customOpenAIAvailableModels] = "\(model), " + (availableModels ?? "") } // looks like Defaults changed but View not update in this case diff --git a/Easydict/objc/Service/Model/EZConstKey.h b/Easydict/objc/Service/Model/EZConstKey.h index 6d2de3344..9da1f3d74 100644 --- a/Easydict/objc/Service/Model/EZConstKey.h +++ b/Easydict/objc/Service/Model/EZConstKey.h @@ -34,7 +34,7 @@ static NSString *const EZCustomOpenAITranslationKey = @"EZCustomOpenAITranslatio static NSString *const EZCustomOpenAIDictionaryKey = @"EZCustomOpenAIDictionaryKey"; static NSString *const EZCustomOpenAISentenceKey = @"EZCustomOpenAISentenceKey"; static NSString *const EZCustomOpenAIServiceUsageStatusKey = @"EZCustomOpenAIServiceUsageStatusKey"; -static NSString *const EZCustomOpenAIModelssAvailableKey = @"EZCustomOpenAIModelssAvailableKey"; +static NSString *const EZCustomOpenAIAvailableModelsKey = @"EZCustomOpenAIAvailableModelsKey"; static NSString *const EZCustomOpenAIModelKey = @"EZCustomOpenAIModelKey"; static NSString *const EZCustomOpenAIValidModelsKey = @"EZCustomOpenAIValidModelsKey"; diff --git a/Easydict/objc/Utility/EZLinkParser/EZSchemeParser.m b/Easydict/objc/Utility/EZLinkParser/EZSchemeParser.m index 72ca12805..b3a4b3c8e 100644 --- a/Easydict/objc/Utility/EZLinkParser/EZSchemeParser.m +++ b/Easydict/objc/Utility/EZLinkParser/EZSchemeParser.m @@ -204,7 +204,7 @@ - (NSArray *)allowedReadWriteKeys { EZCustomOpenAINameKey, EZCustomOpenAIEndPointKey, EZCustomOpenAIAPIKey, - EZCustomOpenAIModelssAvailableKey, + EZCustomOpenAIAvailableModelsKey, EZCustomOpenAIModelKey, EZCustomOpenAITranslationKey, EZCustomOpenAIDictionaryKey, From 743fe9d5ebd37b4023cfc0f9cfc82961699082dd Mon Sep 17 00:00:00 2001 From: tisfeng Date: Sun, 7 Apr 2024 23:12:53 +0800 Subject: [PATCH 11/11] fix: app crashed when set OpenAI model to empty using URL scheme --- .../Service/OpenAI/BaseOpenAIService.swift | 6 +-- ...tomOpenAIService+ConfigurableService.swift | 36 +++++++++++------ .../OpenAIService+ConfigurableService.swift | 39 ++++++++++++------- .../EZBaseQueryViewController.m | 2 + 4 files changed, 52 insertions(+), 31 deletions(-) diff --git a/Easydict/Swift/Service/OpenAI/BaseOpenAIService.swift b/Easydict/Swift/Service/OpenAI/BaseOpenAIService.swift index 11d7f4e35..9659e784b 100644 --- a/Easydict/Swift/Service/OpenAI/BaseOpenAIService.swift +++ b/Easydict/Swift/Service/OpenAI/BaseOpenAIService.swift @@ -129,11 +129,7 @@ public class BaseOpenAIService: QueryService { var model: String { get { - var model = Defaults[.openAIModel] - if model.isEmpty { - model = availableModels.first ?? OpenAIModel.gpt3_5_turbo.rawValue - } - return model + Defaults[.openAIModel] } set { diff --git a/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift index 980755b7b..40517282b 100644 --- a/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift +++ b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/CustomOpenAIService+ConfigurableService.swift @@ -114,7 +114,7 @@ private class CustomOpenAIViewModel: ObservableObject { Defaults.publisher(.customOpenAIModel, options: []) .removeDuplicates() .sink { _ in - self.serviceConfigChanged() + self.modelChanged() } ) cancellables.append( @@ -151,16 +151,31 @@ private class CustomOpenAIViewModel: ObservableObject { private var cancellables: [AnyCancellable] = [] + private func modelChanged() { + if !validModels.contains(model) { + if model.isEmpty { + availableModels = "" + } else { + if availableModels?.isEmpty == true { + availableModels = model + } else { + availableModels = "\(model), " + (availableModels ?? "") + } + } + } + + serviceConfigChanged() + } + private func modelsTextChanged() { guard let availableModels else { return } - if availableModels.isEmpty { - model = "" - validModels = [] - return - } + validModels = availableModels.components(separatedBy: ",") .map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }.filter { !$0.isEmpty } - if validModels.count == 1 || !validModels.contains(model) { + + if validModels.isEmpty { + model = "" + } else if !validModels.contains(model) { model = validModels[0] } @@ -168,13 +183,10 @@ private class CustomOpenAIViewModel: ObservableObject { } private func serviceConfigChanged() { - if !validModels.contains(model) { - Defaults[.customOpenAIAvailableModels] = "\(model), " + (availableModels ?? "") - } - - // looks like Defaults changed but View not update in this case objectWillChange.send() + let userInfo: [String: Any] = [ + EZWindowTypeKey: service.windowType.rawValue, EZServiceTypeKey: service.serviceType().rawValue, ] let notification = Notification(name: .serviceHasUpdated, object: nil, userInfo: userInfo) diff --git a/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift index 0cd2abb38..6160e2245 100644 --- a/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift +++ b/Easydict/Swift/View/SettingView/Tabs/ServiceConfigurationView/QueryService+ConfigurableService/OpenAIService+ConfigurableService.swift @@ -107,7 +107,7 @@ private class OpenAIServiceViewModel: ObservableObject { Defaults.publisher(.openAIModel, options: []) .removeDuplicates() .sink { _ in - self.serviceConfigChanged() + self.modelChanged() } ) cancellables.append( @@ -137,16 +137,34 @@ private class OpenAIServiceViewModel: ObservableObject { private var cancellables: [AnyCancellable] = [] + private func modelChanged() { + // Currently, user of low os versions can change OpenAI model using URL scheme, like easydict://writeKeyValue?EZOpenAIModelKey=gpt-4 + // In this case, model may not be included in validModels, we need to handle it. + + if !validModels.contains(model) { + if model.isEmpty { + availableModels = "" + } else { + if availableModels?.isEmpty == true { + availableModels = model + } else { + availableModels = "\(model), " + (availableModels ?? "") + } + } + } + + serviceConfigChanged() + } + private func modelsTextChanged() { guard let availableModels else { return } - if availableModels.isEmpty { - model = "" - validModels = [] - return - } + validModels = availableModels.components(separatedBy: ",") .map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }.filter { !$0.isEmpty } - if validModels.count == 1 || !validModels.contains(model) { + + if validModels.isEmpty { + model = "" + } else if !validModels.contains(model) { model = validModels[0] } @@ -154,13 +172,6 @@ private class OpenAIServiceViewModel: ObservableObject { } private func serviceConfigChanged() { - // Currently, user of low os versions may change OpenAI model using URL scheme, like easydict://writeKeyValue?EZOpenAIModelKey=gpt-4 - // In this case, model may not be included in validModels, we need to handle it. - - if !validModels.contains(model) { - Defaults[.openAIAvailableModels] = "\(model), " + (availableModels ?? "") - } - objectWillChange.send() let userInfo: [String: Any] = [ diff --git a/Easydict/objc/ViewController/Window/BaseQueryWindow/EZBaseQueryViewController.m b/Easydict/objc/ViewController/Window/BaseQueryWindow/EZBaseQueryViewController.m index 09ee61680..3a414e75c 100644 --- a/Easydict/objc/ViewController/Window/BaseQueryWindow/EZBaseQueryViewController.m +++ b/Easydict/objc/ViewController/Window/BaseQueryWindow/EZBaseQueryViewController.m @@ -243,6 +243,8 @@ - (void)handleServiceUpdate:(NSNotification *)notification { NSDictionary *userInfo = notification.userInfo; EZWindowType type = [userInfo[EZWindowTypeKey] integerValue]; NSString *serviceType = [notification.userInfo objectForKey:EZServiceTypeKey]; + NSLog(@"update service: %@", serviceType); + if ([serviceType length] != 0) { [self reloadSingleService:serviceType]; return;