diff --git a/app/Http/Controllers/Api/SystemController.php b/app/Http/Controllers/Api/SystemController.php index 1f86bd8d8..ea16400db 100755 --- a/app/Http/Controllers/Api/SystemController.php +++ b/app/Http/Controllers/Api/SystemController.php @@ -44,7 +44,7 @@ class SystemController extends AbstractController * @apiParam {String} type * - get: 获取(默认) * - all: 获取所有(需要管理员权限) - * - save: 保存设置(参数:['reg', 'reg_identity', 'reg_invite', 'temp_account_alias', 'login_code', 'password_policy', 'project_invite', 'chat_information', 'anon_message', 'voice2text', 'translation', 'convert_video', 'compress_video', 'e2e_message', 'auto_archived', 'archived_day', 'task_visible', 'task_default_time', 'all_group_mute', 'all_group_autoin', 'user_private_chat_mute', 'user_group_chat_mute', 'system_alias', 'system_welcome', 'image_compress', 'image_quality', 'image_save_local']) + * - save: 保存设置(参数:['reg', 'reg_identity', 'reg_invite', 'temp_account_alias', 'login_code', 'password_policy', 'project_invite', 'chat_information', 'anon_message', 'convert_video', 'compress_video', 'e2e_message', 'auto_archived', 'archived_day', 'task_visible', 'task_default_time', 'all_group_mute', 'all_group_autoin', 'user_private_chat_mute', 'user_group_chat_mute', 'system_alias', 'system_welcome', 'image_compress', 'image_quality', 'image_save_local']) * @apiSuccess {Number} ret 返回状态码(1正确、0错误) * @apiSuccess {String} msg 返回信息(错误描述) @@ -71,8 +71,6 @@ class SystemController extends AbstractController 'project_invite', 'chat_information', 'anon_message', - 'voice2text', - 'translation', 'convert_video', 'compress_video', 'e2e_message', @@ -106,12 +104,6 @@ class SystemController extends AbstractController return Base::retError('自动归档时间不可大于100天!'); } } - if ($all['voice2text'] == 'open' && !Setting::AIOpen()) { - return Base::retError('开启语音转文字功能需要在应用启用 AI 助手。'); - } - if ($all['translation'] == 'open' && !Setting::AIOpen()) { - return Base::retError('开启翻译功能需要在应用启用 AI 助手。'); - } if ($all['system_alias'] == env('APP_NAME')) { $all['system_alias'] = ''; } @@ -138,8 +130,6 @@ class SystemController extends AbstractController $setting['project_invite'] = $setting['project_invite'] ?: 'open'; $setting['chat_information'] = $setting['chat_information'] ?: 'optional'; $setting['anon_message'] = $setting['anon_message'] ?: 'open'; - $setting['voice2text'] = $setting['voice2text'] ?: 'close'; - $setting['translation'] = $setting['translation'] ?: 'close'; $setting['convert_video'] = $setting['convert_video'] ?: 'close'; $setting['compress_video'] = $setting['compress_video'] ?: 'close'; $setting['e2e_message'] = $setting['e2e_message'] ?: 'close'; @@ -285,48 +275,6 @@ class SystemController extends AbstractController return Base::retSuccess($type == 'save' ? '保存成功' : 'success', $setting ?: json_decode('{}')); } - /** - * @api {get} api/system/setting/ai AI助手设置(限管理员) - * - * @apiVersion 1.0.0 - * @apiGroup system - * @apiName setting__ai - * - * @apiParam {String} type - * - get: 获取(默认) - * - save: 保存设置(参数:['ai_provider', 'ai_api_key', 'ai_api_url', 'ai_proxy']) - * @apiSuccess {Number} ret 返回状态码(1正确、0错误) - * @apiSuccess {String} msg 返回信息(错误描述) - * @apiSuccess {Object} data 返回数据 - */ - public function setting__ai() - { - User::auth('admin'); - // - $type = trim(Request::input('type')); - if ($type == 'save') { - if (env("SYSTEM_SETTING") == 'disabled') { - return Base::retError('当前环境禁止修改'); - } - $all = Base::newTrim(Request::input()); - foreach ($all as $key => $value) { - if (!in_array($key, [ - 'ai_provider', - 'ai_api_key', - 'ai_api_url', - 'ai_proxy', - ])) { - unset($all[$key]); - } - } - $setting = Base::setting('aiSetting', Base::newTrim($all)); - } else { - $setting = Base::setting('aiSetting'); - } - // - return Base::retSuccess($type == 'save' ? '保存成功' : 'success', $setting ?: json_decode('{}')); - } - /** * @api {get} api/system/setting/aibot 获取AI设置、保存AI机器人设置(限管理员) * @@ -406,44 +354,6 @@ class SystemController extends AbstractController return Base::retSuccess('success', $setting ?: json_decode('{}')); } - /** - * @api {get} api/system/setting/aibot_defmodels 获取AI默认模型 - * - * @apiDescription 获取AI机器人默认模型 - * @apiVersion 1.0.0 - * @apiGroup system - * @apiName setting__aibot_defmodels - * - * @apiParam {String} type AI类型 - * @apiParam {String} [base_url] 基础URL(仅 type=ollama 时有效) - * @apiParam {String} [key] Key(仅 type=ollama 时有效) - * @apiParam {String} [agency] 使用代理(仅 type=ollama 时有效) - * - * @apiSuccess {Number} ret 返回状态码(1正确、0错误) - * @apiSuccess {String} msg 返回信息(错误描述) - * @apiSuccess {Object} data 返回数据 - */ - public function setting__aibot_defmodels() - { - $type = trim(Request::input('type')); - if ($type == 'ollama') { - $baseUrl = trim(Request::input('base_url')); - $key = trim(Request::input('key')); - $agency = trim(Request::input('agency')); - if (empty($baseUrl)) { - return Base::retError('请先填写 Base URL'); - } - return AI::ollamaModels($baseUrl, $key, $agency); - } - $models = Setting::AIBotDefaultModels($type); - if (empty($models)) { - return Base::retError('未找到默认模型'); - } - return Base::retSuccess('success', [ - 'models' => $models - ]); - } - /** * @api {get} api/system/setting/checkin 获取签到设置、保存签到设置(限管理员) * diff --git a/app/Models/Setting.php b/app/Models/Setting.php index 15a62ef72..8303aad29 100644 --- a/app/Models/Setting.php +++ b/app/Models/Setting.php @@ -6,6 +6,7 @@ use App\Exceptions\ApiException; use App\Module\Base; use App\Module\Doo; use App\Module\Timer; +use App\Module\AI; use Carbon\Carbon; /** @@ -65,14 +66,6 @@ class Setting extends AbstractModel $value['permission_pack_userids'] = is_array($value['permission_pack_userids']) ? $value['permission_pack_userids'] : []; break; - // AI 助手设置 - case 'aiSetting': - $value['ai_provider'] = $value['ai_provider'] ?: 'openai'; - $value['ai_api_key'] = $value['ai_api_key'] ?: ''; - $value['ai_api_url'] = $value['ai_api_url'] ?: ''; - $value['ai_proxy'] = $value['ai_proxy'] ?: ''; - break; - // AI 机器人设置 case 'aibotSetting': if ($value['claude_token'] && empty($value['claude_key'])) { @@ -91,10 +84,7 @@ class Setting extends AbstractModel $content = explode("\n", $content); $content = array_filter($content); } - if (empty($content)) { - $content = self::AIBotDefaultModels($aiName); - } - $content = implode("\n", $content); + $content = is_array($content) ? implode("\n", $content) : ''; break; case 'model': $models = Setting::AIBotModels2Array($array[$key . 's'], true); @@ -121,95 +111,31 @@ class Setting extends AbstractModel */ public static function AIOpen() { - return !!Base::settingFind('aiSetting', 'ai_api_key'); + $setting = Base::setting('aibotSetting'); + if (!is_array($setting) || empty($setting)) { + return false; + } + foreach (AI::TEXT_MODEL_PRIORITY as $vendor) { + if (self::isAIBotVendorEnabled($setting, $vendor)) { + return true; + } + } + return false; } /** - * AI 机器人默认模型 - * @param string $ai - * @return array + * 判断 AI 机器人厂商是否启用 + * @param array $setting + * @param string $vendor + * @return bool */ - public static function AIBotDefaultModels($ai = 'openai') + protected static function isAIBotVendorEnabled(array $setting, string $vendor): bool { - return match ($ai) { - 'openai' => [ - 'gpt-4.1 | GPT-4.1', - 'gpt-4o | GPT-4o', - 'gpt-4 | GPT-4', - 'gpt-4o-mini | GPT-4o Mini', - 'gpt-4-turbo | GPT-4 Turbo', - 'o3 (thinking) | GPT-o3', - 'o1 | GPT-o1', - 'o4-mini | GPT-o4 Mini', - 'o3-mini | GPT-o3 Mini', - 'o1-mini | GPT-o1 Mini', - 'gpt-3.5-turbo | GPT-3.5 Turbo', - 'gpt-3.5-turbo-16k | GPT-3.5 Turbo 16K', - 'gpt-3.5-turbo-0125 | GPT-3.5 Turbo 0125', - 'gpt-3.5-turbo-1106 | GPT-3.5 Turbo 1106' - ], - 'claude' => [ - 'claude-opus-4-0 (thinking) | Claude Opus 4', - 'claude-sonnet-4-0 (thinking) | Claude Sonnet 4', - 'claude-3-7-sonnet-latest (thinking) | Claude Sonnet 3.7', - 'claude-3-5-sonnet-latest | Claude Sonnet 3.5', - 'claude-3-5-haiku-latest | Claude Haiku 3.5', - 'claude-3-opus-latest | Claude Opus 3' - ], - 'deepseek' => [ - 'deepseek-chat | DeepSeek V3', - 'deepseek-reasoner | DeepSeek R1' - ], - 'gemini' => [ - 'gemini-2.5-pro-preview-05-06 (thinking) | Gemini 2.5 Pro Preview', - 'gemini-2.0-flash | Gemini 2.0 Flash', - 'gemini-2.0-flash-lite | Gemini 2.0 Flash-Lite', - 'gemini-1.5-flash | Gemini 1.5 Flash', - 'gemini-1.5-flash-8b | Gemini 1.5 Flash 8B', - 'gemini-1.5-pro | Gemini 1.5 Pro', - 'gemini-1.0-pro | Gemini 1.0 Pro' - ], - 'grok' => [ - 'grok-3-latest | Grok 3', - 'grok-3-fast-latest | Grok 3 Fast', - 'grok-3-mini-latest | Grok 3 Mini', - 'grok-3-mini-fast-latest | Grok 3 Mini Fast', - 'grok-2-vision-latest | Grok 2 Vision', - 'grok-2-latest | Grok 2', - ], - 'zhipu' => [ - 'glm-4 | GLM-4', - 'glm-4-plus | GLM-4 Plus', - 'glm-4-air | GLM-4 Air', - 'glm-4-airx | GLM-4 AirX', - 'glm-4-long | GLM-4 Long', - 'glm-4-flash | GLM-4 Flash', - 'glm-4v | GLM-4V', - 'glm-4v-plus | GLM-4V Plus', - 'glm-3-turbo | GLM-3 Turbo' - ], - 'qianwen' => [ - 'qwen-max | QWEN Max', - 'qwen-max-latest | QWEN Max Latest', - 'qwen-turbo | QWEN Turbo', - 'qwen-turbo-latest | QWEN Turbo Latest', - 'qwen-plus | QWEN Plus', - 'qwen-plus-latest | QWEN Plus Latest', - 'qwen-long | QWEN Long' - ], - 'wenxin' => [ - 'ernie-4.0-8k | Ernie 4.0 8K', - 'ernie-4.0-8k-latest | Ernie 4.0 8K Latest', - 'ernie-4.0-turbo-128k | Ernie 4.0 Turbo 128K', - 'ernie-4.0-turbo-8k | Ernie 4.0 Turbo 8K', - 'ernie-3.5-128k | Ernie 3.5 128K', - 'ernie-3.5-8k | Ernie 3.5 8K', - 'ernie-speed-128k | Ernie Speed 128K', - 'ernie-speed-8k | Ernie Speed 8K', - 'ernie-lite-8k | Ernie Lite 8K', - 'ernie-tiny-8k | Ernie Tiny 8K' - ], - default => [], + $key = trim((string)($setting[$vendor . '_key'] ?? '')); + return match ($vendor) { + 'ollama' => $key !== '' || !empty($setting['ollama_base_url']), + 'wenxin' => $key !== '' && !empty($setting['wenxin_secret']), + default => $key !== '', }; } diff --git a/app/Module/AI.php b/app/Module/AI.php index 4caa43d3b..d472b2645 100644 --- a/app/Module/AI.php +++ b/app/Module/AI.php @@ -11,10 +11,24 @@ use Carbon\Carbon; */ class AI { + public const TEXT_MODEL_PRIORITY = [ + 'openai', + 'claude', + 'deepseek', + 'gemini', + 'grok', + 'ollama', + 'zhipu', + 'qianwen', + 'wenxin' + ]; + protected const OPENAI_DEFAULT_MODEL = 'gpt-5-mini'; + protected $post = []; protected $headers = []; protected $urlPath = ''; protected $timeout = 30; + protected $providerConfig = null; /** * 构造函数 @@ -63,6 +77,15 @@ class AI $this->timeout = $timeout; } + /** + * 指定请求所使用的模型配置 + * @param array $provider + */ + public function setProvider(array $provider) + { + $this->providerConfig = $provider; + } + /** * 请求 AI 接口 * @param bool $resRaw 是否返回原始数据 @@ -70,23 +93,23 @@ class AI */ public function request($resRaw = false) { - $aiSetting = Base::setting('aiSetting'); - if (!Setting::AIOpen()) { - return Base::retError("AI 助手未开启"); + $provider = $this->providerConfig ?: self::resolveTextProvider(); + if (!$provider) { + return Base::retError("请先配置 AI 助手"); } $headers = [ 'Content-Type' => 'application/json', - 'Authorization' => 'Bearer ' . $aiSetting['ai_api_key'], + 'Authorization' => 'Bearer ' . $provider['api_key'], ]; - if ($aiSetting['ai_proxy']) { - $headers['CURLOPT_PROXY'] = $aiSetting['ai_proxy']; - $headers['CURLOPT_PROXYTYPE'] = str_contains($aiSetting['ai_proxy'], 'socks') ? CURLPROXY_SOCKS5 : CURLPROXY_HTTP; + if (!empty($provider['agency'])) { + $headers['CURLOPT_PROXY'] = $provider['agency']; + $headers['CURLOPT_PROXYTYPE'] = str_contains($provider['agency'], 'socks') ? CURLPROXY_SOCKS5 : CURLPROXY_HTTP; } $headers = array_merge($headers, $this->headers); - $url = $aiSetting['ai_api_url'] ?: 'https://api.openai.com/v1'; - $url = $url . ($this->urlPath ?: '/chat/completions'); + $baseUrl = $provider['base_url'] ?: 'https://api.openai.com/v1'; + $url = $baseUrl . ($this->urlPath ?: '/chat/completions'); $result = Ihttp::ihttp_request($url, $this->post, $headers, $this->timeout); if (Base::isError($result)) { @@ -125,17 +148,17 @@ class AI if (!file_exists($filePath)) { return Base::retError("语音文件不存在"); } - $systemSetting = Base::setting('system'); - if ($systemSetting['voice2text'] !== 'open') { - return Base::retError("语音转文字功能未开启"); - } - $cacheKey = "openAItranscriptions::" . md5($filePath . '_' . Base::array2json($extParams)); if ($noCache) { Cache::forget($cacheKey); } - $result = Cache::remember($cacheKey, Carbon::now()->addDays(), function () use ($extParams, $filePath) { + $audioProvider = self::resolveOpenAIAudioProvider(); + if (!$audioProvider) { + return Base::retError("请先在 AI 设置中配置 OpenAI 语音模型"); + } + + $result = Cache::remember($cacheKey, Carbon::now()->addDays(), function () use ($extParams, $filePath, $audioProvider) { $post = array_merge($extParams, [ 'file' => new \CURLFile($filePath), 'model' => 'whisper-1', @@ -145,6 +168,7 @@ class AI ]; $ai = new self($post, $header); + $ai->setProvider($audioProvider); $ai->setUrlPath('/audio/transcriptions'); $ai->setTimeout(15); @@ -177,20 +201,19 @@ class AI */ public static function translations($text, $targetLanguage, $noCache = false) { - $systemSetting = Base::setting('system'); - if ($systemSetting['translation'] !== 'open') { - return Base::retError("翻译功能未开启"); - } - $cacheKey = "openAItranslations::" . md5($text . '_' . $targetLanguage); if ($noCache) { Cache::forget($cacheKey); } - $result = Cache::remember($cacheKey, Carbon::now()->addDays(7), function () use ($text, $targetLanguage) { - $post = json_encode([ - "model" => "gpt-5-mini", - "reasoning_effort" => "minimal", + $provider = self::resolveTextProvider(); + if (!$provider) { + return Base::retError("请先配置 AI 助手"); + } + + $result = Cache::remember($cacheKey, Carbon::now()->addDays(7), function () use ($text, $targetLanguage, $provider) { + $payload = [ + "model" => $provider['model'], "messages" => [ [ "role" => "system", @@ -221,9 +244,14 @@ class AI "content" => "请将以下内容翻译为 {$targetLanguage}:\n\n{$text}" ] ], - ]); + ]; + if (self::shouldSendReasoningEffort($provider)) { + $payload['reasoning_effort'] = 'minimal'; + } + $post = json_encode($payload); $ai = new self($post); + $ai->setProvider($provider); $ai->setTimeout(60); $res = $ai->request(); @@ -261,10 +289,14 @@ class AI Cache::forget($cacheKey); } - $result = Cache::remember($cacheKey, Carbon::now()->addHours(24), function () use ($text) { - $post = json_encode([ - "model" => "gpt-5-mini", - "reasoning_effort" => "minimal", + $provider = self::resolveTextProvider(); + if (!$provider) { + return Base::retError("请先配置 AI 助手"); + } + + $result = Cache::remember($cacheKey, Carbon::now()->addHours(24), function () use ($text, $provider) { + $payload = [ + "model" => $provider['model'], "messages" => [ [ "role" => "system", @@ -289,9 +321,14 @@ class AI "content" => "请为以下内容生成一个合适的标题:\n\n" . $text ] ], - ]); + ]; + if (self::shouldSendReasoningEffort($provider)) { + $payload['reasoning_effort'] = 'minimal'; + } + $post = json_encode($payload); $ai = new self($post); + $ai->setProvider($provider); $ai->setTimeout(10); $res = $ai->request(); @@ -329,10 +366,14 @@ class AI Cache::forget($cacheKey); } - $result = Cache::remember($cacheKey, Carbon::now()->addHours(6), function () { - $post = json_encode([ - "model" => "gpt-5-mini", - "reasoning_effort" => "minimal", + $provider = self::resolveTextProvider(); + if (!$provider) { + return Base::retError("请先配置 AI 助手"); + } + + $result = Cache::remember($cacheKey, Carbon::now()->addHours(6), function () use ($provider) { + $payload = [ + "model" => $provider['model'], "messages" => [ [ "role" => "system", @@ -364,9 +405,14 @@ class AI "content" => "请生成20个职场笑话和20个心灵鸡汤" ] ], - ]); + ]; + if (self::shouldSendReasoningEffort($provider)) { + $payload['reasoning_effort'] = 'minimal'; + } + $post = json_encode($payload); $ai = new self($post); + $ai->setProvider($provider); $ai->setTimeout(120); $res = $ai->request(); @@ -417,43 +463,137 @@ class AI } /** - * 获取 ollama 模型 - * @param $baseUrl - * @param $key - * @param $agency - * @return array + * 选择可用的文本模型配置 + * @return array|null */ - public static function ollamaModels($baseUrl, $key = null, $agency = null) + protected static function resolveTextProvider() { - $extra = [ - 'Content-Type' => 'application/json', - ]; - if ($key) { - $extra['Authorization'] = 'Bearer ' . $key; + $setting = Base::setting('aibotSetting'); + if (!is_array($setting)) { + $setting = []; } - if ($agency) { - $extra['CURLOPT_PROXY'] = $agency; - $extra['CURLOPT_PROXYTYPE'] = str_contains($agency, 'socks') ? CURLPROXY_SOCKS5 : CURLPROXY_HTTP; - } - $res = Ihttp::ihttp_request(rtrim($baseUrl, '/') . '/api/tags', [], $extra, 15); - if (Base::isError($res)) { - return Base::retError("获取失败", $res); - } - $resData = Base::json2array($res['data']); - if (empty($resData['models'])) { - return Base::retError("获取失败", $resData); - } - $models = []; - foreach ($resData['models'] as $model) { - if ($model['name'] !== $model['model']) { - $models[] = "{$model['model']} | {$model['name']}"; - } else { - $models[] = $model['model']; + foreach (self::TEXT_MODEL_PRIORITY as $vendor) { + $config = self::buildProviderConfig($setting, $vendor); + if ($config) { + return $config; } } - return Base::retSuccess("success", [ - 'models' => $models, - 'original' => $resData['models'] - ]); + return null; + } + + /** + * 构建指定厂商的请求参数 + * @param array $setting + * @param string $vendor + * @return array|null + */ + protected static function buildProviderConfig(array $setting, string $vendor) + { + $key = trim((string)($setting[$vendor . '_key'] ?? '')); + $baseUrl = trim((string)($setting[$vendor . '_base_url'] ?? '')); + $agency = trim((string)($setting[$vendor . '_agency'] ?? '')); + + switch ($vendor) { + case 'openai': + if ($key === '') { + return null; + } + $baseUrl = $baseUrl ?: 'https://api.openai.com/v1'; + $model = self::resolveOpenAITextModel($setting); + break; + case 'ollama': + if ($baseUrl === '') { + return null; + } + if ($key === '') { + $key = Base::strRandom(6); + } + $model = trim((string)($setting[$vendor . '_model'] ?? '')); + break; + case 'wenxin': + $secret = trim((string)($setting['wenxin_secret'] ?? '')); + if ($key === '' || $secret === '' || $baseUrl === '') { + return null; + } + $key = $key . ':' . $secret; + $model = trim((string)($setting[$vendor . '_model'] ?? '')); + break; + default: + if ($key === '' || $baseUrl === '') { + return null; + } + $model = trim((string)($setting[$vendor . '_model'] ?? '')); + break; + } + + if ($model === '') { + return null; + } + + return [ + 'vendor' => $vendor, + 'model' => $model, + 'api_key' => $key, + 'base_url' => rtrim($baseUrl, '/'), + 'agency' => $agency, + ]; + } + + /** + * 解析 OpenAI 文本模型 + * @param array $setting + * @return string + */ + protected static function resolveOpenAITextModel(array $setting) + { + $models = Setting::AIBotModels2Array($setting['openai_models'] ?? '', true); + if (in_array(self::OPENAI_DEFAULT_MODEL, $models, true)) { + return self::OPENAI_DEFAULT_MODEL; + } + if (!empty($setting['openai_model'])) { + return $setting['openai_model']; + } + return $models[0] ?? self::OPENAI_DEFAULT_MODEL; + } + + /** + * OpenAI 语音模型配置 + * @return array|null + */ + protected static function resolveOpenAIAudioProvider() + { + $setting = Base::setting('aibotSetting'); + if (!is_array($setting)) { + $setting = []; + } + $key = trim((string)($setting['openai_key'] ?? '')); + if ($key === '') { + return null; + } + $baseUrl = trim((string)($setting['openai_base_url'] ?? '')); + $baseUrl = $baseUrl ?: 'https://api.openai.com/v1'; + $agency = trim((string)($setting['openai_agency'] ?? '')); + + return [ + 'vendor' => 'openai', + 'model' => 'whisper-1', + 'api_key' => $key, + 'base_url' => rtrim($baseUrl, '/'), + 'agency' => $agency, + ]; + } + + /** + * 是否需要附加 reasoning_effort 参数 + * @param array $provider + * @return bool + */ + protected static function shouldSendReasoningEffort(array $provider): bool + { + if (($provider['vendor'] ?? '') !== 'openai') { + return false; + } + $model = $provider['model'] ?? ''; + return str_starts_with($model, 'gpt-5'); } } diff --git a/database/migrations/2025_07_26_112113_create_ai_settings_table.php b/database/migrations/2025_07_26_112113_create_ai_settings_table.php deleted file mode 100644 index fa9940007..000000000 --- a/database/migrations/2025_07_26_112113_create_ai_settings_table.php +++ /dev/null @@ -1,35 +0,0 @@ - 'openai', - 'ai_api_key' => $setting['openai_key'], - 'ai_api_url' => $setting['openai_base_url'], - 'ai_proxy' => $setting['openai_agency'], - ]); - - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - // This migration does not need to be reversible - } -} diff --git a/resources/assets/js/pages/manage/application.vue b/resources/assets/js/pages/manage/application.vue index bebeefaa5..cb6553909 100644 --- a/resources/assets/js/pages/manage/application.vue +++ b/resources/assets/js/pages/manage/application.vue @@ -245,18 +245,6 @@ - - - -
-
- -
-
-
- -
-
-
-

{{ $L('AI 助手') }}

-
- -
    -
  • {{$L('此功能并非聊天机器人,而是用于辅助工作。比如:语音转文字、聊天翻译、整理分析工作报告等。')}}
  • -
  • {{$L('如果需要聊天机器人,请在「应用」中使用「AI 机器人」插件。')}}
  • -
-
-

 

- - -
{{$L('支持:OpenAI')}}
-
- - -
{{$L('请输入 API 密钥,留空表示不启用 AI 助手')}}
-
- - -
{{$L('选填,请输入 API URL')}}
-
- - -
{{$L('选填,支持 http、https、socks5 协议')}}
-
-
-
-
- -
- - - - diff --git a/resources/assets/js/pages/manage/setting/components/SystemSetting.vue b/resources/assets/js/pages/manage/setting/components/SystemSetting.vue index 44e51ae66..38c389066 100644 --- a/resources/assets/js/pages/manage/setting/components/SystemSetting.vue +++ b/resources/assets/js/pages/manage/setting/components/SystemSetting.vue @@ -182,22 +182,6 @@
{{$L('允许匿名发送消息给其他成员。')}}
{{$L('禁止匿名发送消息。')}}
- - - {{$L('开启')}} - {{$L('关闭')}} - -
{{$L('长按语音消息可转换成文字。')}} ({{$L('需要在应用启用 AI 助手')}})
-
{{$L('关闭语音转文字功能。')}}
-
- - - {{$L('开启')}} - {{$L('关闭')}} - -
{{$L('长按文本消息可翻译成当前设置的语言。')}} ({{$L('需要在应用启用 AI 助手')}})
-
{{$L('关闭文本消息翻译功能。')}}
-
{{$L('开启')}}