"""
声通语音评测批量处理工具

功能说明:
- 读取 Excel 文件，其中包含音频链接（userAudio 字段）和参考文本（refText 字段）
- 调用声通 API 对音频进行评测，获取总分、明细和recordId
- 在原 Excel 中添加"测试总分"、"测试明细"和"测试recordId"三个字段
- 输出文件命名为: {原文件名}_add_shengtong_result.xlsx
- 支持串行和并发两种处理模式

环境变量配置:
- ST_APP_KEY: 声通应用 Key
- ST_SECRET_KEY: 声通 Secret Key

声通API文档: http://api.stkouyu.com
"""

import pandas as pd
import os
import requests
import tempfile
from pathlib import Path
import json
import time
import hashlib
import uuid
from concurrent.futures import ThreadPoolExecutor, as_completed
import threading
from queue import Queue
import logging

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('shengtong_batch_processing.log'),
        logging.StreamHandler()
    ]
)

# 从 .env 文件加载环境变量
from dotenv import load_dotenv
load_dotenv()

# ==================== 全局配置 ====================
# DEBUG 模式开关（控制详细日志输出）
DEBUG_MODE = False


def debug_print(message):
    """
    DEBUG 信息输出函数

    Args:
        message (str): 要输出的调试信息
    """
    if DEBUG_MODE:
        print(f"[DEBUG] {message}")


# ==================== 声通 API 相关代码 ====================

class ShengtongEvaluator:
    """声通口语评测 API 封装类"""

    def __init__(self):
        """从环境变量读取 API 配置"""
        self.app_key = os.environ.get('ST_APP_KEY', '')
        self.secret_key = os.environ.get('ST_SECRET_KEY', '')
        self.api_url = "http://api.stkouyu.com:8080/sent.eval"

        # 检查环境变量是否配置
        if not all([self.app_key, self.secret_key]):
            raise ValueError(
                "请配置声通 API 环境变量: ST_APP_KEY, ST_SECRET_KEY"
            )

    def _generate_signature(self, data: str) -> str:
        """生成SHA1签名"""
        return hashlib.sha1(data.encode('utf-8')).hexdigest()

    def _build_request_params(self, ref_text: str, audio_ext: str) -> dict:
        """构建请求参数"""
        timestamp = str(int(time.time()))
        user_id = str(uuid.uuid4())

        # 生成签名
        connect_data = self.app_key + timestamp + self.secret_key
        start_data = self.app_key + timestamp + user_id + self.secret_key
        connect_sig = self._generate_signature(connect_data)
        start_sig = self._generate_signature(start_data)

        # 构建请求参数
        params = {
            "connect": {
                "cmd": "connect",
                "param": {
                    "sdk": {
                        "version": 16777472,
                        "source": 9,
                        "protocol": 2
                    },
                    "app": {
                        "applicationId": self.app_key,
                        "sig": connect_sig,
                        "timestamp": timestamp
                    }
                }
            },
            "start": {
                "cmd": "start",
                "param": {
                    "app": {
                        "applicationId": self.app_key,
                        "sig": start_sig,
                        "timestamp": timestamp,
                        "userId": user_id
                    },
                    "audio": {
                        "audioType": audio_ext,
                        "channel": 1,
                        "sampleBytes": 2,
                        "sampleRate": 16000
                    },
                    "request": {
                        "coreType": "sent.eval",
                        "refText": ref_text,
                        "tokenId": "makee",
                    }
                }
            }
        }

        return params

    def evaluate(self, audio_file_path: str, ref_text: str) -> dict:
        """
        调用声通API进行口语评测

        Args:
            audio_file_path (str): 音频文件路径
            ref_text (str): 参考文本

        Returns:
            dict: 评测结果
        """
        debug_print(f"开始评测音频文件: {audio_file_path}")
        debug_print(f"评测文本: {ref_text}")

        # 检查音频文件是否存在
        if not os.path.exists(audio_file_path):
            error_msg = f"音频文件不存在: {audio_file_path}"
            logging.error(error_msg)
            return {"error": error_msg}

        # 获取音频文件扩展名
        audio_ext = os.path.splitext(audio_file_path)[1][1:]  # 去掉点号
        if not audio_ext:
            audio_ext = "wav"  # 默认为wav

        # 构建请求参数
        params = self._build_request_params(ref_text, audio_ext)

        # 读取音频文件
        try:
            with open(audio_file_path, 'rb') as f:
                audio_data = f.read()

            # 构建multipart/form-data请求
            files = {
                'text': (None, json.dumps(params)),
                'audio': (f"{int(time.time() * 1000000)}.{audio_ext}", audio_data)
            }

            headers = {
                'Request-Index': '0'
            }

            debug_print("开始发送请求到声通API...")
            response = requests.post(
                self.api_url,
                files=files,
                headers=headers,
                timeout=30
            )

            if response.status_code == 200:
                result = response.json()
                debug_print("声通API返回成功")
                return result
            else:
                error_msg = f"请求失败，状态码: {response.status_code}"
                logging.error(f"{error_msg}, 响应: {response.text}")
                return {
                    "error": error_msg,
                    "response": response.text
                }

        except requests.exceptions.RequestException as e:
            error_msg = f"请求异常: {str(e)}"
            logging.error(error_msg)
            return {"error": error_msg}
        except Exception as e:
            error_msg = f"评测过程出错: {str(e)}"
            logging.error(error_msg)
            return {"error": error_msg}


