# ------------
# 字幕生成和时间戳对齐模块
# 
# 功能说明:
# 1. 智能字幕分割 - 支持基于长度的字幕自动分割
# 2. 时间戳对齐 - 模糊匹配和精确匹配字幕时间戳
# 3. 多语言支持 - 支持中文、英文、日文等多种语言字符长度计算
# 4. SRT格式输出 - 生成标准SRT字幕文件格式
# 5. 语法分析 - 使用spaCy进行英文字幕的智能切分
# ------------

import json
import pandas as pd
import os
import re
import math
import concurrent.futures
from typing import List, Tuple, Dict, Any
from rich.panel import Panel
from rich.console import Console
from rich.table import Table
import autocorrect_py as autocorrect
from thefuzz import fuzz
from core.utils import *
from core.utils.models import *
from core.prompts import get_align_prompt
from core.spacy_utils.split_by_syntax import split_english_subtitle_by_syntax
from core.spacy_utils import init_nlp
from core._3_split_semantic import match_timestamps_from_words
console = Console()

def fuzzy_find_text(text, target, threshold=80):
    """
    使用模糊匹配在目标字符串中查找最佳匹配位置
    
    参数:
        text: 要查找的文本
        target: 目标字符串
        threshold: 相似度阈值 (0-100)
        
    返回:
        int: 最佳匹配位置，如果没有找到返回-1
    """
    if not text or not target:
        return -1
    text_len = len(text)
    best_pos = -1
    best_score = 0
    
    # 滑动窗口查找最佳匹配
    for i in range(len(target) - text_len + 1):
        window = target[i:i + text_len]
        score = fuzz.ratio(text, window)
        
        if score > best_score and score >= threshold:
            best_score = score
            best_pos = i
    
    return best_pos

# ------------
# 多语言字符长度计算函数
# 
# 权重说明: 中文和日文1.75字符，韩文1.5字符，泰文1字符，全角符号1.75字符，英文和半角符号1字符
# ------------
def calc_len(text: str) -> float:
    """
    计算文本的加权长度，考虑不同语言字符的显示宽度
   
    功能说明:
    - 根据字符的Unicode范围确定字符的显示权重
    - 东亚文字(中日韩)相比拉丁字母占用更多显示空间
    - 用于字幕长度控制和时间分配计算
   
    参数:
        text (str): 要计算长度的文本字符串
   
    返回:
        float: 加权后的文本显示长度
       
    权重规则:
        - 中文(0x4E00-0x9FFF)和日文假名(0x3040-0x30FF): 1.75倍权重
        - 韩文字母(0xAC00-0xD7A3, 0x1100-0x11FF): 1.5倍权重  
        - 泰文字符(0x0E00-0x0E7F): 1倍权重
        - 全角符号(0xFF01-0xFF5E): 1.75倍权重
        - 其他字符(英文、半角符号等): 1倍权重
    """
    text = str(text)  # 防御性编程，确保输入为字符串类型
   
    def char_weight(char):
        """
        计算单个字符的显示权重
       
        参数:
            char (str): 单个Unicode字符
           
        返回:
            float: 字符的显示权重值
        """
        code = ord(char)
       
        # 中文汉字和日文字符范围
        if 0x4E00 <= code <= 0x9FFF or 0x3040 <= code <= 0x30FF:
            return 1.75
        # 韩文字符范围
        elif 0xAC00 <= code <= 0xD7A3 or 0x1100 <= code <= 0x11FF:
            return 1.5
        # 泰文字符范围
        elif 0x0E00 <= code <= 0x0E7F:
            return 1
        # 全角符号范围
        elif 0xFF01 <= code <= 0xFF5E:
            return 1.75
        # 其他字符(英文字母、数字、半角符号等)
        else:
            return 1

    return sum(char_weight(char) for char in text)

# # ------------
# # 字幕分割位置查找函数
# # ------------
# def find_split_positions(original_sentence, split_sentence):
#     """
#     从带有[br]标记的字符串中提取分割位置索引
    
#     功能说明:
#     - 解析GPT返回的带[br]标记的分割结果
#     - 计算每个分割点在原始句子中的字符位置
#     - 用于后续将分割标记转换为实际的换行符
    
#     参数:
#         original_sentence (str): 原始完整句子
#         split_sentence (str): 包含[br]分割标记的句子
        
#     返回:
#         list: 分割位置的字符索引列表
        
