AI 해상도: CPU 에서 자동이 만화용을 고르면 알리고 '사진' 모델로 바꿔 다시 할 수 있게

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
묶음3
RyuJongJin 2026-10-09 15:45:16 +09:00
parent 986688eafa
commit 300ccdde99
5 changed files with 32 additions and 2 deletions

View File

@ -39,6 +39,7 @@
"\"백그라운드로 실행\" 이 꺼져 있어 앱을 끝내면 작업이 멈춥니다.": "\"Run in background\" is off, so closing the app stops these tasks.",
"\"외부 브라우저로 열기\" 에 쓸 브라우저 (이 PC 에 설치된 것)": "Browser for \"Open in external browser\" (installed on this PC)",
"# Netscape HTTP Cookie File\n# JJ_MKVMaker 앱 안 브라우저에서 내보냄\n\n": "# Netscape HTTP Cookie File\n# Exported from the JJ_MKVMaker in-app browser\n\n",
"'사진' 모델로 바꿔 다시": "Switch to 'Photos' and redo",
"(AI 번역을 쓸 수 없는 기기라 언어를 더할 수 없습니다)": "(Languages cannot be added because AI translation is unavailable on this device)",
"({0}개 지움)": "(delete {0})",
"(동영상을 세 번 누르면 옮깁니다)": "(Tapping a video three times moves it)",
@ -880,6 +881,7 @@
"사용자가 취소했습니다.": "Cancelled by the user.",
"사용할 수 있는 자막 사이트가 없습니다.": "No subtitle site is available.",
"사진": "Photos",
"사진에는 '사진' 모델이 더 낫지만, 이 기기 (그래픽카드 없음) 에서는 한 장에 약 20분 걸립니다.": "The 'Photos' model is better for photos, but on this device (no graphics card) it takes about 20 minutes per image.",
"삭제": "Delete",
"삭제 (목록에서 제거)": "Delete (remove from list)",
"삭제 (중지하고 받던 파일 삭제)": "Delete (stop and delete the partial file)",

View File

@ -39,6 +39,7 @@
"\"백그라운드로 실행\" 이 꺼져 있어 앱을 끝내면 작업이 멈춥니다.": "「バックグラウンドで実行」がオフなので、アプリを終了すると作業が止まります。",
"\"외부 브라우저로 열기\" 에 쓸 브라우저 (이 PC 에 설치된 것)": "「外部ブラウザーで開く」に使うブラウザー(この PC にインストール済み)",
"# Netscape HTTP Cookie File\n# JJ_MKVMaker 앱 안 브라우저에서 내보냄\n\n": "# Netscape HTTP Cookie File\n# JJ_MKVMaker アプリ内ブラウザーから書き出し\n\n",
"'사진' 모델로 바꿔 다시": "「写真」モデルに変えてやり直す",
"(AI 번역을 쓸 수 없는 기기라 언어를 더할 수 없습니다)": "(この端末では AI 翻訳が使えないため言語を追加できません)",
"({0}개 지움)": "({0} 個を削除)",
"(동영상을 세 번 누르면 옮깁니다)": "(動画を 3 回タップすると移動します)",
@ -880,6 +881,7 @@
"사용자가 취소했습니다.": "ユーザーがキャンセルしました。",
"사용할 수 있는 자막 사이트가 없습니다.": "使用できる字幕サイトがありません。",
"사진": "写真",
"사진에는 '사진' 모델이 더 낫지만, 이 기기 (그래픽카드 없음) 에서는 한 장에 약 20분 걸립니다.": "写真には「写真」モデルが適していますが、この端末 (グラフィックカードなし) では 1 枚に約 20 分かかります。",
"삭제": "削除",
"삭제 (목록에서 제거)": "削除(リストから外す)",
"삭제 (중지하고 받던 파일 삭제)": "削除(中止してダウンロード中のファイルを削除)",

View File