def evaluate_audio_file(audio_file_path, text="nice to meet you."):
    """
    简化的音频评测函数

    Args:
        audio_file_path (str): 音频文件路径
        text (str): 评测文本内容

    Returns:
        dict: 评测结果JSON
    """
    api = ShengtongEvaluator()
    return api.evaluate(audio_file_path, text)


# ==================== 批量处理相关代码 ====================

def download_audio_file(audio_url, temp_dir, max_retries=3, timeout=30):
    """
    下载音频文件到临时目录（增强版本）

    Args:
        audio_url (str): 音频文件URL
        temp_dir (str): 临时目录路径
        max_retries (int): 最大重试次数
        timeout (int): 请求超时时间（秒）

    Returns:
        str: 下载的音频文件路径，失败返回None
    """
    if not audio_url or pd.isna(audio_url):
        logging.warning("音频URL为空或无效")
        return None

    # 从URL中提取文件名
    try:
        file_name = os.path.basename(audio_url.split('?')[0])  # 去除URL参数
        if not file_name or '.' not in file_name:
            file_name = f"audio_{hash(audio_url) % 100000}.wav"  # 生成默认文件名

        file_path = os.path.join(temp_dir, file_name)

        # 重试机制
        for attempt in range(max_retries):
            try:
                logging.info(f"正在下载音频文件 (尝试 {attempt + 1}/{max_retries}): {audio_url}")

                # 设置请求头，模拟浏览器
                headers = {
                    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
                }

                response = requests.get(audio_url, timeout=timeout, headers=headers, stream=True)
                response.raise_for_status()

                # 检查内容类型
                content_type = response.headers.get('content-type', '')
                if not any(audio_type in content_type.lower() for audio_type in ['audio', 'wav', 'mp3', 'ogg', 'flac']):
                    logging.warning(f"可能不是音频文件，Content-Type: {content_type}")

                # 写入文件
                with open(file_path, 'wb') as f:
                    for chunk in response.iter_content(chunk_size=8192):
                        if chunk:
                            f.write(chunk)

                # 验证文件大小
                file_size = os.path.getsize(file_path)
                if file_size == 0:
                    raise ValueError("下载的文件为空")

                logging.info(f"音频文件下载成功: {file_path} (大小: {file_size} bytes)")
                return file_path

            except requests.exceptions.Timeout:
                logging.warning(f"下载超时 (尝试 {attempt + 1}/{max_retries}): {audio_url}")
                if attempt < max_retries - 1:
                    time.sleep(2 ** attempt)  # 指数退避
                    continue
            except requests.exceptions.RequestException as e:
                logging.warning(f"下载请求异常 (尝试 {attempt + 1}/{max_retries}): {str(e)}")
                if attempt < max_retries - 1:
                    time.sleep(2 ** attempt)
                    continue
            except Exception as e:
                logging.error(f"下载过程中发生未知错误 (尝试 {attempt + 1}/{max_retries}): {str(e)}")
                if attempt < max_retries - 1:
                    time.sleep(2 ** attempt)
                    continue

        logging.error(f"音频文件下载失败，已达到最大重试次数: {audio_url}")
        return None

    except Exception as e:
        logging.error(f"下载音频文件时发生异常: {str(e)}")
        return None


