Spaces:
Running on Zero
Running on Zero
| """Japanese ASR demo for sbintuitions/kana-whisper on Hugging Face ZeroGPU. | |
| The model is Whisper large-v3-turbo fine-tuned to transcribe Japanese speech | |
| into *katakana* (pronunciation), e.g. キョーワイイテンキデスネ. It was built as | |
| the ASR component for evaluating the reading accuracy of Japanese TTS systems. | |
| """ | |
| import numpy as np | |
| import spaces | |
| import torch | |
| import gradio as gr | |
| from transformers import AutoModelForSpeechSeq2Seq, AutoProcessor, pipeline | |
| MODEL_ID = "sbintuitions/kana-whisper" | |
| # ZeroGPU exposes CUDA at startup, so we can load straight onto the GPU. The | |
| # @spaces.GPU decorator on transcribe() is what actually reserves the slice at | |
| # call time; on non-ZeroGPU hardware the decorator is a no-op. We detect the | |
| # device so the Space still builds/runs on plain CPU hardware (just slower). | |
| if torch.cuda.is_available(): | |
| device = "cuda" | |
| torch_dtype = torch.float16 | |
| else: | |
| device = "cpu" | |
| torch_dtype = torch.float32 | |
| model = AutoModelForSpeechSeq2Seq.from_pretrained( | |
| MODEL_ID, | |
| dtype=torch_dtype, | |
| low_cpu_mem_usage=True, | |
| use_safetensors=True, | |
| ).to(device) | |
| processor = AutoProcessor.from_pretrained(MODEL_ID) | |
| asr = pipeline( | |
| "automatic-speech-recognition", | |
| model=model, | |
| tokenizer=processor.tokenizer, | |
| feature_extractor=processor.feature_extractor, | |
| dtype=torch_dtype, | |
| device=device, | |
| ) | |
| GENERATE_KWARGS = {"language": "ja", "task": "transcribe"} | |
| def _to_float_mono(sampling_rate: int, data: np.ndarray) -> dict: | |
| """Normalize Gradio's (sr, ndarray) audio into what the ASR pipeline wants: | |
| a float32 mono waveform in [-1, 1] with its sampling rate (the feature | |
| extractor resamples to 16 kHz internally).""" | |
| data = np.asarray(data) | |
| if data.ndim > 1: # stereo -> mono | |
| data = data.mean(axis=1) | |
| if np.issubdtype(data.dtype, np.integer): | |
| data = data.astype(np.float32) / np.iinfo(data.dtype).max | |
| else: | |
| data = data.astype(np.float32) | |
| return {"array": data, "sampling_rate": int(sampling_rate)} | |
| def transcribe(audio: tuple | None) -> str: | |
| if audio is None: | |
| return "" | |
| sampling_rate, data = audio | |
| inputs = _to_float_mono(sampling_rate, data) | |
| result = asr(inputs, generate_kwargs=GENERATE_KWARGS) | |
| return result["text"] | |
| DESCRIPTION = """ | |
| # 🎙️ Kana Whisper — Japanese ASR → Katakana | |
| Record or upload a short Japanese audio clip and get back its **katakana** | |
| transcription (pronunciation, not kanji) using | |
| [`sbintuitions/kana-whisper`](https://huggingface.co/sbintuitions/kana-whisper) | |
| — a Whisper large-v3-turbo model fine-tuned by SB Intuitions. | |
| > Example output: `キョーワイイテンキデスネ` | |
| """ | |
| with gr.Blocks(title="Kana Whisper — Japanese ASR") as demo: | |
| gr.Markdown(DESCRIPTION) | |
| with gr.Row(): | |
| audio_in = gr.Audio( | |
| sources=["microphone", "upload"], | |
| type="numpy", | |
| label="Japanese audio (short clip)", | |
| ) | |
| text_out = gr.Textbox( | |
| label="Katakana transcription", | |
| lines=4, | |
| ) | |
| transcribe_btn = gr.Button("Transcribe", variant="primary") | |
| transcribe_btn.click(fn=transcribe, inputs=audio_in, outputs=text_out) | |
| if __name__ == "__main__": | |
| demo.launch() | |