diff --git a/backend/controllers/ai.go b/backend/controllers/ai.go index 7626075..8b8deec 100644 --- a/backend/controllers/ai.go +++ b/backend/controllers/ai.go @@ -64,12 +64,12 @@ func (ctrl *AIController) TestConfig(c *gin.Context) { cfg.APIKey = req.APIKey } - reply, err := services.TestAIConnection(cfg) + result, err := services.TestAIConnection(cfg) if err != nil { utils.Error(c, 400, err.Error()) return } - utils.Success(c, gin.H{"reply": reply, "model": cfg.Model}) + utils.Success(c, result) } func containsMask(s string) bool { diff --git a/backend/services/ai_provider.go b/backend/services/ai_provider.go index 9d5bd24..03f0fc8 100644 --- a/backend/services/ai_provider.go +++ b/backend/services/ai_provider.go @@ -115,17 +115,36 @@ func aiChat(ctx context.Context, cfg models.AIConfig, messages []aiMessage) (str return parsed.Choices[0].Message.Content, parsed.Usage.PromptTokens, parsed.Usage.CompletionTokens, nil } -// TestAIConnection 连通性测试:发一句最小请求,验证 baseURL/key/model 三件套。 -func TestAIConnection(cfg models.AIConfig) (string, error) { +// AIConnectionTest 连通性测试结果:面向展示的结构化信息,不外发原始回复 +type AIConnectionTest struct { + Model string `json:"model"` + LatencyMs int64 `json:"latencyMs"` + TokensUsed int `json:"tokensUsed"` + ReplyLength int `json:"replyLength"` +} + +// TestAIConnection 连通性测试:发一句最小请求,验证 baseURL/key/model 三件套。 +// 返回结构化结果(模型/耗时/token);模型原始回复不回传 —— 测试要的是"通没通、多快",不是看模型说了什么。 +func TestAIConnection(cfg models.AIConfig) (*AIConnectionTest, error) { cfg.MaxTokens = 32 cfg.TimeoutSec = 30 - reply, _, _, err := aiChat(context.Background(), cfg, []aiMessage{ + start := time.Now() + reply, promptTokens, completionTokens, err := aiChat(context.Background(), cfg, []aiMessage{ {Role: "user", Content: "只回复两个字:正常"}, }) if err != nil { - return "", err + return nil, err } - return strings.TrimSpace(reply), nil + trimmed := strings.TrimSpace(reply) + if trimmed == "" { + return nil, fmt.Errorf("模型返回了空内容(检查 baseURL 是否为 OpenAI 兼容端点)") + } + return &AIConnectionTest{ + Model: cfg.Model, + LatencyMs: time.Since(start).Milliseconds(), + TokensUsed: promptTokens + completionTokens, + ReplyLength: len([]rune(trimmed)), + }, nil } // ChatMessage 浮窗助手的多轮消息(user/assistant 交替) diff --git a/frontend/src/api/ai/index.ts b/frontend/src/api/ai/index.ts index 71be0d2..c65849f 100644 --- a/frontend/src/api/ai/index.ts +++ b/frontend/src/api/ai/index.ts @@ -83,7 +83,7 @@ export const aiApi = { getConfig: () => http.get('/ai/config'), saveConfig: (data: Partial) => http.put<{ config: AIConfig }>('/ai/config', data), testConfig: (data: { baseUrl?: string; model?: string; apiKey?: string }) => - http.post<{ reply: string; model: string }>('/ai/config/test', data, { timeout: 45000 }), + http.post<{ model: string; latencyMs: number; tokensUsed: number; replyLength: number }>('/ai/config/test', data, { timeout: 45000 }), analyze: (data: { sourceId: number; start: number; end: number; question?: string; app?: string }) => http.post('/ai/analyze', data, { timeout: 180000 }), runs: (page: number, pageSize: number) => diff --git a/frontend/src/i18n/locales/en/aiops.ts b/frontend/src/i18n/locales/en/aiops.ts index 1262ae3..38ae7ea 100644 --- a/frontend/src/i18n/locales/en/aiops.ts +++ b/frontend/src/i18n/locales/en/aiops.ts @@ -93,7 +93,7 @@ export default { save: 'Save', test: 'Test connection', testing: 'Testing…', - testOk: 'Connection OK, model replied: {{reply}}', + testOk: 'Connected: {{model}} · {{latency}}s · {{tokens}} tokens', usedToday: '{{used}} tokens used today', }, diff --git a/frontend/src/i18n/locales/zh/aiops.ts b/frontend/src/i18n/locales/zh/aiops.ts index 2c972a6..349c76e 100644 --- a/frontend/src/i18n/locales/zh/aiops.ts +++ b/frontend/src/i18n/locales/zh/aiops.ts @@ -93,7 +93,7 @@ export default { save: '保存配置', test: '测试连接', testing: '测试中…', - testOk: '连接正常,模型回复:{{reply}}', + testOk: '连接正常:{{model}} · {{latency}}s · {{tokens}} tokens', usedToday: '今日已用 {{used}} tokens', }, diff --git a/frontend/src/pages/aiops/index.tsx b/frontend/src/pages/aiops/index.tsx index da1e950..8316bc4 100644 --- a/frontend/src/pages/aiops/index.tsx +++ b/frontend/src/pages/aiops/index.tsx @@ -207,7 +207,7 @@ export default function AiopsPage() { model: config?.model, apiKey: apiKeyInput.trim() || undefined, }) - toast.success(t('config.testOk', { reply: res.reply || 'OK' })) + toast.success(t('config.testOk', { model: res.model, latency: (res.latencyMs / 1000).toFixed(1), tokens: res.tokensUsed })) } catch (err) { toast.error(err instanceof Error ? err.message : '连接失败') } finally {