mirror of
https://github.com/arthur-pbty/arthur-os.git
synced 2026-08-03 20:28:21 +02:00
136 lines
3.9 KiB
QML
136 lines
3.9 KiB
QML
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Io
|
|
|
|
Item {
|
|
id: root
|
|
visible: false
|
|
|
|
property string providerId: "codex"
|
|
property string providerName: "Codex"
|
|
property string providerIcon: "ai"
|
|
property bool enabled: false
|
|
property bool ready: false
|
|
property bool refreshing: false
|
|
property double lastRefreshedAtMs: 0
|
|
|
|
property real rateLimitPercent: -1
|
|
property string rateLimitLabel: ""
|
|
property string rateLimitResetAt: ""
|
|
property real secondaryRateLimitPercent: -1
|
|
property string secondaryRateLimitLabel: ""
|
|
property string secondaryRateLimitResetAt: ""
|
|
|
|
property int todayPrompts: 0
|
|
property int todaySessions: 0
|
|
property real todayTotalTokens: 0
|
|
property var todayTokensByModel: ({})
|
|
|
|
property var recentDays: []
|
|
property int totalPrompts: 0
|
|
property int totalSessions: 0
|
|
property var modelUsage: ({})
|
|
|
|
property string tierLabel: ""
|
|
property string usageStatusText: ""
|
|
property string authHelpText: "Run `codex login` to authenticate."
|
|
property bool hasLocalStats: true
|
|
|
|
property string configModel: ""
|
|
property var providerSettings: ({})
|
|
|
|
readonly property string scannerPath: String(Qt.resolvedUrl("../scripts/codex_usage_scanner.py")).replace("file://", "")
|
|
|
|
Process {
|
|
id: usageScanner
|
|
command: ["python3", root.scannerPath]
|
|
running: false
|
|
|
|
stdout: StdioCollector {
|
|
onStreamFinished: root.parseScannerOutput(text)
|
|
}
|
|
|
|
onExited: root.finishRefresh()
|
|
|
|
stderr: StdioCollector {
|
|
onStreamFinished: if (text.trim() !== "") console.warn("model-usage/codex", text.trim())
|
|
}
|
|
}
|
|
|
|
Timer {
|
|
interval: 5 * 60 * 1000
|
|
running: root.enabled
|
|
repeat: true
|
|
triggeredOnStart: true
|
|
onTriggered: root.refresh()
|
|
}
|
|
|
|
onEnabledChanged: if (enabled) refresh()
|
|
|
|
function finishRefresh() {
|
|
root.refreshing = false
|
|
root.lastRefreshedAtMs = Date.now()
|
|
}
|
|
|
|
function refresh(force) {
|
|
if (usageScanner.running)
|
|
return
|
|
root.refreshing = true
|
|
usageScanner.running = true
|
|
}
|
|
|
|
function parseScannerOutput(output) {
|
|
const raw = String(output || "").trim()
|
|
if (raw === "")
|
|
return
|
|
|
|
try {
|
|
const data = JSON.parse(raw.split("\n").pop())
|
|
root.ready = !!data.ready
|
|
root.hasLocalStats = data.hasLocalStats !== false
|
|
|
|
root.todayPrompts = data.todayPrompts || 0
|
|
root.todaySessions = data.todaySessions || 0
|
|
root.todayTotalTokens = data.todayTotalTokens || 0
|
|
root.todayTokensByModel = data.todayTokensByModel || ({})
|
|
root.recentDays = data.recentDays || []
|
|
root.totalPrompts = data.totalPrompts || 0
|
|
root.totalSessions = data.totalSessions || 0
|
|
root.modelUsage = data.modelUsage || ({})
|
|
|
|
root.rateLimitPercent = data.rateLimitPercent ?? -1
|
|
root.rateLimitLabel = data.rateLimitLabel || ""
|
|
root.rateLimitResetAt = data.rateLimitResetAt || ""
|
|
root.secondaryRateLimitPercent = data.secondaryRateLimitPercent ?? -1
|
|
root.secondaryRateLimitLabel = data.secondaryRateLimitLabel || ""
|
|
root.secondaryRateLimitResetAt = data.secondaryRateLimitResetAt || ""
|
|
|
|
root.tierLabel = data.tierLabel || ""
|
|
root.usageStatusText = data.usageStatusText || ""
|
|
root.authHelpText = data.authHelpText || "Run `codex login` to authenticate."
|
|
} catch (e) {
|
|
console.error("model-usage/codex", "Failed to parse scanner output:", e, raw)
|
|
root.usageStatusText = "Codex scan failed"
|
|
root.authHelpText = String(e)
|
|
root.ready = true
|
|
}
|
|
}
|
|
|
|
function formatResetTime(isoTimestamp) {
|
|
if (!isoTimestamp)
|
|
return ""
|
|
const reset = new Date(isoTimestamp)
|
|
const now = new Date()
|
|
const diffMs = reset.getTime() - now.getTime()
|
|
if (diffMs <= 0)
|
|
return "now"
|
|
const hours = Math.floor(diffMs / 3600000)
|
|
const mins = Math.floor((diffMs % 3600000) / 60000)
|
|
if (hours > 24)
|
|
return Math.floor(hours / 24) + "d " + (hours % 24) + "h"
|
|
if (hours > 0)
|
|
return hours + "h " + mins + "m"
|
|
return mins + "m"
|
|
}
|
|
}
|