80 lines
2.5 KiB
JavaScript
80 lines
2.5 KiB
JavaScript
|
|
/*
|
||
|
|
* /api/conversations
|
||
|
|
* 守护: 铸渊 · ICE-GL-ZY001
|
||
|
|
*
|
||
|
|
* GET / → 列表 (按 updated_at desc)
|
||
|
|
* POST / → 新建对话, 返回 {id, ...}
|
||
|
|
* GET /:id/messages → 单对话 + 历史
|
||
|
|
*/
|
||
|
|
"use strict";
|
||
|
|
|
||
|
|
const express = require("express");
|
||
|
|
const crypto = require("crypto");
|
||
|
|
|
||
|
|
const router = express.Router();
|
||
|
|
|
||
|
|
function genConvId() {
|
||
|
|
return "conv_" + crypto.randomBytes(8).toString("hex");
|
||
|
|
}
|
||
|
|
|
||
|
|
function isValidId(id) {
|
||
|
|
return typeof id === "string" && /^conv_[0-9a-f]{16}$/.test(id);
|
||
|
|
}
|
||
|
|
|
||
|
|
router.get("/", (req, res) => {
|
||
|
|
const rows = req.ctx.db
|
||
|
|
.prepare("SELECT id, title, active_model, created_at, updated_at FROM conversations ORDER BY updated_at DESC LIMIT 200")
|
||
|
|
.all();
|
||
|
|
res.json({ items: rows.map((r) => ({ ...r, created_at: new Date(r.created_at).toISOString(), updated_at: new Date(r.updated_at).toISOString() })) });
|
||
|
|
});
|
||
|
|
|
||
|
|
router.post("/", (req, res) => {
|
||
|
|
const body = req.body || {};
|
||
|
|
let active = body.active_model;
|
||
|
|
if (active !== "mother" && active !== "coder") active = "mother";
|
||
|
|
let title = typeof body.title === "string" ? body.title.trim().slice(0, 64) : "";
|
||
|
|
if (!title) title = "(新对话)";
|
||
|
|
const id = genConvId();
|
||
|
|
const now = Date.now();
|
||
|
|
req.ctx.db
|
||
|
|
.prepare(
|
||
|
|
"INSERT INTO conversations (id, title, active_model, created_at, updated_at) VALUES (?, ?, ?, ?, ?)"
|
||
|
|
)
|
||
|
|
.run(id, title, active, now, now);
|
||
|
|
res.status(201).json({
|
||
|
|
id,
|
||
|
|
title,
|
||
|
|
active_model: active,
|
||
|
|
created_at: new Date(now).toISOString(),
|
||
|
|
updated_at: new Date(now).toISOString()
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
router.get("/:id/messages", (req, res) => {
|
||
|
|
const id = req.params.id;
|
||
|
|
if (!isValidId(id)) {
|
||
|
|
return res.status(400).json({ error: true, code: "bad_id", message: "对话 id 格式不合法" });
|
||
|
|
}
|
||
|
|
const conv = req.ctx.db
|
||
|
|
.prepare("SELECT id, title, active_model, created_at, updated_at FROM conversations WHERE id = ?")
|
||
|
|
.get(id);
|
||
|
|
if (!conv) {
|
||
|
|
return res.status(404).json({ error: true, code: "not_found", message: "对话不存在: " + id });
|
||
|
|
}
|
||
|
|
const rows = req.ctx.db
|
||
|
|
.prepare("SELECT id, role, content, ts FROM messages WHERE conv_id = ? ORDER BY ts ASC, id ASC LIMIT 1000")
|
||
|
|
.all(id);
|
||
|
|
res.json({
|
||
|
|
conversation: {
|
||
|
|
...conv,
|
||
|
|
created_at: new Date(conv.created_at).toISOString(),
|
||
|
|
updated_at: new Date(conv.updated_at).toISOString()
|
||
|
|
},
|
||
|
|
items: rows.map((r) => ({ ...r, ts: new Date(r.ts).toISOString() }))
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
module.exports = router;
|
||
|
|
module.exports.isValidId = isValidId;
|
||
|
|
module.exports.genConvId = genConvId;
|