def format_shengtong_details(shengtong_result):
    """
    格式化声通评测结果为明细字符串

    Args:
        shengtong_result (dict): 声通API返回的结果

    Returns:
        str: 格式化的明细字符串
    """
    if not shengtong_result or 'error' in shengtong_result:
        return ""

    try:
        # 从result字段中获取words数组
        result = shengtong_result.get('result', {})
        words = result.get('words', [])

        if not words:
            return ""

        details = []
        for word in words:
            # 获取单词内容和得分
            word_text = word.get('word', '')
            scores = word.get('scores', {})
            overall_score = scores.get('overall', 0)

            # 格式化为 "单词 分数"
            details.append(f"{word_text} {int(overall_score)}")

        return "\n".join(details)

    except Exception as e:
        logging.error(f"格式化声通明细失败: {str(e)}")
        return ""


def get_shengtong_total_score(shengtong_result):
    """
    获取声通评测总分

    Args:
        shengtong_result (dict): 声通API返回的结果

    Returns:
        int: 总分，失败返回0
    """
    if not shengtong_result or 'error' in shengtong_result:
        return 0

    try:
        result = shengtong_result.get('result', {})
        overall_score = result.get('overall', 0)
        return int(overall_score)
    except Exception as e:
        logging.error(f"获取声通总分失败: {str(e)}")
        return 0


def get_shengtong_record_id(shengtong_result):
    """
    获取声通评测recordId

    Args:
        shengtong_result (dict): 声通API返回的结果

    Returns:
        str: recordId，失败返回空字符串
    """
    if not shengtong_result or 'error' in shengtong_result:
        return ""

    try:
        record_id = shengtong_result.get('recordId', '')
        return str(record_id) if record_id else ""
    except Exception as e:
        logging.error(f"获取声通recordId失败: {str(e)}")
        return ""


def process_single_row(row_data, temp_dir, results_dict, lock, rate_limiter=None):
    """
    处理单行数据（并发版本，增强错误处理和时间分析）

    Args:
        row_data (tuple): (index, row) 数据
        temp_dir (str): 临时目录路径
        results_dict (dict): 结果字典
        lock (threading.Lock): 线程锁
        rate_limiter (Queue): 速率限制器

    Returns:
        None
    """
    index, row = row_data
    start_time = time.time()
    timing_info = {}

    try:
        # 1. 速率限制等待时间
        rate_limit_start = time.time()
        if rate_limiter:
            rate_limiter.get()  # 获取令牌
        timing_info['rate_limit_wait'] = time.time() - rate_limit_start

        logging.info(f"开始处理第 {index + 1} 行数据")

        # 2. 数据预处理时间
        preprocess_start = time.time()
        ref_text = str(row['refText']) if pd.notna(row['refText']) else ""
        audio_url = str(row['userAudio']) if pd.notna(row['userAudio']) else ""

        # 数据验证
        if not ref_text:
            raise ValueError("refText 为空或无效")

        if not audio_url:
            raise ValueError("userAudio 为空或无效")
        timing_info['preprocess'] = time.time() - preprocess_start

        # 3. 音频下载时间
        download_start = time.time()
        audio_file_path = download_audio_file(audio_url, temp_dir)
        timing_info['audio_download'] = time.time() - download_start

        if not audio_file_path:
            raise ValueError("音频文件下载失败")

        try:
            # 4. 声通API调用时间
            api_start = time.time()
            logging.info(f"正在调用声通API评测: {ref_text}")
            shengtong_result = evaluate_audio_file(audio_file_path, ref_text)
            timing_info['api_call'] = time.time() - api_start

            if not shengtong_result:
                raise ValueError("声通API返回空结果")

            # 5. 结果处理时间
            result_process_start = time.time()
            shengtong_details = format_shengtong_details(shengtong_result)
            shengtong_total_score = get_shengtong_total_score(shengtong_result)
            shengtong_record_id = get_shengtong_record_id(shengtong_result)
            timing_info['result_process'] = time.time() - result_process_start

            # 6. 数据更新时间
            update_start = time.time()
            with lock:
                results_dict[index] = {
                    '测试总分': shengtong_total_score,
                    '测试明细': shengtong_details,
                    '测试recordId': shengtong_record_id
                }
            timing_info['data_update'] = time.time() - update_start

            # 计算总耗时
            total_time = time.time() - start_time
            timing_info['total'] = total_time

            # 详细的时间分析日志
            logging.info(f"第 {index + 1} 行处理成功 - 总分: {shengtong_total_score} | "
                        f"总耗时: {total_time:.2f}s | "
                        f"速率等待: {timing_info['rate_limit_wait']:.2f}s | "
                        f"预处理: {timing_info['preprocess']:.3f}s | "
                        f"音频下载: {timing_info['audio_download']:.2f}s | "
                        f"API调用: {timing_info['api_call']:.2f}s | "
                        f"结果处理: {timing_info['result_process']:.3f}s | "
                        f"数据更新: {timing_info['data_update']:.3f}s")

        except Exception as api_error:
            total_time = time.time() - start_time
            logging.error(f"第 {index + 1} 行声通API调用失败: {str(api_error)} | "
                         f"总耗时: {total_time:.2f}s | "
                         f"音频下载: {timing_info.get('audio_download', 0):.2f}s | "
                         f"API调用: {timing_info.get('api_call', 0):.2f}s")
            with lock:
                results_dict[index] = {
                    '测试总分': 0,
                    '测试明细': "",
                    '测试recordId': "",
                    'error': f'API调用失败: {str(api_error)}'
                }

        finally:
            # 7. 清理时间
            cleanup_start = time.time()
            try:
                if audio_file_path and os.path.exists(audio_file_path):
                    os.remove(audio_file_path)
                    logging.debug(f"已删除临时文件: {audio_file_path}")
            except Exception as cleanup_error:
                logging.warning(f"清理临时文件失败: {str(cleanup_error)}")
            timing_info['cleanup'] = time.time() - cleanup_start

            # 释放速率限制令牌
            if rate_limiter:
                try:
                    rate_limiter.put(None, timeout=1)  # 归还令牌
                except:
                    pass  # 队列可能已满，忽略

    except Exception as e:
        total_time = time.time() - start_time
        logging.error(f"第 {index + 1} 行处理异常: {str(e)} | 总耗时: {total_time:.2f}s")
        with lock:
            results_dict[index] = {
                '测试总分': 0,
                '测试明细': "",
                '测试recordId': "",
                'error': f'处理异常: {str(e)}'
            }

        # 释放速率限制令牌
        if rate_limiter:
            try:
                rate_limiter.put(None, timeout=1)
            except:
                pass


