forked from Shinonome/dots-hyprland
ai: show search queries, temperature, and token count
This commit is contained in:
@@ -188,10 +188,72 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
component StatusItem: MouseArea {
|
||||||
|
id: statusItem
|
||||||
|
property string icon
|
||||||
|
property string statusText
|
||||||
|
property string description
|
||||||
|
hoverEnabled: true
|
||||||
|
implicitHeight: statusItemRowLayout.implicitHeight
|
||||||
|
implicitWidth: statusItemRowLayout.implicitWidth
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: statusItemRowLayout
|
||||||
|
spacing: 4
|
||||||
|
MaterialSymbol {
|
||||||
|
text: statusItem.icon
|
||||||
|
iconSize: Appearance.font.pixelSize.huge
|
||||||
|
color: Appearance.colors.colSubtext
|
||||||
|
}
|
||||||
|
StyledText {
|
||||||
|
font.pixelSize: Appearance.font.pixelSize.small
|
||||||
|
text: statusItem.statusText
|
||||||
|
color: Appearance.colors.colSubtext
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledToolTip {
|
||||||
|
content: statusItem.description
|
||||||
|
extraVisibleCondition: false
|
||||||
|
alternativeVisibleCondition: statusItem.containsMouse
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component StatusSeparator: Rectangle {
|
||||||
|
implicitWidth: 4
|
||||||
|
implicitHeight: 4
|
||||||
|
radius: implicitWidth / 2
|
||||||
|
color: Appearance.colors.colOutlineVariant
|
||||||
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: columnLayout
|
id: columnLayout
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
|
RowLayout { // Status
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
spacing: 8
|
||||||
|
|
||||||
|
StatusItem {
|
||||||
|
icon: "device_thermostat"
|
||||||
|
statusText: Ai.temperature.toFixed(1)
|
||||||
|
description: Translation.tr("Temperature")
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusSeparator {
|
||||||
|
visible: Ai.tokenCount.total > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusItem {
|
||||||
|
visible: Ai.tokenCount.total > 0
|
||||||
|
icon: "token"
|
||||||
|
statusText: Ai.tokenCount.total
|
||||||
|
description: Translation.tr("Total token count\nInput: %1\nOutput: %2")
|
||||||
|
.arg(Ai.tokenCount.input)
|
||||||
|
.arg(Ai.tokenCount.output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Item { // Messages
|
Item { // Messages
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|||||||
@@ -263,7 +263,6 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Flow { // Annotations
|
Flow { // Annotations
|
||||||
id: annotationFlowLayout
|
|
||||||
visible: root.messageData?.annotationSources?.length > 0
|
visible: root.messageData?.annotationSources?.length > 0
|
||||||
spacing: 5
|
spacing: 5
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
@@ -274,12 +273,28 @@ Rectangle {
|
|||||||
values: root.messageData?.annotationSources || []
|
values: root.messageData?.annotationSources || []
|
||||||
}
|
}
|
||||||
delegate: AnnotationSourceButton {
|
delegate: AnnotationSourceButton {
|
||||||
id: annotationButton
|
required property var modelData
|
||||||
displayText: modelData.text
|
displayText: modelData.text
|
||||||
url: modelData.url
|
url: modelData.url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Flow { // Search queries
|
||||||
|
visible: root.messageData?.searchQueries?.length > 0
|
||||||
|
spacing: 5
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: ScriptModel {
|
||||||
|
values: root.messageData?.searchQueries || []
|
||||||
|
}
|
||||||
|
delegate: SearchQueryButton {
|
||||||
|
required property var modelData
|
||||||
|
query: modelData
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import qs.modules.common
|
||||||
|
import qs.modules.common.widgets
|
||||||
|
import qs.services
|
||||||
|
import qs.modules.common.functions
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
|
||||||
|
RippleButton {
|
||||||
|
id: root
|
||||||
|
property string query
|
||||||
|
|
||||||
|
implicitHeight: 30
|
||||||
|
leftPadding: 6
|
||||||
|
rightPadding: 10
|
||||||
|
buttonRadius: Appearance.rounding.verysmall
|
||||||
|
colBackground: Appearance.colors.colSurfaceContainerHighest
|
||||||
|
colBackgroundHover: Appearance.colors.colSurfaceContainerHighestHover
|
||||||
|
colRipple: Appearance.colors.colSurfaceContainerHighestActive
|
||||||
|
|
||||||
|
PointingHandInteraction {}
|
||||||
|
onClicked: {
|
||||||
|
let url = Config.options.search.engineBaseUrl + root.query;
|
||||||
|
for (let site of (Config?.options?.search.excludedSites ?? [])) {
|
||||||
|
url += ` -site:${site}`;
|
||||||
|
}
|
||||||
|
Qt.openUrlExternally(url);
|
||||||
|
Hyprland.dispatch("global quickshell:sidebarLeftClose")
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: Item {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
implicitWidth: rowLayout.implicitWidth
|
||||||
|
implicitHeight: rowLayout.implicitHeight
|
||||||
|
RowLayout {
|
||||||
|
id: rowLayout
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: 5
|
||||||
|
MaterialSymbol {
|
||||||
|
text: "search"
|
||||||
|
iconSize: 20
|
||||||
|
color: Appearance.m3colors.m3onSurface
|
||||||
|
}
|
||||||
|
StyledText {
|
||||||
|
id: text
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
text: root.query
|
||||||
|
color: Appearance.m3colors.m3onSurface
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,6 +25,11 @@ Singleton {
|
|||||||
readonly property var apiKeysLoaded: KeyringStorage.loaded
|
readonly property var apiKeysLoaded: KeyringStorage.loaded
|
||||||
property var postResponseHook
|
property var postResponseHook
|
||||||
property real temperature: Persistent.states?.ai?.temperature ?? 0.5
|
property real temperature: Persistent.states?.ai?.temperature ?? 0.5
|
||||||
|
property QtObject tokenCount: QtObject {
|
||||||
|
property int input: -1
|
||||||
|
property int output: -1
|
||||||
|
property int total: -1
|
||||||
|
}
|
||||||
|
|
||||||
function idForMessage(message) {
|
function idForMessage(message) {
|
||||||
// Generate a unique ID using timestamp and random value
|
// Generate a unique ID using timestamp and random value
|
||||||
@@ -626,6 +631,7 @@ Singleton {
|
|||||||
root.handleGeminiFunctionCall(functionCall.name, functionCall.args);
|
root.handleGeminiFunctionCall(functionCall.name, functionCall.args);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normal text response
|
// Normal text response
|
||||||
const responseContent = dataJson.candidates[0]?.content?.parts[0]?.text
|
const responseContent = dataJson.candidates[0]?.content?.parts[0]?.text
|
||||||
requester.message.rawContent += responseContent;
|
requester.message.rawContent += responseContent;
|
||||||
@@ -638,6 +644,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}) ?? [];
|
}) ?? [];
|
||||||
|
|
||||||
|
// Handle annotations and search queries
|
||||||
const annotations = dataJson.candidates[0]?.groundingMetadata?.groundingSupports?.map(citation => {
|
const annotations = dataJson.candidates[0]?.groundingMetadata?.groundingSupports?.map(citation => {
|
||||||
return {
|
return {
|
||||||
"type": "url_citation",
|
"type": "url_citation",
|
||||||
@@ -650,6 +657,16 @@ Singleton {
|
|||||||
});
|
});
|
||||||
requester.message.annotationSources = annotationSources;
|
requester.message.annotationSources = annotationSources;
|
||||||
requester.message.annotations = annotations;
|
requester.message.annotations = annotations;
|
||||||
|
requester.message.searchQueries = dataJson.candidates[0]?.groundingMetadata?.webSearchQueries ?? [];
|
||||||
|
// console.log("[AI] Gemini: Search queries: ", JSON.stringify(requester.message.searchQueries, null, 2));
|
||||||
|
|
||||||
|
// Usage
|
||||||
|
root.tokenCount.input = dataJson.usageMetadata?.promptTokenCount ?? -1;
|
||||||
|
root.tokenCount.output = dataJson.usageMetadata?.candidatesTokenCount ?? -1;
|
||||||
|
root.tokenCount.total = dataJson.usageMetadata?.totalTokenCount ?? -1;
|
||||||
|
// console.log("[AI] Gemini: Token count: ", root.tokenCount);
|
||||||
|
|
||||||
|
// Last logging
|
||||||
// console.log(JSON.stringify(requester.message, null, 2));
|
// console.log(JSON.stringify(requester.message, null, 2));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("[AI] Gemini: Could not parse buffer: ", e);
|
console.log("[AI] Gemini: Could not parse buffer: ", e);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ QtObject {
|
|||||||
property bool done: false
|
property bool done: false
|
||||||
property var annotations: []
|
property var annotations: []
|
||||||
property var annotationSources: []
|
property var annotationSources: []
|
||||||
|
property list<string> searchQueries: []
|
||||||
property string functionName
|
property string functionName
|
||||||
property string functionCall
|
property string functionCall
|
||||||
property string functionResponse
|
property string functionResponse
|
||||||
|
|||||||
Reference in New Issue
Block a user