Skip to content

Commit dc3a75b

Browse files
committed
feat: add 24h Graph
1 parent ecd359c commit dc3a75b

File tree

7 files changed

+172
-20
lines changed

7 files changed

+172
-20
lines changed

Diff for: api/apiserver.go

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ func ApiInit(mux *http.ServeMux, a *auth.Auth) {
1515
mux.HandleFunc("/api2/user/widget", api.GetUserWidget)
1616
mux.HandleFunc("/api2/user/logout", api.LogoutUser)
1717
mux.HandleFunc("/api2/admin/table/get", api.GetAdminTable)
18+
mux.HandleFunc("/api2/admin/table/graph/get/", api.GetAdminTableGraph)
1819
mux.HandleFunc("/api2/table/get", api.GetTable)
1920
mux.HandleFunc("/api2/table/entry/save", api.CreateEntry)
2021
mux.HandleFunc("/api2/table/entry/delete/", api.DeleteEntry)

Diff for: api/graph.go

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package api
2+
3+
import (
4+
"fmt"
5+
"html/template"
6+
"log"
7+
"net/http"
8+
db "openai-api-proxy/db"
9+
"strings"
10+
11+
"github.com/go-echarts/go-echarts/v2/charts"
12+
"github.com/go-echarts/go-echarts/v2/opts"
13+
)
14+
15+
func (a *ApiHandler) GetAdminTableGraph(w http.ResponseWriter, r *http.Request) {
16+
key := strings.TrimPrefix(r.URL.Path, "/api2/admin/table/graph/get/")
17+
log.Println(key)
18+
data, err := a.db.LookupApiKeyUserStats(key)
19+
if err != nil {
20+
log.Println(err)
21+
http.Error(w, "Could not get Data from DB for User "+string(key), 500)
22+
return
23+
}
24+
log.Println(data)
25+
// create a new line instance
26+
line := charts.NewLine()
27+
// set some global options like Title/Legend/ToolTip or anything else
28+
line.SetGlobalOptions(
29+
charts.WithColorsOpts(opts.Colors{"white"}),
30+
charts.WithGridOpts(opts.Grid{Width: "335px", Height: "70px", Left: "40px", Top: "6px", Bottom: "0px"}),
31+
charts.WithInitializationOpts(opts.Initialization{Width: "335px", Height: "100px"}),
32+
charts.WithLegendOpts(opts.Legend{Show: opts.Bool(false)}),
33+
charts.WithYAxisOpts(opts.YAxis{SplitNumber: 2}),
34+
// charts.WithVisualMapOpts(opts.VisualMap{Show: opts.Bool(false)})
35+
)
36+
37+
selectedfilter := "24h"
38+
// Put data into instance
39+
td := a.GetAdminTableGraphData(data)
40+
41+
line.SetXAxis(td.timeAxis).
42+
AddSeries(fmt.Sprintf("last %s", selectedfilter), td.data)
43+
// Where the magic happens
44+
chartSnippet := line.RenderSnippet()
45+
46+
tmpl := "{{.Element}} {{.Script}}"
47+
t := template.New("snippet")
48+
t, err = t.Parse(tmpl)
49+
if err != nil {
50+
log.Println("error templating", err)
51+
52+
}
53+
snippetData := struct {
54+
Element template.HTML
55+
Script template.HTML
56+
Option template.HTML
57+
}{
58+
Element: template.HTML(chartSnippet.Element),
59+
Script: template.HTML(chartSnippet.Script),
60+
Option: template.HTML(chartSnippet.Option),
61+
}
62+
// var buf bytes.Buffer
63+
if err := t.Execute(w, snippetData); err != nil {
64+
log.Println("Error Templating Chart", err)
65+
return
66+
}
67+
68+
// line.RenderSnippet()
69+
// log.Println(buf.String())
70+
}
71+
72+
type TableData struct {
73+
data []opts.LineData
74+
timeAxis []string
75+
}
76+
77+
func (a *ApiHandler) GetAdminTableGraphData(d []db.RequestSummary) TableData {
78+
79+
td := TableData{
80+
data: make([]opts.LineData, 0),
81+
timeAxis: make([]string, 0),
82+
}
83+
var totalTokens int
84+
85+
for _, item := range d {
86+
totalTokens = item.TokenCountComplete + item.TokenCountPrompt
87+
td.data = append(td.data, opts.LineData{Value: totalTokens})
88+
td.timeAxis = append(td.timeAxis, item.RequestTime.Format("15:04"))
89+
}
90+
return td
91+
}

Diff for: db/database.go

+68-9
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"log"
77
"os"
8+
"time"
89

910
_ "github.com/jackc/pgx/v5/stdlib"
1011
)
@@ -175,7 +176,12 @@ func (d *Database) WriteRequest(r *Request) error {
175176

176177
func (d *Database) LookupApiKeyInfos(uid string) ([]ApiKey, error) {
177178
var apikeys []ApiKey
178-
rows, err := d.db.Query("SELECT a.UUID,a.Owner,a.AiApi,a.Description,SUM(r.token_count_prompt),SUM(r.token_count_complete) FROM apiKeys a LEFT JOIN requests r ON a.UUID = r.api_key_id WHERE Owner=$1 GROUP BY a.UUID", uid)
179+
rows, err := d.db.Query(`
180+
SELECT a.UUID,a.Owner,a.AiApi,a.Description,SUM(r.token_count_prompt),SUM(r.token_count_complete)
181+
FROM apiKeys a
182+
LEFT JOIN requests r ON a.UUID = r.api_key_id
183+
WHERE Owner=$1
184+
GROUP BY a.UUID`, uid)
179185
if err != nil {
180186
return nil, err
181187
}
@@ -190,21 +196,74 @@ func (d *Database) LookupApiKeyInfos(uid string) ([]ApiKey, error) {
190196
return apikeys, nil
191197
}
192198

193-
func (d *Database) LookupApiKeyUserOverview() ([]ApiKey, error) {
194-
var apikeys []ApiKey
195-
rows, err := d.db.Query("SELECT u.name,SUM(r.token_count_prompt),SUM(r.token_count_complete) FROM apiKeys a LEFT JOIN requests r ON a.UUID = r.api_key_id LEFT JOIN users u on a.Owner = u.id WHERE u.name IS NOT NULL GROUP BY u.name")
199+
type RequestSummary struct {
200+
Uid string
201+
Name string
202+
RequestTime time.Time
203+
TokenCountPrompt int
204+
TokenCountComplete int
205+
}
206+
207+
func (d *Database) LookupApiKeyUserStats(uid string) ([]RequestSummary, error) {
208+
rows, err := d.db.Query(`
209+
SELECT
210+
u.id,
211+
SUM(r.token_count_prompt),
212+
SUM(r.token_count_complete),
213+
date_trunc('hour', r.request_time) AS request_hour
214+
FROM requests r
215+
INNER JOIN apikeys a ON r.api_key_id = a.UUID
216+
INNER JOIN users u on a.Owner = u.id
217+
WHERE
218+
u.id = $1
219+
AND r.request_time >= NOW() - INTERVAL '24 hours'
220+
GROUP BY u.id, request_hour
221+
ORDER BY request_hour;
222+
`, uid)
223+
if err != nil {
224+
return nil, err
225+
}
226+
var summary []RequestSummary
227+
for rows.Next() {
228+
var rq RequestSummary
229+
if err := rows.Scan(&rq.Uid, &rq.TokenCountPrompt, &rq.TokenCountComplete, &rq.RequestTime); err != nil {
230+
return summary, err
231+
}
232+
summary = append(summary, rq)
233+
}
234+
return summary, nil
235+
}
236+
func (d *Database) LookupApiKeyUserOverview() ([]RequestSummary, error) {
237+
var summary []RequestSummary
238+
rows, err := d.db.Query(`
239+
SELECT
240+
u.name,
241+
u.id,
242+
SUM(r.token_count_prompt),
243+
SUM(r.token_count_complete)
244+
FROM apiKeys a
245+
LEFT JOIN users u on a.Owner = u.id
246+
LEFT JOIN requests r ON a.UUID = r.api_key_id
247+
WHERE
248+
u.name IS NOT NULL
249+
AND u.name <> ''
250+
GROUP BY u.id, u.name
251+
`)
196252
if err != nil {
197253
return nil, err
198254
}
199255

200256
for rows.Next() {
201-
var a ApiKey
202-
if err := rows.Scan(&a.Owner, &a.TokenCountPrompt, &a.TokenCountComplete); err != nil {
203-
return apikeys, err
257+
var rq RequestSummary
258+
var tokenprompt, tokencomplete sql.NullInt64
259+
if err := rows.Scan(&rq.Name, &rq.Uid, &tokenprompt, &tokencomplete); err != nil {
260+
return summary, err
204261
}
205-
apikeys = append(apikeys, a)
262+
rq.TokenCountPrompt = int(tokenprompt.Int64)
263+
rq.TokenCountComplete = int(tokencomplete.Int64)
264+
summary = append(summary, rq)
206265
}
207-
return apikeys, nil
266+
return summary, nil
208267
}
209268

210269
func (d *Database) LookupApiKeys(uid string) ([]ApiKey, error) {

Diff for: go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ require (
2222
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
2323
github.com/agext/levenshtein v1.2.3 // indirect
2424
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
25+
github.com/go-echarts/go-echarts/v2 v2.4.2 // indirect
2526
github.com/go-jose/go-jose/v4 v4.0.1 // indirect
2627
github.com/go-openapi/inflect v0.19.0 // indirect
2728
github.com/golang/protobuf v1.5.3 // indirect

Diff for: go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
2222
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2323
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2424
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
25+
github.com/go-echarts/go-echarts/v2 v2.4.2 h1:1FC3tGzsLSgdeO4Ltc3OAtcIiRomfEKxKX9oocIL68g=
26+
github.com/go-echarts/go-echarts/v2 v2.4.2/go.mod h1:56YlvzhW/a+du15f3S2qUGNDfKnFOeJSThBIrVFHDtI=
2527
github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U=
2628
github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
2729
github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4=

Diff for: templates/adminTable.html.templ

+9-8
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11

2+
<script src=" https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js "></script>
23
<table class="min-w-full divide-y dark:text-gray-200 divide-gray-200 shadow overflow-hidden rounded-lg">
34
<thead class="bg-gray-50 dark:bg-slate-800 dark:text-white text-gray-500">
45
<tr>
56
<th class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">
67
User
78
</th>
8-
<!-- <th class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">
9-
Schnittstelle
10-
</th> -->
119
<th class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">
12-
Genutzte Tokens
10+
Genutzte Tokens (Gesamt)
11+
</th>
12+
<th class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">
13+
Genutzte Token (24h)
1314
</th>
1415
</thead>
1516
<tbody id="table-body" class="bg-white dark:bg-slate-900 divide-y divide-gray-200">
@@ -19,14 +20,14 @@
1920
{{ range . }}
2021
<tr>
2122
<td name="keyid" class="px-6 py-4 whitespace-nowrap">
22-
{{ .Owner }}
23+
{{ .Name }}
2324
</td>
24-
<!-- <td class="px-6 py-4 whitespace-nowrap">
25-
{{ .AiApi }}
26-
</td> -->
2725
<td class="px-6 py-4 whitespace-nowrap">
2826
{{ if .TokenCountPrompt }}{{ add .TokenCountPrompt .TokenCountComplete }}{{ else }}0{{ end }}
2927
</td>
28+
<td class="px-6 py-4 whitespace-nowrap">
29+
<div id="user-widget" hx-get="/api2/admin/table/graph/get/{{.Uid}}" hx-swap="innerHTML" class="" hx-trigger="load"></div>
30+
</td>
3031
</tr>
3132
{{ end }}
3233
{{ end }}

Diff for: templates/table.html.templ

-3
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,6 @@
6565
<td name="keyid" class="px-6 py-4 whitespace-nowrap">
6666
{{ .UUID }}
6767
</td>
68-
<!-- <td class="px-6 py-4 whitespace-nowrap">
69-
{{ .AiApi }}
70-
</td> -->
7168
<td class="px-6 py-4 whitespace-nowrap">
7269
{{ .Description }}
7370
</td>

0 commit comments

Comments
 (0)