def process_excel_with_shengtong_concurrent(input_file_path, output_dir="output/audio", max_workers=3, rate_limit_per_second=3):
    """
    处理Excel文件，添加声通评测结果（并发版本，增强控制）

    Args:
        input_file_path (str): 输入Excel文件路径
        output_dir (str): 输出目录路径，默认为 output/audio
        max_workers (int): 最大并发线程数，默认3
        rate_limit_per_second (int): 每秒最大请求数，默认3

    Returns:
        bool: 处理是否成功
    """
    start_time = time.time()

    try:
        # 读取Excel文件
        logging.info(f"正在读取Excel文件: {input_file_path}")
        df = pd.read_excel(input_file_path)

        # 检查必要的列是否存在
        required_columns = ['refText', 'userAudio']
        missing_columns = [col for col in required_columns if col not in df.columns]
        if missing_columns:
            logging.error(f"Excel文件缺少必要的列: {missing_columns}")
            return False

        # 数据预处理和验证
        total_rows = len(df)
        valid_rows = 0
        for index, row in df.iterrows():
            if pd.notna(row.get('refText')) and pd.notna(row.get('userAudio')):
                valid_rows += 1

        logging.info(f"总行数: {total_rows}, 有效行数: {valid_rows}")

        if valid_rows == 0:
            logging.warning("没有找到有效的数据行")
            return False

        # 添加新列
        df['测试总分'] = 0
        df['测试明细'] = ""
        df['测试recordId'] = ""

        # 创建优化的速率限制器
        effective_rate_limit = max(rate_limit_per_second, max_workers)
        rate_limiter = Queue(maxsize=effective_rate_limit * 2)

        # 预填充令牌
        for _ in range(effective_rate_limit):
            rate_limiter.put(None)

        # 启动优化的速率限制器补充线程
        def rate_limiter_refill():
            interval = 1.0 / effective_rate_limit
            while True:
                time.sleep(interval)
                try:
                    rate_limiter.put(None, block=False)
                except:
                    pass

        rate_thread = threading.Thread(target=rate_limiter_refill, daemon=True)
        rate_thread.start()

        logging.info(f"速率限制设置: {effective_rate_limit} req/s (原始: {rate_limit_per_second}, 队列大小: {effective_rate_limit * 2})")

        # 创建临时目录用于下载音频文件
        with tempfile.TemporaryDirectory() as temp_dir:
            logging.info(f"创建临时目录: {temp_dir}")
            logging.info(f"开始并发处理，最大并发数: {max_workers}, 有效速率限制: {effective_rate_limit} req/s")

            # 准备数据
            row_data_list = [(index, row) for index, row in df.iterrows()]

            # 创建结果字典和线程锁
            results_dict = {}
            lock = threading.Lock()

            # 使用线程池进行并发处理
            with ThreadPoolExecutor(max_workers=max_workers) as executor:
                # 提交所有任务
                future_to_index = {
                    executor.submit(process_single_row, row_data, temp_dir, results_dict, lock, rate_limiter): row_data[0]
                    for row_data in row_data_list
                }

                # 等待任务完成并显示进度
                completed_count = 0
                success_count = 0
                error_count = 0

                for future in as_completed(future_to_index):
                    completed_count += 1
                    index = future_to_index[future]

                    try:
                        future.result()  # 获取结果，如果有异常会抛出

                        # 检查处理结果
                        with lock:
                            result = results_dict.get(index, {})
                            if result.get('error') is None:
                                success_count += 1
                            else:
                                error_count += 1

                        # 显示进度
                        if completed_count % 10 == 0 or completed_count == total_rows:
                            elapsed_time = time.time() - start_time
                            avg_time_per_item = elapsed_time / completed_count
                            remaining_time = avg_time_per_item * (total_rows - completed_count)

                            logging.info(f"进度: {completed_count}/{total_rows} ({completed_count/total_rows*100:.1f}%) "
                                       f"成功: {success_count}, 失败: {error_count}, "
                                       f"预计剩余时间: {remaining_time:.1f}秒")

                    except Exception as e:
                        error_count += 1
                        logging.error(f"任务 {index + 1} 执行异常: {str(e)}")
                        with lock:
                            if index not in results_dict:
                                results_dict[index] = {
                                    '测试总分': 0,
                                    '测试明细': "",
                                    '测试recordId': "",
                                    'error': f'任务执行异常: {str(e)}'
                                }

            # 将结果更新到DataFrame
            logging.info("正在更新结果到DataFrame...")
            for index in results_dict:
                result = results_dict[index]
                df.at[index, '测试总分'] = result.get('测试总分', 0)
                df.at[index, '测试明细'] = result.get('测试明细', "")
                df.at[index, '测试recordId'] = result.get('测试recordId', "")

                # 如果有错误，可以选择记录到备注列（如果存在）
                if result.get('error') and '备注' in df.columns:
                    existing_note = str(df.at[index, '备注']) if pd.notna(df.at[index, '备注']) else ""
                    error_note = f"声通API错误: {result['error']}"
                    df.at[index, '备注'] = f"{existing_note}\n{error_note}".strip()

        # 创建输出目录
        output_path = Path(output_dir)
        output_path.mkdir(parents=True, exist_ok=True)

        # 生成输出文件路径
        input_path = Path(input_file_path)
        output_file_path = output_path / f"{input_path.stem}_add_shengtong_result.xlsx"

        # 保存结果
        logging.info(f"正在保存结果到: {output_file_path}")
        df.to_excel(output_file_path, index=False)

        # 计算总耗时
        total_time = time.time() - start_time

        # 统计处理结果
        final_success_count = sum(1 for result in results_dict.values() if result.get('error') is None)
        final_error_count = len(results_dict) - final_success_count

        logging.info("=" * 50)
        logging.info("并发处理完成！")
        logging.info(f"处理统计: 成功 {final_success_count} 条，失败 {final_error_count} 条，总计 {len(results_dict)} 条")
        logging.info(f"总耗时: {total_time:.2f} 秒")
        logging.info(f"平均处理时间: {total_time/len(results_dict):.2f} 秒/条")
        logging.info(f"输出文件: {output_file_path}")
        logging.info("=" * 50)

        return True

    except Exception as e:
        logging.error(f"处理Excel文件时出错: {str(e)}")
        return False


