diff --git a/apps/api/data/channel-state.json b/apps/api/data/channel-state.json index 24adda7..7b620ed 100644 --- a/apps/api/data/channel-state.json +++ b/apps/api/data/channel-state.json @@ -1,5 +1,5 @@ { "topics": {}, "pins": {}, - "savedAt": "2026-03-21T22:17:08.574Z" + "savedAt": "2026-03-21T22:22:08.578Z" } \ No newline at end of file diff --git a/apps/api/data/persona-memory/Pharmacius.json b/apps/api/data/persona-memory/Pharmacius.json index 1eeffbf..0809aa4 100644 --- a/apps/api/data/persona-memory/Pharmacius.json +++ b/apps/api/data/persona-memory/Pharmacius.json @@ -2,5 +2,5 @@ "nick": "Pharmacius", "facts": [], "summary": "", - "lastUpdated": "2026-03-21T22:20:02.284Z" + "lastUpdated": "2026-03-21T22:23:01.597Z" } \ No newline at end of file diff --git a/apps/api/src/ws-commands-chat.ts b/apps/api/src/ws-commands-chat.ts index ff8a318..66f4771 100644 --- a/apps/api/src/ws-commands-chat.ts +++ b/apps/api/src/ws-commands-chat.ts @@ -23,6 +23,7 @@ export const CHAT_COMMANDS = new Set([ "/haiku", "/timer", "/story", + "/speak", ]); export function createChatCommandHandler(deps: CommandHandlerDeps) { @@ -821,6 +822,19 @@ export function createChatCommandHandler(deps: CommandHandlerDeps) { return; } + case "/speak": { + // /speak — force TTS for text as persona + const speakMatch = text.match(/^\/speak\s+(\S+)\s+(.+)$/); + if (!speakMatch) { send(ws, { type: "system", text: "Usage: /speak " }); return; } + const [, speakNick, speakText] = speakMatch; + const persona = getPersonas().find(p => p.nick.toLowerCase() === speakNick.toLowerCase()); + if (!persona) { send(ws, { type: "system", text: `Persona "${speakNick}" inconnue.` }); return; } + + const { synthesizeTTS } = await import("./ws-multimodal.js"); + await synthesizeTTS(persona.nick, speakText, info.channel, broadcast); + return; + } + default: send(ws, { type: "system", text: `Commande inconnue: ${cmd}. Tape /help.` }); } diff --git a/apps/api/src/ws-commands-generate.ts b/apps/api/src/ws-commands-generate.ts index 744f8f7..3bfd550 100644 --- a/apps/api/src/ws-commands-generate.ts +++ b/apps/api/src/ws-commands-generate.ts @@ -30,6 +30,7 @@ export const GENERATE_COMMANDS = new Set([ "/drone", "/grain", "/circus", "/honk", "/kokoro", "/variations", "/imagine-queue", + "/upscale", ]); export function createGenerateCommandHandler(deps: CommandHandlerDeps) { @@ -1547,6 +1548,12 @@ export function createGenerateCommandHandler(deps: CommandHandlerDeps) { return; } + case "/upscale": { + // /upscale — upscale last generated image 2x (placeholder, needs ESRGAN model) + send(ws, { type: "system", text: "Upscale non implemente (necessite modele ESRGAN). Utilisez /imagine avec un prompt plus detaille." }); + return; + } + default: send(ws, { type: "system", text: `Commande inconnue: ${cmd}. Tape /help.` }); } diff --git a/apps/api/src/ws-commands-info.ts b/apps/api/src/ws-commands-info.ts index 85f88e4..845e0bf 100644 --- a/apps/api/src/ws-commands-info.ts +++ b/apps/api/src/ws-commands-info.ts @@ -65,6 +65,7 @@ export const INFO_COMMANDS = new Set([ "/about", "/benchmark", "/ping", + "/count", ]); export function createInfoCommandHandler(deps: CommandHandlerDeps) { @@ -618,8 +619,9 @@ export function createInfoCommandHandler(deps: CommandHandlerDeps) { } case "/flip": { - const result = Math.random() < 0.5 ? "pile" : "face"; - broadcast(info.channel, { type: "system", text: `\u{1FA99} ${info.nick}: ${result}!` }); + const result = Math.random() < 0.5 ? "PILE" : "FACE"; + const emoji = result === "PILE" ? "\u{1FA99}" : "\u{1F451}"; + broadcast(info.channel, { type: "system", text: `${emoji} ${info.nick} lance une piece: ${result}!` }); return; } @@ -629,6 +631,25 @@ export function createInfoCommandHandler(deps: CommandHandlerDeps) { return; } + case "/count": { + const fs = await import("node:fs"); + const countFiles = (dir: string) => { + try { return fs.readdirSync(path.join(process.cwd(), "data", dir)).filter((f: string) => !f.startsWith(".")).length; } catch { return 0; } + }; + const lines = [ + "=== COMPTEURS ===", + ` Personas: ${getPersonas().length}`, + ` Images: ${countFiles("media/images")}`, + ` Audio: ${countFiles("media/audio")}`, + ` Samples DAW: ${countFiles("daw-samples")}`, + ` Compositions: ${countFiles("compositions")}`, + ` Exports: ${countFiles("exports")}`, + ` Feedback: ${countFiles("feedback")}`, + ]; + send(ws, { type: "system", text: lines.join("\n") }); + return; + } + case "/uptime": { const secs = Math.floor(process.uptime()); const h = Math.floor(secs / 3600); diff --git a/apps/web/src/components/AdminPage.tsx b/apps/web/src/components/AdminPage.tsx index cdf4aa6..7148d88 100644 --- a/apps/web/src/components/AdminPage.tsx +++ b/apps/web/src/components/AdminPage.tsx @@ -61,7 +61,7 @@ function ServiceHealth() { className={`admin-health-card ${s.ok ? "admin-health-ok" : "admin-health-fail"}`} >
{name.toUpperCase()}
-
{s.ok ? "\u25CF" : "\u25CB"}
+
{s.ok ? "\u{1F7E2}" : "\u{1F534}"}
{s.detail &&
{s.detail}
} ))}