vcursor-cli 1.0.0__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.
- vcursor_cli-1.0.0/MANIFEST.in +4 -0
- vcursor_cli-1.0.0/PKG-INFO +139 -0
- vcursor_cli-1.0.0/README.md +111 -0
- vcursor_cli-1.0.0/pyproject.toml +49 -0
- vcursor_cli-1.0.0/setup.cfg +4 -0
- vcursor_cli-1.0.0/tests/__init__.py +0 -0
- vcursor_cli-1.0.0/tests/test_types.py +110 -0
- vcursor_cli-1.0.0/vcursor/__init__.py +25 -0
- vcursor_cli-1.0.0/vcursor/cli.py +322 -0
- vcursor_cli-1.0.0/vcursor/client.py +372 -0
- vcursor_cli-1.0.0/vcursor/types.py +222 -0
- vcursor_cli-1.0.0/vcursor_cli.egg-info/PKG-INFO +139 -0
- vcursor_cli-1.0.0/vcursor_cli.egg-info/SOURCES.txt +15 -0
- vcursor_cli-1.0.0/vcursor_cli.egg-info/dependency_links.txt +1 -0
- vcursor_cli-1.0.0/vcursor_cli.egg-info/entry_points.txt +2 -0
- vcursor_cli-1.0.0/vcursor_cli.egg-info/requires.txt +5 -0
- vcursor_cli-1.0.0/vcursor_cli.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vcursor-cli
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: VCursor SDK & CLI - Generate videos from text, images, and URLs using AI
|
|
5
|
+
Author-email: Julius <support@vcursor.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://cli.vcursor.com
|
|
8
|
+
Project-URL: Repository, https://github.com/JThh/vcursor
|
|
9
|
+
Project-URL: Documentation, https://cli.vcursor.com/docs
|
|
10
|
+
Keywords: video,ai,generation,cli,vcursor,sdk
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Multimedia :: Video
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
Requires-Dist: httpx>=0.25.0
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
27
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
|
|
28
|
+
|
|
29
|
+
# VCursor Python SDK & CLI
|
|
30
|
+
|
|
31
|
+
Generate videos from text, images, and URLs using AI.
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install vcursor
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Quick Start
|
|
40
|
+
|
|
41
|
+
### As a library (embedded in code)
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from vcursor import VCursor
|
|
45
|
+
|
|
46
|
+
client = VCursor(api_key="vk-...")
|
|
47
|
+
|
|
48
|
+
# Submit a video generation task
|
|
49
|
+
resp = client.submit("a cat playing piano in a jazz club")
|
|
50
|
+
|
|
51
|
+
# Wait for completion with progress callback
|
|
52
|
+
result = client.wait_for_completion(
|
|
53
|
+
resp.task_id,
|
|
54
|
+
on_progress=lambda p: print(f"{p.data.progress}%")
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
print(result.data.products.url)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Async usage
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
import asyncio
|
|
64
|
+
from vcursor import VCursorAsync
|
|
65
|
+
|
|
66
|
+
async def main():
|
|
67
|
+
async with VCursorAsync(api_key="vk-...") as client:
|
|
68
|
+
resp = await client.submit("sunset timelapse over mountains")
|
|
69
|
+
result = await client.wait_for_completion(resp.task_id)
|
|
70
|
+
print(result.data.products.url)
|
|
71
|
+
|
|
72
|
+
asyncio.run(main())
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Concurrency limiting
|
|
76
|
+
|
|
77
|
+
The server enforces per-user rate limits based on subscription tier:
|
|
78
|
+
|
|
79
|
+
| Tier | Standard Requests | Agent Requests | Window |
|
|
80
|
+
|------|-------------------|----------------|-----------|
|
|
81
|
+
| Free | 3 | 1 | Lifetime |
|
|
82
|
+
| Pro | 30/hr | 5/hr | Rolling 1h|
|
|
83
|
+
| Plus | 120/hr | 15/hr | Rolling 1h|
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
# Check current rate limit status
|
|
87
|
+
status = client.check_concurrency("standard")
|
|
88
|
+
print(f"Standard: {status.summary['standard'].used}/{status.summary['standard'].limit}")
|
|
89
|
+
print(f"Agent: {status.summary['agent'].used}/{status.summary['agent'].limit}")
|
|
90
|
+
|
|
91
|
+
# Client-side limit (capped at server limit)
|
|
92
|
+
client = VCursor(api_key="vk-...", max_concurrency=10)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### As a CLI
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Authenticate
|
|
99
|
+
vcursor login
|
|
100
|
+
|
|
101
|
+
# Generate a video
|
|
102
|
+
vcursor generate "a cat playing piano"
|
|
103
|
+
|
|
104
|
+
# Agent mode
|
|
105
|
+
vcursor generate --agent "create a 30s commercial"
|
|
106
|
+
|
|
107
|
+
# Check concurrency status
|
|
108
|
+
vcursor concurrency
|
|
109
|
+
|
|
110
|
+
# With concurrency limit
|
|
111
|
+
vcursor generate --max-concurrency 2 "sunset timelapse"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## API Reference
|
|
115
|
+
|
|
116
|
+
### `VCursor` / `VCursorAsync`
|
|
117
|
+
|
|
118
|
+
| Method | Description |
|
|
119
|
+
|---------------------------|----------------------------------------|
|
|
120
|
+
| `submit(prompt, **kw)` | Submit a standard video generation task |
|
|
121
|
+
| `get_progress(task_id)` | Get task progress |
|
|
122
|
+
| `wait_for_completion()` | Poll until task completes |
|
|
123
|
+
| `cancel_task(task_id)` | Cancel a running task |
|
|
124
|
+
| `submit_agent(message)` | Submit an agent mode task |
|
|
125
|
+
| `get_agent_progress()` | Get agent task progress |
|
|
126
|
+
| `wait_for_agent_completion()` | Poll until agent task completes |
|
|
127
|
+
| `check_concurrency()` | Check concurrency limit status |
|
|
128
|
+
|
|
129
|
+
## Configuration
|
|
130
|
+
|
|
131
|
+
Config is stored in `~/.vcursor/config.json` (shared with the Node.js CLI).
|
|
132
|
+
|
|
133
|
+
Environment variables:
|
|
134
|
+
- `VCURSOR_API_KEY` - API key
|
|
135
|
+
- `VCURSOR_SERVER` - Server URL
|
|
136
|
+
|
|
137
|
+
## License
|
|
138
|
+
|
|
139
|
+
MIT
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# VCursor Python SDK & CLI
|
|
2
|
+
|
|
3
|
+
Generate videos from text, images, and URLs using AI.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install vcursor
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
### As a library (embedded in code)
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from vcursor import VCursor
|
|
17
|
+
|
|
18
|
+
client = VCursor(api_key="vk-...")
|
|
19
|
+
|
|
20
|
+
# Submit a video generation task
|
|
21
|
+
resp = client.submit("a cat playing piano in a jazz club")
|
|
22
|
+
|
|
23
|
+
# Wait for completion with progress callback
|
|
24
|
+
result = client.wait_for_completion(
|
|
25
|
+
resp.task_id,
|
|
26
|
+
on_progress=lambda p: print(f"{p.data.progress}%")
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
print(result.data.products.url)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Async usage
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
import asyncio
|
|
36
|
+
from vcursor import VCursorAsync
|
|
37
|
+
|
|
38
|
+
async def main():
|
|
39
|
+
async with VCursorAsync(api_key="vk-...") as client:
|
|
40
|
+
resp = await client.submit("sunset timelapse over mountains")
|
|
41
|
+
result = await client.wait_for_completion(resp.task_id)
|
|
42
|
+
print(result.data.products.url)
|
|
43
|
+
|
|
44
|
+
asyncio.run(main())
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Concurrency limiting
|
|
48
|
+
|
|
49
|
+
The server enforces per-user rate limits based on subscription tier:
|
|
50
|
+
|
|
51
|
+
| Tier | Standard Requests | Agent Requests | Window |
|
|
52
|
+
|------|-------------------|----------------|-----------|
|
|
53
|
+
| Free | 3 | 1 | Lifetime |
|
|
54
|
+
| Pro | 30/hr | 5/hr | Rolling 1h|
|
|
55
|
+
| Plus | 120/hr | 15/hr | Rolling 1h|
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
# Check current rate limit status
|
|
59
|
+
status = client.check_concurrency("standard")
|
|
60
|
+
print(f"Standard: {status.summary['standard'].used}/{status.summary['standard'].limit}")
|
|
61
|
+
print(f"Agent: {status.summary['agent'].used}/{status.summary['agent'].limit}")
|
|
62
|
+
|
|
63
|
+
# Client-side limit (capped at server limit)
|
|
64
|
+
client = VCursor(api_key="vk-...", max_concurrency=10)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### As a CLI
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Authenticate
|
|
71
|
+
vcursor login
|
|
72
|
+
|
|
73
|
+
# Generate a video
|
|
74
|
+
vcursor generate "a cat playing piano"
|
|
75
|
+
|
|
76
|
+
# Agent mode
|
|
77
|
+
vcursor generate --agent "create a 30s commercial"
|
|
78
|
+
|
|
79
|
+
# Check concurrency status
|
|
80
|
+
vcursor concurrency
|
|
81
|
+
|
|
82
|
+
# With concurrency limit
|
|
83
|
+
vcursor generate --max-concurrency 2 "sunset timelapse"
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## API Reference
|
|
87
|
+
|
|
88
|
+
### `VCursor` / `VCursorAsync`
|
|
89
|
+
|
|
90
|
+
| Method | Description |
|
|
91
|
+
|---------------------------|----------------------------------------|
|
|
92
|
+
| `submit(prompt, **kw)` | Submit a standard video generation task |
|
|
93
|
+
| `get_progress(task_id)` | Get task progress |
|
|
94
|
+
| `wait_for_completion()` | Poll until task completes |
|
|
95
|
+
| `cancel_task(task_id)` | Cancel a running task |
|
|
96
|
+
| `submit_agent(message)` | Submit an agent mode task |
|
|
97
|
+
| `get_agent_progress()` | Get agent task progress |
|
|
98
|
+
| `wait_for_agent_completion()` | Poll until agent task completes |
|
|
99
|
+
| `check_concurrency()` | Check concurrency limit status |
|
|
100
|
+
|
|
101
|
+
## Configuration
|
|
102
|
+
|
|
103
|
+
Config is stored in `~/.vcursor/config.json` (shared with the Node.js CLI).
|
|
104
|
+
|
|
105
|
+
Environment variables:
|
|
106
|
+
- `VCURSOR_API_KEY` - API key
|
|
107
|
+
- `VCURSOR_SERVER` - Server URL
|
|
108
|
+
|
|
109
|
+
## License
|
|
110
|
+
|
|
111
|
+
MIT
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "vcursor-cli"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "VCursor SDK & CLI - Generate videos from text, images, and URLs using AI"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "MIT"}
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Julius", email = "support@vcursor.com"},
|
|
14
|
+
]
|
|
15
|
+
keywords = ["video", "ai", "generation", "cli", "vcursor", "sdk"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.9",
|
|
22
|
+
"Programming Language :: Python :: 3.10",
|
|
23
|
+
"Programming Language :: Python :: 3.11",
|
|
24
|
+
"Programming Language :: Python :: 3.12",
|
|
25
|
+
"Programming Language :: Python :: 3.13",
|
|
26
|
+
"Topic :: Multimedia :: Video",
|
|
27
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
28
|
+
]
|
|
29
|
+
dependencies = [
|
|
30
|
+
"httpx>=0.25.0",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.optional-dependencies]
|
|
34
|
+
dev = [
|
|
35
|
+
"pytest>=7.0",
|
|
36
|
+
"pytest-asyncio>=0.21",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
[project.urls]
|
|
40
|
+
Homepage = "https://cli.vcursor.com"
|
|
41
|
+
Repository = "https://github.com/JThh/vcursor"
|
|
42
|
+
Documentation = "https://cli.vcursor.com/docs"
|
|
43
|
+
|
|
44
|
+
[project.scripts]
|
|
45
|
+
vcursor = "vcursor.cli:main"
|
|
46
|
+
|
|
47
|
+
[tool.setuptools.packages.find]
|
|
48
|
+
where = ["."]
|
|
49
|
+
include = ["vcursor*"]
|
|
File without changes
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""Basic tests for type serialization/deserialization."""
|
|
2
|
+
|
|
3
|
+
from vcursor.types import (
|
|
4
|
+
SubmitRequest,
|
|
5
|
+
SubmitResponse,
|
|
6
|
+
TaskProgress,
|
|
7
|
+
AgentSubmitRequest,
|
|
8
|
+
AgentProgress,
|
|
9
|
+
ConcurrencyStatus,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_submit_request_to_dict():
|
|
14
|
+
req = SubmitRequest(prompt="hello world")
|
|
15
|
+
d = req.to_dict()
|
|
16
|
+
assert d == {"prompt": "hello world"}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_submit_request_with_extras():
|
|
20
|
+
req = SubmitRequest(
|
|
21
|
+
prompt="test",
|
|
22
|
+
media_keys=["key1"],
|
|
23
|
+
reference_urls=["https://example.com"],
|
|
24
|
+
submission_mode="plan",
|
|
25
|
+
)
|
|
26
|
+
d = req.to_dict()
|
|
27
|
+
assert d["media_keys"] == ["key1"]
|
|
28
|
+
assert d["reference_urls"] == ["https://example.com"]
|
|
29
|
+
assert d["submission_mode"] == "plan"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_submit_response_from_dict():
|
|
33
|
+
resp = SubmitResponse.from_dict({
|
|
34
|
+
"code": 200,
|
|
35
|
+
"message": "OK",
|
|
36
|
+
"task_id": "abc123",
|
|
37
|
+
"mode": "text2video",
|
|
38
|
+
})
|
|
39
|
+
assert resp.task_id == "abc123"
|
|
40
|
+
assert resp.mode == "text2video"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_task_progress_from_dict():
|
|
44
|
+
progress = TaskProgress.from_dict({
|
|
45
|
+
"code": 200,
|
|
46
|
+
"message": "OK",
|
|
47
|
+
"data": {
|
|
48
|
+
"task_id": "t1",
|
|
49
|
+
"status": "processing",
|
|
50
|
+
"progress": 50.0,
|
|
51
|
+
"queuing_time": 1.0,
|
|
52
|
+
"remaining_process_time": 10.0,
|
|
53
|
+
"total_process_time": 20.0,
|
|
54
|
+
"products": {
|
|
55
|
+
"url": "https://cdn.example.com/video.mp4",
|
|
56
|
+
"upload_completed": True,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
})
|
|
60
|
+
assert progress.data.status == "processing"
|
|
61
|
+
assert progress.data.progress == 50.0
|
|
62
|
+
assert progress.data.products.url == "https://cdn.example.com/video.mp4"
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def test_agent_submit_request_to_dict():
|
|
66
|
+
req = AgentSubmitRequest(message="make a commercial", duration="30s")
|
|
67
|
+
d = req.to_dict()
|
|
68
|
+
assert d == {"message": "make a commercial", "duration": "30s"}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_agent_progress_from_dict():
|
|
72
|
+
p = AgentProgress.from_dict({
|
|
73
|
+
"task_id": "a1",
|
|
74
|
+
"status": "completed",
|
|
75
|
+
"progress": 100.0,
|
|
76
|
+
"video_url": "https://cdn.example.com/agent.mp4",
|
|
77
|
+
})
|
|
78
|
+
assert p.status == "completed"
|
|
79
|
+
assert p.video_url == "https://cdn.example.com/agent.mp4"
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def test_concurrency_status_from_dict():
|
|
83
|
+
s = ConcurrencyStatus.from_dict({
|
|
84
|
+
"allowed": True,
|
|
85
|
+
"limit": 30,
|
|
86
|
+
"used": 5,
|
|
87
|
+
"remaining": 25,
|
|
88
|
+
"category": "standard",
|
|
89
|
+
"tier": "pro",
|
|
90
|
+
"bypassEnabled": False,
|
|
91
|
+
"windowHours": 1,
|
|
92
|
+
"resetAt": None,
|
|
93
|
+
"summary": {
|
|
94
|
+
"standard": {"used": 5, "limit": 30, "remaining": 25},
|
|
95
|
+
"agent": {"used": 1, "limit": 5, "remaining": 4},
|
|
96
|
+
},
|
|
97
|
+
})
|
|
98
|
+
assert s.allowed is True
|
|
99
|
+
assert s.limit == 30
|
|
100
|
+
assert s.used == 5
|
|
101
|
+
assert s.remaining == 25
|
|
102
|
+
assert s.category == "standard"
|
|
103
|
+
assert s.tier == "pro"
|
|
104
|
+
assert s.bypass_enabled is False
|
|
105
|
+
assert s.window_hours == 1
|
|
106
|
+
assert s.summary is not None
|
|
107
|
+
assert s.summary["standard"].used == 5
|
|
108
|
+
assert s.summary["standard"].limit == 30
|
|
109
|
+
assert s.summary["agent"].used == 1
|
|
110
|
+
assert s.summary["agent"].limit == 5
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""VCursor SDK - Generate videos from text, images, and URLs using AI."""
|
|
2
|
+
|
|
3
|
+
from vcursor.client import VCursor, VCursorAsync
|
|
4
|
+
from vcursor.types import (
|
|
5
|
+
SubmitRequest,
|
|
6
|
+
SubmitResponse,
|
|
7
|
+
TaskProgress,
|
|
8
|
+
AgentSubmitRequest,
|
|
9
|
+
AgentProgress,
|
|
10
|
+
CategoryUsage,
|
|
11
|
+
ConcurrencyStatus,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
__version__ = "1.0.0"
|
|
15
|
+
__all__ = [
|
|
16
|
+
"VCursor",
|
|
17
|
+
"VCursorAsync",
|
|
18
|
+
"SubmitRequest",
|
|
19
|
+
"SubmitResponse",
|
|
20
|
+
"TaskProgress",
|
|
21
|
+
"AgentSubmitRequest",
|
|
22
|
+
"AgentProgress",
|
|
23
|
+
"CategoryUsage",
|
|
24
|
+
"ConcurrencyStatus",
|
|
25
|
+
]
|