Files
nl-admin-api/app/Service/AiConfigService.php
2026-08-10 15:51:00 +08:00

228 lines
7.6 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Service;
use App\BaseApp\BaseService;
use App\Models\ai\AiApiKeyModel;
use App\Models\ai\AiPlatformModel;
use App\Service\common\ai\AiGenerationLogService;
use App\Service\common\ai\AiRuntimeConfigService;
use App\Service\common\FieldEncryptService;
/**
* AI 配置管理 Service密钥 CRUD + 运行时选项读写
* 平台/模型以种子数据为主,密钥需后台录入后才能真正调用
*/
class AiConfigService extends BaseService
{
public function __construct()
{
parent::__construct();
$this->model = AiApiKeyModel::class;
$this->selectField = ['id', 'platform_id', 'name', 'remark', 'is_default', 'status', 'sort', 'created_at', 'updated_at'];
$this->queryField = [
'platform_id' => '=',
'name' => 'like',
'status' => '=',
];
$this->orderBy = [
'name' => 'sort',
'sort' => 'desc',
];
}
/**
* 获取 AI 管理页选项(平台卡片 + 当前激活组合)
*/
public function getRuntimeOptions(): array
{
return AiRuntimeConfigService::getInstance()->optionsForConfig();
}
/**
* 保存默认平台/模型/密钥
*/
public function saveRuntime(array $params): array
{
$provider = (string) ($params['provider'] ?? '');
$model = (string) ($params['model'] ?? '');
$apiKeyId = (int) ($params['api_key_id'] ?? 0);
return AiRuntimeConfigService::getInstance()->saveActiveConfig($provider, $model, $apiKeyId);
}
/**
* 密钥列表(卡片展示用,不返回明文密钥)
* 直接查表,避免单例 where 被 update 污染导致列表为空
*/
public function listKeys(): array
{
$items = AiApiKeyModel::where('deleted_at', 0)
->orderByDesc('sort')
->orderByDesc('id')
->get(['id', 'platform_id', 'name', 'remark', 'is_default', 'status', 'sort', 'api_key', 'created_at', 'updated_at'])
->toArray();
$platforms = AiPlatformModel::where('deleted_at', 0)
->get(['id', 'code', 'name', 'logo'])
->keyBy('id')
->toArray();
foreach ($items as &$item) {
$pid = (int) ($item['platform_id'] ?? 0);
$item['platform'] = $platforms[$pid] ?? null;
$item['has_key'] = trim((string) ($item['api_key'] ?? '')) !== '';
unset($item['api_key']);
}
unset($item);
return [
'page' => 1,
'size' => count($items),
'page_count' => 1,
'total' => count($items),
'items' => $items,
];
}
/**
* 平台下拉(密钥表单用)
*/
public function platformOptions(): array
{
return AiPlatformModel::where('deleted_at', 0)
->where('status', 1)
->orderByDesc('sort')
->orderBy('id')
->get(['id', 'code', 'name', 'logo'])
->toArray();
}
/**
* 新增密钥(明文入库前加密)
*/
public function createKey(array $params): mixed
{
$platformId = (int) ($params['platform_id'] ?? 0);
$name = trim((string) ($params['name'] ?? ''));
$apiKey = trim((string) ($params['api_key'] ?? ''));
if ($platformId <= 0) {
$this->utils->errorThrow('请选择所属平台');
}
if ($name === '') {
$this->utils->errorThrow('请填写密钥别名');
}
if ($apiKey === '') {
$this->utils->errorThrow('请填写 API Key');
}
$platform = AiPlatformModel::where('id', $platformId)
->where('deleted_at', 0)
->first();
if (!$platform) {
$this->utils->errorThrow('平台不存在');
}
$isDefault = (int) ($params['is_default'] ?? 0);
if ($isDefault === 1) {
// 同平台只保留一个默认密钥
AiApiKeyModel::where('platform_id', $platformId)
->where('deleted_at', 0)
->update(['is_default' => 0, 'updated_at' => time()]);
}
return $this->insert([
'platform_id' => $platformId,
'name' => $name,
'api_key' => FieldEncryptService::getInstance()->encryptForStorage($apiKey),
'remark' => trim((string) ($params['remark'] ?? '')),
'is_default' => $isDefault,
'status' => (int) ($params['status'] ?? 1),
'sort' => (int) ($params['sort'] ?? 0),
'created_at' => time(),
'updated_at' => 0,
'deleted_at' => 0,
]);
}
/**
* 更新密钥api_key 为空表示不改密钥本身
*/
public function updateKey(int $id, array $params): mixed
{
$info = AiApiKeyModel::where('id', $id)->where('deleted_at', 0)->first();
if (!$info) {
$this->utils->notFound('密钥不存在');
}
$data = [];
if (array_key_exists('name', $params)) {
$name = trim((string) $params['name']);
if ($name === '') {
$this->utils->errorThrow('密钥别名不能为空');
}
$data['name'] = $name;
}
if (array_key_exists('remark', $params)) {
$data['remark'] = trim((string) $params['remark']);
}
if (array_key_exists('status', $params)) {
$data['status'] = (int) $params['status'];
}
if (array_key_exists('sort', $params)) {
$data['sort'] = (int) $params['sort'];
}
if (array_key_exists('platform_id', $params)) {
$platformId = (int) $params['platform_id'];
if ($platformId <= 0) {
$this->utils->errorThrow('请选择所属平台');
}
$data['platform_id'] = $platformId;
}
$platformId = (int) ($data['platform_id'] ?? $info->platform_id);
if (array_key_exists('is_default', $params)) {
$isDefault = (int) $params['is_default'];
$data['is_default'] = $isDefault;
if ($isDefault === 1) {
AiApiKeyModel::where('platform_id', $platformId)
->where('deleted_at', 0)
->where('id', '<>', $id)
->update(['is_default' => 0, 'updated_at' => time()]);
}
}
$apiKey = trim((string) ($params['api_key'] ?? ''));
if ($apiKey !== '') {
$data['api_key'] = FieldEncryptService::getInstance()->encryptForStorage($apiKey);
}
if (empty($data)) {
return true;
}
$data['updated_at'] = time();
// 直接 update避免 BaseService::save 污染单例 where 导致后续列表为空
return AiApiKeyModel::where('id', $id)->where('deleted_at', 0)->update($data);
}
/**
* 软删除密钥
*/
public function deleteKeys(array $ids): mixed
{
$ids = array_values(array_filter(array_map('intval', $ids)));
if (empty($ids)) {
$this->utils->errorThrow('参数错误');
}
return AiApiKeyModel::whereIn('id', $ids)->where('deleted_at', 0)->update([
'deleted_at' => time(),
'updated_at' => time(),
]);
}
/**
* AI 生成历史列表
*/
public function generationList(): array
{
return AiGenerationLogService::getInstance()->getPageListForAdmin();
}
/**
* AI 生成历史详情
*/
public function generationDetail(int $id): array
{
return AiGenerationLogService::getInstance()->getDetailForAdmin($id);
}
}