#     示例:
#         original: "This is a long sentence"
#         split: "This is[br] a long sentence" 
#         返回: [7] (表示在第7个字符后分割)
#     """
#     # 移除所有[br]标记，用于验证内容一致性
#     clean_split = split_sentence.replace('[br]', '')
#     split_positions = []
    
#     # 按[br]标记分割句子，获取各个部分
#     parts = split_sentence.split('[br]')
#     current_pos = 0
    
#     # 遍历每个部分(除了最后一个)，计算累积位置
#     for i, part in enumerate(parts[:-1]):
#         current_pos += len(part.strip())
#         split_positions.append(current_pos)
    
#     return split_positions

# # ------------
# # GPT智能句子分割函数
# # ------------
# def split_sentence(sentence, num_parts, word_limit=20, index=-1, retry_attempt=0):
#     """
#     使用GPT模型智能分割长句子，保持语义完整性
    
#     功能说明:
#     - 调用GPT模型分析句子结构并提供分割建议
#     - 支持多次重试机制确保分割质量
#     - 根据Netflix字幕标准进行智能分割
#     - 在自然断点(标点、连词)处进行切分
    
#     参数:
#         sentence (str): 要分割的原始长句子
#         num_parts (int): 目标分割份数(默认2份)
#         word_limit (int): 每份的最大单词数限制(默认20词)
#         index (int): 句子在批处理中的索引号(用于进度显示,-1表示不显示)
#         retry_attempt (int): 当前重试次数(用于GPT prompt微调)
    
#     返回:
#         str: 用换行符('\n')分隔的分割后句子
        
#     算法流程:
#     1. 构建分割提示词发送给GPT
#     2. 验证GPT返回结果的有效性
#     3. 解析[br]标记并转换为实际分割位置
#     4. 生成最终的分割结果并显示对比
#     """
#     # 构建针对该句子的GPT分割提示词
#     split_prompt = get_split_prompt(sentence, num_parts, word_limit)
    
#     def valid_split(response_data):
#         """
#         验证GPT响应数据的有效性和完整性
        
#         参数:
#             response_data (dict): GPT返回的JSON响应数据
            
#         返回:
#             dict: 包含验证状态和错误信息的字典
#         """
#         choice = response_data["choice"]
        
#         # 检查是否包含必需的分割结果键
#         if f'split{choice}' not in response_data:
#             return {"status": "error", "message": "Missing required key: `split`"}
        
#         # 检查分割结果是否包含分割标记
#         if "[br]" not in response_data[f"split{choice}"]:
#             return {"status": "error", "message": "Split failed, no [br] found"}
            
#         return {"status": "success", "message": "Split completed"}
    
#     # 调用GPT进行句子分割(重试时在prompt后加空格以变化输入)
#     response_data = ask_gpt(
#         split_prompt + " " * retry_attempt, 
#         resp_type='json', 
#         valid_def=valid_split, 
#         log_title='split_by_meaning'
#     )
    
#     # 提取GPT选择的最佳分割方案
#     choice = response_data["choice"]
#     best_split = response_data[f"split{choice}"]
    
#     # 解析[br]标记，获取实际分割位置
#     split_points = find_split_positions(sentence, best_split)
    
#     # 将分割位置转换为实际的换行符分割
#     for i, split_point in enumerate(split_points):
#         if i == 0:
#             # 第一个分割点：直接在指定位置插入换行符
#             best_split = sentence[:split_point] + '\n' + sentence[split_point:]
#         else:
#             # 后续分割点：需要考虑前面已插入的换行符偏移
#             parts = best_split.split('\n')
#             last_part = parts[-1]
#             relative_pos = split_point - split_points[i-1]
#             parts[-1] = last_part[:relative_pos] + '\n' + last_part[relative_pos:]
#             best_split = '\n'.join(parts)
    
#     # 显示分割进度(如果提供了索引)
#     if index != -1:
#         console.print(f'[green]✅ Sentence {index} has been successfully split[/green]')
    
#     # 创建分割结果对比表格用于显示
#     table = Table(title="")
#     table.add_column("Type", style="cyan")
#     table.add_column("Sentence")
#     table.add_row("Original", sentence, style="yellow")
#     table.add_row("Split", best_split.replace('\n', ' ||'), style="yellow")
#     console.print(table)
    
#     return best_split

# # ------------
# # GPT分割提示词生成函数
# # ------------
# def get_split_prompt(sentence, num_parts=2, word_limit=20):
#     """
#     生成用于GPT模型的字幕分割提示词
    
