changeset 69:f5e72f2d1025

add stt_prompt
author Franklin Schmidt <fschmidt@gmail.com>
date Sat, 23 Aug 2025 07:07:59 -0600
parents a366d27db8f1
children 4a73af8f2203
files courses/course.txt src/chat.js src/edit_course.html.luan src/lib/Chat.luan src/lib/Course.luan src/lib/ai/claude/Ai_chat.luan src/new_chat.red.luan src/save_course.js.luan src/stt.js.luan src/view_course.html.luan
diffstat 10 files changed, 41 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/courses/course.txt	Sat Aug 23 04:32:17 2025 -0600
+++ b/courses/course.txt	Sat Aug 23 07:07:59 2025 -0600
@@ -4,6 +4,6 @@
 This course is to have Claude help you design your own course.  When you make a course and then start a chat, Claude can read that chat if you give Claude the chat ID from the chat URL.  This let's you discuss a chat with Claude in a chat of this course.
 
 
-This is an AI language learning website using the Claude API.  Users can create courses on this website by entering a system prompt for Claude.  The purpose of this thread/chat is to help users design these courses, mostly by editing the system prompt of the course.  This website also has text-to-speech and speech-to-text using OpenAI.  A course also has instructions for text-to-speech.
+This is an AI language learning website using the Claude API.  Users can create courses on this website by entering a system prompt for Claude.  The purpose of this thread/chat is to help users design these courses, mostly by editing the system prompt of the course.  This website also has text-to-speech and speech-to-text using OpenAI.  A course also has instructions for text-to-speech and a prompt for speech-to-text.
 
 Users can discuss a chat with you by giving you a chat ID so you can read the chat using the tool/function `get_chat`.
--- a/src/chat.js	Sat Aug 23 04:32:17 2025 -0600
+++ b/src/chat.js	Sat Aug 23 07:07:59 2025 -0600
@@ -133,6 +133,7 @@
 			let blob = new Blob(chunks, { type: 'audio/webm' });
 			let formData = new FormData();
 			formData.append('audio', blob, 'recording.webm');
+			formData.append('prompt', chat.stt_prompt);
 			ajax('stt.js',formData);
 			document.querySelector('button[record]').textContent = 'Record';
 		};
--- a/src/edit_course.html.luan	Sat Aug 23 04:32:17 2025 -0600
+++ b/src/edit_course.html.luan	Sat Aug 23 07:07:59 2025 -0600
@@ -30,6 +30,7 @@
 			tts_instructions = ""
 			has_ruby = false
 			description = ""
+			stt_prompt = ""
 		}
 	end
 	Io.stdout = Http.response.text_writer()
@@ -83,6 +84,9 @@
 			<h4>Text to speech instructions</h4>
 			<textarea name=tts_instructions oninput="fixTextarea(event.target)"><%=html_encode(course.tts_instructions)%></textarea>
 
+			<h4>Speech to text prompt</h4>
+			<textarea name=stt_prompt oninput="fixTextarea(event.target)"><%=html_encode(course.stt_prompt)%></textarea>
+
 			<input type=submit>
 
 			<hr>
--- a/src/lib/Chat.luan	Sat Aug 23 04:32:17 2025 -0600
+++ b/src/lib/Chat.luan	Sat Aug 23 07:07:59 2025 -0600
@@ -37,6 +37,7 @@
 		autoplay = doc.autoplay == "true"
 		is_private = doc.is_private == "true"
 		has_ruby = doc.has_ruby == "true"
+		stt_prompt = doc.stt_prompt or ""
 	}
 end
 
@@ -50,12 +51,13 @@
 		name = chat.name or error()
 		ai_thread = chat.ai_thread or error()
 		language = chat.language or error()
-		tts_instructions = chat.tts_instructions -- or error()
+		tts_instructions = chat.tts_instructions or error()
 		voice = chat.voice or error()
 		show_text = chat.show_text
 		autoplay = chat.autoplay and "true" or "false"
 		is_private = chat.is_private and "true" or nil
 		has_ruby = chat.has_ruby and "true" or nil
+		stt_prompt = chat.stt_prompt or error()
 	}
 end
 
@@ -87,6 +89,7 @@
 			show_text = chat.show_text
 			autoplay = chat.autoplay
 			is_private = chat.is_private
+			stt_prompt = chat.stt_prompt
 		}
 	end
 
