Skip to content

Commit 109523d

Browse files
committed
0.1.7
1 parent 204d3ac commit 109523d

File tree

6 files changed

+340
-3
lines changed

6 files changed

+340
-3
lines changed

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "veotools"
7-
version = "0.1.6"
7+
version = "0.1.7"
88
description = "A Python toolkit for AI-powered video generation and seamless stitching using Google's Veo models."
99
readme = "readme.md"
1010
requires-python = ">=3.10"
@@ -54,4 +54,5 @@ mcp = ["mcp[cli]>=1.0.0"]
5454

5555
[project.scripts]
5656
veo = "veotools.cli:main"
57+
veo-mcp = "veotools.mcp_server:main"
5758

readme.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,41 @@ status = veo.generate_get(job_id)
158158
veo.generate_cancel(job_id)
159159
```
160160

161+
### Cursor MCP configuration
162+
163+
Add an entry in `~/.cursor/mcp.json` pointing to the installed `veo-mcp` (or your venv path):
164+
165+
```json
166+
{
167+
"mcpServers": {
168+
"veotools": {
169+
"command": "/Users/you/.venv/bin/veo-mcp",
170+
"args": [],
171+
"env": {
172+
"GEMINI_API_KEY": "your-api-key",
173+
"VEO_OUTPUT_DIR": "/Users/you/projects/output"
174+
},
175+
"disabled": false
176+
}
177+
}
178+
}
179+
```
180+
181+
Alternatively, use Python directly:
182+
183+
```json
184+
{
185+
"mcpServers": {
186+
"veotools": {
187+
"command": "/Users/you/.venv/bin/python",
188+
"args": ["-m", "veotools.mcp_server"],
189+
"env": { "GEMINI_API_KEY": "your-api-key" },
190+
"disabled": false
191+
}
192+
}
193+
}
194+
```
195+
161196
## Model discovery
162197
```python
163198
models = veotools.list_models(include_remote=True)

veotools/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
generate_cancel,
3636
)
3737

38-
__version__ = "0.1.6"
38+
__version__ = "0.1.7"
3939