#     功能说明:
#     - 根据检测到的语言和用户要求生成专业的分割提示
#     - 遵循Netflix字幕标准进行分割指导
#     - 要求GPT提供多个分割方案并选择最佳方案
#     - 确保分割后的语义完整性和长度平衡
    
#     参数:
#         sentence (str): 需要分割的句子文本
#         num_parts (int): 目标分割成的部分数量
#         word_limit (int): 每部分的最大单词数限制
        
#     返回:
#         str: 格式化的GPT提示词字符串
        
#     提示词设计要点:
#     - 角色定位: Netflix专业字幕分割师
#     - 任务目标: 保持语义连贯性的同时控制长度
#     - 分割原则: 在自然断点(标点、连词)处分割
#     - 输出格式: 结构化JSON包含分析和多种方案
#     """
#     # 获取当前检测到的视频语言
#     language = load_key("whisper.detected_language")
    
#     # 构建结构化的GPT提示词
#     split_prompt = f"""
# ## Role
# You are a professional Netflix subtitle splitter in **{language}**.

# ## Task
# Split the given subtitle text into **{num_parts}** parts, each less than **{word_limit}** words.

# 1. Maintain sentence meaning coherence according to Netflix subtitle standards
# 2. MOST IMPORTANT: Keep parts roughly equal in length (minimum 3 words each)
# 3. Split at natural points like punctuation marks or conjunctions
# 4. If provided text is repeated words, simply split at the middle of the repeated words.

# ## Steps
# 1. Analyze the sentence structure, complexity, and key splitting challenges
# 2. Generate two alternative splitting approaches with [br] tags at split positions
# 3. Compare both approaches highlighting their strengths and weaknesses
# 4. Choose the best splitting approach

# ## Given Text
# {sentence}

# ## Output Format
# Return JSON with this exact structure:
# {{
#     "analysis": "Brief analysis of the sentence structure and splitting challenges",
#     "split1": "First approach with [br] tags at split positions",
#     "split2": "Second approach with [br] tags at split positions", 
#     "comparison": "Compare both approaches, highlighting strengths and weaknesses",
#     "choice": 1 or 2,
#     "reason": "Why this choice is better"
# }}

# CRITICAL: Use [br] tags to mark split positions, not actual line breaks.
# """
#     return split_prompt

# # ------------
# # 源语言与目标语言字幕对齐函数
# # ------------
# def align_subs(src_sub: str, tr_sub: str, src_part: str) -> Tuple[List[str], List[str], str]:
#     """
#     使用GPT模型对齐源语言字幕和目标语言字幕的分割部分
    
#     功能说明:
#     - 当源语言字幕被分割后，相应调整目标语言字幕的分割
#     - 确保源语言和目标语言的字幕段落在语义上一一对应
#     - 使用GPT理解语义边界进行智能对齐
#     - 保持翻译的完整性和连贯性
    
#     参数:
#         src_sub (str): 原始完整的源语言字幕文本
#         tr_sub (str): 原始完整的目标语言字幕文本  
#         src_part (str): 已分割的源语言部分(用'\n'分隔)
        
#     返回:
#         Tuple[List[str], List[str], str]: 
#         - 源语言分割部分列表
#         - 目标语言对齐分割部分列表
#         - 重新合并的目标语言文本
        
#     算法流程:
#     1. 调用GPT分析源语言分割点
#     2. 在目标语言中找到对应的语义分割点
#     3. 验证对齐结果的合理性
#     4. 返回对齐后的分割结果
#     """
#     # 生成用于字幕对齐的GPT提示词
#     align_prompt = get_align_prompt(src_sub, tr_sub, src_part)
    
#     def valid_align(response_data):
#         """
#         验证GPT对齐响应数据的有效性
        
#         参数:
#             response_data (dict): GPT返回的对齐数据
            
#         返回:
#             dict: 验证状态和错误信息
#         """
#         # 检查必需的对齐数据键
#         if 'align' not in response_data:
#             return {"status": "error", "message": "Missing required key: `align`"}
        
#         # 确保对齐结果包含多个部分
#         if len(response_data['align']) < 2:
#             return {"status": "error", "message": "Align does not contain more than 1 part as expected!"}
            
#         return {"status": "success", "message": "Align completed"}
    
#     # 调用GPT进行字幕对齐处理
#     parsed = ask_gpt(
#         align_prompt, 
#         resp_type='json', 
#         valid_def=valid_align, 
#         log_title='align_subs'
#     )
#     align_data = parsed['align']
    
#     # 将源语言分割部分转为列表
#     src_parts = src_part.split('\n')
    
