prav2705 commited on
Commit
e411cd2
·
1 Parent(s): 39eb052

Restore Dashboard as main app: serve frontend from FastAPI, add Dockerfile, remove Streamlit entry point

Browse files
Files changed (4) hide show
  1. Dockerfile +24 -0
  2. README.md +0 -11
  3. backend/main.py +16 -0
  4. streamlit_ui.py +132 -0
Dockerfile ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use Python 3.12 slim as base
2
+ FROM python:3.12-slim
3
+
4
+ # Install system dependencies
5
+ RUN apt-get update && apt-get install -y \
6
+ ffmpeg \
7
+ && rm -rf /var/lib/apt/lists/*
8
+
9
+ # Set working directory
10
+ WORKDIR /app
11
+
12
+ # Copy requirements and install
13
+ COPY backend/requirements.txt .
14
+ RUN pip install --no-cache-dir -r requirements.txt
15
+
16
+ # Copy the rest of the application
17
+ COPY . .
18
+
19
+ # Exposure port
20
+ EXPOSE 7860
21
+
22
+ # Run the application
23
+ # Use 0.0.0.0 and port 7860 (default for Hugging Face Spaces)
24
+ CMD ["uvicorn", "backend.main:app", "--host", "0.0.0.0", "--port", "7860", "--root-path", ""]
README.md CHANGED
@@ -1,14 +1,3 @@
1
- ---
2
- title: Swecha Telugu Audio Tracker
3
- emoji: 🎙️
4
- colorFrom: red
5
- colorTo: yellow
6
- sdk: streamlit
7
- sdk_version: "1.42.0"
8
- app_file: streamlit_app.py
9
- pinned: false
10
- ---
11
-
12
  # audio-tracker
13
 
14
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  # audio-tracker
2
 
3
 
backend/main.py CHANGED
@@ -10,6 +10,8 @@ from typing import Any
10
  import requests
11
  from dotenv import load_dotenv
12
  from fastapi import FastAPI, File, Form, HTTPException, UploadFile
 
 
13
  from pydantic import BaseModel
14
  from fastapi.middleware.cors import CORSMiddleware
15
  from transformers import pipeline
@@ -216,6 +218,20 @@ def health():
216
  "model_loaded": get_asr_pipeline.cache_info().currsize > 0,
217
  }
218
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
219
 
220
  @app.post("/transcribe")
221
  async def transcribe(audio: UploadFile = File(...)):
 
10
  import requests
11
  from dotenv import load_dotenv
12
  from fastapi import FastAPI, File, Form, HTTPException, UploadFile
13
+ from fastapi.staticfiles import StaticFiles
14
+ from fastapi.responses import FileResponse
15
  from pydantic import BaseModel
16
  from fastapi.middleware.cors import CORSMiddleware
17
  from transformers import pipeline
 
218
  "model_loaded": get_asr_pipeline.cache_info().currsize > 0,
219
  }
220
 
221
+ # Mount static files from the frontend directory
222
+ # This allows serving index.html, app.js, etc. directly from the backend
223
+ # We mount at root "/" but we must do this AFTER declaring all API routes
224
+ # so the static files don't intercept API calls.
225
+ frontend_path = os.path.absolute(os.path.join(os.path.dirname(__file__), "..", "frontend"))
226
+
227
+ if os.path.exists(frontend_path):
228
+ @app.get("/", include_in_schema=False)
229
+ async def read_index():
230
+ return FileResponse(os.path.join(frontend_path, "index.html"))
231
+
232
+ # Mount remaining static files (js, css)
233
+ app.mount("/", StaticFiles(directory=frontend_path), name="static")
234
+
235
 
236
  @app.post("/transcribe")
237
  async def transcribe(audio: UploadFile = File(...)):
streamlit_ui.py ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import tempfile
3
+ import subprocess
4
+ import re
5
+ from functools import lru_cache
6
+ from typing import Any
7
+
8
+ import streamlit as st
9
+ from transformers import pipeline
10
+ import requests
11
+
12
+ # Page Config
13
+ st.set_page_config(
14
+ page_title="Swecha Telugu Audio Tracker",
15
+ page_icon="🎙️",
16
+ layout="centered"
17
+ )
18
+
19
+ # Constants & Env
20
+ MODEL_ID = os.getenv("MODEL_ID", "viswamaicoe/swecha-gonthuka-asr")
21
+ ASR_DEVICE = os.getenv("ASR_DEVICE", "cpu").lower()
22
+ SWECHA_API_BASE = os.getenv("SWECHA_API_BASE", "https://api.corpus.swecha.org")
23
+ SWECHA_UPLOAD_PATH = os.getenv("SWECHA_UPLOAD_PATH", "/api/v1/content")
24
+ SWECHA_AUTH_TOKEN = os.getenv("SWECHA_AUTH_TOKEN", "")
25
+
26
+ # --- Logic from backend/main.py ---
27
+
28
+ @lru_cache(maxsize=1)
29
+ def get_asr_pipeline():
30
+ device = 0 if ASR_DEVICE == "cuda" else -1
31
+ return pipeline(
32
+ task="automatic-speech-recognition",
33
+ model=MODEL_ID,
34
+ device=device,
35
+ chunk_length_s=30,
36
+ batch_size=8,
37
+ )
38
+
39
+ def clean_noisy_telugu(text: str) -> str:
40
+ if not text:
41
+ return ""
42
+ cleaned = re.sub(r'్{2,}', '్', text)
43
+ cleaned = re.sub(r'\s+', ' ', cleaned).strip()
44
+ return cleaned
45
+
46
+ def transcribe_audio(raw_bytes: bytes, suffix: str) -> str:
47
+ asr = get_asr_pipeline()
48
+
49
+ with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as input_file:
50
+ input_file.write(raw_bytes)
51
+ input_path = input_file.name
52
+
53
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as output_file:
54
+ output_path = output_file.name
55
+
56
+ try:
57
+ ffmpeg_command = [
58
+ "ffmpeg", "-y", "-i", input_path,
59
+ "-acodec", "pcm_s16le", "-ac", "1", "-ar", "16000",
60
+ output_path,
61
+ ]
62
+ subprocess.run(ffmpeg_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
63
+
64
+ result = asr(output_path, generate_kwargs={"task": "transcribe", "language": "telugu"})
65
+
66
+ text = ""
67
+ if isinstance(result, dict) and "text" in result:
68
+ text = clean_noisy_telugu(result["text"])
69
+ elif isinstance(result, str):
70
+ text = clean_noisy_telugu(result)
71
+ return text
72
+
73
+ finally:
74
+ for path in (input_path, output_path):
75
+ if os.path.exists(path):
76
+ os.remove(path)
77
+
78
+ def push_to_swecha(audio_bytes, filename, transcript, title, description):
79
+ if not SWECHA_AUTH_TOKEN:
80
+ return {"error": "SWECHA_AUTH_TOKEN is not configured"}
81
+
82
+ url = f"{SWECHA_API_BASE.rstrip('/')}/{SWECHA_UPLOAD_PATH.lstrip('/')}"
83
+ headers = {"Authorization": f"Bearer {SWECHA_AUTH_TOKEN}"}
84
+ files = {"audio": (filename, audio_bytes, "audio/webm")}
85
+ data = {"title": title, "description": description, "transcript": transcript}
86
+
87
+ resp = requests.post(url, headers=headers, files=files, data=data, timeout=60)
88
+ return resp.json() if resp.ok else {"error": resp.text}
89
+
90
+ # --- Streamlit UI ---
91
+
92
+ st.title("🎙️ Swecha Telugu Audio Tracker")
93
+ st.markdown("Convert Telugu audio to text and store it in the Swecha Corpus.")
94
+
95
+ tab1, tab2 = st.tabs(["Upload/Record", "Settings"])
96
+
97
+ with tab2:
98
+ st.header("Configuration")
99
+ model_id = st.text_input("ASR Model ID", MODEL_ID)
100
+ auth_token = st.text_input("Swecha Auth Token", SWECHA_AUTH_TOKEN, type="password")
101
+ if st.button("Save Settings"):
102
+ os.environ["MODEL_ID"] = model_id
103
+ os.environ["SWECHA_AUTH_TOKEN"] = auth_token
104
+ st.success("Settings updated for this session!")
105
+
106
+ with tab1:
107
+ audio_file = st.file_uploader("Choose an audio file", type=["wav", "mp3", "webm", "m4a"])
108
+
109
+ # Simple Record placeholder since custom components like streamlit-mic-recorder
110
+ # might need specific installation and configuration.
111
+ st.info("You can also record audio if you have 'streamlit-mic-recorder' installed. For now, please upload a file.")
112
+
113
+ if audio_file:
114
+ st.audio(audio_file)
115
+
116
+ with st.expander("Metadata (Optional for storage)"):
117
+ title = st.text_input("Title", value=audio_file.name)
118
+ desc = st.text_area("Description")
119
+
120
+ if st.button("Transcribe", type="primary"):
121
+ with st.spinner("Transcribing Telugu..."):
122
+ try:
123
+ text = transcribe_audio(audio_file.read(), os.path.splitext(audio_file.name)[1])
124
+ st.subheader("Transcription:")
125
+ st.write(text)
126
+
127
+ if text and SWECHA_AUTH_TOKEN:
128
+ if st.button("Push to Swecha Corpus"):
129
+ res = push_to_swecha(audio_file.getvalue(), audio_file.name, text, title, desc)
130
+ st.json(res)
131
+ except Exception as e:
132
+ st.error(f"Error: {e}")