changeset 29:505185272dd7

edit chat
author Franklin Schmidt <fschmidt@gmail.com>
date Sat, 02 Aug 2025 22:39:48 -0600
parents 99b71a377f2c
children d48f48e1b790
files src/chat.html.luan src/chat.js src/lib/Chat.luan src/lib/ai/claude/Ai_chat.luan src/rename_chat.js.luan src/save_chat.js.luan src/save_rename_chat.js.luan src/site.js
diffstat 8 files changed, 74 insertions(+), 80 deletions(-) [+]
line wrap: on
line diff
--- a/src/chat.html.luan	Sat Aug 02 20:04:35 2025 -0600
+++ b/src/chat.html.luan	Sat Aug 02 22:39:48 2025 -0600
@@ -1,5 +1,7 @@
 local Luan = require "luan:Luan.luan"
 local error = Luan.error
+local Parsers = require "luan:Parsers.luan"
+local json_string = Parsers.json_string or error()
 local Io = require "luan:Io.luan"
 local Http = require "luan:http/Http.luan"
 local Shared = require "site:/lib/Shared.luan"
@@ -27,21 +29,17 @@
 		<style>
 			@import "/chat.css?s=<%=started%>";
 		</style>
-		<script>
-			let chatId = <%= chat.id %>;
-			let lang = '<%= chat.language_region %>';
-		</script>
 		<script src="/chat.js?s=<%=started%>"></script>
 	</head>
 	<body>
 <%		header() %>
 		<div content ai_container>
 			<div top>
-				<h3 name><%= chat.name_html() %></h3>
+				<h3 name></h3>
 				<span pulldown>
 					<img onclick="clickMenu(this)" src="/images/menu.svg">
 					<div>
-						<span onclick="renameChat()">Rename Chat</span>
+						<span onclick="editChat()">Edit Chat</span>
 						<span onclick="deleteChat()">Delete Chat</span>
 						<span onclick="systemPrompt()">System Prompt</span>
 					</div>
@@ -60,9 +58,10 @@
 			</div>
 		</div>
 		<img waiting-ai-icon src="/images/spinner_green.gif">
-		<dialog rename>
-			<h2>Rename Chat</h2>
-			<form action="javascript:saveRenameChat()">
+		<dialog edit>
+			<h2>Edit Chat</h2>
+			<form onsubmit="saveChat(this)" action="javascript:">
+				<input type=hidden name=chat value="<%=chat.id%>">
 				<p>
 					<label>Chat name</label><br> 
 					<input name=name required><br>
@@ -70,7 +69,7 @@
 				</p>
 				<div buttons>
 					<button type=button onclick="closeModal(this)">Cancel</button>
-					<button type=submit>Rename</button>
+					<button type=submit>Save</button>
 				</div>
 			</form>
 		</dialog>
@@ -94,7 +93,8 @@
 		</dialog>
 		<input name=initialized style="display:none">
 		<script>
