Mercurial Hosting > lang
changeset 25:3a80ddafe5a4
courses work
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Fri, 01 Aug 2025 00:33:51 -0600 |
parents | 87fe70201aa8 |
children | d3f5448743bf |
files | src/chat.html.luan src/chat.js src/edit_course.html.luan src/lib/Chat.luan src/lib/Course.luan src/lib/ai/Ai.luan src/lib/ai/claude/Ai_chat.luan src/save_course.js.luan |
diffstat | 8 files changed, 93 insertions(+), 70 deletions(-) [+] |
line wrap: on
line diff
diff -r 87fe70201aa8 -r 3a80ddafe5a4 src/chat.html.luan --- a/src/chat.html.luan Thu Jul 31 22:30:26 2025 -0600 +++ b/src/chat.html.luan Fri Aug 01 00:33:51 2025 -0600 @@ -17,6 +17,7 @@ if user == nil then return end local chat_id = Http.request.parameters.chat or error() local chat = get_chat_by_id(chat_id) or error() + local added_message = chat.init_ai() Io.stdout = Http.response.text_writer() %> <!doctype html> @@ -90,6 +91,9 @@ </dialog> <script> handleMarkdown(); +<% if added_message then %> + playLastMessage(); +<% end %> </script> </body> </html>
diff -r 87fe70201aa8 -r 3a80ddafe5a4 src/chat.js --- a/src/chat.js Thu Jul 31 22:30:26 2025 -0600 +++ b/src/chat.js Fri Aug 01 00:33:51 2025 -0600 @@ -40,6 +40,14 @@ document.querySelector('[waiting-ai-icon]').style.display = 'none'; } +function playLastMessage() { + let audios = document.querySelectorAll('audio'); + if( audios.length >= 1 ) { + let audio = audios[audios.length-1]; + audio.play(); + } +} + function updateAi(html) { hideWaitingAiIcon(); document.querySelector('div[messages]').insertAdjacentHTML('beforeend',html); @@ -52,11 +60,7 @@ scroll.scrollTo(0,scroll.scrollHeight); }); */ - let audios = document.querySelectorAll('audio'); - if( audios.length >= 1 ) { - let audio = audios[audios.length-1]; - audio.play(); - } + playLastMessage(); } const isMobile = 'ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0;
diff -r 87fe70201aa8 -r 3a80ddafe5a4 src/edit_course.html.luan --- a/src/edit_course.html.luan Thu Jul 31 22:30:26 2025 -0600 +++ b/src/edit_course.html.luan Fri Aug 01 00:33:51 2025 -0600 @@ -35,35 +35,39 @@ <head> <% head() %> <style> - label, input, textarea { display: block; } + h4 { + margin-top: 22px; + margin-bottom: 4px; + } + input[type=submit] { + margin-top: 22px; + } </style> </head> <body> <% header() %> <form content onsubmit="ajaxForm('/save_course.js',this)" action="javascript:"> - <h1>Edit Course</h1> - <p> - Language: <%= course.language_name() %> - <input type=hidden name=language value="<%=course.language%>"> + <input type=hidden name=language value="<%=course.language%>"> <% if course_id ~= nil then %> - <input type=hidden name=course value="<%=course_id%>"> + <input type=hidden name=course value="<%=course_id%>"> <% end %> - </p> - <p> - <label prompt>Course name</label> - <input required name=name value="<%=html_encode(course.name)%>"> - </p> - <p> - <label prompt>AI system prompt</label> - <textarea required name=ai_system_prompt><%=html_encode(course.ai_system_prompt)%></textarea> - </p> - <p> - <input type=submit> - </p> + <h1>Edit Course</h1> + <h3><%= course.language_name() %></h3> + + <h4>Course name</h4> + <input required name=name value="<%=html_encode(course.name)%>"> + + <h4>AI system prompt</h4> + <textarea required name=ai_system_prompt><%=html_encode(course.ai_system_prompt)%></textarea> + + <h4>AI first message (optional)</h4> + <textarea required name=ai_first_message><%=html_encode(course.ai_first_message or "")%></textarea> + + <input type=submit> </form> </body> </html>
diff -r 87fe70201aa8 -r 3a80ddafe5a4 src/lib/Chat.luan --- a/src/lib/Chat.luan Thu Jul 31 22:30:26 2025 -0600 +++ b/src/lib/Chat.luan Fri Aug 01 00:33:51 2025 -0600 @@ -9,10 +9,12 @@ local html_encode = Html.encode or error() local Db = require "site:/lib/Db.luan" local run_in_transaction = Db.run_in_transaction or error() -local Ai = require "site:/lib/ai/Ai.luan" +local Ai_chat = require "site:/lib/ai/claude/Ai_chat.luan" local languages = require "site:/lib/languages.luan" local Utils = require "site:/lib/Utils.luan" local get_first = Utils.get_first or error() +local Course = require "site:/lib/Course.luan" +local get_course_by_id = Course.get_by_id or error() local Chat = {} @@ -25,7 +27,6 @@ updated = doc.chat_updated course_id = doc.course_id name = doc.name - ai_name = doc.ai_name ai_thread = doc.ai_thread language = doc.language language_region = doc.language_region @@ -40,8 +41,7 @@ chat_updated = long(chat.updated) course_id = long(chat.course_id) name = chat.name or error() - ai_name = chat.ai_name or error() - ai_thread = chat.ai_thread -- or error() + ai_thread = chat.ai_thread language = chat.language or error() language_region = chat.language_region or error() } @@ -53,8 +53,6 @@ function Chat.new(chat) chat.updated = chat.updated or time_now() - chat.ai_name = chat.ai_name or "claude" - chat.ai = Ai[chat.ai_name]["Ai_chat.luan"] or error() chat.language_region = chat.language_region or first_region(chat.language) function chat.save() @@ -75,23 +73,38 @@ return html_encode(chat.name) end - function chat.output_system_prompt() - chat.ai.output_system_prompt(chat.ai_thread) - end - - function chat.output_messages_html() - chat.ai.output_messages_html(chat.language_region,chat.ai_thread) - end - - function chat.ask(input) - local old_thread = chat.ai_thread - local ai_thread = chat.ai.ask(old_thread,input) + function chat.init_ai() -- return if added message + if chat.ai_thread ~= nil then + return false + end + local course = get_course_by_id(chat.course_id) or error() + local ai_first_message = course.ai_first_message + local ai_thread = Ai_chat.ask_first(course.ai_system_prompt,ai_first_message) run_in_transaction( function() chat = chat.reload() chat.ai_thread = ai_thread chat.save() end ) - return `chat.ai.output_messages_html(chat.language_region,ai_thread,old_thread)` + return ai_first_message ~= nil + end + + function chat.output_system_prompt() + Ai_chat.output_system_prompt(chat.ai_thread) + end + + function chat.output_messages_html() + Ai_chat.output_messages_html(chat.language_region,chat.ai_thread) + end + + function chat.ask(input) + local old_thread = chat.ai_thread + local ai_thread = Ai_chat.ask_more(old_thread,input) + run_in_transaction( function() + chat = chat.reload() + chat.ai_thread = ai_thread + chat.save() + end ) + return `Ai_chat.output_messages_html(chat.language_region,ai_thread,old_thread)` end function chat.language_name()
diff -r 87fe70201aa8 -r 3a80ddafe5a4 src/lib/Course.luan --- a/src/lib/Course.luan Thu Jul 31 22:30:26 2025 -0600 +++ b/src/lib/Course.luan Fri Aug 01 00:33:51 2025 -0600 @@ -20,6 +20,7 @@ updated = doc.course_updated name = doc.name ai_system_prompt = doc.ai_system_prompt + ai_first_message = doc.ai_first_message } end @@ -32,6 +33,7 @@ course_updated = long(course.updated) name = course.name or error() ai_system_prompt = course.ai_system_prompt or error() + ai_first_message = course.ai_first_message } end
diff -r 87fe70201aa8 -r 3a80ddafe5a4 src/lib/ai/Ai.luan --- a/src/lib/ai/Ai.luan Thu Jul 31 22:30:26 2025 -0600 +++ b/src/lib/ai/Ai.luan Fri Aug 01 00:33:51 2025 -0600 @@ -3,6 +3,8 @@ local ipairs = Luan.ipairs or error() +error "not used for now" + local Ai = {} local ais = {"claude"}
diff -r 87fe70201aa8 -r 3a80ddafe5a4 src/lib/ai/claude/Ai_chat.luan --- a/src/lib/ai/claude/Ai_chat.luan Thu Jul 31 22:30:26 2025 -0600 +++ b/src/lib/ai/claude/Ai_chat.luan Fri Aug 01 00:33:51 2025 -0600 @@ -74,34 +74,7 @@ end -local system_prompt = [[ -# Your Role - -You are a Japanese language teacher. - -# Romaji - -CRITICAL REQUIREMENT: When writing Japanese, use ruby markdown syntax {japanese|romaji} for pronunciation guidance. - -Apply ruby tags to meaningful pronunciation units: -- Individual kanji or kanji compounds: {私|watashi}, {学生|gakusei} -- Hiragana/katakana words and particles: {は|wa}, {です|desu}, {ありがとう|arigatō} -- Grammatical elements: {ました|mashita}, {ません|masen} - -The romaji must reflect ACTUAL PRONUNCIATION, not character-by-character readings. -Use macrons for long vowels: ā, ī, ū, ē, ō - -APPLIES TO ALL JAPANESE TEXT: Example sentences, grammar explanations, vocabulary lists, casual mentions - ANY Japanese characters in your response need ruby tags. - -VERIFICATION STEP: Before sending, scan your ENTIRE response for any Japanese characters (hiragana, katakana, kanji) and ensure they all have ruby tags. -]] - - -function Ai_chat.ask(thread,input) - thread = thread and json_parse(thread) or { - system = system_prompt - messages = {nil} - } +local function ask(thread,input) local messages = thread.messages or error messages[#messages+1] = { role = "user" @@ -115,7 +88,7 @@ ]] } if true then - return json_string(thread) + return end --]=] -- logger.info(json_string(thread)) @@ -130,6 +103,22 @@ role = "assistant" content = content } +end + +function Ai_chat.ask_first(system_prompt,input) + local thread = { + system = system_prompt + messages = {nil} + } + if input ~= nil then + ask(thread,input) + end + return json_string(thread) +end + +function Ai_chat.ask_more(thread,input) + thread = json_parse(thread) + ask(thread,input) return json_string(thread) end
diff -r 87fe70201aa8 -r 3a80ddafe5a4 src/save_course.js.luan --- a/src/save_course.js.luan Thu Jul 31 22:30:26 2025 -0600 +++ b/src/save_course.js.luan Fri Aug 01 00:33:51 2025 -0600 @@ -1,5 +1,7 @@ local Luan = require "luan:Luan.luan" local error = Luan.error +local String = require "luan:String.luan" +local trim = String.trim or error() local Time = require "luan:Time.luan" local time_now = Time.now or error() local Io = require "luan:Io.luan" @@ -29,6 +31,9 @@ end course.name = parameters.name or error() course.ai_system_prompt = parameters.ai_system_prompt or error() + local ai_first_message = parameters.ai_first_message or error() + ai_first_message = trim(ai_first_message) + course.ai_first_message = ai_first_message~="" and ai_first_message or nil course.updated = time_now() course.save() end )