Skip to content

Commit

Permalink
feat: enable custom ai service duplicatable
Browse files Browse the repository at this point in the history
  • Loading branch information
phlpsong committed Aug 25, 2024
1 parent 85a940c commit 1b582f0
Show file tree
Hide file tree
Showing 15 changed files with 206 additions and 52 deletions.
34 changes: 33 additions & 1 deletion Easydict/App/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -5124,6 +5124,38 @@
}
}
},
"service.configuration.duplicate" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Duplicate"
}
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "复制"
}
}
}
},
"service.configuration.remove" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Remove"
}
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "删除"
}
}
}
},
"service.configuration.validation_fail" : {
"localizations" : {
"en" : {
Expand Down Expand Up @@ -7864,4 +7896,4 @@
}
},
"version" : "1.0"
}
}
14 changes: 10 additions & 4 deletions Easydict/Swift/Feature/Configuration/Configuration+Defaults.swift
Original file line number Diff line number Diff line change
Expand Up @@ -212,14 +212,20 @@ class ShortcutWrapper<T: KeyCombo> {
}
}

func defaultsKey<T>(_ key: StoredKey, serviceType: ServiceType) -> Defaults.Key<T?> {
defaultsKey(key, serviceType: serviceType, defaultValue: nil)
func defaultsKey<T>(_ key: StoredKey, serviceType: ServiceType, id: String) -> Defaults.Key<T?> {
defaultsKey(key, serviceType: serviceType, id: id, defaultValue: nil)
}

func defaultsKey<T: _DefaultsSerializable>(_ key: StoredKey, serviceType: ServiceType, defaultValue: T) -> Defaults
func defaultsKey<T: _DefaultsSerializable>(
_ key: StoredKey,
serviceType: ServiceType,
id: String?,
defaultValue: T
)
-> Defaults
.Key<T> {
Defaults.Key<T>(
storedKey(key, serviceType: serviceType),
storedKey(key, serviceType: serviceType, id: id),
default: defaultValue
)
}
Expand Down
9 changes: 9 additions & 0 deletions Easydict/Swift/Service/CustomOpenAI/CustomOpenAIService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ class CustomOpenAIService: BaseOpenAIService {

// MARK: Internal

override func isDuplicatable() -> Bool {
true
}

override func isRemovable(_ type: EZWindowType) -> Bool {
let serviceTypes = EZLocalStorage.shared().allServiceTypes(type)
return !uuid.isEmpty
}

override func configurationListItems() -> Any {
StreamConfigurationView(
service: self,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,10 @@ extension LLMStreamService {
}

func stringDefaultsKey(_ key: StoredKey, defaultValue: String) -> Defaults.Key<String> {
defaultsKey(key, serviceType: serviceType(), defaultValue: defaultValue)
defaultsKey(key, serviceType: serviceType(), id: uuid, defaultValue: defaultValue)
}

func serviceDefaultsKey<T>(_ key: StoredKey, defaultValue: T) -> Defaults.Key<T> {
defaultsKey(key, serviceType: serviceType(), defaultValue: defaultValue)
defaultsKey(key, serviceType: serviceType(), id: uuid, defaultValue: defaultValue)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,38 @@ struct ServiceConfigurationSecretSectionView<Content: View>: View {
}

var footer: some View {
Button {
validate()
} label: {
Group {
if viewModel.isValidating {
ProgressView()
.controlSize(.small)
.progressViewStyle(.circular)
} else {
Text("service.configuration.validate")
HStack {
if service.isDuplicatable() {
Button {
service.duplicate()
} label: {
Text("service.configuration.duplicate")
}

if service.isRemovable(service.windowType) {
Button("service.configuration.remove", role: .destructive) {
service.remove()
}
}

Spacer()
}

Button {
validate()
} label: {
Group {
if viewModel.isValidating {
ProgressView()
.controlSize(.small)
.progressViewStyle(.circular)
} else {
Text("service.configuration.validate")
}
}
}
.disabled(viewModel.isValidateBtnDisabled)
}
.disabled(viewModel.isValidateBtnDisabled)
}

var body: some View {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,39 @@ extension QueryService: ServiceSecretConfigreValidatable {
translate("曾经沧海难为水", from: .simplifiedChinese, to: .english, completion: completion)
}
}

// MARK: - ServiceSecretConfigreDuplicatable

protocol ServiceSecretConfigreDuplicatable {
func duplicate()
func remove()
}

extension ServiceSecretConfigreDuplicatable {
func duplicate() {}
func remove() {}
}

// MARK: - QueryService + ServiceSecretConfigreDuplicatable

extension QueryService: ServiceSecretConfigreDuplicatable {
func duplicate() {
var allServiceTypes = EZLocalStorage.shared().allServiceTypes(windowType)
let uuid = UUID().uuidString
let newServiceType = "\(serviceType().rawValue)#\(uuid)"
allServiceTypes.append(newServiceType)
let newService = self
newService.uuid = uuid
EZLocalStorage.shared().setService(newService, windowType: windowType)
EZLocalStorage.shared().setAllServiceTypes(allServiceTypes, windowType: windowType)
NotificationCenter.default.postServiceUpdateNotification(windowType: windowType)
}

func remove() {
let allServiceTypes = EZLocalStorage.shared().allServiceTypes(windowType)
.filter { $0 != "\(serviceType().rawValue)#\(uuid)" }

EZLocalStorage.shared().setAllServiceTypes(allServiceTypes, windowType: windowType)
NotificationCenter.default.postServiceUpdateNotification(windowType: windowType)
}
}
27 changes: 16 additions & 11 deletions Easydict/Swift/View/SettingView/Tabs/TabView/ServiceTab.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ struct ServiceTab: View {
.padding(.bottom)
.padding(.horizontal)
.frame(minWidth: 260)
.onReceive(serviceHasUpdatedPub) { _ in
viewModel.updateServices()
}
}

Group {
Expand Down Expand Up @@ -60,6 +63,9 @@ struct ServiceTab: View {

// MARK: Private

private let serviceHasUpdatedPub = NotificationCenter.default
.publisher(for: .serviceHasUpdated)

@StateObject private var viewModel: ServiceTabViewModel = .init()
}

Expand Down Expand Up @@ -89,26 +95,25 @@ private class ServiceTabViewModel: ObservableObject {
}

func updateServices() {
services = getServices()
}
services = EZLocalStorage.shared().allServices(windowType)

func getServices() -> [QueryService] {
EZLocalStorage.shared().allServices(windowType)
let isSelectedExist = services
.contains { $0.serviceType() == selectedService?.serviceType() && $0.uuid == selectedService?.uuid }
if !isSelectedExist {
selectedService = nil
}
}

func onServiceItemMove(fromOffsets: IndexSet, toOffset: Int) {
var services = services

services.move(fromOffsets: fromOffsets, toOffset: toOffset)

let serviceTypes = services.map { service in
service.serviceType()
"\(service.serviceType())#\(service.uuid)"
}

EZLocalStorage.shared().setAllServiceTypes(serviceTypes, windowType: windowType)

postUpdateServiceNotification()

updateServices()
}

Expand All @@ -134,9 +139,9 @@ private struct ServiceItems: View {

@EnvironmentObject private var viewModel: ServiceTabViewModel

private var servicesWithID: [(QueryService, String)] {
viewModel.services.map { service in
(service, service.serviceType().rawValue)
private var servicesWithID: [(QueryService, Int)] {
viewModel.services.enumerated().map { index, service in
(service, index)
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions Easydict/objc/Service/Model/EZQueryService.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ NS_ASSUME_NONNULL_BEGIN
NS_SWIFT_NAME(QueryService)
@interface EZQueryService : NSObject

@property (nonatomic, strong) NSString *uuid;
@property (nonatomic, strong) EZQueryModel *queryModel;

/// 翻译结果
Expand Down Expand Up @@ -121,6 +122,10 @@ NS_SWIFT_NAME(QueryService)

- (BOOL)isStream;

- (BOOL)isDuplicatable;

- (BOOL)isRemovable:(EZWindowType)type;

/// 获取文本的语言
/// @param text 文本
/// @param completion 回调
Expand Down
10 changes: 9 additions & 1 deletion Easydict/objc/Service/Model/EZQueryService.m
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ - (EZDetectManager *)detectManager {
- (void)setEnabledQuery:(BOOL)enabledQuery {
_enabledQuery = enabledQuery;

[[EZLocalStorage shared] setEnabledQuery:enabledQuery serviceType:self.serviceType windowType:self.windowType];
[[EZLocalStorage shared] setEnabledQuery:enabledQuery serviceType:self.serviceType serviceId:self.uuid windowType:self.windowType];
}

- (BOOL)enabledAutoQuery {
Expand Down Expand Up @@ -313,6 +313,14 @@ - (BOOL)isStream {
return NO;
}

- (BOOL)isDuplicatable {
return NO;
}

- (BOOL)isRemovable:(EZWindowType)type {
return YES;
}

- (void)detectText:(NSString *)text completion:(void (^)(EZLanguage language, NSError *_Nullable error))completion {
MethodNotImplemented();
}
Expand Down
3 changes: 3 additions & 0 deletions Easydict/objc/Service/Model/EZServiceTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@ NS_SWIFT_NAME(ServiceTypes)
@interface EZServiceTypes : NSObject

@property (nonatomic, copy, readonly) NSArray<EZServiceType> *allServiceTypes;
@property (nonatomic, copy, readonly) NSArray<NSString *> *allServiceTypeIDs;

+ (instancetype)shared;

- (nullable EZQueryService *)serviceWithType:(EZServiceType)type;

- (NSString *)createDuplicateServiceType:(EZServiceType)type;

- (NSArray<EZQueryService *> *)servicesFromTypes:(NSArray<EZServiceType> *)types;

@end
Expand Down
16 changes: 14 additions & 2 deletions Easydict/objc/Service/Model/EZServiceTypes.m
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ + (instancetype)allocWithZone:(struct _NSZone *)zone {
return [[self allServiceDict] sortedKeys];
}

- (NSString *)createDuplicateServiceType:(EZServiceType)type {
return [[NSString alloc] initWithFormat:@"%@#%@", type, [NSUUID UUID].UUIDString];
}

- (MMOrderedDictionary<EZServiceType, Class> *)allServiceDict {
MMOrderedDictionary *allServiceDict = [[MMOrderedDictionary alloc] initWithKeysAndObjects:
EZServiceTypeAppleDictionary, [EZAppleDictionary class],
Expand Down Expand Up @@ -74,10 +78,18 @@ - (nullable EZQueryService *)serviceWithType:(EZServiceType)type {
return [Cls new];
}

- (NSArray<EZQueryService *> *)servicesFromTypes:(NSArray<EZServiceType> *)types {
- (NSArray<EZQueryService *> *)servicesFromTypes:(NSArray<NSString *> *)types {
NSMutableArray *services = [NSMutableArray array];
for (EZServiceType type in types) {
for (NSString *serviceType in types) {
NSString *type = serviceType;
NSString *uuid = @"";
if ([serviceType containsString:@"#"]) {
NSArray *serivceTypeId = [serviceType componentsSeparatedByString:@"#"];
type = serivceTypeId[0];
uuid = serivceTypeId[1];
}
EZQueryService *service = [self serviceWithType:type];
service.uuid = uuid;
// Maybe OpenAI has been disabled.
if (service) {
[services addObject:service];
Expand Down
1 change: 1 addition & 0 deletions Easydict/objc/ViewController/Model/EZServiceInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ NS_ASSUME_NONNULL_BEGIN

@interface EZServiceInfo : NSObject

@property (nonatomic, strong) NSString *uuid;
@property (nonatomic, assign) EZServiceType type;
@property (nonatomic, assign) BOOL enabled;
@property (nonatomic, assign) BOOL enabledQuery;
Expand Down
2 changes: 1 addition & 1 deletion Easydict/objc/ViewController/Model/EZServiceInfo.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ + (instancetype)serviceInfoWithService:(EZQueryService *)service {
serviceInfo.enabled = service.enabled;
serviceInfo.enabledQuery = service.enabledQuery;
serviceInfo.windowType = service.windowType;

serviceInfo.uuid = service.uuid;
return serviceInfo;
}

Expand Down
8 changes: 4 additions & 4 deletions Easydict/objc/ViewController/Storage/EZLocalStorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,18 @@ static NSString *const EZAutoQueryKey = @"EZAutoQueryKey";
+ (void)destroySharedInstance;


- (NSArray<EZServiceType> *)allServiceTypes:(EZWindowType)windowType;
- (void)setAllServiceTypes:(NSArray<EZServiceType> *)allServiceTypes windowType:(EZWindowType)windowType;
- (NSArray<NSString *> *)allServiceTypes:(EZWindowType)windowType;
- (void)setAllServiceTypes:(NSArray<NSString *> *)allServiceTypes windowType:(EZWindowType)windowType;

- (NSArray<EZQueryService *> *)allServices:(EZWindowType)windowType;
- (EZQueryService *)service:(EZServiceType)serviceType windowType:(EZWindowType)windowType;

- (nullable EZServiceInfo *)serviceInfoWithType:(EZServiceType)type windowType:(EZWindowType)windowType;
- (nullable EZServiceInfo *)serviceInfoWithType:(EZServiceType)type serviceId:(NSString *)serviceId windowType:(EZWindowType)windowType;
- (void)setServiceInfo:(EZServiceInfo *)service windowType:(EZWindowType)windowType;

- (void)setService:(EZQueryService *)service windowType:(EZWindowType)windowType;

- (void)setEnabledQuery:(BOOL)enabledQuery serviceType:(EZServiceType)serviceType windowType:(EZWindowType)windowType;
- (void)setEnabledQuery:(BOOL)enabledQuery serviceType:(EZServiceType)serviceType serviceId:(NSString *)serviceId windowType:(EZWindowType)windowType;

- (void)increaseQueryCount:(NSString *)queryText;
- (NSInteger)queryCount;
Expand Down
Loading

0 comments on commit 1b582f0

Please sign in to comment.