这份代码实现了一个集成小米大模型的法律内容自动化生成工具,核心功能包括法律案例分析、短视频脚本生成、微信普法文章创作,支持在线 API 调用与离线本地备份,还具备并发控制和重试机制。下面按「模块划分 + 逐行逻辑」进行详细说明,兼顾代码功能与设计思路。

一、导入模块(第 1-12 行)

python

运行

import os
  • 功能:导入 Python 内置os模块,用于环境变量读取、文件路径操作
  • 用途:后续读取.env配置、拼接文件路径等依赖该模块。

python

运行

import json
  • 功能:导入 Python 内置json模块,用于JSON 数据的序列化与反序列化
  • 用途:解析小米 API 返回的 JSON 格式案例结果、保存视频制作指令、生成批量处理报告。

python

运行

import time
  • 功能:导入 Python 内置time模块,用于时间延迟、计时控制
  • 用途:API 重试间隔、并发等待、批量处理案例间的延迟。

python

运行

from datetime import datetime
  • 功能:从datetime模块导入datetime类,用于生成时间戳、格式化日期时间
  • 用途:创建唯一文件名(如批量报告、视频文件)、记录处理时间。

python

运行

from pathlib import Path
  • 功能:导入pathlib模块的Path类,用于面向对象的文件路径操作(比os.path更简洁、更易读)。
  • 用途:创建工作目录、拼接文件路径、判断文件是否存在,后续所有路径操作均基于此类。

python

运行

import re
  • 功能:导入 Python 内置正则表达式模块,用于文本匹配、提取、清理
  • 用途:从 API 返回结果中提取 JSON、从案例文本中提取当事人 / 判决结果等关键信息。

python

运行

from openai import OpenAI
  • 功能:从openai库导入OpenAI客户端类,用于调用兼容 OpenAI 接口的小米大模型 API
  • 用途:初始化 API 客户端、发送聊天完成请求,获取 AI 生成的法律内容。

python

运行

from dotenv import load_dotenv
  • 功能:从python-dotenv库导入load_dotenv函数,用于加载.env文件中的环境变量
  • 用途:读取小米 API 密钥、基础 URL、模型参数等配置,避免硬编码敏感信息。

python

运行

import random
  • 功能:导入 Python 内置random模块,用于生成随机数(本代码中未实际使用,预留用于后续扩展,如随机延迟避免 API 限流)。
  • 用途:可扩展为随机化重试延迟、随机选择视频模板等。

python

运行

import threading
  • 功能:导入 Python 内置threading模块,用于多线程编程、线程同步控制
  • 用途:实现并发 API 调用的槽位控制、线程安全的活跃线程数统计。

python

运行

from queue import Queue
  • 功能:从queue模块导入Queue类,用于线程安全的队列操作(本代码中未实际使用,预留用于批量任务队列化处理)。
  • 用途:可扩展为生产者 - 消费者模型,批量处理大量案例时解耦任务提交与执行。

python

运行

import requests
  • 功能:导入requests库,用于发送 HTTP 请求(本代码中未实际使用,预留用于直接调用 HTTP API、下载视频素材等扩展功能)。
  • 用途:可扩展为绕过OpenAI客户端,直接调用小米大模型的 HTTP 接口,或下载普法图片素材。

二、核心类定义:LegalContentGenerator(第 14 行)

python

运行

class LegalContentGenerator:
  • 功能:定义法律内容生成器的核心类,封装所有功能方法与配置属性,实现「高内聚、低耦合」的代码设计。
  • 设计思路:将案例分析、脚本生成、文章创作等功能封装为类方法,配置属性统一管理,方便实例化与复用。

三、类初始化方法:init(第 15-68 行)

python

运行

def __init__(self, api_key=None, base_url=None, max_concurrent=3, retry_delay=5, max_retries=3):
  • 功能:类的构造方法,初始化实例属性与配置,完成环境准备。
  • 入参说明:
    • api_key:可选,手动传入小米 API 密钥,优先级高于环境变量。
    • base_url:可选,手动传入小米 API 基础 URL,优先级高于环境变量。
    • max_concurrent:最大并发数,默认 3,控制同时调用 API 的线程数。
    • retry_delay:重试间隔,默认 5 秒,API 调用失败后等待时间。
    • max_retries:最大重试次数,默认 3 次,API 调用失败后的重试上限。

python

运行

# 加载环境变量
load_dotenv()
  • 功能:调用load_dotenv()函数,加载当前目录下.env文件中的环境变量,存入系统环境变量字典。
  • 注意:若.env文件不存在,该函数无副作用,不会报错。

python

运行

# 从环境变量获取配置,如果没有传入则从环境变量读取
self.api_key = api_key or os.getenv("XIAOMI_API_KEY", "your_xiaomi_api_key_here")
self.base_url = base_url or os.getenv("XIAOMI_BASE_URL", "https://api.xiaomimimo.com/v1")
  • 功能:初始化 API 配置属性,实现「手动传入优先,环境变量次之,默认值兜底」的配置优先级。
  • 逻辑解析:
    • or 运算符:左侧为真则取左侧,否则取右侧(先判断是否手动传入api_key/base_url,无则读取环境变量)。
    • os.getenv(key, default):读取指定环境变量,不存在则返回默认值,避免None导致后续报错。
    • self.api_key:实例属性,存储小米 API 密钥,默认值为占位符。
    • self.base_url:实例属性,存储小米 API 基础 URL,默认值为小米 MiMo 接口地址。

python

运行

# 验证必要配置
if self.api_key == "your_xiaomi_api_key_here" or not self.api_key or self.api_key == "sk-cf3c9b4ioxd0e1wi6n5fi9ylk3nn2yuph0g7ta1j66xk7ssp":
    print("警告: 未设置有效的XIAOMI_API_KEY环境变量,请在.env文件中配置")
    self.use_offline_mode = True
else:
    self.use_offline_mode = False
    try:
        # 初始化OpenAI客户端
        self.client = OpenAI(
            api_key=self.api_key,
            base_url=self.base_url
        )
    except Exception as e:
        print(f"初始化API客户端失败: {str(e)},切换到离线模式")
        self.use_offline_mode = True
  • 功能:验证 API 密钥有效性,初始化 OpenAI 客户端,切换在线 / 离线模式。
  • 逐行逻辑:
    1. 条件判断:检查 API 密钥是否为默认占位符、空值,或测试密钥,若满足则判定为无效配置。
    2. self.use_offline_mode = True:实例属性,标记为离线模式,后续将使用本地规则生成内容,不调用远程 API。
    3. 反之,标记为在线模式(self.use_offline_mode = False),尝试初始化 OpenAI 客户端。
    4. self.client = OpenAI(...):创建 OpenAI 客户端实例,传入小米 API 密钥与基础 URL(小米大模型兼容 OpenAI 接口规范)。
    5. try...except:捕获客户端初始化过程中的异常(如网络错误、配置错误),捕获后切换为离线模式,保证程序不崩溃。