--- a/src/lib/Course.luan	Sat Aug 23 04:32:17 2025 -0600
+++ b/src/lib/Course.luan	Sat Aug 23 07:07:59 2025 -0600
@@ -27,6 +27,7 @@
 		tts_instructions = doc.tts_instructions
 		has_ruby = doc.has_ruby == "true"
 		description = doc.description or ""
+		stt_prompt = doc.stt_prompt or ""
 	}
 end
 
@@ -43,6 +44,7 @@
 		tts_instructions = course.tts_instructions or error()
 		has_ruby = course.has_ruby and "true" or nil
 		description = course.description or error()
+		stt_prompt = course.stt_prompt or error()
 	}
 end
 
--- a/src/lib/ai/claude/Ai_chat.luan	Sat Aug 23 04:32:17 2025 -0600
+++ b/src/lib/ai/claude/Ai_chat.luan	Sat Aug 23 07:07:59 2025 -0600
@@ -105,7 +105,7 @@
 	}
 	get_tts_instructions = {
 		tool = {
-			description = "Get the text-to-speech instructions of a chat/thread on this website.  These instruction are passed to OpenAI.  If there are no instructions, the empty string is returned."
+			description = "Get the text-to-speech instructions of a chat/thread on this website.  These instructions are passed to OpenAI.  If there are no instructions, the empty string is returned."
 			input_schema = {
 				type = "object"
 				properties = {
@@ -122,6 +122,25 @@
 			return chat.tts_instructions or error()
 		end
 	}
+	get_stt_prompt = {
+		tool = {
+			description = "Get the speech-to-text prompt of a chat/thread on this website.  This prompt is passed to OpenAI.  If there is no prompt, the empty string is returned."
+			input_schema = {
+				type = "object"
+				properties = {
+					chat_id = {
+						description = "The ID of the chat"
+						type = "integer"
+					}
+				}
+			}
+		}
+		fn = function(input)
+			local chat_id = input.chat_id or error()
+			local chat = get_chat(chat_id)
+			return chat.stt_prompt or error()
+		end
+	}
 }
 local tools = {nil}
 for name, f in pairs(functions) do
--- a/src/new_chat.red.luan	Sat Aug 23 04:32:17 2025 -0600
+++ b/src/new_chat.red.luan	Sat Aug 23 07:07:59 2025 -0600
@@ -22,6 +22,7 @@
 		language = course.language
 		tts_instructions = course.tts_instructions
 		has_ruby = course.has_ruby
+		stt_prompt = course.stt_prompt
 		ai_thread = ai_init(course.ai_system_prompt)
 	}
 	chat.save()
--- a/src/save_course.js.luan	Sat Aug 23 04:32:17 2025 -0600
+++ b/src/save_course.js.luan	Sat Aug 23 07:07:59 2025 -0600
@@ -33,6 +33,7 @@
 		course.tts_instructions = parameters.tts_instructions or error()
 		course.has_ruby = parameters.has_ruby ~= nil
 		course.description = parameters.description or error()
+		course.stt_prompt = parameters.stt_prompt or error()
 		course.updated = time_now()
 		course.save()
 	end )
--- a/src/stt.js.luan	Sat Aug 23 04:32:17 2025 -0600
+++ b/src/stt.js.luan	Sat Aug 23 07:07:59 2025 -0600
@@ -20,7 +20,7 @@
 	["Content-Type"] = "multipart/form-data"
 }
 
-local function speech_to_text(audio)
+local function speech_to_text(audio,prompt)
 	local options = {
 		method = "POST"
 		headers = headers
@@ -28,6 +28,7 @@
 		parameters = {
 			model = "whisper-1"
 			file = audio
+			prompt = prompt
 		}
 	}
 	local json = uri(url,options).read_text()
@@ -38,7 +39,8 @@
 
 return function()
 	local audio = Http.request.parameters.audio or error()
-	local text = speech_to_text(audio)
+	local prompt = Http.request.parameters.prompt or error()
+	local text = speech_to_text(audio,prompt)
 	Io.stdout = Http.response.text_writer()
 %>
 	setText(<%=json_string(text)%>);
--- a/src/view_course.html.luan	Sat Aug 23 04:32:17 2025 -0600
+++ b/src/view_course.html.luan	Sat Aug 23 07:07:59 2025 -0600
@@ -70,6 +70,9 @@
 			<h4>Text to speech instructions</h4>
 			<pre><%=html_encode(course.tts_instructions)%></pre>
 
+			<h4>Speech to text prompt</h4>
+			<pre><%=html_encode(course.stt_prompt)%></pre>
+
 		</div>
 		<dialog delete>
 			<h2>Delete Course</h2>