arcanus commited on
Commit
026a425
·
1 Parent(s): 115cfdd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +523 -1
app.py CHANGED
@@ -1,2 +1,524 @@
 
 
 
1
  import os
2
- os.system("python app_rvc.py --language czech")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, render_template, request, jsonify, send_file, session, redirect, url_for
2
+ from functools import wraps
3
+ from functools import update_wrapper
4
  import os
5
+ from app_rvc2 import SoniTranslate, TTS_Info
6
+ from soni_translate.language_configuration import LANGUAGES_LIST, LANGUAGES, LANGUAGES_UNIDIRECTIONAL
7
+ import yt_dlp
8
+ from datetime import datetime
9
+ import re
10
+ import shutil
11
+
12
+ app = Flask(__name__)
13
+ app.secret_key = 'koala123' # Změňte na bezpečné heslo
14
+
15
+ # Heslo pro přístup k aplikaci
16
+ APP_PASSWORD = 'koala123' # Změňte na požadované heslo
17
+
18
+ # Middleware pro kontrolu přihlášení
19
+ def login_required(f):
20
+ @wraps(f)
21
+ def decorated_function(*args, **kwargs):
22
+ if 'logged_in' not in session:
23
+ return redirect(url_for('login'))
24
+ return f(*args, **kwargs)
25
+ return decorated_function
26
+
27
+ @app.route('/login', methods=['GET', 'POST'])
28
+ def login():
29
+ if request.method == 'POST':
30
+ if request.form['password'] == APP_PASSWORD:
31
+ session['logged_in'] = True
32
+ return redirect(url_for('index'))
33
+ return render_template('login.html', error='Nesprávné heslo')
34
+ return render_template('login.html')
35
+
36
+ @app.route('/logout')
37
+ def logout():
38
+ session.pop('logged_in', None)
39
+ return redirect(url_for('login'))
40
+
41
+ soni = SoniTranslate()
42
+
43
+ # Přidání cesty pro servírování výsledných videí
44
+ @app.route('/outputs/<path:filename>')
45
+ def serve_output(filename):
46
+ return send_file('outputs/' + filename)
47
+
48
+ @app.route('/uploads/<path:filename>')
49
+ def serve_upload(filename):
50
+ return send_file('uploads/' + filename)
51
+
52
+ @app.route('/exports/<path:filename>')
53
+ def serve_export(filename):
54
+ return send_file('exports/' + filename)
55
+
56
+ @app.route('/')
57
+ @login_required
58
+ def index():
59
+ return render_template('index_new.html',
60
+ languages=LANGUAGES_LIST,
61
+ tts_voices=soni.tts_info.tts_list())
62
+
63
+ def create_project_folder(project_name):
64
+ # Vytvoření názvu složky ve formátu DD-MM-YYYY-H:M-project_name
65
+ current_time = datetime.now()
66
+ sanitized_name = re.sub(r'[<>:"/\\|?*]', '_', project_name) # Nahrazení neplatných znaků
67
+ folder_name = current_time.strftime("%d-%m-%Y-%H-%M-") + sanitized_name
68
+
69
+ # Vytvoření složky v exports
70
+ project_path = os.path.join('exports', folder_name)
71
+ os.makedirs(project_path, exist_ok=True)
72
+ return project_path
73
+
74
+ @app.route('/translate', methods=['POST'])
75
+ @login_required
76
+ def translate():
77
+ try:
78
+ data = request.form
79
+ files = request.files
80
+
81
+ # Kontrola manuální korekce
82
+ manual_correction = data.get('translation_correction', 'off') == 'on'
83
+
84
+ # Vytvoření projektové složky
85
+ project_name = data.get('project_name', 'untitled')
86
+ project_path = create_project_folder(project_name)
87
+
88
+ # Handle file upload or YouTube URL
89
+ media_file = None
90
+ if 'video' in files and files['video'].filename:
91
+ # Handle file upload
92
+ media_filer = files['video']
93
+ custom_filename = "video.mp4"
94
+ upload_paths = os.path.join(project_path, custom_filename)
95
+ os.makedirs(project_path, exist_ok=True)
96
+ media_filer.save(upload_paths)
97
+ media_file = upload_paths
98
+ print("Video saved to project:", media_file)
99
+ elif 'downloaded_video_path' in data and data['downloaded_video_path'].strip():
100
+ # Použít stažené video z YouTube
101
+ downloaded_path = data['downloaded_video_path'].strip()
102
+ if os.path.exists(downloaded_path):
103
+ media_file = downloaded_path
104
+ print("Using downloaded YouTube video:", media_file)
105
+ else:
106
+ return jsonify({'success': False, 'error': 'Stažené video nebylo nalezeno'})
107
+ elif 'url' in data and data['url'].strip():
108
+ # Handle YouTube URL
109
+ url = data['url'].strip()
110
+ if 'youtube.com' in url or 'youtu.be' in url:
111
+ try:
112
+ media_file, thumbnail_url = download_youtube_video(url, project_path)
113
+ # Copy downloaded file to video.mp4
114
+ final_path = os.path.join(project_path, "video.mp4")
115
+ shutil.copy(media_file, final_path)
116
+ media_file = final_path
117
+ print("YouTube video downloaded to:", media_file)
118
+ except Exception as e:
119
+ return jsonify({'success': False, 'error': f'YouTube download failed: {str(e)}'})
120
+ else:
121
+ return jsonify({'success': False, 'error': 'Invalid YouTube URL'})
122
+
123
+ # Pokud je zapnuta manuální korekce, uložit cestu k videu do session
124
+ if manual_correction and media_file:
125
+ session['current_video_path'] = media_file
126
+ print(f"Uloženo do session: {media_file}")
127
+
128
+ if not media_file:
129
+ return jsonify({'success': False, 'error': 'No video file or valid YouTube URL provided'})
130
+
131
+ # Get parameters
132
+ source_lang = data.get('source_language', 'Automatic detection')
133
+ target_lang = data.get('target_language', 'English (en)')
134
+ max_speakers = int(data.get('max_speakers', 1))
135
+
136
+ # Get edited subtitles if available
137
+ edited_subtitles = data.get('edited_subtitles')
138
+
139
+ # If edited subtitles are available, save them to a temporary file
140
+ subtitle_file = None
141
+ if edited_subtitles:
142
+ # If edited subtitles are provided, use target language as source language
143
+ # since the subtitles are already in the target language
144
+ source_lang = target_lang
145
+ get_translated_text=False
146
+ get_video_from_text_json=True
147
+ text_json=edited_subtitles
148
+ os.makedirs('uploads', exist_ok=True)
149
+ subtitle_file = os.path.join('uploads', 'edited_subtitles.srt')
150
+ with open(subtitle_file, 'w', encoding='utf-8') as f:
151
+ f.write(edited_subtitles)
152
+ else:
153
+ get_translated_text=False
154
+ get_video_from_text_json=False
155
+ text_json=""
156
+ tts_voices = {}
157
+ for i in range(max_speakers):
158
+ voice_key = f'tts_voice{i:02d}'
159
+ if voice_key in data:
160
+ tts_voices[voice_key] = data[voice_key]
161
+
162
+ # Process the translation
163
+ result = soni.multilingual_media_conversion(
164
+ media_file=media_file,
165
+ link_media="",
166
+ directory_input="",
167
+ origin_language=source_lang,
168
+ target_language=target_lang,
169
+ max_speakers=max_speakers,
170
+ get_translated_text=get_translated_text,
171
+ get_video_from_text_json=get_video_from_text_json,
172
+ text_json=text_json,
173
+ max_accelerate_audio=1.0,
174
+ acceleration_rate_regulation=False,
175
+ **tts_voices,
176
+ is_gui=True
177
+ )
178
+
179
+ if isinstance(result, list):
180
+ # Přesun výstupních souborů do projektové složky
181
+ new_paths = []
182
+ for file_path in result:
183
+ if os.path.exists(file_path):
184
+ new_path = os.path.join(project_path, os.path.basename(file_path))
185
+ shutil.move(file_path, new_path)
186
+ # Převedení na relativní cestu pro frontend
187
+ relative_path = os.path.relpath(new_path, 'exports')
188
+ new_paths.append(f'/exports/{relative_path.replace(os.sep, "/")}')
189
+
190
+ # Převedení originálního videa na relativní cestu
191
+ original_video_path = None
192
+ if media_file and os.path.exists(media_file):
193
+ original_video_path = f'/exports/{os.path.relpath(media_file, "exports").replace(os.sep, "/")}'
194
+
195
+ return jsonify({
196
+ 'success': True,
197
+ 'video': new_paths[0] if new_paths else None,
198
+ 'original_video': original_video_path,
199
+ 'files': new_paths
200
+ })
201
+ else:
202
+ return jsonify({'success': False, 'error': str(result)})
203
+
204
+ except Exception as e:
205
+ # Clean up temporary subtitle file in case of error
206
+ if 'subtitle_file' in locals() and subtitle_file and os.path.exists(subtitle_file):
207
+ os.remove(subtitle_file)
208
+ return jsonify({'success': False, 'error': str(e)})
209
+
210
+ def download_youtube_video(url, project_path):
211
+ if not url:
212
+ raise Exception("No URL provided")
213
+
214
+ if not ('youtube.com' in url or 'youtu.be' in url):
215
+ raise Exception("Not a valid YouTube URL")
216
+
217
+ filename = datetime.now().strftime("%Y%m%d_%H%M%S") + ".mp4"
218
+ output_path = os.path.join(project_path, 'original_' + filename)
219
+
220
+ print(f"Starting download for URL: {url}")
221
+ print(f"Output path: {output_path}")
222
+
223
+ ydl_opts = {
224
+ 'format': 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best',
225
+ 'outtmpl': output_path,
226
+ 'noplaylist': True,
227
+ 'quiet': False,
228
+ 'no_warnings': False,
229
+ 'extract_flat': False,
230
+ 'verbose': True
231
+ }
232
+
233
+ try:
234
+ with yt_dlp.YoutubeDL(ydl_opts) as ydl:
235
+ info = ydl.extract_info(url, download=False)
236
+ thumbnail_url = info.get('thumbnail', '')
237
+ ydl.download([url])
238
+ return output_path, thumbnail_url
239
+ except Exception as e:
240
+ print(f"Error downloading video: {str(e)}")
241
+ raise
242
+
243
+ @app.route('/download_youtube', methods=['POST'])
244
+ @login_required
245
+ def download_yt():
246
+ try:
247
+ url = request.form.get('url')
248
+ if not url:
249
+ return jsonify({'success': False, 'error': 'URL není zadána'})
250
+
251
+ print(f"Received download request for URL: {url}")
252
+
253
+ if any(x in url.lower() for x in ['youtube.com', 'youtu.be']):
254
+ os.makedirs('uploads', exist_ok=True)
255
+ try:
256
+ file_path, thumbnail_url = download_youtube_video(url, 'uploads')
257
+ if os.path.exists(file_path):
258
+ return jsonify({
259
+ 'success': True,
260
+ 'file_path': file_path,
261
+ 'filename': os.path.basename(file_path),
262
+ 'thumbnail_url': thumbnail_url
263
+ })
264
+ else:
265
+ return jsonify({'success': False, 'error': 'Soubor nebyl vytvořen po stažení'})
266
+ except Exception as e:
267
+ print(f"Download error: {str(e)}")
268
+ return jsonify({'success': False, 'error': f'Chyba při stahování: {str(e)}'})
269
+ else:
270
+ return jsonify({'success': False, 'error': 'Není platná YouTube URL'})
271
+
272
+ except Exception as e:
273
+ print(f"Route error: {str(e)}")
274
+ return jsonify({'success': False, 'error': f'Chyba: {str(e)}'})
275
+
276
+ @app.route('/get_subtitles', methods=['POST'])
277
+ @login_required
278
+ def get_subtitles():
279
+ try:
280
+ data = request.form
281
+ files = request.files
282
+
283
+ # Vytvoření projektové složky
284
+ project_name = data.get('project_name', 'untitled')
285
+ project_path = create_project_folder(project_name)
286
+
287
+ # Get file or URL or directory
288
+ media_file = None
289
+ link_media = ""
290
+ directory_input = ""
291
+
292
+ # Handle file upload
293
+ if 'video' in files and files['video'].filename:
294
+ media_filer = files['video']
295
+ custom_filename = "video.mp4"
296
+ upload_paths = os.path.join(project_path, custom_filename)
297
+ os.makedirs(project_path, exist_ok=True)
298
+ media_filer.save(upload_paths)
299
+ media_file = upload_paths
300
+ print("Video saved to project:", media_file)
301
+
302
+ # Also save to uploads folder
303
+ upload_path = os.path.join('uploads', custom_filename)
304
+ os.makedirs('uploads', exist_ok=True)
305
+ shutil.copy(media_file, upload_path)
306
+ print("Video copied to uploads:", upload_path)
307
+
308
+ # Save video path to session
309
+ session['video_path'] = media_file
310
+
311
+ # Handle URL
312
+ elif 'url' in data and data['url'].strip():
313
+ link_media = data['url'].strip()
314
+ print("URL provided:", link_media)
315
+ session['video_url'] = link_media
316
+
317
+ # Handle directory
318
+ elif 'directory' in data and data['directory'].strip():
319
+ directory_input = data['directory'].strip()
320
+ print("Directory provided:", directory_input)
321
+ session['directory_path'] = directory_input
322
+
323
+ # Get parameters
324
+ source_lang = data.get('source_language', 'Automatic detection')
325
+ target_lang = data.get('target_language', 'English (en)')
326
+
327
+ # Process to get subtitles
328
+ result = soni.multilingual_media_conversion(
329
+ media_file=media_file,
330
+ link_media=link_media,
331
+ directory_input=directory_input,
332
+ origin_language=source_lang,
333
+ target_language=target_lang,
334
+ get_translated_text=True,
335
+ is_gui=True
336
+ )
337
+
338
+ # Save subtitles to session
339
+ if result:
340
+ session['subtitles'] = result
341
+ print("Subtitles saved to session")
342
+
343
+ print("Subtitles result:", result)
344
+ return jsonify({
345
+ 'success': True,
346
+ 'subtitles': result,
347
+ 'video_path': session.get('video_path'),
348
+ 'video_url': session.get('video_url'),
349
+ 'directory_path': session.get('directory_path')
350
+ })
351
+ except Exception as e:
352
+ print("Error in get_subtitles:", str(e))
353
+ return jsonify({'success': False, 'error': str(e)})
354
+
355
+ @app.route('/edit_subtitles', methods=['POST'])
356
+ @login_required
357
+ def edit_subtitles():
358
+ try:
359
+ data = request.json
360
+ subtitle_text = data.get('subtitle_text', '')
361
+
362
+ # Process the edited subtitles
363
+ # This would integrate with your existing subtitle processing logic
364
+ return jsonify({'success': True, 'message': 'Subtitles updated successfully'})
365
+ except Exception as e:
366
+ return jsonify({'success': False, 'error': str(e)})
367
+
368
+ @app.route('/voice_imitation', methods=['POST'])
369
+ @login_required
370
+ def voice_imitation():
371
+ try:
372
+ data = request.form
373
+ files = request.files
374
+
375
+ voice_imitation_enabled = data.get('voice_imitation', 'false').lower() == 'true'
376
+ voice_imitation_method = data.get('voice_imitation_method', 'freevc')
377
+ voice_imitation_max_segments = int(data.get('voice_imitation_max_segments', 3))
378
+ voice_imitation_vocals_dereverb = data.get('voice_imitation_vocals_dereverb', 'false').lower() == 'true'
379
+ voice_imitation_remove_previous = data.get('voice_imitation_remove_previous', 'true').lower() == 'true'
380
+
381
+ return jsonify({'success': True})
382
+ except Exception as e:
383
+ return jsonify({'success': False, 'error': str(e)})
384
+
385
+ @app.route('/get_voice_models', methods=['GET'])
386
+ @login_required
387
+ def get_voice_models():
388
+ try:
389
+ method = request.args.get('method', 'RVC')
390
+ models_dir = 'weights'
391
+
392
+ if not os.path.exists(models_dir):
393
+ return jsonify({'success': False, 'error': 'Models directory not found'})
394
+
395
+ # Get all .pth files from the weights directory
396
+ models = [f for f in os.listdir(models_dir) if f.endswith('.pth')]
397
+
398
+ return jsonify({'success': True, 'models': models})
399
+ except Exception as e:
400
+ return jsonify({'success': False, 'error': str(e)})
401
+
402
+ @app.route('/subtitle_settings', methods=['POST'])
403
+ @login_required
404
+ def subtitle_settings():
405
+ try:
406
+ data = request.form
407
+
408
+ # Get subtitle settings
409
+ output_format = data.get('subtitle_format', 'srt')
410
+ soft_subtitles = data.get('soft_subtitles', 'false').lower() == 'true'
411
+ burn_subtitles = data.get('burn_subtitles', 'false').lower() == 'true'
412
+
413
+ # Get Whisper settings
414
+ literalize_numbers = data.get('literalize_numbers', 'true').lower() == 'true'
415
+ vocal_refinement = data.get('vocal_refinement', 'false').lower() == 'true'
416
+ segment_duration = int(data.get('segment_duration', 15))
417
+ whisper_model = data.get('whisper_model', 'large-v3')
418
+ compute_type = data.get('compute_type', 'float16')
419
+ batch_size = int(data.get('batch_size', 8))
420
+
421
+ # Get text segmentation settings
422
+ text_segmentation = data.get('text_segmentation', 'sentence')
423
+ divide_text_by = data.get('divide_text_by', '')
424
+
425
+ # Get diarization and translation settings
426
+ diarization_model = data.get('diarization_model', 'pyannote_2.1')
427
+ translation_process = data.get('translation_process', 'google_translator_batch')
428
+
429
+ return jsonify({'success': True})
430
+ except Exception as e:
431
+ return jsonify({'success': False, 'error': str(e)})
432
+
433
+ @app.route('/output_settings', methods=['POST'])
434
+ @login_required
435
+ def output_settings():
436
+ try:
437
+ data = request.form
438
+
439
+ # Get output settings
440
+ output_type = data.get('output_type', 'video (mp4)')
441
+ output_name = data.get('output_name', '')
442
+ play_sound = data.get('play_sound', 'true').lower() == 'true'
443
+ enable_cache = data.get('enable_cache', 'true').lower() == 'true'
444
+ preview = data.get('preview', 'false').lower() == 'true'
445
+
446
+ return jsonify({'success': True})
447
+ except Exception as e:
448
+ return jsonify({'success': False, 'error': str(e)})
449
+
450
+ @app.route('/save_srt', methods=['POST'])
451
+ @login_required
452
+ def save_srt():
453
+ try:
454
+ data = request.json
455
+ srt_content = data.get('srt_content')
456
+ project_name = data.get('project_name')
457
+
458
+ if not srt_content or not project_name:
459
+ return jsonify({'success': False, 'error': 'Missing required data'})
460
+ video_path = session.get('video_path')
461
+
462
+ # Create project directory with timestamp like in /translate
463
+ #timestamp = datetime.now().strftime("%d-%m-%Y-%H-%M")
464
+ #project_path = os.path.join('exports', f"{timestamp}-{project_name}")
465
+ #os.makedirs(project_path, exist_ok=True)
466
+ if video_path:
467
+ # Úprava řetězce pomocí regulárních výrazů
468
+ cleaned_path = re.sub(r'^exports\\', '', video_path) # Odstraní 'exports\' na začátku
469
+ cleaned_path = re.sub(r'\\video\.mp4$', '', cleaned_path) # Odstraní '\video.mp4' na konci
470
+
471
+ print(cleaned_path)
472
+ else:
473
+ print("Hodnota video_path není v session.")
474
+
475
+ project_path = os.path.join('exports', cleaned_path)
476
+
477
+
478
+ # Save SRT file in the same directory as video
479
+ srt_path = os.path.join(project_path, 'titulky.srt')
480
+ with open(srt_path, 'w', encoding='utf-8') as f:
481
+ f.write(srt_content)
482
+
483
+ return jsonify({'success': True})
484
+ except Exception as e:
485
+ return jsonify({'success': False, 'error': str(e)})
486
+
487
+ @app.route('/purge', methods=['POST'])
488
+ @login_required
489
+ def purge_folders():
490
+ try:
491
+ # Seznam složek k vymazání
492
+ folders = ['outputs', 'audio']
493
+
494
+ for folder in folders:
495
+ if os.path.exists(folder):
496
+ # Vymaže obsah složky
497
+ for filename in os.listdir(folder):
498
+ file_path = os.path.join(folder, filename)
499
+ try:
500
+ if os.path.isfile(file_path) or os.path.islink(file_path):
501
+ os.unlink(file_path)
502
+ elif os.path.isdir(file_path):
503
+ shutil.rmtree(file_path)
504
+ except Exception as e:
505
+ print(f'Failed to delete {file_path}. Reason: {e}')
506
+
507
+ return jsonify({'success': True, 'message': 'Složky byly úspěšně vymazány'})
508
+ except Exception as e:
509
+ return jsonify({'success': False, 'error': str(e)})
510
+
511
+ @app.route('/get_current_video_path', methods=['GET'])
512
+ @login_required
513
+ def get_current_video_path():
514
+ video_path = session.get('current_video_path')
515
+ if video_path:
516
+ return jsonify({
517
+ 'success': True,
518
+ 'video_path': video_path,
519
+ 'filename': os.path.basename(video_path)
520
+ })
521
+ return jsonify({'success': False, 'error': 'No video path in session'})
522
+
523
+ #if __name__ == '__main__':
524
+ # app.run(debug=True)