free-short-video 7.0.6 → 7.1.1
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 +44 -8
- package/core/api/agnes_chat.py +28 -14
- package/core/api/agnes_image.py +50 -25
- package/core/api/agnes_video.py +191 -183
- package/core/api/key_manager.py +79 -0
- package/core/api/rate_limiter.py +37 -14
- package/core/api/retry_policy.py +124 -0
- package/core/config.py +28 -35
- package/core/i18n_backend.py +19 -0
- package/core/pipelines/anchor_video.py +1 -1
- package/core/pipelines/creative/pipeline.py +1 -1
- package/core/pipelines/creative/steps_frames.py +16 -5
- package/core/pipelines/manuscript_video.py +1 -1
- package/core/pipelines/poetry_video.py +1 -1
- package/core/pipelines/simple_video.py +1 -1
- package/core/screenwriter/scenes.py +2 -1
- package/package.json +1 -1
- package/static/assets/ar-uqdQsD8d.js +1 -0
- package/static/assets/bn-Cs0c8ay0.js +1 -0
- package/static/assets/de-C03R7qVE.js +1 -0
- package/static/assets/es-LJ2OkYIx.js +1 -0
- package/static/assets/fa-DySEd8zE.js +1 -0
- package/static/assets/fr-BTafm0bE.js +1 -0
- package/static/assets/hi-Bk8MY-fF.js +1 -0
- package/static/assets/id-DZGFWLC-.js +1 -0
- package/static/assets/index-C1tAWGVu.js +46 -0
- package/static/assets/index-X0RXgNf5.css +1 -0
- package/static/assets/it-DEnLooJL.js +1 -0
- package/static/assets/ja-D7VxE6bk.js +1 -0
- package/static/assets/ko-nc2euVdS.js +1 -0
- package/static/assets/ms-Jz3t8mz-.js +1 -0
- package/static/assets/nl-D4aafNI8.js +1 -0
- package/static/assets/pt-CBY3pDPr.js +1 -0
- package/static/assets/ru-B3WZA3F-.js +1 -0
- package/static/assets/th-BSUvfnqU.js +1 -0
- package/static/assets/tl-DSeqPP4N.js +1 -0
- package/static/assets/tr-jcUJ-jsZ.js +1 -0
- package/static/assets/ur-cYxmbnCI.js +1 -0
- package/static/assets/vi-Dh-Jp2tU.js +1 -0
- package/static/index.html +2 -2
- package/web/routes/config_routes.py +36 -13
- package/web/routes/task_creation_routes.py +80 -18
- package/static/assets/ar-DDU7VnXA.js +0 -1
- package/static/assets/bn-nY2VgxNf.js +0 -1
- package/static/assets/de-t0gEvqFh.js +0 -1
- package/static/assets/es-BrDX0bsl.js +0 -1
- package/static/assets/fa-DC45iYzo.js +0 -1
- package/static/assets/fr-jNdU3xMA.js +0 -1
- package/static/assets/hi-DU2jFclD.js +0 -1
- package/static/assets/id-xVm_LLjT.js +0 -1
- package/static/assets/index-B_DQr-bu.css +0 -1
- package/static/assets/index-D06v2INE.js +0 -45
- package/static/assets/it-CNEcqCqv.js +0 -1
- package/static/assets/ja-BMrQ7ES8.js +0 -1
- package/static/assets/ko-DLcdCpqD.js +0 -1
- package/static/assets/ms-lz3IP0pE.js +0 -1
- package/static/assets/nl-JdaJ6OFu.js +0 -1
- package/static/assets/pt-BAJ6NELp.js +0 -1
- package/static/assets/ru-DUk7xiI4.js +0 -1
- package/static/assets/th-DBGXh4cH.js +0 -1
- package/static/assets/tl-cWM0TcNr.js +0 -1
- package/static/assets/tr-DY7yRLf-.js +0 -1
- package/static/assets/ur-CBrqZI5F.js +0 -1
- package/static/assets/vi-BWMCwlNI.js +0 -1
package/README.md
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
---
|
|
2
2
|
|
|
3
|
-
# What's New in v7.
|
|
3
|
+
# What's New in v7.1.1
|
|
4
4
|
|
|
5
5
|
## What's New
|
|
6
6
|
|
|
7
7
|
### Features & Improvements
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
- **`agnes-video-2.5-flash` is the default video model.** With the legacy Video 2.0 channel retired upstream, the model lineup now covers the 2.5 series only, and every video task is submitted through the 2.5 standard protocol (`mode` / `seconds` / `size` / `aspect_ratio`). The per-model guidance shown in the create-task form reflects the available models.
|
|
10
|
+
- **Configurable configuration directory for npm deployments.** A new `AGNES_CONFIG_DIR` environment variable lets `npx free-short-video` users keep `config.json` (their saved keys and settings) in a stable location such as `~/.agnes_config`, instead of inside the ephemeral npm cache that is lost on `npm cache clean` or a cache-directory change.
|
|
11
|
+
- **Image uploads are validated on arrival.** Non-whitelisted file types are rejected with a readable message instead of being silently rewritten, and uploaded bytes are checked to be a decodable image. A corrupt file now fails immediately with a clear, scene-scoped message rather than surfacing as a low-level error during generation.
|
|
12
|
+
- **Feedback panel and diagnostic report fully localized.** The remaining feedback-panel and diagnostic-report labels that still appeared in English on non-English interfaces are now translated across all 22 interface languages.
|
|
10
13
|
|
|
11
14
|
### Bug Fixes
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
Existing projects do not need to be recreated. Reopening a Creative or Poetry form after upgrading shows the preset name in the style field, and you can pick any other preset — or clear the field — as before.
|
|
16
|
+
- **Custom end-frame images keep their scene mapping.** Uploaded end-frame images are now saved to their own scene index, so an empty slot no longer shifts later images onto the wrong scenes.
|
|
17
|
+
- **Chat calls retry once on an empty response** instead of aborting the screenwriting stage with a `None` or `KeyError`.
|
|
18
|
+
- **Poetry scene prompts use a language-neutral default style.** When no style is specified, the default hint is no longer a hardcoded Chinese phrase, so non-Chinese runs stay in their own language.
|
|
19
|
+
- **API-key authentication diagnostics no longer write the configured site domain into the log line.**
|
|
18
20
|
|
|
19
21
|
---
|
|
20
22
|
|
|
@@ -102,12 +104,45 @@ schema.org structured data for SEO/GEO indexing. GitHub does not execute this sc
|
|
|
102
104
|
|
|
103
105
|
> **🖥️ Try it now — no install needed:** Visit [video.lichuanyang.top](https://video.lichuanyang.top) and experience **Simple Video** mode directly in your browser. Just enter a prompt and generate a free AI video instantly.
|
|
104
106
|
|
|
105
|
-
## 🚀
|
|
107
|
+
## 🚀 Three Ways to Use — All Completely Free
|
|
106
108
|
|
|
107
109
|
| Project | Run Where | Features | Link |
|
|
108
110
|
|---------|-----------|----------|------|
|
|
109
111
|
| **[Agnes Video Generator](https://github.com/lcy362/agnes-video-generator)** (this project) | **Download & run locally** | **More powerful** — TTS narration, auto subtitles, digital anchor, image-to-video, keyframes animation, manuscript-to-video, checkpoint resume & more | [GitHub](https://github.com/lcy362/agnes-video-generator) |
|
|
110
112
|
| **[FreeShortVideoStudio](https://github.com/lcy362/free-short-video-studio)** | **Fully online, in the browser** | Lightweight, zero install — no setup at all, **features under active construction** | [video.lichuanyang.top/studio](https://video.lichuanyang.top/studio) · [GitHub](https://github.com/lcy362/free-short-video-studio) |
|
|
113
|
+
| **[Agnes Video Generator](https://github.com/lcy362/agnes-video-generator)** — **agent-ready** | **Driven by an AI coding agent** | **Least effort** — ships [`AGENTS.md`](AGENTS.md) plus a companion skill set (usage / troubleshoot / contrib): the agent installs the project, generates the video and debugs failures itself | [Agent guide](docs/public/agent-operations.md) · [Flint](https://github.com/lcy362/flint) |
|
|
114
|
+
|
|
115
|
+
## 🤖 Or Let an AI Agent Drive It
|
|
116
|
+
|
|
117
|
+
This project ships an [`AGENTS.md`](AGENTS.md) written for AI coding assistants, so an agent can install it, generate videos and debug failures after reading one document. Clone the repo, then tell your agent:
|
|
118
|
+
|
|
119
|
+
> "Read the AGENTS.md in this project, install dependencies, configure the API key `<your-key>`, and start the server."
|
|
120
|
+
|
|
121
|
+
Then ask it to prove the setup with `"Run the deployment verification checks."` — it executes the four-layer checklist (connectivity → static analysis → endpoint tests → features) and reports each result.
|
|
122
|
+
|
|
123
|
+
**Want your agent to skip the learning step?** Install the companion skill set — three ready-made skills (**usage**: deploy, pick a mode, submit and watch a task, edit artifacts at Manual Mode checkpoints; **troubleshoot**: find out why a run failed; **contrib**: change the code, get the PR through CI) plus small scripts for task control, deployment verification, evidence collection, media checks and the local CI gate:
|
|
124
|
+
|
|
125
|
+
**[lcy362/agnes-video-generator-skills](https://github.com/lcy362/agnes-video-generator-skills)**
|
|
126
|
+
|
|
127
|
+
Clone the repository first:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
git clone https://github.com/lcy362/agnes-video-generator-skills.git
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Recommended — let [flint](https://github.com/lcy362/flint) install and distribute it.** flint is a local-first, open-source skills manager that keeps your skills in one place and deploys them into any agent or project directory by symlink or copy. It works on local sources only — it never clones anything for you — so you register the directory you just cloned, and the three skills appear in front of every agent you use:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
npx flint-skills-hub # Sources → add the cloned directory (flint reads its skills/ subdirectory)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**Or copy it in by hand** — no flint required, but you repeat it for every project and every new agent:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
cp -R agnes-video-generator-skills/skills/* <project>/.agents/skills/ # any agent that reads .agents/skills
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Full guide: **[Let an AI Agent Operate This Project](docs/public/agent-operations.md)**.
|
|
111
146
|
|
|
112
147
|
## ⭐ Support & Contribute
|
|
113
148
|
|
|
@@ -193,6 +228,7 @@ Full walkthrough: [Getting Started → Configure API Key](docs/public/getting-st
|
|
|
193
228
|
|
|
194
229
|
- **[Features](docs/public/features.md)** — Creation modes, the completely free AI model chain, AI narration & smart subtitles, flexible creative controls, production-grade reliability, and the multilingual Web UI.
|
|
195
230
|
- **[Getting Started](docs/public/getting-started.md)** — Install and deploy in 4 ways: Manual (`start.sh`), Docker, npm (`npx free-short-video`), or AI-Agent assisted.
|
|
231
|
+
- **[AI Agent Operations](docs/public/agent-operations.md)** — Three levels of agent-driven operation: hand your agent `AGENTS.md`, install the companion skill set, or distribute it to every agent with flint.
|
|
196
232
|
- **[Usage Guide](docs/public/usage.md)** — Configure your API key, pick a video mode, resume from checkpoints, the three chaining modes, and logs & output layout.
|
|
197
233
|
- **[Architecture](docs/public/architecture.md)** — Project structure and tech stack.
|
|
198
234
|
- **[API Reference](docs/public/api.md)** — Full REST endpoint list (progress via polling, no WebSocket).
|
package/core/api/agnes_chat.py
CHANGED
|
@@ -191,20 +191,34 @@ class AgnesChatAPI:
|
|
|
191
191
|
from core.config import get_settings
|
|
192
192
|
|
|
193
193
|
timeout_retry_limit = 1
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
"
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
)
|
|
207
|
-
|
|
194
|
+
payload = {
|
|
195
|
+
"model": self.model,
|
|
196
|
+
"messages": [
|
|
197
|
+
{"role": "system", "content": system_prompt},
|
|
198
|
+
{"role": "user", "content": user_prompt},
|
|
199
|
+
],
|
|
200
|
+
"temperature": 0.7,
|
|
201
|
+
"max_tokens": max_tokens,
|
|
202
|
+
}
|
|
203
|
+
# 空响应守卫:缺失 / 空正文时重试一次,避免把 ``None`` 或 KeyError 直接
|
|
204
|
+
# 抛给上层(原实现为裸 ``data["choices"][0]["message"]["content"]``)。
|
|
205
|
+
content = ""
|
|
206
|
+
for attempt in range(2):
|
|
207
|
+
data = self._request_with_retry(
|
|
208
|
+
payload,
|
|
209
|
+
timeout=get_settings().agnes_chat_timeout,
|
|
210
|
+
timeout_retry_limit=timeout_retry_limit,
|
|
211
|
+
)
|
|
212
|
+
try:
|
|
213
|
+
content = data["choices"][0]["message"]["content"] or ""
|
|
214
|
+
except (KeyError, IndexError, TypeError):
|
|
215
|
+
content = ""
|
|
216
|
+
if isinstance(content, str) and content.strip():
|
|
217
|
+
return content
|
|
218
|
+
content = ""
|
|
219
|
+
if attempt == 0:
|
|
220
|
+
logger.warning("[AgnesChat] Empty chat response; retrying once...")
|
|
221
|
+
raise RuntimeError("Agnes Chat returned empty content after retry")
|
|
208
222
|
|
|
209
223
|
def chat_json(self, system_prompt: str, user_prompt: str, max_tokens: int = 4096) -> dict:
|
|
210
224
|
"""Chat 调用并解析 JSON 响应(健壮版)。
|
package/core/api/agnes_image.py
CHANGED
|
@@ -12,6 +12,7 @@ import requests
|
|
|
12
12
|
from core.api.error_collector import collect_error, collect_error_from_exception
|
|
13
13
|
from core.api.key_manager import get_key_ring
|
|
14
14
|
from core.api.rate_limiter import get_rate_limiter
|
|
15
|
+
from core.api.retry_policy import BusyTracker, busy_delay, fault_delay, is_busy_signal
|
|
15
16
|
from core.config import get_base_url_for_key
|
|
16
17
|
from utils.image import download_image
|
|
17
18
|
from utils.image_normalizer import normalize_reference_path
|
|
@@ -21,6 +22,9 @@ logger = logging.getLogger(__name__)
|
|
|
21
22
|
# 图像生成读超时基数(秒):timeout = 基数 * (attempt + 1),首次 120s 逐步放宽
|
|
22
23
|
_READ_TIMEOUT_BASE_SECONDS = 120
|
|
23
24
|
|
|
25
|
+
# v7.2 忙轨次数封顶:等效旧的 300s 预算 ÷ 20s 间隔基数
|
|
26
|
+
_BUSY_MAX_ATTEMPTS = 15
|
|
27
|
+
|
|
24
28
|
|
|
25
29
|
class ImageOutput:
|
|
26
30
|
def __init__(self, fmt: str, ext: str, data: str):
|
|
@@ -159,6 +163,8 @@ class AgnesImageAPI:
|
|
|
159
163
|
rotations = 0
|
|
160
164
|
ring = get_key_ring()
|
|
161
165
|
max_rotations = len(ring) * max_retries
|
|
166
|
+
# 忙轨(429 / 所有 503):首跳贴限流 + 固定间隔 + 次数封顶
|
|
167
|
+
busy: BusyTracker | None = None
|
|
162
168
|
while attempt < max_retries:
|
|
163
169
|
try:
|
|
164
170
|
# 全局限速:在发起 HTTP 请求前获取令牌(2.3 异步原生)
|
|
@@ -174,9 +180,12 @@ class AgnesImageAPI:
|
|
|
174
180
|
timeout=(30, read_timeout),
|
|
175
181
|
)
|
|
176
182
|
|
|
177
|
-
# 429
|
|
178
|
-
|
|
179
|
-
|
|
183
|
+
# ── 忙轨(429 / 所有 503)────────────────────────────────
|
|
184
|
+
# 多 Key 先换 Key 立即重试;换无可换则首跳贴限流(交给共享令牌桶)、
|
|
185
|
+
# 之后固定间隔重试(不逐级加长),由次数封顶兜底。
|
|
186
|
+
if is_busy_signal(resp.status_code):
|
|
187
|
+
if (resp.status_code == 429 and ring.has_multiple()
|
|
188
|
+
and rotations < max_rotations):
|
|
180
189
|
rotations += 1
|
|
181
190
|
ring.rotate()
|
|
182
191
|
logger.warning(
|
|
@@ -184,40 +193,56 @@ class AgnesImageAPI:
|
|
|
184
193
|
f"(image, rotation {rotations})"
|
|
185
194
|
)
|
|
186
195
|
continue
|
|
187
|
-
if
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
196
|
+
if busy is None:
|
|
197
|
+
from core.config import get_settings
|
|
198
|
+
busy = BusyTracker(
|
|
199
|
+
get_settings().agnes_busy_retry_attempts
|
|
200
|
+
or _BUSY_MAX_ATTEMPTS
|
|
192
201
|
)
|
|
202
|
+
error_type = (
|
|
203
|
+
"RateLimit429" if resp.status_code == 429
|
|
204
|
+
else f"Busy{resp.status_code}"
|
|
205
|
+
)
|
|
206
|
+
if busy.exhausted():
|
|
207
|
+
# 次数用尽:交给调用方按原语义抛错(记录最终失败)
|
|
193
208
|
collect_error(
|
|
194
209
|
"image", "generate_single_image",
|
|
195
210
|
prompt=prompt,
|
|
196
|
-
error_type=
|
|
197
|
-
error_message=
|
|
198
|
-
|
|
211
|
+
error_type=error_type,
|
|
212
|
+
error_message=(
|
|
213
|
+
f"HTTP {resp.status_code}: busy retries exhausted"
|
|
214
|
+
),
|
|
215
|
+
status_code=resp.status_code,
|
|
199
216
|
response_body=resp.text,
|
|
200
|
-
retry_count=
|
|
217
|
+
retry_count=busy.retries,
|
|
201
218
|
)
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
#
|
|
219
|
+
resp.raise_for_status()
|
|
220
|
+
break
|
|
221
|
+
busy.retries += 1
|
|
222
|
+
# 第 1 次重试 0s(贴着限流),之后固定基数
|
|
223
|
+
delay = busy_delay(retry_base_delay, 0.0, busy.retries - 1)
|
|
224
|
+
logger.warning(
|
|
225
|
+
f"[AgnesImage] {resp.status_code} busy, "
|
|
226
|
+
f"retry #{busy.retries}/{busy.max_attempts} in {delay:.0f}s..."
|
|
227
|
+
)
|
|
206
228
|
collect_error(
|
|
207
229
|
"image", "generate_single_image",
|
|
208
230
|
prompt=prompt,
|
|
209
|
-
error_type=
|
|
210
|
-
error_message=
|
|
211
|
-
|
|
231
|
+
error_type=error_type,
|
|
232
|
+
error_message=(
|
|
233
|
+
"HTTP 429: rate limited" if resp.status_code == 429
|
|
234
|
+
else f"HTTP {resp.status_code}: server busy"
|
|
235
|
+
),
|
|
236
|
+
status_code=resp.status_code,
|
|
212
237
|
response_body=resp.text,
|
|
213
|
-
retry_count=
|
|
238
|
+
retry_count=busy.retries,
|
|
214
239
|
)
|
|
215
|
-
|
|
216
|
-
|
|
240
|
+
await asyncio.sleep(delay)
|
|
241
|
+
continue
|
|
217
242
|
|
|
218
|
-
# 5xx
|
|
243
|
+
# 故障轨(非忙 5xx):退避逐级加长 + max_retries 次数封顶
|
|
219
244
|
if resp.status_code >= 500 and attempt < max_retries - 1:
|
|
220
|
-
delay = retry_base_delay
|
|
245
|
+
delay = fault_delay(retry_base_delay, attempt)
|
|
221
246
|
logger.warning(
|
|
222
247
|
f"[AgnesImage] {resp.status_code} server error, "
|
|
223
248
|
f"retry {attempt + 1}/{max_retries} in {delay:.0f}s..."
|
|
@@ -247,7 +272,7 @@ class AgnesImageAPI:
|
|
|
247
272
|
exc=e, prompt=prompt, retry_count=attempt + 1,
|
|
248
273
|
)
|
|
249
274
|
if attempt < max_retries - 1:
|
|
250
|
-
delay = retry_base_delay
|
|
275
|
+
delay = fault_delay(retry_base_delay, attempt)
|
|
251
276
|
logger.warning(
|
|
252
277
|
f"[AgnesImage] {type(e).__name__}, "
|
|
253
278
|
f"retry {attempt + 1}/{max_retries} in {delay:.0f}s..."
|