Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
| 1 |
-
#!/usr
|
| 2 |
# coding: utf-8
|
| 3 |
|
| 4 |
""" Hugging Face Space (Gradio) App: Video -> Audio -> Whisper Transkript (+ Downloads SRT/TXT/VTT/JSON)
|
| 5 |
-
FINALE LÖSUNG:
|
| 6 |
"""
|
| 7 |
import os
|
| 8 |
import subprocess
|
|
@@ -30,11 +30,8 @@ except ImportError:
|
|
| 30 |
# ---------------------------------------------------------------------------
|
| 31 |
# DEFINITIVE AUFRUFMETHODE: yt-dlp als Modul
|
| 32 |
# ---------------------------------------------------------------------------
|
| 33 |
-
# sys.executable ist der volle Pfad zum aktuell laufenden Python-Interpreter.
|
| 34 |
-
# python -m yt_dlp nutzt Pythons Mechanismus, um das von pip installierte Paket zu finden.
|
| 35 |
-
# Dies ist die robusteste Methode und umgeht alle PATH-Probleme.
|
| 36 |
YT_DLP_COMMAND = [sys.executable, "-m", "yt_dlp"]
|
| 37 |
-
FFMPEG_PATH = "ffmpeg"
|
| 38 |
|
| 39 |
# ---------------------------------------------------------------------------
|
| 40 |
# Helper: Shell
|
|
@@ -58,11 +55,10 @@ def resolve_hostname_with_dns_python(hostname):
|
|
| 58 |
except Exception: return socket.gethostbyname(hostname)
|
| 59 |
|
| 60 |
# ---------------------------------------------------------------------------
|
| 61 |
-
# MODIFIZIERTE FUNKTION: Download & Audio
|
| 62 |
# ---------------------------------------------------------------------------
|
| 63 |
def download_video_with_ytdlp(url, out_dir, cookies_path=None, format_selector=None):
|
| 64 |
out_template = str(Path(out_dir) / "%(title)s.%(ext)s")
|
| 65 |
-
# KORREKTUR: Verwende den Modul-Aufruf
|
| 66 |
cmd = YT_DLP_COMMAND + ["-o", out_template]
|
| 67 |
|
| 68 |
try:
|
|
@@ -70,8 +66,9 @@ def download_video_with_ytdlp(url, out_dir, cookies_path=None, format_selector=N
|
|
| 70 |
if hostname:
|
| 71 |
ip_address = resolve_hostname_with_dns_python(hostname)
|
| 72 |
if ip_address:
|
| 73 |
-
|
| 74 |
-
|
|
|
|
| 75 |
except Exception as e:
|
| 76 |
print(f"Custom DNS resolution failed, proceeding without it. Error: {e}")
|
| 77 |
|
|
@@ -91,17 +88,13 @@ def extract_audio_ffmpeg(video_path, out_wav):
|
|
| 91 |
subprocess.run(cmd, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 92 |
return out_wav
|
| 93 |
|
| 94 |
-
# ... (
|
| 95 |
def seconds_to_timestamp(s): h, m, s, ms = int(s//3600), int((s%3600)//60), int(s%60), int(round((s-int(s))*1000)); return f"{h:02d}:{m:02d}:{s:02d},{ms:03d}"
|
| 96 |
def format_timestamp_vtt(s): h, m, s, ms = int(s//3600), int((s%3600)//60), int(s%60), int(round((s-int(s))*1000)); return f"{h:02d}:{m:02d}:{s:02d}.{ms:03d}"
|
| 97 |
def segments_to_srt(segments): parts = [f"{i}\n{seconds_to_timestamp(s['start'])} --> {seconds_to_timestamp(s['end'])}\n{s['text'].strip()}" for i,s in enumerate(segments,1)]; return "\n\n".join(parts) + "\n\n"
|
| 98 |
def segments_to_vtt(segments): parts = ["WEBVTT\n"] + [f"{format_timestamp_vtt(s['start'])} --> {format_timestamp_vtt(s['end'])}\n{s['text'].strip()}" for s in segments]; return "\n\n".join(parts)
|
| 99 |
def segments_to_txt(segments): return "\n".join([f"[{seconds_to_timestamp(s['start'])}] {s['text'].strip()}" for s in segments])
|
| 100 |
def segments_to_json(segments, lang=None, meta=None): data={"language":lang, "segments":segments}; [data.update({"metadata":meta}) if meta else None]; return json.dumps(data,ensure_ascii=False,indent=2)
|
| 101 |
-
|
| 102 |
-
# ---------------------------------------------------------------------------
|
| 103 |
-
# Kern-Pipeline (bleibt identisch)
|
| 104 |
-
# ---------------------------------------------------------------------------
|
| 105 |
def transcribe_pipeline(f, u, m, k, c, fmt):
|
| 106 |
if whisper is None: return "Fehler: whisper ist nicht installiert.",*[None]*5
|
| 107 |
tmpdir = tempfile.mkdtemp(prefix="whisper_space_");
|
|
@@ -117,42 +110,31 @@ def transcribe_pipeline(f, u, m, k, c, fmt):
|
|
| 117 |
if not k and u: [os.remove(video_path) for _ in [1] if os.path.exists(video_path)]
|
| 118 |
meta=f"Model: {m}, Sprache: {lang}"; return txt,files["srt"],files["vtt"],files["txt"],files["json"],meta
|
| 119 |
except Exception as e: return f"Fehler: {e}",*[None]*5
|
| 120 |
-
|
| 121 |
-
# ---------------------------------------------------------------------------
|
| 122 |
-
# MODIFIZIERTE DIAGNOSE
|
| 123 |
-
# ---------------------------------------------------------------------------
|
| 124 |
def dns_internet_diag():
|
| 125 |
lines = []
|
| 126 |
lines.append("=== Python & Version Info ===")
|
| 127 |
lines.append(f"Python Executable: {sys.executable}")
|
| 128 |
try:
|
| 129 |
-
# Führe yt-dlp als Modul aus, um die ECHTE, von pip installierte Version zu prüfen
|
| 130 |
cmd = YT_DLP_COMMAND + ["--version"]
|
| 131 |
version_out = run_capture(cmd).strip()
|
| 132 |
-
lines.append(f"Version via '{' '.join(cmd)}': {version_out}
|
| 133 |
except Exception as e:
|
| 134 |
lines.append(f"Fehler bei der Prüfung der yt-dlp Modul-Version: {e}")
|
| 135 |
-
|
| 136 |
lines.append("\n\n=== DNS-Auflösung (via dnspython mit 8.8.8.8) ===")
|
| 137 |
for host in ["huggingface.co", "www.instagram.com", "youtube.com"]:
|
| 138 |
try: ip = resolve_hostname_with_dns_python(host); lines.append(f"{host} -> {ip} (OK)")
|
| 139 |
except Exception as e: lines.append(f"{host} -> ERROR: {e}")
|
| 140 |
return "\n".join(lines)
|
| 141 |
-
|
| 142 |
-
# ---------------------------------------------------------------------------
|
| 143 |
-
# Gradio UI (bleibt identisch)
|
| 144 |
-
# ---------------------------------------------------------------------------
|
| 145 |
with gr.Blocks() as demo:
|
| 146 |
gr.Markdown("# Video → Whisper Transkript (SRT/TXT/VTT/JSON)")
|
| 147 |
with gr.Tab("Transkription"):
|
| 148 |
with gr.Row():
|
| 149 |
-
with gr.Column(): url_in
|
| 150 |
-
with gr.Column(): transcript
|
| 151 |
def run_transcribe(f, u, m, k, c, fmt): cookies_path = c.name if c else None; d, s, v, t, j, meta = transcribe_pipeline(f, u, m, k, cookies_path, (fmt or None)); return (d, gr.update(value=s,visible=bool(s)), gr.update(value=v,visible=bool(v)), gr.update(value=t,visible=bool(t)), gr.update(value=j,visible=bool(j)), meta,)
|
| 152 |
btn.click(run_transcribe, [file_in, url_in, model_sel, keep_chk, cookies_in, fmt_in], [transcript, srt_dl, vtt_dl, txt_dl, json_dl, status])
|
| 153 |
with gr.Tab("Netzwerk / DNS Diagnose"):
|
| 154 |
-
gr.Markdown("""Prüft die Version von yt-dlp, wie sie von Python als Modul ausgeführt wird."""); diag_btn
|
| 155 |
diag_btn.click(dns_internet_diag, inputs=[], outputs=[diag_out])
|
| 156 |
-
|
| 157 |
if __name__ == "__main__":
|
| 158 |
demo.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)))
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
# coding: utf-8
|
| 3 |
|
| 4 |
""" Hugging Face Space (Gradio) App: Video -> Audio -> Whisper Transkript (+ Downloads SRT/TXT/VTT/JSON)
|
| 5 |
+
FINALE, KORRIGIERTE LÖSUNG: Verwendet die korrekte yt-dlp Option --force-ip.
|
| 6 |
"""
|
| 7 |
import os
|
| 8 |
import subprocess
|
|
|
|
| 30 |
# ---------------------------------------------------------------------------
|
| 31 |
# DEFINITIVE AUFRUFMETHODE: yt-dlp als Modul
|
| 32 |
# ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
| 33 |
YT_DLP_COMMAND = [sys.executable, "-m", "yt_dlp"]
|
| 34 |
+
FFMPEG_PATH = "ffmpeg"
|
| 35 |
|
| 36 |
# ---------------------------------------------------------------------------
|
| 37 |
# Helper: Shell
|
|
|
|
| 55 |
except Exception: return socket.gethostbyname(hostname)
|
| 56 |
|
| 57 |
# ---------------------------------------------------------------------------
|
| 58 |
+
# MODIFIZIERTE FUNKTION: Download & Audio mit der KORREKTEN Option
|
| 59 |
# ---------------------------------------------------------------------------
|
| 60 |
def download_video_with_ytdlp(url, out_dir, cookies_path=None, format_selector=None):
|
| 61 |
out_template = str(Path(out_dir) / "%(title)s.%(ext)s")
|
|
|
|
| 62 |
cmd = YT_DLP_COMMAND + ["-o", out_template]
|
| 63 |
|
| 64 |
try:
|
|
|
|
| 66 |
if hostname:
|
| 67 |
ip_address = resolve_hostname_with_dns_python(hostname)
|
| 68 |
if ip_address:
|
| 69 |
+
print(f"Resolved {hostname} to {ip_address}. Using --force-ip.")
|
| 70 |
+
# DIES IST DIE KORREKTE OPTION, KEINE HALLUZINATION
|
| 71 |
+
cmd.extend(["--force-ip", ip_address])
|
| 72 |
except Exception as e:
|
| 73 |
print(f"Custom DNS resolution failed, proceeding without it. Error: {e}")
|
| 74 |
|
|
|
|
| 88 |
subprocess.run(cmd, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 89 |
return out_wav
|
| 90 |
|
| 91 |
+
# ... (Rest des Codes bleibt identisch)
|
| 92 |
def seconds_to_timestamp(s): h, m, s, ms = int(s//3600), int((s%3600)//60), int(s%60), int(round((s-int(s))*1000)); return f"{h:02d}:{m:02d}:{s:02d},{ms:03d}"
|
| 93 |
def format_timestamp_vtt(s): h, m, s, ms = int(s//3600), int((s%3600)//60), int(s%60), int(round((s-int(s))*1000)); return f"{h:02d}:{m:02d}:{s:02d}.{ms:03d}"
|
| 94 |
def segments_to_srt(segments): parts = [f"{i}\n{seconds_to_timestamp(s['start'])} --> {seconds_to_timestamp(s['end'])}\n{s['text'].strip()}" for i,s in enumerate(segments,1)]; return "\n\n".join(parts) + "\n\n"
|
| 95 |
def segments_to_vtt(segments): parts = ["WEBVTT\n"] + [f"{format_timestamp_vtt(s['start'])} --> {format_timestamp_vtt(s['end'])}\n{s['text'].strip()}" for s in segments]; return "\n\n".join(parts)
|
| 96 |
def segments_to_txt(segments): return "\n".join([f"[{seconds_to_timestamp(s['start'])}] {s['text'].strip()}" for s in segments])
|
| 97 |
def segments_to_json(segments, lang=None, meta=None): data={"language":lang, "segments":segments}; [data.update({"metadata":meta}) if meta else None]; return json.dumps(data,ensure_ascii=False,indent=2)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 98 |
def transcribe_pipeline(f, u, m, k, c, fmt):
|
| 99 |
if whisper is None: return "Fehler: whisper ist nicht installiert.",*[None]*5
|
| 100 |
tmpdir = tempfile.mkdtemp(prefix="whisper_space_");
|
|
|
|
| 110 |
if not k and u: [os.remove(video_path) for _ in [1] if os.path.exists(video_path)]
|
| 111 |
meta=f"Model: {m}, Sprache: {lang}"; return txt,files["srt"],files["vtt"],files["txt"],files["json"],meta
|
| 112 |
except Exception as e: return f"Fehler: {e}",*[None]*5
|
|
|
|
|
|
|
|
|
|
|
|
|
| 113 |
def dns_internet_diag():
|
| 114 |
lines = []
|
| 115 |
lines.append("=== Python & Version Info ===")
|
| 116 |
lines.append(f"Python Executable: {sys.executable}")
|
| 117 |
try:
|
|
|
|
| 118 |
cmd = YT_DLP_COMMAND + ["--version"]
|
| 119 |
version_out = run_capture(cmd).strip()
|
| 120 |
+
lines.append(f"Version via '{' '.join(cmd)}': {version_out}")
|
| 121 |
except Exception as e:
|
| 122 |
lines.append(f"Fehler bei der Prüfung der yt-dlp Modul-Version: {e}")
|
|
|
|
| 123 |
lines.append("\n\n=== DNS-Auflösung (via dnspython mit 8.8.8.8) ===")
|
| 124 |
for host in ["huggingface.co", "www.instagram.com", "youtube.com"]:
|
| 125 |
try: ip = resolve_hostname_with_dns_python(host); lines.append(f"{host} -> {ip} (OK)")
|
| 126 |
except Exception as e: lines.append(f"{host} -> ERROR: {e}")
|
| 127 |
return "\n".join(lines)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 128 |
with gr.Blocks() as demo:
|
| 129 |
gr.Markdown("# Video → Whisper Transkript (SRT/TXT/VTT/JSON)")
|
| 130 |
with gr.Tab("Transkription"):
|
| 131 |
with gr.Row():
|
| 132 |
+
with gr.Column(): url_in=gr.Textbox(label="Video URL",placeholder="https://..."); file_in=gr.File(label="Oder Videodatei hochladen"); cookies_in=gr.File(label="Cookies.txt (optional, für yt-dlp)"); fmt_in=gr.Textbox(label="Format (optional, yt-dlp -f)",placeholder="z.B. bestvideo+bestaudio/best"); model_sel=gr.Radio(["tiny","base","small","medium","large"],value="small",label="Whisper-Modell"); keep_chk=gr.Checkbox(label="Video behalten (bei URL-Download)",value=False); btn=gr.Button("Transkribieren"); status=gr.Textbox(label="Status / Meta",interactive=False)
|
| 133 |
+
with gr.Column(): transcript=gr.Textbox(label="Transkript",lines=20); srt_dl=gr.File(label="SRT"); vtt_dl=gr.File(label="VTT"); txt_dl=gr.File(label="TXT"); json_dl=gr.File(label="JSON")
|
| 134 |
def run_transcribe(f, u, m, k, c, fmt): cookies_path = c.name if c else None; d, s, v, t, j, meta = transcribe_pipeline(f, u, m, k, cookies_path, (fmt or None)); return (d, gr.update(value=s,visible=bool(s)), gr.update(value=v,visible=bool(v)), gr.update(value=t,visible=bool(t)), gr.update(value=j,visible=bool(j)), meta,)
|
| 135 |
btn.click(run_transcribe, [file_in, url_in, model_sel, keep_chk, cookies_in, fmt_in], [transcript, srt_dl, vtt_dl, txt_dl, json_dl, status])
|
| 136 |
with gr.Tab("Netzwerk / DNS Diagnose"):
|
| 137 |
+
gr.Markdown("""Prüft die Version von yt-dlp, wie sie von Python als Modul ausgeführt wird."""); diag_btn=gr.Button("Diagnose starten"); diag_out=gr.Textbox(label="Diagnose-Ausgabe",lines=25)
|
| 138 |
diag_btn.click(dns_internet_diag, inputs=[], outputs=[diag_out])
|
|
|
|
| 139 |
if __name__ == "__main__":
|
| 140 |
demo.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)))
|