comparison src/lib/ai/claude/Ai_chat.luan @ 19:0351b3d474f8

minor
author Franklin Schmidt <fschmidt@gmail.com>
date Wed, 30 Jul 2025 15:28:09 -0600
parents src/lib/ai/claude/Chat.luan@f5425a3c1898
children 27989d63fc71
comparison
equal deleted inserted replaced
18:820136c5ee33 19:0351b3d474f8
1 local Luan = require "luan:Luan.luan"
2 local error = Luan.error
3 local ipairs = Luan.ipairs or error()
4 local type = Luan.type or error()
5 local String = require "luan:String.luan"
6 local starts_with = String.starts_with or error()
7 local Html = require "luan:Html.luan"
8 local html_encode = Html.encode or error()
9 local Parsers = require "luan:Parsers.luan"
10 local json_parse = Parsers.json_parse or error()
11 local json_string = Parsers.json_string or error()
12 local Claude = require "site:/lib/ai/claude/Claude.luan"
13 local claude_chat = Claude.chat or error()
14 local Logging = require "luan:logging/Logging.luan"
15 local logger = Logging.logger "claude/Ai_chat"
16
17
18 local Ai_chat = {}
19
20 function Ai_chat.output_system_prompt(thread)
21 if thread == nil then
22 return
23 end
24 thread = json_parse(thread)
25 local system_prompt = thread.system or error
26 system_prompt = html_encode(system_prompt)
27 %><%=system_prompt%><%
28 end
29
30 function Ai_chat.output_messages_html(lang,thread,old_thread)
31 if thread == nil then
32 return
33 end
34 thread = json_parse(thread)
35 local messages = thread.messages or error
36 local n = 0
37 if old_thread ~= nil then
38 old_thread = json_parse(old_thread)
39 local old_messages = old_thread.messages or error
40 n = #old_messages
41 end
42 for i, message in ipairs(messages) do
43 if i <= n then
44 continue
45 end
46 local role = message.role or error()
47 local who
48 if role=="assistant" then
49 who = "Claude"
50 elseif role=="user" then
51 who = "You"
52 else
53 error(role)
54 end
55 local function output(text)
56 text = html_encode(text)
57 %>
58 <h3><%=who%></h3>
59 <div markdown role="<%=role%>" lang="<%=lang%>"><%=text%></div>
60 <%
61 end
62 local content = message.content or error()
63 if type(content) == "string" then
64 output(content)
65 else
66 for _, part in ipairs(content) do
67 if part.type=="text" then
68 local text = part.text or error()
69 output(text)
70 end
71 end
72 end
73 end_for
74 end
75
76
77 local system_prompt = [[
78 CRITICAL REQUIREMENT: When writing Japanese, use ruby markdown syntax {japanese|romaji} for pronunciation guidance.
79
80 Apply ruby tags to meaningful pronunciation units:
81 - Individual kanji or kanji compounds: {私|watashi}, {学生|gakusei}
82 - Hiragana/katakana words and particles: {は|wa}, {です|desu}, {ありがとう|arigatō}
83 - Grammatical elements: {ました|mashita}, {ません|masen}
84
85 The romaji must reflect ACTUAL PRONUNCIATION, not character-by-character readings.
86 Use macrons for long vowels: ā, ī, ū, ē, ō
87
88 APPLIES TO ALL JAPANESE TEXT: Example sentences, grammar explanations, vocabulary lists, casual mentions - ANY Japanese characters in your response need ruby tags.
89
90 VERIFICATION STEP: Before sending, scan your ENTIRE response for any Japanese characters (hiragana, katakana, kanji) and ensure they all have ruby tags.
91 ]]
92
93
94 function Ai_chat.ask(thread,input)
95 thread = thread and json_parse(thread) or {
96 system = system_prompt
97 messages = {nil}
98 }
99 local messages = thread.messages or error
100 messages[#messages+1] = {
101 role = "user"
102 content = input
103 }
104 --[=[
105 messages[#messages+1] = {
106 role = "assistant"
107 content = [[
108 hello
109 ]]
110 }
111 if true then
112 return json_string(thread)
113 end
114 --]=]
115 local resultJson = claude_chat(thread)
116 local result = json_parse(resultJson)
117 -- logger.info(json_string(result))
118 result.type == "message" or error()
119 result.role == "assistant" or error()
120 result.stop_reason == "end_turn" or result.stop_reason == "tool_use" or error()
121 local content = result.content or error()
122 messages[#messages+1] = {
123 role = "assistant"
124 content = content
125 }
126 return json_string(thread)
127 end
128
129 return Ai_chat