request->isPost()) { $row = $this->request->post('row/a'); if (!is_array($row)) { $this->error('参数错误'); } $oldKey = (string)Db::name('config')->where('name', 'llm_online_api_key')->value('value'); $postedKey = isset($row['llm_online_api_key']) ? trim((string)$row['llm_online_api_key']) : ''; if ($postedKey === '') { $row['llm_online_api_key'] = $oldKey; } $row['llm_online_enable'] = !empty($row['llm_online_enable']) && $row['llm_online_enable'] !== '0' ? '1' : '0'; foreach ($this->keys as $name) { if (!array_key_exists($name, $row)) { continue; } $exists = Db::name('config')->where('name', $name)->find(); if ($exists) { Db::name('config')->where('name', $name)->update(['value' => (string)$row[$name]]); } } $this->writeSiteFile(); $this->success('已保存。拆版将优先使用线上视觉模型,本地 Ollama 仍用于简单任务。'); } $site = []; foreach ($this->keys as $name) { $site[$name] = (string)Db::name('config')->where('name', $name)->value('value'); } $this->view->assign('site', $site); $this->view->assign('keySaved', $site['llm_online_api_key'] !== ''); $this->view->assign('providers', [ 'dashscope' => '阿里云通义(推荐,qwen-vl-max)', 'openai' => 'OpenAI', 'moonshot' => '月之暗面 Kimi', 'zhipu' => '智谱 GLM', 'siliconflow' => '硅基流动', 'volcengine' => '火山方舟', 'deepseek' => 'DeepSeek(仅文本,不能拆版)', 'custom' => '自定义 OpenAI 兼容接口', ]); return $this->view->fetch(); } /** * 测试本地 Ollama */ public function testLocal() { $row = $this->request->post('row/a', []); try { $client = new LlmClient([ 'profile' => 'local', 'base_url' => $row['llm_base_url'] ?? '', 'timeout' => (int)($row['llm_timeout'] ?? 30), ]); $models = $client->listModels(); $this->success('本地 Ollama 已连通,共 ' . count($models) . ' 个模型', [ 'models' => array_slice($models, 0, 30), ]); } catch (\Exception $e) { $this->error($e->getMessage()); } } /** * 测试线上接口(用表单当前值,可先测再保存) */ public function testOnline() { $row = $this->request->post('row/a', []); $apiKey = trim((string)($row['llm_online_api_key'] ?? '')); if ($apiKey === '') { $apiKey = (string)Db::name('config')->where('name', 'llm_online_api_key')->value('value'); } if ($apiKey === '') { $this->error('请填写线上 API Key'); } $model = trim((string)($row['llm_online_model'] ?? '')); if ($model === '') { $model = 'qwen-plus'; } try { $client = new LlmClient([ 'profile' => 'online', 'force' => true, 'online_enable'=> '1', 'base_url' => $row['llm_online_base_url'] ?? '', 'api_key' => $apiKey, 'text_model' => $model, 'vision_model' => $row['llm_online_vision_model'] ?? '', 'timeout' => (int)($row['llm_online_timeout'] ?? 60), ]); $reply = $client->chat('只回复两个字:成功', $model, false); $this->success('线上接口可用', [ 'model' => $model, 'reply' => mb_substr(trim((string)$reply), 0, 80), ]); } catch (\Exception $e) { $this->error($e->getMessage()); } } /** * 与系统配置共用 fa_config,直接重写 extra/site.php,避免无 general/config/edit 权限时写不进去。 */ protected function writeSiteFile() { $config = []; $rows = Db::name('config')->select(); foreach ($rows as $value) { if (in_array($value['type'], ['selects', 'checkbox', 'images', 'files'], true)) { $value['value'] = explode(',', (string)$value['value']); } if ($value['type'] === 'array') { $value['value'] = (array)json_decode((string)$value['value'], true); } $config[$value['name']] = $value['value']; } file_put_contents( CONF_PATH . 'extra' . DS . 'site.php', "