feat:初版
This commit is contained in:
298
plugins/Sora2API/修复说明.md
Normal file
298
plugins/Sora2API/修复说明.md
Normal file
@@ -0,0 +1,298 @@
|
||||
# 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)
|
||||
|
||||
**修改前:**
|
||||
```python
|
||||
except Exception as e:
|
||||
logger.error(f"请求异常: {e}")
|
||||
continue
|
||||
```
|
||||
|
||||
**修改后:**
|
||||
```python
|
||||
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)
|
||||
|
||||
**修改前:**
|
||||
```python
|
||||
logger.info(f"Sora2API请求: {model}, 提示词: {prompt[:50]}...")
|
||||
```
|
||||
|
||||
**修改后:**
|
||||
```python
|
||||
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)
|
||||
|
||||
```python
|
||||
# 添加提示词长度检查和警告
|
||||
if len(prompt) > 1000:
|
||||
logger.warning(f"提示词较长 ({len(prompt)} 字符),可能影响处理速度")
|
||||
```
|
||||
|
||||
**改进点:**
|
||||
- 当提示词超过 1000 字符时发出警告
|
||||
- 帮助识别潜在的性能问题
|
||||
|
||||
### 4. 改进视频下载函数 (main.py:218-266)
|
||||
|
||||
**核心改进:404 错误智能处理**
|
||||
|
||||
```python
|
||||
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)
|
||||
|
||||
```python
|
||||
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` 中可以调整重试次数:
|
||||
|
||||
```toml
|
||||
[generation]
|
||||
max_retry_attempts = 3 # 最大重试次数,建议保持 3 次
|
||||
```
|
||||
|
||||
## 测试建议
|
||||
|
||||
1. **运行测试脚本**(可选):
|
||||
```bash
|
||||
cd WechatHookBot/plugins/Sora2API
|
||||
python test_sora.py
|
||||
```
|
||||
|
||||
2. **实际测试**:
|
||||
- 发送命令:`/sora 科比打篮球被蔡徐坤单防`
|
||||
- 观察日志输出
|
||||
- 如果遇到 404,应该会自动重试
|
||||
|
||||
3. **查看日志**:
|
||||
```bash
|
||||
# 查看最新日志
|
||||
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)
|
||||
|
||||
```python
|
||||
# 增加到 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)
|
||||
|
||||
```python
|
||||
except httpx.ReadTimeout:
|
||||
logger.warning(f"读取超时(ReadTimeout),可能是视频生成时间过长,重试中... ({attempt + 1}/{max_retry})")
|
||||
logger.info(f"提示词长度: {len(prompt)} 字符,建议缩短提示词或增加超时时间")
|
||||
continue
|
||||
```
|
||||
|
||||
**改进点:**
|
||||
- 单独捕获 `ReadTimeout` 异常
|
||||
- 提供更友好的错误提示
|
||||
- 自动重试(最多 3 次)
|
||||
|
||||
#### 3. 更新配置文件 (config.toml)
|
||||
|
||||
```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` - 本文档
|
||||
Reference in New Issue
Block a user