#     # 从GPT响应中提取对齐的目标语言部分
#     tr_parts = [
#         item[f'target_part_{i+1}'].strip() 
#         for i, item in enumerate(align_data)
#     ]
    
#     # 获取当前语言设置和对应的文本连接符
#     whisper_language = load_key("whisper.language")
#     language = load_key("whisper.detected_language") if whisper_language == 'auto' else whisper_language
#     joiner = get_joiner(language)
    
#     # 将目标语言部分重新合并为完整文本
#     tr_remerged = joiner.join(tr_parts)
    
#     # 创建对齐结果显示表格
#     table = Table(title="🔗 Aligned parts")
#     table.add_column("Language", style="cyan")
#     table.add_column("Parts", style="magenta")
#     table.add_row("SRC_LANG", "\n".join(src_parts))
#     table.add_row("TARGET_LANG", "\n".join(tr_parts))
#     console.print(table)
    
#     return src_parts, tr_parts, tr_remerged








# ------------
# 字幕输出配置常量
# ------------

# 标准字幕输出配置: (文件名, 包含的字段列表)
SUBTITLE_OUTPUT_CONFIGS = [ 
    ('src.srt', ['Source']),                          # 仅源语言字幕
    ('trans.srt', ['Translation']),                   # 仅翻译字幕
    ('src_trans.srt', ['Source', 'Translation']),     # 源语言+翻译双行字幕
    ('trans_src.srt', ['Translation', 'Source'])      # 翻译+源语言双行字幕
]

# 音频专用字幕输出配置: 用于音频合成的字幕文件
AUDIO_SUBTITLE_OUTPUT_CONFIGS = [
    ('src_subs_for_audio.srt', ['Source']),           # 源语言音频字幕
    ('trans_subs_for_audio.srt', ['Translation'])     # 翻译音频字幕
]



# ------------
# 已删除旧的时间戳获取函数
# ------------

# ------------
# 已删除旧的时间戳对齐函数
# ------------


# ------------
# 字幕生成主函数
# ------------
# ------------
# 核心处理函数
# ------------
def process_and_split_segment(segment_with_docs: Dict[str, Any], word_timestamps_df: pd.DataFrame, settings: Dict[str, Any]) -> List[Dict[str, Any]]:
    """
    处理单个字幕段落的切分和时间戳匹配
    
    参数:
        segment_with_docs: 包含spaCy Doc对象的段落数据
        word_timestamps_df: 词级时间戳数据
        settings: 切分设置参数
        
    返回:
        List[Dict]: 处理后的字幕片段列表
    """
    tr_doc = segment_with_docs['tr_doc']
    src_doc = segment_with_docs['src_doc']
    original_start = segment_with_docs['start']
    original_end = segment_with_docs['end']
    segment_id = segment_with_docs['id']
    
    max_tokens = settings['max_tokens']
    target_multiplier = settings['target_multiplier']
    
    # 检查翻译文本的token长度是否超过限制
    tr_token_count = len(tr_doc)
    adjusted_max_tokens = int(max_tokens / target_multiplier)
    print("tr_token_count: ", tr_token_count)
    print("adjusted_max_tokens: ", adjusted_max_tokens)
    
    if tr_token_count <= adjusted_max_tokens:
        # 不需要切分
        return [{
            'id': str(segment_id),
            'source_text_cleaned': clean_subtitle_text(src_doc.text),
            'translated_text_cleaned': clean_subtitle_text(tr_doc.text),
            'start_time': original_start,
            'end_time': original_end
        }]
    else:
        # 需要切分
        console.print(f"[yellow]✂️  Splitting segment {segment_id}: '{tr_doc.text[:30]}...' ({tr_token_count} tokens)[/yellow]")
        
        # 切分翻译文本
        tr_parts_docs = split_long_sentence_by_rules(tr_doc, settings)

        print("tr_parts_docs: ", tr_parts_docs)
        
        # 按比例切分源文本
        src_parts_docs = proportionally_split_source(src_doc, tr_parts_docs)
        
        # 转换为字符串用于时间戳匹配
        src_parts_text = [doc.text for doc in src_parts_docs]

        print("src_parts_text: ", src_parts_text)
        
        # 匹配时间戳
        timestamps = match_timestamps_for_splits(src_parts_text, word_timestamps_df, original_start, original_end)
        
        # 组装最终结果
        results = []
        for i, (src_doc_part, tr_doc_part, timestamp_tuple) in enumerate(zip(src_parts_docs, tr_parts_docs, timestamps)):
            start_time, end_time = timestamp_tuple
            results.append({
                'id': f"{segment_id}_{i+1}",
                'source_text_cleaned': clean_subtitle_text(src_doc_part.text),
                'translated_text_cleaned': clean_subtitle_text(tr_doc_part.text),
                'start_time': start_time,
                'end_time': end_time
            })
        
        return results

