Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: enable built-in AI to set usage status and dict option #525

Merged
merged 8 commits into from
Apr 29, 2024
8 changes: 8 additions & 0 deletions Easydict.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@
0361967B2A0037F700806370 /* NSData+EZMD5.m in Sources */ = {isa = PBXBuildFile; fileRef = 0361967A2A0037F700806370 /* NSData+EZMD5.m */; };
036A0DB82AD8403A006E6D4F /* NSString+EZHandleInputText.m in Sources */ = {isa = PBXBuildFile; fileRef = 036A0DB72AD8403A006E6D4F /* NSString+EZHandleInputText.m */; };
036A0DBB2AD941F9006E6D4F /* EZReplaceTextButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 036A0DBA2AD941F9006E6D4F /* EZReplaceTextButton.m */; };
036BCD482BDE5D0D009C893F /* BuiltInAIService+ConfigurableService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036BCD472BDE5D0D009C893F /* BuiltInAIService+ConfigurableService.swift */; };
036BCD4A2BDE8A96009C893F /* DefaultsStoredKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036BCD492BDE8A96009C893F /* DefaultsStoredKey.swift */; };
036D62812BCAB613002C95C7 /* BuiltInAIService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036D62802BCAB613002C95C7 /* BuiltInAIService.swift */; };
036E7D7B293F4FC8002675DF /* EZOpenLinkButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 036E7D7A293F4FC8002675DF /* EZOpenLinkButton.m */; };
03779F0E2BB256A7008D3C42 /* OpenAIService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03779F0B2BB256A7008D3C42 /* OpenAIService.swift */; };
Expand Down Expand Up @@ -455,6 +457,8 @@
036A0DB72AD8403A006E6D4F /* NSString+EZHandleInputText.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSString+EZHandleInputText.m"; sourceTree = "<group>"; };
036A0DB92AD941F9006E6D4F /* EZReplaceTextButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EZReplaceTextButton.h; sourceTree = "<group>"; };
036A0DBA2AD941F9006E6D4F /* EZReplaceTextButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EZReplaceTextButton.m; sourceTree = "<group>"; };
036BCD472BDE5D0D009C893F /* BuiltInAIService+ConfigurableService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BuiltInAIService+ConfigurableService.swift"; sourceTree = "<group>"; };
036BCD492BDE8A96009C893F /* DefaultsStoredKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsStoredKey.swift; sourceTree = "<group>"; };
036D62802BCAB613002C95C7 /* BuiltInAIService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuiltInAIService.swift; sourceTree = "<group>"; };
036E7D79293F4FC8002675DF /* EZOpenLinkButton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EZOpenLinkButton.h; sourceTree = "<group>"; };
036E7D7A293F4FC8002675DF /* EZOpenLinkButton.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EZOpenLinkButton.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2461,6 +2465,7 @@
DC46DF7F2B4417B900DEAE3E /* Configuration.swift */,
EA3B81F82B5254AA004C0E8B /* Configuration+Defaults.swift */,
DCF176F12B57CED700CA6026 /* Configuration+UserData.swift */,
036BCD492BDE8A96009C893F /* DefaultsStoredKey.swift */,
);
path = Configuration;
sourceTree = "<group>";
Expand Down Expand Up @@ -2516,6 +2521,7 @@
children = (
EAED41F12B54B39D0005FE0A /* OpenAIService+ConfigurableService.swift */,
0A318F3A2B8CCCCD0005EF77 /* CustomOpenAIService+ConfigurableService.swift */,
036BCD472BDE5D0D009C893F /* BuiltInAIService+ConfigurableService.swift */,
0AC8A8402B695480006DA5CC /* DeepLTranslate+ConfigurableService.swift */,
0AC8A8342B6641A7006DA5CC /* TencentService+ConfigurableService.swift */,
0AC8A8362B6659A8006DA5CC /* NiuTransTranslate+ConfigurableService.swift */,
Expand Down Expand Up @@ -2973,6 +2979,7 @@
EAED41EF2B54B1430005FE0A /* ConfigurableService.swift in Sources */,
03BD2825294875AE00F5891A /* EZMyLabel.m in Sources */,
03B0233029231FA6001C7E63 /* MMCrashUncaughtExceptionHandler.m in Sources */,
036BCD482BDE5D0D009C893F /* BuiltInAIService+ConfigurableService.swift in Sources */,
03D5FCFF2A5EF4E400AD26BE /* EZDeviceSystemInfo.m in Sources */,
27FE95272B3DC55F000AD654 /* EasydictApp.swift in Sources */,
03882F9129D95044005B5A52 /* CTCommon.m in Sources */,
Expand Down Expand Up @@ -3030,6 +3037,7 @@
03DC7C5E2A3ABE28000BF7C9 /* EZConstKey.m in Sources */,
62E2BF4C2B4082BA00E42D38 /* AliTranslateType.swift in Sources */,
EA3B81F92B5254AA004C0E8B /* Configuration+Defaults.swift in Sources */,
036BCD4A2BDE8A96009C893F /* DefaultsStoredKey.swift in Sources */,
03E3E7C22ADE318800812C84 /* EZQueryMenuTextView.m in Sources */,
03B0231829231FA6001C7E63 /* SnipWindowController.m in Sources */,
03542A342936F70F00C34C33 /* EZLanguageManager.m in Sources */,
Expand Down
54 changes: 44 additions & 10 deletions Easydict/Swift/Feature/Configuration/Configuration+Defaults.swift
Original file line number Diff line number Diff line change
Expand Up @@ -216,12 +216,21 @@ class ShortcutWrapper<T: KeyCombo> {
extension Defaults.Keys {
// OpenAI
static let openAIAPIKey = Key<String?>(EZOpenAIAPIKey)
static let openAITranslation = Key<String>(EZOpenAITranslationKey, default: "1")
static let openAIDictionary = Key<String>(EZOpenAIDictionaryKey, default: "1")
static let openAISentence = Key<String>(EZOpenAISentenceKey, default: "1")
static let openAITranslation = Key<String>(
translationStoredKey(.openAI),
default: "1"
)
static let openAIDictionary = Key<String>(
dictionaryStoredKey(.openAI),
default: "1"
)
static let openAISentence = Key<String>(
sentenceStoredKey(.openAI),
default: "1"
)
static let openAIServiceUsageStatus = Key<OpenAIUsageStats>(
EZOpenAIServiceUsageStatusKey,
default: OpenAIUsageStats.default
serviceUsageStatusStoredKey(.openAI),
default: .default
)
static let openAIEndPoint = Key<String?>(EZOpenAIEndPointKey)
static let openAIModel = Key<String>(EZOpenAIModelKey, default: OpenAIModel.gpt3_5_turbo.rawValue)
Expand All @@ -240,12 +249,21 @@ extension Defaults.Keys {
default: NSLocalizedString("custom_openai", comment: "")
)
static let customOpenAIAPIKey = Key<String?>(EZCustomOpenAIAPIKey, default: "")
static let customOpenAITranslation = Key<String>(EZCustomOpenAITranslationKey, default: "1")
static let customOpenAIDictionary = Key<String>(EZCustomOpenAISentenceKey, default: "1")
static let customOpenAISentence = Key<String>(EZCustomOpenAISentenceKey, default: "1")
static let customOpenAITranslation = Key<String>(
translationStoredKey(.customOpenAI),
default: "1"
)
static let customOpenAIDictionary = Key<String>(
dictionaryStoredKey(.customOpenAI),
default: "0"
)
static let customOpenAISentence = Key<String>(
sentenceStoredKey(.customOpenAI),
default: "0"
)
static let customOpenAIServiceUsageStatus = Key<OpenAIUsageStats>(
EZCustomOpenAIServiceUsageStatusKey,
default: OpenAIUsageStats.default
serviceUsageStatusStoredKey(.builtInAI),
default: .default
)
static let customOpenAIEndPoint = Key<String?>(EZCustomOpenAIEndPointKey, default: "")
static let customOpenAIModel = Key<String>(EZCustomOpenAIModelKey, default: "")
Expand All @@ -257,6 +275,22 @@ extension Defaults.Keys {

// Built-in AI
static let builtInAIModel = Key<String>(EZBuiltInAIModelKey, default: "")
static let builtInAITranslation = Key<String>(
translationStoredKey(.builtInAI),
default: "1"
)
static let builtInAIDictionary = Key<String>(
dictionaryStoredKey(.builtInAI),
default: "0"
)
static let builtInAISentence = Key<String>(
sentenceStoredKey(.builtInAI),
default: "0"
)
static let builtInAIServiceUsageStatus = Key<OpenAIUsageStats>(
serviceUsageStatusStoredKey(.builtInAI),
default: .default
)

// DeepL
static let deepLAuth = Key<String?>(EZDeepLAuthKey)
Expand Down
46 changes: 46 additions & 0 deletions Easydict/Swift/Feature/Configuration/DefaultsStoredKey.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// DefaultsStoredKey.swift
// Easydict
//
// Created by tisfeng on 2024/4/28.
// Copyright © 2024 izual. All rights reserved.
//

import Foundation

func storedKey(_ key: String, serviceType: ServiceType) -> String {
// This key should be compatible with existing OpenAI config keys
// EZOpenAIServiceUsageStatusKey
// EZOpenAIDictionaryKey
"EZ" + serviceType.rawValue + key + "Key"
}

func serviceUsageStatusStoredKey(_ serviceType: ServiceType) -> String {
storedKey(EZServiceUsageStatusKey, serviceType: serviceType)
}

func translationStoredKey(_ serviceType: ServiceType) -> String {
storedKey(EZTranslationKey, serviceType: serviceType)
}

func sentenceStoredKey(_ serviceType: ServiceType) -> String {
storedKey(EZSentenceKey, serviceType: serviceType)
}

func dictionaryStoredKey(_ serviceType: ServiceType) -> String {
storedKey(EZDictionaryKey, serviceType: serviceType)
}

extension UserDefaults {
static func bool(forKey key: String, serviceType: ServiceType) -> Bool {
let key = storedKey(key, serviceType: serviceType)
let value = standard.bool(forKey: key)
return value
}

static func string(forKey key: String, serviceType: ServiceType) -> String? {
let key = storedKey(key, serviceType: serviceType)
let value = standard.string(forKey: key)
return value
}
}
41 changes: 14 additions & 27 deletions Easydict/Swift/Service/BuiltInAI/BuiltInAIService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ class BuiltInAIService: BaseOpenAIService {
NSLocalizedString("built_in_ai", comment: "")
}

override public func serviceType() -> ServiceType {
.builtInAI
}

// MARK: Internal

override var apiKey: String {
Expand All @@ -43,40 +47,23 @@ class BuiltInAIService: BaseOpenAIService {

override var availableModels: [String] {
[
// Groq free models https://console.groq.com/docs/models
"llama3-70b-8192",
"mixtral-8x7b-32768",

// It seems that 5.2 will start charging 😥 https://ai.google.dev/pricing?hl=zh-cn
"gemini-pro",

/**
阿里通义千问 DashScope 限时免费开放中 https://help.aliyun.com/zh/dashscope/developer-reference/tongyi-qianwen-7b-14b-72b-metering-and-billing
阿里通义千问 DashScope 限时免费开放中 https://help.aliyun.com/zh/dashscope/developer-reference/tongyi-qianwen-7b-14b-72b-metering-and-billing

通义千问开源系列,开通DashScope即获赠总计 1,000,000 tokens 限时免费使用额度,有效期30天。(qwen1.5-32b-chat模型目前限时免费开放中)
*/
通义千问开源系列,开通DashScope即获赠总计 1,000,000 tokens 限时免费使用额度,有效期30天。(qwen1.5-32b-chat模型目前限时免费开放中)
*/
"qwen1.5-32b-chat", // 目前限时免费开放中
"qwen-turbo", // free total 2,000,000 tokens, until 8.12
"baichuan2-13b-chat-v1", // free until 8.12, total 1,000,000 tokens
"deepseek-7b-chat", // 开通DashScope即获赠总计 1,000,000 tokens 限时免费使用额度,有效期180天。
"internlm-7b-chat", // 开通DashScope即获赠总计 1,000,000 tokens 限时免费使用额度,有效期180天。

// Groq free models https://console.groq.com/docs/models
"mixtral-8x7b-32768",
"llama3-70b-8192",

// It seems that 5.2 will start charging 😥 https://ai.google.dev/pricing?hl=zh-cn
"gemini-pro",
]
}

override func serviceType() -> ServiceType {
.builtInAI
}

override func intelligentQueryTextType() -> EZQueryTextType {
Configuration.shared.intelligentQueryTextTypeForServiceType(serviceType())
}

override func queryTextType() -> EZQueryTextType {
// Since some models are not good at dictionary, so we only use translation here.
[.translation]
}

override func serviceUsageStatus() -> EZServiceUsageStatus {
.default
}
}
60 changes: 4 additions & 56 deletions Easydict/Swift/Service/CustomOpenAI/CustomOpenAIService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,6 @@ import Foundation

@objc(EZCustomOpenAIService)
class CustomOpenAIService: BaseOpenAIService {
// MARK: Lifecycle

override init() {
super.init()
}

// MARK: Public

override public func name() -> String {
Expand All @@ -29,6 +23,10 @@ class CustomOpenAIService: BaseOpenAIService {
return NSLocalizedString("custom_openai", comment: "The name of Custom OpenAI Translate")
}

override public func serviceType() -> ServiceType {
.customOpenAI
}

// MARK: Internal

override var apiKey: String {
Expand All @@ -52,54 +50,4 @@ class CustomOpenAIService: BaseOpenAIService {
override var availableModels: [String] {
Defaults[.customOpenAIVaildModels]
}

override func serviceType() -> ServiceType {
.customOpenAI
}

override func intelligentQueryTextType() -> EZQueryTextType {
Configuration.shared.intelligentQueryTextTypeForServiceType(serviceType())
}

override func supportLanguagesDictionary() -> MMOrderedDictionary<AnyObject, AnyObject> {
let orderedDict = MMOrderedDictionary<AnyObject, AnyObject>()
for language in EZLanguageManager.shared().allLanguages {
var value = language.rawValue
if language == Language.classicalChinese {
value = Language.wenyanwen
}

if language != Language.burmese {
orderedDict.setObject(value as NSString, forKey: language.rawValue as NSString)
}
}

return orderedDict
}

override func queryTextType() -> EZQueryTextType {
var typeOptions: EZQueryTextType = []
let isTranslationEnabled = Defaults[.customOpenAITranslation] == "1"
let isDictionaryEnabled = Defaults[.customOpenAIDictionary] == "1"
let isSentenceEnabled = Defaults[.customOpenAISentence] == "1"
if isTranslationEnabled {
typeOptions.insert(.translation)
}
if isDictionaryEnabled {
typeOptions.insert(.dictionary)
}
if isSentenceEnabled {
typeOptions.insert(.sentence)
}
if typeOptions == [] {
typeOptions = [.translation]
}
return typeOptions
}

override func serviceUsageStatus() -> EZServiceUsageStatus {
let customOpenAIServiceUsageStatus = Defaults[.customOpenAIServiceUsageStatus]
guard let value = UInt(customOpenAIServiceUsageStatus.rawValue) else { return .default }
return EZServiceUsageStatus(rawValue: value) ?? .default
}
}
40 changes: 31 additions & 9 deletions Easydict/Swift/Service/OpenAI/BaseOpenAIService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import OpenAI
public class BaseOpenAIService: QueryService {
// MARK: Public

public override func isStream() -> Bool {
override public func isStream() -> Bool {
true
}

Expand All @@ -43,6 +43,32 @@ public class BaseOpenAIService: QueryService {
return orderedDict
}

override public func queryTextType() -> EZQueryTextType {
var typeOptions: EZQueryTextType = []

let isTranslationEnabled = UserDefaults.bool(forKey: EZTranslationKey, serviceType: serviceType())
let isSentenceEnabled = UserDefaults.bool(forKey: EZSentenceKey, serviceType: serviceType())
let isDictionaryEnabled = UserDefaults.bool(forKey: EZDictionaryKey, serviceType: serviceType())

if isTranslationEnabled {
typeOptions.insert(.translation)
}
if isSentenceEnabled {
typeOptions.insert(.sentence)
}
if isDictionaryEnabled {
typeOptions.insert(.dictionary)
}

return typeOptions
}

override public func serviceUsageStatus() -> EZServiceUsageStatus {
let usageStatus = UserDefaults.string(forKey: EZServiceUsageStatusKey, serviceType: serviceType()) ?? ""
guard let value = UInt(usageStatus) else { return .default }
return EZServiceUsageStatus(rawValue: value) ?? .default
}

// swiftlint:disable identifier_name
override public func translate(
_ text: String,
Expand All @@ -63,7 +89,7 @@ public class BaseOpenAIService: QueryService {
result.to = to
result.isStreamFinished = false

let queryType = queryTextType(text: text, from: from, to: to)
let queryType = queryType(text: text, from: from, to: to)
let chats = chatMessages(queryType: queryType, text: text, from: from, to: to)
let query = ChatQuery(messages: chats, model: model, temperature: 0)
let openAI = OpenAI(apiToken: apiKey)
Expand Down Expand Up @@ -138,7 +164,8 @@ public class BaseOpenAIService: QueryService {

// MARK: Private

private func queryTextType(text: String, from: Language, to _: Language) -> EZQueryTextType {
/// Get query type by text and from && to langauge.
private func queryType(text: String, from: Language, to _: Language) -> EZQueryTextType {
let enableDictionary = queryTextType().contains(.dictionary)
var isQueryDictionary = false
if enableDictionary {
Expand All @@ -160,12 +187,7 @@ public class BaseOpenAIService: QueryService {
}
}

let enableTranslation = queryTextType().contains(.translation)
if enableTranslation {
return .translation
}

return []
return .translation
}

private func handleResult(
Expand Down
Loading