diff --git a/app/Http/Controllers/Admin/AiProviderController.php b/app/Http/Controllers/Admin/AiProviderController.php index 82e16f3..c19e62d 100644 --- a/app/Http/Controllers/Admin/AiProviderController.php +++ b/app/Http/Controllers/Admin/AiProviderController.php @@ -200,6 +200,67 @@ class AiProviderController extends Controller ]); } + /** + * 测试指定 AI 厂商的接口连通性 + * + * 发送一条简短的测试消息,返回响应结果和耗时,用于验证配置是否正确。 + * + * @param int $id 厂商配置 ID + * @return JsonResponse 测试结果 + */ + public function testConnection(int $id): JsonResponse + { + $provider = AiProviderConfig::findOrFail($id); + + $apiKey = $provider->getDecryptedApiKey(); + $base = rtrim($provider->api_endpoint, '/'); + $endpoint = str_ends_with($base, '/v1') + ? $base.'/chat/completions' + : $base.'/v1/chat/completions'; + + $startTime = microtime(true); + + try { + $response = \Illuminate\Support\Facades\Http::withToken($apiKey) + ->timeout(60) // Ollama 本地模型冷启动较慢,给 60s + ->post($endpoint, [ + 'model' => $provider->model, + 'messages' => [ + ['role' => 'user', 'content' => '请用一句话介绍你自己。'], + ], + 'max_tokens' => 64, + ]); + + $ms = (int) ((microtime(true) - $startTime) * 1000); + $data = $response->json(); + + if (! $response->successful()) { + return response()->json([ + 'ok' => false, + 'message' => "HTTP {$response->status()}:{$response->body()}", + 'ms' => $ms, + ]); + } + + $reply = $data['choices'][0]['message']['content'] ?? '(无回复内容)'; + + return response()->json([ + 'ok' => true, + 'message' => trim($reply), + 'ms' => $ms, + 'model' => $data['model'] ?? $provider->model, + ]); + } catch (\Illuminate\Http\Client\ConnectionException $e) { + $ms = (int) ((microtime(true) - $startTime) * 1000); + + return response()->json([ + 'ok' => false, + 'message' => '连接失败:'.$e->getMessage(), + 'ms' => $ms, + ]); + } + } + /** * 删除 AI 厂商配置 * diff --git a/app/Services/AiChatService.php b/app/Services/AiChatService.php index dbaa7b4..d457732 100644 --- a/app/Services/AiChatService.php +++ b/app/Services/AiChatService.php @@ -32,7 +32,7 @@ class AiChatService /** * AI 请求超时时间(秒) */ - private const REQUEST_TIMEOUT = 30; + private const REQUEST_TIMEOUT = 120; // Ollama 本地模型冷启动较慢,给足时间 /** * Redis 上下文 key 前缀 @@ -54,7 +54,7 @@ class AiChatService $charmCross = Sysparam::getValue('charm_cross_sex', '2'); $charmSame = Sysparam::getValue('charm_same_sex', '1'); $charmLimit = Sysparam::getValue('charm_hourly_limit', '20'); - + $levelWarn = Sysparam::getValue('level_warn', '5'); $levelMute = Sysparam::getValue('level_mute', '8'); $levelKick = Sysparam::getValue('level_kick', '10'); @@ -123,8 +123,8 @@ PROMPT; // 将用户消息加入上下文(包含发送者信息) $context[] = [ - 'role' => 'user', - 'content' => "【当前发言人:{$username}】\n" . $message + 'role' => 'user', + 'content' => "【当前发言人:{$username}】\n".$message, ]; // 构建完整的 messages 数组(系统提示 + 对话上下文) diff --git a/resources/views/admin/ai-providers/index.blade.php b/resources/views/admin/ai-providers/index.blade.php index 285410d..4167b5e 100644 --- a/resources/views/admin/ai-providers/index.blade.php +++ b/resources/views/admin/ai-providers/index.blade.php @@ -148,6 +148,9 @@
+
prefix('admin')->name('ad Route::put('/ai-providers/{id}', [\App\Http\Controllers\Admin\AiProviderController::class, 'update'])->name('ai-providers.update'); Route::post('/ai-providers/{id}/toggle', [\App\Http\Controllers\Admin\AiProviderController::class, 'toggleEnabled'])->name('ai-providers.toggle'); Route::post('/ai-providers/{id}/default', [\App\Http\Controllers\Admin\AiProviderController::class, 'setDefault'])->name('ai-providers.default'); + Route::post('/ai-providers/{id}/test', [\App\Http\Controllers\Admin\AiProviderController::class, 'testConnection'])->name('ai-providers.test'); Route::post('/ai-providers/toggle-chatbot', [\App\Http\Controllers\Admin\AiProviderController::class, 'toggleChatBot'])->name('ai-providers.toggle-chatbot'); Route::delete('/ai-providers/{id}', [\App\Http\Controllers\Admin\AiProviderController::class, 'destroy'])->name('ai-providers.destroy');