N4DerAX20 commited on
Commit
b181e94
·
verified ·
1 Parent(s): 574bd98

Upload streamlit_app.py

Browse files
Files changed (1) hide show
  1. streamlit_app.py +1 -144
streamlit_app.py CHANGED
@@ -1,145 +1,2 @@
1
- import streamlit as st
2
- import tempfile
3
- from faster_whisper import WhisperModel
4
- import textwrap
5
- from datetime import timedelta
6
- from xml.sax.saxutils import escape
7
 
8
- st.set_page_config(page_title="VO to Subtitle Generator Multi-languages version", layout="wide")
9
- st.title("🌍 VO to Subtitle Generator — Multi-languages Version")
10
-
11
- def format_time(seconds):
12
- td = timedelta(seconds=seconds)
13
- result = str(td)[:11].replace(".", ",")
14
- return result if "," in result else result + ",000"
15
-
16
- def generate_srt(segments, max_chars, max_lines):
17
- srt_text = ""
18
- count = 1
19
- for seg in segments:
20
- start = seg.start
21
- end = seg.end
22
- text = seg.text.strip()
23
- lines = textwrap.wrap(text, width=max_chars)
24
- grouped = [lines[i:i+max_lines] for i in range(0, len(lines), max_lines)]
25
- chunk_count = len(grouped)
26
- duration = end - start
27
- chunk_duration = duration / chunk_count if chunk_count > 0 else duration
28
-
29
- for j, chunk in enumerate(grouped):
30
- chunk_start = start + j * chunk_duration
31
- chunk_end = chunk_start + chunk_duration
32
- timestamp = f"{format_time(chunk_start)} --> {format_time(chunk_end)}"
33
- content = "\n".join(chunk)
34
- srt_text += f"{count}\n{timestamp}\n{content}\n\n"
35
- count += 1
36
- return srt_text
37
-
38
- def generate_fcpxml(segments, version):
39
- xml = [f'<?xml version="1.0" encoding="UTF-8"?>',
40
- f'<!DOCTYPE fcpxml>',
41
- f'<fcpxml version="{version}">',
42
- ' <resources>',
43
- ' <format id="r1" name="FFVideoFormat1080p30" frameDuration="100/3000s" width="1920" height="1080"/>',
44
- ' <effect id="r2" name="Basic Title" uid=".../Effects.localized/Basic Titles.localized/Basic Title.localized/Basic Title.moti"/>',
45
- ' </resources>',
46
- ' <library>',
47
- ' <event name="Transcription">',
48
- ' <project name="Subtitles">',
49
- f' <sequence duration="{round(segments[-1].end, 2)}s" format="r1" tcStart="0s" tcFormat="NDF">',
50
- ' <spine>']
51
- for seg in segments:
52
- start = round(seg.start, 2)
53
- duration = round(seg.end - seg.start, 2)
54
- text = escape(seg.text.strip())
55
- xml.append(
56
- f' <title lane="1" offset="{start}s" ref="r2" duration="{duration}s" start="{start}s">'
57
- f' <text>{text}</text>'
58
- f' </title>'
59
- )
60
- xml.extend([' </spine>',
61
- ' </sequence>',
62
- ' </project>',
63
- ' </event>',
64
- ' </library>',
65
- '</fcpxml>'])
66
- return '\n'.join(xml)
67
-
68
- # --- Sidebar ---
69
- with st.sidebar:
70
- st.header("⚙️ Settings")
71
- uploaded_file = st.file_uploader("Upload MP3 or WAV", type=["mp3", "wav"])
72
- model_size = st.selectbox("Model Size", ["tiny", "base", "small", "medium"])
73
- layout = st.selectbox("Video Layout", ["Horizontal (37 chars)", "Vertical (25 chars)"])
74
- lines = st.selectbox("Lines per Subtitle", [1, 2], index=1)
75
- language_map = {
76
- "Auto": None,
77
- "Arabic": "ar",
78
- "English": "en",
79
- "French": "fr",
80
- "Farsi": "fa",
81
- "Spanish": "es"
82
- }
83
- language = st.selectbox("Language", list(language_map.keys()))
84
- export_format = st.selectbox("Export Format", ["srt", "fcpxmld"])
85
- fcpxml_version = st.selectbox("FCPXML Version", ["1.13", "1.12", "1.11"], index=0) if export_format == "fcpxmld" else None
86
-
87
- if 'subtitle_data' not in st.session_state:
88
- st.session_state.subtitle_data = ""
89
- st.session_state.text_dir = "rtl"
90
- st.session_state.generated = False
91
-
92
- if uploaded_file and st.button("🔁 Generate Subtitle"):
93
- with st.spinner("Transcribing with Whisper..."):
94
- with tempfile.NamedTemporaryFile(delete=False) as temp_audio:
95
- temp_audio.write(uploaded_file.read())
96
- temp_audio.flush()
97
- whisper = WhisperModel(model_size, device="cpu", compute_type="int8")
98
- segments_gen, _ = whisper.transcribe(temp_audio.name, language=language_map[language])
99
- segments = list(segments_gen)
100
- st.session_state.segments = segments
101
-
102
- max_chars = 25 if "Vertical" in layout else 37
103
- max_lines = int(lines)
104
-
105
- if export_format == "srt":
106
- st.session_state.subtitle_data = generate_srt(segments, max_chars, max_lines)
107
- else:
108
- st.session_state.subtitle_data = generate_fcpxml(segments, fcpxml_version)
109
-
110
- st.session_state.generated = True
111
-
112
- # --- Post Processing ---
113
- if st.session_state.generated and st.session_state.subtitle_data:
114
- col1, col2 = st.columns([1, 6])
115
- with col1:
116
- st.write("Text Direction:")
117
- if st.button("⬅️ RTL"):
118
- st.session_state.text_dir = "rtl"
119
- if st.button("➡️ LTR"):
120
- st.session_state.text_dir = "ltr"
121
-
122
- with col2:
123
- st.markdown("### ✏️ Edit Before Download")
124
- preview_html = f'''
125
- <textarea id="subtitle_editor" name="subtitle_editor"
126
- style="width: 100%; height: 300px; padding: 1.5em 2em;
127
- border: 1px solid #ccc; border-radius: 8px;
128
- font-family: monospace; font-size: 14px;
129
- direction: {st.session_state.text_dir}; white-space: pre-wrap;">{st.session_state.subtitle_data}</textarea>
130
- <script>
131
- const editor = document.getElementById('subtitle_editor');
132
- editor.addEventListener('input', () => {{
133
- window.subtitleEdited = editor.value;
134
- }});
135
- window.subtitleEdited = editor.value;
136
- </script>
137
- '''
138
- st.components.v1.html(preview_html, height=360)
139
-
140
- st.download_button(
141
- label="⬇️ Download Subtitle",
142
- data=st.session_state.subtitle_data,
143
- file_name="output." + ("srt" if export_format == "srt" else "fcpxmld"),
144
- mime="text/plain"
145
- )
 
 
 
 
 
 
 
1
 
2
+ <actual code from previous cell, omitted here for brevity>