chat.mjs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import * as readline from 'node:readline'
  2. import { stdin, stdout } from 'node:process'
  3. import { readFileSync } from 'node:fs'
  4. import { SchemaConverter } from './public/json-schema-to-grammar.mjs'
  5. const args = process.argv.slice(2);
  6. const grammarJsonSchemaFile = args.find(
  7. (_, index) => args[index - 1] === "--grammar-json-schema"
  8. );
  9. const no_cached_prompt = args.find(
  10. (_, index) => args[index - 1] === "--no-cache-prompt"
  11. ) ?? "false";
  12. const grammarFile = args.find((_, index) => args[index - 1] === "--grammar");
  13. // Example usage: function,arguments
  14. const grammarJsonSchemaPropOrder = args.find(
  15. (_, index) => args[index - 1] === "--grammar-json-schema-prop-order"
  16. );
  17. const propOrder = grammarJsonSchemaPropOrder
  18. ? grammarJsonSchemaPropOrder
  19. .split(",")
  20. .reduce((acc, cur, index) => ({ ...acc, [cur]: index }), {})
  21. : {};
  22. let grammar = null
  23. if (grammarJsonSchemaFile) {
  24. const schema = JSON.parse(readFileSync(grammarJsonSchemaFile, 'utf-8'))
  25. const converter = new SchemaConverter(propOrder)
  26. converter.visit(schema, '')
  27. grammar = converter.formatGrammar()
  28. }
  29. if (grammarFile) {
  30. grammar = readFileSync(grammarFile, 'utf-8')
  31. }
  32. // for cached prompt
  33. let slot_id = -1;
  34. const API_URL = 'http://127.0.0.1:8080'
  35. const chat = [
  36. {
  37. human: "Hello, Assistant.",
  38. assistant: "Hello. How may I help you today?"
  39. },
  40. {
  41. human: "Please tell me the largest city in Europe.",
  42. assistant: "Sure. The largest city in Europe is Moscow, the capital of Russia."
  43. },
  44. ]
  45. const instruction = `A chat between a curious human and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the human's questions.`
  46. function format_prompt(question) {
  47. return `${instruction}\n${
  48. chat.map(m =>`### Human: ${m.human}\n### Assistant: ${m.assistant}`).join("\n")
  49. }\n### Human: ${question}\n### Assistant:`
  50. }
  51. async function tokenize(content) {
  52. const result = await fetch(`${API_URL}/tokenize`, {
  53. method: 'POST',
  54. body: JSON.stringify({ content })
  55. })
  56. if (!result.ok) {
  57. return []
  58. }
  59. return await result.json().tokens
  60. }
  61. const n_keep = await tokenize(instruction).length
  62. async function chat_completion(question) {
  63. const result = await fetch(`${API_URL}/completion`, {
  64. method: 'POST',
  65. body: JSON.stringify({
  66. prompt: format_prompt(question),
  67. temperature: 0.2,
  68. top_k: 40,
  69. top_p: 0.9,
  70. n_keep: n_keep,
  71. n_predict: 256,
  72. cache_prompt: no_cached_prompt === "false",
  73. slot_id: slot_id,
  74. stop: ["\n### Human:"], // stop completion after generating this
  75. grammar,
  76. stream: true,
  77. })
  78. })
  79. if (!result.ok) {
  80. return
  81. }
  82. let answer = ''
  83. for await (var chunk of result.body) {
  84. const t = Buffer.from(chunk).toString('utf8')
  85. if (t.startsWith('data: ')) {
  86. const message = JSON.parse(t.substring(6))
  87. slot_id = message.slot_id
  88. answer += message.content
  89. process.stdout.write(message.content)
  90. if (message.stop) {
  91. if (message.truncated) {
  92. chat.shift()
  93. }
  94. break
  95. }
  96. }
  97. }
  98. process.stdout.write('\n')
  99. chat.push({ human: question, assistant: answer.trimStart() })
  100. }
  101. const rl = readline.createInterface({ input: stdin, output: stdout });
  102. const readlineQuestion = (rl, query, options) => new Promise((resolve, reject) => {
  103. rl.question(query, options, resolve)
  104. });
  105. while(true) {
  106. const question = await readlineQuestion(rl, '> ')
  107. await chat_completion(question)
  108. }