Ajay Cursor commited on
Commit
c14dbb6
·
1 Parent(s): 6b5524d

English translation mode, ms-precision time range + duration UI, drop Fly from docs

Browse files
Files changed (4) hide show
  1. DEPLOY.md +1 -10
  2. backend/main.py +2 -2
  3. backend/transcribe.py +2 -1
  4. frontend/index.html +22 -3
DEPLOY.md CHANGED
@@ -38,16 +38,7 @@ Free CPU Spaces give 16 GB RAM and a stable public URL like
38
  4. Add env var `SARVAM_API_KEY`. Render injects `PORT`; the container already
39
  honors it. Deploy and share the `*.onrender.com` URL.
40
 
41
- ## Option C — Fly.io (Docker, good for long requests)
42
-
43
- ```bash
44
- fly launch --no-deploy # generates fly.toml from the Dockerfile
45
- fly secrets set SARVAM_API_KEY=your_key
46
- fly scale memory 2048 # give it 2 GB
47
- fly deploy
48
- ```
49
-
50
- ## Option D — Instant link, zero deploy (temporary)
51
 
52
  Fastest way to show a client *right now*, while your server runs locally:
53
 
 
38
  4. Add env var `SARVAM_API_KEY`. Render injects `PORT`; the container already
39
  honors it. Deploy and share the `*.onrender.com` URL.
40
 
41
+ ## Option C — Instant link, zero deploy (temporary)
 
 
 
 
 
 
 
 
 
42
 
43
  Fastest way to show a client *right now*, while your server runs locally:
44
 