@ -39,6 +39,7 @@
"\"백그라운드로 실행\" 이 꺼져 있어 앱을 끝내면 작업이 멈춥니다.": "“后台运行”已关闭,退出应用会停止这些任务。",
"\"외부 브라우저로 열기\" 에 쓸 브라우저 (이 PC 에 설치된 것)": "“在外部浏览器中打开”使用的浏览器(本机已安装)",
"# Netscape HTTP Cookie File\n# JJ_MKVMaker 앱 안 브라우저에서 내보냄\n\n": "# Netscape HTTP Cookie File\n# 从 JJ_MKVMaker 内置浏览器导出\n\n",
"'사진' 모델로 바꿔 다시": "改用“照片”模型重新处理",
"(AI 번역을 쓸 수 없는 기기라 언어를 더할 수 없습니다)": "(此设备无法使用 AI 翻译,因此无法添加语言)",
"({0}개 지움)": "(删除 {0} 个)",
"(동영상을 세 번 누르면 옮깁니다)": "(连按视频三次会移动它)",
@ -880,6 +881,7 @@
"사용자가 취소했습니다.": "用户已取消。",
"사용할 수 있는 자막 사이트가 없습니다.": "没有可用的字幕网站。",
"사진": "照片",
"사진에는 '사진' 모델이 더 낫지만, 이 기기 (그래픽카드 없음) 에서는 한 장에 약 20분 걸립니다.": "照片更适合使用“照片”模型,但在本设备 (无显卡) 上每张约需 20 分钟。",
"삭제": "删除",
"삭제 (목록에서 제거)": "删除(从列表中移除)",
"삭제 (중지하고 받던 파일 삭제)": "删除(停止并删除正在下载的文件)",

View File

@ -69,9 +69,12 @@ Uint8List _finish((Uint8List, int, int, int, String, int) a) {
/// 그림 한 장 올리기. [input] 은 이 기기의 파일 (ZIP · WebDAV 의 그림은 부르는 쪽이 임시 파일로).
/// 결과를 [save] 가 true 면 저장하고 그 경로를, 아니면 임시 파일 경로를 돌려준다 (비교해 보고 저장할 때).
class AiUpscaler {
AiUpscaler({required this.device, required this.modelPath});
AiUpscaler({required this.device, required this.modelPath, this.modelId = ''});
final SdDevice device;
final String modelPath;
/// 카탈로그 id (자동이 CPU 에서 만화용을 골랐는지 알리려고)
final String modelId;
Process? _proc;
bool _cancelled = false;
@ -139,5 +142,5 @@ Future<AiUpscaler?> prepareUpscaler(AiStore store, {required String modelSetting
final gpu = dev.backend != 'cpu';
final id = pickUpscaleModel(modelSetting, gpu: gpu);
if (!store.isInstalled(id)) return null;
return AiUpscaler(device: dev, modelPath: store.pathOf(aiFile(id)));
return AiUpscaler(device: dev, modelPath: store.pathOf(aiFile(id)), modelId: id);
}

View File

@ -68,6 +68,9 @@ Future<String?> upscaleOne(BuildContext context, AppController c, {required Stri
if (up == null || !context.mounted) return null;
final progress = ValueNotifier<double?>(null);
var cancelled = false;
var toPhoto = false;
// 관리자: CPU 뿐이라 자동이 만화용을 고르면 사진은 질감이 뭉개질 수 있다 - 알리고 바로 바꿀 수 있게
final cpuAnime = c.settings.aiUpModel == 'auto' && up.device.backend == 'cpu' && up.modelId == 'esrgan-anime6b';
final nav = Navigator.of(context);
unawaited(showDialog<void>(
context: context,
@ -84,6 +87,19 @@ Future<String?> upscaleOne(BuildContext context, AppController c, {required Stri
LinearProgressIndicator(value: v),
const SizedBox(height: 4),
Text(v == null ? tr('준비하는 중') : '${(v * 100).round()}%', style: const TextStyle(fontSize: 12)),
if (cpuAnime) ...[
const SizedBox(height: 10),
Text(tr("사진에는 '사진' 모델이 더 낫지만, 이 기기 (그래픽카드 없음) 에서는 한 장에 약 20분 걸립니다."),
style: const TextStyle(fontSize: 12, color: JjColors.textDim)),
TextButton(
onPressed: () {
toPhoto = true;
cancelled = true;
up.cancel();
},
child: Text(tr("'사진' 모델로 바꿔 다시")),
),
],
]),
),
),
@ -107,6 +123,11 @@ Future<String?> upscaleOne(BuildContext context, AppController c, {required Stri
}
nav.pop(); // 진행 창
if (!context.mounted) return null;
if (toPhoto) {
await c.updateSettings((x) => x.aiUpModel = 'photo');
if (!context.mounted) return null;
return upscaleOne(context, c, input: input, nameFrom: nameFrom, outDir: outDir);
}
if (four == null) {
if (!cancelled) ScaffoldMessenger.maybeOf(context)?.showSnackBar(SnackBar(content: Text('$error')));
return null;