4040
__all__ = [
4141
"VeoClient",

veotools/cli.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,18 @@ def cmd_generate(ns: argparse.Namespace) -> int:
4949
kwargs: Dict[str, Any] = {}
5050
if ns.model:
5151
kwargs["model"] = ns.model
52+
if ns.aspect_ratio:
53+
kwargs["aspect_ratio"] = ns.aspect_ratio
54+
if ns.negative_prompt:
55+
kwargs["negative_prompt"] = ns.negative_prompt
56+
if ns.person_generation:
57+
kwargs["person_generation"] = ns.person_generation
5258
if ns.image:
5359
result = veo.generate_from_image(
5460
image_path=Path(ns.image),
5561
prompt=ns.prompt,
5662
on_progress=_print_progress,
63+
**kwargs,
5764
)
5865
elif ns.video:
5966
result = veo.generate_from_video(
@@ -79,12 +86,21 @@ def cmd_generate(ns: argparse.Namespace) -> int:
7986
def cmd_continue(ns: argparse.Namespace) -> int:
8087
veo.init()
8188
# Generate continuation
89+
kwargs: Dict[str, Any] = {}
90+
if ns.model:
91+
kwargs["model"] = ns.model
92+
if ns.aspect_ratio:
93+
kwargs["aspect_ratio"] = ns.aspect_ratio
94+
if ns.negative_prompt:
95+
kwargs["negative_prompt"] = ns.negative_prompt
96+
if ns.person_generation:
97+
kwargs["person_generation"] = ns.person_generation
8298
gen = veo.generate_from_video(
8399
video_path=Path(ns.video),
84100
prompt=ns.prompt,
85101
extract_at=ns.extract_at,
86-
model=ns.model,
87102
on_progress=_print_progress,
103+
**kwargs,
88104
)
89105
# Stitch with original
90106
stitched = veo.stitch_videos([Path(ns.video), Path(gen.path)], overlap=ns.overlap)
@@ -117,6 +133,9 @@ def build_parser() -> argparse.ArgumentParser:
117133
s.add_argument("--image", help="Path to input image")
118134
s.add_argument("--video", help="Path to input video")
119135
s.add_argument("--extract-at", type=float, default=-1.0, help="Time offset for video continuation")
136+
s.add_argument("--aspect-ratio", choices=["16:9","9:16"], help="Requested aspect ratio (model-dependent)")
137+
s.add_argument("--negative-prompt", help="Text to avoid in generation")
138+
s.add_argument("--person-generation", choices=["allow_all","allow_adult","dont_allow"], help="Person generation policy (model/region dependent)")
120139
s.add_argument("--json", action="store_true", help="Output JSON")
121140
s.set_defaults(func=cmd_generate)
122141

@@ -126,6 +145,9 @@ def build_parser() -> argparse.ArgumentParser:
126145
s.add_argument("--model", help="Model ID")
127146
s.add_argument("--extract-at", type=float, default=-1.0)
128147
s.add_argument("--overlap", type=float, default=1.0)
148+
s.add_argument("--aspect-ratio", choices=["16:9","9:16"], help="Requested aspect ratio (model-dependent)")
149+
s.add_argument("--negative-prompt", help="Text to avoid in generation")
150+
s.add_argument("--person-generation", choices=["allow_all","allow_adult","dont_allow"], help="Person generation policy (model/region dependent)")
129151
s.add_argument("--json", action="store_true")
130152
s.set_defaults(func=cmd_continue)
131153

veotools/core.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ class ModelConfig:
119119
"supports_duration": False,
120120
"supports_enhance": False,
121121
"supports_fps": False,
122+
"supports_aspect_ratio": True,
122123
"supports_audio": True,
123124
"default_duration": 8,
124125
"generation_time": 60
@@ -128,6 +129,7 @@ class ModelConfig:
128129
"supports_duration": False,
129130
"supports_enhance": False,
130131
"supports_fps": False,
132+
"supports_aspect_ratio": True,
131133
"supports_audio": True,
132134
"default_duration": 8,
133135
"generation_time": 120
@@ -137,6 +139,7 @@ class ModelConfig:
137139
"supports_duration": True,
138140
"supports_enhance": True,
139141
"supports_fps": True,
142+
"supports_aspect_ratio": True,
140143
"supports_audio": False,
141144
"default_duration": 5,
142145
"generation_time": 180
@@ -166,5 +169,27 @@ def build_generation_config(cls, model: str, **kwargs) -> types.GenerateVideosCo
166169

167170
if config["supports_fps"] and "fps" in kwargs:
168171
params["fps"] = kwargs["fps"]
172+
173+
# Aspect ratio (e.g., "16:9"; Veo 3 limited to 16:9; Veo 2 supports 16:9 and 9:16)
174+
if config.get("supports_aspect_ratio") and "aspect_ratio" in kwargs and kwargs["aspect_ratio"]:
175+
ar = str(kwargs["aspect_ratio"]) # normalize
176+
model_key = model.replace("models/", "")
177+
if model_key.startswith("veo-3.0"):
178+
allowed = {"16:9"}
179+
elif model_key.startswith("veo-2.0"):
180+
allowed = {"16:9", "9:16"}
181+
else:
182+
allowed = {"16:9"}
183+
if ar not in allowed:
184+
raise ValueError(f"aspect_ratio '{ar}' not supported for model '{model_key}'. Allowed: {sorted(allowed)}")
185+
params["aspect_ratio"] = ar
186+
187+
# Docs-backed pass-throughs
188+
if "negative_prompt" in kwargs and kwargs["negative_prompt"]:
189+
params["negative_prompt"] = kwargs["negative_prompt"]
190+
191+
if "person_generation" in kwargs and kwargs["person_generation"]:
192+
# Person generation options vary by model/region; pass through as provided
193+
params["person_generation"] = kwargs["person_generation"]
169194

170195
return types.GenerateVideosConfig(**params)

0 commit comments

Comments
 (0)