mock-refine-llm.mjs 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import http from "node:http"
  2. const HOST = "127.0.0.1"
  3. const PORT = 18080
  4. const payload = JSON.stringify({
  5. chapterOutlines: [
  6. "## 第一卷章节细纲",
  7. "- 第1章:主角在青石镇觉醒异常感知,埋下第一条失踪案伏笔。",
  8. "- 第2章:主角与巡检司冲突后达成合作,确立短期目标。",
  9. "- 第3章:第一名关键配角登场,并暴露与旧案相关的隐秘身份。",
  10. ].join("\n"),
  11. characterBriefs: [
  12. "## 主要人物",
  13. "- 林砚:外冷内执,核心动机是查清父亲失踪真相。",
  14. "- 沈知微:巡检司文书,擅长情报归纳,立场在制度与真相之间摇摆。",
  15. ].join("\n"),
  16. organizationsOutline: [
  17. "## 组织与势力",
  18. "- 巡检司:维护城镇秩序,但内部派系分裂明显。",
  19. "- 夜潮会:黑市网络,掌握失踪案的关键流向信息。",
  20. ].join("\n"),
  21. powerSystem: [
  22. "## 能力体系",
  23. "- 感知系:可读取残留情绪,代价是短时记忆紊乱。",
  24. "- 约束规则:每次能力使用后需通过静息法恢复,否则出现误判。",
  25. ].join("\n"),
  26. foreshadowingPlan: [
  27. "## 伏笔计划",
  28. "- 伏笔A:失踪名单里重复出现同一姓氏,第三卷回收其家族线。",
  29. "- 伏笔B:夜潮会账本缺页,第二卷末揭示被巡检司高层调包。",
  30. ].join("\n"),
  31. locationsOutline: [
  32. "## 地点设定",
  33. "- 青石镇旧码头:夜间交易核心区域,线索密集但风险高。",
  34. "- 北岭废驿站:旧案现场之一,关联主角童年记忆。",
  35. ].join("\n"),
  36. })
  37. function writeSseChunk(res, text) {
  38. const body = JSON.stringify({
  39. id: "mock-chatcmpl-1",
  40. object: "chat.completion.chunk",
  41. created: Math.floor(Date.now() / 1000),
  42. model: "mock-refine-model",
  43. choices: [{ index: 0, delta: { content: text }, finish_reason: null }],
  44. })
  45. res.write(`data: ${body}\n\n`)
  46. }
  47. function streamPayload(res, text) {
  48. const chunkSize = 60
  49. for (let i = 0; i < text.length; i += chunkSize) {
  50. writeSseChunk(res, text.slice(i, i + chunkSize))
  51. }
  52. res.write("data: [DONE]\n\n")
  53. res.end()
  54. }
  55. const server = http.createServer((req, res) => {
  56. if (req.method !== "POST" || req.url !== "/chat/completions") {
  57. res.statusCode = 404
  58. res.setHeader("content-type", "application/json; charset=utf-8")
  59. res.end(JSON.stringify({ error: "not found" }))
  60. return
  61. }
  62. const chunks = []
  63. req.on("data", (chunk) => chunks.push(chunk))
  64. req.on("end", () => {
  65. res.statusCode = 200
  66. res.setHeader("content-type", "text/event-stream; charset=utf-8")
  67. res.setHeader("cache-control", "no-cache")
  68. res.setHeader("connection", "keep-alive")
  69. streamPayload(res, payload)
  70. })
  71. })
  72. server.listen(PORT, HOST, () => {
  73. console.log(`mock refine llm server listening on http://${HOST}:${PORT}`)
  74. })
  75. process.on("SIGINT", () => {
  76. server.close(() => process.exit(0))
  77. })