changeset 73:60ebb333b40c default tip

chunked encoding
author Franklin Schmidt <fschmidt@gmail.com>
date Thu, 28 Aug 2025 05:16:32 -0600
parents 5d274f7a4637
children
files src/chat.js src/site.js src/tts.wav.luan
diffstat 3 files changed, 47 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/src/chat.js	Mon Aug 25 03:45:03 2025 -0600
+++ b/src/chat.js	Thu Aug 28 05:16:32 2025 -0600
@@ -89,7 +89,7 @@
 	textarea.parentNode.scrollIntoViewIfNeeded(false);
 	if( !audio )
 		audio = document.querySelector('div[buttons] audio');
-	audio.src = `/tts.mp3?voice=${chat.voice}&instructions=${encodeURIComponent(chat.tts_instructions)}&text=${encodeURIComponent(textarea.value)}`;
+	audio.src = `/tts.wav?voice=${chat.voice}&instructions=${encodeURIComponent(chat.tts_instructions)}&text=${encodeURIComponent(textarea.value)}`;
 }
 
 function askAi1() {
--- a/src/site.js	Mon Aug 25 03:45:03 2025 -0600
+++ b/src/site.js	Thu Aug 28 05:16:32 2025 -0600
@@ -166,7 +166,7 @@
 				rt.remove();
 			}
 			//console.log(mdDiv.textContent);
-			parent.querySelector('audio').src = `/tts.mp3?voice=${voice}&instructions=${encodeURIComponent(instructions)}&text=${encodeURIComponent(mdDiv.textContent)}`;
+			parent.querySelector('audio').src = `/tts.wav?voice=${voice}&instructions=${encodeURIComponent(instructions)}&text=${encodeURIComponent(mdDiv.textContent)}`;
 		}
 	}
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tts.wav.luan	Thu Aug 28 05:16:32 2025 -0600
@@ -0,0 +1,45 @@
+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 uri = Io.uri or error()
+local Http = require "luan:http/Http.luan"
+local Config = require "site:/private/Config.luan"
+local key = Config.chatgpt.key or error()
+local Logging = require "luan:logging/Logging.luan"
+local logger = Logging.logger "tts.js"
+
+
+-- https://platform.openai.com/docs/guides/text-to-speech
+
+local url = "https://api.openai.com/v1/audio/speech"
+local headers = {
+	Authorization = "Bearer "..key
+	["Content-Type"] = "application/json"
+}
+
+local function text_to_speech(voice,instructions,text)
+	local options = {
+		method = "POST"
+		headers = headers
+		content = json_string{
+			model = "gpt-4o-mini-tts"
+			voice = voice
+			input = text
+			instructions = instructions
+			response_format = "wav"
+		}
+	}
+	return uri(url,options)
+end
+
+return function()
+	local voice = Http.request.parameters.voice or error()
+	local instructions = Http.request.parameters.instructions or error()
+	local text = Http.request.parameters.text or error()
+	local input = text_to_speech(voice,instructions,text)
+	Http.response.write_chunked_binary(function(writer)
+		writer.write_from(input)
+	end)
+end