vision-agents-plugins-pocket 0.2.10__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.
@@ -0,0 +1,90 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .cursor/*
7
+ # Distribution / packaging
8
+ .Python
9
+ build/
10
+ dist/
11
+ downloads/
12
+ develop-eggs/
13
+ eggs/
14
+ .eggs/
15
+ lib64/
16
+ parts/
17
+ sdist/
18
+ var/
19
+ wheels/
20
+ share/python-wheels/
21
+ pip-wheel-metadata/
22
+ MANIFEST
23
+ *.egg-info/
24
+ *.egg
25
+
26
+ # Installer logs
27
+ pip-log.txt
28
+ pip-delete-this-directory.txt
29
+
30
+ # Unit test / coverage reports
31
+ htmlcov/
32
+ .tox/
33
+ .nox/
34
+ .coverage
35
+ .coverage.*
36
+ .cache
37
+ coverage.xml
38
+ nosetests.xml
39
+ *.cover
40
+ *.py,cover
41
+ .hypothesis/
42
+ .pytest_cache/
43
+
44
+ # Type checker / lint caches
45
+ .mypy_cache/
46
+ .dmypy.json
47
+ dmypy.json
48
+ .pytype/
49
+ .pyre/
50
+ .ruff_cache/
51
+
52
+ # Environments
53
+ .venv
54
+ env/
55
+ venv/
56
+ ENV/
57
+ env.bak/
58
+ venv.bak/
59
+ .env
60
+ .env.local
61
+ .env.*.local
62
+ .env.bak
63
+ pyvenv.cfg
64
+ .python-version
65
+
66
+ # Editors / IDEs
67
+ .vscode/
68
+ .idea/
69
+
70
+ # Jupyter Notebook
71
+ .ipynb_checkpoints/
72
+
73
+ # OS / Misc
74
+ .DS_Store
75
+ *.log
76
+
77
+ # Tooling & repo-specific
78
+ pyrightconfig.json
79
+ shell.nix
80
+ bin/*
81
+ lib/*
82
+ stream-py/
83
+
84
+ # Artifacts / assets
85
+ *.pt
86
+ *.kef
87
+ *.onnx
88
+ profile.html
89
+
90
+ /opencode.json
@@ -0,0 +1,68 @@
1
+ Metadata-Version: 2.4
2
+ Name: vision-agents-plugins-pocket
3
+ Version: 0.2.10
4
+ Summary: Pocket TTS integration for Vision Agents - lightweight CPU-based text-to-speech
5
+ Project-URL: Documentation, https://visionagents.ai/
6
+ Project-URL: Website, https://visionagents.ai/
7
+ Project-URL: Source, https://github.com/GetStream/Vision-Agents
8
+ License-Expression: MIT
9
+ Keywords: AI,TTS,agents,kyutai,pocket-tts,text-to-speech,voice agents
10
+ Requires-Python: >=3.10
11
+ Requires-Dist: pocket-tts>=0.1.0
12
+ Requires-Dist: vision-agents
13
+ Description-Content-Type: text/markdown
14
+
15
+ # Pocket TTS Plugin
16
+
17
+ A lightweight Text-to-Speech (TTS) plugin for [Vision Agents](https://github.com/GetStream/Vision-Agents) powered by Kyutai's [Pocket TTS](https://huggingface.co/kyutai/pocket-tts) model. Runs efficiently on CPU with low latency (~200ms) and supports voice cloning.
18
+
19
+ ## Features
20
+
21
+ - Runs on CPU - no GPU required
22
+ - Small model size (100M parameters)
23
+ - Low latency (~200ms to first audio)
24
+ - Voice cloning support
25
+ - Built-in voice selection
26
+
27
+ ## Installation
28
+
29
+ ```bash
30
+ uv add vision-agents[pocket]
31
+ ```
32
+
33
+ ## Usage
34
+
35
+ ```python
36
+ from vision_agents.plugins import pocket
37
+
38
+ # Create TTS with default voice
39
+ tts = pocket.TTS()
40
+
41
+ # Or specify a built-in voice
42
+ tts = pocket.TTS(voice="marius")
43
+
44
+ # Or use a custom voice for cloning
45
+ tts = pocket.TTS(voice="path/to/your/voice.wav")
46
+ ```
47
+
48
+ ## Configuration
49
+
50
+ | Parameter | Description | Values |
51
+ |-----------|-------------|--------|
52
+ | `voice` | Built-in voice name or path to custom wav file | `"alba"` (default), `"marius"`, `"javert"`, `"jean"`, `"fantine"`, `"cosette"`, `"eponine"`, `"azelma"`, or custom path |
53
+
54
+ ## Built-in Voices
55
+
56
+ - `alba` - Default voice
57
+ - `marius`
58
+ - `javert`
59
+ - `jean`
60
+ - `fantine`
61
+ - `cosette`
62
+ - `eponine`
63
+ - `azelma`
64
+
65
+ ## Dependencies
66
+
67
+ - pocket-tts>=0.1.0
68
+ - PyTorch 2.5+
@@ -0,0 +1,54 @@
1
+ # Pocket TTS Plugin
2
+
3
+ A lightweight Text-to-Speech (TTS) plugin for [Vision Agents](https://github.com/GetStream/Vision-Agents) powered by Kyutai's [Pocket TTS](https://huggingface.co/kyutai/pocket-tts) model. Runs efficiently on CPU with low latency (~200ms) and supports voice cloning.
4
+
5
+ ## Features
6
+
7
+ - Runs on CPU - no GPU required
8
+ - Small model size (100M parameters)
9
+ - Low latency (~200ms to first audio)
10
+ - Voice cloning support
11
+ - Built-in voice selection
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ uv add vision-agents[pocket]
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ```python
22
+ from vision_agents.plugins import pocket
23
+
24
+ # Create TTS with default voice
25
+ tts = pocket.TTS()
26
+
27
+ # Or specify a built-in voice
28
+ tts = pocket.TTS(voice="marius")
29
+
30
+ # Or use a custom voice for cloning
31
+ tts = pocket.TTS(voice="path/to/your/voice.wav")
32
+ ```
33
+
34
+ ## Configuration
35
+
36
+ | Parameter | Description | Values |
37
+ |-----------|-------------|--------|
38
+ | `voice` | Built-in voice name or path to custom wav file | `"alba"` (default), `"marius"`, `"javert"`, `"jean"`, `"fantine"`, `"cosette"`, `"eponine"`, `"azelma"`, or custom path |
39
+
40
+ ## Built-in Voices
41
+
42
+ - `alba` - Default voice
43
+ - `marius`
44
+ - `javert`
45
+ - `jean`
46
+ - `fantine`
47
+ - `cosette`
48
+ - `eponine`
49
+ - `azelma`
50
+
51
+ ## Dependencies
52
+
53
+ - pocket-tts>=0.1.0
54
+ - PyTorch 2.5+
@@ -0,0 +1,40 @@
1
+ [build-system]
2
+ requires = ["hatchling", "hatch-vcs"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "vision-agents-plugins-pocket"
7
+ dynamic = ["version"]
8
+ description = "Pocket TTS integration for Vision Agents - lightweight CPU-based text-to-speech"
9
+ readme = "README.md"
10
+ keywords = ["pocket-tts", "TTS", "text-to-speech", "AI", "voice agents", "agents", "kyutai"]
11
+ requires-python = ">=3.10"
12
+ license = "MIT"
13
+ dependencies = [
14
+ "vision-agents",
15
+ "pocket-tts>=0.1.0",
16
+ ]
17
+
18
+ [project.urls]
19
+ Documentation = "https://visionagents.ai/"
20
+ Website = "https://visionagents.ai/"
21
+ Source = "https://github.com/GetStream/Vision-Agents"
22
+
23
+ [tool.hatch.version]
24
+ source = "vcs"
25
+ raw-options = { root = "..", search_parent_directories = true, fallback_version = "0.0.0" }
26
+
27
+ [tool.hatch.build.targets.wheel]
28
+ packages = [".", "vision_agents"]
29
+
30
+ [tool.hatch.build.targets.sdist]
31
+ include = ["/vision_agents"]
32
+
33
+ [tool.uv.sources]
34
+ vision-agents = { workspace = true }
35
+
36
+ [dependency-groups]
37
+ dev = [
38
+ "pytest>=8.4.1",
39
+ "pytest-asyncio>=1.0.0",
40
+ ]
@@ -0,0 +1,3 @@
1
+ from .tts import TTS
2
+
3
+ __all__ = ["TTS"]
@@ -0,0 +1,129 @@
1
+ import asyncio
2
+ import logging
3
+ from concurrent.futures import ThreadPoolExecutor
4
+ from typing import Any, AsyncIterator, Iterator, Literal
5
+
6
+ import numpy as np
7
+
8
+ from getstream.video.rtc.track_util import AudioFormat, PcmData
9
+ from vision_agents.core import tts
10
+ from vision_agents.core.warmup import Warmable
11
+
12
+ from pocket_tts import TTSModel
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+ Voice = Literal[
17
+ "alba", "marius", "javert", "jean", "fantine", "cosette", "eponine", "azelma"
18
+ ]
19
+
20
+ VOICE_PATHS = {
21
+ "alba": "hf://kyutai/tts-voices/alba-mackenna/casual.wav",
22
+ "marius": "hf://kyutai/tts-voices/marius/casual.wav",
23
+ "javert": "hf://kyutai/tts-voices/javert/casual.wav",
24
+ "jean": "hf://kyutai/tts-voices/jean/casual.wav",
25
+ "fantine": "hf://kyutai/tts-voices/fantine/casual.wav",
26
+ "cosette": "hf://kyutai/tts-voices/cosette/casual.wav",
27
+ "eponine": "hf://kyutai/tts-voices/eponine/casual.wav",
28
+ "azelma": "hf://kyutai/tts-voices/azelma/casual.wav",
29
+ }
30
+
31
+
32
+ class TTS(tts.TTS, Warmable[tuple[TTSModel, Any]]):
33
+ """
34
+ Pocket TTS Text-to-Speech implementation.
35
+
36
+ A lightweight CPU-based TTS model from Kyutai with ~200ms latency
37
+ and voice cloning support.
38
+ """
39
+
40
+ def __init__(
41
+ self,
42
+ voice: Voice | str = "alba",
43
+ client: TTSModel | None = None,
44
+ ) -> None:
45
+ """
46
+ Initialize Pocket TTS.
47
+
48
+ Args:
49
+ voice: Built-in voice name or path to custom wav file for voice cloning.
50
+ client: Optional pre-initialized TTSModel instance.
51
+ """
52
+ super().__init__(provider_name="pocket")
53
+
54
+ self.voice = voice
55
+ self._model: TTSModel | None = client
56
+ self._voice_state = None
57
+ self._executor = ThreadPoolExecutor(max_workers=4)
58
+
59
+ async def on_warmup(self) -> tuple[TTSModel, Any]:
60
+ if self._model is not None and self._voice_state is not None:
61
+ return (self._model, self._voice_state)
62
+
63
+ loop = asyncio.get_running_loop()
64
+
65
+ if self._model is not None:
66
+ model = self._model
67
+ else:
68
+ logger.info("Loading Pocket TTS model...")
69
+ model = await loop.run_in_executor(self._executor, TTSModel.load_model)
70
+ logger.info("Pocket TTS model loaded")
71
+
72
+ voice_path = VOICE_PATHS.get(self.voice, self.voice)
73
+ logger.info(f"Loading voice state for: {self.voice}")
74
+ voice_state = await loop.run_in_executor(
75
+ self._executor,
76
+ lambda: model.get_state_for_audio_prompt(voice_path),
77
+ )
78
+ logger.info("Voice state loaded")
79
+ return (model, voice_state)
80
+
81
+ def on_warmed_up(self, resource: tuple[TTSModel, Any]) -> None:
82
+ self._model, self._voice_state = resource
83
+
84
+ async def _ensure_loaded(self) -> None:
85
+ """Ensure model and voice state are loaded."""
86
+ if self._model is None or self._voice_state is None:
87
+ resource = await self.on_warmup()
88
+ self.on_warmed_up(resource)
89
+
90
+ async def stream_audio(
91
+ self, text: str, *_, **__
92
+ ) -> PcmData | Iterator[PcmData] | AsyncIterator[PcmData]:
93
+ """
94
+ Convert text to speech using Pocket TTS.
95
+
96
+ Args:
97
+ text: The text to convert to speech.
98
+
99
+ Returns:
100
+ PcmData containing the synthesized audio.
101
+ """
102
+ await self._ensure_loaded()
103
+ assert self._model is not None
104
+ assert self._voice_state is not None
105
+
106
+ model = self._model
107
+ voice_state = self._voice_state
108
+
109
+ def _generate():
110
+ audio_tensor = model.generate_audio(voice_state, text)
111
+ audio_np = audio_tensor.numpy()
112
+ pcm16 = (np.clip(audio_np, -1.0, 1.0) * 32767.0).astype(np.int16)
113
+ return pcm16, model.sample_rate
114
+
115
+ loop = asyncio.get_running_loop()
116
+ samples, sample_rate = await loop.run_in_executor(self._executor, _generate)
117
+
118
+ return PcmData.from_numpy(
119
+ samples, sample_rate=sample_rate, channels=1, format=AudioFormat.S16
120
+ )
121
+
122
+ async def stop_audio(self) -> None:
123
+ """Stop audio playback (no-op for Pocket TTS)."""
124
+ logger.info("Pocket TTS stop requested (no-op)")
125
+
126
+ async def close(self) -> None:
127
+ """Close the TTS and cleanup resources."""
128
+ await super().close()
129
+ self._executor.shutdown(wait=False)