python

运行

# 从环境变量获取模型参数
self.model_name = os.getenv("MODEL_NAME", "mimo-v2-flash")
self.max_tokens = int(os.getenv("MAX_TOKENS", "1024"))
self.temperature = float(os.getenv("TEMPERATURE", "0.3"))
self.top_p = float(os.getenv("TOP_P", "0.95"))
  • 功能:初始化小米大模型的生成参数,均从环境变量读取,无则使用默认值。
  • 参数说明:
    • self.model_name:模型名称,默认mimo-v2-flash(小米轻量版大模型,兼顾速度与效果)。
    • self.max_tokens:生成内容的最大令牌数(近似字数),默认 1024,转换为整数类型。
    • self.temperature:生成随机性,默认 0.3(低随机性,保证法律内容的准确性与严谨性),转换为浮点型。
    • self.top_p:核采样参数,默认 0.95(控制生成内容的多样性,避免极端结果),转换为浮点型。

python

运行

# 并发和重试配置
self.max_concurrent = max_concurrent  # 最大并发数
self.retry_delay = retry_delay        # 重试间隔
self.max_retries = max_retries        # 最大重试次数
self.active_threads = 0               # 当前活跃线程数
self.thread_lock = threading.Lock()   # 线程锁
  • 功能:初始化并发与重试相关的实例属性,保证多线程调用 API 时的安全性与可控性。
  • 关键属性说明:
    • self.active_threads:统计当前正在运行的 API 调用线程数,初始值为 0。
    • self.thread_lock:创建线程锁实例,用于保护self.active_threads的修改操作,避免多线程竞争导致的数据不一致(线程安全)。

python

运行

# 创建工作目录
self.work_dir = Path("./legal_content_workflow").resolve()
self.cases_dir = self.work_dir / "cases"
self.temp_dir = self.work_dir / "temp"
self.audio_dir = self.work_dir / "audio"
self.video_dir = self.work_dir / "video"
self.output_dir = self.work_dir / "output"
self.wechat_dir = self.work_dir / "wechat_articles"
  • 功能:使用Path类创建工作目录及其子目录的路径对象,实现清晰的目录结构管理。
  • 逐行逻辑:
    • self.work_dir:根工作目录,Path("./legal_content_workflow")创建相对路径对象,.resolve()转换为绝对路径,避免路径歧义。
    • 后续子目录:使用/运算符拼接路径(Path类的便捷特性),分别对应案例文件、临时文件、音频、视频、输出结果、微信文章的存储目录。
  • 目录设计思路:按功能划分目录,方便用户查找与管理生成的内容,保持项目结构整洁。

python

运行

# 确保所有目录存在
directories = [self.work_dir, self.cases_dir, self.temp_dir, self.audio_dir, self.video_dir, self.output_dir, self.wechat_dir]
for directory in directories:
    directory.mkdir(parents=True, exist_ok=True)
  • 功能:遍历所有目录路径,创建不存在的目录,保证后续文件操作不会因目录不存在而报错。
  • 方法说明:
    • directory.mkdir():创建目录。
    • parents=True:递归创建父目录(若legal_content_workflow不存在,会自动创建)。
    • exist_ok=True:若目录已存在,不抛出异常,避免重复创建导致的错误。

四、并发控制方法:wait_for_slot 与 release_slot(第 70-83 行)

python

运行

def wait_for_slot(self):
    """等待并发槽位"""
    while True:
        with self.thread_lock:
            if self.active_threads < self.max_concurrent:
                self.active_threads += 1
                break
        time.sleep(0.5)
  • 功能:等待可用的并发槽位,控制同时调用 API 的线程数不超过max_concurrent,避免触发 API 限流。
  • 逐行逻辑:
    1. while True:无限循环,直到获取到可用槽位。
    2. with self.thread_lock:上下文管理器,自动获取与释放线程锁,保证self.active_threads的修改是原子操作(多线程安全)。
    3. 条件判断:若当前活跃线程数小于最大并发数,说明有可用槽位。
    4. self.active_threads += 1:活跃线程数加 1,标记该槽位已被占用。
    5. break:退出循环,继续执行后续 API 调用。
    6. time.sleep(0.5):若无可用槽位,等待 0.5 秒后再次尝试,避免 CPU 空转。

python

运行

def release_slot(self):
    """释放并发槽位"""
    with self.thread_lock:
        self.active_threads -= 1
  • 功能:API 调用完成(成功或失败)后,释放占用的并发槽位,让其他线程可以获取槽位进行 API 调用。
  • 逻辑解析:通过线程锁保护self.active_threads的减 1 操作,确保线程安全,避免数据混乱。

五、带重试机制的 API 调用:call_xiaomi_api_with_retry(第 85-156 行)

python

运行

def call_xiaomi_api_with_retry(self, prompt, max_tokens=None, temperature=None, top_p=None):
    """带重试机制的API调用"""
    tokens = max_tokens or self.max_tokens
    temp = temperature or self.temperature
    p = top_p or self.top_p
  • 功能:封装小米 API 调用,实现自动重试、并发控制,返回 AI 生成的内容。
  • 入参说明:
    • prompt:用户提示词,传递给 AI 模型的生成指令。
    • max_tokens/temperature/top_p:可选,覆盖实例默认的模型参数,实现个性化生成。
  • 逻辑解析:初始化生成参数,优先使用传入的参数,无则使用实例默认参数。

python

运行

for attempt in range(self.max_retries + 1):
  • 功能:循环执行 API 调用,最多尝试max_retries + 1次(包含首次调用与max_retries次重试)。

python

运行

try:
    # 检查是否达到最大并发限制
    self.wait_for_slot()
  • 功能:进入内层异常捕获块,先调用wait_for_slot()获取可用并发槽位,再执行 API 调用。

python

运行

try:
    completion = self.client.chat.completions.create(
        model=self.model_name,
        messages=[
            {
                "role": "system",
                "content": "You are MiMo, an AI assistant developed by Xiaomi. You are a legal expert specialized in analyzing Chinese legal cases and creating educational content. Please provide clear, accurate, and professional analysis."
            },
            {
                "role": "user",
                "content": prompt
            }
        ],
        max_completion_tokens=tokens,
        temperature=temp,
        top_p=p,
        stream=False,
        stop=None,
        frequency_penalty=0,
        presence_penalty=0,
        extra_body={
            "thinking": {"type": "disabled"}
        }
    )
  • 功能:调用 OpenAI 客户端的chat.completions.create()方法,发送请求到小米大模型 API,获取生成结果。
  • 关键参数解析:
    1. model:指定使用的模型名称(self.model_name)。
    2. messages:消息列表,包含系统角色与用户角色:
      • system:系统提示,定义 AI 的人设(小米 MiMo、法律专家),规范生成内容的风格与专业性。
      • user:用户提示,传递具体的生成任务(如案例分析、脚本生成)。
    3. max_completion_tokens:生成内容的最大令牌数,控制内容长度。
    4. temperature/top_p:生成随机性与多样性参数,保证法律内容的严谨性。
    5. stream=False:关闭流式返回,等待完整结果后再返回。
    6. extra_body:小米大模型扩展参数,禁用思考过程,提升生成速度。

