videopython 0.33.0__tar.gz → 0.33.1__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 (57) hide show
  1. {videopython-0.33.0 → videopython-0.33.1}/PKG-INFO +1 -1
  2. {videopython-0.33.0 → videopython-0.33.1}/pyproject.toml +1 -1
  3. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/generation/audio.py +13 -8
  4. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/generation/image.py +6 -1
  5. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/generation/translation.py +1 -1
  6. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/generation/video.py +21 -13
  7. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/understanding/audio.py +9 -0
  8. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/understanding/image.py +2 -11
  9. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/understanding/temporal.py +12 -6
  10. {videopython-0.33.0 → videopython-0.33.1}/.gitignore +0 -0
  11. {videopython-0.33.0 → videopython-0.33.1}/LICENSE +0 -0
  12. {videopython-0.33.0 → videopython-0.33.1}/README.md +0 -0
  13. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/__init__.py +0 -0
  14. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/__init__.py +0 -0
  15. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/_device.py +0 -0
  16. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/dubbing/__init__.py +0 -0
  17. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/dubbing/config.py +0 -0
  18. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/dubbing/dubber.py +0 -0
  19. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/dubbing/expressiveness.py +0 -0
  20. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/dubbing/loudness.py +0 -0
  21. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/dubbing/models.py +0 -0
  22. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/dubbing/pipeline.py +0 -0
  23. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/dubbing/quality.py +0 -0
  24. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/dubbing/remux.py +0 -0
  25. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/dubbing/timing.py +0 -0
  26. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/dubbing/voice_sample.py +0 -0
  27. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/generation/__init__.py +0 -0
  28. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/generation/qwen3.py +0 -0
  29. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/transforms.py +0 -0
  30. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/understanding/__init__.py +0 -0
  31. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/understanding/faces.py +0 -0
  32. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/understanding/separation.py +0 -0
  33. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/video_analysis/__init__.py +0 -0
  34. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/video_analysis/analyzer.py +0 -0
  35. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/video_analysis/models.py +0 -0
  36. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/video_analysis/sampling.py +0 -0
  37. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/ai/video_analysis/stages.py +0 -0
  38. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/audio/__init__.py +0 -0
  39. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/audio/analysis.py +0 -0
  40. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/audio/audio.py +0 -0
  41. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/base/__init__.py +0 -0
  42. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/base/_dimensions.py +0 -0
  43. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/base/_ffmpeg.py +0 -0
  44. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/base/_video_io.py +0 -0
  45. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/base/description.py +0 -0
  46. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/base/exceptions.py +0 -0
  47. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/base/image_text.py +0 -0
  48. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/base/transcription.py +0 -0
  49. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/base/video.py +0 -0
  50. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/editing/__init__.py +0 -0
  51. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/editing/effects.py +0 -0
  52. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/editing/operation.py +0 -0
  53. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/editing/streaming.py +0 -0
  54. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/editing/transcription_overlay.py +0 -0
  55. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/editing/transforms.py +0 -0
  56. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/editing/video_edit.py +0 -0
  57. {videopython-0.33.0 → videopython-0.33.1}/src/videopython/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: videopython
3
- Version: 0.33.0
3
+ Version: 0.33.1
4
4
  Summary: Minimal video generation and processing library.
5
5
  Project-URL: Homepage, https://videopython.com
6
6
  Project-URL: Repository, https://github.com/bartwojtowicz/videopython/
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "videopython"
3
- version = "0.33.0"
3
+ version = "0.33.1"
4
4
  description = "Minimal video generation and processing library."