-			handleMarkdown();
+			setChat(<%= json_string(chat.info()) %>);
+			handleChatMarkdown();
 			setTimeout(function(){
 				let initialized = document.querySelector('[name=initialized]');
 				if( !initialized.value ) {
--- a/src/chat.js	Sat Aug 02 20:04:35 2025 -0600
+++ b/src/chat.js	Sat Aug 02 22:39:48 2025 -0600
@@ -1,20 +1,21 @@
 'use strict';
 
-function openRenameChat(name) {
-	let dialog = document.querySelector('dialog[rename]');
-	dialog.querySelector('input[name=name]').value = name;
+let chat;
+
+function setChat(newChat) {
+	chat = newChat;
+	document.querySelector('[content] [name]').textContent = chat.name;
+}
+
+function editChat(name) {
+	let dialog = document.querySelector('dialog[edit]');
+	dialog.querySelector('input[name=name]').value = chat.name;
 	dialog.showModal();
 }
 
-function renameChat() {
-	ajax(`rename_chat.js?chat=${chatId}`);
-}
-
-function saveRenameChat() {
-	let dialog = document.querySelector('dialog[rename]');
-	let name = dialog.querySelector('input[name=name]').value;
-	ajax(`save_rename_chat.js?chat=${chatId}&name=${encodeURIComponent(name)}`);
-	dialog.close();
+function saveChat(form) {
+	closeModal(form);
+	ajaxForm('save_chat.js',form);
 }
 
 function deleteChat() {
@@ -24,7 +25,7 @@
 
 function doDeleteChat(el) {
 	closeModal(el);
-	ajax(`delete_chat.js?chat=${chatId}`);
+	ajax(`delete_chat.js?chat=${chat.id}`);
 }
 
 function systemPrompt() {
@@ -48,6 +49,10 @@
 	}
 }
 
+function handleChatMarkdown() {
+	handleMarkdown(chat.language_region);
+}
+
 function scrollToEnd() {
 	window.scrollTo(0, document.body.scrollHeight);
 }
@@ -55,7 +60,7 @@
 function updateAi(html) {
 	hideWaitingAiIcon();
 	document.querySelector('div[messages]').insertAdjacentHTML('beforeend',html);
-	handleMarkdown();
+	handleChatMarkdown();
 	document.querySelector('textarea').focus();
 	scrollToEnd();
 	playLastMessage();
@@ -78,12 +83,12 @@
 	textarea.parentNode.scrollIntoViewIfNeeded(false);
 	if( !audio )
 		audio = document.querySelector('div[buttons] audio');
-	audio.src = `/tts.mp3?lang=${lang}&text=${encodeURIComponent(textarea.value)}`;
+	audio.src = `/tts.mp3?lang=${chat.language_region}&text=${encodeURIComponent(textarea.value)}`;
 }
 
 function askAi() {
 	let input = document.querySelector('textarea');
-	let url = `ai_ask.js?chat=${chatId}&input=${encodeURIComponent(input.value)}`;
+	let url = `ai_ask.js?chat=${chat.id}&input=${encodeURIComponent(input.value)}`;
 	ajax(url);
 	input.value = '';
 	fixTextarea(input);
--- a/src/lib/Chat.luan	Sat Aug 02 20:04:35 2025 -0600
+++ b/src/lib/Chat.luan	Sat Aug 02 22:39:48 2025 -0600
@@ -69,6 +69,14 @@
 		Db.delete("id:"..chat.id)
 	end
 
+	function chat.info()
+		return {
+			id = chat.id
+			language_region = chat.language_region
+			name = chat.name
+		}
+	end
+
 	function chat.name_html()
 		return html_encode(chat.name)
 	end
@@ -93,7 +101,7 @@
 	end
 
 	function chat.output_messages_html()
-		Ai_chat.output_messages_html(chat.language_region,chat.ai_thread)
+		Ai_chat.output_messages_html(chat.ai_thread)
 	end
 
 	function chat.ask(input)
@@ -104,7 +112,7 @@
 			chat.ai_thread = ai_thread
 			chat.save()
 		end )
-		return `Ai_chat.output_messages_html(chat.language_region,ai_thread,old_thread)`
+		return `Ai_chat.output_messages_html(ai_thread,old_thread)`
 	end
 
 	function chat.language_name()
--- a/src/lib/ai/claude/Ai_chat.luan	Sat Aug 02 20:04:35 2025 -0600
+++ b/src/lib/ai/claude/Ai_chat.luan	Sat Aug 02 22:39:48 2025 -0600
@@ -27,7 +27,7 @@
 	%><%=system_prompt%><%
 end
 
-function Ai_chat.output_messages_html(lang,thread,old_thread)
+function Ai_chat.output_messages_html(thread,old_thread)
 	if thread == nil then
 		return
 	end
@@ -56,7 +56,7 @@
 			text = html_encode(text)
 %>
 			<h3><%=who%></h3>
-			<div markdown role="<%=role%>" lang="<%=lang%>"><%=text%></div>
+			<div markdown role="<%=role%>"><%=text%></div>
 <%
 		end
 		local content = message.content or error()
--- a/src/rename_chat.js.luan	Sat Aug 02 20:04:35 2025 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,18 +0,0 @@
-local Luan = require "luan:Luan.luan"
-local error = Luan.error
-local Parsers = require "luan:Parsers.luan"
-local json_string = Parsers.json_string or error()
-local Io = require "luan:Io.luan"
-local Http = require "luan:http/Http.luan"
-local Chat = require "site:/lib/Chat.luan"
-local get_chat_by_id = Chat.get_by_id or error()
-
-
-return function()
-	local chat = Http.request.parameters.chat or error()
-	chat = get_chat_by_id(chat) or error()
-	Io.stdout = Http.response.text_writer()
-%>
-	openRenameChat(<%=json_string(chat.name)%>);
-<%
-end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/save_chat.js.luan	Sat Aug 02 22:39:48 2025 -0600
@@ -0,0 +1,28 @@
+local Luan = require "luan:Luan.luan"
+local error = Luan.error
+local Parsers = require "luan:Parsers.luan"
+local json_string = Parsers.json_string or error()
+local Io = require "luan:Io.luan"
+local Http = require "luan:http/Http.luan"
+local Chat = require "site:/lib/Chat.luan"
+local get_chat_by_id = Chat.get_by_id or error()
+local User = require "site:/lib/User.luan"
+local current_user = User.current or error()
+local Db = require "site:/lib/Db.luan"
+local run_in_transaction = Db.run_in_transaction or error()
+
+
+return function()
+	local chat = Http.request.parameters.chat or error()
+	local name = Http.request.parameters.name or error()
+	run_in_transaction( function()
+		chat = get_chat_by_id(chat) or error()
+		chat.user_id == current_user().id or error()
+		chat.name = name
+		chat.save()
+	end )
+	Io.stdout = Http.response.text_writer()
+%>
+	setChat(<%= json_string(chat.info()) %>);
+<%
+end
--- a/src/save_rename_chat.js.luan	Sat Aug 02 20:04:35 2025 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-local Luan = require "luan:Luan.luan"
-local error = Luan.error
-local Parsers = require "luan:Parsers.luan"
-local json_string = Parsers.json_string or error()
-local Io = require "luan:Io.luan"
-local Http = require "luan:http/Http.luan"
-local Chat = require "site:/lib/Chat.luan"
-local get_chat_by_id = Chat.get_by_id or error()
-local User = require "site:/lib/User.luan"
-local current_user = User.current or error()
-local Db = require "site:/lib/Db.luan"
-local run_in_transaction = Db.run_in_transaction or error()
-
-
-return function()
-	local chat = Http.request.parameters.chat or error()
-	local name = Http.request.parameters.name or error()
-	run_in_transaction( function()
-		chat = get_chat_by_id(chat) or error()
-		chat.user_id == current_user().id or error()
-		chat.name = name
-		chat.save()
-	end )
-	Io.stdout = Http.response.text_writer()
-%>
-	document.querySelector('[content] [name]').textContent = <%=json_string(name)%>;
-<%
-end
--- a/src/site.js	Sat Aug 02 20:04:35 2025 -0600
+++ b/src/site.js	Sat Aug 02 22:39:48 2025 -0600
@@ -124,21 +124,20 @@
 
 let mdDiv = document.createElement('div');
 
-function handleMarkdown() {
+function handleMarkdown(lang) {
 	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);
-		if( div.getAttribute('role')==='assistant' ) {
+		if( lang && div.getAttribute('role')==='assistant' ) {
 			mdDiv.innerHTML = text;
 			let rts = mdDiv.querySelectorAll('rt');
 			for( let rt of rts ) {
 				rt.remove();
 			}
 			//console.log(mdDiv.textContent);
-			let lang = div.getAttribute('lang');
 			text += `\n<p><audio controls preload=none src="/tts.mp3?lang=${lang}&text=${encodeURIComponent(mdDiv.textContent)}"></audio></p>\n`;
 		}
 		div.innerHTML = text;