python

运行

# 提取返回的内容
content = completion.choices[0].message.content
result = content.strip()

# 释放并发槽位
self.release_slot()
return result
  • 功能:提取 API 返回的核心内容,释放并发槽位,返回清理后的结果。
  • 逻辑解析:
    1. completion.choices[0].message.content:获取第一个生成结果的文本内容(OpenAI 接口返回格式)。
    2. content.strip():去除首尾空白字符,清理结果。
    3. 调用release_slot()释放槽位,返回结果。

python

运行

except Exception as e:
    # 释放并发槽位
    self.release_slot()
    
    error_msg = str(e).lower()
    if "rate limit" in error_msg or "concurrent" in error_msg or "too many requests" in error_msg:
        print(f"速率限制错误,等待 {self.retry_delay}s 后重试... (尝试 {attempt + 1}/{self.max_retries + 1})")
        if attempt < self.max_retries:
            time.sleep(self.retry_delay)
            continue
    raise e
  • 功能:捕获 API 调用过程中的异常,处理限流错误,释放槽位,决定是否重试。
  • 逐行逻辑:
    1. 捕获异常后,首先调用release_slot()释放并发槽位(避免槽位被永久占用)。
    2. error_msg = str(e).lower():将错误信息转为小写,方便匹配关键词。
    3. 匹配限流相关关键词(速率限制、并发限制、请求过多),若为限流错误:
      • 打印重试提示,若未达到最大重试次数,等待retry_delay秒后,continue进入下一次循环重试。
    4. 若非限流错误,直接raise e抛出异常,终止当前重试循环,进入外层异常捕获块。

python

运行

except Exception as e:
    if attempt < self.max_retries:
        print(f"API调用失败,等待 {self.retry_delay}s 后重试... (尝试 {attempt + 1}/{self.max_retries + 1})")
        time.sleep(self.retry_delay)
    else:
        print(f"API调用最终失败: {str(e)}")
        return self.simulate_api_response(prompt)
  • 功能:捕获外层异常(如槽位获取失败、非限流类 API 错误),实现通用重试逻辑。
  • 逻辑解析:
    1. 若未达到最大重试次数,打印提示,等待后重试。
    2. 若已达到最大重试次数,打印最终失败提示,调用simulate_api_response()返回模拟结果,保证程序继续运行。

python

运行

return self.simulate_api_response(prompt)
  • 功能:所有重试均失败后,返回模拟 API 响应,兜底保障程序不中断。

六、模拟 API 响应:simulate_api_response(第 158-206 行)

python

运行

def simulate_api_response(self, prompt):
    """模拟API响应"""
    print("使用离线模式处理...")
  • 功能:离线模式下,根据提示词类型返回对应的模拟内容,避免因 API 不可用导致程序崩溃。
  • 设计思路:按提示词关键词匹配任务类型(案例分析、视频脚本、微信文章),返回结构化的模拟结果,保持与在线 API 返回格式的一致性。

python

运行

# 根据提示类型返回不同的模拟响应
if "分析以下法律案例" in prompt or ("标题" in prompt and "当事人" in prompt):
    # 模拟案例分析
    ...
elif "生成一个适合短视频的解说脚本" in prompt or ("开场" in prompt and "案情介绍" in prompt):
    # 模拟视频脚本生成
    ...
elif "为微信公众号生成一篇普法文章" in prompt or "微信普法文章" in prompt:
    # 模拟微信普法文章生成
    ...
else:
    # 通用模拟响应
    ...
  • 功能:通过关键词匹配提示词类型,分发到对应的模拟结果生成逻辑。
  • 逻辑解析:针对不同的任务类型,返回符合格式要求的模拟内容,保证后续处理流程(如 JSON 解析、脚本保存)可以正常执行。

七、核心业务方法(案例分析 / 脚本生成 / 文章创作)

1. 法律案例分析:analyze_legal_case(第 208-252 行)

python

运行

def analyze_legal_case(self, case_text):
    """使用小米API分析法律案例"""
    prompt = f"""
    请仔细分析以下法律案例,并提取以下关键信息:
    1. 案例标题
    2. 当事人信息(原告、被告等)
    3. 案件基本事实
    4. 主要争议焦点
    5. 法院判决结果
    6. 适用的法律条文
    
    案例原文:
    {case_text}
    
    请按照JSON格式返回分析结果:
    ...
    """
  • 功能:构造案例分析的提示词,调用 API 获取分析结果,解析 JSON 并返回结构化数据。
  • 设计思路:通过详细的提示词规范 AI 的返回格式(JSON),方便后续解析与使用,提升结果的结构化程度。

python

运行

result = self.call_xiaomi_api_with_retry(prompt, max_tokens=1500)
  • 功能:调用带重试机制的 API 方法,获取案例分析结果,最大令牌数设为 1500(足够容纳详细的分析内容)。

python

运行

# 提取JSON部分
json_match = re.search(r'\{.*\}', result, re.DOTALL)
if json_match:
    json_str = json_match.group()
    return json.loads(json_str)
  • 功能:使用正则表达式从 API 返回结果中提取 JSON 字符串,解析为 Python 字典并返回。
  • 关键参数:re.DOTALL.匹配包括换行符在内的所有字符,保证完整提取多行 JSON。

python

运行

except json.JSONDecodeError:
    # 解析失败,返回兜底结构
    ...
else:
    # 调用本地规则分析
    return self.local_analyze_case(case_text)
  • 功能:异常处理与兜底,JSON 解析失败时返回默认结构,API 调用失败时调用local_analyze_case()使用本地规则分析案例。

2. 本地案例分析:local_analyze_case(第 254-316 行)

python

运行

def local_analyze_case(self, case_text):
    """使用本地规则分析案例"""
    # 使用正则表达式提取案例信息
    title_match = re.search(r'(判决书|裁定书|案例).*?$', case_text.split('\n')[0] if case_text.split('\n') else ['案例'])
    title = title_match.group() if title_match else "法律案例分析"
  • 功能:离线模式下,使用本地正则表达式与关键词匹配,提取案例关键信息,返回结构化结果。
  • 设计思路:针对中文法律文书的固定格式,使用关键词(如「经审理查明」「争议焦点」)与正则表达式,提取核心信息,保证离线模式的可用性。