5
5
  authors = [
6
6
  { name = "Bartosz Wójtowicz", email = "bartoszwojtowicz@outlook.com" },
@@ -32,7 +32,7 @@ class TextToSpeech:
32
32
  self.language = language
33
33
  self._model: Any = None
34
34
 
35
- def _init_model(self) -> None:
35
+ def _init_local(self) -> None:
36
36
  from chatterbox.mtl_tts import ChatterboxMultilingualTTS # type: ignore[import-untyped]
37
37
 
38
38
  requested_device = self.device
@@ -83,7 +83,7 @@ class TextToSpeech:
83
83
  import numpy as np
84
84
 
85
85
  if self._model is None:
86
- self._init_model()
86
+ self._init_local()
87
87
 
88
88
  speaker_wav_path: Path | None = None
89
89
  cleanup_path = False
@@ -149,7 +149,6 @@ class TextToMusic:
149
149
  self.device = device
150
150
  self._processor: Any = None
151
151
  self._model: Any = None
152
- self._device: str | None = None
153
152
 
154
153
  def _init_local(self) -> None:
155
154
  """Initialize local MusicGen model."""
@@ -160,17 +159,17 @@ class TextToMusic:
160
159
  os.environ["PYTORCH_ENABLE_MPS_FALLBACK"] = "1"
161
160
 
162
161
  requested_device = self.device
163
- self._device = select_device(self.device, mps_allowed=True)
162
+ device = select_device(self.device, mps_allowed=True)
164
163
 
165
164
  model_name = "facebook/musicgen-small"
166
165
  self._processor = AutoProcessor.from_pretrained(model_name)
167
166
  self._model = MusicgenForConditionalGeneration.from_pretrained(model_name)
168
- self._model.to(self._device)
169
- self.device = self._device
167
+ self._model.to(device)
168
+ self.device = device
170
169
  log_device_initialization(
171
170
  "TextToMusic",
172
171
  requested_device=requested_device,
173
- resolved_device=self._device,
172
+ resolved_device=device,
174
173
  )
175
174
 
176
175
  def generate_audio(self, text: str, max_new_tokens: int = 256) -> Audio:
@@ -179,7 +178,7 @@ class TextToMusic:
179
178
  self._init_local()
180
179
 
181
180
  inputs = self._processor(text=[text], padding=True, return_tensors="pt")
182
- inputs = {k: v.to(self._device) if hasattr(v, "to") else v for k, v in inputs.items()}
181
+ inputs = {k: v.to(self.device) if hasattr(v, "to") else v for k, v in inputs.items()}
183
182
  audio_values = self._model.generate(**inputs, max_new_tokens=max_new_tokens)
184
183
  sampling_rate = self._model.config.audio_encoder.sampling_rate
185
184
 
@@ -193,3 +192,9 @@ class TextToMusic:
193
192
  frame_count=len(audio_data),
194
193
  )
195
194
  return Audio(audio_data, metadata)
195
+
196
+ def unload(self) -> None:
197
+ """Release the MusicGen model so the next generate_audio() re-initializes."""
198
+ self._model = None
199
+ self._processor = None
200
+ release_device_memory(self.device)
@@ -6,7 +6,7 @@ from typing import Any
6
6
 
7
7
  from PIL import Image
8
8
 
9
- from videopython.ai._device import log_device_initialization, select_device
9
+ from videopython.ai._device import log_device_initialization, release_device_memory, select_device
10
10
 
11
11
 
12
12
  class TextToImage:
@@ -49,3 +49,8 @@ class TextToImage:
49
49
  if self._pipeline is None:
50
50
  self._init_local()
51
51
  return self._pipeline(prompt=prompt).images[0]
52
+
53
+ def unload(self) -> None:
54
+ """Release the diffusion pipeline so the next generate_image() re-initializes."""
55
+ self._pipeline = None
56
+ release_device_memory(self.device)
@@ -181,7 +181,7 @@ class MarianTranslator:
181
181
  self._model = MarianMTModel.from_pretrained(model_name).to(device)
182
182
  self.device = device
183
183
  log_device_initialization(
184
- "TextTranslator",
184
+ "MarianTranslator",
185
185
  requested_device=requested_device,
186
186
  resolved_device=device,
187
187
  )
@@ -6,7 +6,7 @@ from typing import TYPE_CHECKING, Any
6
6
 
7
7
  import numpy as np
8
8
 
9
- from videopython.ai._device import log_device_initialization, select_device
9
+ from videopython.ai._device import log_device_initialization, release_device_memory, select_device
10
10
  from videopython.base.video import Video
