videogen 2.2.0__tar.gz → 2.5.3__tar.gz
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.
- {videogen-2.2.0 → videogen-2.5.3}/PKG-INFO +7 -5
- {videogen-2.2.0 → videogen-2.5.3}/README.md +6 -4
- {videogen-2.2.0 → videogen-2.5.3}/pyproject.toml +1 -1
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/__init__.py +4 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/async_poll_executed_tool.py +2 -0
- videogen-2.5.3/src/videogen/async_poll_file_url_import.py +38 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/async_poll_workflow_run.py +2 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/async_upload_file.py +10 -3
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/client.py +8 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/poll_executed_tool.py +3 -1
- videogen-2.5.3/src/videogen/poll_file_url_import.py +38 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/poll_workflow_run.py +3 -1
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/resources/files.py +125 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/resources/projects.py +17 -2
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/resources/workflows.py +72 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/upload_file.py +10 -3
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen.egg-info/PKG-INFO +7 -5
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen.egg-info/SOURCES.txt +2 -0
- {videogen-2.2.0 → videogen-2.5.3}/setup.cfg +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/_http.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/async_create_public_preview.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/async_download_file.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/async_get_hydrated_file.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/async_poll_assistant_message.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/async_poll_project_export.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/async_poll_public_preview.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/async_poll_remix_actions.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/async_poll_timeline_interchange.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/create_public_preview.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/download_file.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/errors.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/get_hydrated_file.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/poll_assistant_message.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/poll_helpers.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/poll_project_export.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/poll_public_preview.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/poll_remix_actions.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/poll_timeline_interchange.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/py.typed +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/resources/__init__.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/resources/account.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/resources/assistant.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/resources/entities.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/resources/resources.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/resources/text.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/resources/tools.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/resources/webhooks.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen/verify_webhook_signature.py +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen.egg-info/dependency_links.txt +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen.egg-info/requires.txt +0 -0
- {videogen-2.2.0 → videogen-2.5.3}/src/videogen.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: videogen
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.5.3
|
|
4
4
|
Summary: Official Python SDK for the VideoGen API
|
|
5
5
|
Author-email: VideoGen <support@videogen.io>
|
|
6
6
|
License: MIT
|
|
@@ -101,7 +101,7 @@ print(run.download_url)
|
|
|
101
101
|
| Area | Client surface | Typical entry points |
|
|
102
102
|
| --- | --- | --- |
|
|
103
103
|
| Account | `vg.account` | `get_me` |
|
|
104
|
-
| Workflows | `vg.workflows` | `script_to_video_and_wait`, `prompt_to_video_clip_and_wait`, `voiceover_to_video_and_wait`, `slideshow_to_video_and_wait` |
|
|
104
|
+
| Workflows | `vg.workflows` | `script_to_video_and_wait`, `prompt_to_video_clip_and_wait`, `voiceover_to_video_and_wait`, `slideshow_to_video_and_wait`, `video_to_video_and_wait` |
|
|
105
105
|
| Tools | `vg.tools` | `generate_image_and_wait`, `generate_video_clip_and_wait`, `text_to_speech_and_wait`, … |
|
|
106
106
|
| Files | helpers on `vg` | `upload_file`, `download_file`, `create_public_preview` |
|
|
107
107
|
| Projects | `vg.projects` | `export_and_wait`, `remix_and_wait`, `create_timeline_interchange_and_wait` |
|
|
@@ -136,7 +136,7 @@ run = vg.workflows.prompt_to_video_clip_and_wait(
|
|
|
136
136
|
print(run.download_url)
|
|
137
137
|
```
|
|
138
138
|
|
|
139
|
-
Other workflow starters: `voiceover_to_video_and_wait` (uploaded audio `file_id`), `slideshow_to_video_and_wait` (deck `file_id`).
|
|
139
|
+
Other workflow starters: `voiceover_to_video_and_wait` (uploaded audio `file_id`), `slideshow_to_video_and_wait` (deck `file_id`), `video_to_video_and_wait` (restyles an uploaded `video_file_id` or a public `video_url` from a `prompt`).
|
|
140
140
|
|
|
141
141
|
## Tools
|
|
142
142
|
|
|
@@ -284,8 +284,8 @@ Exported as module functions and bound on the client:
|
|
|
284
284
|
| Helper | Purpose |
|
|
285
285
|
| --- | --- |
|
|
286
286
|
| `poll_assistant_message` / `async_poll_assistant_message` | Poll an assistant message to a terminal status |
|
|
287
|
-
| `poll_executed_tool` / `async_poll_executed_tool` | Poll a tool execution to a terminal status |
|
|
288
|
-
| `poll_workflow_run` / `async_poll_workflow_run` | Poll a workflow run |
|
|
287
|
+
| `poll_executed_tool` / `async_poll_executed_tool` | Poll a tool execution to a terminal status or `awaiting_approval` |
|
|
288
|
+
| `poll_workflow_run` / `async_poll_workflow_run` | Poll a workflow run to a terminal status or `awaiting_approval` |
|
|
289
289
|
| `poll_project_export` / `async_poll_project_export` | Poll a project export |
|
|
290
290
|
| `poll_timeline_interchange` / `async_poll_timeline_interchange` | Poll a timeline interchange job |
|
|
291
291
|
| `poll_remix_actions` / `async_poll_remix_actions` | Poll remix actions until all are terminal |
|
|
@@ -296,6 +296,8 @@ Exported as module functions and bound on the client:
|
|
|
296
296
|
| `create_public_preview` / `async_create_public_preview` | Enable + poll public preview |
|
|
297
297
|
| `verify_webhook_signature` | Verify Standard Webhooks and return the event dict |
|
|
298
298
|
|
|
299
|
+
Workflow and tool pollers, including their `*_and_wait` wrappers, return `awaiting_approval` unchanged without throwing, even with the default `throw_on_failure=True`. This status means the result needs approval; it does not mean the operation succeeded. Check `status` before using the result as a completed operation.
|
|
300
|
+
|
|
299
301
|
Cancellation: pass `cancel_event=threading.Event()` (sync) or `asyncio.Event()` (async) to poll helpers and thin request methods. Setting the event raises `PollCancelledError`.
|
|
300
302
|
|
|
301
303
|
## Errors
|
|
@@ -80,7 +80,7 @@ print(run.download_url)
|
|
|
80
80
|
| Area | Client surface | Typical entry points |
|
|
81
81
|
| --- | --- | --- |
|
|
82
82
|
| Account | `vg.account` | `get_me` |
|
|
83
|
-
| Workflows | `vg.workflows` | `script_to_video_and_wait`, `prompt_to_video_clip_and_wait`, `voiceover_to_video_and_wait`, `slideshow_to_video_and_wait` |
|
|
83
|
+
| Workflows | `vg.workflows` | `script_to_video_and_wait`, `prompt_to_video_clip_and_wait`, `voiceover_to_video_and_wait`, `slideshow_to_video_and_wait`, `video_to_video_and_wait` |
|
|
84
84
|
| Tools | `vg.tools` | `generate_image_and_wait`, `generate_video_clip_and_wait`, `text_to_speech_and_wait`, … |
|
|
85
85
|
| Files | helpers on `vg` | `upload_file`, `download_file`, `create_public_preview` |
|
|
86
86
|
| Projects | `vg.projects` | `export_and_wait`, `remix_and_wait`, `create_timeline_interchange_and_wait` |
|
|
@@ -115,7 +115,7 @@ run = vg.workflows.prompt_to_video_clip_and_wait(
|
|
|
115
115
|
print(run.download_url)
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
-
Other workflow starters: `voiceover_to_video_and_wait` (uploaded audio `file_id`), `slideshow_to_video_and_wait` (deck `file_id`).
|
|
118
|
+
Other workflow starters: `voiceover_to_video_and_wait` (uploaded audio `file_id`), `slideshow_to_video_and_wait` (deck `file_id`), `video_to_video_and_wait` (restyles an uploaded `video_file_id` or a public `video_url` from a `prompt`).
|
|
119
119
|
|
|
120
120
|
## Tools
|
|
121
121
|
|
|
@@ -263,8 +263,8 @@ Exported as module functions and bound on the client:
|
|
|
263
263
|
| Helper | Purpose |
|
|
264
264
|
| --- | --- |
|
|
265
265
|
| `poll_assistant_message` / `async_poll_assistant_message` | Poll an assistant message to a terminal status |
|
|
266
|
-
| `poll_executed_tool` / `async_poll_executed_tool` | Poll a tool execution to a terminal status |
|
|
267
|
-
| `poll_workflow_run` / `async_poll_workflow_run` | Poll a workflow run |
|
|
266
|
+
| `poll_executed_tool` / `async_poll_executed_tool` | Poll a tool execution to a terminal status or `awaiting_approval` |
|
|
267
|
+
| `poll_workflow_run` / `async_poll_workflow_run` | Poll a workflow run to a terminal status or `awaiting_approval` |
|
|
268
268
|
| `poll_project_export` / `async_poll_project_export` | Poll a project export |
|
|
269
269
|
| `poll_timeline_interchange` / `async_poll_timeline_interchange` | Poll a timeline interchange job |
|
|
270
270
|
| `poll_remix_actions` / `async_poll_remix_actions` | Poll remix actions until all are terminal |
|
|
@@ -275,6 +275,8 @@ Exported as module functions and bound on the client:
|
|
|
275
275
|
| `create_public_preview` / `async_create_public_preview` | Enable + poll public preview |
|
|
276
276
|
| `verify_webhook_signature` | Verify Standard Webhooks and return the event dict |
|
|
277
277
|
|
|
278
|
+
Workflow and tool pollers, including their `*_and_wait` wrappers, return `awaiting_approval` unchanged without throwing, even with the default `throw_on_failure=True`. This status means the result needs approval; it does not mean the operation succeeded. Check `status` before using the result as a completed operation.
|
|
279
|
+
|
|
278
280
|
Cancellation: pass `cancel_event=threading.Event()` (sync) or `asyncio.Event()` (async) to poll helpers and thin request methods. Setting the event raises `PollCancelledError`.
|
|
279
281
|
|
|
280
282
|
## Errors
|
|
@@ -9,6 +9,7 @@ from .async_download_file import async_download_file
|
|
|
9
9
|
from .async_get_hydrated_file import async_get_hydrated_file
|
|
10
10
|
from .async_poll_assistant_message import async_poll_assistant_message
|
|
11
11
|
from .async_poll_executed_tool import async_poll_executed_tool
|
|
12
|
+
from .async_poll_file_url_import import async_poll_file_url_import
|
|
12
13
|
from .async_poll_project_export import async_poll_project_export
|
|
13
14
|
from .async_poll_public_preview import async_poll_public_preview
|
|
14
15
|
from .async_poll_remix_actions import async_poll_remix_actions
|
|
@@ -22,6 +23,7 @@ from .errors import PollCancelledError, VideoGenError
|
|
|
22
23
|
from .get_hydrated_file import get_hydrated_file
|
|
23
24
|
from .poll_assistant_message import poll_assistant_message
|
|
24
25
|
from .poll_executed_tool import poll_executed_tool
|
|
26
|
+
from .poll_file_url_import import poll_file_url_import
|
|
25
27
|
from .poll_project_export import poll_project_export
|
|
26
28
|
from .poll_public_preview import poll_public_preview
|
|
27
29
|
from .poll_remix_actions import poll_remix_actions
|
|
@@ -40,6 +42,7 @@ __all__ = [
|
|
|
40
42
|
"async_get_hydrated_file",
|
|
41
43
|
"async_poll_assistant_message",
|
|
42
44
|
"async_poll_executed_tool",
|
|
45
|
+
"async_poll_file_url_import",
|
|
43
46
|
"async_poll_project_export",
|
|
44
47
|
"async_poll_public_preview",
|
|
45
48
|
"async_poll_remix_actions",
|
|
@@ -51,6 +54,7 @@ __all__ = [
|
|
|
51
54
|
"get_hydrated_file",
|
|
52
55
|
"poll_assistant_message",
|
|
53
56
|
"poll_executed_tool",
|
|
57
|
+
"poll_file_url_import",
|
|
54
58
|
"poll_project_export",
|
|
55
59
|
"poll_public_preview",
|
|
56
60
|
"poll_remix_actions",
|
|
@@ -30,6 +30,8 @@ async def async_poll_executed_tool(
|
|
|
30
30
|
tool_execution_id=tool_execution_id,
|
|
31
31
|
cancel_event=cancel_event,
|
|
32
32
|
)
|
|
33
|
+
if isinstance(executed, dict) and executed.get("status") == "awaiting_approval":
|
|
34
|
+
return executed
|
|
33
35
|
if isinstance(executed, dict) and executed.get("status") in TERMINAL_STATUSES:
|
|
34
36
|
raise_if_failed(executed, throw_on_failure=throw_on_failure, kind="Tool execution")
|
|
35
37
|
return executed
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
from typing import Any, Optional
|
|
5
|
+
|
|
6
|
+
from .poll_helpers import (
|
|
7
|
+
TERMINAL_STATUSES,
|
|
8
|
+
async_poll_sleep,
|
|
9
|
+
ensure_within_timeout,
|
|
10
|
+
poll_raise_if_cancelled,
|
|
11
|
+
raise_if_failed,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
async def async_poll_file_url_import(
|
|
16
|
+
client: Any,
|
|
17
|
+
file_import_id: str,
|
|
18
|
+
*,
|
|
19
|
+
poll_interval_ms: int = 1500,
|
|
20
|
+
timeout_ms: Optional[int] = 3_600_000,
|
|
21
|
+
throw_on_failure: bool = True,
|
|
22
|
+
cancel_event: Any = None,
|
|
23
|
+
) -> dict:
|
|
24
|
+
"""Async twin of `poll_file_url_import`."""
|
|
25
|
+
started_at = time.monotonic()
|
|
26
|
+
while True:
|
|
27
|
+
poll_raise_if_cancelled(cancel_event)
|
|
28
|
+
ensure_within_timeout(started_at=started_at, timeout_ms=timeout_ms)
|
|
29
|
+
file_url_import = await client.files.get_file_url_import(
|
|
30
|
+
file_import_id=file_import_id,
|
|
31
|
+
cancel_event=cancel_event,
|
|
32
|
+
)
|
|
33
|
+
if isinstance(file_url_import, dict) and file_url_import.get("status") in TERMINAL_STATUSES:
|
|
34
|
+
raise_if_failed(
|
|
35
|
+
file_url_import, throw_on_failure=throw_on_failure, kind="File import"
|
|
36
|
+
)
|
|
37
|
+
return file_url_import
|
|
38
|
+
await async_poll_sleep(poll_interval_ms, cancel_event)
|
|
@@ -35,6 +35,8 @@ async def async_poll_workflow_run(
|
|
|
35
35
|
progress = run.get("progress_percentage")
|
|
36
36
|
if on_progress is not None and isinstance(progress, (int, float)):
|
|
37
37
|
on_progress(float(progress))
|
|
38
|
+
if run.get("status") == "awaiting_approval":
|
|
39
|
+
return run
|
|
38
40
|
if run.get("status") in TERMINAL_STATUSES:
|
|
39
41
|
raise_if_failed(run, throw_on_failure=throw_on_failure, kind="Workflow run")
|
|
40
42
|
return run
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import time
|
|
4
|
+
import warnings
|
|
4
5
|
from typing import Any, BinaryIO, Optional, Union
|
|
5
6
|
|
|
6
7
|
import httpx
|
|
@@ -29,16 +30,22 @@ async def async_upload_file(
|
|
|
29
30
|
type: Optional file type (IMAGE, VIDEO, AUDIO, PDF, SLIDESHOW, LOTTIE).
|
|
30
31
|
If omitted, auto-detected. Lottie animations (Bodymovin JSON) must
|
|
31
32
|
set LOTTIE explicitly.
|
|
32
|
-
hide_from_ui:
|
|
33
|
-
|
|
33
|
+
hide_from_ui: Deprecated and ignored. Uploaded files always appear in
|
|
34
|
+
the VideoGen app. Passing a value emits a ``DeprecationWarning``.
|
|
34
35
|
timeout_ms: Maximum time in ms to wait for processing. Defaults to
|
|
35
36
|
3_600_000 (1 hour).
|
|
36
37
|
"""
|
|
38
|
+
if hide_from_ui is not None:
|
|
39
|
+
warnings.warn(
|
|
40
|
+
"async_upload_file(hide_from_ui=...) is deprecated and ignored. "
|
|
41
|
+
"Uploaded files always appear in the VideoGen app.",
|
|
42
|
+
DeprecationWarning,
|
|
43
|
+
stacklevel=2,
|
|
44
|
+
)
|
|
37
45
|
if display_name is None:
|
|
38
46
|
display_name = "upload"
|
|
39
47
|
body: dict[str, Any] = {
|
|
40
48
|
"display_name": display_name,
|
|
41
|
-
"hide_from_ui": False if hide_from_ui is None else hide_from_ui,
|
|
42
49
|
}
|
|
43
50
|
if type is not None:
|
|
44
51
|
body["type"] = type
|
|
@@ -10,6 +10,7 @@ from .async_download_file import async_download_file
|
|
|
10
10
|
from .async_get_hydrated_file import async_get_hydrated_file
|
|
11
11
|
from .async_poll_assistant_message import async_poll_assistant_message
|
|
12
12
|
from .async_poll_executed_tool import async_poll_executed_tool
|
|
13
|
+
from .async_poll_file_url_import import async_poll_file_url_import
|
|
13
14
|
from .async_poll_project_export import async_poll_project_export
|
|
14
15
|
from .async_poll_public_preview import async_poll_public_preview
|
|
15
16
|
from .async_poll_remix_actions import async_poll_remix_actions
|
|
@@ -21,6 +22,7 @@ from .download_file import download_file
|
|
|
21
22
|
from .get_hydrated_file import get_hydrated_file
|
|
22
23
|
from .poll_assistant_message import poll_assistant_message
|
|
23
24
|
from .poll_executed_tool import poll_executed_tool
|
|
25
|
+
from .poll_file_url_import import poll_file_url_import
|
|
24
26
|
from .poll_project_export import poll_project_export
|
|
25
27
|
from .poll_public_preview import poll_public_preview
|
|
26
28
|
from .poll_remix_actions import poll_remix_actions
|
|
@@ -112,6 +114,9 @@ class VideoGen:
|
|
|
112
114
|
def poll_timeline_interchange(self, interchange_job_id: str, **kwargs: Any) -> dict:
|
|
113
115
|
return poll_timeline_interchange(self, interchange_job_id, **kwargs)
|
|
114
116
|
|
|
117
|
+
def poll_file_url_import(self, file_import_id: str, **kwargs: Any) -> dict:
|
|
118
|
+
return poll_file_url_import(self, file_import_id, **kwargs)
|
|
119
|
+
|
|
115
120
|
def poll_remix_actions(self, project_id: str, **kwargs: Any) -> dict:
|
|
116
121
|
return poll_remix_actions(self, project_id, **kwargs)
|
|
117
122
|
|
|
@@ -210,6 +215,9 @@ class AsyncVideoGen:
|
|
|
210
215
|
) -> dict:
|
|
211
216
|
return await async_poll_timeline_interchange(self, interchange_job_id, **kwargs)
|
|
212
217
|
|
|
218
|
+
async def poll_file_url_import(self, file_import_id: str, **kwargs: Any) -> dict:
|
|
219
|
+
return await async_poll_file_url_import(self, file_import_id, **kwargs)
|
|
220
|
+
|
|
213
221
|
async def poll_remix_actions(self, project_id: str, **kwargs: Any) -> dict:
|
|
214
222
|
return await async_poll_remix_actions(self, project_id, **kwargs)
|
|
215
223
|
|
|
@@ -21,7 +21,7 @@ def poll_executed_tool(
|
|
|
21
21
|
throw_on_failure: bool = True,
|
|
22
22
|
cancel_event: Any = None,
|
|
23
23
|
) -> dict:
|
|
24
|
-
"""Poll
|
|
24
|
+
"""Poll until succeeded / failed / cancelled or awaiting approval."""
|
|
25
25
|
started_at = time.monotonic()
|
|
26
26
|
while True:
|
|
27
27
|
poll_raise_if_cancelled(cancel_event)
|
|
@@ -30,6 +30,8 @@ def poll_executed_tool(
|
|
|
30
30
|
tool_execution_id=tool_execution_id,
|
|
31
31
|
cancel_event=cancel_event,
|
|
32
32
|
)
|
|
33
|
+
if isinstance(executed, dict) and executed.get("status") == "awaiting_approval":
|
|
34
|
+
return executed
|
|
33
35
|
if isinstance(executed, dict) and executed.get("status") in TERMINAL_STATUSES:
|
|
34
36
|
raise_if_failed(executed, throw_on_failure=throw_on_failure, kind="Tool execution")
|
|
35
37
|
return executed
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
from typing import Any, Optional
|
|
5
|
+
|
|
6
|
+
from .poll_helpers import (
|
|
7
|
+
TERMINAL_STATUSES,
|
|
8
|
+
ensure_within_timeout,
|
|
9
|
+
poll_raise_if_cancelled,
|
|
10
|
+
poll_sleep,
|
|
11
|
+
raise_if_failed,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def poll_file_url_import(
|
|
16
|
+
client: Any,
|
|
17
|
+
file_import_id: str,
|
|
18
|
+
*,
|
|
19
|
+
poll_interval_ms: int = 1500,
|
|
20
|
+
timeout_ms: Optional[int] = 3_600_000,
|
|
21
|
+
throw_on_failure: bool = True,
|
|
22
|
+
cancel_event: Any = None,
|
|
23
|
+
) -> dict:
|
|
24
|
+
"""Poll `get_file_url_import` until succeeded / failed / cancelled."""
|
|
25
|
+
started_at = time.monotonic()
|
|
26
|
+
while True:
|
|
27
|
+
poll_raise_if_cancelled(cancel_event)
|
|
28
|
+
ensure_within_timeout(started_at=started_at, timeout_ms=timeout_ms)
|
|
29
|
+
file_url_import = client.files.get_file_url_import(
|
|
30
|
+
file_import_id=file_import_id,
|
|
31
|
+
cancel_event=cancel_event,
|
|
32
|
+
)
|
|
33
|
+
if isinstance(file_url_import, dict) and file_url_import.get("status") in TERMINAL_STATUSES:
|
|
34
|
+
raise_if_failed(
|
|
35
|
+
file_url_import, throw_on_failure=throw_on_failure, kind="File import"
|
|
36
|
+
)
|
|
37
|
+
return file_url_import
|
|
38
|
+
poll_sleep(poll_interval_ms, cancel_event)
|
|
@@ -22,7 +22,7 @@ def poll_workflow_run(
|
|
|
22
22
|
on_progress: Optional[Callable[[float], None]] = None,
|
|
23
23
|
cancel_event: Any = None,
|
|
24
24
|
) -> dict:
|
|
25
|
-
"""Poll
|
|
25
|
+
"""Poll until succeeded / failed / cancelled or awaiting approval."""
|
|
26
26
|
started_at = time.monotonic()
|
|
27
27
|
while True:
|
|
28
28
|
poll_raise_if_cancelled(cancel_event)
|
|
@@ -35,6 +35,8 @@ def poll_workflow_run(
|
|
|
35
35
|
progress = run.get("progress_percentage")
|
|
36
36
|
if on_progress is not None and isinstance(progress, (int, float)):
|
|
37
37
|
on_progress(float(progress))
|
|
38
|
+
if run.get("status") == "awaiting_approval":
|
|
39
|
+
return run
|
|
38
40
|
if run.get("status") in TERMINAL_STATUSES:
|
|
39
41
|
raise_if_failed(run, throw_on_failure=throw_on_failure, kind="Workflow run")
|
|
40
42
|
return run
|
|
@@ -4,6 +4,9 @@ from typing import Any, TYPE_CHECKING
|
|
|
4
4
|
|
|
5
5
|
from .._http import camel_to_snake, format_path, split_request_args
|
|
6
6
|
|
|
7
|
+
from ..poll_file_url_import import poll_file_url_import
|
|
8
|
+
from ..async_poll_file_url_import import async_poll_file_url_import
|
|
9
|
+
|
|
7
10
|
if TYPE_CHECKING:
|
|
8
11
|
from ..client import AsyncVideoGen, VideoGen
|
|
9
12
|
|
|
@@ -94,6 +97,67 @@ class FilesResource:
|
|
|
94
97
|
cancel_event=cancel_event,
|
|
95
98
|
)
|
|
96
99
|
|
|
100
|
+
# @sdk-operation createFileUrlImport
|
|
101
|
+
def create_file_url_import(self, *args: Any, **kwargs: Any) -> Any:
|
|
102
|
+
if args:
|
|
103
|
+
raise TypeError(f'create_file_url_import() does not take positional arguments')
|
|
104
|
+
path_values, query_values, body, cancel_event = split_request_args(
|
|
105
|
+
kwargs,
|
|
106
|
+
path_params=[],
|
|
107
|
+
query_params=[],
|
|
108
|
+
)
|
|
109
|
+
path = format_path('/v1/files/import-url', path_values)
|
|
110
|
+
return self._client.request(
|
|
111
|
+
method='POST',
|
|
112
|
+
path=path,
|
|
113
|
+
query=query_values or None,
|
|
114
|
+
body=body if body is not None else {},
|
|
115
|
+
cancel_event=cancel_event,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
def create_file_url_import_and_wait(self, *args: Any, **kwargs: Any) -> Any:
|
|
119
|
+
poll_interval_ms = kwargs.pop('poll_interval_ms', 1500)
|
|
120
|
+
timeout_ms = kwargs.pop('timeout_ms', 3_600_000)
|
|
121
|
+
throw_on_failure = kwargs.pop('throw_on_failure', True)
|
|
122
|
+
cancel_event = kwargs.get('cancel_event')
|
|
123
|
+
started = self.create_file_url_import(*args, **kwargs)
|
|
124
|
+
file_import_id = started['file_import_id']
|
|
125
|
+
return poll_file_url_import(
|
|
126
|
+
self._root,
|
|
127
|
+
file_import_id,
|
|
128
|
+
poll_interval_ms=poll_interval_ms,
|
|
129
|
+
timeout_ms=timeout_ms,
|
|
130
|
+
throw_on_failure=throw_on_failure,
|
|
131
|
+
cancel_event=cancel_event,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
# @sdk-operation getFileUrlImport
|
|
135
|
+
def get_file_url_import(self, *args: Any, **kwargs: Any) -> Any:
|
|
136
|
+
path_param_names = ['file_import_id']
|
|
137
|
+
if args:
|
|
138
|
+
if len(args) > len(path_param_names):
|
|
139
|
+
raise TypeError(f'get_file_url_import() takes at most {len(path_param_names)} positional argument(s)')
|
|
140
|
+
for name, value in zip(path_param_names, args):
|
|
141
|
+
if name in kwargs:
|
|
142
|
+
raise TypeError(f"{name} specified twice")
|
|
143
|
+
kwargs[name] = value
|
|
144
|
+
path_values, query_values, body, cancel_event = split_request_args(
|
|
145
|
+
kwargs,
|
|
146
|
+
path_params=['fileImportId'],
|
|
147
|
+
query_params=[],
|
|
148
|
+
)
|
|
149
|
+
for required in ['fileImportId']:
|
|
150
|
+
if required not in path_values:
|
|
151
|
+
raise TypeError(f"missing required argument: {camel_to_snake(required)}")
|
|
152
|
+
path = format_path('/v1/files/imports/{fileImportId}', path_values)
|
|
153
|
+
return self._client.request(
|
|
154
|
+
method='GET',
|
|
155
|
+
path=path,
|
|
156
|
+
query=query_values or None,
|
|
157
|
+
body=body,
|
|
158
|
+
cancel_event=cancel_event,
|
|
159
|
+
)
|
|
160
|
+
|
|
97
161
|
# @sdk-operation hydrateFile
|
|
98
162
|
def hydrate_file(self, *args: Any, **kwargs: Any) -> Any:
|
|
99
163
|
path_param_names = ['file_id']
|
|
@@ -289,6 +353,67 @@ class AsyncFilesResource:
|
|
|
289
353
|
cancel_event=cancel_event,
|
|
290
354
|
)
|
|
291
355
|
|
|
356
|
+
# @sdk-operation createFileUrlImport
|
|
357
|
+
async def create_file_url_import(self, *args: Any, **kwargs: Any) -> Any:
|
|
358
|
+
if args:
|
|
359
|
+
raise TypeError(f'create_file_url_import() does not take positional arguments')
|
|
360
|
+
path_values, query_values, body, cancel_event = split_request_args(
|
|
361
|
+
kwargs,
|
|
362
|
+
path_params=[],
|
|
363
|
+
query_params=[],
|
|
364
|
+
)
|
|
365
|
+
path = format_path('/v1/files/import-url', path_values)
|
|
366
|
+
return await self._client.request(
|
|
367
|
+
method='POST',
|
|
368
|
+
path=path,
|
|
369
|
+
query=query_values or None,
|
|
370
|
+
body=body if body is not None else {},
|
|
371
|
+
cancel_event=cancel_event,
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
async def create_file_url_import_and_wait(self, *args: Any, **kwargs: Any) -> Any:
|
|
375
|
+
poll_interval_ms = kwargs.pop('poll_interval_ms', 1500)
|
|
376
|
+
timeout_ms = kwargs.pop('timeout_ms', 3_600_000)
|
|
377
|
+
throw_on_failure = kwargs.pop('throw_on_failure', True)
|
|
378
|
+
cancel_event = kwargs.get('cancel_event')
|
|
379
|
+
started = await self.create_file_url_import(*args, **kwargs)
|
|
380
|
+
file_import_id = started['file_import_id']
|
|
381
|
+
return await async_poll_file_url_import(
|
|
382
|
+
self._root,
|
|
383
|
+
file_import_id,
|
|
384
|
+
poll_interval_ms=poll_interval_ms,
|
|
385
|
+
timeout_ms=timeout_ms,
|
|
386
|
+
throw_on_failure=throw_on_failure,
|
|
387
|
+
cancel_event=cancel_event,
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
# @sdk-operation getFileUrlImport
|
|
391
|
+
async def get_file_url_import(self, *args: Any, **kwargs: Any) -> Any:
|
|
392
|
+
path_param_names = ['file_import_id']
|
|
393
|
+
if args:
|
|
394
|
+
if len(args) > len(path_param_names):
|
|
395
|
+
raise TypeError(f'get_file_url_import() takes at most {len(path_param_names)} positional argument(s)')
|
|
396
|
+
for name, value in zip(path_param_names, args):
|
|
397
|
+
if name in kwargs:
|
|
398
|
+
raise TypeError(f"{name} specified twice")
|
|
399
|
+
kwargs[name] = value
|
|
400
|
+
path_values, query_values, body, cancel_event = split_request_args(
|
|
401
|
+
kwargs,
|
|
402
|
+
path_params=['fileImportId'],
|
|
403
|
+
query_params=[],
|
|
404
|
+
)
|
|
405
|
+
for required in ['fileImportId']:
|
|
406
|
+
if required not in path_values:
|
|
407
|
+
raise TypeError(f"missing required argument: {camel_to_snake(required)}")
|
|
408
|
+
path = format_path('/v1/files/imports/{fileImportId}', path_values)
|
|
409
|
+
return await self._client.request(
|
|
410
|
+
method='GET',
|
|
411
|
+
path=path,
|
|
412
|
+
query=query_values or None,
|
|
413
|
+
body=body,
|
|
414
|
+
cancel_event=cancel_event,
|
|
415
|
+
)
|
|
416
|
+
|
|
292
417
|
# @sdk-operation hydrateFile
|
|
293
418
|
async def hydrate_file(self, *args: Any, **kwargs: Any) -> Any:
|
|
294
419
|
path_param_names = ['file_id']
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import warnings
|
|
3
4
|
from typing import Any, TYPE_CHECKING
|
|
4
5
|
|
|
5
6
|
from .._http import camel_to_snake, format_path, split_request_args
|
|
@@ -15,6 +16,18 @@ if TYPE_CHECKING:
|
|
|
15
16
|
from ..client import AsyncVideoGen, VideoGen
|
|
16
17
|
|
|
17
18
|
|
|
19
|
+
def _pop_deprecated_include_ui_projects(kwargs: dict[str, Any]) -> None:
|
|
20
|
+
# Unknown kwargs become the request body, so drop this before splitting.
|
|
21
|
+
values = [kwargs.pop(key, None) for key in ('include_ui_projects', 'includeUiProjects')]
|
|
22
|
+
if any(value is not None for value in values):
|
|
23
|
+
warnings.warn(
|
|
24
|
+
"list_projects(include_ui_projects=...) is deprecated and ignored. "
|
|
25
|
+
"The list always includes projects created in the VideoGen app.",
|
|
26
|
+
DeprecationWarning,
|
|
27
|
+
stacklevel=3,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
18
31
|
class ProjectsResource:
|
|
19
32
|
def __init__(self, client: VideoGen) -> None:
|
|
20
33
|
self._root = client
|
|
@@ -24,10 +37,11 @@ class ProjectsResource:
|
|
|
24
37
|
def list_projects(self, *args: Any, **kwargs: Any) -> Any:
|
|
25
38
|
if args:
|
|
26
39
|
raise TypeError(f'list_projects() does not take positional arguments')
|
|
40
|
+
_pop_deprecated_include_ui_projects(kwargs)
|
|
27
41
|
path_values, query_values, body, cancel_event = split_request_args(
|
|
28
42
|
kwargs,
|
|
29
43
|
path_params=[],
|
|
30
|
-
query_params=['limit', 'cursor', 'selfOnly'
|
|
44
|
+
query_params=['limit', 'cursor', 'selfOnly'],
|
|
31
45
|
)
|
|
32
46
|
path = format_path('/v1/projects', path_values)
|
|
33
47
|
return self._client.request(
|
|
@@ -323,10 +337,11 @@ class AsyncProjectsResource:
|
|
|
323
337
|
async def list_projects(self, *args: Any, **kwargs: Any) -> Any:
|
|
324
338
|
if args:
|
|
325
339
|
raise TypeError(f'list_projects() does not take positional arguments')
|
|
340
|
+
_pop_deprecated_include_ui_projects(kwargs)
|
|
326
341
|
path_values, query_values, body, cancel_event = split_request_args(
|
|
327
342
|
kwargs,
|
|
328
343
|
path_params=[],
|
|
329
|
-
query_params=['limit', 'cursor', 'selfOnly'
|
|
344
|
+
query_params=['limit', 'cursor', 'selfOnly'],
|
|
330
345
|
)
|
|
331
346
|
path = format_path('/v1/projects', path_values)
|
|
332
347
|
return await self._client.request(
|
|
@@ -88,6 +88,24 @@ class WorkflowsResource:
|
|
|
88
88
|
cancel_event=cancel_event,
|
|
89
89
|
)
|
|
90
90
|
|
|
91
|
+
# @sdk-operation videoToVideo
|
|
92
|
+
def video_to_video(self, *args: Any, **kwargs: Any) -> Any:
|
|
93
|
+
if args:
|
|
94
|
+
raise TypeError(f'video_to_video() does not take positional arguments')
|
|
95
|
+
path_values, query_values, body, cancel_event = split_request_args(
|
|
96
|
+
kwargs,
|
|
97
|
+
path_params=[],
|
|
98
|
+
query_params=[],
|
|
99
|
+
)
|
|
100
|
+
path = format_path('/v1/workflows/video-to-video', path_values)
|
|
101
|
+
return self._client.request(
|
|
102
|
+
method='POST',
|
|
103
|
+
path=path,
|
|
104
|
+
query=query_values or None,
|
|
105
|
+
body=body if body is not None else {},
|
|
106
|
+
cancel_event=cancel_event,
|
|
107
|
+
)
|
|
108
|
+
|
|
91
109
|
# @sdk-operation listWorkflowRuns
|
|
92
110
|
def list_workflow_runs(self, *args: Any, **kwargs: Any) -> Any:
|
|
93
111
|
if args:
|
|
@@ -232,6 +250,24 @@ class WorkflowsResource:
|
|
|
232
250
|
cancel_event=cancel_event,
|
|
233
251
|
)
|
|
234
252
|
|
|
253
|
+
def video_to_video_and_wait(self, *args: Any, **kwargs: Any) -> Any:
|
|
254
|
+
poll_interval_ms = kwargs.pop('poll_interval_ms', 1500)
|
|
255
|
+
timeout_ms = kwargs.pop('timeout_ms', 3_600_000)
|
|
256
|
+
throw_on_failure = kwargs.pop('throw_on_failure', True)
|
|
257
|
+
on_progress = kwargs.pop('on_progress', None)
|
|
258
|
+
cancel_event = kwargs.get('cancel_event')
|
|
259
|
+
started = self.video_to_video(*args, **kwargs)
|
|
260
|
+
workflow_run_id = started['workflow_run_id']
|
|
261
|
+
return poll_workflow_run(
|
|
262
|
+
self._root,
|
|
263
|
+
workflow_run_id,
|
|
264
|
+
poll_interval_ms=poll_interval_ms,
|
|
265
|
+
timeout_ms=timeout_ms,
|
|
266
|
+
throw_on_failure=throw_on_failure,
|
|
267
|
+
on_progress=on_progress,
|
|
268
|
+
cancel_event=cancel_event,
|
|
269
|
+
)
|
|
270
|
+
|
|
235
271
|
class AsyncWorkflowsResource:
|
|
236
272
|
def __init__(self, client: AsyncVideoGen) -> None:
|
|
237
273
|
self._root = client
|
|
@@ -309,6 +345,24 @@ class AsyncWorkflowsResource:
|
|
|
309
345
|
cancel_event=cancel_event,
|
|
310
346
|
)
|
|
311
347
|
|
|
348
|
+
# @sdk-operation videoToVideo
|
|
349
|
+
async def video_to_video(self, *args: Any, **kwargs: Any) -> Any:
|
|
350
|
+
if args:
|
|
351
|
+
raise TypeError(f'video_to_video() does not take positional arguments')
|
|
352
|
+
path_values, query_values, body, cancel_event = split_request_args(
|
|
353
|
+
kwargs,
|
|
354
|
+
path_params=[],
|
|
355
|
+
query_params=[],
|
|
356
|
+
)
|
|
357
|
+
path = format_path('/v1/workflows/video-to-video', path_values)
|
|
358
|
+
return await self._client.request(
|
|
359
|
+
method='POST',
|
|
360
|
+
path=path,
|
|
361
|
+
query=query_values or None,
|
|
362
|
+
body=body if body is not None else {},
|
|
363
|
+
cancel_event=cancel_event,
|
|
364
|
+
)
|
|
365
|
+
|
|
312
366
|
# @sdk-operation listWorkflowRuns
|
|
313
367
|
async def list_workflow_runs(self, *args: Any, **kwargs: Any) -> Any:
|
|
314
368
|
if args:
|
|
@@ -452,3 +506,21 @@ class AsyncWorkflowsResource:
|
|
|
452
506
|
on_progress=on_progress,
|
|
453
507
|
cancel_event=cancel_event,
|
|
454
508
|
)
|
|
509
|
+
|
|
510
|
+
async def video_to_video_and_wait(self, *args: Any, **kwargs: Any) -> Any:
|
|
511
|
+
poll_interval_ms = kwargs.pop('poll_interval_ms', 1500)
|
|
512
|
+
timeout_ms = kwargs.pop('timeout_ms', 3_600_000)
|
|
513
|
+
throw_on_failure = kwargs.pop('throw_on_failure', True)
|
|
514
|
+
on_progress = kwargs.pop('on_progress', None)
|
|
515
|
+
cancel_event = kwargs.get('cancel_event')
|
|
516
|
+
started = await self.video_to_video(*args, **kwargs)
|
|
517
|
+
workflow_run_id = started['workflow_run_id']
|
|
518
|
+
return await async_poll_workflow_run(
|
|
519
|
+
self._root,
|
|
520
|
+
workflow_run_id,
|
|
521
|
+
poll_interval_ms=poll_interval_ms,
|
|
522
|
+
timeout_ms=timeout_ms,
|
|
523
|
+
throw_on_failure=throw_on_failure,
|
|
524
|
+
on_progress=on_progress,
|
|
525
|
+
cancel_event=cancel_event,
|
|
526
|
+
)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import time
|
|
4
|
+
import warnings
|
|
4
5
|
from typing import Any, BinaryIO, Optional, Union
|
|
5
6
|
|
|
6
7
|
import httpx
|
|
@@ -58,8 +59,8 @@ def upload_file(
|
|
|
58
59
|
type: Optional file type (IMAGE, VIDEO, AUDIO, PDF, SLIDESHOW, LOTTIE).
|
|
59
60
|
If omitted, auto-detected. Lottie animations (Bodymovin JSON) must
|
|
60
61
|
set LOTTIE explicitly.
|
|
61
|
-
hide_from_ui:
|
|
62
|
-
|
|
62
|
+
hide_from_ui: Deprecated and ignored. Uploaded files always appear in
|
|
63
|
+
the VideoGen app. Passing a value emits a ``DeprecationWarning``.
|
|
63
64
|
timeout_ms: Maximum time in ms to wait for processing. Defaults to
|
|
64
65
|
3_600_000 (1 hour).
|
|
65
66
|
|
|
@@ -72,11 +73,17 @@ def upload_file(
|
|
|
72
73
|
source means the upload is usable; only fail when something failed and
|
|
73
74
|
nothing is ready.
|
|
74
75
|
"""
|
|
76
|
+
if hide_from_ui is not None:
|
|
77
|
+
warnings.warn(
|
|
78
|
+
"upload_file(hide_from_ui=...) is deprecated and ignored. "
|
|
79
|
+
"Uploaded files always appear in the VideoGen app.",
|
|
80
|
+
DeprecationWarning,
|
|
81
|
+
stacklevel=2,
|
|
82
|
+
)
|
|
75
83
|
if display_name is None:
|
|
76
84
|
display_name = "upload"
|
|
77
85
|
body: dict[str, Any] = {
|
|
78
86
|
"display_name": display_name,
|
|
79
|
-
"hide_from_ui": False if hide_from_ui is None else hide_from_ui,
|
|
80
87
|
}
|
|
81
88
|
if type is not None:
|
|
82
89
|
body["type"] = type
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: videogen
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.5.3
|
|
4
4
|
Summary: Official Python SDK for the VideoGen API
|
|
5
5
|
Author-email: VideoGen <support@videogen.io>
|
|
6
6
|
License: MIT
|
|
@@ -101,7 +101,7 @@ print(run.download_url)
|
|
|
101
101
|
| Area | Client surface | Typical entry points |
|
|
102
102
|
| --- | --- | --- |
|
|
103
103
|
| Account | `vg.account` | `get_me` |
|
|
104
|
-
| Workflows | `vg.workflows` | `script_to_video_and_wait`, `prompt_to_video_clip_and_wait`, `voiceover_to_video_and_wait`, `slideshow_to_video_and_wait` |
|
|
104
|
+
| Workflows | `vg.workflows` | `script_to_video_and_wait`, `prompt_to_video_clip_and_wait`, `voiceover_to_video_and_wait`, `slideshow_to_video_and_wait`, `video_to_video_and_wait` |
|
|
105
105
|
| Tools | `vg.tools` | `generate_image_and_wait`, `generate_video_clip_and_wait`, `text_to_speech_and_wait`, … |
|
|
106
106
|
| Files | helpers on `vg` | `upload_file`, `download_file`, `create_public_preview` |
|
|
107
107
|
| Projects | `vg.projects` | `export_and_wait`, `remix_and_wait`, `create_timeline_interchange_and_wait` |
|
|
@@ -136,7 +136,7 @@ run = vg.workflows.prompt_to_video_clip_and_wait(
|
|
|
136
136
|
print(run.download_url)
|
|
137
137
|
```
|
|
138
138
|
|
|
139
|
-
Other workflow starters: `voiceover_to_video_and_wait` (uploaded audio `file_id`), `slideshow_to_video_and_wait` (deck `file_id`).
|
|
139
|
+
Other workflow starters: `voiceover_to_video_and_wait` (uploaded audio `file_id`), `slideshow_to_video_and_wait` (deck `file_id`), `video_to_video_and_wait` (restyles an uploaded `video_file_id` or a public `video_url` from a `prompt`).
|
|
140
140
|
|
|
141
141
|
## Tools
|
|
142
142
|
|
|
@@ -284,8 +284,8 @@ Exported as module functions and bound on the client:
|
|
|
284
284
|
| Helper | Purpose |
|
|
285
285
|
| --- | --- |
|
|
286
286
|
| `poll_assistant_message` / `async_poll_assistant_message` | Poll an assistant message to a terminal status |
|
|
287
|
-
| `poll_executed_tool` / `async_poll_executed_tool` | Poll a tool execution to a terminal status |
|
|
288
|
-
| `poll_workflow_run` / `async_poll_workflow_run` | Poll a workflow run |
|
|
287
|
+
| `poll_executed_tool` / `async_poll_executed_tool` | Poll a tool execution to a terminal status or `awaiting_approval` |
|
|
288
|
+
| `poll_workflow_run` / `async_poll_workflow_run` | Poll a workflow run to a terminal status or `awaiting_approval` |
|
|
289
289
|
| `poll_project_export` / `async_poll_project_export` | Poll a project export |
|
|
290
290
|
| `poll_timeline_interchange` / `async_poll_timeline_interchange` | Poll a timeline interchange job |
|
|
291
291
|
| `poll_remix_actions` / `async_poll_remix_actions` | Poll remix actions until all are terminal |
|
|
@@ -296,6 +296,8 @@ Exported as module functions and bound on the client:
|
|
|
296
296
|
| `create_public_preview` / `async_create_public_preview` | Enable + poll public preview |
|
|
297
297
|
| `verify_webhook_signature` | Verify Standard Webhooks and return the event dict |
|
|
298
298
|
|
|
299
|
+
Workflow and tool pollers, including their `*_and_wait` wrappers, return `awaiting_approval` unchanged without throwing, even with the default `throw_on_failure=True`. This status means the result needs approval; it does not mean the operation succeeded. Check `status` before using the result as a completed operation.
|
|
300
|
+
|
|
299
301
|
Cancellation: pass `cancel_event=threading.Event()` (sync) or `asyncio.Event()` (async) to poll helpers and thin request methods. Setting the event raises `PollCancelledError`.
|
|
300
302
|
|
|
301
303
|
## Errors
|
|
@@ -7,6 +7,7 @@ src/videogen/async_download_file.py
|
|
|
7
7
|
src/videogen/async_get_hydrated_file.py
|
|
8
8
|
src/videogen/async_poll_assistant_message.py
|
|
9
9
|
src/videogen/async_poll_executed_tool.py
|
|
10
|
+
src/videogen/async_poll_file_url_import.py
|
|
10
11
|
src/videogen/async_poll_project_export.py
|
|
11
12
|
src/videogen/async_poll_public_preview.py
|
|
12
13
|
src/videogen/async_poll_remix_actions.py
|
|
@@ -20,6 +21,7 @@ src/videogen/errors.py
|
|
|
20
21
|
src/videogen/get_hydrated_file.py
|
|
21
22
|
src/videogen/poll_assistant_message.py
|
|
22
23
|
src/videogen/poll_executed_tool.py
|
|
24
|
+
src/videogen/poll_file_url_import.py
|
|
23
25
|
src/videogen/poll_helpers.py
|
|
24
26
|
src/videogen/poll_project_export.py
|
|
25
27
|
src/videogen/poll_public_preview.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|