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

@ -22,15 +22,6 @@
output.scroll(0, 0);
};
ws = new WebSocket("ws://"+window.location.host+"/ws");
ws.onopen = function(evt) {
print("READY");
}
ws.onclose = function(evt) {
print("CLOSE");
ws = null;
}
ws.onmessage = function(evt) {
const synth = window.speechSynthesis;
const voices = synth.getVoices().sort(function (a, b) {
const aname = a.name.toUpperCase();
@ -44,12 +35,53 @@
return +1;
}
});
const idx = false ? 0 : voices.length-1;
var voices_idx = 0;
const utterThis = new SpeechSynthesisUtterance(evt.data);
{
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.onopen = function(evt) {
print("READY");
}
ws.onclose = function(evt) {
print("CLOSE");
ws = null;
}
ws.onmessage = function(evt) {
console.log("evt.data:", evt.data)
const data = JSON.parse(evt.data);
const utterThis = new SpeechSynthesisUtterance(data.Text);
const idx = data.VoiceIdx || 0;
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);
print("RESPONSE: " + evt.data);
}
@ -61,8 +93,18 @@
if (!ws || !input.value) {
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({
"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);
input.value = "";
@ -73,11 +115,22 @@
</head>
<body>
<div style="width: 80%; height: 80%; margin: auto; display: flex; flex-direction: row;">
<div style="display: flex; flex-direction: column;">
<form style="flex-grow: 1;">
<p><input id="input" type="textarea" value="" autofocus style="width: 80%">
<p>
<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>
</body>

View File

@ -2,4 +2,7 @@ package server
type message struct {
Text string
Pitch int
Rate float64
VoiceIdx int
}

View File

@ -71,7 +71,7 @@ func (s *session) gather() {
return err
}
log.Printf("gathered %+v", m)
log.Printf("gathered %+v (%s)", m, msg)
return s.cb(m)
})
}
@ -81,7 +81,8 @@ func (s *session) scatter() {
select {
case m := <-s.scatterc:
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():
return s.ctx.Err()
}