sapiens-mcp 1.31.0 → 1.32.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/dist/index.js +7 -3
- package/dist/tools/aula.js +13 -1
- package/dist/tools/helen.js +5 -3
- package/dist/tools/meta.js +1 -9
- package/dist/tools/pipeline.js +19 -5
- package/dist/tools/stockAudio.js +60 -8
- package/dist/tools/studios.js +1 -10
- package/dist/tools/video.js +20 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -86,7 +86,7 @@ const TOOLS = {
|
|
|
86
86
|
handler: search,
|
|
87
87
|
},
|
|
88
88
|
sapiens_studios: {
|
|
89
|
-
description: "Catálogo dos estúdios/experimentos Sapiens + o SEU studio + a Emancipação. Sub-actions: mine (o Meu Studio do user: nível/marca/operador/ferramentas), list (todos com URL+status+tags+mcpReady), get (detalhe de 1 slug), publishable_url (formata URL /articles/<slug>), emancipar (INICIA o Nível 3: blueprint pra construir a casa PRÓPRIA do membro na infra dele, fora do Sapiens), module (guia de um módulo de infra: fundacao/sapiens-connect/telegram/email/auth). Use quando user pergunta 'que estúdios existem', 'qual o meu studio', ou 'quero montar meu site/minha casa própria'. Estúdios cobertos: helen-voice, musicator, persona-sapiens, personagem-atlas, sapiens-shorts, sapiens-video,
|
|
89
|
+
description: "Catálogo dos estúdios/experimentos Sapiens + o SEU studio + a Emancipação. Sub-actions: mine (o Meu Studio do user: nível/marca/operador/ferramentas), list (todos com URL+status+tags+mcpReady), get (detalhe de 1 slug), publishable_url (formata URL /articles/<slug>), emancipar (INICIA o Nível 3: blueprint pra construir a casa PRÓPRIA do membro na infra dele, fora do Sapiens), module (guia de um módulo de infra: fundacao/sapiens-connect/telegram/email/auth). Use quando user pergunta 'que estúdios existem', 'qual o meu studio', ou 'quero montar meu site/minha casa própria'. Estúdios cobertos: helen-voice, musicator, persona-sapiens, personagem-atlas, sapiens-shorts, sapiens-video, text-post-builder, comic-builder, carrosel-editorial, comunidade, repertorio.",
|
|
90
90
|
schema: studiosSchema,
|
|
91
91
|
handler: studios,
|
|
92
92
|
},
|
|
@@ -116,7 +116,7 @@ const TOOLS = {
|
|
|
116
116
|
handler: video,
|
|
117
117
|
},
|
|
118
118
|
sapiens_stock_audio: {
|
|
119
|
-
description: "Banco de som
|
|
119
|
+
description: "Banco de som da casa: trilha pronta E efeito sonoro (tabela stockAudio). Sub-actions de leitura (públicas, sem auth): categories (lista os moods/usos), list (busca com filtros mood/albumSlug/durationMax/search; kind='sfx' traz os EFEITOS: whoosh, clique, impacto, ambiência, foley — devolve {count, items} com title/url/durationSeconds/tags), get (1 item por audioId). Use pra puxar trilha/efeito pronto: pega a `url` e usa direto no ffmpeg. Não achou o efeito? generate (COBRA Sinapses, exige login) cria um novo por texto: prompt + durationSeconds (1-15, default 5) + provider ('mirelo' padrão 30 Sinapses/s mín 60 | 'elevenlabs' premium 60/s mín 120), assíncrono — acompanhe com generation-status (generationId) até 'ready' (audioUrl; o efeito também entra no acervo kind=sfx) ou 'failed' (Sinapses reembolsadas). Efeito é CURTO (1-15s): música/trilha nova é no sapiens_musicator. Mood disponíveis: calmo, intenso, narrativo, épico, sombrio.",
|
|
120
120
|
schema: stockAudioSchema,
|
|
121
121
|
handler: stockAudio,
|
|
122
122
|
},
|
|
@@ -205,6 +205,10 @@ Música (sapiens_musicator) é fluxo de 4 passos, EM ORDEM:
|
|
|
205
205
|
4. get passe o trackId e fique polando o status até 'ready' (ou 'failed').
|
|
206
206
|
Pular pro lyrics/render sem create, ou sem os campos, sempre falha.
|
|
207
207
|
|
|
208
|
+
Efeito sonoro (sapiens_stock_audio): primeiro procure pronto (action=list kind=sfx, grátis). Não achou, action=generate: prompt + durationSeconds (1-15, default 5) + provider ('mirelo' padrão | 'elevenlabs' premium, custo por segundo). Assíncrono: devolve generationId, acompanhe com action=generation-status até 'ready' (audioUrl) ou 'failed' (reembolsa sozinho). Efeito é CURTO; música inteira é no sapiens_musicator, não aqui.
|
|
209
|
+
|
|
210
|
+
Sonorizar clipe (sapiens_video action=sonorize): dá som a um vídeo SEU já gerado (status completed). Passe imageId + prompt descrevendo o som da cena (ambiente, materiais, impactos); sai uma VARIANTE nova com trilha sincronizada ao movimento (MMAudio, 20 Sinapses/s do clipe, mín 100), o original fica intacto. Acompanhe com action=status no imageId NOVO que o sonorize devolve. Não re-sonorize uma variante: sonorize sempre o original.
|
|
211
|
+
|
|
208
212
|
Vídeo (sapiens_video) action=create EXIGE 'model': sapiens-video-seedance | kling | wan | kling-motion | lite | fast | quality | omni. Sem model, falha de cara. O 'omni' (Gemini Omni) gera clipe de 10s 720p com áudio nativo a partir de TEXTO (não aceita imagem/vídeo do user, ignora duração/resolução) e EDITA os próprios vídeos: passe editOfImageId com o imageId de um vídeo Omni já gerado e o prompt vira instrução de edição sobre a MESMA cena (troca item/personagem, preserva câmera e ambiente; cada edição debita como geração nova). É o caminho pra variações com continuidade: gera a base uma vez, edita N vezes. Vídeo é o mais caro: confirme com o usuário antes. action=shadows (ADMIN, 200 Sinapses/segundo, refund na falha): passa videoUrl (URL pública) + title (+ durationSec se souber, pra cobrar proporcional; sem ela, flat ~2000) e o servidor extrai a SOMBRA (mapa de profundidade) do vídeo e guarda no Acervo (Corpo) como deepshadow reutilizável (driving pro Shot Mimic/Kling Motion). Vitrine dos demos (sem custo): sapiens_video action=demos lista seus demo films com slug; action=showcase (slug + showcase=true/false + showcaseTag + showcaseOrder) cura o mini-cinema da /conectar-claude. FILMES DA CASA (Estúdio de Vídeo, tela /experimentos/films): são OUTRA coisa, três kinds na tabela videoSpecs: demo (UI clonada + câmera), aula-tour (telas reais + narração) e essay (fita-ensaio abstrata: partícula/tinta vira símbolo, com a logo explodindo no fim; narração da casa OPCIONAL, sai em 16:9 ou 9:16 vertical, e o filme final é limpo, sem rótulos de produção). Eles NÃO são gerados por este MCP: o user monta o spec na tela e um agente local (Claude Code, skill /film) produz o mp4 no repo da casa. Se o user pedir 'fita-ensaio' ou 'demo film' aqui, aponte pra tela e pro agente local.
|
|
209
213
|
|
|
210
214
|
Imagem (sapiens_image) action=generate: prompt + model + aspectRatio. Referência via referenceImageUrls (galeria/Acervo/personagens) e/ou sourceImageIds. templateSlug aplica um super-prompt travado da casa. PROMPT na regra da casa: full-bleed, sujeito oversized (70%+ do frame), sem "tarot card"/"intimate scale"/moldura/margem. action=models (sem custo, sem login) lista os modelos ativos com o preço atual: consulte quando não tiver certeza do modelo ou do custo.
|
|
@@ -237,7 +241,7 @@ Voz da casa: 1ª pessoa, direto, anti-corporate, sem travessão. Pra bom entende
|
|
|
237
241
|
// escreve/cobra (as multi-action com 1 mutation ficam de fora, honestamente).
|
|
238
242
|
const READ_ONLY_TOOLS = new Set([
|
|
239
243
|
"sapiens_search",
|
|
240
|
-
|
|
244
|
+
// sapiens_stock_audio SAIU do set: action=generate cobra Sinapses.
|
|
241
245
|
"sapiens_stock_video",
|
|
242
246
|
"sapiens_atlas",
|
|
243
247
|
"sapiens_reference",
|
package/dist/tools/aula.js
CHANGED
|
@@ -43,7 +43,19 @@ export async function aula(args) {
|
|
|
43
43
|
}
|
|
44
44
|
case "upsert": {
|
|
45
45
|
const slug = need(args.slug, "slug");
|
|
46
|
-
const
|
|
46
|
+
const raw = need(args.aula, "aula");
|
|
47
|
+
// `aula` é z.any(): sem tipo declarado, o cliente costuma serializar o
|
|
48
|
+
// objeto como string JSON. Normaliza aqui pra mandar objeto sempre (o
|
|
49
|
+
// servidor também parseia string, mas o shape certo sai daqui).
|
|
50
|
+
let aulaObj = raw;
|
|
51
|
+
if (typeof aulaObj === "string") {
|
|
52
|
+
try {
|
|
53
|
+
aulaObj = JSON.parse(aulaObj);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
throw new Error('Arg "aula" veio como string mas não é JSON válido. Mande o objeto da aula.');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
47
59
|
return await convexMutation("mcpExtras:mcpUpsertAula", {
|
|
48
60
|
sessionToken,
|
|
49
61
|
slug,
|
package/dist/tools/helen.js
CHANGED
|
@@ -24,7 +24,7 @@ export const helenSchema = z.object({
|
|
|
24
24
|
modelId: z
|
|
25
25
|
.string()
|
|
26
26
|
.optional()
|
|
27
|
-
.describe("ElevenLabs: 'eleven_v3' (default) ou 'eleven_multilingual_v2'. Google: 'gemini-
|
|
27
|
+
.describe("ElevenLabs: 'eleven_v3' (default) ou 'eleven_multilingual_v2'. Google: 'gemini-3.1-flash-tts-preview' (default)."),
|
|
28
28
|
voiceId: z
|
|
29
29
|
.string()
|
|
30
30
|
.optional()
|
|
@@ -71,7 +71,7 @@ const PRESETS = {
|
|
|
71
71
|
],
|
|
72
72
|
},
|
|
73
73
|
google: {
|
|
74
|
-
note: "Google Gemini TTS. modelId 'gemini-
|
|
74
|
+
note: "Google Gemini TTS. modelId 'gemini-3.1-flash-tts-preview'. Custa ~$0.01 USD pra 500 chars (mais barato).",
|
|
75
75
|
voices: [
|
|
76
76
|
{ voiceName: "Kore", use: "feminina, neutra (default)" },
|
|
77
77
|
{ voiceName: "Aoede", use: "feminina, melódica" },
|
|
@@ -98,7 +98,9 @@ export async function helen(args) {
|
|
|
98
98
|
const modelId = args.modelId ??
|
|
99
99
|
(provider === "elevenlabs"
|
|
100
100
|
? "eleven_v3"
|
|
101
|
-
|
|
101
|
+
// 3.1 Flash é o único TTS do Google que gera nas contas free da casa
|
|
102
|
+
// (o 2.5 responde 200 sem áudio nelas e só sai na conta central).
|
|
103
|
+
: "gemini-3.1-flash-tts-preview");
|
|
102
104
|
if (provider === "elevenlabs" && !args.voiceId) {
|
|
103
105
|
throw new Error("provider=elevenlabs exige voiceId. Use action=list_presets pra ver opções.");
|
|
104
106
|
}
|
package/dist/tools/meta.js
CHANGED
|
@@ -84,16 +84,8 @@ const FORMAT_GUIDE = {
|
|
|
84
84
|
scenes: [{ visual: "string", voiceover: "string", duration: "number" }],
|
|
85
85
|
},
|
|
86
86
|
},
|
|
87
|
-
cena_visual: {
|
|
88
|
-
description: "Vídeo curto programático via Hyperframes (movimento + texto entram por código).",
|
|
89
|
-
payloadHint: {
|
|
90
|
-
concept: "string (ideia da cena)",
|
|
91
|
-
scenes: [{ text: "string", motion: "string", durationMs: "number" }],
|
|
92
|
-
durationMs: "number total opcional",
|
|
93
|
-
},
|
|
94
|
-
},
|
|
95
87
|
video_yt: {
|
|
96
|
-
description: "Vídeo
|
|
88
|
+
description: "Vídeo longer-form.",
|
|
97
89
|
payloadHint: {
|
|
98
90
|
title: "string",
|
|
99
91
|
script: "string roteiro completo",
|
package/dist/tools/pipeline.js
CHANGED
|
@@ -10,14 +10,14 @@ const FORMATS = [
|
|
|
10
10
|
"post_social",
|
|
11
11
|
"mega_grafico",
|
|
12
12
|
"shorts_yt",
|
|
13
|
-
"cena_visual",
|
|
14
13
|
"video_yt",
|
|
15
14
|
"musica",
|
|
16
15
|
"aula",
|
|
17
16
|
];
|
|
18
17
|
// Formatos legados: fora do FORMAT_GUIDE (não advertidos), mas ainda aceitos na
|
|
19
|
-
// validação pra editar productions antigas sem quebrar.
|
|
20
|
-
|
|
18
|
+
// validação pra editar productions antigas sem quebrar. cena_visual ("Vídeo
|
|
19
|
+
// Programático") saiu de linha em jul/2026: Films + gerador de vídeo cobrem o caso.
|
|
20
|
+
const LEGACY_FORMATS = ["post_linkedin", "post_twitter", "post_threads", "cena_visual"];
|
|
21
21
|
const ACCEPTED_FORMATS = [...FORMATS, ...LEGACY_FORMATS];
|
|
22
22
|
const STATUSES = ["draft", "ready", "finalized"];
|
|
23
23
|
export const pipelineSchema = z.object({
|
|
@@ -136,6 +136,20 @@ function need(value, name) {
|
|
|
136
136
|
}
|
|
137
137
|
return value;
|
|
138
138
|
}
|
|
139
|
+
// `payload` é z.any(): sem tipo declarado, o cliente costuma serializar o
|
|
140
|
+
// objeto como string JSON (mesmo caso do upsert de aula em aula.ts). Normaliza
|
|
141
|
+
// aqui pra mandar objeto sempre (o servidor também parseia string por defesa,
|
|
142
|
+
// mas o shape certo sai daqui). String crua no banco = editor abre "vazio".
|
|
143
|
+
function coercePayloadArg(raw) {
|
|
144
|
+
if (typeof raw !== "string")
|
|
145
|
+
return raw;
|
|
146
|
+
try {
|
|
147
|
+
return JSON.parse(raw);
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
throw new Error('Arg "payload" veio como string mas não é JSON válido. Mande o objeto do payload.');
|
|
151
|
+
}
|
|
152
|
+
}
|
|
139
153
|
export async function pipeline(args) {
|
|
140
154
|
const sessionToken = getSessionToken();
|
|
141
155
|
switch (args.action) {
|
|
@@ -190,7 +204,7 @@ export async function pipeline(args) {
|
|
|
190
204
|
sessionToken,
|
|
191
205
|
sourceId: need(args.sourceId, "sourceId"),
|
|
192
206
|
format: need(args.format, "format"),
|
|
193
|
-
payload: args.payload,
|
|
207
|
+
payload: coercePayloadArg(args.payload),
|
|
194
208
|
});
|
|
195
209
|
return { productionId: id };
|
|
196
210
|
}
|
|
@@ -198,7 +212,7 @@ export async function pipeline(args) {
|
|
|
198
212
|
await convexMutation("pipelineMcp:mcpUpdateProductionPayload", {
|
|
199
213
|
sessionToken,
|
|
200
214
|
productionId: need(args.productionId, "productionId"),
|
|
201
|
-
payload: need(args.payload, "payload"),
|
|
215
|
+
payload: coercePayloadArg(need(args.payload, "payload")),
|
|
202
216
|
status: args.status,
|
|
203
217
|
});
|
|
204
218
|
return { ok: true };
|
package/dist/tools/stockAudio.js
CHANGED
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { convexQuery } from "../convexClient.js";
|
|
2
|
+
import { convexQuery, convexAction, getSessionToken } from "../convexClient.js";
|
|
3
3
|
/**
|
|
4
|
-
* Banco de som
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Banco de som da casa (tabela stockAudio): trilha pronta E efeito sonoro.
|
|
5
|
+
* Leitura pública (acervo free, sem auth); geração de efeito cobra Sinapses
|
|
6
|
+
* (exige login). Espelha o padrão do stock de imagem.
|
|
7
7
|
*
|
|
8
8
|
* Fluxo típico numa skill de vídeo:
|
|
9
9
|
* 1. action=categories -> ver os moods/usos disponíveis
|
|
10
|
-
* 2. action=list (mood=.. durationMax=..) -> achar candidatas
|
|
11
|
-
* 3. pega a `url` da escolhida -> usa direto no ffmpeg como trilha
|
|
10
|
+
* 2. action=list (mood=.. durationMax=.. | kind=sfx) -> achar candidatas
|
|
11
|
+
* 3. pega a `url` da escolhida -> usa direto no ffmpeg como trilha/efeito
|
|
12
|
+
*
|
|
13
|
+
* Não achou o efeito? action=generate cria um novo (assíncrono):
|
|
14
|
+
* generate (prompt + durationSeconds + provider) -> generationId
|
|
15
|
+
* generation-status (generationId) até 'ready' -> audioUrl
|
|
16
|
+
* O efeito pronto também entra no acervo (action=list kind=sfx).
|
|
12
17
|
*/
|
|
13
18
|
export const stockAudioSchema = z.object({
|
|
14
19
|
action: z
|
|
15
|
-
.enum(["list", "get", "categories"])
|
|
16
|
-
.describe("list = busca faixas; get = 1
|
|
20
|
+
.enum(["list", "get", "categories", "generate", "generation-status"])
|
|
21
|
+
.describe("list = busca faixas/efeitos; get = 1 item por id; categories = moods/usos; " +
|
|
22
|
+
"generate = cria efeito sonoro novo (COBRA Sinapses, assíncrono); " +
|
|
23
|
+
"generation-status = status de uma geração (até ready/failed)."),
|
|
17
24
|
limit: z
|
|
18
25
|
.number()
|
|
19
26
|
.int()
|
|
@@ -42,7 +49,29 @@ export const stockAudioSchema = z.object({
|
|
|
42
49
|
.positive()
|
|
43
50
|
.optional()
|
|
44
51
|
.describe("Duração máxima em segundos (ex: 120 pra trilha de movie < 2min)."),
|
|
52
|
+
kind: z
|
|
53
|
+
.enum(["music", "sfx", "all"])
|
|
54
|
+
.optional()
|
|
55
|
+
.describe("action=list: 'music' (default, trilhas) | 'sfx' (efeitos sonoros: whoosh, clique, ambiência, foley) | 'all'."),
|
|
45
56
|
audioId: z.string().optional().describe("stockAudio:_id (obrigatório pra action=get)."),
|
|
57
|
+
// --- action=generate (efeito sonoro novo) ---
|
|
58
|
+
prompt: z
|
|
59
|
+
.string()
|
|
60
|
+
.optional()
|
|
61
|
+
.describe("action=generate: descreve o efeito (ex: 'whoosh curto de transição, grave e limpo'). " +
|
|
62
|
+
"Mín. 4 chars. Efeito é CURTO (1-15s); música/trilha é no sapiens_musicator."),
|
|
63
|
+
durationSeconds: z
|
|
64
|
+
.number()
|
|
65
|
+
.optional()
|
|
66
|
+
.describe("action=generate: duração alvo em segundos, 1 a 15. Default 5. O custo escala por segundo."),
|
|
67
|
+
provider: z
|
|
68
|
+
.enum(["mirelo", "elevenlabs"])
|
|
69
|
+
.optional()
|
|
70
|
+
.describe("action=generate: 'mirelo' (padrão, 30 Sinapses/s, mín 60) | 'elevenlabs' (premium, 60/s, mín 120)."),
|
|
71
|
+
generationId: z
|
|
72
|
+
.string()
|
|
73
|
+
.optional()
|
|
74
|
+
.describe("action=generation-status: o generationId que o generate devolveu."),
|
|
46
75
|
});
|
|
47
76
|
export async function stockAudio(args) {
|
|
48
77
|
if (args.action === "categories") {
|
|
@@ -54,6 +83,28 @@ export async function stockAudio(args) {
|
|
|
54
83
|
throw new Error("action=get exige audioId.");
|
|
55
84
|
return await convexQuery("stockAudio:getAudioById", { id: args.audioId });
|
|
56
85
|
}
|
|
86
|
+
if (args.action === "generate") {
|
|
87
|
+
if (!args.prompt || args.prompt.trim().length < 4) {
|
|
88
|
+
throw new Error("action=generate exige prompt (mín. 4 chars descrevendo o efeito).");
|
|
89
|
+
}
|
|
90
|
+
const sessionToken = getSessionToken();
|
|
91
|
+
return await convexAction("mcpExtrasActions:mcpStockAudioGenerate", {
|
|
92
|
+
sessionToken,
|
|
93
|
+
prompt: args.prompt,
|
|
94
|
+
durationSeconds: args.durationSeconds,
|
|
95
|
+
provider: args.provider,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
if (args.action === "generation-status") {
|
|
99
|
+
if (!args.generationId) {
|
|
100
|
+
throw new Error("action=generation-status exige generationId (o que o generate devolveu).");
|
|
101
|
+
}
|
|
102
|
+
const sessionToken = getSessionToken();
|
|
103
|
+
return await convexQuery("mcpExtras:mcpSfxStatus", {
|
|
104
|
+
sessionToken,
|
|
105
|
+
generationId: args.generationId,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
57
108
|
// action=list
|
|
58
109
|
return await convexQuery("stockAudio:getAudio", {
|
|
59
110
|
limit: args.limit ?? 20,
|
|
@@ -62,5 +113,6 @@ export async function stockAudio(args) {
|
|
|
62
113
|
mood: args.mood,
|
|
63
114
|
albumSlug: args.albumSlug,
|
|
64
115
|
durationMax: args.durationMax,
|
|
116
|
+
kind: args.kind,
|
|
65
117
|
});
|
|
66
118
|
}
|
package/dist/tools/studios.js
CHANGED
|
@@ -88,7 +88,7 @@ const STUDIOS = {
|
|
|
88
88
|
},
|
|
89
89
|
"sapiens-video": {
|
|
90
90
|
name: "Sapiens Video (longer-form)",
|
|
91
|
-
description: "Vídeo
|
|
91
|
+
description: "Vídeo longer-form com prompt livre. v1.5: generate via MCP.",
|
|
92
92
|
url: `${APP}/imgen-sapiens-video`,
|
|
93
93
|
status: "beta",
|
|
94
94
|
tags: ["video", "longform", "voiceover", "veo"],
|
|
@@ -96,15 +96,6 @@ const STUDIOS = {
|
|
|
96
96
|
mcpReady: true,
|
|
97
97
|
mcpNote: "Coberto via sapiens_video (generate). Aspect configurável, references opcionais (start/end frames).",
|
|
98
98
|
},
|
|
99
|
-
"cena-visual": {
|
|
100
|
-
name: "Sapiens Cena Visual",
|
|
101
|
-
description: "Still única pra abertura, ou hero shot, ou simbólica.",
|
|
102
|
-
url: `${APP}/imgen-sapiens-cena-visual`,
|
|
103
|
-
status: "stable",
|
|
104
|
-
tags: ["image", "still", "hero"],
|
|
105
|
-
convex: "sapiensCenaVisualActions",
|
|
106
|
-
mcpReady: false,
|
|
107
|
-
},
|
|
108
99
|
"text-post-builder": {
|
|
109
100
|
name: "Text Post Builder",
|
|
110
101
|
description: "Gerador de post de texto puro pra rede social (Instagram, LinkedIn, Twitter). Inclui geração de imagem opcional acoplada.",
|
package/dist/tools/video.js
CHANGED
|
@@ -21,6 +21,9 @@ import { httpUrl } from "../schema.js";
|
|
|
21
21
|
* com as duas views por ficha: url = sombra pura (driving pros
|
|
22
22
|
* geradores) e skeletonUrl = a soma (sombras + esqueleto, preview
|
|
23
23
|
* humano que separa personagem de objeto). Sem custo.
|
|
24
|
+
* - sonorize: dá som a um clipe SEU já gerado (MMAudio v2): imageId + prompt do
|
|
25
|
+
* som da cena -> VARIANTE nova com trilha sincronizada (o original
|
|
26
|
+
* fica intacto). Cobra por segundo do clipe; poll via action=status.
|
|
24
27
|
*
|
|
25
28
|
* Modelos (action=create):
|
|
26
29
|
* - sapiens-video-seedance Seedance 2.0 — cena com áudio nativo, 4-15s, 480/720/1080p (t2v/i2v)
|
|
@@ -54,7 +57,7 @@ const VIDEO_MODELS = [
|
|
|
54
57
|
"sapiens-video-omni",
|
|
55
58
|
];
|
|
56
59
|
export const videoSchema = z.object({
|
|
57
|
-
action: z.enum(["create", "generate", "status", "models", "demos", "showcase", "shadows", "shadows-list"]),
|
|
60
|
+
action: z.enum(["create", "generate", "status", "models", "demos", "showcase", "shadows", "shadows-list", "sonorize"]),
|
|
58
61
|
// --- action=shadows (deepshadows: extrai o mapa de profundidade de um vídeo) ---
|
|
59
62
|
videoUrl: httpUrl()
|
|
60
63
|
.optional()
|
|
@@ -121,7 +124,8 @@ export const videoSchema = z.object({
|
|
|
121
124
|
.string()
|
|
122
125
|
.optional()
|
|
123
126
|
.describe("action=generate ou action=status: generatedImages:_id do vídeo. O create devolve o imageId; " +
|
|
124
|
-
"ou um vídeo já criado no site (o row define modelo + custo). Use sapiens_gallery action=list pra descobrir."
|
|
127
|
+
"ou um vídeo já criado no site (o row define modelo + custo). Use sapiens_gallery action=list pra descobrir. " +
|
|
128
|
+
"action=sonorize: o imageId do clipe SEU (status completed) que vai ganhar som."),
|
|
125
129
|
// --- comum ---
|
|
126
130
|
prompt: z
|
|
127
131
|
.string()
|
|
@@ -185,7 +189,7 @@ export async function video(args) {
|
|
|
185
189
|
count: models.length,
|
|
186
190
|
default: "sapiens-video-seedance",
|
|
187
191
|
models,
|
|
188
|
-
note: "basePriceSinapses é o PISO (config mais barata, já com override admin); o preço real escala por duração x resolução [x áudio]. available=false = 'em breve' (depende de env, ex: Omni).
|
|
192
|
+
note: "basePriceSinapses é o PISO (config mais barata, já com override admin); o preço real escala por duração x resolução [x áudio]. available=false = 'em breve' (depende de env, ex: Omni).",
|
|
189
193
|
};
|
|
190
194
|
}
|
|
191
195
|
const sessionToken = getSessionToken();
|
|
@@ -216,6 +220,19 @@ export async function video(args) {
|
|
|
216
220
|
imageId: args.imageId,
|
|
217
221
|
});
|
|
218
222
|
}
|
|
223
|
+
if (args.action === "sonorize") {
|
|
224
|
+
if (!args.imageId) {
|
|
225
|
+
throw new Error("action=sonorize exige imageId (o clipe SEU, já completed, que vai ganhar som).");
|
|
226
|
+
}
|
|
227
|
+
if (!args.prompt || args.prompt.trim().length < 4) {
|
|
228
|
+
throw new Error("action=sonorize exige prompt descrevendo o som da cena (ambiente, materiais, impactos, textura).");
|
|
229
|
+
}
|
|
230
|
+
return await convexAction("mcpExtrasActions:mcpVideoSonorize", {
|
|
231
|
+
sessionToken,
|
|
232
|
+
sourceImageId: args.imageId,
|
|
233
|
+
prompt: args.prompt,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
219
236
|
if (args.action === "create") {
|
|
220
237
|
if (!args.model) {
|
|
221
238
|
throw new Error("action=create exige model (ex: sapiens-video-seedance, sapiens-video-kling, sapiens-video-wan, sapiens-video-kling-motion).");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sapiens-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.32.0",
|
|
4
4
|
"description": "MCP server pra operar o Sapiens Sintéticos (sapiensinteticos.com) pelo Claude Code: gerar imagem, escrever artigo, voz, música e mais, na sua conta. Login pelo código de sapiensinteticos.com/conectar-claude.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|