add model-usage plugin
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
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"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user