Mercurial Hosting > lang
changeset 9:46097e607701
romaji
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Mon, 21 Jul 2025 15:16:47 -0600 |
parents | 2b7dcf355a78 |
children | b0b325565d30 |
files | src/chat.css src/chat.html.luan src/chat.js src/lib/Chat.luan src/lib/Shared.luan src/lib/Utils.luan src/lib/ai/claude/Chat.luan src/lib/ai/claude/Claude.luan src/private/tools/chat.html.luan src/site.css src/site.js |
diffstat | 11 files changed, 102 insertions(+), 24 deletions(-) [+] |
line wrap: on
line diff
--- a/src/chat.css Fri Jul 18 23:46:48 2025 -0600 +++ b/src/chat.css Mon Jul 21 15:16:47 2025 -0600 @@ -36,3 +36,7 @@ dialog[rename] input { width: 300px; } + +div[system_prompt] { + white-space-collapse: preserve; +}
--- a/src/chat.html.luan Fri Jul 18 23:46:48 2025 -0600 +++ b/src/chat.html.luan Mon Jul 21 15:16:47 2025 -0600 @@ -41,7 +41,6 @@ <script> let chatId = <%= chat.id %>; </script> - <script src="https://cdn.jsdelivr.net/npm/markdown-it@14.1.0/dist/markdown-it.min.js"></script> <script src="/chat.js?s=<%=started%>"></script> </head> <body> @@ -54,6 +53,7 @@ <div> <span onclick="renameChat()">Rename Chat</span> <span onclick="deleteChat()">Delete Chat</span> + <span onclick="systemPrompt()">System Prompt</span> </div> </span> </div> @@ -88,6 +88,15 @@ <button onclick="doDeleteChat(this)">Delete</button> </div> </dialog> + <dialog system_prompt> + <h2>System Prompt</h2> + <div system_prompt> +<% chat.output_system_prompt() %> + </div> + <div buttons> + <button onclick="closeModal(this)">Close</button> + </div> + </dialog> <script> handleMarkdown(); </script>
--- a/src/chat.js Fri Jul 18 23:46:48 2025 -0600 +++ b/src/chat.js Mon Jul 21 15:16:47 2025 -0600 @@ -27,6 +27,11 @@ ajax(`delete_chat.js?chat=${chatId}`); } +function systemPrompt() { + let dialog = document.querySelector('dialog[system_prompt]'); + dialog.showModal(); +} + function showWaitingAiIcon() { document.querySelector('[waiting-ai-icon]').style.display = 'block'; } @@ -35,15 +40,6 @@ document.querySelector('[waiting-ai-icon]').style.display = 'none'; } -// requires markdown-it -function handleMarkdown() { - let converter = window.markdownit(); - let divs = document.querySelectorAll('[role]'); - for( let div of divs ) { - div.innerHTML = converter.render(div.textContent); - } -} - function updateAi(html) { hideWaitingAiIcon(); document.querySelector('div[messages]').innerHTML = html;
--- a/src/lib/Chat.luan Fri Jul 18 23:46:48 2025 -0600 +++ b/src/lib/Chat.luan Mon Jul 21 15:16:47 2025 -0600 @@ -61,6 +61,10 @@ 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.ai_thread) end
--- a/src/lib/Shared.luan Fri Jul 18 23:46:48 2025 -0600 +++ b/src/lib/Shared.luan Mon Jul 21 15:16:47 2025 -0600 @@ -21,6 +21,7 @@ <style> @import "/site.css?s=<%=started%>"; </style> + <script src="https://cdn.jsdelivr.net/npm/markdown-it@14.1.0/dist/markdown-it.min.js"></script> <script src="/site.js?s=<%=started%>"></script> <% end
--- a/src/lib/Utils.luan Fri Jul 18 23:46:48 2025 -0600 +++ b/src/lib/Utils.luan Mon Jul 21 15:16:47 2025 -0600 @@ -1,5 +1,6 @@ local Luan = require "luan:Luan.luan" local error = Luan.error +local pairs = Luan.pairs or error() local Http = require "luan:http/Http.luan" @@ -10,4 +11,12 @@ return request.scheme.."://"..request.headers["Host"] end +function Utils.shallow_copy(t) + local rtn = {} + for key, val in pairs(t) do + rtn[key] = val + end + return rtn +end + return Utils
--- a/src/lib/ai/claude/Chat.luan Fri Jul 18 23:46:48 2025 -0600 +++ b/src/lib/ai/claude/Chat.luan Mon Jul 21 15:16:47 2025 -0600 @@ -18,8 +18,22 @@ local Chat = {} +function Chat.output_system_prompt(thread) + if thread == nil then + return + end + thread = json_parse(thread) + local system_prompt = thread.system or error + system_prompt = html_encode(system_prompt) + %><%=system_prompt%><% +end + function Chat.output_messages_html(thread) - local messages = thread and json_parse(thread) or {nil} + if thread == nil then + return + end + thread = json_parse(thread) + local messages = thread.messages or error for _, message in ipairs(messages) do local role = message.role or error() local who @@ -31,9 +45,10 @@ error(role) end local function output(text) + text = html_encode(text) %> <h3><%=who%></h3> - <div role="<%=role%>"><%=html_encode(text)%></div> + <div markdown role="<%=role%>"><%=text%></div> <% end local content = message.content or error() @@ -50,8 +65,30 @@ end_for end + +local system_prompt = [[ +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 Chat.ask(thread,input) - local messages = thread and json_parse(thread) or {nil} + thread = thread and json_parse(thread) or { + system = system_prompt + messages = {nil} + } + local messages = thread.messages or error messages[#messages+1] = { role = "user" content = input @@ -74,12 +111,10 @@ Thread.sleep(5000) } if true then - return json_string(messages) + return json_string(thread) end --]=] - local resultJson = claude_chat{ - messages = messages - } + local resultJson = claude_chat(thread) local result = json_parse(resultJson) -- logger.info(json_string(result)) result.type == "message" or error() @@ -90,7 +125,7 @@ role = "assistant" content = content } - return json_string(messages) + return json_string(thread) end return Chat
--- a/src/lib/ai/claude/Claude.luan Fri Jul 18 23:46:48 2025 -0600 +++ b/src/lib/ai/claude/Claude.luan Mon Jul 21 15:16:47 2025 -0600 @@ -5,6 +5,8 @@ local Parsers = require "luan:Parsers.luan" local json_string = Parsers.json_string or error() local Config = require "site:/private/Config.luan" +local Utils = require "site:/lib/Utils.luan" +local shallow_copy = Utils.shallow_copy or error() local Logging = require "luan:logging/Logging.luan" local logger = Logging.logger "claude/Claude" @@ -21,6 +23,7 @@ local max_tokens = 8192 function Claude.chat(content) + content = shallow_copy(content) content.model = content.model or model content.max_tokens = content.max_tokens or max_tokens local options = {
--- a/src/private/tools/chat.html.luan Fri Jul 18 23:46:48 2025 -0600 +++ b/src/private/tools/chat.html.luan Mon Jul 21 15:16:47 2025 -0600 @@ -21,18 +21,14 @@ <head> <% head() %> <style> - @import "/chat.css?s=<%=started%>"; - <% if not process_markdown then %> - [ai_container] [role] { + [markdown] { white-space-collapse: preserve; } <% end %> </style> - <script src="https://cdn.jsdelivr.net/npm/markdown-it@14.1.0/dist/markdown-it.min.js"></script> - <script src="/chat.js?s=<%=started%>"></script> </head> - <body ai_container> + <body> <% header() %> <div content> <h1>Chat <%=chat_id%></h1>
--- a/src/site.css Fri Jul 18 23:46:48 2025 -0600 +++ b/src/site.css Mon Jul 21 15:16:47 2025 -0600 @@ -78,3 +78,12 @@ color: #ffffff; background-color: #428bca; } + +ruby rt { + user-select: none; +} + +pre, +code { + text-wrap: wrap; +}
--- a/src/site.js Fri Jul 18 23:46:48 2025 -0600 +++ b/src/site.js Mon Jul 21 15:16:47 2025 -0600 @@ -119,3 +119,15 @@ window.scrollTo( 0, lastY ); } +// requires markdown-it +function handleMarkdown() { + let converter = window.markdownit({html: true}); + let divs = document.querySelectorAll('[markdown]'); + for( let div of divs ) { + let text = div.textContent; + text = text.replace(/\{([^|}]+)\|([^|}]+)\}/g, '<ruby>$1<rt>$2</rt></ruby>'); + text = converter.render(text); + div.innerHTML = text; + div.removeAttribute('markdown'); + } +}