feat(*): 模型生成链路 - 完善 Agnes 结果兼容、价格展示与请求日志追踪

This commit is contained in:
ddCat
2026-08-28 06:53:57 +08:00
parent 2c02f5ef3d
commit bd0d0fd4fd
20 changed files with 671 additions and 108 deletions

View File

@@ -144,8 +144,8 @@ func (r *Repository) filteredAPICallLogQuery(filter APICallLogFilter) *gorm.DB {
Joins("LEFT JOIN users ON users.id = api_call_logs.user_id").
Joins("LEFT JOIN model_channels ON model_channels.id = api_call_logs.channel_id").
Where(
"lower(api_call_logs.user_id) LIKE ? OR lower(users.username) LIKE ? OR lower(users.display_name) LIKE ? OR lower(api_call_logs.channel_id) LIKE ? OR lower(model_channels.name) LIKE ? OR lower(api_call_logs.model) LIKE ? OR lower(api_call_logs.path) LIKE ? OR lower(api_call_logs.provider_request_id) LIKE ?",
pattern, pattern, pattern, pattern, pattern, pattern, pattern, pattern,
"lower(api_call_logs.user_id) LIKE ? OR lower(users.username) LIKE ? OR lower(users.display_name) LIKE ? OR lower(api_call_logs.channel_id) LIKE ? OR lower(model_channels.name) LIKE ? OR lower(api_call_logs.model) LIKE ? OR lower(api_call_logs.path) LIKE ? OR lower(api_call_logs.provider_request_id) LIKE ? OR lower(api_call_logs.error_code) LIKE ? OR lower(api_call_logs.error) LIKE ?",
pattern, pattern, pattern, pattern, pattern, pattern, pattern, pattern, pattern, pattern,
)
}
if filter.Status != "" {
@@ -172,6 +172,15 @@ func (r *Repository) LatestProviderRequestIDForTask(taskID string) (string, erro
return strings.TrimSpace(log.ProviderRequestID), err
}
func (r *Repository) HasAPICallLogForTask(taskID string) (bool, error) {
if strings.TrimSpace(taskID) == "" {
return false, nil
}
var count int64
err := r.db.Model(&model.ApiCallLog{}).Where("task_id = ?", taskID).Count(&count).Error
return count > 0, err
}
func visibleAPICallLogQuery(query *gorm.DB) *gorm.DB {
// 视频轮询属于一次生成调用的内部阶段,管理端只展示聚合后的创建主记录。
return query.Where("NOT (api_call_logs.capability = ? AND api_call_logs.request_kind IN ?)", "video", []string{"poll", "download"})

View File

@@ -6,7 +6,10 @@ import (
"testing"
"time"
"infinite-canvas/backend/internal/model"
"gorm.io/driver/postgres"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
@@ -71,3 +74,41 @@ func TestRecordUserActivityQualifiesPostgresConflictColumns(t *testing.T) {
})
}
}
func TestQueryAPICallLogsSearchesFailureFields(t *testing.T) {
db, err := gorm.Open(sqlite.Open("file:api-log-error-search?mode=memory&cache=shared"), &gorm.Config{})
if err != nil {
t.Fatal(err)
}
if err := db.AutoMigrate(&model.User{}, &model.ModelChannel{}, &model.ApiCallLog{}); err != nil {
t.Fatal(err)
}
now := time.Now()
item := model.ApiCallLog{
ID: "api-log-1",
UserID: "user-1",
RequestKind: "create",
Status: model.ApiCallStatusFailed,
ErrorCode: "request_not_sent",
Error: "模型服务拒绝了请求,请检查模型和参数;上游:invalid parameter: size",
CreatedAt: now,
}
if err := db.Create(&item).Error; err != nil {
t.Fatal(err)
}
repo := New(db)
for _, keyword := range []string{"模型服务拒绝", "invalid parameter", "request_not_sent"} {
logs, total, err := repo.QueryAPICallLogs(APICallLogFilter{
AnalyticsFilter: AnalyticsFilter{From: now.Add(-time.Hour), To: now.Add(time.Hour)},
Keyword: keyword,
Page: 1,
Limit: 20,
})
if err != nil {
t.Fatalf("QueryAPICallLogs(%q) error = %v", keyword, err)
}
if total != 1 || len(logs) != 1 || logs[0].ID != item.ID {
t.Fatalf("QueryAPICallLogs(%q) = total:%d logs:%#v", keyword, total, logs)
}
}
}