Spaces:
Sleeping
Sleeping
Update ASR LLM Agent
Browse files- README.md +7 -9
- data/manifest.jsonl +0 -2
- data/manifest_hf.jsonl +0 -50
- pipeline/run_all.py +15 -5
- scripts/run_hf_job.py +16 -74
- ui/app.py +45 -19
README.md
CHANGED
|
@@ -11,22 +11,21 @@ pinned: false
|
|
| 11 |
|
| 12 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
| 13 |
|
| 14 |
-
|
| 15 |
## ASR LLM Agent Upgrade
|
| 16 |
|
| 17 |
-
This version adds an LLM-based diagnosis layer on top of alignment
|
| 18 |
|
| 19 |
-
- `analysis/llm_analyzer.py`: sends representative ASR error cases
|
| 20 |
- `pipeline/run_analysis.py`: optionally runs LLM diagnosis when `OPENAI_API_KEY` is set
|
| 21 |
-
- `scripts/run_diagnostic.py`:
|
| 22 |
-
- `report.md`:
|
| 23 |
|
| 24 |
### What the LLM adds
|
| 25 |
|
| 26 |
Compared with rule-only classification, the LLM layer can:
|
| 27 |
|
| 28 |
- separate surface-form differences from true semantic distortions
|
| 29 |
-
- identify meaning-preserving paraphrases
|
| 30 |
- infer likely causes from representative cases
|
| 31 |
- propose prioritized, actionable improvement suggestions
|
| 32 |
|
|
@@ -34,7 +33,7 @@ Compared with rule-only classification, the LLM layer can:
|
|
| 34 |
|
| 35 |
```bash
|
| 36 |
export OPENAI_API_KEY=your_key
|
| 37 |
-
python pipeline/run_all.py
|
| 38 |
```
|
| 39 |
|
| 40 |
Or rerun diagnosis only for an existing run:
|
|
@@ -44,10 +43,9 @@ export OPENAI_API_KEY=your_key
|
|
| 44 |
python scripts/run_diagnostic.py --run_id <run_id> --model gpt-4.1-mini
|
| 45 |
```
|
| 46 |
|
| 47 |
-
|
| 48 |
## Qwen3-ASR
|
| 49 |
|
| 50 |
-
This project
|
| 51 |
|
| 52 |
Install the runtime dependency:
|
| 53 |
|
|
|
|
| 11 |
|
| 12 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
| 13 |
|
|
|
|
| 14 |
## ASR LLM Agent Upgrade
|
| 15 |
|
| 16 |
+
This version adds an LLM-based diagnosis layer on top of alignment and event statistics:
|
| 17 |
|
| 18 |
+
- `analysis/llm_analyzer.py`: sends representative ASR error cases and aggregate stats to an LLM
|
| 19 |
- `pipeline/run_analysis.py`: optionally runs LLM diagnosis when `OPENAI_API_KEY` is set
|
| 20 |
+
- `scripts/run_diagnostic.py`: regenerates `llm_diagnosis.json` and `diagnostic_report.md`
|
| 21 |
+
- `report.md`: includes LLM semantic findings and priority actions
|
| 22 |
|
| 23 |
### What the LLM adds
|
| 24 |
|
| 25 |
Compared with rule-only classification, the LLM layer can:
|
| 26 |
|
| 27 |
- separate surface-form differences from true semantic distortions
|
| 28 |
+
- identify meaning-preserving paraphrases versus business-critical errors
|
| 29 |
- infer likely causes from representative cases
|
| 30 |
- propose prioritized, actionable improvement suggestions
|
| 31 |
|
|
|
|
| 33 |
|
| 34 |
```bash
|
| 35 |
export OPENAI_API_KEY=your_key
|
| 36 |
+
python pipeline/run_all.py --manifest data/manifest.jsonl --model_name openai/whisper-small --llm_model gpt-4.1-mini
|
| 37 |
```
|
| 38 |
|
| 39 |
Or rerun diagnosis only for an existing run:
|
|
|
|
| 43 |
python scripts/run_diagnostic.py --run_id <run_id> --model gpt-4.1-mini
|
| 44 |
```
|
| 45 |
|
|
|
|
| 46 |
## Qwen3-ASR
|
| 47 |
|
| 48 |
+
This project supports `Qwen/Qwen3-ASR-0.6B` and `Qwen/Qwen3-ASR-1.7B` via the `qwen-asr` package.
|
| 49 |
|
| 50 |
Install the runtime dependency:
|
| 51 |
|
data/manifest.jsonl
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 1 |
-
{"utt_id":"u001","audio_uri":"data/audio/u001.wav","ref_text":"今天天气很好","meta":{"device":"mobile","domain":"daily","speaker":"spk1"}}
|
| 2 |
-
{"utt_id":"u002","audio_uri":"data/audio/u002.wav","ref_text":"我们下午三点开会","meta":{"device":"farfield","domain":"meeting","speaker":"spk2"}}
|
|
|
|
|
|
|
|
|
data/manifest_hf.jsonl
DELETED
|
@@ -1,50 +0,0 @@
|
|
| 1 |
-
{"utt_id": "fsicoli_common_voice_22_0_00000", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00000.wav", "ref_text": "巴顿是位于美国加利福尼亚州阿马多尔县的一个非建制地区。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "bcb4464171113dd9b51f371c3eecea06771fde83e7e3239ad0516469c6dcdf80170d26c7d1b1ef2476c45b51bfb4ee5549f07d7002bcfcec9b371a30c873b92d", "gender": "male_masculine", "accent": "", "age": "twenties", "locale": "zh-CN"}}
|
| 2 |
-
{"utt_id": "fsicoli_common_voice_22_0_00001", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00001.wav", "ref_text": "恩骑尉,是中国清朝时的爵名。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "bcb4464171113dd9b51f371c3eecea06771fde83e7e3239ad0516469c6dcdf80170d26c7d1b1ef2476c45b51bfb4ee5549f07d7002bcfcec9b371a30c873b92d", "gender": "male_masculine", "accent": "", "age": "twenties", "locale": "zh-CN"}}
|
| 3 |
-
{"utt_id": "fsicoli_common_voice_22_0_00002", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00002.wav", "ref_text": "仙台盐釜港是位于日本宫城县、内的海港,由宫城县政府负责港务营运。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "bcb4464171113dd9b51f371c3eecea06771fde83e7e3239ad0516469c6dcdf80170d26c7d1b1ef2476c45b51bfb4ee5549f07d7002bcfcec9b371a30c873b92d", "gender": "male_masculine", "accent": "", "age": "twenties", "locale": "zh-CN"}}
|
| 4 |
-
{"utt_id": "fsicoli_common_voice_22_0_00003", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00003.wav", "ref_text": "利马的阳台是西班牙殖民时期和共和国时期建造的文化遗产。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "bcb4464171113dd9b51f371c3eecea06771fde83e7e3239ad0516469c6dcdf80170d26c7d1b1ef2476c45b51bfb4ee5549f07d7002bcfcec9b371a30c873b92d", "gender": "male_masculine", "accent": "", "age": "twenties", "locale": "zh-CN"}}
|
| 5 |
-
{"utt_id": "fsicoli_common_voice_22_0_00004", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00004.wav", "ref_text": "成山,字屏临,号进斋,满洲正蓝旗人。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "bcb4464171113dd9b51f371c3eecea06771fde83e7e3239ad0516469c6dcdf80170d26c7d1b1ef2476c45b51bfb4ee5549f07d7002bcfcec9b371a30c873b92d", "gender": "male_masculine", "accent": "", "age": "twenties", "locale": "zh-CN"}}
|
| 6 |
-
{"utt_id": "fsicoli_common_voice_22_0_00005", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00005.wav", "ref_text": "嘉靖十一年任福建龙溪县知县。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "bcb4464171113dd9b51f371c3eecea06771fde83e7e3239ad0516469c6dcdf80170d26c7d1b1ef2476c45b51bfb4ee5549f07d7002bcfcec9b371a30c873b92d", "gender": "male_masculine", "accent": "", "age": "twenties", "locale": "zh-CN"}}
|
| 7 |
-
{"utt_id": "fsicoli_common_voice_22_0_00006", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00006.wav", "ref_text": "科莫巴比是位于美国亚利桑那州皮马县的一个人口普查指定地区。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "bcb4464171113dd9b51f371c3eecea06771fde83e7e3239ad0516469c6dcdf80170d26c7d1b1ef2476c45b51bfb4ee5549f07d7002bcfcec9b371a30c873b92d", "gender": "male_masculine", "accent": "", "age": "twenties", "locale": "zh-CN"}}
|
| 8 |
-
{"utt_id": "fsicoli_common_voice_22_0_00007", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00007.wav", "ref_text": "历史上明永乐皇帝、清干隆皇帝等曾经多次到访,并留下牌匾和诗句。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "bcb4464171113dd9b51f371c3eecea06771fde83e7e3239ad0516469c6dcdf80170d26c7d1b1ef2476c45b51bfb4ee5549f07d7002bcfcec9b371a30c873b92d", "gender": "male_masculine", "accent": "", "age": "twenties", "locale": "zh-CN"}}
|
| 9 |
-
{"utt_id": "fsicoli_common_voice_22_0_00008", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00008.wav", "ref_text": "小花仙动画角色列表记录了所有在中国大陆动画《小花仙》系列中出场角色的详细介绍。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "bcb4464171113dd9b51f371c3eecea06771fde83e7e3239ad0516469c6dcdf80170d26c7d1b1ef2476c45b51bfb4ee5549f07d7002bcfcec9b371a30c873b92d", "gender": "male_masculine", "accent": "", "age": "twenties", "locale": "zh-CN"}}
|
| 10 |
-
{"utt_id": "fsicoli_common_voice_22_0_00009", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00009.wav", "ref_text": "妳不要再去那里了", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "bcb4464171113dd9b51f371c3eecea06771fde83e7e3239ad0516469c6dcdf80170d26c7d1b1ef2476c45b51bfb4ee5549f07d7002bcfcec9b371a30c873b92d", "gender": "male_masculine", "accent": "", "age": "twenties", "locale": "zh-CN"}}
|
| 11 |
-
{"utt_id": "fsicoli_common_voice_22_0_00010", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00010.wav", "ref_text": "银座松竹广场是位于日本东京都中央区筑地一丁目的摩天大楼。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "bcb4464171113dd9b51f371c3eecea06771fde83e7e3239ad0516469c6dcdf80170d26c7d1b1ef2476c45b51bfb4ee5549f07d7002bcfcec9b371a30c873b92d", "gender": "male_masculine", "accent": "", "age": "twenties", "locale": "zh-CN"}}
|
| 12 |
-
{"utt_id": "fsicoli_common_voice_22_0_00011", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00011.wav", "ref_text": "儿童权利监察使办公室设于华沙。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "bcb4464171113dd9b51f371c3eecea06771fde83e7e3239ad0516469c6dcdf80170d26c7d1b1ef2476c45b51bfb4ee5549f07d7002bcfcec9b371a30c873b92d", "gender": "male_masculine", "accent": "", "age": "twenties", "locale": "zh-CN"}}
|
| 13 |
-
{"utt_id": "fsicoli_common_voice_22_0_00012", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00012.wav", "ref_text": "灰阶音乐是位于香港的一家独立唱片厂牌和音乐出版公司。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "bcb4464171113dd9b51f371c3eecea06771fde83e7e3239ad0516469c6dcdf80170d26c7d1b1ef2476c45b51bfb4ee5549f07d7002bcfcec9b371a30c873b92d", "gender": "male_masculine", "accent": "", "age": "twenties", "locale": "zh-CN"}}
|
| 14 |
-
{"utt_id": "fsicoli_common_voice_22_0_00013", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00013.wav", "ref_text": "梁士济,字遂良,广东广州府南海县人,明朝、南明政治人物。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "bcb4464171113dd9b51f371c3eecea06771fde83e7e3239ad0516469c6dcdf80170d26c7d1b1ef2476c45b51bfb4ee5549f07d7002bcfcec9b371a30c873b92d", "gender": "male_masculine", "accent": "", "age": "twenties", "locale": "zh-CN"}}
|
| 15 |
-
{"utt_id": "fsicoli_common_voice_22_0_00014", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00014.wav", "ref_text": "姜涛曾就读轩尼诗道官立下午小学、邓肇坚维多利亚官立中学和青年学院。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "bcb4464171113dd9b51f371c3eecea06771fde83e7e3239ad0516469c6dcdf80170d26c7d1b1ef2476c45b51bfb4ee5549f07d7002bcfcec9b371a30c873b92d", "gender": "male_masculine", "accent": "", "age": "twenties", "locale": "zh-CN"}}
|
| 16 |
-
{"utt_id": "fsicoli_common_voice_22_0_00015", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00015.wav", "ref_text": "上海江南长兴重工有限责任公司简称长兴重工,厂区位于上海长兴岛船舶制造基地。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "bcb4464171113dd9b51f371c3eecea06771fde83e7e3239ad0516469c6dcdf80170d26c7d1b1ef2476c45b51bfb4ee5549f07d7002bcfcec9b371a30c873b92d", "gender": "male_masculine", "accent": "", "age": "twenties", "locale": "zh-CN"}}
|
| 17 |
-
{"utt_id": "fsicoli_common_voice_22_0_00016", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00016.wav", "ref_text": "卢启贤是香港的亿万富翁企业家和慈善家。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "bcb4464171113dd9b51f371c3eecea06771fde83e7e3239ad0516469c6dcdf80170d26c7d1b1ef2476c45b51bfb4ee5549f07d7002bcfcec9b371a30c873b92d", "gender": "male_masculine", "accent": "", "age": "twenties", "locale": "zh-CN"}}
|
| 18 |
-
{"utt_id": "fsicoli_common_voice_22_0_00017", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00017.wav", "ref_text": "在这类故事的早期版本里,女人的猪脸外观是由巫术导致的。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "bcb4464171113dd9b51f371c3eecea06771fde83e7e3239ad0516469c6dcdf80170d26c7d1b1ef2476c45b51bfb4ee5549f07d7002bcfcec9b371a30c873b92d", "gender": "male_masculine", "accent": "", "age": "twenties", "locale": "zh-CN"}}
|
| 19 |
-
{"utt_id": "fsicoli_common_voice_22_0_00018", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00018.wav", "ref_text": "事件起因据信是天然气爆炸。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "bcb4464171113dd9b51f371c3eecea06771fde83e7e3239ad0516469c6dcdf80170d26c7d1b1ef2476c45b51bfb4ee5549f07d7002bcfcec9b371a30c873b92d", "gender": "male_masculine", "accent": "", "age": "twenties", "locale": "zh-CN"}}
|
| 20 |
-
{"utt_id": "fsicoli_common_voice_22_0_00019", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00019.wav", "ref_text": "在工作了九年后,伯爵不幸去世。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "bcb4464171113dd9b51f371c3eecea06771fde83e7e3239ad0516469c6dcdf80170d26c7d1b1ef2476c45b51bfb4ee5549f07d7002bcfcec9b371a30c873b92d", "gender": "male_masculine", "accent": "", "age": "twenties", "locale": "zh-CN"}}
|
| 21 |
-
{"utt_id": "fsicoli_common_voice_22_0_00020", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00020.wav", "ref_text": "整个系统称为键接合。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "bcb4464171113dd9b51f371c3eecea06771fde83e7e3239ad0516469c6dcdf80170d26c7d1b1ef2476c45b51bfb4ee5549f07d7002bcfcec9b371a30c873b92d", "gender": "male_masculine", "accent": "", "age": "twenties", "locale": "zh-CN"}}
|
| 22 |
-
{"utt_id": "fsicoli_common_voice_22_0_00021", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00021.wav", "ref_text": "大和和纪,日本漫画家,代表作有《窈窕淑女》、《源氏物语》等。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "bcb4464171113dd9b51f371c3eecea06771fde83e7e3239ad0516469c6dcdf80170d26c7d1b1ef2476c45b51bfb4ee5549f07d7002bcfcec9b371a30c873b92d", "gender": "male_masculine", "accent": "", "age": "twenties", "locale": "zh-CN"}}
|
| 23 |
-
{"utt_id": "fsicoli_common_voice_22_0_00022", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00022.wav", "ref_text": "事后三天,赵宇被福州市公安局晋安分局以涉嫌故意伤害罪刑事拘留。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "bcb4464171113dd9b51f371c3eecea06771fde83e7e3239ad0516469c6dcdf80170d26c7d1b1ef2476c45b51bfb4ee5549f07d7002bcfcec9b371a30c873b92d", "gender": "male_masculine", "accent": "", "age": "twenties", "locale": "zh-CN"}}
|
| 24 |
-
{"utt_id": "fsicoli_common_voice_22_0_00023", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00023.wav", "ref_text": "由春岗互通向萝岗方向排列", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "bcb4464171113dd9b51f371c3eecea06771fde83e7e3239ad0516469c6dcdf80170d26c7d1b1ef2476c45b51bfb4ee5549f07d7002bcfcec9b371a30c873b92d", "gender": "male_masculine", "accent": "", "age": "twenties", "locale": "zh-CN"}}
|
| 25 |
-
{"utt_id": "fsicoli_common_voice_22_0_00024", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00024.wav", "ref_text": "弘光帝即位,让刘文照袭封新乐伯,南京沦陷后寄居在高邮,开辟农田种菜直到去世。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "bcb4464171113dd9b51f371c3eecea06771fde83e7e3239ad0516469c6dcdf80170d26c7d1b1ef2476c45b51bfb4ee5549f07d7002bcfcec9b371a30c873b92d", "gender": "male_masculine", "accent": "", "age": "twenties", "locale": "zh-CN"}}
|
| 26 |
-
{"utt_id": "fsicoli_common_voice_22_0_00025", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00025.wav", "ref_text": "露露夫人终究与三姐弟达成了协议。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "99a4cee094a7058f27e615982d793da9039f8916c4cb0934eafecb601214cb89657ddee22f688a38782a72f5b6622a323ed6dca74f6663430f8cb3c0804563ea", "gender": "male_masculine", "accent": "出生地:31 上海市", "age": "teens", "locale": "zh-CN"}}
|
| 27 |
-
{"utt_id": "fsicoli_common_voice_22_0_00026", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00026.wav", "ref_text": "武定州,中国唐朝时设置的州。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "99a4cee094a7058f27e615982d793da9039f8916c4cb0934eafecb601214cb89657ddee22f688a38782a72f5b6622a323ed6dca74f6663430f8cb3c0804563ea", "gender": "male_masculine", "accent": "出生地:31 上海市", "age": "teens", "locale": "zh-CN"}}
|
| 28 |
-
{"utt_id": "fsicoli_common_voice_22_0_00027", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00027.wav", "ref_text": "宝陀寺,可以指", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "99a4cee094a7058f27e615982d793da9039f8916c4cb0934eafecb601214cb89657ddee22f688a38782a72f5b6622a323ed6dca74f6663430f8cb3c0804563ea", "gender": "male_masculine", "accent": "出生地:31 上海市", "age": "teens", "locale": "zh-CN"}}
|
| 29 |
-
{"utt_id": "fsicoli_common_voice_22_0_00028", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00028.wav", "ref_text": "去札幌啤酒博物馆", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "99a4cee094a7058f27e615982d793da9039f8916c4cb0934eafecb601214cb89657ddee22f688a38782a72f5b6622a323ed6dca74f6663430f8cb3c0804563ea", "gender": "male_masculine", "accent": "出生地:31 上海市", "age": "teens", "locale": "zh-CN"}}
|
| 30 |
-
{"utt_id": "fsicoli_common_voice_22_0_00029", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00029.wav", "ref_text": "洛莱塔是位于美国加利福尼亚州洪堡县的一个人口普查指定地区。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "99a4cee094a7058f27e615982d793da9039f8916c4cb0934eafecb601214cb89657ddee22f688a38782a72f5b6622a323ed6dca74f6663430f8cb3c0804563ea", "gender": "male_masculine", "accent": "出生地:31 上海市", "age": "teens", "locale": "zh-CN"}}
|
| 31 |
-
{"utt_id": "fsicoli_common_voice_22_0_00030", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00030.wav", "ref_text": "许州人。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "99a4cee094a7058f27e615982d793da9039f8916c4cb0934eafecb601214cb89657ddee22f688a38782a72f5b6622a323ed6dca74f6663430f8cb3c0804563ea", "gender": "male_masculine", "accent": "出生地:31 上海市", "age": "teens", "locale": "zh-CN"}}
|
| 32 |
-
{"utt_id": "fsicoli_common_voice_22_0_00031", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00031.wav", "ref_text": "班纳镇区为美国堪萨斯州杰克逊县辖下的镇区。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "99a4cee094a7058f27e615982d793da9039f8916c4cb0934eafecb601214cb89657ddee22f688a38782a72f5b6622a323ed6dca74f6663430f8cb3c0804563ea", "gender": "male_masculine", "accent": "出生地:31 上海市", "age": "teens", "locale": "zh-CN"}}
|
| 33 |
-
{"utt_id": "fsicoli_common_voice_22_0_00032", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00032.wav", "ref_text": "范家庄遗址,位于山东省潍坊市坊子区坊城街道。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "99a4cee094a7058f27e615982d793da9039f8916c4cb0934eafecb601214cb89657ddee22f688a38782a72f5b6622a323ed6dca74f6663430f8cb3c0804563ea", "gender": "male_masculine", "accent": "出生地:31 上海市", "age": "teens", "locale": "zh-CN"}}
|
| 34 |
-
{"utt_id": "fsicoli_common_voice_22_0_00033", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00033.wav", "ref_text": "郭新立,河北安国人,出生于北京,中国教育人物,现任山东大学党委书记。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "99a4cee094a7058f27e615982d793da9039f8916c4cb0934eafecb601214cb89657ddee22f688a38782a72f5b6622a323ed6dca74f6663430f8cb3c0804563ea", "gender": "male_masculine", "accent": "出生地:31 上海市", "age": "teens", "locale": "zh-CN"}}
|
| 35 |
-
{"utt_id": "fsicoli_common_voice_22_0_00034", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00034.wav", "ref_text": "龟山风景区管理处是下辖的一个类似乡级单位。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "22950d9b987d2554c0d7130808cc60fcb5255d92bb579ad138f4da5e2d5fc52b02d4639e4fe708ef5b820a04812fd3f530e3ea93abfac3e55c8dc2ad22696403", "gender": "", "accent": "", "age": "", "locale": "zh-CN"}}
|
| 36 |
-
{"utt_id": "fsicoli_common_voice_22_0_00035", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00035.wav", "ref_text": "后来他随着李成栋反正,历任光禄卿、户部右侍郎,兵部左侍郎,永历二年晋兵部尚书。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "22950d9b987d2554c0d7130808cc60fcb5255d92bb579ad138f4da5e2d5fc52b02d4639e4fe708ef5b820a04812fd3f530e3ea93abfac3e55c8dc2ad22696403", "gender": "", "accent": "", "age": "", "locale": "zh-CN"}}
|
| 37 |
-
{"utt_id": "fsicoli_common_voice_22_0_00036", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00036.wav", "ref_text": "同年加入中国人民解放军。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "22950d9b987d2554c0d7130808cc60fcb5255d92bb579ad138f4da5e2d5fc52b02d4639e4fe708ef5b820a04812fd3f530e3ea93abfac3e55c8dc2ad22696403", "gender": "", "accent": "", "age": "", "locale": "zh-CN"}}
|
| 38 |
-
{"utt_id": "fsicoli_common_voice_22_0_00037", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00037.wav", "ref_text": "由马可、许亚军领衔主演,并由岳红、柯蓝、王策、孙爽联合主演。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "22950d9b987d2554c0d7130808cc60fcb5255d92bb579ad138f4da5e2d5fc52b02d4639e4fe708ef5b820a04812fd3f530e3ea93abfac3e55c8dc2ad22696403", "gender": "", "accent": "", "age": "", "locale": "zh-CN"}}
|
| 39 |
-
{"utt_id": "fsicoli_common_voice_22_0_00038", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00038.wav", "ref_text": "生于崎玉县川越市,女子美术大学肄业。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "22950d9b987d2554c0d7130808cc60fcb5255d92bb579ad138f4da5e2d5fc52b02d4639e4fe708ef5b820a04812fd3f530e3ea93abfac3e55c8dc2ad22696403", "gender": "", "accent": "", "age": "", "locale": "zh-CN"}}
|
| 40 |
-
{"utt_id": "fsicoli_common_voice_22_0_00039", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00039.wav", "ref_text": "旧福布斯敦是位于美国加利福尼亚州比尤特县的一个非建制地区。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "22950d9b987d2554c0d7130808cc60fcb5255d92bb579ad138f4da5e2d5fc52b02d4639e4fe708ef5b820a04812fd3f530e3ea93abfac3e55c8dc2ad22696403", "gender": "", "accent": "", "age": "", "locale": "zh-CN"}}
|
| 41 |
-
{"utt_id": "fsicoli_common_voice_22_0_00040", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00040.wav", "ref_text": "大厅供穆斯林祈祷,这也是他们见面以结束禁食的地方。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "22950d9b987d2554c0d7130808cc60fcb5255d92bb579ad138f4da5e2d5fc52b02d4639e4fe708ef5b820a04812fd3f530e3ea93abfac3e55c8dc2ad22696403", "gender": "", "accent": "", "age": "", "locale": "zh-CN"}}
|
| 42 |
-
{"utt_id": "fsicoli_common_voice_22_0_00041", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00041.wav", "ref_text": "我们就没办法改善", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "22950d9b987d2554c0d7130808cc60fcb5255d92bb579ad138f4da5e2d5fc52b02d4639e4fe708ef5b820a04812fd3f530e3ea93abfac3e55c8dc2ad22696403", "gender": "", "accent": "", "age": "", "locale": "zh-CN"}}
|
| 43 |
-
{"utt_id": "fsicoli_common_voice_22_0_00042", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00042.wav", "ref_text": "四号镇区是位于美国阿肯色州本顿县的一个镇区。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "22950d9b987d2554c0d7130808cc60fcb5255d92bb579ad138f4da5e2d5fc52b02d4639e4fe708ef5b820a04812fd3f530e3ea93abfac3e55c8dc2ad22696403", "gender": "", "accent": "", "age": "", "locale": "zh-CN"}}
|
| 44 |
-
{"utt_id": "fsicoli_common_voice_22_0_00043", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00043.wav", "ref_text": "格梅林后来出版了若干本关于化学、制药科学、矿物学和植物学的教科书。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "22950d9b987d2554c0d7130808cc60fcb5255d92bb579ad138f4da5e2d5fc52b02d4639e4fe708ef5b820a04812fd3f530e3ea93abfac3e55c8dc2ad22696403", "gender": "", "accent": "", "age": "", "locale": "zh-CN"}}
|
| 45 |
-
{"utt_id": "fsicoli_common_voice_22_0_00044", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00044.wav", "ref_text": "同年获选澳门十大杰出运动员,是首位获奖的篮球员。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "3c71635420e0de3a0272e28a63d340dbaaeb5d99e246668955f38c25279dfdbbd8eec8cc8663601fe11d6cfd81a45f9a2e8a5d55379220fe71d24a00bee0effb", "gender": "male_masculine", "accent": "出生地:42 湖北省", "age": "thirties", "locale": "zh-CN"}}
|
| 46 |
-
{"utt_id": "fsicoli_common_voice_22_0_00045", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00045.wav", "ref_text": "阿尔德斯普林斯是位于美国加利福尼亚州弗雷斯诺县的一个非建制地区。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "3c71635420e0de3a0272e28a63d340dbaaeb5d99e246668955f38c25279dfdbbd8eec8cc8663601fe11d6cfd81a45f9a2e8a5d55379220fe71d24a00bee0effb", "gender": "male_masculine", "accent": "出生地:42 湖北省", "age": "thirties", "locale": "zh-CN"}}
|
| 47 |
-
{"utt_id": "fsicoli_common_voice_22_0_00046", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00046.wav", "ref_text": "巴特勒是位于美国亚利桑那州莫哈维县的一个非建制地区。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "3c71635420e0de3a0272e28a63d340dbaaeb5d99e246668955f38c25279dfdbbd8eec8cc8663601fe11d6cfd81a45f9a2e8a5d55379220fe71d24a00bee0effb", "gender": "male_masculine", "accent": "出生地:42 湖北省", "age": "thirties", "locale": "zh-CN"}}
|
| 48 |
-
{"utt_id": "fsicoli_common_voice_22_0_00047", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00047.wav", "ref_text": "最后放弃", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "3c71635420e0de3a0272e28a63d340dbaaeb5d99e246668955f38c25279dfdbbd8eec8cc8663601fe11d6cfd81a45f9a2e8a5d55379220fe71d24a00bee0effb", "gender": "male_masculine", "accent": "出生地:42 湖北省", "age": "thirties", "locale": "zh-CN"}}
|
| 49 |
-
{"utt_id": "fsicoli_common_voice_22_0_00048", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00048.wav", "ref_text": "薄刀峰林场,是下辖的一个类似乡级单位。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "3c71635420e0de3a0272e28a63d340dbaaeb5d99e246668955f38c25279dfdbbd8eec8cc8663601fe11d6cfd81a45f9a2e8a5d55379220fe71d24a00bee0effb", "gender": "male_masculine", "accent": "出生地:42 湖北省", "age": "thirties", "locale": "zh-CN"}}
|
| 50 |
-
{"utt_id": "fsicoli_common_voice_22_0_00049", "audio_uri": "C:\\Users\\hp\\Desktop\\ASR Agent\\ASR_AGENT_\\data\\hf_audio\\fsicoli_common_voice_22_0_00049.wav", "ref_text": "该季他第一次出赛是在九局上担任普林斯·菲尔德的代跑。", "meta": {"dataset_id": "fsicoli/common_voice_22_0", "dataset_config": "zh-CN", "split": "validation", "text_field": "sentence", "sample_rate": 48000, "client_id": "dfacf81ef98f2b80ebf3a932d8c926f7fa65ffaa8dfc35edefc1344d0e4096cc52dd6cd86f2b29d9ae8dc8bf25d4ac3e0fd6133ed370de7f4e6df6d89193c9b4", "gender": "male_masculine", "accent": "出生地:35 福建省", "age": "twenties", "locale": "zh-CN"}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pipeline/run_all.py
CHANGED
|
@@ -6,26 +6,36 @@ from pipeline.run_analysis import run_analysis
|
|
| 6 |
from pipeline.run_asr import run_asr
|
| 7 |
|
| 8 |
|
| 9 |
-
|
|
|
|
|
|
|
|
|
|
| 10 |
ap = argparse.ArgumentParser()
|
| 11 |
ap.add_argument("--manifest", required=True)
|
| 12 |
ap.add_argument("--model_name", default="openai/whisper-small")
|
| 13 |
ap.add_argument("--device", default="cpu")
|
| 14 |
-
ap.add_argument("--backend", default="auto", choices=
|
|
|
|
|
|
|
| 15 |
ap.add_argument("--llm_model", default="gpt-4.1-mini")
|
| 16 |
ap.add_argument("--disable_llm", action="store_true")
|
| 17 |
-
ap.add_argument("--language", default="zh")
|
| 18 |
args = ap.parse_args()
|
| 19 |
|
| 20 |
run_id = run_asr(
|
| 21 |
manifest_path=args.manifest,
|
|
|
|
| 22 |
model_repo_id=args.model_name,
|
| 23 |
device=args.device,
|
| 24 |
asr_config={"language": args.language},
|
| 25 |
backend=args.backend,
|
| 26 |
)
|
| 27 |
-
run_analysis(
|
| 28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
|
| 30 |
|
| 31 |
if __name__ == "__main__":
|
|
|
|
| 6 |
from pipeline.run_asr import run_asr
|
| 7 |
|
| 8 |
|
| 9 |
+
BACKEND_CHOICES = ["auto", "whisper_transformers", "qwen3_asr"]
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def main() -> None:
|
| 13 |
ap = argparse.ArgumentParser()
|
| 14 |
ap.add_argument("--manifest", required=True)
|
| 15 |
ap.add_argument("--model_name", default="openai/whisper-small")
|
| 16 |
ap.add_argument("--device", default="cpu")
|
| 17 |
+
ap.add_argument("--backend", default="auto", choices=BACKEND_CHOICES)
|
| 18 |
+
ap.add_argument("--language", default="zh")
|
| 19 |
+
ap.add_argument("--out_root", default="runs")
|
| 20 |
ap.add_argument("--llm_model", default="gpt-4.1-mini")
|
| 21 |
ap.add_argument("--disable_llm", action="store_true")
|
|
|
|
| 22 |
args = ap.parse_args()
|
| 23 |
|
| 24 |
run_id = run_asr(
|
| 25 |
manifest_path=args.manifest,
|
| 26 |
+
out_root=args.out_root,
|
| 27 |
model_repo_id=args.model_name,
|
| 28 |
device=args.device,
|
| 29 |
asr_config={"language": args.language},
|
| 30 |
backend=args.backend,
|
| 31 |
)
|
| 32 |
+
run_analysis(
|
| 33 |
+
run_id,
|
| 34 |
+
out_root=args.out_root,
|
| 35 |
+
llm_enabled=not args.disable_llm,
|
| 36 |
+
llm_model=args.llm_model,
|
| 37 |
+
)
|
| 38 |
+
print(f"Done. Run: {args.out_root}/{run_id}")
|
| 39 |
|
| 40 |
|
| 41 |
if __name__ == "__main__":
|
scripts/run_hf_job.py
CHANGED
|
@@ -5,9 +5,7 @@ import json
|
|
| 5 |
import os
|
| 6 |
import sys
|
| 7 |
from pathlib import Path
|
| 8 |
-
from typing import
|
| 9 |
-
|
| 10 |
-
import pandas as pd
|
| 11 |
|
| 12 |
# Ensure project root is on sys.path
|
| 13 |
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
|
@@ -29,11 +27,6 @@ def build_manifest_from_hf(
|
|
| 29 |
num_samples: int,
|
| 30 |
out_manifest: Path,
|
| 31 |
) -> int:
|
| 32 |
-
"""
|
| 33 |
-
Robust HF loader for datasets with audio.
|
| 34 |
-
Uses streaming=True and materializes audio to local wav files.
|
| 35 |
-
Works well for Common Voice-like datasets when dataset scripts are supported.
|
| 36 |
-
"""
|
| 37 |
from datasets import load_dataset
|
| 38 |
import soundfile as sf
|
| 39 |
|
|
@@ -96,7 +89,6 @@ def build_manifest_from_hf(
|
|
| 96 |
"text_field": text_field,
|
| 97 |
"sample_rate": sr,
|
| 98 |
}
|
| 99 |
-
|
| 100 |
for k in ["client_id", "gender", "accent", "age", "locale"]:
|
| 101 |
if k in item:
|
| 102 |
meta[k] = item.get(k)
|
|
@@ -121,61 +113,7 @@ def build_manifest_from_hf(
|
|
| 121 |
return len(records)
|
| 122 |
|
| 123 |
|
| 124 |
-
def
|
| 125 |
-
"""
|
| 126 |
-
Generate:
|
| 127 |
-
- root_cause.json
|
| 128 |
-
- diagnostic_report.md
|
| 129 |
-
under runs/<run_id>/
|
| 130 |
-
"""
|
| 131 |
-
from analysis.root_cause import infer_root_causes
|
| 132 |
-
from report.diagnostic_report import generate_report_with_openai
|
| 133 |
-
from openai import OpenAI
|
| 134 |
-
|
| 135 |
-
run_dir = Path(runs_dir) / run_id
|
| 136 |
-
|
| 137 |
-
# aligned.jsonl
|
| 138 |
-
aligned_path = run_dir / "aligned.jsonl"
|
| 139 |
-
aligned_rows = []
|
| 140 |
-
if aligned_path.exists():
|
| 141 |
-
with aligned_path.open("r", encoding="utf-8") as f:
|
| 142 |
-
for line in f:
|
| 143 |
-
line = line.strip()
|
| 144 |
-
if line:
|
| 145 |
-
aligned_rows.append(json.loads(line))
|
| 146 |
-
df_align = pd.DataFrame(aligned_rows)
|
| 147 |
-
|
| 148 |
-
# events.parquet
|
| 149 |
-
events_path = run_dir / "events.parquet"
|
| 150 |
-
df_events = pd.read_parquet(events_path) if events_path.exists() else pd.DataFrame()
|
| 151 |
-
|
| 152 |
-
# summary.json
|
| 153 |
-
summary_path = run_dir / "summary.json"
|
| 154 |
-
summary = json.loads(summary_path.read_text(encoding="utf-8")) if summary_path.exists() else {}
|
| 155 |
-
|
| 156 |
-
# Rule/statistics-based diagnosis
|
| 157 |
-
root_cause = infer_root_causes(df_events, df_align)
|
| 158 |
-
(run_dir / "root_cause.json").write_text(
|
| 159 |
-
json.dumps(root_cause, ensure_ascii=False, indent=2),
|
| 160 |
-
encoding="utf-8"
|
| 161 |
-
)
|
| 162 |
-
|
| 163 |
-
# LLM report
|
| 164 |
-
api_key = os.getenv("OPENAI_API_KEY", "").strip()
|
| 165 |
-
if not api_key:
|
| 166 |
-
report_text = (
|
| 167 |
-
"# Diagnostic Report\n\n"
|
| 168 |
-
"OPENAI_API_KEY is not set, so only root_cause.json was generated.\n\n"
|
| 169 |
-
"Please add OPENAI_API_KEY in Hugging Face Space Settings → Secrets."
|
| 170 |
-
)
|
| 171 |
-
else:
|
| 172 |
-
client = OpenAI(api_key=api_key)
|
| 173 |
-
report_text = generate_report_with_openai(root_cause, summary, client)
|
| 174 |
-
|
| 175 |
-
(run_dir / "diagnostic_report.md").write_text(report_text, encoding="utf-8")
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
def main():
|
| 179 |
ap = argparse.ArgumentParser()
|
| 180 |
ap.add_argument("--dataset_id", required=True)
|
| 181 |
ap.add_argument("--dataset_config", default="")
|
|
@@ -186,7 +124,9 @@ def main():
|
|
| 186 |
ap.add_argument("--model_repo_id", required=True)
|
| 187 |
ap.add_argument("--backend", default="auto", choices=["auto", "whisper_transformers", "qwen3_asr"])
|
| 188 |
ap.add_argument("--language", default="zh")
|
| 189 |
-
|
|
|
|
|
|
|
| 190 |
ap.add_argument("--out_root", default="runs")
|
| 191 |
args = ap.parse_args()
|
| 192 |
|
|
@@ -196,7 +136,7 @@ def main():
|
|
| 196 |
data_dir.mkdir(parents=True, exist_ok=True)
|
| 197 |
manifest_path = data_dir / "manifest_hf.jsonl"
|
| 198 |
|
| 199 |
-
print("[1/
|
| 200 |
n = build_manifest_from_hf(
|
| 201 |
dataset_id=args.dataset_id,
|
| 202 |
dataset_config=args.dataset_config.strip() or None,
|
|
@@ -207,28 +147,30 @@ def main():
|
|
| 207 |
)
|
| 208 |
print(f" - Wrote {n} samples to {manifest_path}")
|
| 209 |
|
| 210 |
-
print("[2/
|
| 211 |
from pipeline.run_asr import run_asr
|
| 212 |
|
| 213 |
run_id = run_asr(
|
| 214 |
manifest_path=str(manifest_path),
|
| 215 |
out_root=args.out_root,
|
| 216 |
model_repo_id=args.model_repo_id,
|
| 217 |
-
device=
|
| 218 |
asr_config={"language": args.language},
|
| 219 |
backend=args.backend,
|
| 220 |
)
|
| 221 |
print(f" - ASR done. run_id={run_id}")
|
| 222 |
|
| 223 |
-
print("[3/
|
| 224 |
from pipeline.run_analysis import run_analysis
|
| 225 |
|
| 226 |
-
run_analysis(
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
|
|
|
|
|
|
| 230 |
|
| 231 |
-
print("[
|
| 232 |
print(f"Run directory: {Path(args.out_root) / run_id}")
|
| 233 |
|
| 234 |
|
|
|
|
| 5 |
import os
|
| 6 |
import sys
|
| 7 |
from pathlib import Path
|
| 8 |
+
from typing import Any, Dict, Optional
|
|
|
|
|
|
|
| 9 |
|
| 10 |
# Ensure project root is on sys.path
|
| 11 |
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
| 27 |
num_samples: int,
|
| 28 |
out_manifest: Path,
|
| 29 |
) -> int:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
from datasets import load_dataset
|
| 31 |
import soundfile as sf
|
| 32 |
|
|
|
|
| 89 |
"text_field": text_field,
|
| 90 |
"sample_rate": sr,
|
| 91 |
}
|
|
|
|
| 92 |
for k in ["client_id", "gender", "accent", "age", "locale"]:
|
| 93 |
if k in item:
|
| 94 |
meta[k] = item.get(k)
|
|
|
|
| 113 |
return len(records)
|
| 114 |
|
| 115 |
|
| 116 |
+
def main() -> None:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
ap = argparse.ArgumentParser()
|
| 118 |
ap.add_argument("--dataset_id", required=True)
|
| 119 |
ap.add_argument("--dataset_config", default="")
|
|
|
|
| 124 |
ap.add_argument("--model_repo_id", required=True)
|
| 125 |
ap.add_argument("--backend", default="auto", choices=["auto", "whisper_transformers", "qwen3_asr"])
|
| 126 |
ap.add_argument("--language", default="zh")
|
| 127 |
+
ap.add_argument("--device", default="cpu")
|
| 128 |
+
ap.add_argument("--llm_model", default="gpt-4.1-mini")
|
| 129 |
+
ap.add_argument("--disable_llm", action="store_true")
|
| 130 |
ap.add_argument("--out_root", default="runs")
|
| 131 |
args = ap.parse_args()
|
| 132 |
|
|
|
|
| 136 |
data_dir.mkdir(parents=True, exist_ok=True)
|
| 137 |
manifest_path = data_dir / "manifest_hf.jsonl"
|
| 138 |
|
| 139 |
+
print("[1/4] Building manifest from Hugging Face dataset...")
|
| 140 |
n = build_manifest_from_hf(
|
| 141 |
dataset_id=args.dataset_id,
|
| 142 |
dataset_config=args.dataset_config.strip() or None,
|
|
|
|
| 147 |
)
|
| 148 |
print(f" - Wrote {n} samples to {manifest_path}")
|
| 149 |
|
| 150 |
+
print("[2/4] Running ASR inference...")
|
| 151 |
from pipeline.run_asr import run_asr
|
| 152 |
|
| 153 |
run_id = run_asr(
|
| 154 |
manifest_path=str(manifest_path),
|
| 155 |
out_root=args.out_root,
|
| 156 |
model_repo_id=args.model_repo_id,
|
| 157 |
+
device=args.device,
|
| 158 |
asr_config={"language": args.language},
|
| 159 |
backend=args.backend,
|
| 160 |
)
|
| 161 |
print(f" - ASR done. run_id={run_id}")
|
| 162 |
|
| 163 |
+
print("[3/4] Running analysis and diagnosis...")
|
| 164 |
from pipeline.run_analysis import run_analysis
|
| 165 |
|
| 166 |
+
run_analysis(
|
| 167 |
+
run_id,
|
| 168 |
+
out_root=args.out_root,
|
| 169 |
+
llm_enabled=not args.disable_llm,
|
| 170 |
+
llm_model=args.llm_model,
|
| 171 |
+
)
|
| 172 |
|
| 173 |
+
print("[4/4] Done.")
|
| 174 |
print(f"Run directory: {Path(args.out_root) / run_id}")
|
| 175 |
|
| 176 |
|
ui/app.py
CHANGED
|
@@ -4,6 +4,7 @@ import json
|
|
| 4 |
import subprocess
|
| 5 |
import sys
|
| 6 |
from pathlib import Path
|
|
|
|
| 7 |
|
| 8 |
import gradio as gr
|
| 9 |
import pandas as pd
|
|
@@ -13,9 +14,10 @@ RUNS_DIR = Path("runs")
|
|
| 13 |
SEMANTIC_JUDGEMENTS = ["ALL", "语义基本等价", "轻微偏差", "明显偏差", "严重失真", "不确定"]
|
| 14 |
SEVERITIES = ["ALL", "high", "medium", "low"]
|
| 15 |
BUSINESS_IMPACTS = ["ALL", "high", "medium", "low"]
|
|
|
|
| 16 |
|
| 17 |
|
| 18 |
-
def list_runs():
|
| 19 |
if not RUNS_DIR.exists():
|
| 20 |
return []
|
| 21 |
return sorted(
|
|
@@ -41,7 +43,7 @@ def _read_jsonl(path: Path):
|
|
| 41 |
|
| 42 |
|
| 43 |
def _normalize_semantic_cell(xs):
|
| 44 |
-
def _clean_seq(seq):
|
| 45 |
out = []
|
| 46 |
for x in seq:
|
| 47 |
if x is None:
|
|
@@ -95,6 +97,21 @@ def _normalize_semantic_df(df: pd.DataFrame) -> pd.DataFrame:
|
|
| 95 |
return out
|
| 96 |
|
| 97 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 98 |
def load_run(run_id: str):
|
| 99 |
run_dir = RUNS_DIR / run_id
|
| 100 |
meta = _read_json(run_dir / "run_meta.json", {})
|
|
@@ -110,10 +127,11 @@ def load_run(run_id: str):
|
|
| 110 |
return meta, summary, df_align, df_events, df_semantic, llm_diagnosis, diagnostic_text
|
| 111 |
|
| 112 |
|
| 113 |
-
def build_summary_md(meta, summary, df_semantic: pd.DataFrame | None = None):
|
| 114 |
lines = []
|
| 115 |
lines.append(f"### Run ID: `{meta.get('run_id')}`")
|
| 116 |
lines.append(f"- Model: `{meta.get('model_info')}`")
|
|
|
|
| 117 |
if "wer_mean" in summary and summary["wer_mean"] is not None:
|
| 118 |
lines.append(f"- WER(mean): **{summary['wer_mean']:.4f}**")
|
| 119 |
if "cer_mean" in summary and summary["cer_mean"] is not None:
|
|
@@ -129,7 +147,7 @@ def build_summary_md(meta, summary, df_semantic: pd.DataFrame | None = None):
|
|
| 129 |
return "\n".join(lines)
|
| 130 |
|
| 131 |
|
| 132 |
-
def build_semantic_overview_md(df_semantic: pd.DataFrame, llm_diagnosis: dict):
|
| 133 |
if df_semantic is None or len(df_semantic) == 0:
|
| 134 |
return "### Semantic Overview\n暂无 per-utterance LLM 语义诊断结果。请先用配置了 `OPENAI_API_KEY` 的流程跑分析。"
|
| 135 |
lines = ["### Semantic Overview"]
|
|
@@ -175,13 +193,13 @@ def _head_semantic(df_semantic: pd.DataFrame) -> pd.DataFrame:
|
|
| 175 |
"semantic_error_types_str", "reason", "ref_text", "hyp_text",
|
| 176 |
]
|
| 177 |
cols = [c for c in cols if c in df_semantic.columns]
|
| 178 |
-
return
|
| 179 |
|
| 180 |
|
| 181 |
def on_select_run(run_id):
|
| 182 |
if not run_id:
|
| 183 |
empty = pd.DataFrame()
|
| 184 |
-
return "", empty, empty, empty, "", "No diagnostic report yet.", gr.update(choices=[]), gr.update(choices=[])
|
| 185 |
|
| 186 |
meta, summary, df_align, df_events, df_semantic, llm_diagnosis, diagnostic_text = load_run(run_id)
|
| 187 |
md = build_summary_md(meta, summary, df_semantic)
|
|
@@ -261,10 +279,7 @@ def search_semantic(run_id, judgement, severity, business_impact, semantic_type,
|
|
| 261 |
if min_cer is not None and "cer" in q.columns:
|
| 262 |
q = q[q["cer"].fillna(0) >= float(min_cer)]
|
| 263 |
|
| 264 |
-
|
| 265 |
-
if order_cols:
|
| 266 |
-
q = q.sort_values(order_cols, ascending=[True, True, False][:len(order_cols)])
|
| 267 |
-
|
| 268 |
cols = [
|
| 269 |
"utt_id", "semantic_judgement", "severity", "business_impact", "wer", "cer",
|
| 270 |
"semantic_error_types_str", "reason", "improvement_suggestions_str", "domain", "accent",
|
|
@@ -278,6 +293,7 @@ def apply_backend_preset(backend, model_repo_id, language):
|
|
| 278 |
backend = str(backend or "auto").strip()
|
| 279 |
model_repo_id = str(model_repo_id or "").strip()
|
| 280 |
language = str(language or "").strip()
|
|
|
|
| 281 |
if backend == "qwen3_asr":
|
| 282 |
if (not model_repo_id) or ("qwen3-asr" not in model_repo_id.lower()):
|
| 283 |
model_repo_id = "Qwen/Qwen3-ASR-0.6B"
|
|
@@ -285,16 +301,20 @@ def apply_backend_preset(backend, model_repo_id, language):
|
|
| 285 |
language = "zh"
|
| 286 |
info = "Qwen3-ASR 已启用。建议模型:Qwen/Qwen3-ASR-0.6B 或 Qwen/Qwen3-ASR-1.7B。若环境未安装 qwen-asr,任务会失败。"
|
| 287 |
return model_repo_id, language, info
|
|
|
|
| 288 |
if backend == "whisper_transformers":
|
| 289 |
if (not model_repo_id) or ("whisper" not in model_repo_id.lower()):
|
| 290 |
model_repo_id = "openai/whisper-small"
|
|
|
|
|
|
|
| 291 |
info = "Whisper Transformers 已启用。"
|
| 292 |
-
return model_repo_id, language
|
|
|
|
| 293 |
info = "backend=auto:会根据模型名自动选择适配器;模型名包含 qwen3-asr 时会走 Qwen3-ASR Adapter。"
|
| 294 |
return model_repo_id or "openai/whisper-small", language or "zh", info
|
| 295 |
|
| 296 |
|
| 297 |
-
def run_hf_job(dataset_id, dataset_config, split, text_field, model_repo_id, backend, language, num_samples):
|
| 298 |
model_repo_id, language, preset_info = apply_backend_preset(backend, model_repo_id, language)
|
| 299 |
cmd = [
|
| 300 |
sys.executable,
|
|
@@ -305,16 +325,19 @@ def run_hf_job(dataset_id, dataset_config, split, text_field, model_repo_id, bac
|
|
| 305 |
"--model_repo_id", model_repo_id.strip(),
|
| 306 |
"--backend", str(backend).strip(),
|
| 307 |
"--language", language.strip(),
|
|
|
|
|
|
|
| 308 |
"--num", str(int(num_samples)),
|
| 309 |
]
|
|
|
|
|
|
|
| 310 |
if dataset_config and dataset_config.strip():
|
| 311 |
cmd += ["--dataset_config", dataset_config.strip()]
|
| 312 |
|
| 313 |
p = subprocess.run(cmd, capture_output=True, text=True)
|
| 314 |
-
out = (p.stdout or "") + ("\n" + (p.stderr or "") if p.stderr else "")
|
| 315 |
if p.returncode != 0:
|
| 316 |
-
out =
|
| 317 |
-
out += "\n\n[HINT] If you see 401/403 for Common Voice: set HF_TOKEN in Space Settings → Secrets, and accept dataset terms on HF."
|
| 318 |
empty = pd.DataFrame()
|
| 319 |
return out, gr.update(), "", empty, empty, empty, "", "No diagnostic report yet.", gr.update(), gr.update()
|
| 320 |
|
|
@@ -325,7 +348,6 @@ def run_hf_job(dataset_id, dataset_config, split, text_field, model_repo_id, bac
|
|
| 325 |
else:
|
| 326 |
md, align_view, events_view, semantic_view, semantic_md, diagnostic_text, type_dd, domain_dd = "", pd.DataFrame(), pd.DataFrame(), pd.DataFrame(), "", "No diagnostic report yet.", gr.update(), gr.update()
|
| 327 |
|
| 328 |
-
out = preset_info + "\n\n" + out
|
| 329 |
return out, gr.update(choices=runs, value=latest), md, align_view, events_view, semantic_view, semantic_md, diagnostic_text, type_dd, domain_dd
|
| 330 |
|
| 331 |
|
|
@@ -335,7 +357,7 @@ with gr.Blocks() as demo:
|
|
| 335 |
with gr.Accordion("Run from Hugging Face", open=True):
|
| 336 |
gr.Markdown(
|
| 337 |
"Fill in a dataset and an ASR model, then click **Run**. "
|
| 338 |
-
"If the dataset is gated, set `HF_TOKEN` in Space **Settings
|
| 339 |
"For LLM semantic diagnostics, make sure `OPENAI_API_KEY` is available."
|
| 340 |
)
|
| 341 |
with gr.Row():
|
|
@@ -347,8 +369,12 @@ with gr.Blocks() as demo:
|
|
| 347 |
num_samples = gr.Number(label="Num samples", value=50, precision=0)
|
| 348 |
with gr.Row():
|
| 349 |
model_repo_id = gr.Textbox(label="HF model repo id", value="openai/whisper-small")
|
| 350 |
-
backend = gr.Dropdown(label="ASR backend", choices=
|
| 351 |
language = gr.Textbox(label="Language", value="zh")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 352 |
run_btn = gr.Button("Run")
|
| 353 |
backend_info = gr.Markdown("backend=auto:会根据模型名自动选择适配器;模型名包含 qwen3-asr 时会走 Qwen3-ASR Adapter。")
|
| 354 |
logs = gr.Textbox(label="Logs", lines=16)
|
|
@@ -421,6 +447,6 @@ with gr.Blocks() as demo:
|
|
| 421 |
|
| 422 |
run_btn.click(
|
| 423 |
run_hf_job,
|
| 424 |
-
inputs=[dataset_id, dataset_config, split, text_field, model_repo_id, backend, language, num_samples],
|
| 425 |
outputs=[logs, run_dd, summary_md, align_tbl, events_tbl, semantic_tbl, semantic_overview_md, diagnostic_md, semantic_type, semantic_domain],
|
| 426 |
)
|
|
|
|
| 4 |
import subprocess
|
| 5 |
import sys
|
| 6 |
from pathlib import Path
|
| 7 |
+
from typing import Iterable
|
| 8 |
|
| 9 |
import gradio as gr
|
| 10 |
import pandas as pd
|
|
|
|
| 14 |
SEMANTIC_JUDGEMENTS = ["ALL", "语义基本等价", "轻微偏差", "明显偏差", "严重失真", "不确定"]
|
| 15 |
SEVERITIES = ["ALL", "high", "medium", "low"]
|
| 16 |
BUSINESS_IMPACTS = ["ALL", "high", "medium", "low"]
|
| 17 |
+
_BACKEND_CHOICES = ["auto", "whisper_transformers", "qwen3_asr"]
|
| 18 |
|
| 19 |
|
| 20 |
+
def list_runs() -> list[str]:
|
| 21 |
if not RUNS_DIR.exists():
|
| 22 |
return []
|
| 23 |
return sorted(
|
|
|
|
| 43 |
|
| 44 |
|
| 45 |
def _normalize_semantic_cell(xs):
|
| 46 |
+
def _clean_seq(seq: Iterable):
|
| 47 |
out = []
|
| 48 |
for x in seq:
|
| 49 |
if x is None:
|
|
|
|
| 97 |
return out
|
| 98 |
|
| 99 |
|
| 100 |
+
def _apply_priority_order(df: pd.DataFrame) -> pd.DataFrame:
|
| 101 |
+
if df is None or len(df) == 0:
|
| 102 |
+
return df
|
| 103 |
+
out = df.copy()
|
| 104 |
+
if "business_impact" in out.columns:
|
| 105 |
+
out["business_impact"] = pd.Categorical(out["business_impact"], categories=["high", "medium", "low"], ordered=True)
|
| 106 |
+
if "severity" in out.columns:
|
| 107 |
+
out["severity"] = pd.Categorical(out["severity"], categories=["high", "medium", "low"], ordered=True)
|
| 108 |
+
order_cols = [c for c in ["business_impact", "severity", "cer"] if c in out.columns]
|
| 109 |
+
if order_cols:
|
| 110 |
+
ascending = [True if c != "cer" else False for c in order_cols]
|
| 111 |
+
out = out.sort_values(order_cols, ascending=ascending, na_position="last")
|
| 112 |
+
return out
|
| 113 |
+
|
| 114 |
+
|
| 115 |
def load_run(run_id: str):
|
| 116 |
run_dir = RUNS_DIR / run_id
|
| 117 |
meta = _read_json(run_dir / "run_meta.json", {})
|
|
|
|
| 127 |
return meta, summary, df_align, df_events, df_semantic, llm_diagnosis, diagnostic_text
|
| 128 |
|
| 129 |
|
| 130 |
+
def build_summary_md(meta, summary, df_semantic: pd.DataFrame | None = None) -> str:
|
| 131 |
lines = []
|
| 132 |
lines.append(f"### Run ID: `{meta.get('run_id')}`")
|
| 133 |
lines.append(f"- Model: `{meta.get('model_info')}`")
|
| 134 |
+
lines.append(f"- Backend: `{meta.get('backend', 'unknown')}`")
|
| 135 |
if "wer_mean" in summary and summary["wer_mean"] is not None:
|
| 136 |
lines.append(f"- WER(mean): **{summary['wer_mean']:.4f}**")
|
| 137 |
if "cer_mean" in summary and summary["cer_mean"] is not None:
|
|
|
|
| 147 |
return "\n".join(lines)
|
| 148 |
|
| 149 |
|
| 150 |
+
def build_semantic_overview_md(df_semantic: pd.DataFrame, llm_diagnosis: dict) -> str:
|
| 151 |
if df_semantic is None or len(df_semantic) == 0:
|
| 152 |
return "### Semantic Overview\n暂无 per-utterance LLM 语义诊断结果。请先用配置了 `OPENAI_API_KEY` 的流程跑分析。"
|
| 153 |
lines = ["### Semantic Overview"]
|
|
|
|
| 193 |
"semantic_error_types_str", "reason", "ref_text", "hyp_text",
|
| 194 |
]
|
| 195 |
cols = [c for c in cols if c in df_semantic.columns]
|
| 196 |
+
return _apply_priority_order(df_semantic).head(100)[cols]
|
| 197 |
|
| 198 |
|
| 199 |
def on_select_run(run_id):
|
| 200 |
if not run_id:
|
| 201 |
empty = pd.DataFrame()
|
| 202 |
+
return "", empty, empty, empty, "", "No diagnostic report yet.", gr.update(choices=["ALL"], value="ALL"), gr.update(choices=["ALL"], value="ALL")
|
| 203 |
|
| 204 |
meta, summary, df_align, df_events, df_semantic, llm_diagnosis, diagnostic_text = load_run(run_id)
|
| 205 |
md = build_summary_md(meta, summary, df_semantic)
|
|
|
|
| 279 |
if min_cer is not None and "cer" in q.columns:
|
| 280 |
q = q[q["cer"].fillna(0) >= float(min_cer)]
|
| 281 |
|
| 282 |
+
q = _apply_priority_order(q)
|
|
|
|
|
|
|
|
|
|
| 283 |
cols = [
|
| 284 |
"utt_id", "semantic_judgement", "severity", "business_impact", "wer", "cer",
|
| 285 |
"semantic_error_types_str", "reason", "improvement_suggestions_str", "domain", "accent",
|
|
|
|
| 293 |
backend = str(backend or "auto").strip()
|
| 294 |
model_repo_id = str(model_repo_id or "").strip()
|
| 295 |
language = str(language or "").strip()
|
| 296 |
+
|
| 297 |
if backend == "qwen3_asr":
|
| 298 |
if (not model_repo_id) or ("qwen3-asr" not in model_repo_id.lower()):
|
| 299 |
model_repo_id = "Qwen/Qwen3-ASR-0.6B"
|
|
|
|
| 301 |
language = "zh"
|
| 302 |
info = "Qwen3-ASR 已启用。建议模型:Qwen/Qwen3-ASR-0.6B 或 Qwen/Qwen3-ASR-1.7B。若环境未安装 qwen-asr,任务会失败。"
|
| 303 |
return model_repo_id, language, info
|
| 304 |
+
|
| 305 |
if backend == "whisper_transformers":
|
| 306 |
if (not model_repo_id) or ("whisper" not in model_repo_id.lower()):
|
| 307 |
model_repo_id = "openai/whisper-small"
|
| 308 |
+
if not language:
|
| 309 |
+
language = "zh"
|
| 310 |
info = "Whisper Transformers 已启用。"
|
| 311 |
+
return model_repo_id, language, info
|
| 312 |
+
|
| 313 |
info = "backend=auto:会根据模型名自动选择适配器;模型名包含 qwen3-asr 时会走 Qwen3-ASR Adapter。"
|
| 314 |
return model_repo_id or "openai/whisper-small", language or "zh", info
|
| 315 |
|
| 316 |
|
| 317 |
+
def run_hf_job(dataset_id, dataset_config, split, text_field, model_repo_id, backend, language, device, llm_model, disable_llm, num_samples):
|
| 318 |
model_repo_id, language, preset_info = apply_backend_preset(backend, model_repo_id, language)
|
| 319 |
cmd = [
|
| 320 |
sys.executable,
|
|
|
|
| 325 |
"--model_repo_id", model_repo_id.strip(),
|
| 326 |
"--backend", str(backend).strip(),
|
| 327 |
"--language", language.strip(),
|
| 328 |
+
"--device", str(device).strip(),
|
| 329 |
+
"--llm_model", str(llm_model).strip(),
|
| 330 |
"--num", str(int(num_samples)),
|
| 331 |
]
|
| 332 |
+
if disable_llm:
|
| 333 |
+
cmd.append("--disable_llm")
|
| 334 |
if dataset_config and dataset_config.strip():
|
| 335 |
cmd += ["--dataset_config", dataset_config.strip()]
|
| 336 |
|
| 337 |
p = subprocess.run(cmd, capture_output=True, text=True)
|
| 338 |
+
out = preset_info + "\n\n" + (p.stdout or "") + ("\n" + (p.stderr or "") if p.stderr else "")
|
| 339 |
if p.returncode != 0:
|
| 340 |
+
out += "\n\n[HINT] If you see 401/403 for Common Voice: set HF_TOKEN in Space Settings -> Secrets, and accept dataset terms on HF."
|
|
|
|
| 341 |
empty = pd.DataFrame()
|
| 342 |
return out, gr.update(), "", empty, empty, empty, "", "No diagnostic report yet.", gr.update(), gr.update()
|
| 343 |
|
|
|
|
| 348 |
else:
|
| 349 |
md, align_view, events_view, semantic_view, semantic_md, diagnostic_text, type_dd, domain_dd = "", pd.DataFrame(), pd.DataFrame(), pd.DataFrame(), "", "No diagnostic report yet.", gr.update(), gr.update()
|
| 350 |
|
|
|
|
| 351 |
return out, gr.update(choices=runs, value=latest), md, align_view, events_view, semantic_view, semantic_md, diagnostic_text, type_dd, domain_dd
|
| 352 |
|
| 353 |
|
|
|
|
| 357 |
with gr.Accordion("Run from Hugging Face", open=True):
|
| 358 |
gr.Markdown(
|
| 359 |
"Fill in a dataset and an ASR model, then click **Run**. "
|
| 360 |
+
"If the dataset is gated, set `HF_TOKEN` in Space **Settings -> Secrets**. "
|
| 361 |
"For LLM semantic diagnostics, make sure `OPENAI_API_KEY` is available."
|
| 362 |
)
|
| 363 |
with gr.Row():
|
|
|
|
| 369 |
num_samples = gr.Number(label="Num samples", value=50, precision=0)
|
| 370 |
with gr.Row():
|
| 371 |
model_repo_id = gr.Textbox(label="HF model repo id", value="openai/whisper-small")
|
| 372 |
+
backend = gr.Dropdown(label="ASR backend", choices=_BACKEND_CHOICES, value="auto")
|
| 373 |
language = gr.Textbox(label="Language", value="zh")
|
| 374 |
+
with gr.Row():
|
| 375 |
+
device = gr.Dropdown(label="Device", choices=["cpu", "cuda"], value="cpu")
|
| 376 |
+
llm_model = gr.Textbox(label="LLM model", value="gpt-4.1-mini")
|
| 377 |
+
disable_llm = gr.Checkbox(label="Disable LLM diagnosis", value=False)
|
| 378 |
run_btn = gr.Button("Run")
|
| 379 |
backend_info = gr.Markdown("backend=auto:会根据模型名自动选择适配器;模型名包含 qwen3-asr 时会走 Qwen3-ASR Adapter。")
|
| 380 |
logs = gr.Textbox(label="Logs", lines=16)
|
|
|
|
| 447 |
|
| 448 |
run_btn.click(
|
| 449 |
run_hf_job,
|
| 450 |
+
inputs=[dataset_id, dataset_config, split, text_field, model_repo_id, backend, language, device, llm_model, disable_llm, num_samples],
|
| 451 |
outputs=[logs, run_dd, summary_md, align_tbl, events_tbl, semantic_tbl, semantic_overview_md, diagnostic_md, semantic_type, semantic_domain],
|
| 452 |
)
|