bug fix
This commit is contained in:
parent
383e73c2cd
commit
74790f6180
5 changed files with 284 additions and 132 deletions
|
|
@ -33,32 +33,121 @@ public function __construct(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 檢查客戶是否有活躍的令牌
|
* 獲取客戶列表
|
||||||
*/
|
*/
|
||||||
private function hasActiveTokens(Client $client): bool
|
public function index(): JsonResponse
|
||||||
{
|
{
|
||||||
$pattern = 'auth_token:*';
|
try {
|
||||||
$keys = Redis::keys($pattern);
|
$clients = Client::with('llmProvider:id,name,service_name')
|
||||||
|
->select([
|
||||||
|
'id',
|
||||||
|
'name',
|
||||||
|
'llm_provider_id',
|
||||||
|
'rate_limit',
|
||||||
|
'timeout',
|
||||||
|
'status',
|
||||||
|
'created_at',
|
||||||
|
])
|
||||||
|
->get();
|
||||||
|
|
||||||
foreach ($keys as $key) {
|
return $this->success($clients);
|
||||||
$data = Redis::get($key);
|
|
||||||
if ($data) {
|
} catch (\Exception $e) {
|
||||||
$tokenData = json_decode($data, true);
|
Log::error('Error fetching clients', [
|
||||||
if ($tokenData &&
|
'error' => $e->getMessage(),
|
||||||
$tokenData['client_id'] === $client->id &&
|
'trace' => $e->getTraceAsString(),
|
||||||
now()->isBefore($tokenData['expires_at'])) {
|
]);
|
||||||
return true;
|
|
||||||
}
|
return $this->error(
|
||||||
}
|
ErrorCode::SERVER_ERROR,
|
||||||
|
ErrorCode::getMessage(ErrorCode::SERVER_ERROR)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 停用客戶
|
* 新增客戶
|
||||||
*/
|
*/
|
||||||
public function deactivate(int $id): JsonResponse
|
public function store(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$validated = $request->validate([
|
||||||
|
'name' => [
|
||||||
|
'required',
|
||||||
|
'string',
|
||||||
|
'max:100',
|
||||||
|
'unique:clients',
|
||||||
|
],
|
||||||
|
'llm_provider_id' => [
|
||||||
|
'required',
|
||||||
|
'integer',
|
||||||
|
'exists:llm_providers,id',
|
||||||
|
],
|
||||||
|
'rate_limit' => [
|
||||||
|
'required',
|
||||||
|
'integer',
|
||||||
|
'min:1',
|
||||||
|
'max:1000',
|
||||||
|
],
|
||||||
|
'timeout' => [
|
||||||
|
'required',
|
||||||
|
'integer',
|
||||||
|
'min:1',
|
||||||
|
'max:300',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$validated['status'] = Client::STATUS_ACTIVE;
|
||||||
|
$client = Client::create($validated);
|
||||||
|
|
||||||
|
// 加載 LLM 提供商信息
|
||||||
|
$client->load('llmProvider:id,name,service_name');
|
||||||
|
|
||||||
|
$this->logService->logOperation(
|
||||||
|
'admin',
|
||||||
|
$this->admin->id,
|
||||||
|
"Created client: {$client->name}"
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->created([
|
||||||
|
'id' => $client->id,
|
||||||
|
'name' => $client->name,
|
||||||
|
'llm_provider_id' => $client->llm_provider_id,
|
||||||
|
'llm_provider' => [
|
||||||
|
'id' => $client->llmProvider->id,
|
||||||
|
'name' => $client->llmProvider->name,
|
||||||
|
'service_name' => $client->llmProvider->service_name,
|
||||||
|
],
|
||||||
|
'rate_limit' => $client->rate_limit,
|
||||||
|
'timeout' => $client->timeout,
|
||||||
|
'status' => $client->status,
|
||||||
|
'created_at' => $client->created_at->toIso8601String(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
} catch (ValidationException $e) {
|
||||||
|
return $this->error(
|
||||||
|
ErrorCode::VALIDATION_ERROR,
|
||||||
|
ErrorCode::getMessage(ErrorCode::VALIDATION_ERROR),
|
||||||
|
$e->errors()
|
||||||
|
);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Error creating client', [
|
||||||
|
'error' => $e->getMessage(),
|
||||||
|
'trace' => $e->getTraceAsString(),
|
||||||
|
'request_data' => $request->all(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this->error(
|
||||||
|
ErrorCode::SERVER_ERROR,
|
||||||
|
ErrorCode::getMessage(ErrorCode::SERVER_ERROR)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改客戶
|
||||||
|
*/
|
||||||
|
public function update(Request $request, int $id): JsonResponse
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$client = Client::findOrFail($id);
|
$client = Client::findOrFail($id);
|
||||||
|
|
@ -70,32 +159,91 @@ public function deactivate(int $id): JsonResponse
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->hasActiveTokens($client)) {
|
$validated = $request->validate([
|
||||||
return $this->error(
|
'name' => [
|
||||||
ErrorCode::CLIENT_HAS_ACTIVE_TOKENS,
|
'required',
|
||||||
'該客戶有活躍的認證令牌,無法停用。'
|
'string',
|
||||||
);
|
'max:100',
|
||||||
|
"unique:clients,name,{$id}",
|
||||||
|
],
|
||||||
|
'llm_provider_id' => [
|
||||||
|
'required',
|
||||||
|
'integer',
|
||||||
|
'exists:llm_providers,id',
|
||||||
|
],
|
||||||
|
'rate_limit' => [
|
||||||
|
'required',
|
||||||
|
'integer',
|
||||||
|
'min:1',
|
||||||
|
'max:1000',
|
||||||
|
],
|
||||||
|
'timeout' => [
|
||||||
|
'required',
|
||||||
|
'integer',
|
||||||
|
'min:1',
|
||||||
|
'max:300',
|
||||||
|
],
|
||||||
|
'status' => [
|
||||||
|
'required',
|
||||||
|
'string',
|
||||||
|
'in:active,inactive',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 如果要停用客戶,檢查是否有活躍的令牌
|
||||||
|
if ($validated['status'] === Client::STATUS_INACTIVE &&
|
||||||
|
$client->status === Client::STATUS_ACTIVE) {
|
||||||
|
if ($this->hasActiveTokens($client)) {
|
||||||
|
return $this->error(
|
||||||
|
ErrorCode::CLIENT_HAS_ACTIVE_TOKENS,
|
||||||
|
'該客戶有活躍的認證令牌,無法停用。'
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$client->update(['status' => Client::STATUS_INACTIVE]);
|
$client->update($validated);
|
||||||
|
|
||||||
|
// 加載 LLM 提供商信息
|
||||||
|
$client->load('llmProvider:id,name,service_name');
|
||||||
|
|
||||||
$this->logService->logOperation(
|
$this->logService->logOperation(
|
||||||
'admin',
|
'admin',
|
||||||
$this->admin->id,
|
$this->admin->id,
|
||||||
"Deactivated client: {$client->name}"
|
"Updated client: {$client->name}"
|
||||||
);
|
);
|
||||||
|
|
||||||
return $this->success();
|
return $this->success([
|
||||||
|
'id' => $client->id,
|
||||||
|
'name' => $client->name,
|
||||||
|
'llm_provider_id' => $client->llm_provider_id,
|
||||||
|
'llm_provider' => [
|
||||||
|
'id' => $client->llmProvider->id,
|
||||||
|
'name' => $client->llmProvider->name,
|
||||||
|
'service_name' => $client->llmProvider->service_name,
|
||||||
|
],
|
||||||
|
'rate_limit' => $client->rate_limit,
|
||||||
|
'timeout' => $client->timeout,
|
||||||
|
'status' => $client->status,
|
||||||
|
'updated_at' => $client->updated_at->toIso8601String(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
} catch (ValidationException $e) {
|
||||||
|
return $this->error(
|
||||||
|
ErrorCode::VALIDATION_ERROR,
|
||||||
|
ErrorCode::getMessage(ErrorCode::VALIDATION_ERROR),
|
||||||
|
$e->errors()
|
||||||
|
);
|
||||||
} catch (ModelNotFoundException $e) {
|
} catch (ModelNotFoundException $e) {
|
||||||
return $this->error(
|
return $this->error(
|
||||||
ErrorCode::CLIENT_NOT_FOUND,
|
ErrorCode::CLIENT_NOT_FOUND,
|
||||||
ErrorCode::getMessage(ErrorCode::CLIENT_NOT_FOUND)
|
ErrorCode::getMessage(ErrorCode::CLIENT_NOT_FOUND)
|
||||||
);
|
);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
Log::error('Error deactivating client', [
|
Log::error('Error updating client', [
|
||||||
'error' => $e->getMessage(),
|
'error' => $e->getMessage(),
|
||||||
'trace' => $e->getTraceAsString(),
|
'trace' => $e->getTraceAsString(),
|
||||||
|
'client_id' => $id,
|
||||||
|
'request_data' => $request->all(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $this->error(
|
return $this->error(
|
||||||
|
|
@ -135,7 +283,7 @@ public function destroy(int $id): JsonResponse
|
||||||
"Deleted client: {$client->name}"
|
"Deleted client: {$client->name}"
|
||||||
);
|
);
|
||||||
|
|
||||||
return $this->success();
|
return $this->success(null, '客戶已刪除。');
|
||||||
|
|
||||||
} catch (ModelNotFoundException $e) {
|
} catch (ModelNotFoundException $e) {
|
||||||
return $this->error(
|
return $this->error(
|
||||||
|
|
@ -146,6 +294,7 @@ public function destroy(int $id): JsonResponse
|
||||||
Log::error('Error deleting client', [
|
Log::error('Error deleting client', [
|
||||||
'error' => $e->getMessage(),
|
'error' => $e->getMessage(),
|
||||||
'trace' => $e->getTraceAsString(),
|
'trace' => $e->getTraceAsString(),
|
||||||
|
'client_id' => $id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $this->error(
|
return $this->error(
|
||||||
|
|
@ -177,7 +326,7 @@ public function generateAuthToken(int $id): JsonResponse
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$token = $this->tokenService->generateAuthToken($client);
|
$result = $this->tokenService->generateAuthToken($client);
|
||||||
|
|
||||||
$this->logService->logOperation(
|
$this->logService->logOperation(
|
||||||
'admin',
|
'admin',
|
||||||
|
|
@ -185,15 +334,7 @@ public function generateAuthToken(int $id): JsonResponse
|
||||||
"Generated auth token for client: {$client->name}"
|
"Generated auth token for client: {$client->name}"
|
||||||
);
|
);
|
||||||
|
|
||||||
return $this->success([
|
return $this->success($result);
|
||||||
'auth_token' => $token['token'],
|
|
||||||
'expires_at' => $token['expires_at'],
|
|
||||||
'client' => [
|
|
||||||
'id' => $client->id,
|
|
||||||
'name' => $client->name,
|
|
||||||
'status' => $client->status,
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
} catch (ModelNotFoundException $e) {
|
} catch (ModelNotFoundException $e) {
|
||||||
return $this->error(
|
return $this->error(
|
||||||
|
|
@ -204,6 +345,7 @@ public function generateAuthToken(int $id): JsonResponse
|
||||||
Log::error('Error generating auth token', [
|
Log::error('Error generating auth token', [
|
||||||
'error' => $e->getMessage(),
|
'error' => $e->getMessage(),
|
||||||
'trace' => $e->getTraceAsString(),
|
'trace' => $e->getTraceAsString(),
|
||||||
|
'client_id' => $id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $this->error(
|
return $this->error(
|
||||||
|
|
@ -212,4 +354,27 @@ public function generateAuthToken(int $id): JsonResponse
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 檢查客戶是否有活躍的令牌
|
||||||
|
*/
|
||||||
|
private function hasActiveTokens(Client $client): bool
|
||||||
|
{
|
||||||
|
$pattern = 'auth_token:*';
|
||||||
|
$keys = Redis::keys($pattern);
|
||||||
|
|
||||||
|
foreach ($keys as $key) {
|
||||||
|
$data = Redis::get($key);
|
||||||
|
if ($data) {
|
||||||
|
$tokenData = json_decode($data, true);
|
||||||
|
if ($tokenData &&
|
||||||
|
$tokenData['client_id'] === $client->id &&
|
||||||
|
now()->isBefore($tokenData['expires_at'])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
use App\Constants\ErrorCode;
|
use App\Constants\ErrorCode;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Admin;
|
||||||
use App\Models\LlmProvider;
|
use App\Models\LlmProvider;
|
||||||
use App\Services\LogService;
|
use App\Services\LogService;
|
||||||
use App\Traits\ApiResponse;
|
use App\Traits\ApiResponse;
|
||||||
|
|
@ -19,48 +20,31 @@ class LlmProviderController extends Controller
|
||||||
{
|
{
|
||||||
use ApiResponse;
|
use ApiResponse;
|
||||||
|
|
||||||
|
private Admin $admin;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly LogService $logService,
|
private readonly LogService $logService,
|
||||||
) {}
|
Request $request
|
||||||
|
) {
|
||||||
|
$this->admin = $request->admin;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 LLM 提供商列表
|
* 獲取 LLM 提供商列表
|
||||||
*
|
|
||||||
* @param Request $request
|
|
||||||
* @return JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function index(Request $request): JsonResponse
|
public function index(): JsonResponse
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$perPage = $request->input('per_page', 15);
|
$providers = LlmProvider::select([
|
||||||
$perPage = min(max($perPage, 1), 100);
|
'id',
|
||||||
$search = $request->input('search');
|
'name',
|
||||||
$status = $request->input('status');
|
'service_name',
|
||||||
|
'api_url',
|
||||||
|
'status',
|
||||||
|
'created_at',
|
||||||
|
])->get();
|
||||||
|
|
||||||
$query = LlmProvider::query()->orderBy('created_at', 'desc');
|
return $this->success($providers);
|
||||||
|
|
||||||
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) {
|
} catch (\Exception $e) {
|
||||||
Log::error('Error fetching LLM providers', [
|
Log::error('Error fetching LLM providers', [
|
||||||
|
|
@ -76,10 +60,7 @@ public function index(Request $request): JsonResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建 LLM 提供商
|
* 新增 LLM 提供商
|
||||||
*
|
|
||||||
* @param Request $request
|
|
||||||
* @return JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function store(Request $request): JsonResponse
|
public function store(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
|
|
@ -90,38 +71,42 @@ public function store(Request $request): JsonResponse
|
||||||
'string',
|
'string',
|
||||||
'max:100',
|
'max:100',
|
||||||
'unique:llm_providers',
|
'unique:llm_providers',
|
||||||
'regex:/^[\w\-\s]+$/u',
|
|
||||||
],
|
],
|
||||||
'service_name' => [
|
'service_name' => [
|
||||||
'required',
|
'required',
|
||||||
'string',
|
'string',
|
||||||
'max:100',
|
'max:100',
|
||||||
'regex:/^[\w\-]+$/u',
|
|
||||||
],
|
],
|
||||||
'api_url' => [
|
'api_url' => [
|
||||||
'required',
|
'required',
|
||||||
'string',
|
'string',
|
||||||
'max:255',
|
|
||||||
'url',
|
'url',
|
||||||
'starts_with:https',
|
'max:255',
|
||||||
|
],
|
||||||
|
'api_token' => [
|
||||||
|
'required',
|
||||||
|
'string',
|
||||||
|
'max:255',
|
||||||
],
|
],
|
||||||
'api_token' => 'required|string|max:255',
|
|
||||||
], [
|
|
||||||
'name.regex' => '提供商名称只能包含字母、数字、下划线、横线和空格。',
|
|
||||||
'service_name.regex' => '服务名称只能包含字母、数字、下划线和横线。',
|
|
||||||
'api_url.starts_with' => 'API URL 必须使用 HTTPS 协议。',
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$validated['status'] = 'active';
|
$validated['status'] = LlmProvider::STATUS_ACTIVE;
|
||||||
$provider = LlmProvider::create($validated);
|
$provider = LlmProvider::create($validated);
|
||||||
|
|
||||||
$this->logService->logOperation(
|
$this->logService->logOperation(
|
||||||
'admin',
|
'admin',
|
||||||
$request->admin->id,
|
$this->admin->id,
|
||||||
"Created LLM provider: {$provider->name}"
|
"Created LLM provider: {$provider->name}"
|
||||||
);
|
);
|
||||||
|
|
||||||
return $this->created($provider);
|
return $this->created([
|
||||||
|
'id' => $provider->id,
|
||||||
|
'name' => $provider->name,
|
||||||
|
'service_name' => $provider->service_name,
|
||||||
|
'api_url' => $provider->api_url,
|
||||||
|
'api_token' => $provider->api_token,
|
||||||
|
'created_at' => $provider->created_at->toIso8601String(),
|
||||||
|
]);
|
||||||
|
|
||||||
} catch (ValidationException $e) {
|
} catch (ValidationException $e) {
|
||||||
return $this->error(
|
return $this->error(
|
||||||
|
|
@ -144,57 +129,57 @@ public function store(Request $request): JsonResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新 LLM 提供商
|
* 修改 LLM 提供商
|
||||||
*
|
|
||||||
* @param Request $request
|
|
||||||
* @param int $id
|
|
||||||
* @return JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function update(Request $request, int $id): JsonResponse
|
public function update(Request $request, int $id): JsonResponse
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$provider = LlmProvider::findOrFail($id);
|
$provider = LlmProvider::findOrFail($id);
|
||||||
|
|
||||||
|
if (!$this->admin->canManageLlmProvider($provider->id)) {
|
||||||
|
return $this->error(
|
||||||
|
ErrorCode::FORBIDDEN,
|
||||||
|
'您無權管理該 LLM 提供商。'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
$validated = $request->validate([
|
$validated = $request->validate([
|
||||||
'name' => [
|
'name' => [
|
||||||
'required',
|
'required',
|
||||||
'string',
|
'string',
|
||||||
'max:100',
|
'max:100',
|
||||||
"unique:llm_providers,name,{$id}",
|
"unique:llm_providers,name,{$id}",
|
||||||
'regex:/^[\w\-\s]+$/u',
|
|
||||||
],
|
],
|
||||||
'service_name' => [
|
'service_name' => [
|
||||||
'required',
|
'required',
|
||||||
'string',
|
'string',
|
||||||
'max:100',
|
'max:100',
|
||||||
'regex:/^[\w\-]+$/u',
|
|
||||||
],
|
],
|
||||||
'api_url' => [
|
'api_url' => [
|
||||||
'required',
|
'required',
|
||||||
'string',
|
'string',
|
||||||
'max:255',
|
|
||||||
'url',
|
'url',
|
||||||
'starts_with:https',
|
'max:255',
|
||||||
|
],
|
||||||
|
'api_token' => [
|
||||||
|
'required',
|
||||||
|
'string',
|
||||||
|
'max:255',
|
||||||
],
|
],
|
||||||
'api_token' => 'required|string|max:255',
|
|
||||||
'status' => [
|
'status' => [
|
||||||
'required',
|
'required',
|
||||||
'string',
|
'string',
|
||||||
'in:active,inactive',
|
'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 ($validated['status'] === LlmProvider::STATUS_INACTIVE &&
|
||||||
|
$provider->status === LlmProvider::STATUS_ACTIVE) {
|
||||||
if ($provider->clients()->exists()) {
|
if ($provider->clients()->exists()) {
|
||||||
return $this->error(
|
return $this->error(
|
||||||
ErrorCode::RESOURCE_IN_USE,
|
ErrorCode::RESOURCE_IN_USE,
|
||||||
'该提供商正在被客户使用,无法停用。'
|
'該提供商正在被客戶使用,無法停用。'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -203,11 +188,18 @@ public function update(Request $request, int $id): JsonResponse
|
||||||
|
|
||||||
$this->logService->logOperation(
|
$this->logService->logOperation(
|
||||||
'admin',
|
'admin',
|
||||||
$request->admin->id,
|
$this->admin->id,
|
||||||
"Updated LLM provider: {$provider->name}"
|
"Updated LLM provider: {$provider->name}"
|
||||||
);
|
);
|
||||||
|
|
||||||
return $this->success($provider);
|
return $this->success([
|
||||||
|
'id' => $provider->id,
|
||||||
|
'name' => $provider->name,
|
||||||
|
'service_name' => $provider->service_name,
|
||||||
|
'api_url' => $provider->api_url,
|
||||||
|
'api_token' => $provider->api_token,
|
||||||
|
'updated_at' => $provider->updated_at->toIso8601String(),
|
||||||
|
]);
|
||||||
|
|
||||||
} catch (ValidationException $e) {
|
} catch (ValidationException $e) {
|
||||||
return $this->error(
|
return $this->error(
|
||||||
|
|
@ -236,22 +228,25 @@ public function update(Request $request, int $id): JsonResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除 LLM 提供商
|
* 刪除 LLM 提供商
|
||||||
*
|
|
||||||
* @param Request $request
|
|
||||||
* @param int $id
|
|
||||||
* @return JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function destroy(Request $request, int $id): JsonResponse
|
public function destroy(int $id): JsonResponse
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$provider = LlmProvider::findOrFail($id);
|
$provider = LlmProvider::findOrFail($id);
|
||||||
|
|
||||||
// 检查是否有客户正在使用
|
if (!$this->admin->canManageLlmProvider($provider->id)) {
|
||||||
|
return $this->error(
|
||||||
|
ErrorCode::FORBIDDEN,
|
||||||
|
'您無權管理該 LLM 提供商。'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 檢查是否有客戶在使用
|
||||||
if ($provider->clients()->exists()) {
|
if ($provider->clients()->exists()) {
|
||||||
return $this->error(
|
return $this->error(
|
||||||
ErrorCode::RESOURCE_IN_USE,
|
ErrorCode::RESOURCE_IN_USE,
|
||||||
'该提供商正在被客户使用,无法删除。'
|
'該提供商正在被客戶使用,無法刪除。'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -260,11 +255,11 @@ public function destroy(Request $request, int $id): JsonResponse
|
||||||
|
|
||||||
$this->logService->logOperation(
|
$this->logService->logOperation(
|
||||||
'admin',
|
'admin',
|
||||||
$request->admin->id,
|
$this->admin->id,
|
||||||
"Deleted LLM provider: {$providerName}"
|
"Deleted LLM provider: {$providerName}"
|
||||||
);
|
);
|
||||||
|
|
||||||
return $this->success(null, '提供商已删除。');
|
return $this->success(null, 'LLM 提供商已刪除。');
|
||||||
|
|
||||||
} catch (ModelNotFoundException $e) {
|
} catch (ModelNotFoundException $e) {
|
||||||
return $this->error(
|
return $this->error(
|
||||||
|
|
|
||||||
|
|
@ -49,11 +49,7 @@ public function getAccessToken(Request $request): JsonResponse
|
||||||
|
|
||||||
$result = $this->tokenService->generateAccessToken($authTokenData);
|
$result = $this->tokenService->generateAccessToken($authTokenData);
|
||||||
|
|
||||||
return $this->success([
|
return $this->success($result);
|
||||||
'access_token' => $result['access_token'],
|
|
||||||
'expires_in' => $result['expires_in'],
|
|
||||||
'token_type' => $result['token_type'],
|
|
||||||
]);
|
|
||||||
|
|
||||||
} catch (ValidationException $e) {
|
} catch (ValidationException $e) {
|
||||||
return $this->error(
|
return $this->error(
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,7 @@ public function __construct(
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送 LLM 请求
|
* 發送 LLM 請求
|
||||||
*
|
|
||||||
* @param Request $request
|
|
||||||
* @return JsonResponse
|
|
||||||
*/
|
*/
|
||||||
public function request(Request $request): JsonResponse
|
public function request(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
|
|
@ -47,7 +44,6 @@ public function request(Request $request): JsonResponse
|
||||||
|
|
||||||
return $this->success([
|
return $this->success([
|
||||||
'response' => $result['response'],
|
'response' => $result['response'],
|
||||||
'usage' => $result['usage'],
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
} catch (ValidationException $e) {
|
} catch (ValidationException $e) {
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ public function __construct(
|
||||||
/**
|
/**
|
||||||
* 生成認證令牌
|
* 生成認證令牌
|
||||||
*
|
*
|
||||||
* @return array{token: string, expires_at: string}
|
* @return array{auth_token: string, expires_at: string, client_id: int}
|
||||||
*/
|
*/
|
||||||
public function generateAuthToken(Client $client, ?int $expiresInHours = null): array
|
public function generateAuthToken(Client $client, ?int $expiresInHours = null): array
|
||||||
{
|
{
|
||||||
|
|
@ -56,8 +56,9 @@ public function generateAuthToken(Client $client, ?int $expiresInHours = null):
|
||||||
);
|
);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'token' => $token,
|
'auth_token' => $token,
|
||||||
'expires_at' => $expiresAt->toIso8601String(),
|
'expires_at' => $expiresAt->toIso8601String(),
|
||||||
|
'client_id' => $client->id,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,7 +92,7 @@ public function validateAuthToken(string $token): ?array
|
||||||
/**
|
/**
|
||||||
* 生成訪問令牌
|
* 生成訪問令牌
|
||||||
*
|
*
|
||||||
* @return array{access_token: string, expires_in: int, token_type: string}
|
* @return array{access_token: string, expires_in: int}
|
||||||
*/
|
*/
|
||||||
public function generateAccessToken(array $authTokenData): array
|
public function generateAccessToken(array $authTokenData): array
|
||||||
{
|
{
|
||||||
|
|
@ -118,7 +119,6 @@ public function generateAccessToken(array $authTokenData): array
|
||||||
return [
|
return [
|
||||||
'access_token' => $accessToken,
|
'access_token' => $accessToken,
|
||||||
'expires_in' => self::ACCESS_TOKEN_TTL,
|
'expires_in' => self::ACCESS_TOKEN_TTL,
|
||||||
'token_type' => 'Bearer',
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue