176 lines
5.2 KiB
QML
176 lines
5.2 KiB
QML
import QtQuick 2.15
|
|
import QtQuick.Controls 2.15
|
|
import QtQuick.Layouts 1.15
|
|
|
|
ApplicationWindow {
|
|
id: root
|
|
visible: true
|
|
width: 1000
|
|
height: 600
|
|
title: "Ollie"
|
|
|
|
// Chat tail buffer — only keep last 8KB for display
|
|
property string chatTail: ""
|
|
readonly property int maxTail: 8192
|
|
|
|
Component.onCompleted: {
|
|
// Load initial log content
|
|
var log = ollie.readLog()
|
|
if (log.length > maxTail)
|
|
log = log.slice(-maxTail)
|
|
chatTail = log
|
|
}
|
|
|
|
Connections {
|
|
target: ollie
|
|
function onChatReceived(text) {
|
|
chatTail += text
|
|
if (chatTail.length > maxTail * 2) {
|
|
chatTail = chatTail.slice(-maxTail)
|
|
}
|
|
}
|
|
function onActiveSessionIdChanged() {
|
|
chatTail = ""
|
|
var log = ollie.readLog()
|
|
if (log.length > maxTail)
|
|
log = log.slice(-maxTail)
|
|
chatTail = log
|
|
}
|
|
function onStreamingDone() {
|
|
// Session was killed
|
|
chatTail += "\n[session ended]\n"
|
|
}
|
|
}
|
|
|
|
SplitView {
|
|
anchors.fill: parent
|
|
|
|
// Left pane: session list
|
|
ColumnLayout {
|
|
SplitView.preferredWidth: 200
|
|
SplitView.minimumWidth: 120
|
|
spacing: 0
|
|
|
|
ToolBar {
|
|
Layout.fillWidth: true
|
|
RowLayout {
|
|
anchors.fill: parent
|
|
Label { text: "Sessions"; Layout.fillWidth: true; font.bold: true; leftPadding: 8 }
|
|
ToolButton {
|
|
text: "↻"
|
|
onClicked: ollie.refreshSessions()
|
|
}
|
|
}
|
|
}
|
|
|
|
ListView {
|
|
id: sessionList
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
model: ollie.sessions
|
|
clip: true
|
|
|
|
delegate: ItemDelegate {
|
|
width: sessionList.width
|
|
text: modelData.id || ""
|
|
highlighted: (modelData.id === ollie.activeSessionId)
|
|
onClicked: ollie.activeSessionId = modelData.id
|
|
|
|
Rectangle {
|
|
width: 8; height: 8; radius: 4
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 8
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
color: {
|
|
var s = modelData.state || "idle"
|
|
if (s === "idle") return "#4caf50"
|
|
if (s.startsWith("calling")) return "#ff9800"
|
|
return "#2196f3"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Right pane: chat + input
|
|
ColumnLayout {
|
|
spacing: 0
|
|
|
|
// Header
|
|
RowLayout {
|
|
Layout.fillWidth: true
|
|
Layout.margins: 6
|
|
spacing: 8
|
|
|
|
Rectangle {
|
|
width: 10; height: 10; radius: 5
|
|
color: {
|
|
if (ollie.activeState === "idle") return "#4caf50"
|
|
if (ollie.activeState.startsWith("calling")) return "#ff9800"
|
|
return "#2196f3"
|
|
}
|
|
}
|
|
|
|
Label {
|
|
text: ollie.activeState
|
|
opacity: 0.7
|
|
font.pixelSize: 11
|
|
}
|
|
|
|
Item { Layout.fillWidth: true }
|
|
|
|
ToolButton {
|
|
text: "Stop"
|
|
onClicked: ollie.interrupt()
|
|
}
|
|
}
|
|
|
|
Rectangle { Layout.fillWidth: true; height: 1; color: palette.mid }
|
|
|
|
// Chat display — streaming text, last 8KB
|
|
ScrollView {
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
|
|
TextArea {
|
|
id: chatArea
|
|
readOnly: true
|
|
wrapMode: TextEdit.NoWrap
|
|
text: root.chatTail
|
|
font.family: "monospace"
|
|
font.pixelSize: 12
|
|
onTextChanged: cursorPosition = text.length
|
|
}
|
|
}
|
|
|
|
Rectangle { Layout.fillWidth: true; height: 1; color: palette.mid }
|
|
|
|
// Input
|
|
RowLayout {
|
|
Layout.fillWidth: true
|
|
Layout.margins: 6
|
|
spacing: 4
|
|
|
|
TextField {
|
|
id: promptInput
|
|
Layout.fillWidth: true
|
|
placeholderText: ollie.activeSessionId ? "Message..." : "No session"
|
|
enabled: ollie.activeSessionId !== ""
|
|
onAccepted: {
|
|
if (text.trim() !== "") {
|
|
ollie.submit(text.trim())
|
|
text = ""
|
|
}
|
|
}
|
|
}
|
|
|
|
Button {
|
|
text: "Send"
|
|
enabled: promptInput.text.trim() !== "" && ollie.activeSessionId !== ""
|
|
onClicked: promptInput.accepted()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|