beplus-mcp 0.41.0 → 0.42.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/README.md +11 -1
- package/dist/index.js +41 -19
- package/dist/index.js.map +1 -1
- package/dist/remote-server.js +41 -19
- package/dist/remote-server.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -103,7 +103,7 @@ Reinicie o cliente. Rode a tool **`whoami`** para confirmar o vínculo.
|
|
|
103
103
|
| `generate_image` | Gera imagem (nano-banana / gpt-image-2). Bloqueante ~90s; retorna URL + imagem inline. Suporta refs, tamanho/qualidade, e extras do gpt-image-2 (background, moderation, output_format/compression). |
|
|
104
104
|
| `generate_video` | Gera vídeo (Seedance / Kling). Aguarda ~120s; senão devolve o id pra `check_generation`. Suporta first/last frame, refs de imagem/vídeo/áudio, prompt negativo, áudio gerado, mode e motion-control. |
|
|
105
105
|
| `upscale` | Melhora a resolução de uma imagem ou vídeo que já existe (Topaz). Detecta o tipo pelo arquivo. Imagem até 4x (~20s, a partir de 6💎); vídeo até 30s e saída até 1080p, custa por bloco de 10s e **descarta o áudio**. Mede o arquivo sozinho para o preço sair certo. ⚠️ Vídeo é restrito à equipe. |
|
|
106
|
-
| `generate_audio` | Sintetiza fala
|
|
106
|
+
| `generate_audio` | Sintetiza fala com Gemini TTS ou SeedAudio 1.0 com referência de voz. Padrão `gemini-3.8-flash-lite-tts`; os modelos 3.8 aceitam vozes da biblioteca, tags vocais (`<laugh>`, `<sigh>`...) e `style` por locutor; os legados só as 30 vozes clássicas. Síncrono. |
|
|
107
107
|
| `list_tts_voices` | Lista as vozes da biblioteca do TTS 3.8 (filtros: idioma, gênero, tom, contexto, busca) com o id para usar em `voice`. Somente leitura. |
|
|
108
108
|
| `list_custom_voices` | Lista suas vozes próprias do TTS 3.8 (máx. 3) com o `voice_xxx` para usar em `voice`. Clonar a própria voz só no app web. Somente leitura. |
|
|
109
109
|
| `design_voice` | Cria uma voz própria a partir de uma descrição. Gasta 💎 e leva ~30 s. |
|
|
@@ -232,3 +232,13 @@ BEPLUS_API_TOKEN=pat_… npx @modelcontextprotocol/inspector node dist/index.js
|
|
|
232
232
|
- **stdout** é o canal JSON-RPC — todo log vai pra **stderr** e o token nunca é logado.
|
|
233
233
|
- Limites, créditos, visibilidade e logging são enforçados pelo backend; um PAT vazado é limitado aos caps/diamantes do dono e pode ser revogado no painel.
|
|
234
234
|
- `list_models` é a fonte de verdade em runtime; os enums do pacote podem ficar atrás quando o backend adiciona modelos.
|
|
235
|
+
|
|
236
|
+
### SeedAudio 1.0
|
|
237
|
+
|
|
238
|
+
Use `generate_audio` com `model: "seed-audio-1.0"`, `text` e direção opcional em `style_instruction`. Omita `voice` ou use `seed-auto`. Texto e direção somados: até 2700 caracteres. Sem diálogo nem vozes Gemini.
|
|
239
|
+
|
|
240
|
+
Para referência, passe `seed_reference` como arquivo local no stdio ou URL pública no conector remoto. Um áudio de 1 a 30 segundos, até 3 MiB, com `seed_consent: true` após autorização explícita da pessoa. O MCP envia os bytes diretamente ao backend, sem publicar um novo arquivo de referência. O modo remoto mantém a proteção de caminhos locais e rede privada.
|
|
241
|
+
|
|
242
|
+
A resposta inclui o ID da geração. Para repetir a voz, use esse ID em `seed_reference_generation_id` e confirme novamente `seed_consent`. Só referências de gerações da própria conta são aceitas. Essa referência por pedido é separada das vozes próprias do Gemini.
|
|
243
|
+
|
|
244
|
+
O conector remoto também precisa da nova versão do pacote no backend. Ordem de entrega: configurar `SEEDAUDIO_API_KEY` e disponibilizar o backend TTS, atualizar o pacote MCP no backend, depois disponibilizar IA Lab e Canvas.
|
package/dist/index.js
CHANGED
|
@@ -21619,7 +21619,7 @@ var BeplusClient = class {
|
|
|
21619
21619
|
});
|
|
21620
21620
|
}
|
|
21621
21621
|
tts(body2) {
|
|
21622
|
-
return this.request("POST", "/tts", { body: body2, timeoutMs: 9e4 });
|
|
21622
|
+
return this.request("POST", "/tts", { body: body2, timeoutMs: body2.model === "seed-audio-1.0" ? 18e4 : 9e4 });
|
|
21623
21623
|
}
|
|
21624
21624
|
ttsVoices(query) {
|
|
21625
21625
|
return this.request("GET", "/tts/voices", { query, timeoutMs: 2e4 });
|
|
@@ -21919,7 +21919,7 @@ function tooLarge(name, bytes) {
|
|
|
21919
21919
|
`"${name}" ${size} acima do teto de 95 MB para subir pela API (o proxy da Cloudflare corta corpo acima de 100 MB antes de chegar no servidor). Comprima ou corte o arquivo (ex.: ffmpeg -i entrada.mp4 -crf 26 saida.mp4) e tente de novo.`
|
|
21920
21920
|
);
|
|
21921
21921
|
}
|
|
21922
|
-
async function loadLocal(ref) {
|
|
21922
|
+
async function loadLocal(ref, maxBytes = MAX_UPLOAD_BYTES) {
|
|
21923
21923
|
const abs = toLocalPath(ref);
|
|
21924
21924
|
const name = basename(abs);
|
|
21925
21925
|
let size;
|
|
@@ -21931,10 +21931,10 @@ async function loadLocal(ref) {
|
|
|
21931
21931
|
`Arquivo local n\xE3o encontrado: "${ref}". Passe um caminho v\xE1lido ou uma URL p\xFAblica (http/https).`
|
|
21932
21932
|
);
|
|
21933
21933
|
}
|
|
21934
|
-
if (size >
|
|
21934
|
+
if (size > maxBytes) throw maxBytes === MAX_UPLOAD_BYTES ? tooLarge(name, size) : new ApiError(413, `O arquivo deve ter at\xE9 ${mb(maxBytes)} MB.`);
|
|
21935
21935
|
return { buf: await readFile2(abs), name, mime: mimeForName(abs), localPath: abs };
|
|
21936
21936
|
}
|
|
21937
|
-
async function loadRemote(url) {
|
|
21937
|
+
async function loadRemote(url, maxBytes = MAX_UPLOAD_BYTES) {
|
|
21938
21938
|
const u = new URL(url);
|
|
21939
21939
|
let name = decodeURIComponent(basename(u.pathname)) || "arquivo";
|
|
21940
21940
|
let res;
|
|
@@ -21950,10 +21950,10 @@ async function loadRemote(url) {
|
|
|
21950
21950
|
throw new ApiError(res.status, `N\xE3o consegui baixar ${url}: a origem respondeu HTTP ${res.status}.`);
|
|
21951
21951
|
}
|
|
21952
21952
|
const declared = Number(res.headers.get("content-length") ?? NaN);
|
|
21953
|
-
if (Number.isFinite(declared) && declared >
|
|
21953
|
+
if (Number.isFinite(declared) && declared > maxBytes) {
|
|
21954
21954
|
await res.body?.cancel().catch(() => {
|
|
21955
21955
|
});
|
|
21956
|
-
throw tooLarge(name, declared);
|
|
21956
|
+
throw maxBytes === MAX_UPLOAD_BYTES ? tooLarge(name, declared) : new ApiError(413, `O arquivo deve ter at\xE9 ${mb(maxBytes)} MB.`);
|
|
21957
21957
|
}
|
|
21958
21958
|
const chunks = [];
|
|
21959
21959
|
let total = 0;
|
|
@@ -21964,10 +21964,10 @@ async function loadRemote(url) {
|
|
|
21964
21964
|
const { done, value } = await reader.read();
|
|
21965
21965
|
if (done) break;
|
|
21966
21966
|
total += value.byteLength;
|
|
21967
|
-
if (total >
|
|
21967
|
+
if (total > maxBytes) {
|
|
21968
21968
|
await reader.cancel().catch(() => {
|
|
21969
21969
|
});
|
|
21970
|
-
throw tooLarge(name, null);
|
|
21970
|
+
throw maxBytes === MAX_UPLOAD_BYTES ? tooLarge(name, null) : new ApiError(413, `O arquivo deve ter at\xE9 ${mb(maxBytes)} MB.`);
|
|
21971
21971
|
}
|
|
21972
21972
|
chunks.push(Buffer.from(value.buffer, value.byteOffset, value.byteLength));
|
|
21973
21973
|
}
|
|
@@ -22282,6 +22282,7 @@ var MUSIC_TASK_TYPES = ["create", "extend", "cover", "upload_extend", "upload_co
|
|
|
22282
22282
|
var MUSIC_TOOLS = ["wav", "midi", "stems-basic", "stems-full", "bpm", "lyrics-timeline"];
|
|
22283
22283
|
var VOCAL_GENDERS = ["f", "m"];
|
|
22284
22284
|
var TTS_MODELS = [
|
|
22285
|
+
"seed-audio-1.0",
|
|
22285
22286
|
"gemini-3.8-flash-lite-tts",
|
|
22286
22287
|
"gemini-3.8-flash-tts",
|
|
22287
22288
|
"gemini-3.1-flash-tts-preview",
|
|
@@ -23856,7 +23857,7 @@ var VOICE_HELP_TOP = `${VOICE_HELP} Ou o id de uma voz pr\xF3pria (voice_xxx, de
|
|
|
23856
23857
|
var voiceSchema = external_exports.string().refine((v) => VOICES.includes(v) || LIBRARY_VOICE_ID.test(v), {
|
|
23857
23858
|
message: "Voz inv\xE1lida: use uma das 30 vozes cl\xE1ssicas (ex.: Kore) ou um id da biblioteca (ex.: pt-br-advisor-10)."
|
|
23858
23859
|
});
|
|
23859
|
-
var topVoiceSchema = external_exports.string().refine((v) => VOICES.includes(v) || LIBRARY_VOICE_ID.test(v) || CUSTOM_VOICE_ID.test(v), {
|
|
23860
|
+
var topVoiceSchema = external_exports.string().refine((v) => v === "seed-auto" || VOICES.includes(v) || LIBRARY_VOICE_ID.test(v) || CUSTOM_VOICE_ID.test(v), {
|
|
23860
23861
|
message: "Voz inv\xE1lida: use uma das 30 vozes cl\xE1ssicas (ex.: Kore), um id da biblioteca (ex.: pt-br-advisor-10) ou uma voz pr\xF3pria (voice_xxx)."
|
|
23861
23862
|
});
|
|
23862
23863
|
function isCustomVoice(v) {
|
|
@@ -23875,10 +23876,13 @@ function registerAudioTools(server, client, cfg) {
|
|
|
23875
23876
|
"generate_audio",
|
|
23876
23877
|
{
|
|
23877
23878
|
title: "Gerar \xE1udio (TTS)",
|
|
23878
|
-
description: 'Sintetiza fala a partir de texto
|
|
23879
|
+
description: 'Sintetiza fala a partir de texto e retorna a URL usando o IA Lab da BePlus. SeedAudio 1.0 (seed-audio-1.0) aceita dire\xE7\xE3o e uma refer\xEAncia de voz opcional via seed_reference ou seed_reference_generation_id, com seed_consent. Texto e dire\xE7\xE3o somados at\xE9 2700 caracteres. N\xE3o aceita di\xE1logo nem vozes Gemini. Modelos Gemini 3.8 (`gemini-3.8-flash-lite-tts`, padr\xE3o, r\xE1pido e barato; `gemini-3.8-flash-tts`, qualidade de est\xFAdio, melhor para di\xE1logo e narra\xE7\xE3o longa) aceitam: vozes da biblioteca (milhares, por idioma; liste com `list_tts_voices` e passe o id em `voice`), tags vocais no texto como <laugh> <chuckle> <sigh> <breath> <gasp> <cough> <sneeze> <throat-clearing> <yawn> <groan> <scream> <whimper> <argh> <short pause> <long pause> (viram som de verdade), e estilo por locutor (`style` em cada speaker). No 3.8, `style_instruction` \xE9 dire\xE7\xE3o e N\xC3O \xE9 lida em voz alta. Os modelos legados (`gemini-3.1-flash-tts-preview`, `gemini-2.5-pro-preview-tts`) s\xF3 aceitam as 30 vozes cl\xE1ssicas (Kore, Puck, Charon...) e n\xE3o t\xEAm voz da biblioteca. Vozes pr\xF3prias (voice_xxx; liste com `list_custom_voices`, crie com `design_voice`) s\xF3 no 3.8 e sem `multi_speaker`. No 3.8, dire\xE7\xE3o por linha: `(sussurrando) texto` no in\xEDcio da linha vale at\xE9 a pr\xF3xima dire\xE7\xE3o; no di\xE1logo, `Ana (rindo): fala`; rea\xE7\xF5es `|hmm|` `|aham|` no meio da fala (s\xF3 di\xE1logo). Opcional `style_instruction` (ex.: "fale animado e pausado") e di\xE1logo com 2 locutores via `multi_speaker`. Consome diamantes por segundo de \xE1udio.' + TEAM_GATING_NOTE,
|
|
23879
23880
|
inputSchema: {
|
|
23880
23881
|
text: external_exports.string().min(1).max(1e4).describe("Texto a ser falado."),
|
|
23881
|
-
voice: topVoiceSchema.
|
|
23882
|
+
voice: topVoiceSchema.optional().describe(VOICE_HELP_TOP + " No SeedAudio, omita ou use seed-auto."),
|
|
23883
|
+
seed_reference: external_exports.string().min(1).optional().describe("SeedAudio: arquivo local (stdio) ou URL p\xFAblica de uma voz autorizada, de 1 a 30 s e at\xE9 3 MiB. N\xE3o \xE9 publicado pelo MCP."),
|
|
23884
|
+
seed_reference_generation_id: external_exports.string().uuid().optional().describe("Reutiliza a refer\xEAncia de uma gera\xE7\xE3o SeedAudio sua. Alternativa a seed_reference."),
|
|
23885
|
+
seed_consent: external_exports.literal(true).optional().describe("Confirme apenas ap\xF3s autoriza\xE7\xE3o expl\xEDcita da pessoa para usar sua voz. Obrigat\xF3rio com refer\xEAncia."),
|
|
23882
23886
|
model: external_exports.enum(TTS_MODELS).default(DEFAULTS.ttsModel).describe("Modelo TTS."),
|
|
23883
23887
|
style_instruction: external_exports.string().max(2e3).optional().describe("Instru\xE7\xE3o de estilo/tom aplicada \xE0 fala."),
|
|
23884
23888
|
multi_speaker: external_exports.object({
|
|
@@ -23890,9 +23894,17 @@ function registerAudioTools(server, client, cfg) {
|
|
|
23890
23894
|
},
|
|
23891
23895
|
async (args) => {
|
|
23892
23896
|
try {
|
|
23897
|
+
const seed = args.model === "seed-audio-1.0";
|
|
23898
|
+
const voice = args.voice ?? (seed ? "seed-auto" : DEFAULTS.voice);
|
|
23899
|
+
const hasReference = !!(args.seed_reference || args.seed_reference_generation_id);
|
|
23900
|
+
if (!seed && (hasReference || args.seed_consent || voice === "seed-auto")) return errorResult("Os controles SeedAudio exigem seed-audio-1.0.");
|
|
23901
|
+
if (seed && (voice !== "seed-auto" || args.multi_speaker)) return errorResult("SeedAudio usa seed-auto e n\xE3o aceita di\xE1logo.");
|
|
23902
|
+
if (args.seed_reference && args.seed_reference_generation_id) return errorResult("Use apenas uma origem de refer\xEAncia.");
|
|
23903
|
+
if (hasReference && !args.seed_consent) return errorResult("Confirme a autoriza\xE7\xE3o da voz em seed_consent.");
|
|
23904
|
+
if (seed && args.text.trim().length + (args.style_instruction?.trim().length ?? 0) > 2700) return errorResult("SeedAudio: texto e dire\xE7\xE3o devem somar at\xE9 2700 caracteres.");
|
|
23893
23905
|
const ms = args.multi_speaker;
|
|
23894
|
-
const voices = [
|
|
23895
|
-
if (isCustomVoice(
|
|
23906
|
+
const voices = [voice, ms?.speaker1.voice, ms?.speaker2.voice].filter((v) => !!v);
|
|
23907
|
+
if (isCustomVoice(voice)) {
|
|
23896
23908
|
if (!TTS_MODELS_38.includes(args.model)) {
|
|
23897
23909
|
return errorResult("Vozes pr\xF3prias s\xF3 funcionam nos modelos Gemini 3.8 (gemini-3.8-flash-lite-tts, gemini-3.8-flash-tts).");
|
|
23898
23910
|
}
|
|
@@ -23900,7 +23912,7 @@ function registerAudioTools(server, client, cfg) {
|
|
|
23900
23912
|
return errorResult("Vozes pr\xF3prias n\xE3o funcionam no modo di\xE1logo (multi_speaker). Use uma voz da biblioteca ou cl\xE1ssica.");
|
|
23901
23913
|
}
|
|
23902
23914
|
}
|
|
23903
|
-
if (!TTS_MODELS_38.includes(args.model)) {
|
|
23915
|
+
if (!seed && !TTS_MODELS_38.includes(args.model)) {
|
|
23904
23916
|
if (voices.some(isLibraryVoice)) {
|
|
23905
23917
|
return errorResult(
|
|
23906
23918
|
`Vozes da biblioteca s\xF3 funcionam nos modelos Gemini 3.8 (gemini-3.8-flash-lite-tts, gemini-3.8-flash-tts). O modelo ${args.model} s\xF3 aceita as 30 vozes cl\xE1ssicas (Kore, Puck, Charon...).`
|
|
@@ -23910,9 +23922,18 @@ function registerAudioTools(server, client, cfg) {
|
|
|
23910
23922
|
return errorResult("O estilo por locutor (`style`) s\xF3 funciona nos modelos Gemini 3.8.");
|
|
23911
23923
|
}
|
|
23912
23924
|
}
|
|
23925
|
+
let seedReference;
|
|
23926
|
+
if (args.seed_reference) {
|
|
23927
|
+
const file = await (isRemoteRef(args.seed_reference) ? loadRemote(args.seed_reference, 3 * 1024 * 1024) : loadLocal(args.seed_reference, 3 * 1024 * 1024));
|
|
23928
|
+
if (!file.buf.length || file.buf.length > 3 * 1024 * 1024) return errorResult("A refer\xEAncia deve ter at\xE9 3 MiB.");
|
|
23929
|
+
seedReference = { audio: file.buf.toString("base64"), mime: file.mime };
|
|
23930
|
+
}
|
|
23913
23931
|
const body2 = compact({
|
|
23932
|
+
seedReference,
|
|
23933
|
+
seedReferenceGenerationId: args.seed_reference_generation_id,
|
|
23934
|
+
seedConsent: args.seed_consent,
|
|
23914
23935
|
text: args.text,
|
|
23915
|
-
voice
|
|
23936
|
+
voice,
|
|
23916
23937
|
model: args.model,
|
|
23917
23938
|
styleInstruction: args.style_instruction,
|
|
23918
23939
|
multiSpeaker: args.multi_speaker,
|
|
@@ -23922,12 +23943,13 @@ function registerAudioTools(server, client, cfg) {
|
|
|
23922
23943
|
const parts = [`Custo: ${res.diamond_cost} \u{1F48E}`];
|
|
23923
23944
|
if (res.diamonds_refunded) parts.push(`Estorno: ${res.diamonds_refunded} \u{1F48E}`);
|
|
23924
23945
|
const projLine = res.project_code ? `
|
|
23925
|
-
\u{1F4C1} Projeto: ${res.project_code}${res.project_name ?
|
|
23946
|
+
\u{1F4C1} Projeto: ${res.project_code}${res.project_name ? `: ${res.project_name}` : ""}` : "";
|
|
23926
23947
|
const wa = weeklyAllowanceLine(res.weekly_allowance);
|
|
23927
23948
|
const budget = budgetLine(res.budget);
|
|
23928
23949
|
return textResult(
|
|
23929
|
-
`\u2705 \xC1udio gerado (${res.model}, voz ${res.voice}, ${res.duration_sec.toFixed(1)}s).
|
|
23950
|
+
`\u2705 \xC1udio gerado (${res.model}, voz ${seed ? "por refer\xEAncia ou descri\xE7\xE3o" : res.voice}, ${res.duration_sec.toFixed(1)}s).
|
|
23930
23951
|
${res.url}
|
|
23952
|
+
Gera\xE7\xE3o: ${res.generation_id}
|
|
23931
23953
|
${parts.join(" \xB7 ")}${projLine}` + (budget ? `
|
|
23932
23954
|
${budget}` : "") + (wa ? `
|
|
23933
23955
|
${wa}` : "")
|
|
@@ -24773,7 +24795,7 @@ var KINDS = {
|
|
|
24773
24795
|
data: { model: "gemini-3.8-flash-lite-tts", voice: "Algieba", speed: "normal" },
|
|
24774
24796
|
inputs: ["text"],
|
|
24775
24797
|
outputs: ["audio", "approved"],
|
|
24776
|
-
dynamic: "style conforme o modelo"
|
|
24798
|
+
dynamic: "style conforme o modelo; SeedAudio 1.0 tem reference (audio), usa voice: seed-auto e seedConsent: true com refer\xEAncia; alternativa seedReferenceGenerationId de gera\xE7\xE3o pr\xF3pria"
|
|
24777
24799
|
},
|
|
24778
24800
|
music: {
|
|
24779
24801
|
title: "Trilha",
|
|
@@ -27823,7 +27845,7 @@ N\xF3s: ${Object.entries(ids).map(([k, v]) => `${k}=${v}`).join(" \xB7 ")}` : ""
|
|
|
27823
27845
|
import { createRequire } from "module";
|
|
27824
27846
|
var require2 = createRequire(import.meta.url);
|
|
27825
27847
|
function readVersion() {
|
|
27826
|
-
if ("0.
|
|
27848
|
+
if ("0.42.0") return "0.42.0";
|
|
27827
27849
|
try {
|
|
27828
27850
|
const pkg = require2("../package.json");
|
|
27829
27851
|
return pkg.version ?? "0.0.0-unknown";
|