def split_long_sentence_by_rules(long_doc, settings):
    """
    基于多层级规则切分过长的句子
    
    参数:
        long_doc: spaCy Doc对象
        settings: 切分设置
        
    返回:
        List[spaCy.Doc]: 切分后的Doc对象列表
    """
    # nlp已在外部初始化，这里不需要重复获取
    max_tokens = settings['max_tokens']
    min_tokens = settings['min_tokens']
    
    # 初始化处理队列
    processing_queue = [long_doc]
    final_parts = []
    
    # 第一轮：标点符号切分
    next_queue = []
    for doc in processing_queue:
        parts = split_by_punctuation_marks(doc)
        valid_split = True
        
        for part in parts:
            if len(part) < min_tokens:
                valid_split = False
                break
        
        if valid_split and len(parts) > 1:
            for part in parts:
                if len(part) <= max_tokens:
                    final_parts.append(part)
                else:
                    next_queue.append(part)
        else:
            next_queue.append(doc)
    
    # 第二轮：关联词切分
    processing_queue = next_queue
    next_queue = []
    for doc in processing_queue:
        parts = split_by_connectors(doc)
        valid_split = True
        
        for part in parts:
            if len(part) < min_tokens:
                valid_split = False
                break
        
        if valid_split and len(parts) > 1:
            for part in parts:
                if len(part) <= max_tokens:
                    final_parts.append(part)
                else:
                    next_queue.append(part)
        else:
            next_queue.append(doc)
    
    # 第三轮：平均切分
    processing_queue = next_queue
    for doc in processing_queue:
        if len(doc) <= max_tokens:
            final_parts.append(doc)
        else:
            # 计算需要切分的份数
            n_parts = min(5, math.ceil(len(doc) / max_tokens))
            parts = split_doc_evenly(doc, n_parts)
            final_parts.extend(parts)
    
    return final_parts

def split_by_punctuation_marks(doc):
    """基于标点符号切分文档"""
    # 参考test.py中的标点符号列表
    punctuation_marks = ['.', ',', ';', '!', '?', '。', '，', '；', '！', '？']
    
    parts = []
    current_start = 0
    
    for i, token in enumerate(doc):
        if token.text in punctuation_marks and i < len(doc) - 1:
            # 在标点符号后切分
            part_doc = doc[current_start:i+1]
            if len(part_doc) > 0:
                parts.append(part_doc)
            current_start = i + 1
    
    # 添加最后一部分
    if current_start < len(doc):
        part_doc = doc[current_start:]
        if len(part_doc) > 0:
            parts.append(part_doc)
    
    return parts if len(parts) > 1 else [doc]

def split_by_connectors(doc):
    """基于关联词切分文档"""
    # 参考test.py中的关联词列表
    connectors = [
        "and", "who", "which", "that", "because", "so", "but", "or", 
        "however", "therefore", "thus", "hence", "although", "though", 
        "since", "as", "if", "unless", "until", "when", "while", 
        "after", "before", "so that", "in order to", "whereas", 
        "despite", "provided that"
    ]
    
    parts = []
    current_start = 0
    
    for i, token in enumerate(doc):
        if token.text.lower() in connectors and i > 0:
            # 在关联词前切分
            part_doc = doc[current_start:i]
            if len(part_doc) > 0:
                parts.append(part_doc)
            current_start = i
    
    # 添加最后一部分
    if current_start < len(doc):
        part_doc = doc[current_start:]
        if len(part_doc) > 0:
            parts.append(part_doc)
    
    return parts if len(parts) > 1 else [doc]

def split_doc_evenly(doc, n_parts):
    """将文档平均切分为n部分"""
    tokens_per_part = len(doc) // n_parts
    parts = []
    
    for i in range(n_parts):
        start_idx = i * tokens_per_part
        if i == n_parts - 1:
            # 最后一部分包含剩余所有tokens
            end_idx = len(doc)
        else:
            end_idx = (i + 1) * tokens_per_part
        
        part_doc = doc[start_idx:end_idx]
        if len(part_doc) > 0:
            parts.append(part_doc)
    
    return parts

