@gaudiolab/mcp-developers 1.0.0
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.
- package/LICENSE +21 -0
- package/README.md +110 -0
- package/dist/api/client.d.ts +27 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +106 -0
- package/dist/api/client.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/models/registry.d.ts +14 -0
- package/dist/models/registry.d.ts.map +1 -0
- package/dist/models/registry.js +116 -0
- package/dist/models/registry.js.map +1 -0
- package/dist/tools/create-job.d.ts +4 -0
- package/dist/tools/create-job.d.ts.map +1 -0
- package/dist/tools/create-job.js +44 -0
- package/dist/tools/create-job.js.map +1 -0
- package/dist/tools/get-job.d.ts +4 -0
- package/dist/tools/get-job.d.ts.map +1 -0
- package/dist/tools/get-job.js +39 -0
- package/dist/tools/get-job.js.map +1 -0
- package/dist/tools/list-models.d.ts +3 -0
- package/dist/tools/list-models.d.ts.map +1 -0
- package/dist/tools/list-models.js +31 -0
- package/dist/tools/list-models.js.map +1 -0
- package/dist/tools/separate-audio.d.ts +4 -0
- package/dist/tools/separate-audio.d.ts.map +1 -0
- package/dist/tools/separate-audio.js +102 -0
- package/dist/tools/separate-audio.js.map +1 -0
- package/dist/tools/sync-lyrics.d.ts +4 -0
- package/dist/tools/sync-lyrics.d.ts.map +1 -0
- package/dist/tools/sync-lyrics.js +96 -0
- package/dist/tools/sync-lyrics.js.map +1 -0
- package/dist/tools/upload-file.d.ts +4 -0
- package/dist/tools/upload-file.d.ts.map +1 -0
- package/dist/tools/upload-file.js +20 -0
- package/dist/tools/upload-file.js.map +1 -0
- package/dist/utils/errors.d.ts +8 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +48 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/polling.d.ts +10 -0
- package/dist/utils/polling.d.ts.map +1 -0
- package/dist/utils/polling.js +49 -0
- package/dist/utils/polling.js.map +1 -0
- package/package.json +42 -0
- package/server.json +28 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Gaudio Lab
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# @gaudiolab/mcp-developers
|
|
2
|
+
|
|
3
|
+
MCP server for [Gaudio Lab](https://www.gaudiolab.com) Audio AI API. Separate vocals, instruments, dialogue, music, effects from any audio/video — or sync lyrics to timestamps — all through natural language in your AI tools.
|
|
4
|
+
|
|
5
|
+
Works with Claude, ChatGPT, Cursor, VS Code, GitHub Copilot, and any MCP-compatible client.
|
|
6
|
+
|
|
7
|
+
## Get Your API Key
|
|
8
|
+
|
|
9
|
+
1. Sign up at [Gaudio Developers](https://developers.gaudiolab.io)
|
|
10
|
+
2. Create a project and get your API key from the dashboard
|
|
11
|
+
|
|
12
|
+
## Quick Start
|
|
13
|
+
|
|
14
|
+
Add to your MCP client config:
|
|
15
|
+
|
|
16
|
+
```json
|
|
17
|
+
{
|
|
18
|
+
"mcpServers": {
|
|
19
|
+
"gaudio": {
|
|
20
|
+
"command": "npx",
|
|
21
|
+
"args": ["-y", "@gaudiolab/mcp-developers"],
|
|
22
|
+
"env": {
|
|
23
|
+
"GAUDIO_API_KEY": "your-api-key-here"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Then just ask in natural language:
|
|
31
|
+
|
|
32
|
+
- *"Separate the vocals from this file"*
|
|
33
|
+
- *"Extract the dialogue from this video"*
|
|
34
|
+
- *"Sync these lyrics to this song"*
|
|
35
|
+
- *"What models are available?"*
|
|
36
|
+
|
|
37
|
+
## Tools
|
|
38
|
+
|
|
39
|
+
| Tool | Description |
|
|
40
|
+
|------|-------------|
|
|
41
|
+
| `gaudio_list_models` | List available AI models by category |
|
|
42
|
+
| `gaudio_upload_file` | Upload audio/video/text file (multipart, auto-chunked) |
|
|
43
|
+
| `gaudio_create_job` | Create a processing job |
|
|
44
|
+
| `gaudio_get_job` | Check job status and get download URLs |
|
|
45
|
+
| `gaudio_separate_audio` | All-in-one: upload → process → download URLs |
|
|
46
|
+
| `gaudio_sync_lyrics` | All-in-one lyrics sync with timestamps |
|
|
47
|
+
|
|
48
|
+
## Models
|
|
49
|
+
|
|
50
|
+
### Stem Separation
|
|
51
|
+
|
|
52
|
+
| Model | Description | Type Options |
|
|
53
|
+
|-------|-------------|-------------|
|
|
54
|
+
| `gsep_music_hq_v1` | Multi-instrument separation | vocal, drum, bass, electric_guitar, acoustic_piano |
|
|
55
|
+
| `gsep_music_shq_v1` | Super HQ vocal + accompaniment | vocal |
|
|
56
|
+
| `gsep_speech_hq_v1` | Speech / noise removal | speech |
|
|
57
|
+
|
|
58
|
+
Max: 1GB / 20 min per file. Types can be combined (e.g. `vocal,drum`).
|
|
59
|
+
|
|
60
|
+
### DME Separation (Dialogue, Music, Effects)
|
|
61
|
+
|
|
62
|
+
| Model | Description |
|
|
63
|
+
|-------|-------------|
|
|
64
|
+
| `gsep_dme_dtrack_v1` | Dialogue extraction |
|
|
65
|
+
| `gsep_dme_d2track_v1` | Dialogue + vocals |
|
|
66
|
+
| `gsep_dme_metrack_v1` | Music + effects |
|
|
67
|
+
| `gsep_dme_me2track_v1` | Music + effects v1 |
|
|
68
|
+
| `gsep_dme_me2track_v2` | Music + effects v2 (high quality) |
|
|
69
|
+
| `gsep_dme_mtrack_v1` | Music only |
|
|
70
|
+
| `gsep_dme_etrack_v1` | Effects only |
|
|
71
|
+
|
|
72
|
+
Max: 10GB / 200 min per file.
|
|
73
|
+
|
|
74
|
+
### AI Text Sync
|
|
75
|
+
|
|
76
|
+
| Model | Description | Languages |
|
|
77
|
+
|-------|-------------|-----------|
|
|
78
|
+
| `gts_lyrics_line_v1` | Lyrics line sync | en, ko, ja, zh-cn |
|
|
79
|
+
|
|
80
|
+
Max: 1GB / 10 min. Text: `.txt` (UTF-8), min 2 lines, max 60 chars/line.
|
|
81
|
+
|
|
82
|
+
Output: CSV (timestamp, lyric_text, confidence_score) + JSON report.
|
|
83
|
+
|
|
84
|
+
## Supported Formats
|
|
85
|
+
|
|
86
|
+
| Type | Formats |
|
|
87
|
+
|------|---------|
|
|
88
|
+
| Audio | WAV, FLAC, MP3, M4A |
|
|
89
|
+
| Video | MOV, MP4 (audio auto-extracted) |
|
|
90
|
+
| Text | TXT (UTF-8) |
|
|
91
|
+
|
|
92
|
+
Output: MP3 (48kHz/320kbps) + WAV (same as input). Download URLs valid for 48 hours.
|
|
93
|
+
|
|
94
|
+
## How It Works
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
Upload file → Create job → Poll status → Get download URLs
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The high-level tools (`gaudio_separate_audio`, `gaudio_sync_lyrics`) handle this entire flow automatically. Upload IDs are valid for 72 hours and can be reused across multiple jobs.
|
|
101
|
+
|
|
102
|
+
## Links
|
|
103
|
+
|
|
104
|
+
- [Gaudio Developers](https://developers.gaudiolab.io) — API dashboard & key management
|
|
105
|
+
- [Documentation](https://www.gaudiolab.com/docs) — Full API reference
|
|
106
|
+
- [Gaudio Lab](https://www.gaudiolab.com) — Company homepage
|
|
107
|
+
|
|
108
|
+
## License
|
|
109
|
+
|
|
110
|
+
MIT
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface ApiResponse {
|
|
2
|
+
resultCode: number;
|
|
3
|
+
resultData?: Record<string, unknown>;
|
|
4
|
+
}
|
|
5
|
+
export declare class GaudioClient {
|
|
6
|
+
private apiKey;
|
|
7
|
+
constructor(apiKey: string);
|
|
8
|
+
private request;
|
|
9
|
+
uploadCreate(fileName: string, fileSize: number): Promise<{
|
|
10
|
+
uploadId: string;
|
|
11
|
+
chunkSize: number;
|
|
12
|
+
preSignedUrl: string[];
|
|
13
|
+
}>;
|
|
14
|
+
uploadChunk(presignedUrl: string, chunk: Uint8Array, contentType: string): Promise<string>;
|
|
15
|
+
uploadComplete(uploadId: string, parts: {
|
|
16
|
+
awsETag: string;
|
|
17
|
+
partNumber: number;
|
|
18
|
+
}[]): Promise<void>;
|
|
19
|
+
uploadFile(filePath: string): Promise<{
|
|
20
|
+
uploadId: string;
|
|
21
|
+
}>;
|
|
22
|
+
createJob(model: string, params: Record<string, unknown>): Promise<{
|
|
23
|
+
jobId: string;
|
|
24
|
+
}>;
|
|
25
|
+
getJob(model: string, jobId: string): Promise<ApiResponse>;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,MAAM;YAIZ,OAAO;IAgDf,YAAY,CAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QACT,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,EAAE,CAAC;KACxB,CAAC;IAYI,WAAW,CACf,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,UAAU,EACjB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC;IAqBZ,cAAc,CAClB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,EAAE,GAC/C,OAAO,CAAC,IAAI,CAAC;IAOV,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAwC3D,SAAS,CACb,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAKvB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;CAGjE"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { readFileSync, statSync } from "node:fs";
|
|
2
|
+
import { basename } from "node:path";
|
|
3
|
+
import { GaudioApiError, getResultCodeMessage, getHttpErrorMessage } from "../utils/errors.js";
|
|
4
|
+
const BASE_URL = "https://restapi.gaudiolab.io/developers/api/v1";
|
|
5
|
+
const RATE_LIMIT_WAIT_MS = 61_000;
|
|
6
|
+
const MAX_RETRIES = 2;
|
|
7
|
+
export class GaudioClient {
|
|
8
|
+
apiKey;
|
|
9
|
+
constructor(apiKey) {
|
|
10
|
+
this.apiKey = apiKey;
|
|
11
|
+
}
|
|
12
|
+
async request(method, path, body) {
|
|
13
|
+
const url = `${BASE_URL}${path}`;
|
|
14
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
15
|
+
const response = await fetch(url, {
|
|
16
|
+
method,
|
|
17
|
+
headers: {
|
|
18
|
+
"x-ga-apikey": this.apiKey,
|
|
19
|
+
"Content-Type": "application/json",
|
|
20
|
+
},
|
|
21
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
22
|
+
});
|
|
23
|
+
if (response.status === 429) {
|
|
24
|
+
if (attempt < MAX_RETRIES) {
|
|
25
|
+
await new Promise((r) => setTimeout(r, RATE_LIMIT_WAIT_MS));
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
throw new GaudioApiError(getHttpErrorMessage(429), 429);
|
|
29
|
+
}
|
|
30
|
+
if (!response.ok) {
|
|
31
|
+
throw new GaudioApiError(getHttpErrorMessage(response.status), response.status);
|
|
32
|
+
}
|
|
33
|
+
const data = (await response.json());
|
|
34
|
+
if (data.resultCode !== 1000) {
|
|
35
|
+
throw new GaudioApiError(getResultCodeMessage(data.resultCode), 200, data.resultCode);
|
|
36
|
+
}
|
|
37
|
+
return data;
|
|
38
|
+
}
|
|
39
|
+
throw new GaudioApiError("Max retries exceeded");
|
|
40
|
+
}
|
|
41
|
+
async uploadCreate(fileName, fileSize) {
|
|
42
|
+
const res = await this.request("POST", "/files/upload-multipart/create", {
|
|
43
|
+
fileName,
|
|
44
|
+
fileSize,
|
|
45
|
+
});
|
|
46
|
+
return res.resultData;
|
|
47
|
+
}
|
|
48
|
+
async uploadChunk(presignedUrl, chunk, contentType) {
|
|
49
|
+
const response = await fetch(presignedUrl, {
|
|
50
|
+
method: "PUT",
|
|
51
|
+
headers: { "Content-Type": contentType },
|
|
52
|
+
body: chunk,
|
|
53
|
+
});
|
|
54
|
+
if (!response.ok) {
|
|
55
|
+
throw new GaudioApiError(`Chunk upload failed: ${response.status}`, response.status);
|
|
56
|
+
}
|
|
57
|
+
const etag = response.headers.get("ETag");
|
|
58
|
+
if (!etag) {
|
|
59
|
+
throw new GaudioApiError("ETag header missing from chunk upload response");
|
|
60
|
+
}
|
|
61
|
+
return etag.replace(/"/g, "");
|
|
62
|
+
}
|
|
63
|
+
async uploadComplete(uploadId, parts) {
|
|
64
|
+
await this.request("POST", "/files/upload-multipart/complete", {
|
|
65
|
+
uploadId,
|
|
66
|
+
parts,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
async uploadFile(filePath) {
|
|
70
|
+
const stat = statSync(filePath);
|
|
71
|
+
const fileName = basename(filePath);
|
|
72
|
+
const fileSize = stat.size;
|
|
73
|
+
const fileBuffer = readFileSync(filePath);
|
|
74
|
+
const ext = fileName.split(".").pop()?.toLowerCase() ?? "";
|
|
75
|
+
const contentTypeMap = {
|
|
76
|
+
wav: "audio/wav",
|
|
77
|
+
flac: "audio/flac",
|
|
78
|
+
mp3: "audio/mpeg",
|
|
79
|
+
m4a: "audio/mp4",
|
|
80
|
+
mov: "video/quicktime",
|
|
81
|
+
mp4: "video/mp4",
|
|
82
|
+
txt: "text/plain",
|
|
83
|
+
};
|
|
84
|
+
const contentType = contentTypeMap[ext] ?? "application/octet-stream";
|
|
85
|
+
const { uploadId, chunkSize, preSignedUrl } = await this.uploadCreate(fileName, fileSize);
|
|
86
|
+
const parts = [];
|
|
87
|
+
for (let i = 0; i < preSignedUrl.length; i++) {
|
|
88
|
+
const start = i * chunkSize;
|
|
89
|
+
const end = Math.min(start + chunkSize, fileSize);
|
|
90
|
+
const chunk = fileBuffer.subarray(start, end);
|
|
91
|
+
const etag = await this.uploadChunk(preSignedUrl[i], new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength), contentType);
|
|
92
|
+
parts.push({ awsETag: etag, partNumber: i + 1 });
|
|
93
|
+
}
|
|
94
|
+
parts.sort((a, b) => a.partNumber - b.partNumber);
|
|
95
|
+
await this.uploadComplete(uploadId, parts);
|
|
96
|
+
return { uploadId };
|
|
97
|
+
}
|
|
98
|
+
async createJob(model, params) {
|
|
99
|
+
const res = await this.request("POST", `/${model}/jobs`, params);
|
|
100
|
+
return { jobId: res.resultData?.jobId };
|
|
101
|
+
}
|
|
102
|
+
async getJob(model, jobId) {
|
|
103
|
+
return this.request("GET", `/${model}/jobs/${jobId}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE/F,MAAM,QAAQ,GAAG,gDAAgD,CAAC;AAClE,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAClC,MAAM,WAAW,GAAG,CAAC,CAAC;AAOtB,MAAM,OAAO,YAAY;IACf,MAAM,CAAS;IAEvB,YAAY,MAAc;QACxB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAEO,KAAK,CAAC,OAAO,CACnB,MAAc,EACd,IAAY,EACZ,IAAc;QAEd,MAAM,GAAG,GAAG,GAAG,QAAQ,GAAG,IAAI,EAAE,CAAC;QAEjC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;YACxD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAChC,MAAM;gBACN,OAAO,EAAE;oBACP,aAAa,EAAE,IAAI,CAAC,MAAM;oBAC1B,cAAc,EAAE,kBAAkB;iBACnC;gBACD,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;aAC9C,CAAC,CAAC;YAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAC5B,IAAI,OAAO,GAAG,WAAW,EAAE,CAAC;oBAC1B,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC;oBAC5D,SAAS;gBACX,CAAC;gBACD,MAAM,IAAI,cAAc,CAAC,mBAAmB,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;YAC1D,CAAC;YAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,cAAc,CACtB,mBAAmB,CAAC,QAAQ,CAAC,MAAM,CAAC,EACpC,QAAQ,CAAC,MAAM,CAChB,CAAC;YACJ,CAAC;YAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAgB,CAAC;YAEpD,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;gBAC7B,MAAM,IAAI,cAAc,CACtB,oBAAoB,CAAC,IAAI,CAAC,UAAU,CAAC,EACrC,GAAG,EACH,IAAI,CAAC,UAAU,CAChB,CAAC;YACJ,CAAC;YAED,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,IAAI,cAAc,CAAC,sBAAsB,CAAC,CAAC;IACnD,CAAC;IAED,KAAK,CAAC,YAAY,CAChB,QAAgB,EAChB,QAAgB;QAMhB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,gCAAgC,EAAE;YACvE,QAAQ;YACR,QAAQ;SACT,CAAC,CAAC;QACH,OAAO,GAAG,CAAC,UAIV,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,WAAW,CACf,YAAoB,EACpB,KAAiB,EACjB,WAAmB;QAEnB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,YAAY,EAAE;YACzC,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE;YACxC,IAAI,EAAE,KAA4B;SACnC,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,cAAc,CACtB,wBAAwB,QAAQ,CAAC,MAAM,EAAE,EACzC,QAAQ,CAAC,MAAM,CAChB,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC1C,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,cAAc,CAAC,gDAAgD,CAAC,CAAC;QAC7E,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,cAAc,CAClB,QAAgB,EAChB,KAAgD;QAEhD,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,kCAAkC,EAAE;YAC7D,QAAQ;YACR,KAAK;SACN,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,QAAgB;QAC/B,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAChC,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC;QAC3B,MAAM,UAAU,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;QAE1C,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;QAC3D,MAAM,cAAc,GAA2B;YAC7C,GAAG,EAAE,WAAW;YAChB,IAAI,EAAE,YAAY;YAClB,GAAG,EAAE,YAAY;YACjB,GAAG,EAAE,WAAW;YAChB,GAAG,EAAE,iBAAiB;YACtB,GAAG,EAAE,WAAW;YAChB,GAAG,EAAE,YAAY;SAClB,CAAC;QACF,MAAM,WAAW,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,0BAA0B,CAAC;QAEtE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,MAAM,IAAI,CAAC,YAAY,CACnE,QAAQ,EACR,QAAQ,CACT,CAAC;QAEF,MAAM,KAAK,GAA8C,EAAE,CAAC;QAE5D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7C,MAAM,KAAK,GAAG,CAAC,GAAG,SAAS,CAAC;YAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,SAAS,EAAE,QAAQ,CAAC,CAAC;YAClD,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YAE9C,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,IAAI,UAAU,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,EAAE,WAAW,CAAC,CAAC;YACpI,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACnD,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC;QAClD,MAAM,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAE3C,OAAO,EAAE,QAAQ,EAAE,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,SAAS,CACb,KAAa,EACb,MAA+B;QAE/B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,KAAK,OAAO,EAAE,MAAM,CAAC,CAAC;QACjE,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,UAAU,EAAE,KAAe,EAAE,CAAC;IACpD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,KAAa;QACvC,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,KAAK,SAAS,KAAK,EAAE,CAAC,CAAC;IACxD,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { GaudioClient } from "./api/client.js";
|
|
5
|
+
import { registerListModels } from "./tools/list-models.js";
|
|
6
|
+
import { registerUploadFile } from "./tools/upload-file.js";
|
|
7
|
+
import { registerCreateJob } from "./tools/create-job.js";
|
|
8
|
+
import { registerGetJob } from "./tools/get-job.js";
|
|
9
|
+
import { registerSeparateAudio } from "./tools/separate-audio.js";
|
|
10
|
+
import { registerSyncLyrics } from "./tools/sync-lyrics.js";
|
|
11
|
+
const apiKey = process.env.GAUDIO_API_KEY;
|
|
12
|
+
if (!apiKey) {
|
|
13
|
+
console.error("GAUDIO_API_KEY environment variable is required.");
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
const server = new McpServer({
|
|
17
|
+
name: "com.gaudiolab/mcp-developers",
|
|
18
|
+
version: "1.0.0",
|
|
19
|
+
});
|
|
20
|
+
const client = new GaudioClient(apiKey);
|
|
21
|
+
registerListModels(server);
|
|
22
|
+
registerUploadFile(server, client);
|
|
23
|
+
registerCreateJob(server, client);
|
|
24
|
+
registerGetJob(server, client);
|
|
25
|
+
registerSeparateAudio(server, client);
|
|
26
|
+
registerSyncLyrics(server, client);
|
|
27
|
+
const transport = new StdioServerTransport();
|
|
28
|
+
await server.connect(transport);
|
|
29
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;AAC1C,IAAI,CAAC,MAAM,EAAE,CAAC;IACZ,OAAO,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;IAClE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,8BAA8B;IACpC,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;AAExC,kBAAkB,CAAC,MAAM,CAAC,CAAC;AAC3B,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACnC,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAClC,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAC/B,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACtC,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEnC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface ModelInfo {
|
|
2
|
+
name: string;
|
|
3
|
+
category: "stem" | "dme" | "text_sync";
|
|
4
|
+
description: string;
|
|
5
|
+
typeOptions?: string[];
|
|
6
|
+
typeRequired: boolean;
|
|
7
|
+
maxFileSize: string;
|
|
8
|
+
maxDuration: string;
|
|
9
|
+
outputFormat: string;
|
|
10
|
+
}
|
|
11
|
+
export declare const MODEL_REGISTRY: ModelInfo[];
|
|
12
|
+
export declare function getModel(name: string): ModelInfo | undefined;
|
|
13
|
+
export declare function getModelsByCategory(category?: string): ModelInfo[];
|
|
14
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/models/registry.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,GAAG,KAAK,GAAG,WAAW,CAAC;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,cAAc,EAAE,SAAS,EA0GrC,CAAC;AAEF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAE5D;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE,CAGlE"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
export const MODEL_REGISTRY = [
|
|
2
|
+
// Stem Separation
|
|
3
|
+
{
|
|
4
|
+
name: "gsep_music_hq_v1",
|
|
5
|
+
category: "stem",
|
|
6
|
+
description: "High-quality multi-instrument separation. Separates vocals, drums, bass, electric guitar, and acoustic piano.",
|
|
7
|
+
typeOptions: ["vocal", "drum", "bass", "electric_guitar", "acoustic_piano"],
|
|
8
|
+
typeRequired: true,
|
|
9
|
+
maxFileSize: "1GB",
|
|
10
|
+
maxDuration: "20 minutes",
|
|
11
|
+
outputFormat: "mp3 (48kHz/320kbps) + wav (same as input)",
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
name: "gsep_music_shq_v1",
|
|
15
|
+
category: "stem",
|
|
16
|
+
description: "Super high-quality vocal + accompaniment separation.",
|
|
17
|
+
typeOptions: ["vocal"],
|
|
18
|
+
typeRequired: true,
|
|
19
|
+
maxFileSize: "1GB",
|
|
20
|
+
maxDuration: "20 minutes",
|
|
21
|
+
outputFormat: "mp3 (48kHz/320kbps) + wav (same as input)",
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: "gsep_speech_hq_v1",
|
|
25
|
+
category: "stem",
|
|
26
|
+
description: "Speech separation / noise removal.",
|
|
27
|
+
typeOptions: ["speech"],
|
|
28
|
+
typeRequired: true,
|
|
29
|
+
maxFileSize: "1GB",
|
|
30
|
+
maxDuration: "20 minutes",
|
|
31
|
+
outputFormat: "mp3 (48kHz/320kbps) + wav (same as input)",
|
|
32
|
+
},
|
|
33
|
+
// DME Separation
|
|
34
|
+
{
|
|
35
|
+
name: "gsep_dme_dtrack_v1",
|
|
36
|
+
category: "dme",
|
|
37
|
+
description: "Extract dialogue track from audio/video.",
|
|
38
|
+
typeRequired: false,
|
|
39
|
+
maxFileSize: "10GB",
|
|
40
|
+
maxDuration: "200 minutes",
|
|
41
|
+
outputFormat: "mp3 (48kHz/320kbps) + wav (same as input)",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: "gsep_dme_d2track_v1",
|
|
45
|
+
category: "dme",
|
|
46
|
+
description: "Extract dialogue + vocals track from audio/video.",
|
|
47
|
+
typeRequired: false,
|
|
48
|
+
maxFileSize: "10GB",
|
|
49
|
+
maxDuration: "200 minutes",
|
|
50
|
+
outputFormat: "mp3 (48kHz/320kbps) + wav (same as input)",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: "gsep_dme_metrack_v1",
|
|
54
|
+
category: "dme",
|
|
55
|
+
description: "Extract music + effects track (paired with dtrack).",
|
|
56
|
+
typeRequired: false,
|
|
57
|
+
maxFileSize: "10GB",
|
|
58
|
+
maxDuration: "200 minutes",
|
|
59
|
+
outputFormat: "mp3 (48kHz/320kbps) + wav (same as input)",
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: "gsep_dme_me2track_v1",
|
|
63
|
+
category: "dme",
|
|
64
|
+
description: "Extract music + effects track v1 (paired with d2track).",
|
|
65
|
+
typeRequired: false,
|
|
66
|
+
maxFileSize: "10GB",
|
|
67
|
+
maxDuration: "200 minutes",
|
|
68
|
+
outputFormat: "mp3 (48kHz/320kbps) + wav (same as input)",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: "gsep_dme_me2track_v2",
|
|
72
|
+
category: "dme",
|
|
73
|
+
description: "Extract music + effects track v2 (high quality, paired with d2track).",
|
|
74
|
+
typeRequired: false,
|
|
75
|
+
maxFileSize: "10GB",
|
|
76
|
+
maxDuration: "200 minutes",
|
|
77
|
+
outputFormat: "mp3 (48kHz/320kbps) + wav (same as input)",
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: "gsep_dme_mtrack_v1",
|
|
81
|
+
category: "dme",
|
|
82
|
+
description: "Extract music-only track from audio/video.",
|
|
83
|
+
typeRequired: false,
|
|
84
|
+
maxFileSize: "10GB",
|
|
85
|
+
maxDuration: "200 minutes",
|
|
86
|
+
outputFormat: "mp3 (48kHz/320kbps) + wav (same as input)",
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: "gsep_dme_etrack_v1",
|
|
90
|
+
category: "dme",
|
|
91
|
+
description: "Extract effects-only track from audio/video.",
|
|
92
|
+
typeRequired: false,
|
|
93
|
+
maxFileSize: "10GB",
|
|
94
|
+
maxDuration: "200 minutes",
|
|
95
|
+
outputFormat: "mp3 (48kHz/320kbps) + wav (same as input)",
|
|
96
|
+
},
|
|
97
|
+
// AI Text Sync
|
|
98
|
+
{
|
|
99
|
+
name: "gts_lyrics_line_v1",
|
|
100
|
+
category: "text_sync",
|
|
101
|
+
description: "AI lyrics line sync. Aligns lyrics text to audio timestamps. Outputs CSV (timestamp, lyric_text, confidence_score) + JSON report.",
|
|
102
|
+
typeRequired: false,
|
|
103
|
+
maxFileSize: "1GB",
|
|
104
|
+
maxDuration: "10 minutes",
|
|
105
|
+
outputFormat: "CSV (lyrics) + JSON (report)",
|
|
106
|
+
},
|
|
107
|
+
];
|
|
108
|
+
export function getModel(name) {
|
|
109
|
+
return MODEL_REGISTRY.find((m) => m.name === name);
|
|
110
|
+
}
|
|
111
|
+
export function getModelsByCategory(category) {
|
|
112
|
+
if (!category)
|
|
113
|
+
return MODEL_REGISTRY;
|
|
114
|
+
return MODEL_REGISTRY.filter((m) => m.category === category);
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/models/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-job.d.ts","sourceRoot":"","sources":["../../src/tools/create-job.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGrD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,QAgDxE"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getModel } from "../models/registry.js";
|
|
3
|
+
export function registerCreateJob(server, client) {
|
|
4
|
+
server.tool("gaudio_create_job", "Create a processing job with an uploaded file. For Stem Separation models (gsep_music_hq_v1, gsep_music_shq_v1, gsep_speech_hq_v1), the 'type' parameter is required (e.g. 'vocal', 'vocal,drum'). For DME models, no type is needed. For Text Sync (gts_lyrics_line_v1), use gaudio_sync_lyrics instead.", {
|
|
5
|
+
uploadId: z.string().describe("Upload ID from gaudio_upload_file (used as audioUploadId)"),
|
|
6
|
+
model: z.string().describe("Model name (e.g. gsep_music_hq_v1, gsep_dme_dtrack_v1)"),
|
|
7
|
+
type: z
|
|
8
|
+
.string()
|
|
9
|
+
.optional()
|
|
10
|
+
.describe("Stem type(s), comma-separated. Required for Stem Separation models. e.g. 'vocal', 'vocal,drum,bass'"),
|
|
11
|
+
}, async ({ uploadId, model, type }) => {
|
|
12
|
+
const modelInfo = getModel(model);
|
|
13
|
+
if (!modelInfo) {
|
|
14
|
+
return {
|
|
15
|
+
content: [{ type: "text", text: `Unknown model: ${model}. Use gaudio_list_models to see available models.` }],
|
|
16
|
+
isError: true,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
if (modelInfo.typeRequired && !type) {
|
|
20
|
+
return {
|
|
21
|
+
content: [
|
|
22
|
+
{
|
|
23
|
+
type: "text",
|
|
24
|
+
text: `Model ${model} requires a 'type' parameter. Options: ${modelInfo.typeOptions?.join(", ")}`,
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
isError: true,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const params = { audioUploadId: uploadId };
|
|
31
|
+
if (type)
|
|
32
|
+
params.type = type;
|
|
33
|
+
const { jobId } = await client.createJob(model, params);
|
|
34
|
+
return {
|
|
35
|
+
content: [
|
|
36
|
+
{
|
|
37
|
+
type: "text",
|
|
38
|
+
text: JSON.stringify({ jobId, model, status: "created" }, null, 2),
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=create-job.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-job.js","sourceRoot":"","sources":["../../src/tools/create-job.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,MAAM,UAAU,iBAAiB,CAAC,MAAiB,EAAE,MAAoB;IACvE,MAAM,CAAC,IAAI,CACT,mBAAmB,EACnB,2SAA2S,EAC3S;QACE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2DAA2D,CAAC;QAC1F,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wDAAwD,CAAC;QACpF,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,qGAAqG,CAAC;KACnH,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE;QAClC,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,kBAAkB,KAAK,mDAAmD,EAAE,CAAC;gBACtH,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,IAAI,SAAS,CAAC,YAAY,IAAI,CAAC,IAAI,EAAE,CAAC;YACpC,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,SAAS,KAAK,0CAA0C,SAAS,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE;qBAClG;iBACF;gBACD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAA4B,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC;QACpE,IAAI,IAAI;YAAE,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC;QAE7B,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAExD,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;iBACnE;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-job.d.ts","sourceRoot":"","sources":["../../src/tools/get-job.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGrD,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,QA2CrE"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getModel } from "../models/registry.js";
|
|
3
|
+
export function registerGetJob(server, client) {
|
|
4
|
+
server.tool("gaudio_get_job", "Check job status and get results. Status: 'waiting' (queued), 'running' (processing), 'success' (done, downloadUrl included), 'failed' (error). Download URLs expire after 48 hours.", {
|
|
5
|
+
jobId: z.string().describe("Job ID from gaudio_create_job or gaudio_separate_audio"),
|
|
6
|
+
model: z.string().describe("Model name used to create the job"),
|
|
7
|
+
}, async ({ jobId, model }) => {
|
|
8
|
+
const modelInfo = getModel(model);
|
|
9
|
+
if (!modelInfo) {
|
|
10
|
+
return {
|
|
11
|
+
content: [{ type: "text", text: `Unknown model: ${model}` }],
|
|
12
|
+
isError: true,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
const res = await client.getJob(model, jobId);
|
|
16
|
+
const data = res.resultData ?? {};
|
|
17
|
+
const result = {
|
|
18
|
+
jobId,
|
|
19
|
+
model,
|
|
20
|
+
status: data.status,
|
|
21
|
+
};
|
|
22
|
+
if (data.status === "success") {
|
|
23
|
+
result.downloadUrl = data.downloadUrl;
|
|
24
|
+
result.expireAt = data.expireAt;
|
|
25
|
+
}
|
|
26
|
+
else if (data.status === "failed") {
|
|
27
|
+
result.errorMessage = data.errorMessage;
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
content: [
|
|
31
|
+
{
|
|
32
|
+
type: "text",
|
|
33
|
+
text: JSON.stringify(result, null, 2),
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=get-job.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-job.js","sourceRoot":"","sources":["../../src/tools/get-job.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,MAAM,UAAU,cAAc,CAAC,MAAiB,EAAE,MAAoB;IACpE,MAAM,CAAC,IAAI,CACT,gBAAgB,EAChB,sLAAsL,EACtL;QACE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wDAAwD,CAAC;QACpF,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;KAChE,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;QACzB,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,kBAAkB,KAAK,EAAE,EAAE,CAAC;gBACrE,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC9C,MAAM,IAAI,GAAG,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC;QAElC,MAAM,MAAM,GAA4B;YACtC,KAAK;YACL,KAAK;YACL,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC;QAEF,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC9B,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;YACtC,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAClC,CAAC;aAAM,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACpC,MAAM,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;QAC1C,CAAC;QAED,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;iBACtC;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-models.d.ts","sourceRoot":"","sources":["../../src/tools/list-models.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGzE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,QAiCnD"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getModelsByCategory } from "../models/registry.js";
|
|
3
|
+
export function registerListModels(server) {
|
|
4
|
+
server.tool("gaudio_list_models", "List available Gaudio AI models. Filter by category: 'stem' (instrument separation), 'dme' (dialogue/music/effects separation), 'text_sync' (lyrics sync).", {
|
|
5
|
+
category: z
|
|
6
|
+
.enum(["all", "stem", "dme", "text_sync"])
|
|
7
|
+
.default("all")
|
|
8
|
+
.describe("Filter by category: all (default), stem, dme, or text_sync"),
|
|
9
|
+
}, async ({ category }) => {
|
|
10
|
+
const models = getModelsByCategory(category === "all" ? undefined : category);
|
|
11
|
+
const formatted = models.map((m) => ({
|
|
12
|
+
name: m.name,
|
|
13
|
+
category: m.category,
|
|
14
|
+
description: m.description,
|
|
15
|
+
typeOptions: m.typeOptions ?? null,
|
|
16
|
+
typeRequired: m.typeRequired,
|
|
17
|
+
maxFileSize: m.maxFileSize,
|
|
18
|
+
maxDuration: m.maxDuration,
|
|
19
|
+
outputFormat: m.outputFormat,
|
|
20
|
+
}));
|
|
21
|
+
return {
|
|
22
|
+
content: [
|
|
23
|
+
{
|
|
24
|
+
type: "text",
|
|
25
|
+
text: JSON.stringify(formatted, null, 2),
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=list-models.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-models.js","sourceRoot":"","sources":["../../src/tools/list-models.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,UAAU,kBAAkB,CAAC,MAAiB;IAClD,MAAM,CAAC,IAAI,CACT,oBAAoB,EACpB,4JAA4J,EAC5J;QACE,QAAQ,EAAE,CAAC;aACR,IAAI,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC;aACzC,OAAO,CAAC,KAAK,CAAC;aACd,QAAQ,CAAC,4DAA4D,CAAC;KAC1E,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACrB,MAAM,MAAM,GAAG,mBAAmB,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QAC9E,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACnC,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,IAAI;YAClC,YAAY,EAAE,CAAC,CAAC,YAAY;YAC5B,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,YAAY,EAAE,CAAC,CAAC,YAAY;SAC7B,CAAC,CAAC,CAAC;QAEJ,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;iBACzC;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"separate-audio.d.ts","sourceRoot":"","sources":["../../src/tools/separate-audio.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAIrD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,QA6G5E"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getModel } from "../models/registry.js";
|
|
3
|
+
import { pollJob } from "../utils/polling.js";
|
|
4
|
+
export function registerSeparateAudio(server, client) {
|
|
5
|
+
server.tool("gaudio_separate_audio", "All-in-one audio separation: upload file (or reuse uploadId) → create job → poll until done → return download URLs. For Stem Separation, provide 'type' (e.g. 'vocal', 'vocal,drum'). For DME Separation, no type needed. Supports WAV, FLAC, MP3, M4A, MOV, MP4.", {
|
|
6
|
+
filePath: z
|
|
7
|
+
.string()
|
|
8
|
+
.optional()
|
|
9
|
+
.describe("Path to local audio/video file. Either filePath or uploadId is required."),
|
|
10
|
+
uploadId: z
|
|
11
|
+
.string()
|
|
12
|
+
.optional()
|
|
13
|
+
.describe("Existing uploadId to reuse (skips upload). Valid for 72 hours."),
|
|
14
|
+
model: z.string().describe("Model name (e.g. gsep_music_hq_v1, gsep_dme_dtrack_v1)"),
|
|
15
|
+
type: z
|
|
16
|
+
.string()
|
|
17
|
+
.optional()
|
|
18
|
+
.describe("Stem type(s) for Stem Separation models. e.g. 'vocal', 'vocal,drum'"),
|
|
19
|
+
pollInterval: z
|
|
20
|
+
.number()
|
|
21
|
+
.optional()
|
|
22
|
+
.default(10)
|
|
23
|
+
.describe("Polling interval in seconds (default: 10)"),
|
|
24
|
+
}, async ({ filePath, uploadId, model, type, pollInterval }) => {
|
|
25
|
+
const modelInfo = getModel(model);
|
|
26
|
+
if (!modelInfo) {
|
|
27
|
+
return {
|
|
28
|
+
content: [{ type: "text", text: `Unknown model: ${model}. Use gaudio_list_models to see available models.` }],
|
|
29
|
+
isError: true,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if (!filePath && !uploadId) {
|
|
33
|
+
return {
|
|
34
|
+
content: [{ type: "text", text: "Either filePath or uploadId is required." }],
|
|
35
|
+
isError: true,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
if (modelInfo.typeRequired && !type) {
|
|
39
|
+
return {
|
|
40
|
+
content: [
|
|
41
|
+
{
|
|
42
|
+
type: "text",
|
|
43
|
+
text: `Model ${model} requires 'type'. Options: ${modelInfo.typeOptions?.join(", ")}`,
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
isError: true,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
if (modelInfo.category === "text_sync") {
|
|
50
|
+
return {
|
|
51
|
+
content: [{ type: "text", text: "For Text Sync, use gaudio_sync_lyrics instead." }],
|
|
52
|
+
isError: true,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const messages = [];
|
|
56
|
+
const log = (msg) => messages.push(msg);
|
|
57
|
+
// Step 1: Upload if needed
|
|
58
|
+
let resolvedUploadId = uploadId;
|
|
59
|
+
if (!resolvedUploadId) {
|
|
60
|
+
log("업로드 중...");
|
|
61
|
+
const result = await client.uploadFile(filePath);
|
|
62
|
+
resolvedUploadId = result.uploadId;
|
|
63
|
+
log(`업로드 완료. uploadId: ${resolvedUploadId}`);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
log(`기존 uploadId 재사용: ${resolvedUploadId}`);
|
|
67
|
+
}
|
|
68
|
+
// Step 2: Create job
|
|
69
|
+
const params = {
|
|
70
|
+
audioUploadId: resolvedUploadId,
|
|
71
|
+
};
|
|
72
|
+
if (type)
|
|
73
|
+
params.type = type;
|
|
74
|
+
const { jobId } = await client.createJob(model, params);
|
|
75
|
+
log(`Job 생성 완료. jobId: ${jobId}`);
|
|
76
|
+
// Step 3: Poll
|
|
77
|
+
const intervalMs = (pollInterval ?? 10) * 1000;
|
|
78
|
+
const result = await pollJob(client, model, jobId, intervalMs, 30, log);
|
|
79
|
+
const output = {
|
|
80
|
+
jobId: result.jobId,
|
|
81
|
+
status: result.status,
|
|
82
|
+
uploadId: resolvedUploadId,
|
|
83
|
+
model,
|
|
84
|
+
};
|
|
85
|
+
if (result.downloadUrl)
|
|
86
|
+
output.downloadUrl = result.downloadUrl;
|
|
87
|
+
if (result.expireAt)
|
|
88
|
+
output.expireAt = result.expireAt;
|
|
89
|
+
if (result.errorMessage)
|
|
90
|
+
output.errorMessage = result.errorMessage;
|
|
91
|
+
messages.push(JSON.stringify(output, null, 2));
|
|
92
|
+
return {
|
|
93
|
+
content: [
|
|
94
|
+
{
|
|
95
|
+
type: "text",
|
|
96
|
+
text: messages.join("\n"),
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
};
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=separate-audio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"separate-audio.js","sourceRoot":"","sources":["../../src/tools/separate-audio.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-lyrics.d.ts","sourceRoot":"","sources":["../../src/tools/sync-lyrics.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGrD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,QA8GzE"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { pollJob } from "../utils/polling.js";
|
|
3
|
+
export function registerSyncLyrics(server, client) {
|
|
4
|
+
server.tool("gaudio_sync_lyrics", "All-in-one lyrics sync: upload audio + text files → create gts_lyrics_line_v1 job → poll → return CSV (timestamp, lyric_text, confidence_score) + JSON report URLs. Text file requirements: .txt format, UTF-8, minimum 2 lines, max 60 characters per line. Audio limit: 1GB / 10 minutes.", {
|
|
5
|
+
audioFilePath: z
|
|
6
|
+
.string()
|
|
7
|
+
.optional()
|
|
8
|
+
.describe("Path to local audio file. Either audioFilePath or audioUploadId required."),
|
|
9
|
+
audioUploadId: z
|
|
10
|
+
.string()
|
|
11
|
+
.optional()
|
|
12
|
+
.describe("Existing audio uploadId to reuse."),
|
|
13
|
+
textFilePath: z
|
|
14
|
+
.string()
|
|
15
|
+
.optional()
|
|
16
|
+
.describe("Path to local .txt lyrics file. Either textFilePath or textUploadId required."),
|
|
17
|
+
textUploadId: z
|
|
18
|
+
.string()
|
|
19
|
+
.optional()
|
|
20
|
+
.describe("Existing text uploadId to reuse."),
|
|
21
|
+
language: z
|
|
22
|
+
.enum(["en", "ko", "ja", "zh-cn"])
|
|
23
|
+
.describe("Language of the lyrics: en (English), ko (Korean), ja (Japanese), zh-cn (Chinese Simplified)"),
|
|
24
|
+
pollInterval: z
|
|
25
|
+
.number()
|
|
26
|
+
.optional()
|
|
27
|
+
.default(10)
|
|
28
|
+
.describe("Polling interval in seconds (default: 10)"),
|
|
29
|
+
}, async ({ audioFilePath, audioUploadId, textFilePath, textUploadId, language, pollInterval, }) => {
|
|
30
|
+
if (!audioFilePath && !audioUploadId) {
|
|
31
|
+
return {
|
|
32
|
+
content: [{ type: "text", text: "Either audioFilePath or audioUploadId is required." }],
|
|
33
|
+
isError: true,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
if (!textFilePath && !textUploadId) {
|
|
37
|
+
return {
|
|
38
|
+
content: [{ type: "text", text: "Either textFilePath or textUploadId is required." }],
|
|
39
|
+
isError: true,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const messages = [];
|
|
43
|
+
const log = (msg) => messages.push(msg);
|
|
44
|
+
// Step 1: Upload audio if needed
|
|
45
|
+
let resolvedAudioId = audioUploadId;
|
|
46
|
+
if (!resolvedAudioId) {
|
|
47
|
+
log("오디오 파일 업로드 중...");
|
|
48
|
+
const res = await client.uploadFile(audioFilePath);
|
|
49
|
+
resolvedAudioId = res.uploadId;
|
|
50
|
+
log(`오디오 업로드 완료. uploadId: ${resolvedAudioId}`);
|
|
51
|
+
}
|
|
52
|
+
// Step 2: Upload text if needed
|
|
53
|
+
let resolvedTextId = textUploadId;
|
|
54
|
+
if (!resolvedTextId) {
|
|
55
|
+
log("텍스트 파일 업로드 중...");
|
|
56
|
+
const res = await client.uploadFile(textFilePath);
|
|
57
|
+
resolvedTextId = res.uploadId;
|
|
58
|
+
log(`텍스트 업로드 완료. uploadId: ${resolvedTextId}`);
|
|
59
|
+
}
|
|
60
|
+
// Step 3: Create job
|
|
61
|
+
const model = "gts_lyrics_line_v1";
|
|
62
|
+
const { jobId } = await client.createJob(model, {
|
|
63
|
+
audioUploadId: resolvedAudioId,
|
|
64
|
+
textUploadId: resolvedTextId,
|
|
65
|
+
language,
|
|
66
|
+
});
|
|
67
|
+
log(`Job 생성 완료. jobId: ${jobId}`);
|
|
68
|
+
// Step 4: Poll
|
|
69
|
+
const intervalMs = (pollInterval ?? 10) * 1000;
|
|
70
|
+
const result = await pollJob(client, model, jobId, intervalMs, 30, log);
|
|
71
|
+
const output = {
|
|
72
|
+
jobId: result.jobId,
|
|
73
|
+
status: result.status,
|
|
74
|
+
model,
|
|
75
|
+
audioUploadId: resolvedAudioId,
|
|
76
|
+
textUploadId: resolvedTextId,
|
|
77
|
+
language,
|
|
78
|
+
};
|
|
79
|
+
if (result.downloadUrl)
|
|
80
|
+
output.downloadUrl = result.downloadUrl;
|
|
81
|
+
if (result.expireAt)
|
|
82
|
+
output.expireAt = result.expireAt;
|
|
83
|
+
if (result.errorMessage)
|
|
84
|
+
output.errorMessage = result.errorMessage;
|
|
85
|
+
messages.push(JSON.stringify(output, null, 2));
|
|
86
|
+
return {
|
|
87
|
+
content: [
|
|
88
|
+
{
|
|
89
|
+
type: "text",
|
|
90
|
+
text: messages.join("\n"),
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=sync-lyrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-lyrics.js","sourceRoot":"","sources":["../../src/tools/sync-lyrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAE9C,MAAM,UAAU,kBAAkB,CAAC,MAAiB,EAAE,MAAoB;IACxE,MAAM,CAAC,IAAI,CACT,oBAAoB,EACpB,6RAA6R,EAC7R;QACE,aAAa,EAAE,CAAC;aACb,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,2EAA2E,CAAC;QACxF,aAAa,EAAE,CAAC;aACb,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,mCAAmC,CAAC;QAChD,YAAY,EAAE,CAAC;aACZ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,+EAA+E,CAAC;QAC5F,YAAY,EAAE,CAAC;aACZ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,kCAAkC,CAAC;QAC/C,QAAQ,EAAE,CAAC;aACR,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;aACjC,QAAQ,CAAC,8FAA8F,CAAC;QAC3G,YAAY,EAAE,CAAC;aACZ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,OAAO,CAAC,EAAE,CAAC;aACX,QAAQ,CAAC,2CAA2C,CAAC;KACzD,EACD,KAAK,EAAE,EACL,aAAa,EACb,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,QAAQ,EACR,YAAY,GACb,EAAE,EAAE;QACH,IAAI,CAAC,aAAa,IAAI,CAAC,aAAa,EAAE,CAAC;YACrC,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,oDAAoD,EAAE,CAAC;gBAChG,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,YAAY,IAAI,CAAC,YAAY,EAAE,CAAC;YACnC,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,kDAAkD,EAAE,CAAC;gBAC9F,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAEhD,iCAAiC;QACjC,IAAI,eAAe,GAAG,aAAa,CAAC;QACpC,IAAI,CAAC,eAAe,EAAE,CAAC;YACrB,GAAG,CAAC,iBAAiB,CAAC,CAAC;YACvB,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,aAAc,CAAC,CAAC;YACpD,eAAe,GAAG,GAAG,CAAC,QAAQ,CAAC;YAC/B,GAAG,CAAC,yBAAyB,eAAe,EAAE,CAAC,CAAC;QAClD,CAAC;QAED,gCAAgC;QAChC,IAAI,cAAc,GAAG,YAAY,CAAC;QAClC,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,GAAG,CAAC,iBAAiB,CAAC,CAAC;YACvB,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,YAAa,CAAC,CAAC;YACnD,cAAc,GAAG,GAAG,CAAC,QAAQ,CAAC;YAC9B,GAAG,CAAC,yBAAyB,cAAc,EAAE,CAAC,CAAC;QACjD,CAAC;QAED,qBAAqB;QACrB,MAAM,KAAK,GAAG,oBAAoB,CAAC;QACnC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE;YAC9C,aAAa,EAAE,eAAe;YAC9B,YAAY,EAAE,cAAc;YAC5B,QAAQ;SACT,CAAC,CAAC;QACH,GAAG,CAAC,qBAAqB,KAAK,EAAE,CAAC,CAAC;QAElC,eAAe;QACf,MAAM,UAAU,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;QAC/C,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;QAExE,MAAM,MAAM,GAA4B;YACtC,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,KAAK;YACL,aAAa,EAAE,eAAe;YAC9B,YAAY,EAAE,cAAc;YAC5B,QAAQ;SACT,CAAC;QAEF,IAAI,MAAM,CAAC,WAAW;YAAE,MAAM,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;QAChE,IAAI,MAAM,CAAC,QAAQ;YAAE,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QACvD,IAAI,MAAM,CAAC,YAAY;YAAE,MAAM,CAAC,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC;QAEnE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAE/C,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;iBAC1B;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload-file.d.ts","sourceRoot":"","sources":["../../src/tools/upload-file.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,QA0BzE"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerUploadFile(server, client) {
|
|
3
|
+
server.tool("gaudio_upload_file", "Upload a local audio/video/text file to Gaudio servers. Handles multipart upload automatically (create → chunk upload → complete). The returned uploadId is valid for 72 hours and can be reused across multiple jobs. Supported formats: WAV, FLAC, MP3, M4A, MOV, MP4, TXT.", {
|
|
4
|
+
filePath: z
|
|
5
|
+
.string()
|
|
6
|
+
.describe("Absolute path to the local file to upload"),
|
|
7
|
+
}, async ({ filePath }) => {
|
|
8
|
+
const { uploadId } = await client.uploadFile(filePath);
|
|
9
|
+
const expiresAt = new Date(Date.now() + 72 * 60 * 60 * 1000).toISOString();
|
|
10
|
+
return {
|
|
11
|
+
content: [
|
|
12
|
+
{
|
|
13
|
+
type: "text",
|
|
14
|
+
text: JSON.stringify({ uploadId, expiresAt }, null, 2),
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=upload-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload-file.js","sourceRoot":"","sources":["../../src/tools/upload-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,MAAM,UAAU,kBAAkB,CAAC,MAAiB,EAAE,MAAoB;IACxE,MAAM,CAAC,IAAI,CACT,oBAAoB,EACpB,+QAA+Q,EAC/Q;QACE,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,QAAQ,CAAC,2CAA2C,CAAC;KACzD,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACrB,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAEvD,MAAM,SAAS,GAAG,IAAI,IAAI,CACxB,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CACjC,CAAC,WAAW,EAAE,CAAC;QAEhB,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;iBACvD;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare class GaudioApiError extends Error {
|
|
2
|
+
readonly statusCode?: number | undefined;
|
|
3
|
+
readonly resultCode?: number | undefined;
|
|
4
|
+
constructor(message: string, statusCode?: number | undefined, resultCode?: number | undefined);
|
|
5
|
+
}
|
|
6
|
+
export declare function getResultCodeMessage(code: number): string;
|
|
7
|
+
export declare function getHttpErrorMessage(status: number): string;
|
|
8
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AA8BA,qBAAa,cAAe,SAAQ,KAAK;aAGrB,UAAU,CAAC,EAAE,MAAM;aACnB,UAAU,CAAC,EAAE,MAAM;gBAFnC,OAAO,EAAE,MAAM,EACC,UAAU,CAAC,EAAE,MAAM,YAAA,EACnB,UAAU,CAAC,EAAE,MAAM,YAAA;CAKtC;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAK1D"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const RESULT_CODE_MESSAGES = {
|
|
2
|
+
1007: "지정한 언어가 텍스트 내용과 일치하지 않습니다.",
|
|
3
|
+
1008: "텍스트는 최소 2줄 이상 포함해야 합니다.",
|
|
4
|
+
1014: "지원하지 않는 샘플레이트입니다. 16kHz ~ 192kHz를 사용하세요.",
|
|
5
|
+
1015: "지원하지 않는 채널입니다. 모노(1ch) 또는 스테레오(2ch)를 사용하세요.",
|
|
6
|
+
1100: "알 수 없는 오류가 발생했습니다. 지속되면 Gaudio 고객지원에 문의하세요.",
|
|
7
|
+
1102: "크레딧이 부족합니다. Gaudio 대시보드에서 충전하세요.",
|
|
8
|
+
1103: "계약이 유효하지 않거나 만료되었습니다.",
|
|
9
|
+
1104: "요청한 Job을 찾을 수 없습니다.",
|
|
10
|
+
1105: "업로드 ID를 찾을 수 없습니다. 파일을 다시 업로드해주세요.",
|
|
11
|
+
1106: "업로드 ID가 만료되었습니다 (72시간). 파일을 다시 업로드해주세요.",
|
|
12
|
+
1107: "지원하지 않는 파일 형식입니다. WAV, FLAC, MP3, M4A, MOV, MP4를 사용하세요.",
|
|
13
|
+
1108: "오디오 길이가 0초입니다. 파일을 확인하세요.",
|
|
14
|
+
1109: "오디오 길이가 허용 한도를 초과했습니다.",
|
|
15
|
+
1110: "파일 크기가 허용 한도를 초과했습니다.",
|
|
16
|
+
1111: "지원하지 않는 언어입니다. en, ko, ja, zh-cn 중 선택하세요.",
|
|
17
|
+
1112: "지원하지 않는 텍스트 형식입니다. .txt 파일을 사용하세요.",
|
|
18
|
+
1113: "지원하지 않는 파일명 형식입니다.",
|
|
19
|
+
1114: "프로젝트가 삭제되었습니다.",
|
|
20
|
+
1122: "필수 파라미터 'type'이 누락되었습니다.",
|
|
21
|
+
};
|
|
22
|
+
const HTTP_ERROR_MESSAGES = {
|
|
23
|
+
400: "API 키가 요청 헤더에 없습니다. GAUDIO_API_KEY 환경변수를 확인하세요.",
|
|
24
|
+
401: "API 키가 유효하지 않습니다. 대시보드에서 키를 확인하세요.",
|
|
25
|
+
403: "이 API 키로 해당 모델에 접근할 수 없습니다. 프로젝트 설정을 확인하세요.",
|
|
26
|
+
405: "해당 모델은 현재 사용할 수 없습니다. 다른 모델을 사용하세요.",
|
|
27
|
+
429: "요청이 너무 많습니다. 60초 후 자동 재시도합니다.",
|
|
28
|
+
};
|
|
29
|
+
export class GaudioApiError extends Error {
|
|
30
|
+
statusCode;
|
|
31
|
+
resultCode;
|
|
32
|
+
constructor(message, statusCode, resultCode) {
|
|
33
|
+
super(message);
|
|
34
|
+
this.statusCode = statusCode;
|
|
35
|
+
this.resultCode = resultCode;
|
|
36
|
+
this.name = "GaudioApiError";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export function getResultCodeMessage(code) {
|
|
40
|
+
return RESULT_CODE_MESSAGES[code] ?? `알 수 없는 오류 (resultCode: ${code})`;
|
|
41
|
+
}
|
|
42
|
+
export function getHttpErrorMessage(status) {
|
|
43
|
+
if (status >= 500) {
|
|
44
|
+
return "Gaudio 서버에 일시적 오류가 발생했습니다. 잠시 후 다시 시도해주세요.";
|
|
45
|
+
}
|
|
46
|
+
return HTTP_ERROR_MESSAGES[status] ?? `HTTP 오류 (${status})`;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA,MAAM,oBAAoB,GAA2B;IACnD,IAAI,EAAE,4BAA4B;IAClC,IAAI,EAAE,yBAAyB;IAC/B,IAAI,EAAE,0CAA0C;IAChD,IAAI,EAAE,6CAA6C;IACnD,IAAI,EAAE,6CAA6C;IACnD,IAAI,EAAE,kCAAkC;IACxC,IAAI,EAAE,uBAAuB;IAC7B,IAAI,EAAE,qBAAqB;IAC3B,IAAI,EAAE,oCAAoC;IAC1C,IAAI,EAAE,yCAAyC;IAC/C,IAAI,EAAE,yDAAyD;IAC/D,IAAI,EAAE,2BAA2B;IACjC,IAAI,EAAE,wBAAwB;IAC9B,IAAI,EAAE,uBAAuB;IAC7B,IAAI,EAAE,2CAA2C;IACjD,IAAI,EAAE,oCAAoC;IAC1C,IAAI,EAAE,oBAAoB;IAC1B,IAAI,EAAE,gBAAgB;IACtB,IAAI,EAAE,0BAA0B;CACjC,CAAC;AAEF,MAAM,mBAAmB,GAA2B;IAClD,GAAG,EAAE,iDAAiD;IACtD,GAAG,EAAE,oCAAoC;IACzC,GAAG,EAAE,6CAA6C;IAClD,GAAG,EAAE,qCAAqC;IAC1C,GAAG,EAAE,+BAA+B;CACrC,CAAC;AAEF,MAAM,OAAO,cAAe,SAAQ,KAAK;IAGrB;IACA;IAHlB,YACE,OAAe,EACC,UAAmB,EACnB,UAAmB;QAEnC,KAAK,CAAC,OAAO,CAAC,CAAC;QAHC,eAAU,GAAV,UAAU,CAAS;QACnB,eAAU,GAAV,UAAU,CAAS;QAGnC,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,OAAO,oBAAoB,CAAC,IAAI,CAAC,IAAI,0BAA0B,IAAI,GAAG,CAAC;AACzE,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAc;IAChD,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;QAClB,OAAO,4CAA4C,CAAC;IACtD,CAAC;IACD,OAAO,mBAAmB,CAAC,MAAM,CAAC,IAAI,YAAY,MAAM,GAAG,CAAC;AAC9D,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { GaudioClient } from "../api/client.js";
|
|
2
|
+
export interface PollResult {
|
|
3
|
+
jobId: string;
|
|
4
|
+
status: string;
|
|
5
|
+
downloadUrl?: Record<string, unknown>;
|
|
6
|
+
errorMessage?: string;
|
|
7
|
+
expireAt?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function pollJob(client: GaudioClient, model: string, jobId: string, intervalMs?: number, maxAttempts?: number, onProgress?: (message: string) => void): Promise<PollResult>;
|
|
10
|
+
//# sourceMappingURL=polling.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polling.d.ts","sourceRoot":"","sources":["../../src/utils/polling.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGrD,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,OAAO,CAC3B,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,UAAU,GAAE,MAAe,EAC3B,WAAW,GAAE,MAAW,EACxB,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GACrC,OAAO,CAAC,UAAU,CAAC,CAkDrB"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { GaudioApiError } from "./errors.js";
|
|
2
|
+
export async function pollJob(client, model, jobId, intervalMs = 10_000, maxAttempts = 30, onProgress) {
|
|
3
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
4
|
+
let result;
|
|
5
|
+
try {
|
|
6
|
+
result = await client.getJob(model, jobId);
|
|
7
|
+
}
|
|
8
|
+
catch (err) {
|
|
9
|
+
if (err instanceof GaudioApiError) {
|
|
10
|
+
return {
|
|
11
|
+
jobId,
|
|
12
|
+
status: "failed",
|
|
13
|
+
errorMessage: err.message,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
throw err;
|
|
17
|
+
}
|
|
18
|
+
const status = result.resultData?.status;
|
|
19
|
+
if (status === "success") {
|
|
20
|
+
onProgress?.("처리 완료!");
|
|
21
|
+
return {
|
|
22
|
+
jobId,
|
|
23
|
+
status: "success",
|
|
24
|
+
downloadUrl: result.resultData?.downloadUrl,
|
|
25
|
+
expireAt: result.resultData?.expireAt,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
if (status === "failed") {
|
|
29
|
+
return {
|
|
30
|
+
jobId,
|
|
31
|
+
status: "failed",
|
|
32
|
+
errorMessage: result.resultData?.errorMessage ?? "Job failed",
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
if (attempt === 0) {
|
|
36
|
+
onProgress?.("처리 대기 중...");
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
onProgress?.(`처리 중... (${attempt + 1}/${maxAttempts})`);
|
|
40
|
+
}
|
|
41
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
jobId,
|
|
45
|
+
status: "polling_timeout",
|
|
46
|
+
errorMessage: `${maxAttempts}회 폴링 후에도 미완료. gaudio_get_job으로 나중에 확인하세요. jobId: ${jobId}`,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=polling.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polling.js","sourceRoot":"","sources":["../../src/utils/polling.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAU7C,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,MAAoB,EACpB,KAAa,EACb,KAAa,EACb,aAAqB,MAAM,EAC3B,cAAsB,EAAE,EACxB,UAAsC;IAEtC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;QACvD,IAAI,MAAM,CAAC;QACX,IAAI,CAAC;YACH,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC7C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,cAAc,EAAE,CAAC;gBAClC,OAAO;oBACL,KAAK;oBACL,MAAM,EAAE,QAAQ;oBAChB,YAAY,EAAE,GAAG,CAAC,OAAO;iBAC1B,CAAC;YACJ,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,EAAE,MAAgB,CAAC;QAEnD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,UAAU,EAAE,CAAC,QAAQ,CAAC,CAAC;YACvB,OAAO;gBACL,KAAK;gBACL,MAAM,EAAE,SAAS;gBACjB,WAAW,EAAE,MAAM,CAAC,UAAU,EAAE,WAAsC;gBACtE,QAAQ,EAAE,MAAM,CAAC,UAAU,EAAE,QAAkB;aAChD,CAAC;QACJ,CAAC;QAED,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;YACxB,OAAO;gBACL,KAAK;gBACL,MAAM,EAAE,QAAQ;gBAChB,YAAY,EAAG,MAAM,CAAC,UAAU,EAAE,YAAuB,IAAI,YAAY;aAC1E,CAAC;QACJ,CAAC;QAED,IAAI,OAAO,KAAK,CAAC,EAAE,CAAC;YAClB,UAAU,EAAE,CAAC,YAAY,CAAC,CAAC;QAC7B,CAAC;aAAM,CAAC;YACN,UAAU,EAAE,CAAC,YAAY,OAAO,GAAG,CAAC,IAAI,WAAW,GAAG,CAAC,CAAC;QAC1D,CAAC;QAED,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,OAAO;QACL,KAAK;QACL,MAAM,EAAE,iBAAiB;QACzB,YAAY,EAAE,GAAG,WAAW,oDAAoD,KAAK,EAAE;KACxF,CAAC;AACJ,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gaudiolab/mcp-developers",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Gaudio Lab Audio AI API — MCP Server for Stem Separation, DME Separation, AI Text Sync",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"gaudio-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"start": "node dist/index.js",
|
|
13
|
+
"dev": "tsc --watch"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"mcp",
|
|
17
|
+
"gaudio",
|
|
18
|
+
"audio",
|
|
19
|
+
"ai",
|
|
20
|
+
"stem-separation",
|
|
21
|
+
"dme",
|
|
22
|
+
"text-sync"
|
|
23
|
+
],
|
|
24
|
+
"author": "Gaudio Lab",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@modelcontextprotocol/sdk": "^1.12.1"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/node": "^22.0.0",
|
|
31
|
+
"typescript": "^5.7.0"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=18.0.0"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist",
|
|
38
|
+
"server.json",
|
|
39
|
+
"README.md",
|
|
40
|
+
"LICENSE"
|
|
41
|
+
]
|
|
42
|
+
}
|
package/server.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
|
+
"name": "com.gaudiolab/mcp-developers",
|
|
4
|
+
"description": "Gaudio Lab Audio AI API — Stem Separation, DME Separation, AI Text Sync for music, film, and media production.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"url": "https://bitbucket.org/gaudiolab/mcp-developers",
|
|
7
|
+
"source": "bitbucket"
|
|
8
|
+
},
|
|
9
|
+
"version": "1.0.0",
|
|
10
|
+
"packages": [
|
|
11
|
+
{
|
|
12
|
+
"registryType": "npm",
|
|
13
|
+
"identifier": "@gaudiolab/mcp-developers",
|
|
14
|
+
"version": "1.0.0",
|
|
15
|
+
"transport": {
|
|
16
|
+
"type": "stdio"
|
|
17
|
+
},
|
|
18
|
+
"environmentVariables": [
|
|
19
|
+
{
|
|
20
|
+
"name": "GAUDIO_API_KEY",
|
|
21
|
+
"description": "Gaudio Lab API key from https://www.gaudiolab.com/developers",
|
|
22
|
+
"isRequired": true,
|
|
23
|
+
"isSecret": true
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|