|
|
import os |
|
|
import sys |
|
|
import time |
|
|
import threading |
|
|
from flask import Flask, render_template, request, jsonify, Response |
|
|
import numpy as np |
|
|
import requests |
|
|
import re |
|
|
import queue |
|
|
import april_asr as april |
|
|
import json |
|
|
|
|
|
|
|
|
try: |
|
|
from googletrans import Translator |
|
|
GOOGLE_TRANSLATE_AVAILABLE = True |
|
|
except Exception as e: |
|
|
print(f"Google Translate loading error: {e}") |
|
|
GOOGLE_TRANSLATE_AVAILABLE = False |
|
|
|
|
|
try: |
|
|
import deepl |
|
|
DEEPL_AVAILABLE = True |
|
|
except ImportError: |
|
|
DEEPL_AVAILABLE = False |
|
|
|
|
|
|
|
|
app = Flask(__name__) |
|
|
|
|
|
|
|
|
live_caption_instance = None |
|
|
is_running = False |
|
|
asr_queue = queue.Queue() |
|
|
translator = None |
|
|
|
|
|
class SimpleGoogleTranslator: |
|
|
def __init__(self): |
|
|
self.session = requests.Session() |
|
|
self.session.headers.update({ |
|
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' |
|
|
}) |
|
|
|
|
|
def translate(self, text, target_lang='tr', source_lang='en'): |
|
|
try: |
|
|
url = "https://translate.googleapis.com/translate_a/single" |
|
|
params = { |
|
|
'client': 'gtx', |
|
|
'sl': source_lang, |
|
|
'tl': target_lang, |
|
|
'dt': 't', |
|
|
'q': text |
|
|
} |
|
|
response = self.session.get(url, params=params, timeout=10) |
|
|
if response.status_code == 200: |
|
|
result = response.json() |
|
|
if result and len(result) > 0 and len(result[0]) > 0: |
|
|
translated_text = ''.join([item[0] for item in result[0] if item[0]]) |
|
|
return translated_text |
|
|
return None |
|
|
except Exception as e: |
|
|
print(f"Simple Google Translate error: {e}") |
|
|
return None |
|
|
|
|
|
class ImprovedTranslator: |
|
|
def __init__(self): |
|
|
self.google_translator = None |
|
|
self.simple_translator = SimpleGoogleTranslator() |
|
|
self.deepl_translator = None |
|
|
|
|
|
def translate(self, text, target_lang, service="Google Translate", deepl_key=""): |
|
|
if not text or not text.strip(): |
|
|
return "" |
|
|
|
|
|
try: |
|
|
cleaned_text = self._clean_text(text) |
|
|
|
|
|
if service == "Google Translate": |
|
|
return self._google_translate(cleaned_text, target_lang) |
|
|
elif service == "DeepL" and DEEPL_AVAILABLE and deepl_key: |
|
|
return self._deepl_translate(cleaned_text, target_lang, deepl_key) |
|
|
else: |
|
|
return f"[{service} not available]" |
|
|
|
|
|
except Exception as e: |
|
|
return f"[Translation error: {str(e)[:50]}...]" |
|
|
|
|
|
def _clean_text(self, text): |
|
|
text = text.strip() |
|
|
text = re.sub(r'\s+', ' ', text) |
|
|
return text |
|
|
|
|
|
def _google_translate(self, text, target_lang): |
|
|
try: |
|
|
result = self.simple_translator.translate(text, target_lang) |
|
|
if result: |
|
|
return result |
|
|
except Exception as e: |
|
|
print(f"Simple translator failed: {e}") |
|
|
|
|
|
if GOOGLE_TRANSLATE_AVAILABLE: |
|
|
try: |
|
|
if self.google_translator is None: |
|
|
self.google_translator = Translator() |
|
|
result = self.google_translator.translate(text, dest=target_lang, src='en') |
|
|
if result and result.text: |
|
|
return result.text |
|
|
except Exception as e: |
|
|
print(f"Googletrans failed: {e}") |
|
|
|
|
|
return "[Google translation failed]" |
|
|
|
|
|
def _deepl_translate(self, text, target_lang, deepl_key): |
|
|
try: |
|
|
if self.deepl_translator is None: |
|
|
self.deepl_translator = deepl.Translator(deepl_key) |
|
|
|
|
|
deepl_lang_map = { |
|
|
'tr': 'TR', 'fr': 'FR', 'de': 'DE', 'es': 'ES', |
|
|
'it': 'IT', 'ru': 'RU', 'ja': 'JA', 'zh-CN': 'ZH', |
|
|
'pt': 'PT', 'nl': 'NL', 'ko': 'KO' |
|
|
} |
|
|
deepl_target = deepl_lang_map.get(target_lang, target_lang.upper()) |
|
|
|
|
|
result = self.deepl_translator.translate_text(text, target_lang=deepl_target) |
|
|
return result.text if result else "[DeepL no result]" |
|
|
|
|
|
except Exception as e: |
|
|
return f"[DeepL error]" |
|
|
|
|
|
def init_asr(): |
|
|
"""ASR modelini başlatır.""" |
|
|
global live_caption_instance |
|
|
if live_caption_instance is None: |
|
|
try: |
|
|
model_path = "april-english-dev-01110_en.april" |
|
|
if not os.path.exists(model_path): |
|
|
print(f"[HATA] Model dosyası bulunamadı: {model_path}") |
|
|
return |
|
|
|
|
|
model = april.Model(model_path) |
|
|
|
|
|
def asr_handler(result_type, tokens): |
|
|
text = "".join(token.token for token in tokens).strip() |
|
|
if not text: |
|
|
return |
|
|
if result_type == april.Result.PARTIAL_RECOGNITION: |
|
|
asr_queue.put({"english": text, "type": "partial"}) |
|
|
elif result_type == april.Result.FINAL_RECOGNITION: |
|
|
asr_queue.put({"english": text, "type": "final"}) |
|
|
|
|
|
live_caption_instance = april.Session(model, asr_handler, asynchronous=True) |
|
|
print("ASR Model başarıyla başlatıldı.") |
|
|
except Exception as e: |
|
|
print(f"[HATA] ASR Model yükleme hatası: {e}") |
|
|
live_caption_instance = None |
|
|
|
|
|
@app.route('/') |
|
|
def index(): |
|
|
return render_template('index.html') |
|
|
|
|
|
@app.route('/start', methods=['POST']) |
|
|
def start_stream(): |
|
|
global is_running, translator |
|
|
if not is_running: |
|
|
init_asr() |
|
|
translator = ImprovedTranslator() |
|
|
is_running = True |
|
|
return jsonify({"status": "started"}) |
|
|
|
|
|
@app.route('/stop', methods=['POST']) |
|
|
def stop_stream(): |
|
|
global is_running, live_caption_instance |
|
|
if is_running: |
|
|
is_running = False |
|
|
if live_caption_instance: |
|
|
live_caption_instance = None |
|
|
return jsonify({"status": "stopped"}) |
|
|
|
|
|
@app.route('/upload_audio', methods=['POST']) |
|
|
def upload_audio(): |
|
|
audio_data = request.data |
|
|
|
|
|
if live_caption_instance: |
|
|
try: |
|
|
live_caption_instance.feed_pcm16(audio_data) |
|
|
except Exception as e: |
|
|
print(f"[HATA] ASR feed hatası: {e}") |
|
|
return jsonify({"status": "error", "message": str(e)}), 500 |
|
|
|
|
|
return '', 204 |
|
|
|
|
|
@app.route('/stream_results') |
|
|
def stream_results(): |
|
|
target_lang = request.args.get("target_lang", "tr") |
|
|
service = request.args.get("service", "Google Translate") |
|
|
deepl_key = request.args.get("deepl_key", "") |
|
|
|
|
|
def generate(): |
|
|
while is_running: |
|
|
try: |
|
|
result = asr_queue.get(timeout=0.1) |
|
|
english_text = result["english"] |
|
|
result_type = result["type"] |
|
|
|
|
|
translated_text = "" |
|
|
if result_type == "partial": |
|
|
translated_text = translator.translate(english_text, target_lang, "Google Translate", "") |
|
|
elif result_type == "final": |
|
|
translated_text = translator.translate(english_text, target_lang, service, deepl_key) |
|
|
|
|
|
response_data = { |
|
|
"english": english_text, |
|
|
"type": result_type, |
|
|
"translation": translated_text, |
|
|
} |
|
|
yield f"data: {json.dumps(response_data)}\n\n" |
|
|
|
|
|
except queue.Empty: |
|
|
continue |
|
|
except Exception as e: |
|
|
print(f"SSE hatası: {e}") |
|
|
break |
|
|
|
|
|
return Response(generate(), mimetype='text/event-stream') |
|
|
|
|
|
if __name__ == '__main__': |
|
|
init_asr() |
|
|
|
|
|
port = int(os.environ.get('PORT', 7860)) |
|
|
app.run(host='0.0.0.0', port=port, threaded=True) |