Spaces:
Sleeping
Sleeping
Commit History
-
Phrasebook eval harness + accent/filler-tolerant matching
ous-sow +1: Claude Opus 5.5- configs/eval/phrasebook_eval.json: 85 held-out inputs (typos, code-switching, filler words, open-ended questions that must reach the LLM), written to differ from the curated aliases. - scripts/eval_phrasebook.py: scores correct / wrong / false_hit / miss per language. - _normalize now folds Latin accents (ça -> ca), drops politeness filler (please, svp, s'il vous plaît) and leading articles (du, une, some). Applied to both sides; Bambara/Pular letters (ɛ ɔ ɓ ŋ) are untouched. Hit rate on the eval set: before aliases bam 43% ful 46% + aliases bam 80% ful 77% + normaliser bam 88% ful 86% wrong=0 and false_hit=0 at every step. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>ea5dc26 -
Phrasebook: +502 English paraphrase and French aliases
ous-sow +1: Claude Opus 5.5Adds sources / source_fr / sources_fr to all 210 curated rows via scripts/add_phrasebook_aliases.py (idempotent, aborts on any alias that would map to two different targets). Bambara and Pular target strings are untouched — verified against HEAD. The two context-dependent Pular "We are working" rows intentionally get no aliases. Bambara: 100 rows -> 340 match keys. Pular: 110 rows -> 363 match keys. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>b8a88ef
-
Phrasebook: multi-alias + French source keys, plus misses-script stub
jefffffff9 +1: Claude Opus 4.7Two-track vocabulary enrichment that keeps the matcher and UI unchanged: 1. Multi-alias entries. Each curated row may now carry any combination of `source`, `sources` (list), `source_fr`, `sources_fr` (list). The loader flattens them into one match-candidate per alias, all pointing at the same target translation. A typed paraphrase ("morning, sir") or French equivalent ("bonjour") hits the same Bambara/Pular target as the canonical English source. Existing single-`source` rows keep working unchanged (verified: 110 rows → 110 candidates, exact match preserved). 2. top_k now dedupes by canonical target so multi-alias rows can't crowd out the RAG few-shot slots. 3. scripts/phrasebook_misses.py — stub for the data-driven curation loop. Reads data/field_turns.jsonl, groups translate-phase rows where phrasebook=null, prints the most frequent unmet inputs. Filters by --lang and --since. --draft (LLM-proposed target per miss) is a marked TODO — wire it when …5815492
-
Forbid parenthetical glosses in LLM replies
jefffffff9 +1: Claude Opus 4.7The model was appending English literal-translation annotations (e.g. "On walli e jam? (Lit: Did you sleep in peace?)") which then got read aloud by TTS as gibberish. Two-layer fix: 1. System prompt now explicitly bans "(Lit: ...)", "(meaning ...)", and any English/French parenthetical aside, and demands 100% target-language output. 2. Defensive client-side regex strips any "(Lit/Literal/Meaning/ Translation/English/French ...)" parenthetical the model emits anyway before returning the string to TTS. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>757e833
-
Stage 4: split translate/reply UI + CPU-safe TTS + reply-not-translate prompt
jefffffff9 +1: Claude Opus 4.7- 4-box layout on both Voice and Text tabs: phrasebook translation (text + audio) is automatic on submit; "Generate reply" runs the dialect-anchored LLM only when clicked. - Shared gr.State carries the canonical input (typed text or Whisper transcript) into the reply button so we never re-transcribe. - Robust device resolution: probe cuda.device_count(), and have _synthesize retry on CPU when CUDA path raises (fixes "Torch not compiled with CUDA" on CPU-only laptops). - System prompt now explicitly tells the LLM to REPLY conversationally and reframes the curated few-shot pairs as style/orthography references only, fixing the regression where the model would echo the phrasebook target verbatim instead of replying. - README: add Stage 4 entry + update entry-points table. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>9e99c2c -
Per-turn telemetry + RAG few-shot on phrasebook miss
jefffffff9Telemetry (src/engine/turn_logger.py) Thread-safe JSONL append logger writing one self-contained row per turn to data/field_turns.jsonl (overridable via FIELD_TURNS_PATH). Captures ts, tab, langs, transcript/user_text, phrasebook hit details, llm model + ms, reply, tts ms, total ms, error. Foundation for field-test review, phrasebook hit-rate measurement, and Stage-4 training-data curation. Never raises — telemetry must not break the user-facing pipeline. RAG few-shot (src/llm/phrasebook.py + src/llm/minimal_client.py) - phrasebook.top_k(text, lang, k=3): nearest-K phrasebook entries regardless of threshold, sorted by descending fuzzy score. - MinimalClient.chat() now accepts extra_examples; _build_system_prompt appends them as a second 'Additional reference phrases relevant to the current user input' section after the 30-pair anchor list. app_minimal.py - Both run_pipeline (voice) and run_text_pipeline (text) now share a single _resolve_reply() help…064d08b -
Remove stale Qwen references from minimal-baseline docstrings
jefffffff9Runtime defaults already point to CohereLabs/aya-expanse-32b; only docstrings / usage examples still named Qwen. Cosmetic cleanup only.cc82bd8
-
Ground-zero Stages 1–3: dialect anchors + phrasebook short-circuit + Aya-Expanse
jefffffff9Stage 1 — dialect-pinned LLM client (src/llm/minimal_client.py) Plain-text replacement for GemmaClient's JSON/teacher flow. System prompt pins Bambara-Mali and Pular-Fuuta-Jallon explicitly, names forbidden neighbouring languages (Wolof, Hausa, Pulaar-Senegal, Fulfulde-Nigeria, Jula-CI), and injects a 30-pair bilingual gold list as few-shot anchoring from configs/dialect_anchors/{bambara_mali,pular_guinea}.json. Stage 2 — curated phrasebook short-circuit (src/llm/phrasebook.py) 100 Bambara + 110 Pular English-keyed pairs across greetings, family, food, farming, health, shopping, travel, clarity, time, parting. Fuzzy matched (threshold 0.88) before every LLM call; on hit returns the gold translation directly — zero drift risk, zero latency. Stage 3 — default LLM swapped to CohereLabs/aya-expanse-32b 23-language multilingual base with stronger West African coverage than Qwen 2.5-7B. Overridable via LLM_MODEL_ID. Space wiring - README frontmatter app_file: app.p…d0e28fa
-
space(ground-zero): point Space at app_minimal.py
Broulaye Doumbia26659d8 -
step 2: add app_minimal.py — zero-shot baseline for rebuild.
Broulaye Doumbia34edd5f -
fix read me
Broulaye Doumbiada3a060 -
restructuring
Broulaye Doumbia76aac1b -
push docs and script
Broulaye Doumbiacc8b90c
-
Add torchcodec install for datasets 4.x audio decoding
jefffffff9 +1: Claude Opus 4.7datasets >= 4.0 uses torchcodec as the audio backend; prepare_dataset would fail with ImportError on batch['audio'] without it. - scripts/runpod_setup.sh: pip install torchcodec with torch-version pinning fallback (0.1/0.2/0.3/0.4 → torch 2.4/2.5/2.6/2.7+) - kaggle_master_trainer.ipynb Cell 2: defensive try/except install so the notebook is self-healing on any fresh environment Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>bb78cbf -
Prepare training stack for RunPod: env-aware notebook + bootstrap script
jefffffff9 +1: Claude Sonnet 4.6Cell 3 now auto-detects Kaggle (/kaggle/working), Colab (/content), RunPod (/workspace), or local — and adjusts defaults per environment. On RunPod the base model defaults to whisper-large-v3-turbo (128 mel bins, matches the Space and fits in 24 GB VRAM); on Kaggle T4 it stays on whisper-small to avoid OOM. Batch size / grad accumulation tuned per card (8x4 on 24 GB vs 16x2 on T4, both yield effective batch 32). TRAIN_LANG, HF_USERNAME, and WHISPER_MODEL_ID are now env-var overridable so the notebook can be driven headlessly from a shell. scripts/runpod_setup.sh bootstraps a fresh pod: - clones the Space repo into /workspace/sahel-voice - installs training deps (peft, evaluate, tensorboard, etc.) that are intentionally absent from the HF Spaces runtime requirements.txt - sources .env for HF_TOKEN; falls back to prompting the user - creates persistent checkpoint dirs on the Volume disk so adapters survive pod stop/start - prints GPU / VRAM sanity check at the end C…9049ef3 -
Align Whisper default to turbo-v3 + add document upload to Knowledge Base tab
jefffffff9 +1: Claude Sonnet 4.6The __main__ re-read of WHISPER_MODEL_ID still defaulted to whisper-small, overriding the module-level default of whisper-large-v3-turbo. Align both so the Space uses turbo-v3 consistently with the training notebook. Add a new section to the Knowledge Base tab that accepts multiple PDF, Word, or TXT uploads tagged to a specific language (Bambara or Fula). Each upload: - is parsed with pypdf / python-docx / plain text - runs through language-specific normalisation (Adlam -> Latin for Fula, French-influenced spellings -> standard Bambara) - is split into 3-25-word sentences - appends to vocabulary.jsonl in the feedback repo so the Kaggle notebook picks it up on the next training run Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>cc50efb -
Fix WhisperProcessor import in reload + upgrade base to large-v3-turbo
jefffffff9 +1: Claude Sonnet 4.6_reload_adapters_from_hub() imported WhisperForConditionalGeneration but not WhisperProcessor, causing: "name 'WhisperProcessor' is not defined". Add WhisperProcessor to the same try/except import block. Switch default WHISPER_MODEL_ID from whisper-small (80 mel bins) to whisper-large-v3-turbo (128 mel bins) so the base processor matches the fine-tuned adapters. Without this the fallback path still produces 80-channel inputs that turbo-based adapters reject. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>c33a061 -
Fix mel-bin mismatch: load per-language processor from fine-tuned checkpoint
jefffffff9 +1: Claude Sonnet 4.6When a fine-tuned checkpoint uses a different Whisper size than the base model (e.g. large-v3-turbo=128 bins vs small=80 bins), the feature extractor from the base model produces inputs the fine-tuned model rejects with: "expected input to have 128 channels, but got 80 channels". Fix: track _fine_tuned_processors{} alongside _fine_tuned_models{}. _reload_adapters_from_hub() now saves WhisperProcessor.from_pretrained() from the checkpoint path. All three ASR call sites (_do_asr, _convo_pipeline, correction loop) resolve active_processor = _fine_tuned_processors.get(lang, _whisper_processor) so the processor always matches the model in use. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>7fae91b
-
Fix jiwer crash on post-normalisation empty refs; register SLR106/105 datasets
jefffffff9 +1: Claude Sonnet 4.6compute_metrics: pre-apply lowercasing + punctuation removal before filtering empty references — a label like "?" passes r.strip() but becomes "" after RemovePunctuation, causing jiwer to raise ValueError mid-evaluation. Pass already-normalised strings directly to jiwer.cer / jiwer.wer so no second transform is applied. web_harvester: add commented-in registry entries for OpenSLR SLR106 (10k clean Guinea Pular utterances, 49 speakers, CC BY-SA 4.0) and SLR105 (Guinea radio corpus, Pular-tagged validation split). Both are uncommented once the audio is uploaded to HF — best available Guinea Pular ASR data. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>6682858 -
Fix SyntaxError in Cell 17: unterminated f-string literal
jefffffff9 +1: Claude Sonnet 4.6A bare newline inside a single-quoted f-string caused SyntaxError on Python 3.12+. Replace the literal newline with the \n escape sequence so the print statement is valid on a single line. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>58f431a -
Fix compute_metrics crash on empty eval references in Fula training
jefffffff9 +1: Claude Sonnet 4.6jiwer raises ValueError when a reference string decodes to empty (silent audio / all-padding labels). Filter out empty reference/ hypothesis pairs before calling jiwer.cer and jiwer.wer; guard the all-empty edge case by returning 0.0 metrics safely. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>3632a23
-
Fix Self-Teaching language detection: parse code from dropdown label
jefffffff9 +1: Claude Sonnet 4.6_harvest_hf_dataset and _harvest_wikipedia received "Fula (ful)" from the dropdown but looked it up in SUPPORTED_LANGUAGES which has "Fula / Pular — Guinea (ful)" — no match, silently defaulted to bam. Now extract the code from the trailing (xxx) parentheses directly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>33c3a5a -
Add Adlam/Pular Fula integration: transliterator + 3 new datasets + normalisation pipeline
jefffffff9 +1: Claude Sonnet 4.6- src/data/adlam.py: full Adlam↔Latin transliterator for Pular (Guinea Fula) — bidirectional char map (U+1E900–U+1E95F), digraph-aware latin_to_adlam(), contains_adlam(), normalize_pular() (Adlam→Latin + NFC + lowercase) - src/data/web_harvester.py: add 3 Fula training sources to HF_DATASET_REGISTRY: Pullo-Africa-Protagonist/Fula-pular (9,761 audio rows, primary), guizme/adlam_fulfulde (51 Adlam-script rows, auto-converted to Latin) - notebooks/kaggle_master_trainer.ipynb: Cell 11 gets inline _normalize_pular (Adlam→Latin); Cell 12 applies it for lang=='ful' in prepare_dataset - app.py: import normalize_pular; apply in _do_asr and _convo_pipeline for Fula; update Self-Teaching tab help text to list all 3 Fula datasets Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>ced078c -
Fix language mixing: per-language prompts + Mali Bambara / Guinea Pular context
jefffffff9 +1: Claude Sonnet 4.6Root cause: one generic system prompt for all languages with no language code injected. The LLM had no instructions to stay in one dialect, so it mixed Bambara and Fula words freely. app.py: - SUPPORTED_LANGUAGES: labels now say "Bambara — Mali" and "Fula / Pular — Guinea" - LANG_CONTEXT dict: per-language country, region, script, phonetic rules, and explicit "do_not_mix" field naming the languages to never blend in - _build_system_prompt(language_code, vocab): generates a language-specific system prompt that opens with "You MUST respond exclusively in {lang} ({country})" and lists exactly which other languages must NOT appear in responses - _get_vocab_context_for(language_code): filters vocabulary cache to only entries tagged [bam] or [ful] — LLM never sees the other language's words in its context - _build_messages: uses _build_system_prompt + filtered vocab instead of the single generic template - LLM fallback messages now cover bam (Mali Bambara), ful (Guinea Pular), and…40cf84d
-
Fix model loading stuck forever + unhandled TTS crash in conversation mode
Broulaye Doumbia_do_load_whisper had import statements outside the try/except block — if torch or transformers imports failed the thread crashed silently, leaving _model_status permanently at "loading…" with no retry. Wrap the entire function body so any exception is captured. Also add a 180s stuck-load timeout in _ensure_whisper_loaded so the timer can recover and retry. Wrap _tts.synthesize() in try/except in both conversation and sensor modes so a TTS failure returns the text response instead of crashing the whole handler. Align .env.example with the variable names app.py actually reads (WHISPER_MODEL_ID, LLM_MODEL_ID) and re-read LLM_MODEL_ID after load_dotenv() in __main__. Made-with: Cursor618eab5
-
Fix: add trust_remote_code=True for datasets 3.x compatibility
Broulaye Doumbia71bb3bc
-
Fix 'Model loading' stuck state: block in _do_asr until Whisper is ready
jefffffff9 +1: Claude Sonnet 4.6_ensure_whisper_loaded() fires a background thread and returns immediately. _do_asr checked _whisper_model is None and returned a loading message — but nothing ever re-triggered the pipeline after the model finished loading, so the UI stayed stuck on that message forever. Fix: _wait_for_whisper(timeout=120) polls _whisper_model every 0.5s until ready or timeout. _do_asr and handle_ask now call this instead of the non-blocking _ensure_whisper_loaded(). On a cold start the first request waits (showing a spinner in the Gradio component) and then runs normally — no retry needed by the user. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>1958814 -
Fix conversation mode timeout: two-stage pipeline + faster LLM
jefffffff9 +1: Claude Sonnet 4.6Root cause: the entire pipeline (ASR + LLM API call + TTS) ran as one blocking Gradio event before anything appeared in the UI. On cpu-basic: - Whisper small on CPU: ~5-10s - Qwen 72B on HF Serverless: 20-40s (queue + generation) - MMS-TTS on CPU: ~5-10s Total: 30-60s, hitting Gradio's request timeout → error in all boxes. Fix 1 — Two-stage pipeline with .then() chaining: Stage 1 (_do_asr): Whisper only → transcript appears in ~5s Stage 2 (_do_respond): LLM + TTS → response + audio follow after User sees the transcript almost immediately; no more blank wait. Fix 2 — LLM model: Qwen 72B → Qwen 7B (10x faster on HF Serverless, same quality for 1-3 sentence voice responses). Env var LLM_MODEL_ID still overrides to any model. Fix 3 — max_tokens 300→150: voice responses are short; cutting tokens in half cuts LLM latency ~40% further. Fix 4 — Remove @_gpu from _convo_pipeline: the LLM step is a network request; wrapping it in the GPU time budget wasted the 55s allow…8d7d9d8 -
Add real conversational memory + live learning to Conversation Mode
jefffffff9 +1: Claude Sonnet 4.6Problem: every turn was stateless — no history, no vocabulary context. The LLM received only the current utterance with a generic system prompt, so it had no idea what was said before and could not use taught words. Changes to app.py: Vocabulary context cache (_vocab_context_cache): - _refresh_vocab_context(): loads vocabulary.jsonl from Hub at startup and after every vocabulary write; formats top 200 entries as compact "word = meaning [lang]" lines injected into every LLM system prompt - Called on startup (background thread) and after phrase imports, Wikipedia harvests, and mid-conversation LEARNED saves Conversation history (gr.State): - conv_history = gr.State(value=[]) — per-session, not shared - Passed as input + output on every ask_btn / stop_recording event - Capped at 20 turns to stay within LLM token budget - Displayed in gr.Chatbot (visible only when Conversation Mode is ON) - "Clear" button resets history and chatbot to empty Smarter system prompt (_CONVO_SYSTEM_TE…ad902c6 -
Fix slow build: strip runtime-irrelevant heavy packages from requirements.txt
jefffffff9 +1: Claude Sonnet 4.6Removed from requirements.txt (causes slow builds, unused at Space runtime): - torch / torchaudio pins → Spaces pre-installs correct CUDA build; re-pinning forces pip to re-download ~1 GB on every build - f5-tts>=1.0.0 → ~2 GB install with vocos/x-transformers/jieba/einops; src/tts/f5_tts.py already falls back to MMS-TTS on ImportError - speechbrain → heavy ML package, speaker-id not on critical path - peft → training-only (Kaggle notebook), removed from app pipeline - evaluate → training-only - bitsandbytes → quantization library, not usable on cpu-basic anyway - audiomentations → training-time augmentation only - pytest / pytest-asyncio → dev-only, never run in production Space Estimated build time improvement: 10-15 min -> ~2 min Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>bfe5b59 -
Phase 3: Voice-to-Voice S2S pipeline — F5-TTS, LLM brain, CER metric
jefffffff9 +1: Claude Sonnet 4.6app.py: - Add LLM_MODEL_ID env var (default: Qwen/Qwen2.5-72B-Instruct) - Import GemmaClient + bam_normalize at module level - Add _voice_ref_path / _voice_ref_text / _llm_client state - Add set_voice_reference(): converts MP3->24kHz WAV, auto-transcribes - Add _convo_pipeline(): ASR -> bam_normalize -> LLM (phonetic Bambara system prompt) -> F5-TTS (voice ref) with MMS-TTS fallback - handle_ask() accepts convo_mode=bool, routes to _convo_pipeline or the original sensor pipeline accordingly - Tab 1 UI: Conversation Mode toggle, Voice Reference upload accordion, stop_recording auto-submit for true back-to-back loop src/tts/f5_tts.py (new): - Lazy-loaded F5TTS wrapper; synthesize() with ref_wav + ref_text - to_wav_24k() resampler (F5-TTS needs 24 kHz input) - Graceful fallback (returns None) when f5-tts not installed src/data/bam_normalize.py (new): - _bam_norm(): ou->u, dj->j, gn->ny, ch->c, oo->o-open, ee->e-open - Used at inference (app.py) and training (notebook Cell 11) req…8952fff
-
Fix Cell 16 ValueError: load model fp32 so AMP gradient scaler works
jefffffff9 +1: Claude Sonnet 4.6Root cause: model loaded in fp16 + fp16=True training args causes GradScaler to see fp16 params and raise "Attempting to unscale FP16 gradients". Fix: load fp32, let AMP cast internally during forward pass. Cell 13: torch_dtype float16 -> float32; remove manual gradient_checkpointing_enable Cell 14: remove explicit .to(float16) cast in data collator (AMP handles it) Cell 15: gradient_checkpointing False->True; remove deprecated logging_dir kwarg Cell 17: remove .half() on eval features (fp32 model needs fp32 input) Cell 19: fix f-string ternary precedence so commit msg always includes all fields Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>cd017e2 -
Fix Self-Teaching tab: float sliders, deduplication, Kaggle API fallback
jefffffff9 +1: Claude Sonnet 4.6- Cast slider values to int (Gradio returns float; broke Wikipedia aplimit and Kaggle ds.take() in notebook Cell 9) - Deduplicate dataset_sources.jsonl on each HF import (avoid loading same dataset multiple times per training run) - Kaggle trigger: try Python API (KaggleApiExtended) first to avoid binary PATH issues; subprocess + shutil.which as fallback - Fix Fula dataset registry: fleurs uses legacy script loader incompatible with datasets>=3.0; switch to google/WaxalNLP ful_asr - Fix UI description: HF import writes to dataset_sources.jsonl (streamed by Kaggle), not to corrections.jsonl Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>24b1617 -
Fix Kaggle trigger 401: pass credentials as env vars instead of KAGGLE_CONFIG_DIR
jefffffff9 +1: Claude Sonnet 4.6Newer kaggle CLI ignores KAGGLE_CONFIG_DIR; pass KAGGLE_USERNAME and KAGGLE_KEY directly as environment variables so the CLI authenticates correctly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>670a1d1 -
Fix kaggle trigger: use kaggle binary not python -m kaggle
jefffffff97f169d8 -
Add kaggle to requirements.txt for Space trigger
jefffffff9317a499 -
chore: force Space restart
jefffffff9be96d03 -
Fix Kaggle trigger: use kaggle CLI push instead of fake /run endpoint
jefffffff9 +1: Claude Sonnet 4.6The Kaggle REST API has no /run endpoint. The correct way to trigger a new kernel run is kaggle kernels push, which creates a new kernel version (which immediately starts executing on Kaggle's servers). New approach: - Reads notebook + kernel-metadata.json from the Space filesystem - Writes temporary kaggle.json from KAGGLE_USERNAME/KAGGLE_KEY secrets - Runs: python -m kaggle kernels push -p notebooks/ - Returns the CLI output so errors are visible in the UI Also logs auto-trigger result to Space logs instead of silently failing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>3d43385 -
Fix Wikipedia and HF harvest buttons
jefffffff9 +1: Claude Sonnet 4.6Wikipedia fix: - Add User-Agent header to all requests (Wikipedia API returns 403 without it) - Extract shared _upload_jsonl() helper to reduce code duplication HF harvest fix: - Remove audio re-upload approach (500 HTTP requests -> Gradio timeout) - Instead write dataset references to dataset_sources.jsonl on the Hub - One small file upload (~instant) instead of gigabytes of audio - Kaggle notebook Cell 4 now reads dataset_sources.jsonl dynamically: any dataset registered in Space Self-Teaching tab is automatically picked up at training time with no notebook edits needed Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>a5737ac -
Fix: point Space to app.py (was app_lab.py)
jefffffff9520ca12 -
Add mass training + internet self-teaching features
jefffffff9 +1: Claude Sonnet 4.6New Tab 5 — Bulk Upload: - Upload ZIP of audio files + CSV (filename,transcription) in one operation - Batch-inserts all samples into corrections.jsonl + uploads audio to Hub New Tab 6 — Self-Teaching: - Wikipedia harvest: bm/ff Wikipedia API → sentence text → vocabulary.jsonl (868 Bambara articles, 17k+ Fula articles) - HF dataset import: RobotsMali/jeli-asr (33k Bambara) + google/fleurs ff_sn (Fula) → corrections.jsonl, one click - Auto-training trigger: fires Kaggle kernel via REST API when corrections.jsonl reaches AUTO_TRAIN_THRESHOLD (default 50) entries Requires KAGGLE_USERNAME + KAGGLE_KEY Space secrets New src/data/web_harvester.py: - harvest_wikipedia_text(lang, max_articles) — MediaWiki API, no deps - harvest_hf_audio(lang, token) — generator yielding (wav_bytes, text, path) - _numpy_to_wav_bytes() — stdlib-only WAV encoder Auto-trigger also fires after each Tab 2 correction save. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>eddcaea -
Align Space app with Kaggle notebook training pipeline
jefffffff9 +1: Claude Sonnet 4.61. Replace PEFT AdapterManager with full-checkpoint loader - _fine_tuned_models dict replaces _adapter_manager/PEFT - _reload_adapters_from_hub loads WhisperForConditionalGeneration from config.json checkpoints (what the notebook actually saves) - _run_pipeline uses _fine_tuned_models.get(lang, base_model) 2. Tab 3 audio uploads now write to corrections.jsonl + audio/ - Previously saved to training_audio/ which the notebook never read - Now saved under audio/{lang}_{ts}.wav with corrected_text field exactly matching what Cell 7 of the notebook expects 3. Phrase pairs now also append to vocabulary.jsonl - _append_phrases_to_vocabulary_jsonl writes {word, translation, language} entries so Cell 7 vocab_entries picks them up as synthetic fallback labels 4. Tab 4 updated: correct notebook name, clear data flow docs, button renamed to "Reload Fine-tuned Models from Hub" Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>98eece8
-
Fix eval_loss nan + add generation_config to Seq2SeqTrainer
jefffffff9 +1: Claude Sonnet 4.61. Seq2SeqTrainer now receives generation_config=model.generation_config explicitly -- ensures forced_decoder_ids is applied during eval's generate() call, fixing the '!!!!!' prediction output 2. eval_loss nan handled gracefully in cells 17, 19, 20 -- transformers 5.x predict_with_generate=True does not compute loss, always returns nan; display shows 'n/a (generation-based eval)' instead of crashing on .4f Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>9f07d46 -
Fix GenerationConfig deprecation warning in cells 13 and 16
jefffffff9 +1: Claude Sonnet 4.6forced_decoder_ids/suppress_tokens belong in generation_config not model.config. Fixes the warning before it becomes an exception in transformers v4.41+. Also saves generation_config alongside the model checkpoint so it loads correctly from the HF hub. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>1f2993e -
Auto-cap MAX_STEPS based on dataset size after Cell 12 builds train_ds
jefffffff9 +1: Claude Sonnet 4.64000 steps on 11 samples = 2-hour wasted run. New rule: cap at max(200, steps_per_epoch * 20) so small/synthetic datasets complete in ~5 min while full datasets (5000+ samples) still run the full MAX_STEPS. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>73a3f3a -
Fix Cell 15: detect eval_strategy vs evaluation_strategy at runtime
jefffffff9 +1: Claude Sonnet 4.6transformers 4.x: evaluation_strategy; transformers 4.45+: eval_strategy. Kaggle's transformers 5.x raises TypeError on eval_strategy. Use inspect to detect the accepted param name and unpack via **{key: value}. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>1c462f3 -
Proactive notebook audit: fix 5 issues before they cause errors
jefffffff9 +1: Claude Sonnet 4.61. Cell 3: remove dead LORA_R/ALPHA/DROPOUT/TARGETS vars (PEFT removed) 2. Cell 13: fix train_test_split test_size -- was float(0.05) which gives 0 eval samples on small datasets; now max(1, int(0.05 * n)) 3. Cell 22: remove forced_decoder_ids kwarg from model.generate() -- transformers 5.x removed this param; config already has it set 4. Cell 13: remove num_proc=2 from waxal map (multiprocessing + audio can hang on Kaggle when dataset is small) 5. Update stale markdown cells (LoRA/PEFT/8-bit references removed) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>aef60bc -
Simplify Cell 2: no restart needed since PEFT is removed
jefffffff9 +1: Claude Sonnet 4.6Without PEFT, the transformers/numpy/scipy downgrade is unnecessary. Kaggle system packages (transformers 5.x, numpy 2.x, etc.) work fine. Cell 2 now only installs jiwer which Kaggle doesn't ship. No kernel restart, no sentinel file, no 3-minute wait. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>8e41441 -
Fix Cell 16 TypeError: replace PEFT LoRA with freeze/unfreeze fine-tuning
jefffffff9 +1: Claude Sonnet 4.6Root cause: PeftModelForSeq2SeqLM.forward wraps the entire WhisperForConditionalGeneration in BaseTuner, whose forward(*args, **kwargs) combined with transformers 5.x @auto_docstring causes input_ids to be passed to WhisperDecoder twice -- TypeError even when no decoder layers have LoRA. The issue is in the PEFT model wrapper itself, not in which layers are targeted. Fix: remove PEFT entirely. Freeze all params, unfreeze last 2 decoder layers + layer_norm + proj_out (~5% trainable, same capacity as LoRA r=32). Standard Seq2SeqTrainer works cleanly with the unfrozen plain model. Also update push commit message from 'LoRA adapter' to 'fine-tuned checkpoint'. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>6dc0dfc -
Fix Cell 16 TypeError: target encoder-only LoRA to avoid PEFT/transformers 5.x conflict
jefffffff9 +1: Claude Sonnet 4.6PEFT 0.18.x + transformers 5.x: WhisperDecoder.forward receives input_ids via both positional args and kwargs when LoRA wraps decoder layers, causing TypeError('got multiple values for keyword argument input_ids'). Fix: LORA_TARGETS changed from list ['q_proj','v_proj'] (matches all layers) to regex that targets only encoder self-attention projections. The encoder processes audio features and has no input_ids, so the conflict cannot occur. Also adds model.config.use_cache = False (required with gradient checkpointing). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>c37ce59