import '../../services/image_ai.dart'; import 'settings_group.dart'; /// 약속 (설정 A): 환경 설정 > AI 그림 · 해상도 올리기 (123 · 121) - 자기 키 (이름 · 처음 값 · 읽기 · 쓰기) 를 스스로 갖는다. /// 설정 하나를 더할 때는 이 파일만 고친다. 저장 파일의 키 이름은 예전 그대로 (평평한 키) class AiImageSettings implements SettingsGroup { /// 그리는 엔진: 'local' 이 기기 안 (기본) · 아니면 [services] 의 id (사용자가 추가한 서버 · 서비스) String engine = 'local'; /// 기기 안 처리 장치: 'auto' (잰 결과로 빠른 쪽) 또는 장치 열쇠 (예: 'engine-cuda:cuda0', 'engine-vulkan:cpu') String device = 'auto'; /// 'auto' 가 잰 가장 빠른 장치와 그때의 장치 목록 (목록이 바뀌면 다시 잰다) String autoDevice = ''; String autoDeviceFor = ''; /// 빠른 디코더 (TAESD) - 그림이 거의 같고 디코드가 10배쯤 빠르다 (받아 두었을 때) bool taesd = true; int width = 512; int height = 512; int steps = 4; double cfg = 1; int count = 1; double strength = 0.6; String negative = ''; /// 159: 마지막 프롬프트와 만든 그림 목록 (최근 것부터, 업데이트 · 다시 열어도 남게) String prompt = ''; List recent = []; /// 저장 폴더 (비어 있으면 사진 폴더의 JJ_MKVMaker_AI) String saveDir = ''; /// 사용자가 추가한 그림 서버 · 서비스 (API 키는 안전 저장소에) List services = []; /// 라이선스 조건에 동의한 받는 파일 (149-④: 한 번 동의하면 다시 묻지 않음) List agreed = []; /// 모델 'auto' (GPU 면 사진용, CPU 뿐이면 가볍고 빠른 만화용) · 'photo' · 'anime' String upModel = 'auto'; /// 176: 해상도 올리기 메모리 (Android CPU 타일 크기) - 'low' 20% · 'normal' 30% (처음 값) · 'high' 45% (기기 메모리 중) String upMemory = 'normal'; /// 156-2: 해상도 올리기에 걸린 시간 (처리 장치|모델 → 원본 100만 화소당 초) - "한 장 약 n초" 를 미리 알리려고 Map upSecPerMp = {}; /// 배율 2 · 3 · 4 int upScale = 2; /// 관리자 판단 (10/17): 보기 화면의 [품질 올리기] 단추 (그림 → 그림 약하게 + 해상도 올리기). 처음 값: 끔 bool qualityButton = false; /// [품질 올리기] 다듬기 정도 (그림 → 그림 바꾸는 정도): 'weak' 0.15 · 'normal' 0.25 (처음 값) · 'strong' 0.4 (관리자 지시 - 판단은 설정으로) String qualityStrength = 'normal'; /// 저장 형식 'same' (원본과 같게, 못 쓰는 형식은 PNG) · 'png' · 'jpg' · JPG 품질 String upFormat = 'same'; int upJpgQuality = 92; /// 저장 위치 (비어 있으면 원본 옆 "이름_x2") String upDir = ''; /// 저장한 뒤 'upscaled' 올린 것으로 계속 보기 · 'original' 원본으로 String upAfter = 'upscaled'; @override void write(Map j, {required bool plainSecrets}) { j['aiEngine'] = engine; j['aiDevice'] = device; j['aiAutoDevice'] = autoDevice; j['aiAutoDeviceFor'] = autoDeviceFor; j['aiTaesd'] = taesd; j['aiWidth'] = width; j['aiHeight'] = height; j['aiSteps'] = steps; j['aiCfg'] = cfg; j['aiCount'] = count; j['aiStrength'] = strength; j['aiNegative'] = negative; j['aiPrompt'] = prompt; j['aiRecent'] = recent; j['aiSaveDir'] = saveDir; j['aiServices'] = [ for (final x in services) {...x.toJson(), if (plainSecrets) 'apiKey': x.apiKey}, ]; j['aiAgreed'] = agreed; j['aiUpModel'] = upModel; j['aiUpMemory'] = upMemory; j['aiUpSecPerMp'] = upSecPerMp; j['aiUpScale'] = upScale; j['aiQualityButton'] = qualityButton; j['aiQualityStrength'] = qualityStrength; j['aiUpFormat'] = upFormat; j['aiUpJpgQuality'] = upJpgQuality; j['aiUpDir'] = upDir; j['aiUpAfter'] = upAfter; } @override void read(Map j) { engine = j['aiEngine'] as String? ?? 'local'; device = j['aiDevice'] as String? ?? 'auto'; autoDevice = j['aiAutoDevice'] as String? ?? ''; autoDeviceFor = j['aiAutoDeviceFor'] as String? ?? ''; taesd = j['aiTaesd'] != false; width = ((j['aiWidth'] as num?)?.toInt() ?? 512).clamp(64, 2048); height = ((j['aiHeight'] as num?)?.toInt() ?? 512).clamp(64, 2048); steps = ((j['aiSteps'] as num?)?.toInt() ?? 4).clamp(1, 150); cfg = ((j['aiCfg'] as num?)?.toDouble() ?? 1).clamp(0, 30); count = ((j['aiCount'] as num?)?.toInt() ?? 1).clamp(1, 100); strength = ((j['aiStrength'] as num?)?.toDouble() ?? 0.6).clamp(0, 1); negative = j['aiNegative'] as String? ?? ''; prompt = j['aiPrompt'] as String? ?? ''; recent = [for (final x in (j['aiRecent'] as List?) ?? const []) '$x']; saveDir = j['aiSaveDir'] as String? ?? ''; agreed = [for (final x in (j['aiAgreed'] as List?) ?? const []) '$x']; upModel = const ['photo', 'anime'].contains(j['aiUpModel']) ? j['aiUpModel'] as String : 'auto'; upMemory = const ['low', 'high'].contains(j['aiUpMemory']) ? j['aiUpMemory'] as String : 'normal'; upSecPerMp = { if (j['aiUpSecPerMp'] case final Map m) for (final e in m.entries) if (e.value is num && (e.value as num) > 0) '${e.key}': (e.value as num).toDouble(), }; // 1 = 크기는 그대로 선명하게만 (관리자 판단 10/17 - 사용자 질문에 답이 없어 넣되 처음 값은 2배 그대로) upScale = const [1, 3, 4].contains(j['aiUpScale']) ? j['aiUpScale'] as int : 2; qualityButton = j['aiQualityButton'] == true; qualityStrength = const ['weak', 'normal', 'strong'].contains(j['aiQualityStrength']) ? j['aiQualityStrength'] as String : 'normal'; upFormat = const ['png', 'jpg'].contains(j['aiUpFormat']) ? j['aiUpFormat'] as String : 'same'; upJpgQuality = ((j['aiUpJpgQuality'] as num?)?.toInt() ?? 92).clamp(50, 100); upDir = j['aiUpDir'] as String? ?? ''; upAfter = j['aiUpAfter'] == 'original' ? 'original' : 'upscaled'; services = [ for (final x in (j['aiServices'] as List?) ?? const []) if (x is Map) AiService.fromJson(x), ]; } }