def process_excel_with_shengtong(input_file_path, output_dir="output/audio"):
    """
    处理Excel文件，添加声通评测结果（串行版本）

    Args:
        input_file_path (str): 输入Excel文件路径
        output_dir (str): 输出目录路径，默认为 output/audio

    Returns:
        bool: 处理是否成功
    """
    try:
        # 读取Excel文件
        print(f"正在读取Excel文件: {input_file_path}")
        df = pd.read_excel(input_file_path)

        # 检查必要的列是否存在
        required_columns = ['refText', 'userAudio']
        missing_columns = [col for col in required_columns if col not in df.columns]
        if missing_columns:
            print(f"错误: Excel文件缺少必要的列: {missing_columns}")
            return False

        # 添加新列
        df['测试总分'] = 0
        df['测试明细'] = ""
        df['测试recordId'] = ""

        # 创建临时目录用于下载音频文件
        with tempfile.TemporaryDirectory() as temp_dir:
            print(f"创建临时目录: {temp_dir}")

            # 处理每一行数据
            total_rows = len(df)
            for index, row in df.iterrows():
                print(f"\n处理进度: {index + 1}/{total_rows}")

                ref_text = str(row['refText']) if pd.notna(row['refText']) else ""
                audio_url = str(row['userAudio']) if pd.notna(row['userAudio']) else ""

                if not ref_text or not audio_url:
                    print(f"第 {index + 1} 行数据不完整，跳过")
                    continue

                print(f"参考文本: {ref_text}")
                print(f"音频URL: {audio_url}")

                # 下载音频文件
                audio_file_path = download_audio_file(audio_url, temp_dir)
                if not audio_file_path:
                    print(f"第 {index + 1} 行音频下载失败，跳过")
                    continue

                # 调用声通API进行评测
                print("正在调用声通API进行评测...")
                try:
                    shengtong_result = evaluate_audio_file(audio_file_path, ref_text)
                    print(f"声通API返回结果: {json.dumps(shengtong_result, indent=2, ensure_ascii=False)}")

                    # 提取总分、明细和recordId
                    total_score = get_shengtong_total_score(shengtong_result)
                    details = format_shengtong_details(shengtong_result)
                    record_id = get_shengtong_record_id(shengtong_result)

                    # 更新DataFrame
                    df.at[index, '测试总分'] = total_score
                    df.at[index, '测试明细'] = details
                    df.at[index, '测试recordId'] = record_id

                    print(f"测试总分: {total_score}")
                    print(f"测试明细: {details}")
                    print(f"测试recordId: {record_id}")

                except Exception as e:
                    print(f"第 {index + 1} 行声通API调用失败: {str(e)}")
                    continue

                # 删除临时音频文件
                try:
                    os.remove(audio_file_path)
                except:
                    pass

                # 添加延时避免API调用过于频繁
                time.sleep(1)

        # 创建输出目录
        output_path = Path(output_dir)
        output_path.mkdir(parents=True, exist_ok=True)

        # 生成输出文件路径
        input_path = Path(input_file_path)
        output_file_path = output_path / f"{input_path.stem}_add_shengtong_result.xlsx"

        # 保存结果
        print(f"\n正在保存结果到: {output_file_path}")
        df.to_excel(output_file_path, index=False)
        print("处理完成！")

        return True

    except Exception as e:
        print(f"处理Excel文件时出错: {str(e)}")
        return False


