Better usage menu
This commit is contained in:
parent
26450e7d39
commit
255f86e48b
104
Chat.go
104
Chat.go
@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -379,64 +380,83 @@ func LoadUsageKPIHandler(c *fiber.Ctx) error {
|
|||||||
if !checkIfLogin() || !checkIfHaveKey() {
|
if !checkIfLogin() || !checkIfHaveKey() {
|
||||||
return c.SendString("")
|
return c.SendString("")
|
||||||
}
|
}
|
||||||
var TotalUsage float32
|
|
||||||
// Using the database. Get the sum of all usage.inputCost and outputCost
|
InputDateID := c.FormValue("month", time.Now().Format("01-2006"))
|
||||||
err := edgeClient.QuerySingle(edgeCtx, `
|
offset := c.FormValue("offset")
|
||||||
WITH
|
IsActive := false
|
||||||
U := (
|
|
||||||
SELECT Usage
|
var InputDate time.Time
|
||||||
FILTER .user = global currentUser
|
InputDate, err := time.Parse("01-2006", InputDateID)
|
||||||
)
|
|
||||||
SELECT sum(U.input_cost) + sum(U.output_cost)
|
|
||||||
`, &TotalUsage)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now()
|
if offset == "-1" {
|
||||||
|
InputDate = InputDate.AddDate(0, -1, 0)
|
||||||
|
IsActive = true
|
||||||
|
} else if offset == "1" {
|
||||||
|
InputDate = InputDate.AddDate(0, 1, 0)
|
||||||
|
IsActive = true
|
||||||
|
}
|
||||||
|
|
||||||
var TodayUsage float32
|
type UsageKPI struct {
|
||||||
// Using the database. Get the sum of all usage.inputCost and outputCost
|
Key struct {
|
||||||
err = edgeClient.QuerySingle(edgeCtx, `
|
ModelID string `edgedb:"model_id"`
|
||||||
WITH
|
} `edgedb:"key"`
|
||||||
U := (
|
TotalCost float32 `edgedb:"total_cost"`
|
||||||
SELECT Usage
|
TotalCount int64 `edgedb:"total_count"`
|
||||||
FILTER .user = global currentUser AND .date >= <datetime>$0
|
}
|
||||||
)
|
|
||||||
SELECT sum(U.input_cost) + sum(U.output_cost)
|
var usages []UsageKPI
|
||||||
`, &TodayUsage, now.Add(time.Hour*-24))
|
err = edgeClient.Query(edgeCtx, `
|
||||||
|
WITH
|
||||||
|
U := (
|
||||||
|
SELECT Usage
|
||||||
|
FILTER .user = global currentUser and .date >= <datetime>$0 AND .date < <datetime>$1
|
||||||
|
),
|
||||||
|
grouped := (
|
||||||
|
GROUP U {
|
||||||
|
model_id,
|
||||||
|
input_cost,
|
||||||
|
output_cost,
|
||||||
|
} BY .model_id
|
||||||
|
)
|
||||||
|
SELECT grouped {
|
||||||
|
key := .key { model_id },
|
||||||
|
total_count := count(.elements),
|
||||||
|
total_cost := sum(.elements.input_cost) + sum(.elements.output_cost),
|
||||||
|
} FILTER .total_count > 0 ORDER BY .total_cost DESC
|
||||||
|
`, &usages, InputDate, InputDate.AddDate(0, 1, 0))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var WeekUsage float32
|
BeautifullDate := InputDate.Format("Jan 2006")
|
||||||
// Using the database. Get the sum of all usage.inputCost and outputCost
|
|
||||||
edgeClient.QuerySingle(edgeCtx, `
|
|
||||||
WITH
|
|
||||||
U := (
|
|
||||||
SELECT Usage
|
|
||||||
FILTER .user = global currentUser AND .date >= <datetime>$0
|
|
||||||
)
|
|
||||||
SELECT sum(U.input_cost) + sum(U.output_cost)
|
|
||||||
`, &WeekUsage, now.Add(time.Hour*-24*7))
|
|
||||||
|
|
||||||
var MonthUsage float32
|
var (
|
||||||
// Using the database. Get the sum of all usage.inputCost and outputCost
|
TotalCount int64
|
||||||
edgeClient.QuerySingle(edgeCtx, `
|
TotalCost float32
|
||||||
WITH
|
)
|
||||||
U := (
|
for _, usage := range usages {
|
||||||
SELECT Usage
|
TotalCost += usage.TotalCost
|
||||||
FILTER .user = global currentUser AND .date >= <datetime>$0
|
TotalCount += usage.TotalCount
|
||||||
)
|
}
|
||||||
SELECT sum(U.input_cost) + sum(U.output_cost)
|
|
||||||
`, &MonthUsage, now.Add(time.Hour*-24*30))
|
fmt.Println(TotalCost, TotalCount)
|
||||||
|
|
||||||
out, err := pongo2.Must(pongo2.FromFile("views/partials/popover-usage.html")).Execute(pongo2.Context{
|
out, err := pongo2.Must(pongo2.FromFile("views/partials/popover-usage.html")).Execute(pongo2.Context{
|
||||||
"TotalUsage": TotalUsage, "TodayUsage": TodayUsage, "WeekUsage": WeekUsage, "MonthUsage": MonthUsage,
|
"usages": usages,
|
||||||
|
"TotalCost": TotalCost,
|
||||||
|
"TotalCount": TotalCount,
|
||||||
|
"Date": BeautifullDate,
|
||||||
|
"DateID": InputDate.Format("01-2006"),
|
||||||
|
"IsActive": IsActive,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.SendString(out)
|
return c.SendString(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css">
|
||||||
<link href="https://fonts.googleapis.com/css?family=Russo+One" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css?family=Russo+One" rel="stylesheet">
|
||||||
|
|
||||||
<link rel="stylesheet" href="/animations.css">
|
<!--link rel="stylesheet" href="/animations.css"-->
|
||||||
<link rel="stylesheet" href="/style.css">
|
<link rel="stylesheet" href="/style.css">
|
||||||
|
|
||||||
<script src="https://unpkg.com/htmx.org@1.9.11"></script>
|
<script src="https://unpkg.com/htmx.org@1.9.11"></script>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="dropdown-menu" id="dropdown-menu3" role="menu">
|
<div class="dropdown-menu" id="dropdown-menu3" role="menu">
|
||||||
<div class="dropdown-content is-small">
|
<div class="dropdown-content">
|
||||||
<div class="dropdown-item" id="models-list">
|
<div class="dropdown-item" id="models-list">
|
||||||
{% for LLM in LLMs %}
|
{% for LLM in LLMs %}
|
||||||
<div class="icon-text has-text unselected" onclick="toggleSelection(this)" style="cursor: pointer;"
|
<div class="icon-text has-text unselected" onclick="toggleSelection(this)" style="cursor: pointer;"
|
||||||
@ -84,18 +84,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function toggleDropdown(event) {
|
document.addEventListener('click', function (event) {
|
||||||
event.stopPropagation();
|
|
||||||
document.getElementById('models-dropdown').classList.toggle('is-active');
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeDropdown(event) {
|
|
||||||
if (!document.getElementById('models-dropdown').contains(event.target)) {
|
if (!document.getElementById('models-dropdown').contains(event.target)) {
|
||||||
document.getElementById('models-dropdown').classList.remove('is-active');
|
document.getElementById('models-dropdown').classList.remove('is-active');
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
document.addEventListener('click', closeDropdown);
|
|
||||||
|
|
||||||
document.getElementById('model-id-input').querySelector('select').addEventListener('change', function () {
|
document.getElementById('model-id-input').querySelector('select').addEventListener('change', function () {
|
||||||
const customEndpoint = this.value === 'custom';
|
const customEndpoint = this.value === 'custom';
|
||||||
|
@ -1,17 +1,115 @@
|
|||||||
<div class="dropdown is-hoverable is-up is-right">
|
<div class="dropdown is-up is-right {% if IsActive %} is-active{% endif %}" id="usage-dropdown">
|
||||||
<div class="dropdown-trigger">
|
<div class="dropdown-trigger">
|
||||||
<button class="button is-small" aria-haspopup="true" aria-controls="dropdown-menu4">
|
<button class="button is-small" aria-haspopup="true" aria-controls="dropdown-menu3"
|
||||||
|
onclick="this.parentElement.parentElement.classList.toggle('is-active')">
|
||||||
<span class="icon"><i class="fa-regular fa-money-bill-1"></i></span>
|
<span class="icon"><i class="fa-regular fa-money-bill-1"></i></span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="dropdown-menu" id="dropdown-menu4" role="menu">
|
<div class="dropdown-menu" id="dropdown-menu3" role="menu">
|
||||||
<div class="dropdown-content">
|
<div class="dropdown-content">
|
||||||
<div class="dropdown-item">
|
<div class="dropdown-item">
|
||||||
<div><strong>Total: {{ TotalUsage }}$</strong></div>
|
<!-- Placeholder for additional text -->
|
||||||
<div><strong>Month: {{ MonthUsage }}$</strong></div>
|
<div class="content" style="max-height: 50vh; overflow-y: auto;">
|
||||||
<div><strong>Week: {{ WeekUsage }}$</strong></div>
|
<table class="table is-narrow is-fullwidth is-striped">
|
||||||
<div><strong>Today: {{ TodayUsage }}$</strong></div>
|
<tbody>
|
||||||
|
{% for usage in usages %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<small>{{ usage.Key.ModelID }}</small>
|
||||||
|
</td>
|
||||||
|
<td class="has-text-right totalCostCell">
|
||||||
|
<small>{{ usage.TotalCost|floatformat:2 }}$</small>
|
||||||
|
</td>
|
||||||
|
<td class="has-text-right is-hidden totalCountCell">
|
||||||
|
<small>{{ usage.TotalCount }}</small>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!-- Total cost -->
|
||||||
|
<div class="content totalCostCell">
|
||||||
|
<p>
|
||||||
|
<strong>Total: </strong>
|
||||||
|
<span class="totalCost">
|
||||||
|
{{ TotalCost|floatformat:2 }}$
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<!-- Total count -->
|
||||||
|
<div class="content is-hidden totalCountCell">
|
||||||
|
<p>
|
||||||
|
<strong>Total: </strong>
|
||||||
|
<span class="totalCount">
|
||||||
|
{{ TotalCount }} messages
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<!-- Top buttons -->
|
||||||
|
<div class="buttons has-addons is-centered">
|
||||||
|
<button class="button is-small is-primary" title="Money Spent" id="money-spent-button">
|
||||||
|
<span class="icon ml-4 mr-4"><i class="fa-regular fa-money-bill-1"></i></span>
|
||||||
|
</button>
|
||||||
|
<button class="button is-small" title="Messages Sent" id="messages-sent-button">
|
||||||
|
<span class="icon ml-4 mr-4"><i class="fa-regular fa-envelope"></i></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- Row with text and buttons -->
|
||||||
|
<div class="level">
|
||||||
|
<div class="level-left">
|
||||||
|
<button class="button is-small" hx-get="/loadUsageKPI?month={{ DateID }}&offset=-1"
|
||||||
|
hx-swap="outerHTML" hx-target="#usage-dropdown">
|
||||||
|
<span class="icon"><i class="fa-solid fa-chevron-left"></i></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="level-item">
|
||||||
|
<p>{{ Date }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="level-right">
|
||||||
|
<button class="button is-small" hx-get="/loadUsageKPI?month={{ DateID }}&offset=1"
|
||||||
|
hx-swap="outerHTML" hx-target="#usage-dropdown">
|
||||||
|
<span class="icon"><i class="fa-solid fa-chevron-right"></i></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('click', function (event) {
|
||||||
|
if (!document.getElementById('usage-dropdown').contains(event.target)) {
|
||||||
|
document.getElementById('usage-dropdown').classList.remove('is-active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('money-spent-button').addEventListener('click', function () {
|
||||||
|
document.getElementById('money-spent-button').classList.add('is-primary');
|
||||||
|
document.getElementById('messages-sent-button').classList.remove('is-primary');
|
||||||
|
// Change all totalCountCell to is-hidden and remove is-hidden from totalCostCell
|
||||||
|
const totalCountCells = document.getElementsByClassName('totalCountCell');
|
||||||
|
for (let i = 0; i < totalCountCells.length; i++) {
|
||||||
|
totalCountCells[i].classList.add('is-hidden');
|
||||||
|
}
|
||||||
|
const totalCostCells = document.getElementsByClassName('totalCostCell');
|
||||||
|
for (let i = 0; i < totalCostCells.length; i++) {
|
||||||
|
totalCostCells[i].classList.remove('is-hidden');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
document.getElementById('messages-sent-button').addEventListener('click', function () {
|
||||||
|
document.getElementById('messages-sent-button').classList.add('is-primary');
|
||||||
|
document.getElementById('money-spent-button').classList.remove('is-primary');
|
||||||
|
// Change all totalCostCell to is-hidden and remove is-hidden from totalCountCell
|
||||||
|
const totalCostCells = document.getElementsByClassName('totalCostCell');
|
||||||
|
for (let i = 0; i < totalCostCells.length; i++) {
|
||||||
|
totalCostCells[i].classList.add('is-hidden');
|
||||||
|
}
|
||||||
|
const totalCountCells = document.getElementsByClassName('totalCountCell');
|
||||||
|
for (let i = 0; i < totalCountCells.length; i++) {
|
||||||
|
totalCountCells[i].classList.remove('is-hidden');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
Loading…
x
Reference in New Issue
Block a user