backend/main.py CHANGED
@@ -102,8 +102,8 @@ async def transcribe(
102
  "speakers": speakers,
103
  "segments": [
104
  {
105
- "start": round(s.start, 2),
106
- "end": round(s.end, 2),
107
  "speaker_id": s.speaker_id,
108
  "text": s.text,
109
  "gender": speakers.get(s.speaker_id, {}).get("label", "uncertain"),
 
102
  "speakers": speakers,
103
  "segments": [
104
  {
105
+ "start": round(s.start, 3),
106
+ "end": round(s.end, 3),
107
  "speaker_id": s.speaker_id,
108
  "text": s.text,
109
  "gender": speakers.get(s.speaker_id, {}).get("label", "uncertain"),
backend/transcribe.py CHANGED
@@ -36,7 +36,8 @@ def transcribe_with_diarization(
36
 
37
  job = client.speech_to_text_job.create_job(
38
  model="saaras:v3",
39
- mode="verbatim",
 
40
  language_code="unknown",
41
  with_diarization=True,
42
  num_speakers=num_speakers,
 
36
 
37
  job = client.speech_to_text_job.create_job(
38
  model="saaras:v3",
39
+ # "translate" makes Saaras output English regardless of the spoken language.
40
+ mode="translate",
41
  language_code="unknown",
42
  with_diarization=True,
43
  num_speakers=num_speakers,
frontend/index.html CHANGED
@@ -156,7 +156,7 @@
156
 
157
  .transcript { display: flex; flex-direction: column; gap: 10px; }
158
  .seg {
159
- display: grid; grid-template-columns: 58px 1fr; gap: 16px; padding: 15px 18px; position: relative;
160
  border-radius: 16px; border: 1px solid var(--stroke); cursor: pointer; transition: .18s cubic-bezier(.2,.8,.2,1);
161
  background: var(--glass-2); overflow: hidden;
162
  }
@@ -164,7 +164,14 @@
164
  .seg:hover { border-color: var(--stroke-strong); transform: translateX(2px); }
165
  .seg.active { border-color: rgba(168,85,247,.5); background: rgba(168,85,247,.09); box-shadow: 0 8px 24px rgba(168,85,247,.18); }
166
  .seg.active::before { background: var(--grad); }
167
- .seg .time { font-variant-numeric: tabular-nums; font-size: 12px; color: var(--muted); padding-top: 3px; font-weight: 500; }
 
 
 
 
 
 
 
168
  .seg .who { display: flex; align-items: center; gap: 9px; margin-bottom: 6px; }
169
  .seg .who b { font-family: "Space Grotesk"; font-size: 12.5px; }
170
  .seg .txt { font-size: 15px; line-height: 1.55; color: #e9eaf4; }
@@ -241,6 +248,13 @@
241
  const sec = Math.floor(s % 60);
242
  return `${m}:${sec.toString().padStart(2, "0")}`;
243
  };
 
 
 
 
 
 
 
244
 
245
  drop.addEventListener("click", () => fileInput.click());
246
  ["dragover", "dragenter"].forEach(e =>
@@ -326,8 +340,13 @@
326
  el.className = "seg";
327
  el.dataset.start = seg.start;
328
  el.dataset.end = seg.end;
 
329
  el.innerHTML = `
330
- <div class="time">${fmt(seg.start)}</div>
 
 
 
 
331
  <div class="body">
332
  <div class="who">
333
  <span class="dot" style="background:${c}; box-shadow:0 0 10px ${c}88"></span>
 
156
 
157
  .transcript { display: flex; flex-direction: column; gap: 10px; }
158
  .seg {
159
+ display: grid; grid-template-columns: 96px 1fr; gap: 16px; padding: 15px 18px; position: relative;
160
  border-radius: 16px; border: 1px solid var(--stroke); cursor: pointer; transition: .18s cubic-bezier(.2,.8,.2,1);
161
  background: var(--glass-2); overflow: hidden;
162
  }
 
164
  .seg:hover { border-color: var(--stroke-strong); transform: translateX(2px); }
165
  .seg.active { border-color: rgba(168,85,247,.5); background: rgba(168,85,247,.09); box-shadow: 0 8px 24px rgba(168,85,247,.18); }
166
  .seg.active::before { background: var(--grad); }
167
+ .seg .time { font-variant-numeric: tabular-nums; padding-top: 2px;
168
+ display: flex; flex-direction: column; align-items: flex-start; gap: 3px; line-height: 1.25; }
169
+ .seg .time .t-start { color: var(--text); font-weight: 700; font-size: 12.5px; letter-spacing: .01em; transition: color .18s; }
170
+ .seg .time .t-end { color: var(--muted); font-size: 11px; display: flex; align-items: center; gap: 4px; }
171
+ .seg .time .t-end::before { content: "→"; opacity: .45; font-size: 10px; }
172
+ .seg .time .t-dur { margin-top: 3px; font-size: 10px; font-weight: 600; color: var(--cyan);
173
+ background: rgba(34,211,238,.1); border: 1px solid rgba(34,211,238,.22); padding: 1.5px 8px; border-radius: 999px; }
174
+ .seg.active .time .t-start { color: var(--violet); }
175
  .seg .who { display: flex; align-items: center; gap: 9px; margin-bottom: 6px; }
176
  .seg .who b { font-family: "Space Grotesk"; font-size: 12.5px; }
177
  .seg .txt { font-size: 15px; line-height: 1.55; color: #e9eaf4; }
 
248
  const sec = Math.floor(s % 60);
249
  return `${m}:${sec.toString().padStart(2, "0")}`;
250
  };
251
+ // m:ss.mmm — millisecond precision (the resolution Sarvam actually provides).
252
+ const fmtPrecise = (s) => {
253
+ const m = Math.floor(s / 60);
254
+ const sec = Math.floor(s % 60);
255
+ const ms = Math.round((s - Math.floor(s)) * 1000);
256
+ return `${m}:${sec.toString().padStart(2, "0")}.${ms.toString().padStart(3, "0")}`;
257
+ };
258
 
259
  drop.addEventListener("click", () => fileInput.click());
260
  ["dragover", "dragenter"].forEach(e =>
 
340
  el.className = "seg";
341
  el.dataset.start = seg.start;
342
  el.dataset.end = seg.end;
343
+ const dur = Math.max(0, seg.end - seg.start);
344
  el.innerHTML = `
345
+ <div class="time" title="${seg.start}s – ${seg.end}s (${dur.toFixed(3)}s)">
346
+ <span class="t-start">${fmtPrecise(seg.start)}</span>
347
+ <span class="t-end">${fmtPrecise(seg.end)}</span>
348
+ <span class="t-dur">${dur.toFixed(2)}s</span>
349
+ </div>
350
  <div class="body">
351
  <div class="who">
352
  <span class="dot" style="background:${c}; box-shadow:0 0 10px ${c}88"></span>