mioku-service-webui 4.4.3 → 4.4.5
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/database.ts +42 -0
- package/package.json +1 -1
- package/routes/ai.ts +27 -0
- package/routes/db.ts +5 -5
package/database.ts
CHANGED
|
@@ -5,6 +5,14 @@ import { CHAT_DATA_DIR, readJsonFile, writeJsonFile } from "./utils";
|
|
|
5
5
|
|
|
6
6
|
const DB_PATH = path.join(CHAT_DATA_DIR, "chat.db");
|
|
7
7
|
const SAFE_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
8
|
+
const STICKER_FILE_PATTERN = /\.(png|jpg|jpeg|gif|webp)$/i;
|
|
9
|
+
|
|
10
|
+
export interface StickerCatalogItem {
|
|
11
|
+
id: string;
|
|
12
|
+
character: string;
|
|
13
|
+
label: string;
|
|
14
|
+
url: string;
|
|
15
|
+
}
|
|
8
16
|
|
|
9
17
|
function openDb(): any {
|
|
10
18
|
if (!fs.existsSync(DB_PATH)) {
|
|
@@ -299,6 +307,40 @@ export function listMemeTree(): Record<string, Record<string, string[]>> {
|
|
|
299
307
|
return tree;
|
|
300
308
|
}
|
|
301
309
|
|
|
310
|
+
export function listStickerCatalog(): StickerCatalogItem[] {
|
|
311
|
+
const root = path.join(CHAT_DATA_DIR, "meme");
|
|
312
|
+
if (!fs.existsSync(root)) return [];
|
|
313
|
+
|
|
314
|
+
const items: StickerCatalogItem[] = [];
|
|
315
|
+
const visit = (dir: string, character: string) => {
|
|
316
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
317
|
+
const entryPath = path.join(dir, entry.name);
|
|
318
|
+
if (entry.isDirectory()) {
|
|
319
|
+
visit(entryPath, character);
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
if (!entry.isFile() || !STICKER_FILE_PATTERN.test(entry.name)) continue;
|
|
323
|
+
|
|
324
|
+
const id = path.relative(root, entryPath).split(path.sep).join("/");
|
|
325
|
+
const label = path
|
|
326
|
+
.basename(entry.name, path.extname(entry.name))
|
|
327
|
+
.replace(/[_-]+/g, " ")
|
|
328
|
+
.trim();
|
|
329
|
+
const url = `/meme/${id
|
|
330
|
+
.split("/")
|
|
331
|
+
.map((segment) => encodeURIComponent(segment))
|
|
332
|
+
.join("/")}`;
|
|
333
|
+
items.push({ id, character, label, url });
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
for (const entry of fs.readdirSync(root, { withFileTypes: true })) {
|
|
338
|
+
if (entry.isDirectory()) visit(path.join(root, entry.name), entry.name);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
return items.sort((a, b) => a.id.localeCompare(b.id));
|
|
342
|
+
}
|
|
343
|
+
|
|
302
344
|
export function savePluginConfig(pluginName: string, fileName: string, value: any): void {
|
|
303
345
|
const filePath = path.join(process.cwd(), "config", pluginName, `${fileName}.json`);
|
|
304
346
|
writeJsonFile(filePath, value);
|
package/package.json
CHANGED
package/routes/ai.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
2
|
import { logger } from "mioki";
|
|
3
3
|
import { getChatConfig, updateChatConfig } from "../system";
|
|
4
|
+
import { listStickerCatalog } from "../database";
|
|
4
5
|
import aiService from "mioku-service-ai";
|
|
5
6
|
import type { AIUsageRange } from "mioku-service-ai/usage/types";
|
|
6
7
|
|
|
@@ -96,6 +97,28 @@ function normalizePersonalizationConfig(input: any): any {
|
|
|
96
97
|
delete rawExpression.maxExpressions;
|
|
97
98
|
|
|
98
99
|
data.expression = rawExpression;
|
|
100
|
+
|
|
101
|
+
const rawEmoji =
|
|
102
|
+
data.emoji && typeof data.emoji === "object" && !Array.isArray(data.emoji)
|
|
103
|
+
? { ...data.emoji }
|
|
104
|
+
: {};
|
|
105
|
+
rawEmoji.enabled =
|
|
106
|
+
typeof rawEmoji.enabled === "boolean" ? rawEmoji.enabled : true;
|
|
107
|
+
rawEmoji.characters = Array.isArray(rawEmoji.characters)
|
|
108
|
+
? rawEmoji.characters
|
|
109
|
+
.map(String)
|
|
110
|
+
.map((value: string) => value.trim())
|
|
111
|
+
.filter(Boolean)
|
|
112
|
+
: [];
|
|
113
|
+
rawEmoji.stickers = Array.isArray(rawEmoji.stickers)
|
|
114
|
+
? rawEmoji.stickers
|
|
115
|
+
.map(String)
|
|
116
|
+
.map((value: string) => value.trim())
|
|
117
|
+
.filter(Boolean)
|
|
118
|
+
: [];
|
|
119
|
+
delete rawEmoji.useAISelection;
|
|
120
|
+
data.emoji = rawEmoji;
|
|
121
|
+
|
|
99
122
|
return data;
|
|
100
123
|
}
|
|
101
124
|
|
|
@@ -189,6 +212,10 @@ export function createAIRoutes() {
|
|
|
189
212
|
});
|
|
190
213
|
});
|
|
191
214
|
|
|
215
|
+
app.get("/stickers", (c) =>
|
|
216
|
+
c.json({ ok: true, data: listStickerCatalog() }),
|
|
217
|
+
);
|
|
218
|
+
|
|
192
219
|
app.get("/usage", (c) => {
|
|
193
220
|
if (!aiService?.api?.getUsageSummary) {
|
|
194
221
|
return c.json({ ok: false, error: "AI_USAGE_UNAVAILABLE" }, 503);
|
package/routes/db.ts
CHANGED
|
@@ -306,10 +306,10 @@ export function createServiceConfigRoutes() {
|
|
|
306
306
|
return c.json({ ok: true, data: overview });
|
|
307
307
|
});
|
|
308
308
|
|
|
309
|
-
app.get("/:name/page", (c) => {
|
|
309
|
+
app.get("/:name/page", async (c) => {
|
|
310
310
|
const name = c.req.param("name");
|
|
311
311
|
const manifest = loadServiceConfigPage(name);
|
|
312
|
-
const configs = getServiceConfigs(name);
|
|
312
|
+
const configs = await getServiceConfigs(name);
|
|
313
313
|
|
|
314
314
|
if (!manifest) {
|
|
315
315
|
return c.json({ ok: true, data: null });
|
|
@@ -329,16 +329,16 @@ export function createServiceConfigRoutes() {
|
|
|
329
329
|
});
|
|
330
330
|
});
|
|
331
331
|
|
|
332
|
-
app.get("/:name", (c) => {
|
|
332
|
+
app.get("/:name", async (c) => {
|
|
333
333
|
const name = c.req.param("name");
|
|
334
|
-
return c.json({ ok: true, data: getServiceConfigs(name) });
|
|
334
|
+
return c.json({ ok: true, data: await getServiceConfigs(name) });
|
|
335
335
|
});
|
|
336
336
|
|
|
337
337
|
app.put("/:name/:config", async (c) => {
|
|
338
338
|
const serviceName = c.req.param("name");
|
|
339
339
|
const configName = c.req.param("config");
|
|
340
340
|
const body = await c.req.json();
|
|
341
|
-
updateServiceConfig(serviceName, configName, body);
|
|
341
|
+
await updateServiceConfig(serviceName, configName, body);
|
|
342
342
|
return c.json({ ok: true });
|
|
343
343
|
});
|
|
344
344
|
|