287 lines
9 KiB
PHP
287 lines
9 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace App\Http\Controllers\Api\Admin;
|
||
|
||
use App\Constants\ErrorCode;
|
||
use App\Http\Controllers\Controller;
|
||
use App\Models\LlmProvider;
|
||
use App\Services\LogService;
|
||
use App\Traits\ApiResponse;
|
||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||
use Illuminate\Http\JsonResponse;
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Support\Facades\Log;
|
||
use Illuminate\Validation\ValidationException;
|
||
|
||
class LlmProviderController extends Controller
|
||
{
|
||
use ApiResponse;
|
||
|
||
public function __construct(
|
||
private readonly LogService $logService,
|
||
) {}
|
||
|
||
/**
|
||
* 获取 LLM 提供商列表
|
||
*
|
||
* @param Request $request
|
||
* @return JsonResponse
|
||
*/
|
||
public function index(Request $request): JsonResponse
|
||
{
|
||
try {
|
||
$perPage = $request->input('per_page', 15);
|
||
$perPage = min(max($perPage, 1), 100);
|
||
$search = $request->input('search');
|
||
$status = $request->input('status');
|
||
|
||
$query = LlmProvider::query()->orderBy('created_at', 'desc');
|
||
|
||
if ($search) {
|
||
$query->where(function ($q) use ($search) {
|
||
$q->where('name', 'like', "%{$search}%")
|
||
->orWhere('service_name', 'like', "%{$search}%");
|
||
});
|
||
}
|
||
|
||
if ($status && in_array($status, ['active', 'inactive'])) {
|
||
$query->where('status', $status);
|
||
}
|
||
|
||
$providers = $query->paginate($perPage);
|
||
|
||
return $this->paginate(
|
||
$providers->items(),
|
||
[
|
||
'current_page' => $providers->currentPage(),
|
||
'per_page' => $providers->perPage(),
|
||
'total' => $providers->total(),
|
||
'total_pages' => $providers->lastPage(),
|
||
]
|
||
);
|
||
|
||
} catch (\Exception $e) {
|
||
Log::error('Error fetching LLM providers', [
|
||
'error' => $e->getMessage(),
|
||
'trace' => $e->getTraceAsString(),
|
||
]);
|
||
|
||
return $this->error(
|
||
ErrorCode::SERVER_ERROR,
|
||
ErrorCode::getMessage(ErrorCode::SERVER_ERROR)
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 创建 LLM 提供商
|
||
*
|
||
* @param Request $request
|
||
* @return JsonResponse
|
||
*/
|
||
public function store(Request $request): JsonResponse
|
||
{
|
||
try {
|
||
$validated = $request->validate([
|
||
'name' => [
|
||
'required',
|
||
'string',
|
||
'max:100',
|
||
'unique:llm_providers',
|
||
'regex:/^[\w\-\s]+$/u',
|
||
],
|
||
'service_name' => [
|
||
'required',
|
||
'string',
|
||
'max:100',
|
||
'regex:/^[\w\-]+$/u',
|
||
],
|
||
'api_url' => [
|
||
'required',
|
||
'string',
|
||
'max:255',
|
||
'url',
|
||
'starts_with:https',
|
||
],
|
||
'api_token' => 'required|string|max:255',
|
||
], [
|
||
'name.regex' => '提供商名称只能包含字母、数字、下划线、横线和空格。',
|
||
'service_name.regex' => '服务名称只能包含字母、数字、下划线和横线。',
|
||
'api_url.starts_with' => 'API URL 必须使用 HTTPS 协议。',
|
||
]);
|
||
|
||
$validated['status'] = 'active';
|
||
$provider = LlmProvider::create($validated);
|
||
|
||
$this->logService->logOperation(
|
||
'admin',
|
||
$request->admin->id,
|
||
"Created LLM provider: {$provider->name}"
|
||
);
|
||
|
||
return $this->created($provider);
|
||
|
||
} catch (ValidationException $e) {
|
||
return $this->error(
|
||
ErrorCode::VALIDATION_ERROR,
|
||
ErrorCode::getMessage(ErrorCode::VALIDATION_ERROR),
|
||
$e->errors()
|
||
);
|
||
} catch (\Exception $e) {
|
||
Log::error('Error creating LLM provider', [
|
||
'error' => $e->getMessage(),
|
||
'trace' => $e->getTraceAsString(),
|
||
'request_data' => $request->except(['api_token']),
|
||
]);
|
||
|
||
return $this->error(
|
||
ErrorCode::SERVER_ERROR,
|
||
ErrorCode::getMessage(ErrorCode::SERVER_ERROR)
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 更新 LLM 提供商
|
||
*
|
||
* @param Request $request
|
||
* @param int $id
|
||
* @return JsonResponse
|
||
*/
|
||
public function update(Request $request, int $id): JsonResponse
|
||
{
|
||
try {
|
||
$provider = LlmProvider::findOrFail($id);
|
||
|
||
$validated = $request->validate([
|
||
'name' => [
|
||
'required',
|
||
'string',
|
||
'max:100',
|
||
"unique:llm_providers,name,{$id}",
|
||
'regex:/^[\w\-\s]+$/u',
|
||
],
|
||
'service_name' => [
|
||
'required',
|
||
'string',
|
||
'max:100',
|
||
'regex:/^[\w\-]+$/u',
|
||
],
|
||
'api_url' => [
|
||
'required',
|
||
'string',
|
||
'max:255',
|
||
'url',
|
||
'starts_with:https',
|
||
],
|
||
'api_token' => 'required|string|max:255',
|
||
'status' => [
|
||
'required',
|
||
'string',
|
||
'in:active,inactive',
|
||
],
|
||
], [
|
||
'name.regex' => '提供商名称只能包含字母、数字、下划线、横线和空格。',
|
||
'service_name.regex' => '服务名称只能包含字母、数字、下划线和横线。',
|
||
'api_url.starts_with' => 'API URL 必须使用 HTTPS 协议。',
|
||
'status.in' => '状态只能是 active 或 inactive。',
|
||
]);
|
||
|
||
// 如果状态改为 inactive,检查是否有客户正在使用
|
||
if ($validated['status'] === 'inactive' && $provider->status === 'active') {
|
||
if ($provider->clients()->exists()) {
|
||
return $this->error(
|
||
ErrorCode::RESOURCE_IN_USE,
|
||
'该提供商正在被客户使用,无法停用。'
|
||
);
|
||
}
|
||
}
|
||
|
||
$provider->update($validated);
|
||
|
||
$this->logService->logOperation(
|
||
'admin',
|
||
$request->admin->id,
|
||
"Updated LLM provider: {$provider->name}"
|
||
);
|
||
|
||
return $this->success($provider);
|
||
|
||
} catch (ValidationException $e) {
|
||
return $this->error(
|
||
ErrorCode::VALIDATION_ERROR,
|
||
ErrorCode::getMessage(ErrorCode::VALIDATION_ERROR),
|
||
$e->errors()
|
||
);
|
||
} catch (ModelNotFoundException $e) {
|
||
return $this->error(
|
||
ErrorCode::RESOURCE_NOT_FOUND,
|
||
ErrorCode::getMessage(ErrorCode::RESOURCE_NOT_FOUND)
|
||
);
|
||
} catch (\Exception $e) {
|
||
Log::error('Error updating LLM provider', [
|
||
'error' => $e->getMessage(),
|
||
'trace' => $e->getTraceAsString(),
|
||
'provider_id' => $id,
|
||
'request_data' => $request->except(['api_token']),
|
||
]);
|
||
|
||
return $this->error(
|
||
ErrorCode::SERVER_ERROR,
|
||
ErrorCode::getMessage(ErrorCode::SERVER_ERROR)
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 删除 LLM 提供商
|
||
*
|
||
* @param Request $request
|
||
* @param int $id
|
||
* @return JsonResponse
|
||
*/
|
||
public function destroy(Request $request, int $id): JsonResponse
|
||
{
|
||
try {
|
||
$provider = LlmProvider::findOrFail($id);
|
||
|
||
// 检查是否有客户正在使用
|
||
if ($provider->clients()->exists()) {
|
||
return $this->error(
|
||
ErrorCode::RESOURCE_IN_USE,
|
||
'该提供商正在被客户使用,无法删除。'
|
||
);
|
||
}
|
||
|
||
$providerName = $provider->name;
|
||
$provider->delete();
|
||
|
||
$this->logService->logOperation(
|
||
'admin',
|
||
$request->admin->id,
|
||
"Deleted LLM provider: {$providerName}"
|
||
);
|
||
|
||
return $this->success(null, '提供商已删除。');
|
||
|
||
} catch (ModelNotFoundException $e) {
|
||
return $this->error(
|
||
ErrorCode::RESOURCE_NOT_FOUND,
|
||
ErrorCode::getMessage(ErrorCode::RESOURCE_NOT_FOUND)
|
||
);
|
||
} catch (\Exception $e) {
|
||
Log::error('Error deleting LLM provider', [
|
||
'error' => $e->getMessage(),
|
||
'trace' => $e->getTraceAsString(),
|
||
'provider_id' => $id,
|
||
]);
|
||
|
||
return $this->error(
|
||
ErrorCode::SERVER_ERROR,
|
||
ErrorCode::getMessage(ErrorCode::SERVER_ERROR)
|
||
);
|
||
}
|
||
}
|
||
}
|