Tusahartsar commited on
Commit
48b403b
Β·
verified Β·
1 Parent(s): 931608b

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +176 -0
app.py ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import whisper
3
+ import tempfile
4
+ import os
5
+ import re
6
+ from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
7
+
8
+ # =========================
9
+ # PAGE CONFIG
10
+ # =========================
11
+ st.set_page_config(page_title="Speech to Text Translator", page_icon="πŸŽ™οΈ", layout="centered")
12
+
13
+ # =========================
14
+ # UI STYLE
15
+ # =========================
16
+ st.markdown("""
17
+ <style>
18
+ html, body, [data-testid="stAppViewContainer"] {
19
+ background: radial-gradient(circle at 20% 20%, #1e293b, #020617 70%);
20
+ color: white;
21
+ font-family: 'Inter', sans-serif;
22
+ }
23
+ .title {
24
+ text-align: center;
25
+ font-size: 40px;
26
+ font-weight: 700;
27
+ }
28
+ .subtitle {
29
+ text-align: center;
30
+ color: #cbd5e1;
31
+ margin-bottom: 22px;
32
+ }
33
+ [data-testid="stFileUploader"] {
34
+ border-radius: 16px;
35
+ border: 1px dashed rgba(255,255,255,0.25);
36
+ }
37
+ .result-box {
38
+ background: rgba(16,185,129,0.12);
39
+ border-radius: 16px;
40
+ padding: 16px;
41
+ border: 1px solid rgba(16,185,129,0.35);
42
+ }
43
+ </style>
44
+ """, unsafe_allow_html=True)
45
+
46
+ # =========================
47
+ # HEADER
48
+ # =========================
49
+ st.markdown('<div class="title">πŸŽ™οΈ Speech to Text Translator</div>', unsafe_allow_html=True)
50
+ st.markdown('<div class="subtitle">Transcribe speech or translate into any language</div>', unsafe_allow_html=True)
51
+
52
+ # =========================
53
+ # TEXT UTILS
54
+ # =========================
55
+ def split_text(text, max_len=200):
56
+ sentences = re.split(r'(?<=[.!?γ€‚οΌοΌŸ])', text)
57
+ chunks = []
58
+ cur = ""
59
+ for s in sentences:
60
+ if len(cur) + len(s) < max_len:
61
+ cur += " " + s
62
+ else:
63
+ chunks.append(cur.strip())
64
+ cur = s
65
+ if cur:
66
+ chunks.append(cur.strip())
67
+ return chunks
68
+
69
+ # =========================
70
+ # MODEL CACHE
71
+ # =========================
72
+ @st.cache_resource
73
+ def load_models():
74
+ whisper_model = whisper.load_model("base")
75
+ model_name = "facebook/nllb-200-distilled-600M"
76
+ tokenizer = AutoTokenizer.from_pretrained(model_name)
77
+ nllb_model = AutoModelForSeq2SeqLM.from_pretrained(model_name)
78
+ return whisper_model, tokenizer, nllb_model
79
+
80
+ whisper_model, tokenizer, nllb_model = load_models()
81
+
82
+ # =========================
83
+ # LANGUAGE MAP
84
+ # =========================
85
+ LANG_CODE = {
86
+ "Arabic":"arb_Arab","Assamese":"asm_Beng","Awadhi":"awa_Deva",
87
+ "Bengali":"ben_Beng","Bhojpuri":"bho_Deva","Chinese":"zho_Hans",
88
+ "English":"eng_Latn","French":"fra_Latn","German":"deu_Latn",
89
+ "Hindi":"hin_Deva","Japanese":"jpn_Jpan","Korean":"kor_Hang",
90
+ "Maithili":"mai_Deva","Marathi":"mar_Deva","Persian":"pes_Arab",
91
+ "Punjabi":"pan_Guru","Russian":"rus_Cyrl","Sanskrit":"san_Deva",
92
+ "Spanish":"spa_Latn","Tamil":"tam_Taml","Telugu":"tel_Telu",
93
+ "Urdu":"urd_Arab","Vietnamese":"vie_Latn"
94
+ }
95
+
96
+ # =========================
97
+ # OPTIONS
98
+ # =========================
99
+ col1, col2 = st.columns(2)
100
+ with col1:
101
+ transcribe = st.checkbox("πŸ“„ Transcribe")
102
+ with col2:
103
+ translate = st.checkbox("🌍 Translate", value=True)
104
+
105
+ target_lang = None
106
+ if translate:
107
+ target_lang = st.selectbox("Translate into", sorted(LANG_CODE.keys()))
108
+
109
+ # =========================
110
+ # UPLOAD
111
+ # =========================
112
+ audio_file = st.file_uploader(
113
+ "Upload audio (MP3, WAV, M4A, MP4)",
114
+ type=["mp3","wav","m4a","mp4"]
115
+ )
116
+
117
+ if audio_file:
118
+ st.audio(audio_file)
119
+
120
+ # =========================
121
+ # PROCESS
122
+ # =========================
123
+ if st.button("πŸš€ Process Audio") and audio_file:
124
+
125
+ with st.spinner("Processing audio..."):
126
+
127
+ # Save uploaded audio
128
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp:
129
+ tmp.write(audio_file.read())
130
+ tmp_path = tmp.name
131
+
132
+ # ---------- TRANSCRIBE ----------
133
+ result = whisper_model.transcribe(tmp_path, fp16=False)
134
+ detected_lang = result["language"]
135
+ text = result["text"]
136
+
137
+ st.success(f"Detected language: {detected_lang}")
138
+
139
+ output_text = text
140
+
141
+ # ---------- TRANSLATE ----------
142
+ if translate and target_lang:
143
+ tgt_code = LANG_CODE[target_lang]
144
+ chunks = split_text(text)
145
+
146
+ translated_parts = []
147
+
148
+ for chunk in chunks:
149
+ inputs = tokenizer(chunk, return_tensors="pt")
150
+
151
+ tokens = nllb_model.generate(
152
+ **inputs,
153
+ forced_bos_token_id=tokenizer.convert_tokens_to_ids(tgt_code),
154
+ max_length=256,
155
+ num_beams=4,
156
+ no_repeat_ngram_size=3,
157
+ repetition_penalty=1.2,
158
+ early_stopping=True
159
+ )
160
+
161
+ translated = tokenizer.batch_decode(tokens, skip_special_tokens=True)[0]
162
+ translated_parts.append(translated)
163
+
164
+ output_text = " ".join(translated_parts)
165
+
166
+ # ================= OUTPUT =================
167
+ st.markdown("### πŸ“ Output Text")
168
+ st.markdown(f'<div class="result-box">{output_text}</div>', unsafe_allow_html=True)
169
+
170
+ st.download_button(
171
+ "⬇ Download Text",
172
+ output_text,
173
+ file_name="translated_text.txt"
174
+ )
175
+
176
+ os.remove(tmp_path)