// Direktör pipeline — app kodu: 2 sahne resim→video + ffmpeg birleştir. import 'dart:convert'; import 'dart:io'; import 'package:dio/dio.dart'; import '../lib/comfy/workflow/resim_workflow.dart'; import '../lib/comfy/workflow/video_workflow.dart'; Future main() async { const base = 'http://127.0.0.1:8188'; final dio = Dio(BaseOptions(baseUrl: base, receiveTimeout: const Duration(minutes: 8))); final cikti = Directory(r'D:\__sistem__\Masaustu\FikoYT.Yeni.Cag\video-uretim-1\ciktilar\direktor_test'); cikti.createSync(recursive: true); Future uretBekle(Map wf) async { final r = await dio.post('/prompt', data: {'prompt': wf, 'client_id': 'fikoyt-dir'}); final pid = (r.data as Map)['prompt_id']; for (var i = 0; i < 160; i++) { await Future.delayed(const Duration(seconds: 3)); final h = await dio.get('/history/$pid'); final m = h.data as Map; if (m[pid] != null) { final st = (m[pid] as Map)['status'] as Map?; if (st?['status_str'] == 'error') throw 'HATA'; if (st?['completed'] == true) return (m[pid] as Map)['outputs'] as Map; } } throw 'ZAMAN ASIMI'; } String ilkDosya(Map outputs) { for (final v in outputs.values) { final imgs = (v as Map)['images']; if (imgs is List && imgs.isNotEmpty) return imgs.first['filename']; } throw 'cikti yok'; } Future indir(String filename, String hedef) async { final r = await dio.get>('/view', queryParameters: {'filename': filename, 'subfolder': 'fikoyt', 'type': 'output'}, options: Options(responseType: ResponseType.bytes)); await File(hedef).writeAsBytes(r.data!); } final videolar = []; for (var s = 0; s < 2; s++) { stdout.writeln('Sahne $s: resim...'); final rp = ResimParametreleri( prompt: s == 0 ? 'a serene beach at sunset, cinematic' : 'a neon city street at night, cinematic', genislik: 512, yukseklik: 320, steps: 18, guidance: 3.5); final ro = await uretBekle(resimWorkflowOlustur(rp)); final imgName = ilkDosya(ro); final imgYol = '${cikti.path}/sahne_${s}_resim.png'; await indir(imgName, imgYol); // upload final form = FormData.fromMap({ 'image': await MultipartFile.fromFile(imgYol, filename: 'sahne_${s}_resim.png'), 'overwrite': 'true', }); final up = await dio.post('/upload/image', data: form); final inputAdi = (up.data as Map)['name']; stdout.writeln('Sahne $s: video (I2V)...'); final vp = VideoParametreleri( prompt: rp.prompt, kaynakResim: inputAdi, genislik: 512, yukseklik: 320, uzunluk: 49, fps: 24, steps: 18); final vo = await uretBekle(videoWorkflowOlustur(vp)); String vidName = ''; for (final v in vo.values) { final imgs = (v as Map)['images']; if (imgs is List && imgs.isNotEmpty) vidName = imgs.first['filename']; } final vidYol = '${cikti.path}/sahne_${s}_video.mp4'; await indir(vidName, vidYol); videolar.add(vidYol); stdout.writeln('Sahne $s tamam: $vidYol'); } // ffmpeg birlestir final liste = File('${cikti.path}/liste.txt'); await liste.writeAsString(videolar.map((v) => "file '${v.replaceAll(r'\', '/')}'").join('\n')); final hedef = '${cikti.path}/final_klip.mp4'; final r = await Process.run('ffmpeg', ['-y', '-f', 'concat', '-safe', '0', '-i', liste.path, '-c:v', 'libx264', '-pix_fmt', 'yuv420p', hedef]); if (r.exitCode == 0 && File(hedef).existsSync()) { stdout.writeln('BASARILI: klip birlesti → $hedef (${File(hedef).lengthSync()} bayt)'); exit(0); } else { stdout.writeln('FFMPEG HATA: ${r.stderr}'); exit(1); } }