Skip to content

视频剪辑对含英文大写的内容永远匹配失败,且零命中时静默返回原始视频 #198

Description

@sumchor
 ### 环境                                                                                                                                             
                                                                                                                                                      
 - FunClip 版本:v2.1.0(GitHub release tag)                                                                                                         
 - funasr:1.4.0(requirements 要求 >=1.3.29)                                                                                                        
 - ASR 模型:`iic/speech_seaco_paraformer_large_asr_nat-zh-cn-16k-common-vocab8404-pytorch`(中文)                                                   
 - 平台:Windows 11 / Python 3.11(与平台无关)                                                                                                       
                                                                                                                                                      
 ### 问题概述                                                                                                                                         
                                                                                                                                                      
 对中文视频剪辑时,**只要裁剪文本(dest_text)中包含英文字母,匹配就永远失败**;                                                                      
 更隐蔽的是,匹配失败时 `video_clip()` 不报任何错误,而是**静默返回原始视频路径**,                                                                   
 调用方会误以为剪辑成功。                                                                                                                             
                                                                                                                                                      
 ### 根因分析                                                                                                                                         
                                                                                                                                                      
 `funclip/videoclipper.py` 的 `video_clip()` 中(约 309 行):                                                                                        
                                                                                                                                                      
 ```python                                                                                                                                            
 ts = proc(recog_res_raw, timestamp, _dest_text.lower())                                                                                              
 ```                                                                                                                                                  
                                                                                                                                                      
 `proc()`(`funclip/utils/trans_utils.py:28`)用 `raw_text.find(dest_text)` 做精确匹配。                                                              
 这里存在**单边归一化**:                                                                                                                             
                                                                                                                                                      
 - 搜索词 `_dest_text` 被 `.lower()` 强制转小写;                                                                                                     
 - 被搜索的 `recog_res_raw` 保持 ASR 原始输出,其中英文缩写/型号名按惯例为**大写**                                                                    
   (如 `FK`、`AE`、`ASML`)。                                                                                                                        
                                                                                                                                                      
 于是 `"fk 三 零 零 零"` 在 `"FK 三 零 零 零"` 中 `find()` 返回 -1,该句永远匹配不上。                                                                
 纯中文内容不受影响(无大小写概念),所以该 bug 只在"中文内容夹英文词"时发作。                                                                        
                                                                                                                                                      
 ### 相关的不一致                                                                                                                                     
                                                                                                                                                      
 1. **音频/视频路径行为不对称**:`clip()`(音频,约 193 行)调用 `proc()` 时**没有**                                                                  
    `.lower()`,`video_clip()` 有——同一份 `recog_res_raw` 在两条路径上匹配语义不同。                                                                  
 2. **零命中静默失败**:`video_clip()` 在所有目标文本都未匹配时(约 384-386 行):                                                                    
                                                                                                                                                      
    ```python                                                                                                                                         
    else:                                                                                                                                             
        clip_video_file = video_filename   # 返回原始视频路径,无任何错误                                                                             
    ```                                                                                                                                               
                                                                                                                                                      
    调用方拿到的返回值与成功剪辑无法区分,属于静默失败。                                                                                              
                                                                                                                                                      
 ### 最小复现                                                                                                                                         
                                                                                                                                                      
 ```python                                                                                                                                            
 from funasr import AutoModel                                                                                                                         
 from videoclipper import VideoClipper                                                                                                                
                                                                                                                                                      
 model = AutoModel(                                                                                                                                   
     model="iic/speech_seaco_paraformer_large_asr_nat-zh-cn-16k-common-vocab8404-pytorch",                                                            
     vad_model="damo/speech_fsmn_vad_zh-cn-16k-common-pytorch",                                                                                       
     punc_model="damo/punc_ct-transformer_zh-cn-common-vocab272727-pytorch",                                                                          
     spk_model="damo/speech_campplus_sv_zh-cn_16k-common",                                                                                            
 )                                                                                                                                                    
 clipper = VideoClipper(model)                                                                                                                        
 clipper.lang = "zh"                                                                                                                                  
                                                                                                                                                      
 text, srt, state = clipper.video_recog("含英文缩写词的视频.mp4")                                                                                     
 # 假设识别文本包含句子 "但航天科工的FK三零零零已经列装部队……"                                                                                        
 # state["recog_res_raw"] 中对应内容为 "FK"(大写)                                                                                                   
                                                                                                                                                      
 result, message, _ = clipper.video_clip(                                                                                                             
     "但航天科工的FK三零零零已经列装部队", 0, 100, state                                                                                              
 )                                                                                                                                                    
 # 期望:命中并输出剪辑片段                                                                                                                           
 # 实际:message = "No period found in the audio...",result = 原始视频路径(无报错)                                                                 
 ```                                                                                                                                                  
                                                                                                                                                      
 ### 实际影响                                                                                                                                         
                                                                                                                                                      
 按句多段剪辑(`#` 连接)时,所有含英文的句子被静默丢弃,输出视频丢句;                                                                               
 单段剪辑时直接返回原始完整视频,表现为"剪辑成功但内容是整个原视频"。                                                                                 
                                                                                                                                                      
 ### 修复建议                                                                                                                                         
                                                                                                                                                      
 1. 匹配前对**两侧**统一大小写归一化(任选一):                                                                                                      
    - `recog()` 中将 `state['recog_res_raw']` 统一 `.lower()` 后存入(等长变换,                                                                      
      不影响空格计数与 timestamp 下标映射);                                                                                                         
    - 或 `proc()` 内部对 `raw_text` 与 `dest_text` 做一致归一化。                                                                                     
 2. `clip()` / `video_clip()` 两条路径对齐 `.lower()` 行为。                                                                                          
 3. 零命中时输出 WARNING 日志或抛出异常,不要静默返回原始视频路径。                                                                                   
                                                                                                                                                      
 ### 临时规避(调用方)                                                                                                                               
                                                                                                                                                      
 在 `video_recog()` 返回后手动 `state["recog_res_raw"] = state["recog_res_raw"].lower()`,                                                            
 并检查返回值是否等于原始视频路径以识别零命中。                                                                                                                                                 

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingneeds feedbackWaiting for reporter feedback or retest results

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions