Files
WechatHookBot/plugins/Sora2API/修复说明.md
2025-12-03 15:48:44 +08:00

8.0 KiB
Raw Permalink Blame History

Sora2API 插件修复说明

问题诊断

通过分析日志文件 hookbot.2025-11-25_22-18-49_952160.log,发现问题不是因为提示词太长,而是:

真正的问题API 返回的视频 URL 存在两种情况

  1. 成功的情况(域名:sora.goodnet.icu

    • URL 示例:https://sora.goodnet.icu/tmp/88dd7f3c0fa08c2115b05dae056b5c4e.mp4
    • 可以正常下载
  2. 失败的情况(域名:oscdn2.dyysy.com

    • URL 示例:https://oscdn2.dyysy.com/MP4/s_6925bc764f388191b51a9f46aa27b0f9.mp4
    • 立即返回 404 错误

日志证据

# 成功案例
22:18:51 | Sora2API请求: sora-video-portrait-15s, 提示词: 科比打篮球...
22:22:47 | 提取到视频URL: https://sora.goodnet.icu/tmp/88dd7f3c0fa08c2115b05dae056b5c4e.mp4
22:22:58 | 视频下载成功 ✅

# 失败案例
22:25:45 | Sora2API请求: sora-video-landscape-15s, 提示词: 科比在篮球场上打篮球...
22:26:00 | 提取到视频URL: https://oscdn2.dyysy.com/MP4/s_6925bc764f388191b51a9f46aa27b0f9.mp4
22:26:03 | ERROR | 下载视频失败: Client error '404 Not Found' ❌

修复方案

1. 改进错误日志 (main.py:180-185)

修改前:

except Exception as e:
    logger.error(f"请求异常: {e}")
    continue

修改后:

except Exception as e:
    import traceback
    logger.error(f"请求异常: {type(e).__name__}: {str(e)}")
    logger.error(f"异常详情:\n{traceback.format_exc()}")
    logger.error(f"提示词长度: {len(prompt)} 字符")
    continue

改进点:

  • 显示完整的异常类型和堆栈跟踪
  • 记录提示词长度,便于诊断
  • 不再截断错误信息

2. 增强调试信息 (main.py:106-109)

修改前:

logger.info(f"Sora2API请求: {model}, 提示词: {prompt[:50]}...")

修改后:

logger.info(f"Sora2API请求: {model}, 提示词长度: {len(prompt)} 字符")
logger.debug(f"完整提示词: {prompt}")
logger.debug(f"请求URL: {url}")
logger.debug(f"Payload大小: {len(str(payload))} 字节")

改进点:

  • 记录提示词长度而不是截断内容
  • 添加 DEBUG 级别的详细信息
  • 便于排查请求问题

3. 添加长提示词警告 (main.py:120-122)

# 添加提示词长度检查和警告
if len(prompt) > 1000:
    logger.warning(f"提示词较长 ({len(prompt)} 字符),可能影响处理速度")

改进点:

  • 当提示词超过 1000 字符时发出警告
  • 帮助识别潜在的性能问题

4. 改进视频下载函数 (main.py:218-266)

核心改进404 错误智能处理

async def _download_video(self, url: str, retry_on_404: bool = True) -> Optional[str]:
    """
    下载视频到本地

    Args:
        url: 视频URL
        retry_on_404: 是否在404时返回None以触发重试
    """
    try:
        # ... 下载逻辑 ...

        # 检查是否是404错误
        if response.status_code == 404:
            logger.warning(f"视频URL返回404: {url}")
            if retry_on_404:
                logger.info("将触发重试以获取新的视频链接")
                return None  # 返回 None 触发重试

        response.raise_for_status()
        # ... 保存文件 ...

    except httpx.HTTPStatusError as e:
        if e.response.status_code == 404:
            logger.warning(f"视频URL返回404: {url}")
            if retry_on_404:
                logger.info("将触发重试以获取新的视频链接")
                return None  # 返回 None 触发重试
        logger.error(f"下载视频失败: {e}")

改进点:

  • 专门处理 404 错误
  • 返回 None 触发上层重试逻辑
  • 区分 404 和其他错误类型

5. 添加自动重试机制 (main.py:170-179)

if video_url:
    # 下载视频
    video_path = await self._download_video(video_url)
    if video_path:
        logger.success("成功生成视频")
        return [video_path]
    else:
        # 下载失败可能是404继续重试
        logger.warning(f"视频下载失败,将重试 ({attempt + 1}/{max_retry})")
        continue

改进点:

  • 当下载失败时,自动重新请求 API
  • 利用现有的重试机制max_retry_attempts
  • 每次重试都会获取新的视频 URL

工作原理

修复前的流程:

1. 请求 API 生成视频
2. 获取视频 URL (可能是 oscdn2.dyysy.com)
3. 尝试下载 → 404 错误
4. ❌ 失败,不再重试

修复后的流程:

1. 请求 API 生成视频
2. 获取视频 URL (可能是 oscdn2.dyysy.com)
3. 尝试下载 → 404 错误
4. 检测到 404返回 None
5. 触发重试机制
6. 重新请求 API 生成视频
7. 获取新的视频 URL (可能是 sora.goodnet.icu)
8. 下载成功 ✅

配置说明

config.toml 中可以调整重试次数:

[generation]
max_retry_attempts = 3  # 最大重试次数,建议保持 3 次

测试建议

  1. 运行测试脚本(可选):

    cd WechatHookBot/plugins/Sora2API
    python test_sora.py
    
  2. 实际测试

    • 发送命令:/sora 科比打篮球被蔡徐坤单防
    • 观察日志输出
    • 如果遇到 404应该会自动重试
  3. 查看日志

    # 查看最新日志
    tail -f WechatHookBot/logs/hookbot.log
    
    # 搜索 Sora 相关日志
    grep "Sora2API" WechatHookBot/logs/hookbot.log
    

预期效果

修复后,即使 API 返回 oscdn2.dyysy.com 域名的 404 链接,插件也会:

  1. 检测到 404 错误
  2. 记录警告日志
  3. 自动重试请求
  4. 获取新的视频链接
  5. 成功下载并发送视频

补充修复ReadTimeout 超时问题

问题描述

在处理较长提示词(如 370 字符)时,可能会遇到 httpx.ReadTimeout 错误:

ERROR | 请求异常: ReadTimeout:
ERROR | 提示词长度: 370 字符

原因分析

  • 视频生成需要较长时间(尤其是长提示词)
  • 流式响应在等待数据时可能超过读取超时限制
  • 原超时配置300秒对于复杂视频生成可能不够

修复方案

1. 增加超时时间 (main.py:114-121)

# 增加到 10 分钟
max_timeout = min(api_config["timeout"], 600)
timeout = httpx.Timeout(
    connect=10.0,      # 连接超时10秒
    read=max_timeout,  # 读取超时10分钟两次数据块之间的最大间隔
    write=10.0,        # 写入超时10秒
    pool=10.0          # 连接池超时10秒
)

关键点:

  • 对于流式响应,read 超时是指两次数据块之间的最大间隔,而不是总时间
  • 增加到 600 秒10分钟以应对长时间的视频生成

2. 专门处理 ReadTimeout (main.py:200-203)

except httpx.ReadTimeout:
    logger.warning(f"读取超时ReadTimeout可能是视频生成时间过长重试中... ({attempt + 1}/{max_retry})")
    logger.info(f"提示词长度: {len(prompt)} 字符,建议缩短提示词或增加超时时间")
    continue

改进点:

  • 单独捕获 ReadTimeout 异常
  • 提供更友好的错误提示
  • 自动重试(最多 3 次)

3. 更新配置文件 (config.toml)

[api]
timeout = 600  # 请求超时时间(秒),流式响应的读取超时

工作流程

1. 发送长提示词请求
2. 开始接收流式响应
3. 等待视频生成...
4. 如果超过 10 分钟无数据 → ReadTimeout
5. 捕获异常,记录日志
6. 自动重试attempt 2/3
7. 重新请求 API
8. 成功接收响应 ✅

注意事项

  • 如果 3 次重试都失败,会返回错误提示
  • 每次重试之间有指数退避延迟2^attempt 秒,最多 10 秒)
  • 404 错误不会计入熔断器的失败次数
  • ReadTimeout 会自动重试,不影响其他请求
  • 代理配置目前被临时禁用(第 124、241 行),如需启用请取消注释
  • 如果经常遇到超时,建议:
    • 缩短提示词长度
    • 或在 config.toml 中增加 timeout 值(当前 600 秒)

相关文件

  • main.py - 主要修改文件
  • config.toml - 配置文件
  • test_sora.py - 测试脚本(新增)
  • 修复说明.md - 本文档