Skip to content

Commit

Permalink
Add basic support for CaiyunService
Browse files Browse the repository at this point in the history
Add basic implementation for Caiyun Service

Fix CR suggestion

Add caiyun service transtype support

perf: split caiyun test token to more parts

perf: improve caiyun supported langauges dict

Update Easydict/Feature/Service/Caiyun/CaiyunService.swift

Co-authored-by: Kyle <kyle201817146@gmail.com>
  • Loading branch information
Kyle-Ye committed Nov 23, 2023
1 parent d0d4583 commit 4762aec
Show file tree
Hide file tree
Showing 10 changed files with 240 additions and 3 deletions.
35 changes: 35 additions & 0 deletions Easydict.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,10 @@
03F639952AA6CFBB009B9914 /* EZBingConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 03F639942AA6CFBB009B9914 /* EZBingConfig.m */; };
17BCAEF72B0DFF9000A7D372 /* EZNiuTransTranslateResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 17BCAEF52B0DFF9000A7D372 /* EZNiuTransTranslateResponse.m */; };
17BCAEF82B0DFF9000A7D372 /* EZNiuTransTranslate.m in Sources */ = {isa = PBXBuildFile; fileRef = 17BCAEF62B0DFF9000A7D372 /* EZNiuTransTranslate.m */; };
2721E4D02AFE920700A059AC /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 2721E4CF2AFE920700A059AC /* Alamofire */; };
2746AEC12AF95138005FE0A1 /* CaiyunService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2746AEC02AF95138005FE0A1 /* CaiyunService.swift */; };
278322602B0FB0EA0026644C /* CaiyunResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2783225F2B0FB0EA0026644C /* CaiyunResponse.swift */; };
278322622B0FB8EF0026644C /* CaiyunTranslateType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 278322612B0FB8EF0026644C /* CaiyunTranslateType.swift */; };
27B7919E2AEC36A1006E07C6 /* Easydict.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 27B7919C2AEC36A1006E07C6 /* Easydict.xcconfig */; };
27B7919F2AEC36A1006E07C6 /* Easydict-debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 27B7919D2AEC36A1006E07C6 /* Easydict-debug.xcconfig */; };
6220AD5B2A82812300BBFB52 /* EZBingService.m in Sources */ = {isa = PBXBuildFile; fileRef = 6220AD5A2A82812300BBFB52 /* EZBingService.m */; };
Expand Down Expand Up @@ -637,6 +640,8 @@
17BCAEF52B0DFF9000A7D372 /* EZNiuTransTranslateResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EZNiuTransTranslateResponse.m; sourceTree = "<group>"; };
17BCAEF62B0DFF9000A7D372 /* EZNiuTransTranslate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EZNiuTransTranslate.m; sourceTree = "<group>"; };
2746AEC02AF95138005FE0A1 /* CaiyunService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaiyunService.swift; sourceTree = "<group>"; };
2783225F2B0FB0EA0026644C /* CaiyunResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaiyunResponse.swift; sourceTree = "<group>"; };
278322612B0FB8EF0026644C /* CaiyunTranslateType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaiyunTranslateType.swift; sourceTree = "<group>"; };
27B7919C2AEC36A1006E07C6 /* Easydict.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Easydict.xcconfig; sourceTree = "<group>"; };
27B7919D2AEC36A1006E07C6 /* Easydict-debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Easydict-debug.xcconfig"; sourceTree = "<group>"; };
27B791A02AEC3A5C006E07C6 /* Easydict-debug.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = "Easydict-debug.entitlements"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -679,6 +684,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
2721E4D02AFE920700A059AC /* Alamofire in Frameworks */,
B87AC7E36367075BA5D13234 /* Pods_Easydict.framework in Frameworks */,
03B63ABF2A86967800E155ED /* CoreServices.framework in Frameworks */,
);
Expand Down Expand Up @@ -1835,6 +1841,8 @@
isa = PBXGroup;
children = (
2746AEC02AF95138005FE0A1 /* CaiyunService.swift */,
2783225F2B0FB0EA0026644C /* CaiyunResponse.swift */,
278322612B0FB8EF0026644C /* CaiyunTranslateType.swift */,
);
path = Caiyun;
sourceTree = "<group>";
Expand Down Expand Up @@ -1968,6 +1976,9 @@
dependencies = (
);
name = Easydict;
packageProductDependencies = (
2721E4CF2AFE920700A059AC /* Alamofire */,
);
productName = Bob;
productReference = C99EEB182385796700FEE666 /* Easydict-Debug.app */;
productType = "com.apple.product-type.application";
Expand Down Expand Up @@ -2006,6 +2017,9 @@
"zh-Hans",
);
mainGroup = C99EEB0F2385796700FEE666;
packageReferences = (
2721E4CE2AFE920700A059AC /* XCRemoteSwiftPackageReference "Alamofire" */,
);
productRefGroup = C99EEB192385796700FEE666 /* Products */;
projectDirPath = "";
projectRoot = "";
Expand Down Expand Up @@ -2252,6 +2266,7 @@
03B0232329231FA6001C7E63 /* NSString+MM.m in Sources */,
036196772A000F5900806370 /* NSData+CommonCrypto.m in Sources */,
03882F8D29D95044005B5A52 /* CTView.m in Sources */,
278322602B0FB0EA0026644C /* CaiyunResponse.swift in Sources */,
03B3B8B52925DD3D00168E8D /* EZPopButtonViewController.m in Sources */,
03542A5B2938DA2B00C34C33 /* EZDetectLanguageButton.m in Sources */,
03B0232929231FA6001C7E63 /* NSDictionary+MM.m in Sources */,
Expand Down Expand Up @@ -2324,6 +2339,7 @@
17BCAEF72B0DFF9000A7D372 /* EZNiuTransTranslateResponse.m in Sources */,
03BDA7B82A26DA280079D04F /* XPMValuedArgument.m in Sources */,
036196762A000F5900806370 /* NSData+Base64.m in Sources */,
278322622B0FB8EF0026644C /* CaiyunTranslateType.swift in Sources */,
03BDA7BA2A26DA280079D04F /* XPMMutableAttributedArray.m in Sources */,
037852B629588EDE00D0E2CF /* EZCustomTableRowView.m in Sources */,
03F0DB382953428300EBF9C1 /* EZLog.m in Sources */,
Expand Down Expand Up @@ -2730,6 +2746,25 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */

