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

Add GeminiService Support #297

Merged
merged 26 commits into from
Jan 28, 2024
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
8e1171e
test Google Gemini
tisfeng Dec 22, 2023
db4c2a5
perf: use Task to wrap gemini async stream
tisfeng Dec 29, 2023
a353c4a
feat: initiate support for Google Gemini
Jerry23011 Jan 3, 2024
6b7a4d4
fix: build error
Jerry23011 Jan 3, 2024
3a51658
fix: missing GeminiTranslateType file
Jerry23011 Jan 3, 2024
15ee269
perf: restore CaiyunService
Jerry23011 Jan 3, 2024
3d7ca38
perf: improve gemini prompt
Jerry23011 Jan 3, 2024
6835cc3
refractor: define static property for translation prompt
Jerry23011 Jan 4, 2024
06d924b
perf: bump debug version
Jerry23011 Jan 5, 2024
b14666e
fix: resolve deprecated warnings
tisfeng Jan 7, 2024
bf330be
refractor: remove GeminiTranslateType
Jerry23011 Jan 8, 2024
3163dcb
perf: change min version back to 11.0
Jerry23011 Jan 10, 2024
8f5e20f
perf: resolve xcode warning
Jerry23011 Jan 10, 2024
eae5eef
perf: adjust gemini safety level
Jerry23011 Jan 24, 2024
0a43a63
Merge branch 'dev' into google-gemini
tisfeng Jan 25, 2024
b0103ba
refractor: manual error handling
Jerry23011 Jan 25, 2024
ac8a4ae
perf: improve error message for Gemini
tisfeng Jan 25, 2024
7ca612c
Merge branch 'dev' into google-gemini
tisfeng Jan 25, 2024
fcc3b11
fix: content streaming on macOS 12+
Jerry23011 Jan 26, 2024
c26d1f4
Merge branch 'dev' into google-gemini
Jerry23011 Jan 26, 2024
20f79ea
perf: improve code, remove logs
tisfeng Jan 26, 2024
cef098e
perf: update generative-ai-swift to 0.4.7
Jerry23011 Jan 26, 2024
8cd89c0
Merge branch 'dev' into google-gemini
tisfeng Jan 27, 2024
6044690
perf: rename variable
tisfeng Jan 27, 2024
127d4ba
Merge branch 'dev' into google-gemini
tisfeng Jan 27, 2024
dc3b3e8
Merge branch 'dev' into google-gemini
tisfeng Jan 28, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions Easydict.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
03008B2B2940D3230062B821 /* EZDeepLTranslate.m in Sources */ = {isa = PBXBuildFile; fileRef = 03008B2A2940D3230062B821 /* EZDeepLTranslate.m */; };
03008B2E2941956D0062B821 /* EZURLSchemeHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 03008B2D2941956D0062B821 /* EZURLSchemeHandler.m */; };
03008B3F29444B0A0062B821 /* NSView+EZAnimatedHidden.m in Sources */ = {isa = PBXBuildFile; fileRef = 03008B3E29444B0A0062B821 /* NSView+EZAnimatedHidden.m */; };
03022F192B3591AE00B63209 /* GoogleGenerativeAI in Frameworks */ = {isa = PBXBuildFile; productRef = 03022F182B3591AE00B63209 /* GoogleGenerativeAI */; };
03022F1C2B35DEBA00B63209 /* Hue in Frameworks */ = {isa = PBXBuildFile; productRef = 03022F1B2B35DEBA00B63209 /* Hue */; };
03022F1F2B36CF3100B63209 /* SwiftShell in Frameworks */ = {isa = PBXBuildFile; productRef = 03022F1E2B36CF3100B63209 /* SwiftShell */; };
03022F222B36D1A400B63209 /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = 03022F212B36D1A400B63209 /* SnapKit */; };
Expand Down Expand Up @@ -83,6 +84,7 @@
03882F9029D95044005B5A52 /* ToastWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 03882F8829D95044005B5A52 /* ToastWindowController.xib */; };
03882F9129D95044005B5A52 /* CTCommon.m in Sources */ = {isa = PBXBuildFile; fileRef = 03882F8929D95044005B5A52 /* CTCommon.m */; };
03882F9229D95044005B5A52 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03882F8C29D95044005B5A52 /* Info.plist */; };
038A72402B62C0B9004995E3 /* String+Regex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 038A723F2B62C0B9004995E3 /* String+Regex.swift */; };
038EA1AA2B41169C008A6DD1 /* ZipArchive in Frameworks */ = {isa = PBXBuildFile; productRef = 038EA1A92B41169C008A6DD1 /* ZipArchive */; };
038EA1AD2B41282F008A6DD1 /* MJExtension in Frameworks */ = {isa = PBXBuildFile; productRef = 038EA1AC2B41282F008A6DD1 /* MJExtension */; };
0396D611292C932F006A11D9 /* EZSelectLanguageCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 0396D610292C932F006A11D9 /* EZSelectLanguageCell.m */; };
Expand Down Expand Up @@ -260,6 +262,7 @@
9672D7D22B4008B40023B8FB /* MASShortcutBinder+EZMASShortcutBinder.m in Sources */ = {isa = PBXBuildFile; fileRef = 9672D7D12B4008B40023B8FB /* MASShortcutBinder+EZMASShortcutBinder.m */; };
A0B65CA0F31AC8ECFB8347CC /* Pods_EasydictTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 378E73A7EA8FC8FB9C975A63 /* Pods_EasydictTests.framework */; };
B87AC7E36367075BA5D13234 /* Pods_Easydict.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6372B33DFF803C7096A82250 /* Pods_Easydict.framework */; };
C415C0AD2B450D4800A9D231 /* GeminiService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415C0AC2B450D4800A9D231 /* GeminiService.swift */; };
C4DD01E92B12B3C80025EE8E /* TencentService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4DD01E82B12B3C80025EE8E /* TencentService.swift */; };
C4DD01EB2B12BA250025EE8E /* TencentResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4DD01EA2B12BA250025EE8E /* TencentResponse.swift */; };
C4DD01ED2B12BE9B0025EE8E /* TencentTranslateType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4DD01EC2B12BE9B0025EE8E /* TencentTranslateType.swift */; };
Expand Down Expand Up @@ -445,6 +448,7 @@
03882F8A29D95044005B5A52 /* CTView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CTView.h; sourceTree = "<group>"; };
03882F8B29D95044005B5A52 /* CoolToast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CoolToast.h; sourceTree = "<group>"; };
03882F8C29D95044005B5A52 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
038A723F2B62C0B9004995E3 /* String+Regex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Regex.swift"; sourceTree = "<group>"; };
0396D60F292C932F006A11D9 /* EZSelectLanguageCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EZSelectLanguageCell.h; sourceTree = "<group>"; };
0396D610292C932F006A11D9 /* EZSelectLanguageCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EZSelectLanguageCell.m; sourceTree = "<group>"; };
0396D613292CC4C3006A11D9 /* EZLocalStorage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EZLocalStorage.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -755,6 +759,7 @@
9672D7D02B4008B40023B8FB /* MASShortcutBinder+EZMASShortcutBinder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MASShortcutBinder+EZMASShortcutBinder.h"; sourceTree = "<group>"; };
9672D7D12B4008B40023B8FB /* MASShortcutBinder+EZMASShortcutBinder.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "MASShortcutBinder+EZMASShortcutBinder.m"; sourceTree = "<group>"; };
A230E9A2358C7FBC7FB26189 /* Pods-EasydictTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-EasydictTests.debug.xcconfig"; path = "Target Support Files/Pods-EasydictTests/Pods-EasydictTests.debug.xcconfig"; sourceTree = "<group>"; };
C415C0AC2B450D4800A9D231 /* GeminiService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeminiService.swift; sourceTree = "<group>"; };
C4DD01E82B12B3C80025EE8E /* TencentService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TencentService.swift; sourceTree = "<group>"; };
C4DD01EA2B12BA250025EE8E /* TencentResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TencentResponse.swift; sourceTree = "<group>"; };
C4DD01EC2B12BE9B0025EE8E /* TencentTranslateType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TencentTranslateType.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -806,6 +811,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
03022F192B3591AE00B63209 /* GoogleGenerativeAI in Frameworks */,
2721E4D02AFE920700A059AC /* Alamofire in Frameworks */,
03022F1F2B36CF3100B63209 /* SwiftShell in Frameworks */,
038030952B4106800009230C /* CocoaLumberjack in Frameworks */,
Expand Down Expand Up @@ -1198,6 +1204,14 @@
path = Kit;
sourceTree = "<group>";
};
038A723E2B62C07B004995E3 /* String */ = {
isa = PBXGroup;
children = (
038A723F2B62C0B9004995E3 /* String+Regex.swift */,
);
path = String;
sourceTree = "<group>";
};
0396D612292CBDFD006A11D9 /* Storage */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1317,6 +1331,7 @@
isa = PBXGroup;
children = (
62E2BF462B4082BA00E42D38 /* Ali */,
C415C0AB2B450C4500A9D231 /* Gemini */,
17BCAEF22B0DFF9000A7D372 /* Niutrans */,
2746AEBF2AF95040005FE0A1 /* Caiyun */,
C4DD01E72B12B3B00025EE8E /* Tencent */,
Expand Down Expand Up @@ -2166,6 +2181,14 @@
path = Pods;
sourceTree = "<group>";
};
C415C0AB2B450C4500A9D231 /* Gemini */ = {
isa = PBXGroup;
children = (
C415C0AC2B450D4800A9D231 /* GeminiService.swift */,
);
path = Gemini;
sourceTree = "<group>";
};
C4A40A9B2AC0168400B8E6EF /* Recovered References */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -2250,6 +2273,7 @@
EA9943E62B534D7C00EE7B97 /* Extensions */ = {
isa = PBXGroup;
children = (
038A723E2B62C07B004995E3 /* String */,
EAED41F02B54B1A60005FE0A /* QueryService+ConfigurableService */,
EA9943E72B534D8900EE7B97 /* LanguageDetectOptimizeExtensions.swift */,
EA9943ED2B5353AB00EE7B97 /* WindowTypeExtensions.swift */,
Expand Down Expand Up @@ -2375,6 +2399,7 @@
038EA1A92B41169C008A6DD1 /* ZipArchive */,
038EA1AC2B41282F008A6DD1 /* MJExtension */,
EA3B81FB2B52555C004C0E8B /* Defaults */,
03022F182B3591AE00B63209 /* GoogleGenerativeAI */,
);
productName = Bob;
productReference = C99EEB182385796700FEE666 /* Easydict-debug.app */;
Expand Down Expand Up @@ -2434,6 +2459,7 @@
038EA1A82B41169C008A6DD1 /* XCRemoteSwiftPackageReference "ZipArchive" */,
038EA1AB2B41282F008A6DD1 /* XCRemoteSwiftPackageReference "MJExtension" */,
EA3B81FA2B52555C004C0E8B /* XCRemoteSwiftPackageReference "Defaults" */,
03022F172B3591AE00B63209 /* XCRemoteSwiftPackageReference "generative-ai-swift" */,
);
productRefGroup = C99EEB192385796700FEE666 /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -2758,8 +2784,10 @@
03B0232229231FA6001C7E63 /* NSImage+MM.m in Sources */,
03BB2DEF29F59C8A00447EDD /* EZSymbolImageButton.m in Sources */,
0A2BA9642B4A3CCD002872A4 /* Notification+Name.swift in Sources */,
C415C0AD2B450D4800A9D231 /* GeminiService.swift in Sources */,
62A2D03F2A82967F007EEB01 /* EZBingRequest.m in Sources */,
03BDA7BE2A26DA280079D04F /* XPMCountedArgument.m in Sources */,
038A72402B62C0B9004995E3 /* String+Regex.swift in Sources */,
03D35DAA2AA6C49B00B023FE /* NSString+EZRegex.m in Sources */,
03B022FE29231FA6001C7E63 /* EZBaseQueryViewController.m in Sources */,
DC6D9C892B3969510055EFFC /* Appearance.swift in Sources */,
Expand Down Expand Up @@ -3318,6 +3346,14 @@
/* End XCConfigurationList section */