3. 视频脚本生成:generate_video_script(第 318-352 行)

4. 微信文章生成:generate_wechat_article(第 374-408 行)

  • 核心逻辑与analyze_legal_case一致:
    1. 构造针对性的提示词,规范生成格式(如短视频脚本的分场景结构、微信文章的分段结构)。
    2. 调用带重试机制的 API 方法,获取生成结果。
    3. API 调用失败时,调用对应的本地生成方法(local_generate_script/local_generate_article),返回兜底内容。
  • 设计亮点:生成结果符合短视频 / 微信公众号的传播特性,语言通俗易懂,结构清晰,兼顾专业性与可读性。

八、辅助方法(文件操作 / 语音合成 / 视频制作)

1. 文件读取与保存:read_case_from_file /save_case_to_file(第 458-498 行)

  • 功能:读取案例文件(支持 UTF-8 与 GBK 编码,解决中文乱码问题),保存案例内容到指定目录。
  • 亮点:自动适配文件编码,避免中文法律文书读取时出现乱码;生成唯一时间戳文件名,避免文件覆盖。

2. 模拟语音合成与视频制作:convert_to_speech /create_video_with_scenes(第 410-456 行)

  • 功能:模拟文字转语音(保存语音脚本),分割视频脚本为场景,生成视频制作指令(JSON 格式)。
  • 设计思路:本代码为框架实现,实际应用中可集成 TTS 服务(如百度语音、阿里云语音)与视频编辑库(如moviepy),替换模拟实现,实现真正的语音合成与视频生成。

九、批量处理方法:process_single_case /batch_process_all_cases(第 500-598 行)

1. 处理单个案例:process_single_case(第 500-572 行)

  • 功能:串联「读取案例→分析案例→生成脚本→生成文章→语音合成→视频制作」的完整流程,处理单个案例文件,返回处理结果。
  • 亮点:步骤清晰,每一步都有异常处理与状态反馈,生成的文件按功能分类存储,方便后续管理。

2. 批量处理所有案例:batch_process_all_cases(第 574-598 行)

  • 功能:递归查找所有案例文件,批量处理,生成处理报告(JSON 格式),统计成功 / 失败数量。
  • 亮点:
    1. 生成详细的批量处理报告,方便用户追溯处理结果。
    2. 案例间添加 2 秒延迟,避免触发 API 限流。
    3. 统计成功与失败数量,提供清晰的处理总结。

十、辅助函数与程序入口(第 600-680 行)

1. 环境配置:setup_environment(第 600-622 行)

  • 功能:创建.env配置文件(若不存在),填充默认配置,提醒用户替换 API 密钥。

2. 依赖检查:check_dependencies(第 624-644 行)

  • 功能:检查必要的依赖包(openaipython-dotenv)是否安装,缺失则提示用户安装。

3. 主函数:main(第 646-680 行)

  • 功能:程序入口,串联「检查依赖→创建环境配置→初始化生成器→创建示例案例→批量处理案例」的完整流程。
  • 亮点:若未找到案例文件,自动创建示例案例,方便用户快速测试程序功能,降低使用门槛。

python

运行

if __name__ == "__main__":
    main()
  • 功能:Python 程序入口判断,直接运行该脚本时执行main()函数,作为模块导入时不执行,保证代码的可复用性。

总结

  1. 核心流程环境准备→案例读取→AI分析→内容生成→文件保存→批量报告,逻辑闭环,功能完整,兼顾在线与离线模式。
  2. 设计亮点
    • 并发控制与重试机制,提升 API 调用的稳定性与效率。
    • 结构化提示词设计,保证 AI 生成结果的规范性。
    • 完善的异常处理与兜底方案,程序鲁棒性强。
    • 清晰的目录结构与文件管理,方便用户使用与扩展。

——————————————————————————————

完整代码

import os
import json
import time
from datetime import datetime
from pathlib import Path
import re
from openai import OpenAI
from dotenv import load_dotenv
import random
import threading
from queue import Queue
import requests