if __name__ == "__main__":
    # ==================== 配置参数 ====================
    input_file = "人工筛选测试集v2_denoise.xlsx"
    output_directory = "output/audio"  # 输出目录，可以修改
    use_concurrent = True  # True: 使用并发版本，False: 使用串行版本

    # DEBUG 模式开关（True: 显示详细调试信息，False: 仅显示关键信息）
    enable_debug = False  # 可以设置为 True 来查看详细的 DEBUG 日志

    # 设置全局 DEBUG_MODE
    globals()['DEBUG_MODE'] = enable_debug

    # 检查环境变量
    required_env_vars = ['ST_APP_KEY', 'ST_SECRET_KEY']
    missing_vars = [var for var in required_env_vars if not os.environ.get(var)]

    if missing_vars:
        print(f"错误: 缺少必要的环境变量: {missing_vars}")
        print("请在 .env 文件或系统环境变量中配置:")
        print("  ST_APP_KEY=你的应用Key")
        print("  ST_SECRET_KEY=你的Secret Key")
    elif not os.path.exists(input_file):
        print(f"文件不存在: {input_file}")
        print("请确保Excel文件存在并包含 'refText' 和 'userAudio' 列")
    else:
        if use_concurrent:
            print("使用并发版本处理（3路并发，3 req/s）...")
            success = process_excel_with_shengtong_concurrent(
                input_file,
                output_dir=output_directory,
                max_workers=3,
                rate_limit_per_second=3
            )
        else:
            print("使用串行版本处理...")
            success = process_excel_with_shengtong(input_file, output_dir=output_directory)

        if success:
            print("处理成功！")
        else:
            print("处理失败！")
