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.
Files changed (51) hide show
  1. {videogen-2.2.0 → videogen-2.5.3}/PKG-INFO +7 -5
  2. {videogen-2.2.0 → videogen-2.5.3}/README.md +6 -4
  3. {videogen-2.2.0 → videogen-2.5.3}/pyproject.toml +1 -1
  4. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/__init__.py +4 -0
  5. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/async_poll_executed_tool.py +2 -0
  6. videogen-2.5.3/src/videogen/async_poll_file_url_import.py +38 -0
  7. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/async_poll_workflow_run.py +2 -0
  8. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/async_upload_file.py +10 -3
  9. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/client.py +8 -0
  10. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/poll_executed_tool.py +3 -1
  11. videogen-2.5.3/src/videogen/poll_file_url_import.py +38 -0
  12. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/poll_workflow_run.py +3 -1
  13. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/resources/files.py +125 -0
  14. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/resources/projects.py +17 -2
  15. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/resources/workflows.py +72 -0
  16. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/upload_file.py +10 -3
  17. {videogen-2.2.0 → videogen-2.5.3}/src/videogen.egg-info/PKG-INFO +7 -5
  18. {videogen-2.2.0 → videogen-2.5.3}/src/videogen.egg-info/SOURCES.txt +2 -0
  19. {videogen-2.2.0 → videogen-2.5.3}/setup.cfg +0 -0
  20. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/_http.py +0 -0
  21. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/async_create_public_preview.py +0 -0
  22. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/async_download_file.py +0 -0
  23. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/async_get_hydrated_file.py +0 -0
  24. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/async_poll_assistant_message.py +0 -0
  25. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/async_poll_project_export.py +0 -0
  26. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/async_poll_public_preview.py +0 -0
  27. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/async_poll_remix_actions.py +0 -0
  28. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/async_poll_timeline_interchange.py +0 -0
  29. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/create_public_preview.py +0 -0
  30. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/download_file.py +0 -0
  31. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/errors.py +0 -0
  32. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/get_hydrated_file.py +0 -0
  33. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/poll_assistant_message.py +0 -0
  34. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/poll_helpers.py +0 -0
  35. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/poll_project_export.py +0 -0
  36. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/poll_public_preview.py +0 -0
  37. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/poll_remix_actions.py +0 -0
  38. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/poll_timeline_interchange.py +0 -0
  39. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/py.typed +0 -0
  40. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/resources/__init__.py +0 -0
  41. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/resources/account.py +0 -0
  42. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/resources/assistant.py +0 -0
  43. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/resources/entities.py +0 -0
  44. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/resources/resources.py +0 -0
  45. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/resources/text.py +0 -0
  46. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/resources/tools.py +0 -0
  47. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/resources/webhooks.py +0 -0
  48. {videogen-2.2.0 → videogen-2.5.3}/src/videogen/verify_webhook_signature.py +0 -0
  49. {videogen-2.2.0 → videogen-2.5.3}/src/videogen.egg-info/dependency_links.txt +0 -0
  50. {videogen-2.2.0 → videogen-2.5.3}/src/videogen.egg-info/requires.txt +0 -0
  51. {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.2.0
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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "videogen"
7
- version = "2.2.0"
7
+ version = "2.5.3"
8
8
  description = "Official Python SDK for the VideoGen API"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -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: When true, hide the file from the VideoGen Media page.
33
- Defaults to false.
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 `get_tool_execution_info` until succeeded / failed / cancelled."""
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 `get_workflow_run` until succeeded / failed / cancelled."""
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', 'includeUiProjects'],
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', 'includeUiProjects'],
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: When true, hide the file from the VideoGen Media page.
62
- Defaults to false.
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.2.0
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