11
11
 
12
12
  if TYPE_CHECKING:
@@ -29,22 +29,21 @@ class TextToVideo:
29
29
  def __init__(self, device: str | None = None):
30
30
  self.device = device
31
31
  self._pipeline: Any = None
32
- self._device: str | None = None
33
32
 
34
33
  def _init_local(self) -> None:
35
34
  from diffusers import CogVideoXPipeline
36
35
 
37
36
  requested_device = self.device
38
- self._device, dtype = _get_torch_device_and_dtype(self.device)
37
+ device, dtype = _get_torch_device_and_dtype(self.device)
39
38
 
40
39
  model_name = "THUDM/CogVideoX1.5-5B"
41
40
  self._pipeline = CogVideoXPipeline.from_pretrained(model_name, torch_dtype=dtype)
42
- self._pipeline.to(self._device)
43
- self.device = self._device
41
+ self._pipeline.to(device)
42
+ self.device = device
44
43
  log_device_initialization(
45
44
  "TextToVideo",
46
45
  requested_device=requested_device,
47
- resolved_device=self._device,
46
+ resolved_device=device,
48
47
  )
49
48
 
50
49
  def generate_video(
@@ -65,11 +64,16 @@ class TextToVideo:
65
64
  num_inference_steps=num_steps,
66
65
  num_frames=num_frames,
67
66
  guidance_scale=guidance_scale,
68
- generator=torch.Generator(device=self._device).manual_seed(42),
67
+ generator=torch.Generator(device=self.device).manual_seed(42),
69
68
  ).frames[0]
70
69
  video_frames = np.asarray(video_frames, dtype=np.uint8)
71
70
  return Video.from_frames(video_frames, fps=16.0)
72
71
 
72
+ def unload(self) -> None:
73
+ """Release the diffusion pipeline so the next generate_video() re-initializes."""
74
+ self._pipeline = None
75
+ release_device_memory(self.device)
76
+
73
77
 
74
78
  class ImageToVideo:
75
79
  """Generates videos from static images using local video diffusion."""
@@ -77,22 +81,21 @@ class ImageToVideo:
77
81
  def __init__(self, device: str | None = None):
78
82
  self.device = device
79
83
  self._pipeline: Any = None
80
- self._device: str | None = None
81
84
 
82
85
  def _init_local(self) -> None:
83
86
  from diffusers import CogVideoXImageToVideoPipeline
84
87
 
85
88
  requested_device = self.device
86
- self._device, dtype = _get_torch_device_and_dtype(self.device)
89
+ device, dtype = _get_torch_device_and_dtype(self.device)
87
90
 
88
91
  model_name = "THUDM/CogVideoX1.5-5B-I2V"
89
92
  self._pipeline = CogVideoXImageToVideoPipeline.from_pretrained(model_name, torch_dtype=dtype)
90
- self._pipeline.to(self._device)
91
- self.device = self._device
93
+ self._pipeline.to(device)
94
+ self.device = device
92
95
  log_device_initialization(
93
96
  "ImageToVideo",
94
97
  requested_device=requested_device,
95
- resolved_device=self._device,
98
+ resolved_device=device,
96
99
  )
97
100
 
98
101
  def generate_video(
@@ -115,7 +118,12 @@ class ImageToVideo:
115
118
  num_inference_steps=num_steps,
116
119
  num_frames=num_frames,
117
120
  guidance_scale=guidance_scale,
118
- generator=torch.Generator(device=self._device).manual_seed(42),
121
+ generator=torch.Generator(device=self.device).manual_seed(42),
119
122
  ).frames[0]
120
123
  video_frames = np.asarray(video_frames, dtype=np.uint8)
121
124
  return Video.from_frames(video_frames, fps=16.0)
125
+
126
+ def unload(self) -> None:
127
+ """Release the diffusion pipeline so the next generate_video() re-initializes."""
128
+ self._pipeline = None
129
+ release_device_memory(self.device)
@@ -520,6 +520,15 @@ class AudioClassifier:
520
520
 
