Spaces:
Running
Running
| """Apollo 11 mission audio search — gradio.Server backend + custom frontend. | |
| Search the diarized transcripts (davanstrien/apollo-11-diarized) and listen | |
| to the original tape at the matched moment (Internet Archive audio, media | |
| fragments). See index.html for the frontend. | |
| """ | |
| import os | |
| import re | |
| from pathlib import Path | |
| from datasets import load_dataset | |
| from fastapi.responses import HTMLResponse, JSONResponse | |
| from gradio import Server | |
| DATASET = "davanstrien/apollo-11-diarized" | |
| print("Loading segments...") | |
| df = load_dataset( | |
| DATASET, "segments", split="train", token=os.environ.get("HF_TOKEN") | |
| ).to_pandas() | |
| df["text_lower"] = df["text"].str.lower() | |
| TAPES = sorted(df["tape"].unique().tolist()) | |
| tapes_ds = load_dataset( | |
| DATASET, "tapes", split="train", token=os.environ.get("HF_TOKEN") | |
| ).to_pandas() | |
| STATS = { | |
| "segments": int(len(df)), | |
| "tapes": len(TAPES), | |
| "hours": int(round(tapes_ds["duration_s"].sum() / 3600)), | |
| } | |
| print(f"{STATS['segments']} segments across {STATS['tapes']} tapes") | |
| app = Server() | |
| INDEX = Path(__file__).parent / "index.html" | |
| def fmt_time(s: float) -> str: | |
| h, rem = divmod(int(s), 3600) | |
| m, sec = divmod(rem, 60) | |
| return f"{h}:{m:02d}:{sec:02d}" | |
| def search(q: str = "", tape: str = "", limit: int = 150): | |
| hits = df | |
| if tape and tape in TAPES: | |
| hits = hits[hits["tape"] == tape] | |
| q = (q or "").strip().lower() | |
| if q: | |
| try: | |
| mask = hits["text_lower"].str.contains(q, regex=True, na=False) | |
| except re.error: | |
| mask = hits["text_lower"].str.contains(re.escape(q), na=False) | |
| hits = hits[mask] | |
| total = int(len(hits)) | |
| rows = [ | |
| { | |
| "tape": r.tape, | |
| "get": fmt_time(r.start), | |
| "start": int(r.start), | |
| "speaker": r.speaker or "?", | |
| "text": r.text, | |
| } | |
| for r in hits.head(limit).itertuples() | |
| ] | |
| return JSONResponse({"total": total, "shown": len(rows), "results": rows}) | |
| def meta(): | |
| return JSONResponse({"stats": STATS, "tapes": TAPES}) | |
| async def homepage(): | |
| return INDEX.read_text(encoding="utf-8") | |
| if __name__ == "__main__": | |
| app.launch() | |