hoox-mcp 0.1.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.
- hoox_mcp-0.1.0/.gitignore +18 -0
- hoox_mcp-0.1.0/LICENSE +22 -0
- hoox_mcp-0.1.0/PKG-INFO +187 -0
- hoox_mcp-0.1.0/README.md +163 -0
- hoox_mcp-0.1.0/hoox_mcp/__init__.py +5 -0
- hoox_mcp-0.1.0/hoox_mcp/client.py +164 -0
- hoox_mcp-0.1.0/hoox_mcp/server.py +510 -0
- hoox_mcp-0.1.0/pyproject.toml +45 -0
- hoox_mcp-0.1.0/setup.py +5 -0
- hoox_mcp-0.1.0/tests/__init__.py +0 -0
- hoox_mcp-0.1.0/tests/test_tools.py +284 -0
- hoox_mcp-0.1.0/uv.lock +748 -0
hoox_mcp-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Hoox
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
hoox_mcp-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hoox-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MCP server for Hoox — AI video generation platform
|
|
5
|
+
Project-URL: Homepage, https://hoox.video
|
|
6
|
+
Project-URL: Documentation, https://docs.hoox.video
|
|
7
|
+
Author-email: Hoox <alerts@hoox.video>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: ai,generation,hoox,mcp,video
|
|
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.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Multimedia :: Video
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Requires-Dist: httpx>=0.27.0
|
|
22
|
+
Requires-Dist: mcp>=1.0.0
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# Hoox MCP Server
|
|
26
|
+
|
|
27
|
+
Official [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server for [Hoox](https://hoox.video) — the AI video generation platform. This server lets any MCP-compatible client (Claude Desktop, Cursor, Windsurf, etc.) generate videos, manage avatars and voices, and export MP4 files using natural language.
|
|
28
|
+
|
|
29
|
+
## Quickstart with Claude Desktop
|
|
30
|
+
|
|
31
|
+
1. Get your API key from [app.hoox.video → Settings → API Keys](https://app.hoox.video). An **Enterprise** plan is required to access the API.
|
|
32
|
+
2. Install `uv` (Python package manager): `curl -LsSf https://astral.sh/uv/install.sh | sh`
|
|
33
|
+
3. Add the following configuration to your `claude_desktop_config.json` (Claude → Preferences → Developer → Edit Config):
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"mcpServers": {
|
|
38
|
+
"hoox": {
|
|
39
|
+
"command": "uvx",
|
|
40
|
+
"args": ["hoox-mcp"],
|
|
41
|
+
"env": {
|
|
42
|
+
"HOOX_API_KEY": "hx_live_your_key_here"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Other MCP clients
|
|
50
|
+
|
|
51
|
+
For Cursor, Windsurf, or any other compatible client:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install hoox-mcp
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Then add the configuration to your client's MCP configuration file:
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"mcpServers": {
|
|
62
|
+
"hoox": {
|
|
63
|
+
"command": "hoox-mcp",
|
|
64
|
+
"env": {
|
|
65
|
+
"HOOX_API_KEY": "hx_live_your_key_here"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Your MCP client can now interact with Hoox through the tools listed below.
|
|
73
|
+
|
|
74
|
+
## Example prompts
|
|
75
|
+
|
|
76
|
+
> ⚠️ Hoox credits are required to use these tools.
|
|
77
|
+
|
|
78
|
+
Try for example:
|
|
79
|
+
|
|
80
|
+
- *"Use the Hoox API to generate a 60-second vertical product demo video for our new DTC skincare serum."*
|
|
81
|
+
- *"List the male avatars available with a professional style"*
|
|
82
|
+
- *"Create an avatar from this description: man in a conference room in a suit"*
|
|
83
|
+
- *"Duplicate the video vid_xxx by changing the voice to a male English voice"*
|
|
84
|
+
- *"Generate a 45 second script about our new DTC skincare serum, then start the video generation and export the result as MP4"*
|
|
85
|
+
|
|
86
|
+
## Available tools
|
|
87
|
+
|
|
88
|
+
### Voices
|
|
89
|
+
|
|
90
|
+
| Tool | Description |
|
|
91
|
+
|-----------------------|-------------------------------------------------------------------|
|
|
92
|
+
| `list_voices` | List available voices with optional filters (language, gender, tags) |
|
|
93
|
+
| `get_voice` | Get details for a voice by ID |
|
|
94
|
+
| `list_resource_voices`| Simplified voice list optimized for generation |
|
|
95
|
+
|
|
96
|
+
### Avatars
|
|
97
|
+
|
|
98
|
+
| Tool | Description |
|
|
99
|
+
|-------------------------|---------------------------------------------------------------|
|
|
100
|
+
| `list_avatars` | List available avatars with optional filters (gender, tags) |
|
|
101
|
+
| `get_avatar` | Get full details for an avatar and its looks |
|
|
102
|
+
| `get_avatar_look` | Get details for a specific look |
|
|
103
|
+
| `create_avatar` | Create a new avatar from a prompt or reference images |
|
|
104
|
+
| `edit_avatar` | Edit an existing look to create a new variation |
|
|
105
|
+
| `get_avatar_status` | Check the creation status of an avatar |
|
|
106
|
+
| `list_resource_avatars` | Simplified avatar list optimized for generation |
|
|
107
|
+
|
|
108
|
+
### Script
|
|
109
|
+
|
|
110
|
+
| Tool | Description |
|
|
111
|
+
|-------------------|--------------------------------------------------|
|
|
112
|
+
| `generate_script` | Generate a video narration script from a prompt |
|
|
113
|
+
|
|
114
|
+
### Video generation
|
|
115
|
+
|
|
116
|
+
| Tool | Description |
|
|
117
|
+
|----------------------|-----------------------------------------------------|
|
|
118
|
+
| `start_generation` | Start an AI video generation job |
|
|
119
|
+
| `get_generation_status` | Check the status and progress of a generation job |
|
|
120
|
+
|
|
121
|
+
### Export
|
|
122
|
+
|
|
123
|
+
| Tool | Description |
|
|
124
|
+
|------------------|-----------------------------------------------|
|
|
125
|
+
| `start_export` | Start exporting a generated video to MP4 |
|
|
126
|
+
| `get_export_status` | Check the status of an export job |
|
|
127
|
+
|
|
128
|
+
### Video management
|
|
129
|
+
|
|
130
|
+
| Tool | Description |
|
|
131
|
+
|------------------|---------------------------------------------------------------------|
|
|
132
|
+
| `duplicate_video`| Duplicate a completed video, optionally changing the voice or avatar|
|
|
133
|
+
|
|
134
|
+
## Typical workflow
|
|
135
|
+
|
|
136
|
+
```text
|
|
137
|
+
1. list_resource_voices / list_resource_avatars → pick a voice & avatar
|
|
138
|
+
2. generate_script (optional) → get narration text
|
|
139
|
+
3. start_generation → get job_id
|
|
140
|
+
4. get_generation_status (polling) → get video_id
|
|
141
|
+
5. start_export → get export job_id
|
|
142
|
+
6. get_export_status (polling) → get MP4 download URL
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Configuration
|
|
146
|
+
|
|
147
|
+
| Environment variable | Required | Default | Description |
|
|
148
|
+
|----------------------|---------|------------------------------------------|-------------------------------------|
|
|
149
|
+
| `HOOX_API_KEY` | Yes | — | Your Hoox API key (`hx_live_...`) |
|
|
150
|
+
| `HOOX_BASE_URL` | No | `https://app.hoox.video/api/public/v1` | Override the API base URL |
|
|
151
|
+
|
|
152
|
+
## Troubleshooting
|
|
153
|
+
|
|
154
|
+
### "HOOX_API_KEY is required"
|
|
155
|
+
|
|
156
|
+
Make sure the `HOOX_API_KEY` environment variable is set in your MCP client configuration. The key must start with `hx_live_` or `hx_`.
|
|
157
|
+
|
|
158
|
+
### Error `plan_required` (403)
|
|
159
|
+
|
|
160
|
+
Your Hoox account must have an **Enterprise** plan to use the API. Upgrade at [app.hoox.video](https://app.hoox.video).
|
|
161
|
+
|
|
162
|
+
### Error `insufficient_credits` (402)
|
|
163
|
+
|
|
164
|
+
Your workspace has run out of credits. Top up from the Hoox dashboard under Settings → Billing.
|
|
165
|
+
|
|
166
|
+
### Error `rate_limit_exceeded` (429)
|
|
167
|
+
|
|
168
|
+
The API allows 100 requests per minute on the Enterprise plan. Wait a bit before trying again.
|
|
169
|
+
|
|
170
|
+
### Tool not showing up in Claude Desktop / Cursor
|
|
171
|
+
|
|
172
|
+
1. Check that `hoox-mcp` is installed: `pip install hoox-mcp` or `uvx hoox-mcp --help`
|
|
173
|
+
2. Restart your MCP client after updating the configuration
|
|
174
|
+
3. Check your client's logs for connection errors
|
|
175
|
+
|
|
176
|
+
Claude Desktop logs are located at:
|
|
177
|
+
|
|
178
|
+
- macOS: `~/Library/Logs/Claude/mcp-server-hoox.log`
|
|
179
|
+
- Windows: `%APPDATA%\\Claude\\logs\\mcp-server-hoox.log`
|
|
180
|
+
|
|
181
|
+
### Generation stuck in "processing"
|
|
182
|
+
|
|
183
|
+
Video generation can take between 1 and 5 minutes depending on duration and options. Use `get_generation_status` to monitor progress. If the job is stuck for more than 10 minutes, it may have failed — check the `error` field in the status response.
|
|
184
|
+
|
|
185
|
+
## License
|
|
186
|
+
|
|
187
|
+
This project is licensed under the MIT License. See `LICENSE` for details.
|
hoox_mcp-0.1.0/README.md
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Hoox MCP Server
|
|
2
|
+
|
|
3
|
+
Official [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server for [Hoox](https://hoox.video) — the AI video generation platform. This server lets any MCP-compatible client (Claude Desktop, Cursor, Windsurf, etc.) generate videos, manage avatars and voices, and export MP4 files using natural language.
|
|
4
|
+
|
|
5
|
+
## Quickstart with Claude Desktop
|
|
6
|
+
|
|
7
|
+
1. Get your API key from [app.hoox.video → Settings → API Keys](https://app.hoox.video). An **Enterprise** plan is required to access the API.
|
|
8
|
+
2. Install `uv` (Python package manager): `curl -LsSf https://astral.sh/uv/install.sh | sh`
|
|
9
|
+
3. Add the following configuration to your `claude_desktop_config.json` (Claude → Preferences → Developer → Edit Config):
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"mcpServers": {
|
|
14
|
+
"hoox": {
|
|
15
|
+
"command": "uvx",
|
|
16
|
+
"args": ["hoox-mcp"],
|
|
17
|
+
"env": {
|
|
18
|
+
"HOOX_API_KEY": "hx_live_your_key_here"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Other MCP clients
|
|
26
|
+
|
|
27
|
+
For Cursor, Windsurf, or any other compatible client:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install hoox-mcp
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Then add the configuration to your client's MCP configuration file:
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"mcpServers": {
|
|
38
|
+
"hoox": {
|
|
39
|
+
"command": "hoox-mcp",
|
|
40
|
+
"env": {
|
|
41
|
+
"HOOX_API_KEY": "hx_live_your_key_here"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Your MCP client can now interact with Hoox through the tools listed below.
|
|
49
|
+
|
|
50
|
+
## Example prompts
|
|
51
|
+
|
|
52
|
+
> ⚠️ Hoox credits are required to use these tools.
|
|
53
|
+
|
|
54
|
+
Try for example:
|
|
55
|
+
|
|
56
|
+
- *"Use the Hoox API to generate a 60-second vertical product demo video for our new DTC skincare serum."*
|
|
57
|
+
- *"List the male avatars available with a professional style"*
|
|
58
|
+
- *"Create an avatar from this description: man in a conference room in a suit"*
|
|
59
|
+
- *"Duplicate the video vid_xxx by changing the voice to a male English voice"*
|
|
60
|
+
- *"Generate a 45 second script about our new DTC skincare serum, then start the video generation and export the result as MP4"*
|
|
61
|
+
|
|
62
|
+
## Available tools
|
|
63
|
+
|
|
64
|
+
### Voices
|
|
65
|
+
|
|
66
|
+
| Tool | Description |
|
|
67
|
+
|-----------------------|-------------------------------------------------------------------|
|
|
68
|
+
| `list_voices` | List available voices with optional filters (language, gender, tags) |
|
|
69
|
+
| `get_voice` | Get details for a voice by ID |
|
|
70
|
+
| `list_resource_voices`| Simplified voice list optimized for generation |
|
|
71
|
+
|
|
72
|
+
### Avatars
|
|
73
|
+
|
|
74
|
+
| Tool | Description |
|
|
75
|
+
|-------------------------|---------------------------------------------------------------|
|
|
76
|
+
| `list_avatars` | List available avatars with optional filters (gender, tags) |
|
|
77
|
+
| `get_avatar` | Get full details for an avatar and its looks |
|
|
78
|
+
| `get_avatar_look` | Get details for a specific look |
|
|
79
|
+
| `create_avatar` | Create a new avatar from a prompt or reference images |
|
|
80
|
+
| `edit_avatar` | Edit an existing look to create a new variation |
|
|
81
|
+
| `get_avatar_status` | Check the creation status of an avatar |
|
|
82
|
+
| `list_resource_avatars` | Simplified avatar list optimized for generation |
|
|
83
|
+
|
|
84
|
+
### Script
|
|
85
|
+
|
|
86
|
+
| Tool | Description |
|
|
87
|
+
|-------------------|--------------------------------------------------|
|
|
88
|
+
| `generate_script` | Generate a video narration script from a prompt |
|
|
89
|
+
|
|
90
|
+
### Video generation
|
|
91
|
+
|
|
92
|
+
| Tool | Description |
|
|
93
|
+
|----------------------|-----------------------------------------------------|
|
|
94
|
+
| `start_generation` | Start an AI video generation job |
|
|
95
|
+
| `get_generation_status` | Check the status and progress of a generation job |
|
|
96
|
+
|
|
97
|
+
### Export
|
|
98
|
+
|
|
99
|
+
| Tool | Description |
|
|
100
|
+
|------------------|-----------------------------------------------|
|
|
101
|
+
| `start_export` | Start exporting a generated video to MP4 |
|
|
102
|
+
| `get_export_status` | Check the status of an export job |
|
|
103
|
+
|
|
104
|
+
### Video management
|
|
105
|
+
|
|
106
|
+
| Tool | Description |
|
|
107
|
+
|------------------|---------------------------------------------------------------------|
|
|
108
|
+
| `duplicate_video`| Duplicate a completed video, optionally changing the voice or avatar|
|
|
109
|
+
|
|
110
|
+
## Typical workflow
|
|
111
|
+
|
|
112
|
+
```text
|
|
113
|
+
1. list_resource_voices / list_resource_avatars → pick a voice & avatar
|
|
114
|
+
2. generate_script (optional) → get narration text
|
|
115
|
+
3. start_generation → get job_id
|
|
116
|
+
4. get_generation_status (polling) → get video_id
|
|
117
|
+
5. start_export → get export job_id
|
|
118
|
+
6. get_export_status (polling) → get MP4 download URL
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Configuration
|
|
122
|
+
|
|
123
|
+
| Environment variable | Required | Default | Description |
|
|
124
|
+
|----------------------|---------|------------------------------------------|-------------------------------------|
|
|
125
|
+
| `HOOX_API_KEY` | Yes | — | Your Hoox API key (`hx_live_...`) |
|
|
126
|
+
| `HOOX_BASE_URL` | No | `https://app.hoox.video/api/public/v1` | Override the API base URL |
|
|
127
|
+
|
|
128
|
+
## Troubleshooting
|
|
129
|
+
|
|
130
|
+
### "HOOX_API_KEY is required"
|
|
131
|
+
|
|
132
|
+
Make sure the `HOOX_API_KEY` environment variable is set in your MCP client configuration. The key must start with `hx_live_` or `hx_`.
|
|
133
|
+
|
|
134
|
+
### Error `plan_required` (403)
|
|
135
|
+
|
|
136
|
+
Your Hoox account must have an **Enterprise** plan to use the API. Upgrade at [app.hoox.video](https://app.hoox.video).
|
|
137
|
+
|
|
138
|
+
### Error `insufficient_credits` (402)
|
|
139
|
+
|
|
140
|
+
Your workspace has run out of credits. Top up from the Hoox dashboard under Settings → Billing.
|
|
141
|
+
|
|
142
|
+
### Error `rate_limit_exceeded` (429)
|
|
143
|
+
|
|
144
|
+
The API allows 100 requests per minute on the Enterprise plan. Wait a bit before trying again.
|
|
145
|
+
|
|
146
|
+
### Tool not showing up in Claude Desktop / Cursor
|
|
147
|
+
|
|
148
|
+
1. Check that `hoox-mcp` is installed: `pip install hoox-mcp` or `uvx hoox-mcp --help`
|
|
149
|
+
2. Restart your MCP client after updating the configuration
|
|
150
|
+
3. Check your client's logs for connection errors
|
|
151
|
+
|
|
152
|
+
Claude Desktop logs are located at:
|
|
153
|
+
|
|
154
|
+
- macOS: `~/Library/Logs/Claude/mcp-server-hoox.log`
|
|
155
|
+
- Windows: `%APPDATA%\\Claude\\logs\\mcp-server-hoox.log`
|
|
156
|
+
|
|
157
|
+
### Generation stuck in "processing"
|
|
158
|
+
|
|
159
|
+
Video generation can take between 1 and 5 minutes depending on duration and options. Use `get_generation_status` to monitor progress. If the job is stuck for more than 10 minutes, it may have failed — check the `error` field in the status response.
|
|
160
|
+
|
|
161
|
+
## License
|
|
162
|
+
|
|
163
|
+
This project is licensed under the MIT License. See `LICENSE` for details.
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"""Thin async HTTP client wrapping the Hoox public REST API."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
import httpx
|
|
9
|
+
|
|
10
|
+
DEFAULT_BASE_URL = "https://app.hoox.video/api/public/v1"
|
|
11
|
+
REQUEST_TIMEOUT = 120.0
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class HooxClientError(Exception):
|
|
15
|
+
"""Raised when the Hoox API returns a non-2xx response."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, status_code: int, detail: str) -> None:
|
|
18
|
+
self.status_code = status_code
|
|
19
|
+
self.detail = detail
|
|
20
|
+
super().__init__(f"HTTP {status_code}: {detail}")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class HooxClient:
|
|
24
|
+
"""Lightweight async wrapper around the Hoox public API v1."""
|
|
25
|
+
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
api_key: str | None = None,
|
|
29
|
+
base_url: str | None = None,
|
|
30
|
+
) -> None:
|
|
31
|
+
self.api_key = api_key or os.environ.get("HOOX_API_KEY", "")
|
|
32
|
+
# HOOX_BASE_URL is intentionally not read from the environment to avoid
|
|
33
|
+
# accidentally sending API requests (and the API key) to an unexpected host.
|
|
34
|
+
# If a different endpoint is needed (e.g. for staging), it must be passed
|
|
35
|
+
# explicitly via the base_url argument.
|
|
36
|
+
self.base_url = (base_url or DEFAULT_BASE_URL).rstrip("/")
|
|
37
|
+
if not self.api_key:
|
|
38
|
+
raise ValueError(
|
|
39
|
+
"HOOX_API_KEY is required. Set it as an environment variable or pass it directly."
|
|
40
|
+
)
|
|
41
|
+
self._client = httpx.AsyncClient(
|
|
42
|
+
base_url=self.base_url,
|
|
43
|
+
headers={
|
|
44
|
+
"Authorization": f"Bearer {self.api_key}",
|
|
45
|
+
"Content-Type": "application/json",
|
|
46
|
+
},
|
|
47
|
+
timeout=REQUEST_TIMEOUT,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
async def close(self) -> None:
|
|
51
|
+
await self._client.aclose()
|
|
52
|
+
|
|
53
|
+
async def _request(
|
|
54
|
+
self,
|
|
55
|
+
method: str,
|
|
56
|
+
path: str,
|
|
57
|
+
*,
|
|
58
|
+
params: dict[str, Any] | None = None,
|
|
59
|
+
json_body: dict[str, Any] | None = None,
|
|
60
|
+
) -> Any:
|
|
61
|
+
resp = await self._client.request(method, path, params=params, json=json_body)
|
|
62
|
+
if resp.status_code >= 400:
|
|
63
|
+
try:
|
|
64
|
+
detail = resp.json()
|
|
65
|
+
except Exception:
|
|
66
|
+
detail = resp.text
|
|
67
|
+
raise HooxClientError(resp.status_code, str(detail))
|
|
68
|
+
return resp.json()
|
|
69
|
+
|
|
70
|
+
# ------------------------------------------------------------------
|
|
71
|
+
# Voices
|
|
72
|
+
# ------------------------------------------------------------------
|
|
73
|
+
|
|
74
|
+
async def list_voices(
|
|
75
|
+
self,
|
|
76
|
+
language: str | None = None,
|
|
77
|
+
gender: str | None = None,
|
|
78
|
+
tags: str | None = None,
|
|
79
|
+
only_public: bool | None = None,
|
|
80
|
+
) -> Any:
|
|
81
|
+
params: dict[str, Any] = {}
|
|
82
|
+
if language:
|
|
83
|
+
params["language"] = language
|
|
84
|
+
if gender:
|
|
85
|
+
params["gender"] = gender
|
|
86
|
+
if tags:
|
|
87
|
+
params["tags"] = tags
|
|
88
|
+
if only_public is not None:
|
|
89
|
+
params["onlyPublic"] = str(only_public).lower()
|
|
90
|
+
return await self._request("GET", "/voice/list", params=params)
|
|
91
|
+
|
|
92
|
+
async def get_voice(self, voice_id: str) -> Any:
|
|
93
|
+
return await self._request("GET", f"/voice/{voice_id}")
|
|
94
|
+
|
|
95
|
+
# ------------------------------------------------------------------
|
|
96
|
+
# Avatars
|
|
97
|
+
# ------------------------------------------------------------------
|
|
98
|
+
|
|
99
|
+
async def list_avatars(
|
|
100
|
+
self,
|
|
101
|
+
gender: str | None = None,
|
|
102
|
+
tags: str | None = None,
|
|
103
|
+
only_public: bool | None = None,
|
|
104
|
+
) -> Any:
|
|
105
|
+
params: dict[str, Any] = {}
|
|
106
|
+
if gender:
|
|
107
|
+
params["gender"] = gender
|
|
108
|
+
if tags:
|
|
109
|
+
params["tags"] = tags
|
|
110
|
+
if only_public is not None:
|
|
111
|
+
params["onlyPublic"] = str(only_public).lower()
|
|
112
|
+
return await self._request("GET", "/avatar/list", params=params)
|
|
113
|
+
|
|
114
|
+
async def get_avatar(self, avatar_id: str) -> Any:
|
|
115
|
+
return await self._request("GET", f"/avatar/{avatar_id}")
|
|
116
|
+
|
|
117
|
+
async def get_avatar_look(self, avatar_id: str, look_id: str) -> Any:
|
|
118
|
+
return await self._request("GET", f"/avatar/{avatar_id}/look/{look_id}")
|
|
119
|
+
|
|
120
|
+
async def get_avatar_status(self, avatar_id: str, look_id: str) -> Any:
|
|
121
|
+
return await self._request(
|
|
122
|
+
"GET", "/avatar/status", params={"avatar_id": avatar_id, "look_id": look_id}
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
async def create_avatar(self, **kwargs: Any) -> Any:
|
|
126
|
+
return await self._request("POST", "/avatar/create", json_body=kwargs)
|
|
127
|
+
|
|
128
|
+
async def edit_avatar(self, **kwargs: Any) -> Any:
|
|
129
|
+
return await self._request("POST", "/avatar/edit", json_body=kwargs)
|
|
130
|
+
|
|
131
|
+
# ------------------------------------------------------------------
|
|
132
|
+
# Script
|
|
133
|
+
# ------------------------------------------------------------------
|
|
134
|
+
|
|
135
|
+
async def generate_script(self, **kwargs: Any) -> Any:
|
|
136
|
+
return await self._request("POST", "/script/generate", json_body=kwargs)
|
|
137
|
+
|
|
138
|
+
# ------------------------------------------------------------------
|
|
139
|
+
# Generation
|
|
140
|
+
# ------------------------------------------------------------------
|
|
141
|
+
|
|
142
|
+
async def start_generation(self, **kwargs: Any) -> Any:
|
|
143
|
+
return await self._request("POST", "/generation/start", json_body=kwargs)
|
|
144
|
+
|
|
145
|
+
async def get_generation_status(self, job_id: str) -> Any:
|
|
146
|
+
return await self._request("GET", f"/generation/status/{job_id}")
|
|
147
|
+
|
|
148
|
+
# ------------------------------------------------------------------
|
|
149
|
+
# Export
|
|
150
|
+
# ------------------------------------------------------------------
|
|
151
|
+
|
|
152
|
+
async def start_export(self, **kwargs: Any) -> Any:
|
|
153
|
+
return await self._request("POST", "/export/start", json_body=kwargs)
|
|
154
|
+
|
|
155
|
+
async def get_export_status(self, job_id: str) -> Any:
|
|
156
|
+
return await self._request("GET", f"/export/status/{job_id}")
|
|
157
|
+
|
|
158
|
+
# ------------------------------------------------------------------
|
|
159
|
+
# Video
|
|
160
|
+
# ------------------------------------------------------------------
|
|
161
|
+
|
|
162
|
+
async def duplicate_video(self, **kwargs: Any) -> Any:
|
|
163
|
+
return await self._request("POST", "/video/duplicate", json_body=kwargs)
|
|
164
|
+
|