def proportionally_split_source(source_doc, translated_parts_docs):
    """按翻译文本的token比例切分源文本"""
    if len(translated_parts_docs) <= 1:
        return [source_doc]
    
    # 计算每个翻译部分的token比例
    tr_token_counts = [len(doc) for doc in translated_parts_docs]
    total_tr_tokens = sum(tr_token_counts)
    
    if total_tr_tokens == 0:
        return [source_doc] + [source_doc[:0] for _ in range(len(translated_parts_docs) - 1)]
    
    # 按比例分配源文本tokens
    src_parts = []
    total_src_tokens = len(source_doc)
    start_idx = 0
    
    for i, tr_token_count in enumerate(tr_token_counts):
        if i == len(tr_token_counts) - 1:
            # 最后一部分包含剩余所有tokens
            part_doc = source_doc[start_idx:]
        else:
            # 计算当前部分应包含的token数
            proportion = tr_token_count / total_tr_tokens
            tokens_count = max(1, int(total_src_tokens * proportion))
            part_doc = source_doc[start_idx:start_idx + tokens_count]
            start_idx += tokens_count
        
        src_parts.append(part_doc)
    
    return src_parts

def bag_of_words_match_timestamps(source_parts_text, word_timestamps_df):
    """
    使用简化的序列匹配算法匹配时间戳
    
    参数:
        source_parts_text: 源语言切分后的文本列表
        word_timestamps_df: 词级时间戳DataFrame
        
    返回:
        List[Tuple]: (start_time, end_time)元组列表
    """
    # 确保数据按时间排序
    # word_timestamps_df = word_timestamps_df.sort_values('start').reset_index(drop=True)
    print("word_timestamps_df: ", word_timestamps_df)
    print("source_parts_text: ", source_parts_text)
    
    def clean_char(text):
        """清理文本，移除引号和标点"""
        import re
        return re.sub(r'["\s，。！？,!?.]', '', str(text))
    
    # 构建完整的字符序列用于匹配
    all_chars = ''.join([clean_char(row['text']) for _, row in word_timestamps_df.iterrows()])
    print("all_chars: ", all_chars)

    results = []
    start_pos = 0  # 在all_chars中的当前搜索位置
    
    for part_text in source_parts_text:
        print("before clean part_text: ", part_text)
        part_chars = clean_char(part_text)
        print("after clean part_text: ", part_chars)

        if not part_chars:
            continue
            
        # 使用模糊匹配在all_chars中找到part_chars的位置
        search_range = all_chars[start_pos:]
        fuzzy_pos = fuzzy_find_text(part_chars, search_range)
        print("fuzzy_pos: ", fuzzy_pos)
        
        if fuzzy_pos != -1:
            found_pos = start_pos + fuzzy_pos
            print(f"模糊匹配找到位置: {found_pos}")
        else:
            raise ValueError(f"无法为文本片段找到匹配的时间戳: '{part_text[:50]}...'")
        
        # 计算对应的词索引范围
        char_to_word_idx = []
        char_pos = 0
        for word_idx, (_, row) in enumerate(word_timestamps_df.iterrows()):
            word_chars = clean_char(row['text'])
            for _ in word_chars:
                char_to_word_idx.append(word_idx)
                char_pos += 1
        print("char_to_word_idx: ", char_to_word_idx)
        
        # 找到起始和结束词的索引
        if found_pos < len(char_to_word_idx):
            start_word_idx = char_to_word_idx[found_pos]
            end_pos = min(found_pos + len(part_chars) - 1, len(char_to_word_idx) - 1)
            end_word_idx = char_to_word_idx[end_pos]
            
            start_time = word_timestamps_df.iloc[start_word_idx]['start']
            end_time = word_timestamps_df.iloc[end_word_idx]['end']
            results.append((start_time, end_time))
            print("for the part_chars: ", part_chars,"start_time:", start_time,"end_time:", end_time)
            # 更新搜索位置，避免重叠
            start_pos = found_pos + len(part_chars)
        else:
            raise ValueError(f"字符位置超出范围: '{part_text[:50]}...'")
    
    return results

def match_timestamps_for_splits(source_parts_text, word_timestamps_df, original_start, original_end):
    """为切分后的源语言片段匹配时间戳"""
    # 移除兜底机制，直接使用新的词袋匹配算法
    timestamps = bag_of_words_match_timestamps(source_parts_text, word_timestamps_df)
    
    console.print(f"[green]✅ 成功匹配 {len(timestamps)} 个时间戳片段[/green]")
    
    return timestamps

