free-short-video 7.0.3 → 7.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -10
- package/core/api/agnes_video.py +18 -0
- package/core/api/error_collector.py +63 -0
- package/core/config.py +1 -1
- package/package.json +1 -1
- package/static/assets/index-KzCkI4Os.js +45 -0
- package/static/index.html +1 -1
- package/web/routes/task_routes.py +6 -0
- package/web/routes/video_routes.py +7 -0
- package/static/assets/index-BC30W-Gs.js +0 -45
package/README.md
CHANGED
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
---
|
|
2
2
|
|
|
3
|
-
# What's New in v7.0.
|
|
3
|
+
# What's New in v7.0.4
|
|
4
4
|
|
|
5
5
|
## What's New
|
|
6
6
|
|
|
7
7
|
### Features & Improvements
|
|
8
8
|
|
|
9
|
-
* **
|
|
10
|
-
* **Honest
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
* **Upstream API error trends.** Errors that carry an HTTP status code are now aggregated per task — by status code, model type (chat / image / video) and API method — and returned by the task detail API. The frontend reports them anonymously as `api_error` events, and task-failure / creation-failure events now carry the extracted status code as well, so recurring upstream failures (for example `503 video_queue_full`) can be tracked as a trend over time instead of being seen as unrelated single errors. The aggregation lives in memory for the lifetime of the task and is cleared with it; `error_logs/` remains the offline source of truth.
|
|
10
|
+
* **Honest "not ready yet" state while polling.** A transient `404` while waiting for a submitted video is now an expected intermediate state rather than an error. It no longer consumes the consecutive-failure budget and no longer gets flushed into `error_logs`, so the failure panel and the logs stop reporting failures for tasks that were in fact still queued upstream.
|
|
11
|
+
|
|
12
|
+
### Refactoring & Optimizations
|
|
13
|
+
|
|
14
|
+
* Regression coverage for the upstream error-handling path: consecutive `404`s followed by a successful completion, and a permanent `404` that correctly falls back to the overall polling timeout.
|
|
14
15
|
|
|
15
16
|
### Bug Fixes
|
|
16
17
|
|
|
17
|
-
*
|
|
18
|
-
* **Frontend no longer breaks after an update.** The app entry page is now served with `Cache-Control: no-cache`, so browsers can no longer keep a stale entry page that references deleted build assets — the "task list (or the whole app) silently stopped working after pulling a new version" failure mode is gone. After upgrading, do one hard refresh (`Cmd/Ctrl+Shift+R`); afterwards updates apply on normal reload.
|
|
19
|
-
* Fixed the queue-full messaging to name Agnes, quote the raw upstream error, and include an actionable suggestion (retry off-peak), instead of the vague "upstream video queue is full".
|
|
18
|
+
* Fixed video tasks failing with a spurious error when the upstream gateway had not made the task record visible yet — a state observed for 420s and even 1100s+ under peak load. The overall polling timeout stays as the final backstop, and it keeps the `video_id` so the task can be resumed rather than reported as a server-confirmed failure.
|
|
20
19
|
|
|
21
20
|
---
|
|
22
21
|
|
|
23
|
-
No action is required after upgrading. If
|
|
22
|
+
No action is required after upgrading. If a task still fails, the failure panel now shows the real upstream reason with its HTTP status code, and repeated upstream errors of the same kind become visible as a trend.
|
|
24
23
|
|
|
25
24
|
---
|
|
26
25
|
|
package/core/api/agnes_video.py
CHANGED
|
@@ -461,6 +461,12 @@ class AgnesVideoAPI:
|
|
|
461
461
|
last_status = ""
|
|
462
462
|
poll_count = 0
|
|
463
463
|
consecutive_failures = 0
|
|
464
|
+
# U9(v7.0.4):提交返回的是网关路由键,任务记录入库可见有延迟——
|
|
465
|
+
# 轮询侧 404 "task not found" 是「任务还没准备好」的中间态而非错误
|
|
466
|
+
# (实测上游高峰期可见性延迟可从历史 ~20s 劣化到 10min+),单独计数、
|
|
467
|
+
# 只做周期性 info 日志,不进 error_logs、不消耗连续失败配额;
|
|
468
|
+
# 最终兜底是循环顶部的 max_poll_duration 整体超时。
|
|
469
|
+
not_found_count = 0
|
|
464
470
|
start_time = asyncio.get_event_loop().time()
|
|
465
471
|
# 2.5 系列查询需带 model_name(text 模式可省略,但带上更通用)
|
|
466
472
|
model_param = f"&model_name={self.model}" if is_v25_video_model(self.model) else ""
|
|
@@ -511,6 +517,18 @@ class AgnesVideoAPI:
|
|
|
511
517
|
logger.warning("[KeyRotation] HTTP 429 on poll, 换 Key 立即重试")
|
|
512
518
|
continue
|
|
513
519
|
break
|
|
520
|
+
# U9:404(task not found)= 记录尚未在网关任务库可见,中间态
|
|
521
|
+
if resp.status_code == 404:
|
|
522
|
+
not_found_count += 1
|
|
523
|
+
poll_count += 1 # 计入自适应间隔与周期日志的推进
|
|
524
|
+
if not_found_count == 1 or not_found_count % 10 == 0:
|
|
525
|
+
logger.info(
|
|
526
|
+
f"[AgnesVideo] Video {video_id[:16]}... not yet visible "
|
|
527
|
+
f"(404 task not found), poll #{not_found_count}, "
|
|
528
|
+
f"elapsed {elapsed:.0f}s"
|
|
529
|
+
)
|
|
530
|
+
await asyncio.sleep(_adaptive_poll_interval(interval, poll_count))
|
|
531
|
+
continue
|
|
514
532
|
resp.raise_for_status()
|
|
515
533
|
result = resp.json()
|
|
516
534
|
status = result.get("status", "")
|
|
@@ -33,6 +33,63 @@ _WORKSPACE_ROOT: Optional[Path] = None
|
|
|
33
33
|
# 用 contextvar 而非逐层传参,将改动面收敛到 API 模块内部(PRD FR9)。
|
|
34
34
|
_TASK_ID_CTX: ContextVar[str] = ContextVar("error_collector_task_id", default="")
|
|
35
35
|
|
|
36
|
+
# ── GA 埋点:上游接口报错聚合(内存态,按 task_id 分组)──
|
|
37
|
+
# 结构:{task_id: {"{status_code}|{model_type}|{api_method}": {
|
|
38
|
+
# "status_code": int, "model_type": str, "api_method": str,
|
|
39
|
+
# "count": int, "first_ts": iso, "last_ts": iso}}}
|
|
40
|
+
#
|
|
41
|
+
# 设计说明:故意**不写入 task_state.json**——流水线持有自己的 TaskManager
|
|
42
|
+
# 缓存实例,每次 update_state 都会拿缓存快照整份覆盖落盘,error_collector
|
|
43
|
+
# 若单独写盘会被下一次流水线落盘冲掉。改为内存聚合 +
|
|
44
|
+
# GET /api/tasks/{id}(web/routes/task_routes.py)读取时合并下发,
|
|
45
|
+
# 前端轮询到新增量即上报 GA `api_error` 事件(503 趋势分析用)。
|
|
46
|
+
# 进程重启后内存聚合清零属预期:前端埋点本身只覆盖"页面开着"的窗口,
|
|
47
|
+
# 完整离线趋势仍以 error_logs/ 落盘文件为准。
|
|
48
|
+
_TASK_ERROR_AGG: dict = {}
|
|
49
|
+
_MAX_AGG_ENTRIES_PER_TASK = 32 # 按维度聚合后条目数上限,防异常状态码刷爆
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _bump_upstream_error(task_id: str, status_code: int, model_type: str, api_method: str) -> None:
|
|
53
|
+
"""累加一次带 HTTP 状态码的上游报错(内存聚合,失败静默不影响主流程)。"""
|
|
54
|
+
try:
|
|
55
|
+
now = datetime.now().isoformat(timespec="seconds")
|
|
56
|
+
per_task = _TASK_ERROR_AGG.setdefault(task_id, {})
|
|
57
|
+
key = f"{status_code}|{model_type}|{api_method}"
|
|
58
|
+
entry = per_task.get(key)
|
|
59
|
+
if entry is None:
|
|
60
|
+
if len(per_task) >= _MAX_AGG_ENTRIES_PER_TASK:
|
|
61
|
+
logger.warning(
|
|
62
|
+
f"[ErrorCollector] Upstream error agg cap "
|
|
63
|
+
f"({_MAX_AGG_ENTRIES_PER_TASK}) reached for task {task_id}, dropping"
|
|
64
|
+
)
|
|
65
|
+
return
|
|
66
|
+
per_task[key] = {
|
|
67
|
+
"status_code": status_code,
|
|
68
|
+
"model_type": model_type,
|
|
69
|
+
"api_method": api_method,
|
|
70
|
+
"count": 1,
|
|
71
|
+
"first_ts": now,
|
|
72
|
+
"last_ts": now,
|
|
73
|
+
}
|
|
74
|
+
else:
|
|
75
|
+
entry["count"] += 1
|
|
76
|
+
entry["last_ts"] = now
|
|
77
|
+
except Exception as e:
|
|
78
|
+
logger.debug(f"[ErrorCollector] Failed to bump upstream error agg: {e}")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def get_task_upstream_errors(task_id: str) -> list:
|
|
82
|
+
"""返回某任务聚合后的上游报错列表(按首次发生时间排序,供任务详情端点合并下发)。"""
|
|
83
|
+
per_task = _TASK_ERROR_AGG.get(task_id or "")
|
|
84
|
+
if not per_task:
|
|
85
|
+
return []
|
|
86
|
+
return sorted(per_task.values(), key=lambda e: e.get("first_ts", ""))
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def clear_task_upstream_errors(task_id: str) -> None:
|
|
90
|
+
"""任务删除时清理对应聚合(防内存缓慢增长)。"""
|
|
91
|
+
_TASK_ERROR_AGG.pop(task_id or "", None)
|
|
92
|
+
|
|
36
93
|
|
|
37
94
|
def set_workspace_root(path: str) -> None:
|
|
38
95
|
"""设置错误日志存储的根目录(通常为激活的工作空间路径)。
|
|
@@ -198,6 +255,12 @@ def collect_error(
|
|
|
198
255
|
with open(filepath, "w", encoding="utf-8") as f:
|
|
199
256
|
json.dump(error_data, f, ensure_ascii=False, indent=2)
|
|
200
257
|
|
|
258
|
+
# GA 埋点:带 HTTP 状态码的报错同步累加进任务级内存聚合
|
|
259
|
+
if status_code and error_data["task_id"]:
|
|
260
|
+
_bump_upstream_error(
|
|
261
|
+
error_data["task_id"], status_code, model_type, api_method
|
|
262
|
+
)
|
|
263
|
+
|
|
201
264
|
# 优化路线图 1.5b:按数量轮转,防止 error_logs 无限膨胀
|
|
202
265
|
_rotate_error_logs(log_dir)
|
|
203
266
|
|
package/core/config.py
CHANGED
|
@@ -18,7 +18,7 @@ CONFIG_FILE = os.path.join(CONFIG_DIR, "config.json")
|
|
|
18
18
|
# ═══════════════════════════════════════════════════
|
|
19
19
|
# 应用版本号(v6.1 新增:发版时同步更新,见 docs/dev/release_process.md)
|
|
20
20
|
# ═══════════════════════════════════════════════════
|
|
21
|
-
APP_VERSION = "7.0.
|
|
21
|
+
APP_VERSION = "7.0.4"
|
|
22
22
|
|
|
23
23
|
# 未配置 API Key 时的统一报错文案(含免费获取与在线体验兜底,全站路由共用)
|
|
24
24
|
#
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "free-short-video",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.4",
|
|
4
4
|
"description": "Free AI short-video generator — run the full free-short-video service locally with one command. Text-to-video, image generation, Edge-TTS narration, subtitles, and compositing, all free. Official site: https://video.lichuanyang.top",
|
|
5
5
|
"bin": {
|
|
6
6
|
"free-short-video": "bin/cli.js",
|