class LegalContentGenerator:
    def __init__(self, api_key=None, base_url=None, max_concurrent=3, retry_delay=5, max_retries=3):
        # 加载环境变量
        load_dotenv()
        
        # 从环境变量获取配置,如果没有传入则从环境变量读取
        self.api_key = api_key or os.getenv("XIAOMI_API_KEY", "your_xiaomi_api_key_here")
        self.base_url = base_url or os.getenv("XIAOMI_BASE_URL", "https://api.xiaomimimo.com/v1")
        
        # 验证必要配置
        if self.api_key == "your_xiaomi_api_key_here" or not self.api_key or self.api_key == "sk-cf3c9b4ioxd0e1wi6n5fi9ylk3nn2yuph0g7ta1j66xk7ssp":
            print("警告: 未设置有效的XIAOMI_API_KEY环境变量,请在.env文件中配置")
            self.use_offline_mode = True
        else:
            self.use_offline_mode = False
            try:
                # 初始化OpenAI客户端
                self.client = OpenAI(
                    api_key=self.api_key,
                    base_url=self.base_url
                )
            except Exception as e:
                print(f"初始化API客户端失败: {str(e)},切换到离线模式")
                self.use_offline_mode = True
        
        # 从环境变量获取模型参数
        self.model_name = os.getenv("MODEL_NAME", "mimo-v2-flash")
        self.max_tokens = int(os.getenv("MAX_TOKENS", "1024"))
        self.temperature = float(os.getenv("TEMPERATURE", "0.3"))
        self.top_p = float(os.getenv("TOP_P", "0.95"))
        
        # 并发和重试配置
        self.max_concurrent = max_concurrent  # 最大并发数
        self.retry_delay = retry_delay        # 重试间隔
        self.max_retries = max_retries        # 最大重试次数
        self.active_threads = 0               # 当前活跃线程数
        self.thread_lock = threading.Lock()   # 线程锁
        
        # 创建工作目录
        self.work_dir = Path("./legal_content_workflow").resolve()
        self.cases_dir = self.work_dir / "cases"
        self.temp_dir = self.work_dir / "temp"
        self.audio_dir = self.work_dir / "audio"
        self.video_dir = self.work_dir / "video"
        self.output_dir = self.work_dir / "output"
        self.wechat_dir = self.work_dir / "wechat_articles"
        
        # 确保所有目录存在
        directories = [self.work_dir, self.cases_dir, self.temp_dir, self.audio_dir, self.video_dir, self.output_dir, self.wechat_dir]
        for directory in directories:
            directory.mkdir(parents=True, exist_ok=True)

    def wait_for_slot(self):
        """等待并发槽位"""
        while True:
            with self.thread_lock:
                if self.active_threads < self.max_concurrent:
                    self.active_threads += 1
                    break
            time.sleep(0.5)

    def release_slot(self):
        """释放并发槽位"""
        with self.thread_lock:
            self.active_threads -= 1

    def call_xiaomi_api_with_retry(self, prompt, max_tokens=None, temperature=None, top_p=None):
        """带重试机制的API调用"""
        tokens = max_tokens or self.max_tokens
        temp = temperature or self.temperature
        p = top_p or self.top_p
        
        for attempt in range(self.max_retries + 1):
            try:
                # 检查是否达到最大并发限制
                self.wait_for_slot()
                
                try:
                    completion = self.client.chat.completions.create(
                        model=self.model_name,
                        messages=[
                            {
                                "role": "system",
                                "content": "You are MiMo, an AI assistant developed by Xiaomi. You are a legal expert specialized in analyzing Chinese legal cases and creating educational content. Please provide clear, accurate, and professional analysis."
                            },
                            {
                                "role": "user",
                                "content": prompt
                            }
                        ],
                        max_completion_tokens=tokens,
                        temperature=temp,
                        top_p=p,
                        stream=False,
                        stop=None,
                        frequency_penalty=0,
                        presence_penalty=0,
                        extra_body={
                            "thinking": {"type": "disabled"}
                        }
                    )
                    
                    # 提取返回的内容
                    content = completion.choices[0].message.content
                    result = content.strip()
                    
                    # 释放并发槽位
                    self.release_slot()
                    return result
                    
                except Exception as e:
                    # 释放并发槽位
                    self.release_slot()
                    
                    error_msg = str(e).lower()
                    if "rate limit" in error_msg or "concurrent" in error_msg or "too many requests" in error_msg:
                        print(f"速率限制错误,等待 {self.retry_delay}s 后重试... (尝试 {attempt + 1}/{self.max_retries + 1})")
                        if attempt < self.max_retries:
                            time.sleep(self.retry_delay)
                            continue
                    raise e
                    
            except Exception as e:
                if attempt < self.max_retries:
                    print(f"API调用失败,等待 {self.retry_delay}s 后重试... (尝试 {attempt + 1}/{self.max_retries + 1})")
                    time.sleep(self.retry_delay)
                else:
                    print(f"API调用最终失败: {str(e)}")
                    return self.simulate_api_response(prompt)
        
        return self.simulate_api_response(prompt)

    def simulate_api_response(self, prompt):
        """模拟API响应"""
        print("使用离线模式处理...")
        
        # 根据提示类型返回不同的模拟响应
        if "分析以下法律案例" in prompt or ("标题" in prompt and "当事人" in prompt):
            # 模拟案例分析
            case_text = prompt.split("案例原文:")[1] if "案例原文:" in prompt else prompt
            title = "模拟案例分析结果"
            parties = "原告: 未知, 被告: 未知"
            facts = case_text[:300] + "..." if len(case_text) > 300 else case_text
            dispute_points = "争议焦点: 合同履行问题"
            ruling = "法院判决: 支持原告部分诉讼请求"
            legal_basis = "法律依据: 《民法典》相关条款"
            
            return f"""{{
  "title": "{title}",
  "parties": "{parties}",
  "facts": "{facts}",
  "dispute_points": "{dispute_points}",
  "ruling": "{ruling}",
  "legal_basis": "{legal_basis}"
}}"""
        elif "生成一个适合短视频的解说脚本" in prompt or ("开场" in prompt and "案情介绍" in prompt):
            # 模拟视频脚本生成
            return """【开场】
大家好,今天为大家解读一个重要的法律案例。
【案情介绍】
本案涉及合同纠纷,具体情况是...
【争议焦点】
案件的核心争议在于...
【法院判决】
最终法院认定...
【法条解读】
相关法律条文规定...
【结语】
这个案例提醒我们..."""
        elif "为微信公众号生成一篇普法文章,人设是中年女律师,高智慧高情商" in prompt or "微信普法文章" in prompt:
            # 模拟微信普法文章生成
            return """# 微信普法 | 重要法律案例解读

## 案例背景
今日为您解读一起重要法律案例...

## 争议焦点
案件核心争议在于...

## 专业分析
作为专业律师,我们认为...

## 法律启示
此案例提醒大家注意...

*本文由专业律师团队撰写,仅供参考*"""
        else:
            # 通用模拟响应
            return f"模拟API响应:由于离线模式,返回基于'{prompt[:50]}...'的分析结果"

    def analyze_legal_case(self, case_text):
        """使用小米API分析法律案例"""
        prompt = f"""
        请仔细分析以下法律案例,并提取以下关键信息:
        1. 案例标题
        2. 当事人信息(原告、被告等)
        3. 案件基本事实
        4. 主要争议焦点
        5. 法院判决结果
        6. 适用的法律条文
        
        案例原文:
        {case_text}
        
        请按照JSON格式返回分析结果:
        {{
          "title": "...",
          "parties": "...",
          "facts": "...",
          "dispute_points": "...",
          "ruling": "...",
          "legal_basis": "..."
        }}
        """
        
        result = self.call_xiaomi_api_with_retry(prompt, max_tokens=1500)
        if result and not result.startswith("API调用失败") and not result.startswith("模拟API响应"):
            try:
                # 提取JSON部分
                json_match = re.search(r'\{.*\}', result, re.DOTALL)
                if json_match:
                    json_str = json_match.group()
                    return json.loads(json_str)
                else:
                    # 如果无法提取JSON,返回模拟结构
                    return {
                        "title": "案例分析结果",
                        "parties": "当事人信息分析中",
                        "facts": result[:500],
                        "dispute_points": "争议焦点分析中",
                        "ruling": "判决结果分析中",
                        "legal_basis": "法律依据分析中"
                    }
            except json.JSONDecodeError:
                print("JSON解析失败,使用文本分析结果")
                return {
                    "title": "案例分析结果",
                    "parties": "分析结果",
                    "facts": result[:500],
                    "dispute_points": "争议焦点待分析",
                    "ruling": "判决结果待分析",
                    "legal_basis": "法律依据待分析"
                }
        else:
            # 使用本地规则分析
            print("使用本地规则分析案例...")
            return self.local_analyze_case(case_text)

    def local_analyze_case(self, case_text):
        """使用本地规则分析案例"""
        # 使用正则表达式提取案例信息
        title_match = re.search(r'(判决书|裁定书|案例).*?$', case_text.split('\n')[0] if case_text.split('\n') else ['案例'])
        title = title_match.group() if title_match else "法律案例分析"
        
        # 查找当事人信息
        parties = "当事人信息待提取"
        parties_patterns = [
            r'原告.*?与.*?被告',
            r'申请人.*?与.*?被申请人',
            r'上诉人.*?与.*?被上诉人'
        ]
        for pattern in parties_patterns:
            match = re.search(pattern, case_text, re.IGNORECASE)
            if match:
                parties = match.group()
                break
        
        # 提取案件事实
        facts_keywords = ['经审理查明', '事实如下', '查明事实', '案件事实']
        facts = "案件事实待提取"
        for keyword in facts_keywords:
            if keyword in case_text:
                start_pos = case_text.find(keyword) + len(keyword)
                end_pos = case_text.find('\n\n', start_pos)
                if end_pos == -1:
                    end_pos = start_pos + 500  # 默认取500字符
                facts = case_text[start_pos:end_pos].strip()
                break
        
        # 提取争议焦点
        dispute_keywords = ['争议焦点', '争议问题', '争议所在']
        dispute_points = "争议焦点待提取"
        for keyword in dispute_keywords:
            if keyword in case_text:
                start_pos = case_text.find(keyword) + len(keyword)
                end_pos = case_text.find('\n\n', start_pos)
                if end_pos == -1:
                    end_pos = start_pos + 300  # 默认取300字符
                dispute_points = case_text[start_pos:end_pos].strip()
                break
        
        # 提取判决结果
        ruling_keywords = ['判决如下', '裁定如下', '法院认为', '法院判决']
        ruling = "判决结果待提取"
        for keyword in ruling_keywords:
            if keyword in case_text:
                start_pos = case_text.find(keyword) + len(keyword)
                end_pos = case_text.find('\n\n', start_pos)
                if end_pos == -1:
                    end_pos = start_pos + 300  # 默认取300字符
                ruling = case_text[start_pos:end_pos].strip()
                break
        
        # 提取法律依据
        legal_basis = "法律依据待提取"
        legal_patterns = [
            r'《.*?》第.*?条',
            r'根据.*?规定',
            r'依据.*?法律'
        ]
        for pattern in legal_patterns:
            matches = re.findall(pattern, case_text)
            if matches:
                legal_basis = ', '.join(matches[:5])  # 最多取5个
                break
        
        return {
            "title": title,
            "parties": parties,
            "facts": facts,
            "dispute_points": dispute_points,
            "ruling": ruling,
            "legal_basis": legal_basis
        }

    def generate_video_script(self, analysis_result):
        """生成视频解说脚本"""
        prompt = f"""
        基于以下法律案例分析结果,生成一个适合短视频的解说脚本。
        要求:
        1. 语言通俗易懂,适合普通观众
        2. 结构清晰,分为开场、案情介绍、争议焦点、法院判决、法条解读、结语
        3. 总长度控制在2-3分钟(约300-500字)
        4. 突出重点,便于配合画面展示
        
        分析结果:
        标题:{analysis_result.get('title', '')}
        当事人:{analysis_result.get('parties', '')}
        事实:{analysis_result.get('facts', '')}
        争议焦点:{analysis_result.get('dispute_points', '')}
        判决:{analysis_result.get('ruling', '')}
        法律依据:{analysis_result.get('legal_basis', '')}
        
        返回格式:
        【开场】
        ...
        【案情介绍】
        ...
        【争议焦点】
        ...
        【法院判决】
        ...
        【法条解读】
        ...
        【结语】
        ...
        """
        
        script = self.call_xiaomi_api_with_retry(prompt, max_tokens=1000)
        if script and not script.startswith("视频脚本生成失败") and not script.startswith("模拟API响应"):
            return script
        else:
            # 使用本地规则生成脚本
            print("使用本地规则生成视频脚本...")
            return self.local_generate_script(analysis_result)

    def local_generate_script(self, analysis_result):
        """使用本地规则生成视频脚本"""
        title = analysis_result.get('title', '法律案例解读')
        parties = analysis_result.get('parties', '当事人信息')
        facts = analysis_result.get('facts', '案件事实')
        disputes = analysis_result.get('dispute_points', '争议焦点')
        ruling = analysis_result.get('ruling', '判决结果')
        basis = analysis_result.get('legal_basis', '法律依据')
        
        script = f"""【开场】
大家好,今天为您解读一起重要的法律案例——《{title}》。

【案情介绍】
本案涉及{parties}。案件的基本情况是:{facts[:200]}...

【争议焦点】
案件的核心争议在于:{disputes}

【法院判决】
法院最终认定:{ruling[:150]}...

【法条解读】
相关法律依据是:{basis}

【结语】
通过这个案例,我们可以了解到...希望对您有所帮助!"""
        
        return script

    def generate_wechat_article(self, analysis_result):
        """生成微信普法文章"""
        prompt = f"""
        基于以下法律案例分析结果,为微信公众号生成一篇专业的普法文章。
        要求:
        1. 文章标题吸引人,突出争议焦点
        2. 内容专业但通俗易懂
        3. 重点突出争议焦点和法律分析
        4. 体现律师专业性
        5. 结构清晰,适合手机阅读
        6. 总长度控制在800-1200字
        
        分析结果:
        标题:{analysis_result.get('title', '')}
        当事人:{analysis_result.get('parties', '')}
        事实:{analysis_result.get('facts', '')}
        争议焦点:{analysis_result.get('dispute_points', '')}
        判断:{analysis_result.get('ruling', '')}
        法律依据:{analysis_result.get('legal_basis', '')}
        
        返回格式:
        # 文章标题
        ## 案例背景
        ...
        ## 争议焦点
        ...
        ## 专业分析
        ...
        ## 法律启示
        ...
        *本文由专业律师团队撰写,仅供参考*
        """
        
        article = self.call_xiaomi_api_with_retry(prompt, max_tokens=1500)
        if article and not article.startswith("微信文章生成失败") and not article.startswith("模拟API响应"):
            return article
        else:
            # 使用本地规则生成文章
            print("使用本地规则生成微信普法文章...")
            return self.local_generate_article(analysis_result)

    def local_generate_article(self, analysis_result):
        """使用本地规则生成微信普法文章"""
        title = analysis_result.get('title', '法律案例解读')
        parties = analysis_result.get('parties', '当事人信息')
        facts = analysis_result.get('facts', '案件事实')
        disputes = analysis_result.get('dispute_points', '争议焦点')
        ruling = analysis_result.get('ruling', '判决结果')
        basis = analysis_result.get('legal_basis', '法律依据')
        
        article = f"""# 【以案说法】{title}

## 案例背景
近日,我们关注到一起涉及{parties}的重要法律案例。案件基本情况如下:{facts[:300]}...

## 争议焦点
本案的核心争议在于:{disputes}。这一争议点涉及到法律适用的关键问题,值得我们深入分析。

## 专业分析
作为专业律师,我们对此案例进行如下分析:

1. **法律关系认定**:根据{basis},本案中的法律关系明确...

2. **争议焦点剖析**:{disputes}的实质在于...

3. **判决合理性**:{ruling}体现了法律对此类问题的处理原则...

4. **实务启示**:此类案件提醒我们在实践中应注意...

## 法律启示
此案例具有重要的实践意义,特别是对于{parties}而言,提醒我们在类似情况下应当...

*本文由专业律师团队撰写,仅供参考。如需专业法律咨询,请联系执业律师。*"""
        
        return article

    def convert_to_speech(self, text, output_path):
        """模拟文字转语音(实际应用中应使用TTS服务)"""
        # 这里简化处理,保存文本作为语音脚本
        with open(output_path, 'w', encoding='utf-8') as f:
            f.write(text)
        print(f"语音脚本已保存至: {output_path}")

    def create_video_with_scenes(self, script, output_path):
        """创建分场景的视频脚本"""
        # 分割脚本为不同场景
        scenes = script.split('【')
        scene_descriptions = []
        
        for i, scene in enumerate(scenes):
            if scene.strip():
                scene_name = scene.split('】')[0] if '】' in scene else f"场景{i+1}"
                scene_content = scene.split('】')[1] if '】' in scene else scene
                
                scene_info = {
                    "scene_number": i,
                    "scene_name": scene_name,
                    "content": scene_content.strip(),
                    "duration": min(len(scene_content) // 10, 30)  # 估计时长
                }
                scene_descriptions.append(scene_info)
        
        # 生成视频制作说明
        video_instructions = {
            "title": "法律案例解读视频",
            "scenes": scene_descriptions,
            "total_duration": sum(s['duration'] for s in scene_descriptions),
            "bg_music": True,
            "font_size": "medium",
            "color_scheme": "professional"
        }
        
        # 保存视频制作指令
        instruction_file = output_path.with_suffix('.json')
        with open(instruction_file, 'w', encoding='utf-8') as f:
            json.dump(video_instructions, f, ensure_ascii=False, indent=2)
        
        print(f"视频制作指令已保存至: {instruction_file}")
        
        # 模拟生成视频文件
        with open(output_path, 'wb') as f:
            f.write(b"dummy_video_file")  # 模拟视频内容
        
        return str(output_path)

    def read_case_from_file(self, file_path):
        """从文件读取法律案例"""
        file_path = Path(file_path)
        if not file_path.exists():
            print(f"错误: 文件不存在 - {file_path}")
            return None
            
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
            print(f"成功读取案例文件: {file_path}")
            return content
        except UnicodeDecodeError:
            # 如果UTF-8解码失败,尝试其他编码
            try:
                with open(file_path, 'r', encoding='gbk') as f:
                    content = f.read()
                print(f"成功读取案例文件: {file_path} (使用GBK编码)")
                return content
            except UnicodeDecodeError:
                print(f"错误: 无法解码文件 - {file_path}")
                return None
        except Exception as e:
            print(f"读取文件时发生错误: {str(e)}")
            return None

    def save_case_to_file(self, case_content, filename=None):
        """保存案例到文件"""
        if filename is None:
            timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
            filename = f"case_{timestamp}.txt"
        
        file_path = self.cases_dir / filename
        with open(file_path, 'w', encoding='utf-8') as f:
            f.write(case_content)
        print(f"案例已保存到: {file_path}")
        return str(file_path)

    def list_available_cases(self):
        """递归列出cases文件夹及子文件夹下的所有案例文件"""
        case_files = []
        for root, dirs, files in os.walk(self.cases_dir):
            for file in files:
                if file.lower().endswith(('.txt', '.md')):
                    file_path = Path(root) / file
                    case_files.append(file_path)
        
        if not case_files:
            print("未找到案例文件")
            return []
        
        print(f"找到 {len(case_files)} 个案例文件:")
        for i, file_path in enumerate(case_files, 1):
            # 计算相对于cases_dir的路径
            rel_path = file_path.relative_to(self.cases_dir)
            print(f"  {i}. {rel_path} ({file_path.stat().st_size} 字节)")
        return case_files

    def process_single_case(self, case_file):
        """处理单个案例文件"""
        try:
            print(f"开始处理案例: {case_file}")
            
            # 读取案例内容
            case_text = self.read_case_from_file(case_file)
            if case_text is None:
                print(f"无法读取案例文件: {case_file}")
                return {
                    "case_file": str(case_file),
                    "result": None,
                    "status": "failed",
                    "error": "无法读取文件"
                }
            
            # 使用文件名作为标题前缀
            title_prefix = case_file.stem.replace(' ', '_')
            
            # 步骤1: 分析法律案例
            print(f"[{title_prefix}] 步骤1: 正在分析法律案例...")
            analysis = self.analyze_legal_case(case_text)
            if not analysis:
                print(f"[{title_prefix}] 案例分析失败")
                return {
                    "case_file": str(case_file),
                    "result": None,
                    "status": "failed",
                    "error": "案例分析失败"
                }
            
            print(f"[{title_prefix}] 案例分析完成")
            
            # 步骤2: 生成视频脚本
            print(f"[{title_prefix}] 步骤2: 正在生成视频脚本...")
            script = self.generate_video_script(analysis)
            if not script or script.startswith("视频脚本生成失败"):
                print(f"[{title_prefix}] 视频脚本生成失败")
                return {
                    "case_file": str(case_file),
                    "result": None,
                    "status": "failed",
                    "error": "视频脚本生成失败"
                }
                
            script_path = self.temp_dir / f"{title_prefix}_video_script.txt"
            with open(script_path, 'w', encoding='utf-8') as f:
                f.write(script)
            print(f"[{title_prefix}] 视频脚本生成完成")
            
            # 步骤3: 生成微信普法文章
            print(f"[{title_prefix}] 步骤3: 正在生成微信普法文章...")
            article = self.generate_wechat_article(analysis)
            if not article or article.startswith("微信文章生成失败"):
                print(f"[{title_prefix}] 微信文章生成失败")
                return {
                    "case_file": str(case_file),
                    "result": None,
                    "status": "failed",
                    "error": "微信文章生成失败"
                }
                
            article_path = self.wechat_dir / f"{title_prefix}_wechat_article.md"
            with open(article_path, 'w', encoding='utf-8') as f:
                f.write(article)
            print(f"[{title_prefix}] 微信普法文章生成完成")
            
            # 步骤4: 语音合成
            print(f"[{title_prefix}] 步骤4: 正在生成语音...")
            speech_path = self.audio_dir / f"{title_prefix}_speech.txt"
            self.convert_to_speech(script, speech_path)
            print(f"[{title_prefix}] 语音生成完成")
            
            # 步骤5: 创建视频制作指令
            print(f"[{title_prefix}] 步骤5: 正在创建视频制作指令...")
            timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
            video_output_path = self.output_dir / f"{title_prefix}_{timestamp}.mp4"
            final_video = self.create_video_with_scenes(script, video_output_path)
            
            print(f"[{title_prefix}] 视频制作指令生成完成: {final_video}")
            
            # 返回处理结果
            result = {
                "video_path": final_video,
                "script_path": str(script_path),
                "article_path": str(article_path),
                "speech_path": str(speech_path),
                "analysis": analysis,
                "processing_time": time.time()
            }
            
            return {
                "case_file": str(case_file),
                "result": result,
                "status": "success",
                "error": None
            }
            
        except Exception as e:
            print(f"处理案例 {case_file} 时发生错误: {str(e)}")
            return {
                "case_file": str(case_file),
                "result": None,
                "status": "failed",
                "error": str(e)
            }

    def batch_process_all_cases(self):
        """批量处理所有案例文件"""
        print("开始批量处理所有案例文件...")
        
        case_files = self.list_available_cases()
        if not case_files:
            print("未找到任何案例文件,无法批量处理")
            return []
        
        results = []
        completed = 0
        failed = 0
        
        for i, case_file in enumerate(case_files, 1):
            print(f"\n--- 处理第 {i}/{len(case_files)} 个案例 ---")
            # 计算相对于cases_dir的路径作为显示名
            rel_path = case_file.relative_to(self.cases_dir)
            print(f"案例文件: {rel_path}")
            
            # 处理单个案例
            result = self.process_single_case(case_file)
            results.append(result)
            
            if result['status'] == 'success':
                completed += 1
                print(f"✓ 成功处理: {rel_path}")
            else:
                failed += 1
                print(f"✗ 失败处理: {rel_path}, 错误: {result['error']}")
            
            # 添加延迟以避免API限制
            if i < len(case_files):
                print("等待2秒后继续处理下一个案例...")
                time.sleep(2)
        
        # 生成批量处理报告
        report_path = self.output_dir / f"batch_processing_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
        report = {
            "batch_start_time": datetime.now().isoformat(),
            "total_cases": len(case_files),
            "successful_cases": completed,
            "failed_cases": failed,
            "results": results
        }
        
        with open(report_path, 'w', encoding='utf-8') as f:
            json.dump(report, f, ensure_ascii=False, indent=2)
        
        print(f"\n批量处理完成!")
        print(f"总案例数: {report['total_cases']}")
        print(f"成功处理: {report['successful_cases']}")
        print(f"处理失败: {report['failed_cases']}")
        print(f"报告保存至: {report_path}")
        
        return results

def setup_environment():
    """创建环境配置文件"""
    env_path = Path(".env")
    if not env_path.exists():
        env_content = '''
# 小米大模型API配置
XIAOMI_API_KEY=your_actual_xiaomi_api_key_here
XIAOMI_BASE_URL=https://api.xiaomimimo.com/v1

# 可选配置
MODEL_NAME=mimo-v2-flash
MAX_TOKENS=1024
TEMPERATURE=0.3
TOP_P=0.95
'''
        with open(env_path, 'w', encoding='utf-8') as f:
            f.write(env_content.strip())
        print(f"已创建环境配置文件: {env_path.absolute()}")
    else:
        print(f"环境配置文件已存在: {env_path.absolute()}")
        
        # 检查配置内容
        with open(env_path, 'r', encoding='utf-8') as f:
            content = f.read()
        
        if 'sk-cf3c9b4ioxd0e1wi6n5fi9ylk3nn2yuph0g7ta1j66xk7ssp' in content:
            print("警告: 发现测试密钥,请替换为实际的API密钥")

def check_dependencies():
    """检查必要的依赖包"""
    missing_deps = []
    
    try:
        import openai
        print("✓ openai 已安装")
    except ImportError:
        missing_deps.append("openai")
        print("✗ 缺少依赖包: openai")
    
    try:
        import dotenv
        print("✓ python-dotenv 已安装")
    except ImportError:
        missing_deps.append("python-dotenv")
        print("✗ 缺少依赖包: python-dotenv")
    
    if missing_deps:
        print(f"请运行: pip install {' '.join(missing_deps)}")
        return False
    
    return True

def main():
    # 检查依赖
    if not check_dependencies():
        return
    
    # 创建环境配置文件
    setup_environment()
    
    # 初始化生成器(降低并发数以避免API限制)
    generator = LegalContentGenerator(max_concurrent=2, retry_delay=3, max_retries=2)
    
    # 显示当前配置
    print(f"当前配置:")
    print(f"  API Key: {'已配置' if generator.api_key != 'your_xiaomi_api_key_here' else '未配置'}")
    print(f"  Base URL: {generator.base_url}")
    print(f"  Model: {generator.model_name}")
    print(f"  Max Tokens: {generator.max_tokens}")
    print(f"  Temperature: {generator.temperature}")
    print(f"  Top P: {generator.top_p}")
    print(f"  最大并发数: {generator.max_concurrent}")
    print(f"  重试延迟: {generator.retry_delay}s")
    print(f"  最大重试次数: {generator.max_retries}")
    print(f"  工作目录: {generator.work_dir.absolute()}")
    print(f"  案例目录: {generator.cases_dir.absolute()}")
    print(f"  模式: {'在线模式' if not generator.use_offline_mode else '离线模式'}")
    
    # 列出并处理所有可用案例
    print("\n--- 开始处理所有可用案例文件 ---")
    available_cases = generator.list_available_cases()
    
    if not available_cases:
        print("未找到案例文件,创建示例案例...")
        sample_case = """
        北京市朝阳区人民法院民事判决书
        原告张三与被告李四房屋租赁合同纠纷一案
        
        经审理查明:2023年3月1日,原告张三与被告李四签订房屋租赁合同,
        约定被告将其位于北京市朝阳区某小区房屋出租给原告,租期一年,
        月租金5000元,押金10000元。合同签订后,原告依约支付了租金和押金。
        
        2023年5月,被告无故要求解除合同并收回房屋,原告不同意,
        被告强行换锁导致原告无法进入房屋。原告认为被告构成根本违约,
        要求解除合同并返还押金、赔偿损失。
        
        被告辩称:因家庭原因需要收回房屋自住,同意退还部分租金,
        但认为不应全额退还押金。
        
        争议焦点:1. 被告是否有权单方解除合同;2. 押金是否应当返还
        
        法院认为:双方签订的租赁合同合法有效,被告无正当理由单方解约
        构成根本违约,应承担违约责任。判决:1. 解除租赁合同;
        2. 被告返还原告押金10000元;3. 被告赔偿原告损失3000元。
        
        适用法律:《中华人民共和国民法典》第563条、第584条
        """
        
        # 确保示例案例目录存在
        sample_dir = generator.cases_dir / "sample"
        sample_dir.mkdir(exist_ok=True)
        case_file = generator.save_case_to_file(sample_case, "sample/sample_case.txt")
        print(f"已创建示例案例文件: {case_file}")
        available_cases = [Path(case_file)]
    
    # 自动批量处理所有案例
    print(f"\n自动开始批量处理所有 {len(available_cases)} 个案例...")
    results = generator.batch_process_all_cases()

if __name__ == "__main__":
    main()

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