def clean_subtitle_text(text):
    """清洗字幕文本，移除标点符号和特殊符号"""
    # 移除所有标点符号和特殊符号，仅保留字母、数字和空格
    cleaned = re.sub(r'[^\w\s]', '', text)
    # 合并多个空白字符为单个空格
    cleaned = re.sub(r'\s+', ' ', cleaned)
    return cleaned.strip()

def generate_srt_files(final_segments, output_dir):
    """生成源语言和翻译语言的SRT文件"""
    os.makedirs(output_dir, exist_ok=True)
    
    # 生成源语言SRT文件
    src_srt_path = os.path.join(output_dir, "final_src.srt")
    trans_srt_path = os.path.join(output_dir, "final_trans.srt")
    
    def seconds_to_srt_time(seconds):
        hours = int(seconds // 3600)
        minutes = int((seconds % 3600) // 60)
        secs = int(seconds % 60)
        millisecs = int((seconds % 1) * 1000)
        return f"{hours:02d}:{minutes:02d}:{secs:02d},{millisecs:03d}"
    
    # 写入源语言SRT
    with open(src_srt_path, 'w', encoding='utf-8') as f:
        for i, segment in enumerate(final_segments, 1):
            f.write(f"{i}\n")
            f.write(f"{seconds_to_srt_time(segment['start_time'])} --> {seconds_to_srt_time(segment['end_time'])}\n")
            f.write(f"{segment['source_text_cleaned']}\n\n")
    
    # 写入翻译SRT
    with open(trans_srt_path, 'w', encoding='utf-8') as f:
        for i, segment in enumerate(final_segments, 1):
            f.write(f"{i}\n")
            f.write(f"{seconds_to_srt_time(segment['start_time'])} --> {seconds_to_srt_time(segment['end_time'])}\n")
            f.write(f"{segment['translated_text_cleaned']}\n\n")
    
    console.print(f"[green]✅ Generated source SRT: {src_srt_path}[/green]")
    console.print(f"[green]✅ Generated translation SRT: {trans_srt_path}[/green]")

# ------------
# 新的字幕生成主函数 - 基于Token的智能切分
# ------------
def align_timestamp_main():
    """
    新版字幕生成主函数 - 支持Token级别的智能分割和并行处理
    
    功能说明:
    - 基于translate_result.json直接生成最终字幕
    - 使用spaCy进行Token级别的长度检测和切分
    - 支持标点符号、关联词和平均切分的多层级策略
    - 按Token比例切分源语言字幕并匹配时间戳
    - 并行处理提升性能
    
    算法流程:
    1. 加载翻译结果和词级时间戳数据
    2. 预处理: 一次性使用spaCy分词所有文本
    3. 并行处理每个段落的切分和时间戳匹配
    4. 清洗字幕文本并生成最终SRT文件
    """
    console.print("[bold green]🎬 Starting new token-based subtitle generation...[/bold green]")
    
    # ------------
    # 步骤1: 加载数据
    # ------------
    with open(_TRANSLATE_RESULT, 'r', encoding='utf-8') as f:
        translate_result = json.load(f)
    
    # 加载词级时间戳数据用于精确匹配
    word_timestamps_df = pd.read_excel(_2_CLEANED_CHUNKS)
    
    console.print(f"[bold green]📊 Loaded {len(translate_result)} segments and {len(word_timestamps_df)} word timestamps[/bold green]")
    
    # 加载字幕设置
    subtitle_set = load_key("subtitle")
    MAX_TOKENS = 10  # 新的Token限制
    TARGET_SUB_MULTIPLIER = subtitle_set["target_multiplier"]
    
    console.print(f"[bold cyan]📏 New token limits: Max={MAX_TOKENS}, Target multiplier={TARGET_SUB_MULTIPLIER}[/bold cyan]")
    
    # ------------
    # 步骤2: 预处理 - 一次性分词
    # ------------
    console.print("[bold blue]🔤 Preprocessing with spaCy tokenization...[/bold blue]")
    nlp = init_nlp()
    
    # 预处理所有文本
    for segment in translate_result:
        src_text = segment.get('source_text', '').strip()
        tr_text = segment['translated_text'].strip()
        
        # 使用spaCy分词
        segment['src_doc'] = nlp(src_text)
        print(segment['src_doc'])
        segment['tr_doc'] = nlp(tr_text)
        print(segment['tr_doc'])
    
    # ------------
    # 步骤3: 并行处理段落
    # ------------
    console.print("[bold blue]⚡ Starting sequential processing for debugging...[/bold blue]")
    
    settings = {
        'max_tokens': MAX_TOKENS,
        'min_tokens': 3,
        'target_multiplier': TARGET_SUB_MULTIPLIER
    }
    
    # ------------
    # 逐个处理每个段落 (用于调试)
    # ------------
    all_results = []
    for i, segment in enumerate(translate_result):
        console.print(f"[bold yellow]Processing segment {i+1}/{len(translate_result)}...[/bold yellow]")
        result = process_and_split_segment(segment, word_timestamps_df, settings)
        all_results.extend(result)
        console.print(f"[green]Segment {i+1} completed, generated {len(result)} subtitle entries.[/green]")
    
    # ------------
    # 原并行处理代码 (已注释用于调试)
    # ------------
    # with concurrent.futures.ThreadPoolExecutor(max_workers=load_key("max_workers")) as executor:
    #     # 并行处理每个段落
    #     futures = [
    #         executor.submit(process_and_split_segment, segment, word_timestamps_df, settings)
    #         for segment in translate_result
    #     ]
    #     
    #     # 收集结果
    #     all_results = []
    #     for future in concurrent.futures.as_completed(futures):
    #         result = future.result()
    #         all_results.extend(result)
    # 
    # # 按原始顺序排序
    # def sort_key(x):
    #     id_str = x['id']
    #     if '_' in id_str:
    #         # 处理格式如 "1_2" 的id
    #         base_id, sub_id = id_str.split('_')
    #         return (int(base_id), int(sub_id))
    #     else:
    #         # 处理纯数字字符串id如 "1" 
    #         return (int(id_str), 0)
    # 
    # all_results.sort(key=sort_key)
    
    # ------------
    # 步骤4: 生成最终字幕文件
    # ------------
    generate_srt_files(all_results, _OUTPUT_DIR)
    
    console.print(Panel(f"[bold green]🎉📝 Token-based subtitle generation completed! Generated {len(all_results)} subtitle entries.[/bold green]"))
    console.print(Panel(f"[bold green]📁 Subtitle files saved to: {_OUTPUT_DIR}[/bold green]"))


# ------------
# 模块执行入口
# ------------
if __name__ == '__main__':
    # # 当模块作为主程序运行时，执行字幕生成主函数
    align_timestamp_main()
    
    # ------------
    # Debug bag_of_words_match_timestamps function
    # ------------
    # import pandas as pd
    
    # # 硬编码测试数据
    # test_source_parts = [
    #     "Ditch the city chaos like now",
    #     "Welcome to your ultimate star",
    #     "Yo 30 luxury tents hiding"
    # ]
    
    # # 模拟词级时间戳数据
    # test_word_data = [
    #     {"text": "Ditch", "start": 0.0, "end": 0.5},
    #     {"text": "the", "start": 0.5, "end": 0.7},
    #     {"text": "city", "start": 0.7, "end": 1.0},
    #     {"text": "chaos", "start": 1.0, "end": 1.4},
    #     {"text": "like", "start": 1.4, "end": 1.6},
    #     {"text": "now", "start": 1.6, "end": 2.0},
    #     {"text": "Welcome", "start": 2.5, "end": 3.0},
    #     {"text": "to", "start": 3.0, "end": 3.2},
    #     {"text": "your", "start": 3.2, "end": 3.5},
    #     {"text": "ultimate", "start": 3.5, "end": 4.0},
    #     {"text": "star", "start": 4.0, "end": 4.5},
    #     {"text": "Yo", "start": 5.0, "end": 5.3},
    #     {"text": "30", "start": 5.3, "end": 5.6},
    #     {"text": "luxury", "start": 5.6, "end": 6.0},
    #     {"text": "tents", "start": 6.0, "end": 6.4},
    #     {"text": "hiding", "start": 6.4, "end": 7.0}
    # ]
    
    # test_word_timestamps_df = pd.DataFrame(test_word_data)
    
    # print("🔧 开始调试 bag_of_words_match_timestamps 函数...")
    # print(f"📝 测试文本片段: {test_source_parts}")
    # print(f"⏰ 词级时间戳数量: {len(test_word_timestamps_df)}")
    
    # try:
    #     results = bag_of_words_match_timestamps(test_source_parts, test_word_timestamps_df)
    #     print("✅ 函数执行成功!")
    #     for i, (start, end) in enumerate(results):
    #         print(f"  片段 {i}: '{test_source_parts[i]}' -> 时间: {start:.2f}s - {end:.2f}s")
    # except Exception as e:
    #     print(f"❌ 函数执行失败: {e}")
    #     import traceback
    #     traceback.print_exc()