/* Begin XCRemoteSwiftPackageReference section */
03022F172B3591AE00B63209 /* XCRemoteSwiftPackageReference "generative-ai-swift" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/google/generative-ai-swift";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 0.4.4;
};
};
03022F1A2B35DEBA00B63209 /* XCRemoteSwiftPackageReference "Hue" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/zenangst/Hue";
Expand Down Expand Up @@ -3425,6 +3461,11 @@
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
03022F182B3591AE00B63209 /* GoogleGenerativeAI */ = {
isa = XCSwiftPackageProductDependency;
package = 03022F172B3591AE00B63209 /* XCRemoteSwiftPackageReference "generative-ai-swift" */;
productName = GoogleGenerativeAI;
};
03022F1B2B35DEBA00B63209 /* Hue */ = {
isa = XCSwiftPackageProductDependency;
package = 03022F1A2B35DEBA00B63209 /* XCRemoteSwiftPackageReference "Hue" */;
Expand Down
9 changes: 9 additions & 0 deletions Easydict.xcworkspace/xcshareddata/swiftpm/Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,15 @@
"version" : "10.19.1"
}
},
{
"identity" : "generative-ai-swift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/generative-ai-swift",
"state" : {
"revision" : "dcbdb5e591e1aa2bb68851dc7515f6b0a59026cd",
"version" : "0.4.7"
}
},
{
"identity" : "googleappmeasurement",
"kind" : "remoteSourceControl",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Gemini.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions Easydict/App/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -1315,6 +1315,23 @@
}
}
},
"gemini_translate" : {
"comment" : "The name of Gemini Translate",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Gemini Translate"
}
},
"zh-Hans" : {
"stringUnit" : {
"state" : "needs_review",
"value" : "Gemini 翻译"
}
}
}
},
"GitHub:" : {
"localizations" : {
"zh-Hans" : {
Expand Down
139 changes: 139 additions & 0 deletions Easydict/Feature/Service/Gemini/GeminiService.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
//
// GeminiService.swift
// Easydict
//
// Created by Jerry on 2024-01-02.
// Copyright © 2024 izual. All rights reserved.
//

import Foundation
import GoogleGenerativeAI

@objc(EZGeminiService)
public final class GeminiService: QueryService {
override public func serviceType() -> ServiceType {
.gemini
}

override public func link() -> String? {
"https://bard.google.com/chat"
}

override public func name() -> String {
NSLocalizedString("gemini_translate", comment: "The name of Gemini Translate")
}

// https://ai.google.dev/available_regions
private static let unsupportedLanguages: [Language] = [.persian, .filipino, .khmer, .lao, .malay, .mongolian, .burmese, .telugu, .tamil, .urdu]

override public func supportLanguagesDictionary() -> MMOrderedDictionary<AnyObject, AnyObject> {
// TODO: Replace MMOrderedDictionary.
let orderedDict = MMOrderedDictionary<AnyObject, AnyObject>()
for language in EZLanguageManager.shared().allLanguages {
let value = language.rawValue
if !GeminiService.unsupportedLanguages.contains(language) {
orderedDict.setObject(value as NSString, forKey: language.rawValue as NSString)
}
}

return orderedDict
}

override public func ocr(_: EZQueryModel) async throws -> EZOCRResult {
NSLog("Gemini Translate does not support OCR")
throw QueryServiceError.notSupported
}

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

override public func hasPrivateAPIKey() -> Bool {
if apiKey == defaultAPIKey {
return false
}
return true
}

private let defaultAPIKey = "" /* .decryptAES() */

// easydict://writeKeyValue?EZGeminiAPIKey=xxx
private var apiKey: String {
let apiKey = UserDefaults.standard.string(forKey: EZGeminiAPIKey)
if let apiKey, !apiKey.isEmpty {
return apiKey
} else {
return defaultAPIKey
}
}

// Set Gemini safety level to BLOCK_NONE
private static let harassmentSafety = SafetySetting(harmCategory: .harassment, threshold: .blockNone)
private static let hateSpeechSafety = SafetySetting(harmCategory: .hateSpeech, threshold: .blockNone)
private static let sexuallyExplicitSafety = SafetySetting(harmCategory: .sexuallyExplicit, threshold: .blockNone)
private static let dangerousContentSafety = SafetySetting(harmCategory: .dangerousContent, threshold: .blockNone)

private static let translationPrompt = "You are a translation expert proficient in various languages that can only translate text and cannot interpret it. You are able to accurately understand the meaning of proper nouns, idioms, metaphors, allusions or other obscure words in sentences and translate them into appropriate words by combining the context and language environment. The result of the translation should be natural and fluent, you can only return the translated text, do not show additional information and notes."

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

override public func translate(_ text: String, from: Language, to: Language, completion: @escaping (EZQueryResult, Error?) -> Void) {
Task {
do {
let prompt = GeminiService.translationPrompt + "Translate the following \(from.rawValue) text into \(to.rawValue): \(text)"
print("gemini prompt: \(prompt)")
let model = GenerativeModel(
name: "gemini-pro",
apiKey: apiKey,
safetySettings: [
GeminiService.harassmentSafety,
GeminiService.hateSpeechSafety,
GeminiService.sexuallyExplicitSafety,
GeminiService.dangerousContentSafety,
]
)

if #available(macOS 12.0, *) {
var resultString = ""
let outputContentStream = model.generateContentStream(prompt)

// stream response
for try await outputContent in outputContentStream {
guard let line = outputContent.text else {
return
}

resultString += line
result.translatedResults = [resultString]
completion(result, nil)
}

} else {
let outputContent = try await model.generateContent(prompt)
guard let line = outputContent.text else {
return
}

result.translatedResults = [line]
completion(result, nil)
}
} catch {
/**
https://github.com/google/generative-ai-swift/issues/89

String(describing: error)

"internalError(underlying: GoogleGenerativeAI.RPCError(httpResponseCode: 400, message: \"API key not valid. Please pass a valid API key.\", status: GoogleGenerativeAI.RPCStatus.invalidArgument))"
*/
let ezError = EZError(nsError: error)
let errorString = String(describing: error)
let errorMessage = errorString.extract(withPattern: "message: \"([^\"]*)\"") ?? errorString
ezError?.errorDataMessage = errorMessage

completion(result, ezError)
}
}
}
}
1 change: 1 addition & 0 deletions Easydict/Feature/Service/Model/EZConstKey.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ static NSString *const EZNiuTransAPIKey = @"EZNiuTransAPIKey";
static NSString *const EZCaiyunToken = @"EZCaiyunToken";
static NSString *const EZTencentSecretId = @"EZTencentSecretId";
static NSString *const EZTencentSecretKey = @"EZTencentSecretKey";
static NSString *const EZGeminiAPIKey = @"EZGeminiAPIKey";

static NSString *const EZAliAccessKeyId = @"EZAliAccessKeyId";
static NSString *const EZAliAccessKeySecret = @"EZAliAccessKeySecret";
Expand Down
1 change: 1 addition & 0 deletions Easydict/Feature/Service/Model/EZEnumTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ FOUNDATION_EXPORT EZServiceType const EZServiceTypeNiuTrans;
FOUNDATION_EXPORT EZServiceType const EZServiceTypeCaiyun;
FOUNDATION_EXPORT EZServiceType const EZServiceTypeTencent;
FOUNDATION_EXPORT EZServiceType const EZServiceTypeAli;
FOUNDATION_EXPORT EZServiceType const EZServiceTypeGemini;

FOUNDATION_EXPORT NSString *const EZQueryTextTypeKey;
FOUNDATION_EXPORT NSString *const EZIntelligentQueryTextTypeKey;
Expand Down
1 change: 1 addition & 0 deletions Easydict/Feature/Service/Model/EZEnumTypes.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
NSString *const EZServiceTypeCaiyun = @"Caiyun";
NSString *const EZServiceTypeTencent = @"Tencent";
NSString *const EZServiceTypeAli = @"Alibaba";
NSString *const EZServiceTypeGemini = @"Gemini";

NSString *const EZServiceTypeAppleDictionary = @"AppleDictionary";

Expand Down
1 change: 1 addition & 0 deletions Easydict/Feature/Service/Model/EZServiceTypes.m
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ + (instancetype)allocWithZone:(struct _NSZone *)zone {
EZServiceTypeCaiyun, [EZCaiyunService class],
EZServiceTypeTencent, [EZTencentService class],
EZServiceTypeAli, [EZAliService class],
EZServiceTypeGemini, [EZGeminiService class],
nil];
return allServiceDict;
}
Expand Down
Loading