feat: v0.1.0 — client Sailfish per hermes-webui con voce

- ApiClient HTTP/SSE: login, sessioni, chat/start, stream SSE, transcribe, tts
- ChatModel: streaming live + risincronizzazione dallo stato del server
- CookieJar persistente (0600, mai la password); Settings
- Recorder OGG/Opus (fallback WAV/PCM, retry); Player TTS (QMediaPlayer)
- UI Silica: splash, login, sessioni, chat (dettatura + read-aloud), settings, cover
- Sailjail Internet;Audio;Microphone; icone; spec RPM; docs PROTOCOL/BUILD
- tests/core_test: unit parser SSE + integrazione live (probe :8899)
This commit is contained in:
2026-09-12 07:11:20 +02:00
commit 9c6a1242f7
36 changed files with 2954 additions and 0 deletions
+108
View File
@@ -0,0 +1,108 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
Page {
id: page
property var voiceNames: [
"it-IT-ElsaNeural",
"it-IT-DiegoNeural",
"it-IT-IsabellaNeural",
"it-IT-GiuseppeMultilingualNeural",
"en-US-AriaNeural"
]
property var engineNames: ["edge", "openai", "elevenlabs"]
SilicaFlickable {
anchors.fill: parent
contentHeight: col.height + Theme.paddingLarge
Column {
id: col
width: parent.width
spacing: Theme.paddingMedium
PageHeader { title: qsTr("Settings") }
SectionHeader { text: qsTr("Server") }
TextField {
id: urlField
width: parent.width
label: qsTr("Web UI address")
placeholderText: "https://hermes.example.com"
inputMethodHints: Qt.ImhUrlCharactersOnly | Qt.ImhNoAutoUppercase
onTextChanged: {
if (text !== appSettings.baseUrl)
appSettings.baseUrl = text
}
}
SectionHeader { text: qsTr("Voice") }
ComboBox {
label: qsTr("Read-aloud voice")
currentIndex: Math.max(0, page.voiceNames.indexOf(appSettings.ttsVoice))
menu: ContextMenu {
Repeater {
model: page.voiceNames
MenuItem {
text: modelData
onClicked: appSettings.ttsVoice = modelData
}
}
}
}
ComboBox {
label: qsTr("TTS engine")
currentIndex: Math.max(0, page.engineNames.indexOf(appSettings.ttsEngine))
menu: ContextMenu {
Repeater {
model: page.engineNames
MenuItem {
text: modelData
onClicked: appSettings.ttsEngine = modelData
}
}
}
}
TextSwitch {
text: qsTr("Read replies aloud")
description: qsTr("Speak every completed reply automatically")
checked: appSettings.ttsAutoRead
onCheckedChanged: appSettings.ttsAutoRead = checked
}
SectionHeader { text: qsTr("Account") }
Button {
anchors.horizontalCenter: parent.horizontalCenter
text: qsTr("Sign out")
onClicked: {
api.logout()
pageStack.replace(Qt.resolvedUrl("LoginPage.qml"))
}
}
SectionHeader { text: qsTr("About") }
Label {
x: Theme.horizontalPageMargin
width: parent.width - 2 * Theme.horizontalPageMargin
wrapMode: Text.WordWrap
font.pixelSize: Theme.fontSizeSmall
color: Theme.secondaryColor
text: "harbour-hermes " + appVersion + "\n\n" +
qsTr("Native client for the Hermes Web UI (hermes-webui): " +
"sessions, live streaming chat, server-side voice " +
"dictation and read-aloud.")
}
}
VerticalScrollDecorator {}
}
Component.onCompleted: urlField.text = appSettings.baseUrl
}