521
521
  self._labels = [self._model.config.id2label[i] for i in range(len(self._model.config.id2label))]
522
522
 
523
+ def unload(self) -> None:
524
+ """Release the AST model so the next classify() re-initializes.
525
+
526
+ Used by low-memory dubbing to free VRAM between pipeline stages.
527
+ """
528
+ self._model = None
529
+ self._processor = None
530
+ release_device_memory(self.device)
531
+
523
532
  def _merge_events(self, events: list[AudioEvent], gap_threshold: float = 0.5) -> list[AudioEvent]:
524
533
  """Merge consecutive events of the same class."""
525
534
  if not events:
@@ -11,7 +11,7 @@ from typing import Any, Literal
11
11
  import numpy as np
12
12
  from PIL import Image
13
13
 
14
- from videopython.ai._device import log_device_initialization, select_device
14
+ from videopython.ai._device import log_device_initialization, release_device_memory, select_device
15
15
  from videopython.base.description import SceneDescription
16
16
 
17
17
  logger = logging.getLogger(__name__)
@@ -190,16 +190,7 @@ class SceneVLM:
190
190
  """
191
191
  self._model = None
192
192
  self._processor = None
193
- try:
194
- import gc
195
-
196
- import torch
197
-
198
- gc.collect()
199
- if torch.cuda.is_available():
200
- torch.cuda.empty_cache()
201
- except ImportError:
202
- pass
193
+ release_device_memory(self.device)
203
194
 
204
195
  def _downscale_image(self, img: Image.Image) -> Image.Image:
205
196
  """Downscale image to fit within max_image_pixels budget, preserving aspect ratio."""
@@ -9,7 +9,7 @@ from __future__ import annotations
9
9
  from pathlib import Path
10
10
  from typing import TYPE_CHECKING, Any
11
11
 
12
- from videopython.ai._device import log_device_initialization, select_device
12
+ from videopython.ai._device import log_device_initialization, release_device_memory, select_device
13
13
  from videopython.base.description import SceneBoundary
14
14
 
15
15
  if TYPE_CHECKING:
@@ -56,26 +56,32 @@ class SemanticSceneDetector:
56
56
 
57
57
  self.threshold = threshold
58
58
  self.min_scene_length = min_scene_length
59
- self._device: str | None = device
59
+ self.device: str | None = device
60
60
  self._model: Any = None
61
61
 
62
- def _load_model(self) -> None:
62
+ def _init_local(self) -> None:
63
63
  """Load the TransNetV2 model with pretrained weights."""
64
64
  if self._model is not None:
65
65
  return
66
66
 
67
67
  from transnetv2_pytorch import TransNetV2
68
68
 
69
- requested_device = self._device
70
- device = select_device(self._device, mps_allowed=True)
69
+ requested_device = self.device
70
+ device = select_device(self.device, mps_allowed=True)
71
71
  log_device_initialization(
72
72
  "SemanticSceneDetector",
73
73
  requested_device=requested_device,
74
74
  resolved_device=device,
75
75
  )
76
+ self.device = device
76
77
  self._model = TransNetV2(device=device)
77
78
  self._model.eval()
78
79
 
80
+ def unload(self) -> None:
81
+ """Release the TransNetV2 model so the next call re-initializes."""
82
+ self._model = None
83
+ release_device_memory(self.device)
84
+
79
85
  def detect(self, video: Video) -> list[SceneBoundary]:
80
86
  """Detect scenes in a video using ML-based boundary detection.
81
87
 
@@ -114,7 +120,7 @@ class SemanticSceneDetector:
114
120
  Returns:
115
121
  List of SceneBoundary objects representing detected scenes.
116
122
  """
117
- self._load_model()
123
+ self._init_local()
118
124
 
119
125
  # Use TransNetV2's detect_scenes which handles everything internally
120
126
  raw_scenes = self._model.detect_scenes(str(path), threshold=self.threshold)
File without changes
File without changes
File without changes