16b05476a1
CI / docker (push) Failing after 1m54s
引入用户端对话/生图与管理端 Provider 配置,统一 invoke 编排、Gateway、请求日志与模型管理;前端按设计规范拆分布局,Go module 更名为 github.com/rose_cat707/Atlas;生图长任务 SSE 推送;管理端登录防爆破;协议与服务类型联动;Replicate 模型同步修复;用户端创作台 UI 重构;管理端创作历史替代请求日志。 Co-authored-by: Cursor <cursoragent@cursor.com>
102 lines
3.6 KiB
Go
102 lines
3.6 KiB
Go
package store
|
|
|
|
import "context"
|
|
|
|
type RequestLog struct {
|
|
ID int64 `json:"id"`
|
|
SessionID string `json:"session_id"`
|
|
Method string `json:"method"`
|
|
Path string `json:"path"`
|
|
Protocol string `json:"protocol"`
|
|
ProviderID *int64 `json:"provider_id"`
|
|
Model string `json:"model"`
|
|
StatusCode int `json:"status_code"`
|
|
LatencyMS int `json:"latency_ms"`
|
|
Error string `json:"error"`
|
|
RequestSummary string `json:"request_summary"`
|
|
ResponseSummary string `json:"response_summary"`
|
|
CreatedAt string `json:"created_at"`
|
|
}
|
|
|
|
func (s *Store) InsertRequestLog(ctx context.Context, l *RequestLog) (int64, error) {
|
|
res, err := s.db.ExecContext(ctx,
|
|
`INSERT INTO request_logs (session_id, method, path, protocol, provider_id, model, status_code, latency_ms, error, request_summary, response_summary) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
l.SessionID, l.Method, l.Path, l.Protocol, l.ProviderID, l.Model, l.StatusCode, l.LatencyMS, l.Error, l.RequestSummary, l.ResponseSummary,
|
|
)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return res.LastInsertId()
|
|
}
|
|
|
|
func (s *Store) ListRequestLogs(ctx context.Context, filter RequestLogFilter, limit, offset int) ([]RequestLog, int, error) {
|
|
where := `WHERE 1=1`
|
|
args := []any{}
|
|
if filter.Path != "" {
|
|
where += ` AND path LIKE ?`
|
|
args = append(args, "%"+filter.Path+"%")
|
|
}
|
|
if filter.StatusCode > 0 {
|
|
where += ` AND status_code = ?`
|
|
args = append(args, filter.StatusCode)
|
|
}
|
|
if filter.ProviderID > 0 {
|
|
where += ` AND provider_id = ?`
|
|
args = append(args, filter.ProviderID)
|
|
}
|
|
var total int
|
|
if err := s.db.QueryRowContext(ctx, `SELECT COUNT(*) FROM request_logs `+where, args...).Scan(&total); err != nil {
|
|
return nil, 0, err
|
|
}
|
|
q := `SELECT id, session_id, method, path, protocol, provider_id, model, status_code, latency_ms, error, request_summary, response_summary, created_at FROM request_logs ` + where + ` ORDER BY id DESC LIMIT ? OFFSET ?`
|
|
qArgs := append(args, limit, offset)
|
|
rows, err := s.db.QueryContext(ctx, q, qArgs...)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
defer rows.Close()
|
|
var items []RequestLog
|
|
for rows.Next() {
|
|
var l RequestLog
|
|
if err := rows.Scan(&l.ID, &l.SessionID, &l.Method, &l.Path, &l.Protocol, &l.ProviderID, &l.Model, &l.StatusCode, &l.LatencyMS, &l.Error, &l.RequestSummary, &l.ResponseSummary, &l.CreatedAt); err != nil {
|
|
return nil, 0, err
|
|
}
|
|
items = append(items, l)
|
|
}
|
|
return items, total, rows.Err()
|
|
}
|
|
|
|
type RequestLogFilter struct {
|
|
Path string
|
|
StatusCode int
|
|
ProviderID int64
|
|
}
|
|
|
|
type DashboardStats struct {
|
|
TotalRequests int `json:"total_requests"`
|
|
SuccessRate float64 `json:"success_rate"`
|
|
AvgLatencyMS float64 `json:"avg_latency_ms"`
|
|
P50LatencyMS float64 `json:"p50_latency_ms"`
|
|
P95LatencyMS float64 `json:"p95_latency_ms"`
|
|
ByServiceType map[string]int `json:"by_service_type"`
|
|
ByProvider map[string]int `json:"by_provider"`
|
|
FileCount int `json:"file_count"`
|
|
FileBytes int64 `json:"file_bytes"`
|
|
}
|
|
|
|
func (s *Store) DashboardStats(ctx context.Context) (*DashboardStats, error) {
|
|
stats := &DashboardStats{ByServiceType: map[string]int{}, ByProvider: map[string]int{}}
|
|
var success int
|
|
err := s.db.QueryRowContext(ctx,
|
|
`SELECT COUNT(*), COALESCE(AVG(latency_ms),0), SUM(CASE WHEN status_code >= 200 AND status_code < 400 THEN 1 ELSE 0 END) FROM request_logs WHERE created_at >= datetime('now','-7 days')`,
|
|
).Scan(&stats.TotalRequests, &stats.AvgLatencyMS, &success)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if stats.TotalRequests > 0 {
|
|
stats.SuccessRate = float64(success) / float64(stats.TotalRequests)
|
|
}
|
|
stats.FileCount, stats.FileBytes, _ = s.CountFiles(ctx)
|
|
return stats, nil
|
|
}
|