dungca commited on
Commit
2df61f9
·
1 Parent(s): ac1b4ce

Upload source application

Browse files
Files changed (3) hide show
  1. README.md +4 -4
  2. app.py +144 -0
  3. requirements.txt +7 -0
README.md CHANGED
@@ -1,8 +1,8 @@
1
  ---
2
- title: Whisper Tiny Ja Lora Demo
3
- emoji: 👁
4
- colorFrom: red
5
- colorTo: indigo
6
  sdk: gradio
7
  sdk_version: 6.9.0
8
  app_file: app.py
 
1
  ---
2
+ title: Whisper Ja Demo
3
+ emoji: 🐨
4
+ colorFrom: yellow
5
+ colorTo: red
6
  sdk: gradio
7
  sdk_version: 6.9.0
8
  app_file: app.py
app.py ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import torch
3
+ import numpy as np
4
+ from transformers import AutoProcessor, WhisperForConditionalGeneration
5
+ from peft import PeftModel
6
+
7
+ # ── Constants ──────────────────────────────────────────────────────────────────
8
+ BASE_MODEL_ID = "openai/whisper-tiny"
9
+ LORA_MODEL_ID = "dungca/whisper-tiny-ja-lora"
10
+ SAMPLING_RATE = 16000
11
+
12
+ # ── Load model (cached after first load) ───────────────────────────────────────
13
+ def load_model():
14
+ print("Loading model...")
15
+ processor = AutoProcessor.from_pretrained(BASE_MODEL_ID)
16
+ base_model = WhisperForConditionalGeneration.from_pretrained(BASE_MODEL_ID)
17
+ model = PeftModel.from_pretrained(base_model, LORA_MODEL_ID)
18
+ model.eval()
19
+ if torch.cuda.is_available():
20
+ model = model.cuda()
21
+ print("Using GPU")
22
+ else:
23
+ print("Using CPU")
24
+ return processor, model
25
+
26
+ processor, model = load_model()
27
+
28
+ # ── Inference ──────────────────────────────────────────────────────────────────
29
+ def transcribe(audio):
30
+ if audio is None:
31
+ return "⚠️ Vui lòng cung cấp audio (upload file hoặc record từ mic)."
32
+
33
+ sr, audio_array = audio
34
+
35
+ # Convert to float32 mono
36
+ audio_array = audio_array.astype(np.float32)
37
+ if audio_array.ndim > 1:
38
+ audio_array = audio_array.mean(axis=1)
39
+
40
+ # Normalize
41
+ max_val = np.abs(audio_array).max()
42
+ if max_val > 0:
43
+ audio_array = audio_array / max_val
44
+
45
+ # Resample if needed
46
+ if sr != SAMPLING_RATE:
47
+ import librosa
48
+ audio_array = librosa.resample(audio_array, orig_sr=sr, target_sr=SAMPLING_RATE)
49
+
50
+ # Process
51
+ inputs = processor(
52
+ audio_array,
53
+ sampling_rate=SAMPLING_RATE,
54
+ return_tensors="pt"
55
+ )
56
+
57
+ if torch.cuda.is_available():
58
+ inputs = {k: v.cuda() for k, v in inputs.items()}
59
+
60
+ with torch.no_grad():
61
+ predicted_ids = model.generate(
62
+ inputs["input_features"],
63
+ language="japanese",
64
+ task="transcribe",
65
+ max_new_tokens=256,
66
+ )
67
+
68
+ transcription = processor.batch_decode(predicted_ids, skip_special_tokens=True)[0]
69
+ return transcription.strip() if transcription.strip() else "(音声が認識できませんでした)"
70
+
71
+
72
+ # ── UI ─────────────────────────────────────────────────────────────────────────
73
+ CSS = """
74
+ .gradio-container {
75
+ max-width: 800px !important;
76
+ margin: auto !important;
77
+ }
78
+ .title {
79
+ text-align: center;
80
+ font-size: 2rem;
81
+ font-weight: 700;
82
+ margin-bottom: 0.25rem;
83
+ }
84
+ .subtitle {
85
+ text-align: center;
86
+ color: #666;
87
+ margin-bottom: 1.5rem;
88
+ }
89
+ footer { display: none !important; }
90
+ """
91
+
92
+ with gr.Blocks(css=CSS, title="Whisper Japanese ASR Demo") as demo:
93
+
94
+ gr.HTML("""
95
+ <div class="title">🎙️ Whisper Japanese ASR</div>
96
+ <div class="subtitle">
97
+ LoRA fine-tuned on <b>ReazonSpeech</b> dataset ·
98
+ Base: <code>openai/whisper-tiny</code> ·
99
+ Adapter: <a href="https://huggingface.co/dungca/whisper-tiny-ja-lora" target="_blank">dungca/whisper-tiny-ja-lora</a>
100
+ </div>
101
+ """)
102
+
103
+ with gr.Tab("🎤 Record từ Mic"):
104
+ mic_input = gr.Audio(
105
+ sources=["microphone"],
106
+ type="numpy",
107
+ label="Nói tiếng Nhật vào mic...",
108
+ )
109
+ mic_btn = gr.Button("📝 Transcribe", variant="primary")
110
+ mic_output = gr.Textbox(
111
+ label="Kết quả phiên âm (日本語)",
112
+ placeholder="Kết quả sẽ hiện ở đây...",
113
+ lines=3,
114
+ show_copy_button=True,
115
+ )
116
+ mic_btn.click(fn=transcribe, inputs=mic_input, outputs=mic_output)
117
+
118
+ with gr.Tab("📁 Upload File"):
119
+ file_input = gr.Audio(
120
+ sources=["upload"],
121
+ type="numpy",
122
+ label="Upload file audio (wav, mp3, m4a...)",
123
+ )
124
+ file_btn = gr.Button("📝 Transcribe", variant="primary")
125
+ file_output = gr.Textbox(
126
+ label="Kết quả phiên âm (日本語)",
127
+ placeholder="Kết quả sẽ hiện ở đây...",
128
+ lines=3,
129
+ show_copy_button=True,
130
+ )
131
+ file_btn.click(fn=transcribe, inputs=file_input, outputs=file_output)
132
+
133
+ gr.HTML("""
134
+ <div style="margin-top:1.5rem; padding:1rem; background:#f8f9fa; border-radius:8px; font-size:0.9rem; color:#555;">
135
+ <b>📊 Model Info</b><br>
136
+ • Base: openai/whisper-tiny (39M params)<br>
137
+ • Fine-tuning: LoRA (r=16, α=32) trên ReazonSpeech small<br>
138
+ • CER: 0.525 · Eval loss: 1.177 · Trained on Kaggle P100<br>
139
+ • <i>whisper-small version đang được train để cải thiện độ chính xác</i>
140
+ </div>
141
+ """)
142
+
143
+ if __name__ == "__main__":
144
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ torch>=2.0.0
2
+ transformers>=4.36.0
3
+ peft>=0.18.0
4
+ gradio>=4.0.0
5
+ librosa>=0.10.0
6
+ numpy>=1.24.0
7
+ soundfile>=0.12.0