sender can choose voice and pitch and rate

master
bel 2025-10-14 23:21:24 -06:00
parent bc1f7779d7
commit d5c3a52215
3 changed files with 82 additions and 25 deletions

View File

@ -21,6 +21,41 @@
output.innerHTML = after; output.innerHTML = after;
output.scroll(0, 0); output.scroll(0, 0);
}; };
const synth = window.speechSynthesis;
const voices = synth.getVoices().sort(function (a, b) {
const aname = a.name.toUpperCase();
const bname = b.name.toUpperCase();
if (aname < bname) {
return -1;
} else if (aname == bname) {
return 0;
} else {
return +1;
}
});
var voices_idx = 0;
{
var ele = document.getElementById("voices");
for(var i in voices) {
var voice = voices[i];
const opt = document.createElement("input");
opt.type = "radio";
opt.name = "voice";
opt.id = `voices-${i}-${voice.name}`
opt.value = i;
const label = document.createElement("label");
label.for = opt.id;
label.textContent = voice.name;
ele.appendChild(opt);
ele.appendChild(label);
ele.appendChild(document.createElement("br"));
}
}
ws = new WebSocket("ws://"+window.location.host+"/ws"); ws = new WebSocket("ws://"+window.location.host+"/ws");
ws.onopen = function(evt) { ws.onopen = function(evt) {
@ -31,25 +66,22 @@
ws = null; ws = null;
} }
ws.onmessage = function(evt) { ws.onmessage = function(evt) {
const synth = window.speechSynthesis; console.log("evt.data:", evt.data)
const voices = synth.getVoices().sort(function (a, b) { const data = JSON.parse(evt.data);
const aname = a.name.toUpperCase();
const bname = b.name.toUpperCase();
if (aname < bname) { const utterThis = new SpeechSynthesisUtterance(data.Text);
return -1;
} else if (aname == bname) {
return 0;
} else {
return +1;
}
});
const idx = false ? 0 : voices.length-1;
const utterThis = new SpeechSynthesisUtterance(evt.data); const idx = data.VoiceIdx || 0;
utterThis.voice = voices[idx]; utterThis.voice = voices[idx];
//utterThis.pitch = 10;
//utterThis.rate = 10; if (data.Pitch) {
utterThis.pitch = data.Pitch
}
if (data.Rate) {
utterThis.rate = data.Rate
}
window.speechSynthesis.speak(utterThis); window.speechSynthesis.speak(utterThis);
print("RESPONSE: " + evt.data); print("RESPONSE: " + evt.data);
} }
@ -61,8 +93,18 @@
if (!ws || !input.value) { if (!ws || !input.value) {
return false; return false;
} }
var voiceIdx = "0";
var voiceEles = document.getElementsByName("voice");
for (var i = 0; i < voiceEles.length; i++)
if (voiceEles[i].checked)
voiceIdx = voiceEles[i].value;
ws.send(JSON.stringify({ ws.send(JSON.stringify({
"text": input.value "Text": input.value,
"Pitch": Number.parseInt(document.getElementById("pitch").value, 10),
"Rate": Number.parseFloat(document.getElementById("rate").value, 10),
"VoiceIdx": Number.parseInt(voiceIdx, 10),
})); }));
print("SENT: " + input.value); print("SENT: " + input.value);
input.value = ""; input.value = "";
@ -73,11 +115,22 @@
</head> </head>
<body> <body>
<div style="width: 80%; height: 80%; margin: auto; display: flex; flex-direction: row;"> <div style="width: 80%; height: 80%; margin: auto; display: flex; flex-direction: row;">
<form style="flex-grow: 1;"> <div style="display: flex; flex-direction: column;">
<p><input id="input" type="textarea" value="" autofocus style="width: 80%"> <form style="flex-grow: 1;">
<p> <p><input id="input" type="textarea" value="" autofocus style="width: 80%">
<button id="send">Send</button> <p>
</form> <button id="send">Send</button>
</form>
<div>
<form id="voices"></form>
<input id="pitch" type="number" value="0"/>
<label for="pitch">pitch</label></br>
<input id="rate" type="number" value="0"/>
<label for="rate">rate</label></br>
</div>
</div>
<div id="output" style="flex-grow: 1; overflow-y: scroll;"></div> <div id="output" style="flex-grow: 1; overflow-y: scroll;"></div>
</div> </div>
</body> </body>

View File

@ -1,5 +1,8 @@
package server package server
type message struct { type message struct {
Text string Text string
Pitch int
Rate float64
VoiceIdx int
} }

View File

@ -71,7 +71,7 @@ func (s *session) gather() {
return err return err
} }
log.Printf("gathered %+v", m) log.Printf("gathered %+v (%s)", m, msg)
return s.cb(m) return s.cb(m)
}) })
} }
@ -81,7 +81,8 @@ func (s *session) scatter() {
select { select {
case m := <-s.scatterc: case m := <-s.scatterc:
log.Printf("scattering %+v", m) log.Printf("scattering %+v", m)
return s.ws.WriteMessage(1, []byte(m.Text)) b, _ := json.Marshal(m)
return s.ws.WriteMessage(1, b)
case <-s.ctx.Done(): case <-s.ctx.Done():
return s.ctx.Err() return s.ctx.Err()
} }