/* Begin XCRemoteSwiftPackageReference section */
2721E4CE2AFE920700A059AC /* XCRemoteSwiftPackageReference "Alamofire" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/Alamofire/Alamofire.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 5.8.1;
};
};
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
2721E4CF2AFE920700A059AC /* Alamofire */ = {
isa = XCSwiftPackageProductDependency;
package = 2721E4CE2AFE920700A059AC /* XCRemoteSwiftPackageReference "Alamofire" */;
productName = Alamofire;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = C99EEB102385796700FEE666 /* Project object */;
}
2 changes: 2 additions & 0 deletions Easydict/App/Easydict-Bridging-Header.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@
#import "MMLog.h"

#import "EZQueryService.h"
#import "EZConstKey.h"
#import "FWEncryptorAES.h"
11 changes: 11 additions & 0 deletions Easydict/App/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,17 @@
}
}
},
"caiyun_translate" : {
"comment" : "The name of Caiyun Translate",
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "彩云小译"
}
}
}
},
"cancel" : {
"localizations" : {
"en" : {
Expand Down
15 changes: 15 additions & 0 deletions Easydict/Feature/Service/Caiyun/CaiyunResponse.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// CaiyunResponse.swift
// Easydict
//
// Created by Kyle on 2023/11/24.
// Copyright © 2023 izual. All rights reserved.
//

import Foundation

struct CaiyunResponse: Codable {
var confidence: Double
var rc: Int
var target: [String]
}
99 changes: 99 additions & 0 deletions Easydict/Feature/Service/Caiyun/CaiyunService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,108 @@
// Copyright © 2023 izual. All rights reserved.
//

import Alamofire
import Foundation

@objc(EZCaiyunService)
public final class CaiyunService: QueryService {
override public func serviceType() -> ServiceType {
.caiyun
}

override public func link() -> String? {
"https://fanyi.caiyunapp.com"
}

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

override public func supportLanguagesDictionary() -> MMOrderedDictionary<AnyObject, AnyObject> {
// TODO: Replace MMOrderedDictionary in the API
let orderedDict = MMOrderedDictionary<AnyObject, AnyObject>()
let dic: [Language: String] = [
.auto: "auto",
.simplifiedChinese: "zh",
.english: "en",
.japanese: "ja",
]
dic.forEach { key, value in
orderedDict.setObject(value as NSString, forKey: key.rawValue as NSString)
}
return orderedDict
}

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

private var apiEndPoint = "https://api.interpreter.caiyunai.com/v1/translator"

/// Official Test Token for Caiyun
private static let defaultTestToken = FWEncryptorAES.decryptText("hlvDXvvfjeFTjMjhkB5HMlyPWEXQhn3U1r+qIqn/YAk=", key: "Easydict")

private var token: String {
let token = UserDefaults.standard.string(forKey: EZCaiyunAPIKey)
if let token, !token.isEmpty {
return token
} else {
return CaiyunService.defaultTestToken
}
}

public override func translate(_ text: String, from: Language, to: Language, completion: @escaping (EZQueryResult, Error?) -> Void) {
if prehandleQueryTextLanguage(text, autoConvertChineseText: false, from: from, to: to, completion: completion) {
return
}
let transType = CaiyunTranslateType.type(from: from, to: to)
guard transType != .unsupported else {
result.errorType = .unsupportedLanguage
result.errorMessage = "不支持的翻译类型: \(from.rawValue) --> \(to.rawValue)"
completion(result, nil)
return
}

let parameters: [String: Any] = [
"source": text.split(separator: "\n"),
"trans_type": transType.rawValue,
"media": "text",
"request_id": "Easydict",
"detect": true,
]
let headers: HTTPHeaders = [
"content-type": "application/json",
"x-authorization": "token " + token,
]

let request = AF.request(apiEndPoint,
method: .post,
parameters: parameters,
encoding: JSONEncoding.default,
headers: headers)
.validate()
.responseDecodable(of: CaiyunResponse.self) { [weak self] response in
guard let self else { return }
let result = self.result
switch response.result {
case let .success(value):
result.from = from
result.to = to
result.queryText = text
result.translatedResults = value.target
completion(result, nil)
case let .failure(error):
NSLog("Caiyun lookup error \(error)")
completion(result, error)
}
}
queryModel.setStop({
request.cancel()
}, serviceType: serviceType().rawValue)
}
}

enum QueryServiceError: Error {
case notSupported
}
73 changes: 73 additions & 0 deletions Easydict/Feature/Service/Caiyun/CaiyunTranslateType.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//
// CaiyunTranslateType.swift
// Easydict
//
// Created by Kyle on 2023/11/24.
// Copyright © 2023 izual. All rights reserved.
//

import Foundation

struct CaiyunTranslateType: RawRepresentable {
var rawValue: String

static let unsupported = CaiyunTranslateType(rawValue: "unsupported")

// Align with the web interface
static func type(from: Language, to: Language) -> CaiyunTranslateType {
if from.isChinese {
guard [Language.english, .japanese, .korean, .spanish, .french, .russian].contains(to) else {
return .unsupported
}
} else if from == .english {
guard [Language.simplifiedChinese, .spanish, .french, .russian].contains(to) else {
return .unsupported
}
} else if from == .japanese {
guard [Language.simplifiedChinese].contains(to) else {
return .unsupported
}
} else if from == .korean {
guard [Language.simplifiedChinese].contains(to) else {
return .unsupported
}
} else if from == .spanish {
guard [Language.simplifiedChinese, .english, .french, .russian].contains(to) else {
return .unsupported
}
} else if from == .french {
guard [Language.simplifiedChinese, .english, .spanish, .russian].contains(to) else {
return .unsupported
}
} else if from == .french {
guard [Language.simplifiedChinese, .english, .spanish, .french].contains(to) else {
return .unsupported
}
} else if from == .auto {
guard [Language.simplifiedChinese, .english, .japanese, .korean, .spanish, .french, .russian].contains(to) else {
return .unsupported
}
}
return CaiyunTranslateType(rawValue: "\(from.caiyunValue)2\(to.caiyunValue)")
}
}

extension Language {
var isChinese: Bool {
[Language.classicalChinese, .simplifiedChinese, .traditionalChinese].contains(self)
}

var caiyunValue: String {
switch self {
case .classicalChinese, .simplifiedChinese, .traditionalChinese: return "zh"
case .english: return "en"
case .japanese: return "ja"
case .korean: return "ko"
case .spanish: return "es"
case .french: return "fr"
case .russian: return "ru"
case .auto: return "auto"
default: return ""
}
}
}
2 changes: 1 addition & 1 deletion Easydict/Feature/Service/Language/EZLanguageModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
NS_ASSUME_NONNULL_BEGIN

// Refer Apple NLLanguage.
typedef NSString *EZLanguage NS_STRING_ENUM;
typedef NSString *EZLanguage NS_STRING_ENUM NS_SWIFT_NAME(Language);

// 目前总计支持 49 种语言:简体中文,繁体中文,文言文,英语,日语,韩语,法语,西班牙语,葡萄牙语,意大利语,德语,俄语,阿拉伯语,瑞典语,罗马尼亚语,泰语,斯洛伐克语,荷兰语,匈牙利语,希腊语,丹麦语,芬兰语,波兰语,捷克语,土耳其语,立陶宛语,拉脱维亚语,乌克兰语,保加利亚语,印尼语,马来语,斯洛文尼亚语,爱沙尼亚语,越南语,波斯语,印地语,泰卢固语,泰米尔语,乌尔都语,菲律宾语,高棉语,老挝语,孟加拉语,缅甸语,挪威语,塞尔维亚语,克罗地亚语,蒙古语,希伯来语。

Expand Down
1 change: 1 addition & 0 deletions Easydict/Feature/Service/Model/EZConstKey.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ static NSString *const EZDeepLAuthKey = @"EZDeepLAuthKey";

static NSString *const EZBingCookieKey = @"EZBingCookieKey";
static NSString *const EZNiuTransAPIKey = @"EZNiuTransAPIKey";
static NSString *const EZCaiyunAPIKey = @"EZCaiyunAPIKey";


@interface EZConstKey : NSObject
Expand Down
2 changes: 1 addition & 1 deletion Easydict/Feature/Service/Model/EZEnumTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ typedef NS_ENUM(NSUInteger, EZShowWindowPosition) {

FOUNDATION_EXPORT NSString *const EZServiceTypeKey;

typedef NSString *EZServiceType NS_STRING_ENUM;
typedef NSString *EZServiceType NS_STRING_ENUM NS_SWIFT_NAME(ServiceType);
FOUNDATION_EXPORT EZServiceType const EZServiceTypeGoogle;
FOUNDATION_EXPORT EZServiceType const EZServiceTypeBaidu;
FOUNDATION_EXPORT EZServiceType const EZServiceTypeYoudao;
Expand Down
3 changes: 2 additions & 1 deletion Easydict/Feature/Utility/EZLinkParser/EZSchemeParser.m
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,8 @@ - (NSArray *)allowedReadWriteKeys {
EZDeepLAuthKey,
EZDeepLTranslationAPIKey,
EZNiuTransAPIKey,

// EZCaiyunAPIKey,

EZIntelligentQueryModeKey,

EZBingCookieKey,
Expand Down

0 comments on commit 4762aec

Please sign in to comment.