1
This commit is contained in:
@@ -21,7 +21,7 @@ export function savePromptTemplate(data) {
|
|||||||
return request({
|
return request({
|
||||||
url: '/jarvis/social-media/prompt/save',
|
url: '/jarvis/social-media/prompt/save',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,26 +33,61 @@ export function deletePromptTemplate(key) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 大模型接入配置(与 Jarvis 共用 Redis)
|
// —— 多套大模型接入(与 Jarvis 共用 Redis)——
|
||||||
export function getLlmConfig() {
|
export function listLlmProfiles() {
|
||||||
return request({
|
return request({
|
||||||
url: '/jarvis/social-media/llm-config',
|
url: '/jarvis/social-media/llm-config',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function saveLlmConfig(data) {
|
export function getLlmProfile(id) {
|
||||||
return request({
|
return request({
|
||||||
url: '/jarvis/social-media/llm-config/save',
|
url: '/jarvis/social-media/llm-config/profiles/' + encodeURIComponent(id),
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createLlmProfile(data) {
|
||||||
|
return request({
|
||||||
|
url: '/jarvis/social-media/llm-config/profiles',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resetLlmConfig() {
|
export function updateLlmProfile(id, data) {
|
||||||
|
return request({
|
||||||
|
url: '/jarvis/social-media/llm-config/profiles/' + encodeURIComponent(id),
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteLlmProfile(id) {
|
||||||
|
return request({
|
||||||
|
url: '/jarvis/social-media/llm-config/profiles/' + encodeURIComponent(id),
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setActiveLlmProfile(id) {
|
||||||
|
return request({
|
||||||
|
url: '/jarvis/social-media/llm-config/active/' + encodeURIComponent(id),
|
||||||
|
method: 'put'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearActiveLlmProfile() {
|
||||||
|
return request({
|
||||||
|
url: '/jarvis/social-media/llm-config/active',
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resetAllLlmConfig() {
|
||||||
return request({
|
return request({
|
||||||
url: '/jarvis/social-media/llm-config',
|
url: '/jarvis/social-media/llm-config',
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="app-main">
|
<section class="app-main">
|
||||||
<transition name="fade-transform" mode="out-in">
|
<transition name="fade-transform" mode="out-in">
|
||||||
<keep-alive :include="cachedViews">
|
<keep-alive :include="keepAliveInclude">
|
||||||
<router-view v-if="!$route.meta.link" :key="key" />
|
<router-view v-if="!$route.meta.link" :key="key" />
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
</transition>
|
</transition>
|
||||||
@@ -21,6 +21,11 @@ export default {
|
|||||||
cachedViews() {
|
cachedViews() {
|
||||||
return this.$store.state.tagsView.cachedViews
|
return this.$store.state.tagsView.cachedViews
|
||||||
},
|
},
|
||||||
|
// cachedViews 为空时勿传 []:Vue2 keep-alive 的 include 为 [] 会匹配不到任何组件,部分环境下首屏空白
|
||||||
|
keepAliveInclude() {
|
||||||
|
const list = this.cachedViews
|
||||||
|
return list && list.length ? list : undefined
|
||||||
|
},
|
||||||
key() {
|
key() {
|
||||||
return this.$route.path
|
return this.$route.path
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,11 @@ router.beforeEach((to, from, next) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
router.afterEach(() => {
|
router.afterEach((to) => {
|
||||||
NProgress.done()
|
NProgress.done()
|
||||||
|
// 移动端不渲染 TagsView,其 watch 里的 addTags 不会执行,cachedViews 一直为空。
|
||||||
|
// AppMain 中 keep-alive 的 include 依赖 cachedViews,空数组时部分页面(如闲鱼商品)首进可能白屏,需刷新才正常。
|
||||||
|
if (to.name) {
|
||||||
|
store.dispatch('tagsView/addView', to)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -423,7 +423,11 @@ export default {
|
|||||||
if (this.erpAccountList.length > 0 && !this.queryParams.appid) {
|
if (this.erpAccountList.length > 0 && !this.queryParams.appid) {
|
||||||
this.queryParams.appid = this.erpAccountList[0].value;
|
this.queryParams.appid = this.erpAccountList[0].value;
|
||||||
this.getList();
|
this.getList();
|
||||||
|
} else if (!this.queryParams.appid) {
|
||||||
|
this.loading = false;
|
||||||
}
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
this.loading = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/** 加载会员名列表 */
|
/** 加载会员名列表 */
|
||||||
|
|||||||
@@ -112,12 +112,16 @@
|
|||||||
<div slot="header" class="clearfix">
|
<div slot="header" class="clearfix">
|
||||||
<span class="card-title">
|
<span class="card-title">
|
||||||
<i class="el-icon-connection"></i>
|
<i class="el-icon-connection"></i>
|
||||||
大模型接入配置
|
大模型接入配置(多套 · 激活一套生效)
|
||||||
</span>
|
</span>
|
||||||
|
<div style="float: right;">
|
||||||
|
<el-button type="primary" size="small" icon="el-icon-plus" @click="openLlmDialog(false)">新增配置</el-button>
|
||||||
|
<el-button size="small" icon="el-icon-refresh" @click="loadLlmList">刷新</el-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-alert
|
<el-alert
|
||||||
v-if="llmConfig && llmConfig.redisAvailable === false"
|
v-if="llmSummary && llmSummary.redisAvailable === false"
|
||||||
title="当前未连接 Redis,无法保存接入配置;Jarvis 将始终使用其 application.yml 中的默认 Ollama。"
|
title="当前未连接 Redis,无法保存;Jarvis 将始终使用 application.yml 中的默认 Ollama。"
|
||||||
type="warning"
|
type="warning"
|
||||||
:closable="false"
|
:closable="false"
|
||||||
show-icon
|
show-icon
|
||||||
@@ -128,30 +132,88 @@
|
|||||||
show-icon
|
show-icon
|
||||||
style="margin-bottom: 16px;">
|
style="margin-bottom: 16px;">
|
||||||
<div slot="title">
|
<div slot="title">
|
||||||
<p style="margin: 0 0 8px 0;"><strong>说明:</strong>与上方提示词相同,配置写入 Redis,由 Jarvis 读取。可在「本地 Ollama」与「OpenAI 兼容 HTTP」之间切换。</p>
|
<p style="margin: 0 0 8px 0;"><strong>说明:</strong>可保存多套(如本地 Ollama、远程 API),在表格中点击<strong>激活</strong>后,Jarvis 社媒 AI 仅使用<strong>当前激活</strong>的一套。未激活或清空全部时走 Jarvis 默认 Ollama。</p>
|
||||||
<ul style="margin: 0; padding-left: 18px;">
|
<ul style="margin: 0; padding-left: 18px;">
|
||||||
<li><strong>Ollama</strong>:填写根地址(如 <code>http://127.0.0.1:11434</code>),可不填则使用 Jarvis 默认;模型名可空则使用 yml 默认。</li>
|
<li><strong>Ollama</strong>:根地址可空(用 Jarvis 默认),模型可空。</li>
|
||||||
<li><strong>OpenAI 兼容</strong>:填写完整 Chat Completions URL(如远程 <code>https://api.xxx.com/v1/chat/completions</code> 或本地 <code>http://127.0.0.1:11434/v1/chat/completions</code>),并填写模型名;密钥无则留空(部分本地服务不需要)。</li>
|
<li><strong>OpenAI 兼容</strong>:须填完整 Chat Completions URL 与模型名;密钥可空。</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</el-alert>
|
</el-alert>
|
||||||
|
<p v-if="llmSummary && llmSummary.redisAvailable !== false" class="llm-active-hint">
|
||||||
|
<template v-if="llmSummary.activeId">
|
||||||
|
当前 Jarvis 使用:
|
||||||
|
<el-tag type="success" size="small">{{ llmActiveName || llmSummary.activeId }}</el-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<el-tag type="info" size="small">未激活</el-tag>
|
||||||
|
<span style="margin-left: 8px; color: #909399;">将使用 Jarvis yml 默认 Ollama</span>
|
||||||
|
</template>
|
||||||
|
</p>
|
||||||
|
<el-table
|
||||||
|
v-loading="llmListLoading"
|
||||||
|
:data="llmProfileRows"
|
||||||
|
border
|
||||||
|
stripe
|
||||||
|
empty-text="暂无配置,请点击「新增配置」"
|
||||||
|
style="width: 100%;">
|
||||||
|
<el-table-column prop="name" label="名称" min-width="120" show-overflow-tooltip />
|
||||||
|
<el-table-column label="方式" width="108">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
{{ scope.row.mode === 'openai' ? 'OpenAI兼容' : 'Ollama' }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="baseUrl" label="地址" min-width="200" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="model" label="模型" min-width="120" show-overflow-tooltip />
|
||||||
|
<el-table-column label="密钥" width="100">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
{{ scope.row.hasApiKey ? (scope.row.apiKeyMasked || '已设') : '—' }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="当前" width="88" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-tag v-if="scope.row.active" type="success" size="mini">使用中</el-tag>
|
||||||
|
<span v-else>—</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" width="200" fixed="right">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button type="text" size="small" :disabled="scope.row.active" @click="handleActivateLlm(scope.row)">激活</el-button>
|
||||||
|
<el-button type="text" size="small" @click="openLlmDialog(true, scope.row)">编辑</el-button>
|
||||||
|
<el-button type="text" size="small" class="llm-del-btn" @click="handleDeleteLlm(scope.row)">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<div class="llm-toolbar-bottom">
|
||||||
|
<el-button size="small" @click="handleClearActiveLlm">取消激活</el-button>
|
||||||
|
<el-button type="danger" plain size="small" @click="handleResetAllLlm">清空全部配置</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-dialog
|
||||||
|
:title="llmDialogEditId ? '编辑大模型配置' : '新增大模型配置'"
|
||||||
|
:visible.sync="llmDialogVisible"
|
||||||
|
width="580px"
|
||||||
|
append-to-body
|
||||||
|
@close="resetLlmDialogForm">
|
||||||
<el-form :model="llmForm" label-width="140px" class="llm-form">
|
<el-form :model="llmForm" label-width="140px" class="llm-form">
|
||||||
|
<el-form-item label="配置名称" required>
|
||||||
|
<el-input v-model="llmForm.name" placeholder="如:本机 Ollama、DeepSeek 官方" maxlength="80" show-word-limit />
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="接入方式">
|
<el-form-item label="接入方式">
|
||||||
<el-radio-group v-model="llmForm.mode">
|
<el-radio-group v-model="llmForm.mode">
|
||||||
<el-radio label="ollama">本地 Ollama</el-radio>
|
<el-radio label="ollama">Ollama</el-radio>
|
||||||
<el-radio label="openai">OpenAI 兼容接口</el-radio>
|
<el-radio label="openai">OpenAI 兼容</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="llmForm.mode === 'openai' ? 'API 完整地址' : 'Ollama 根地址'">
|
<el-form-item :label="llmForm.mode === 'openai' ? 'API 完整地址' : 'Ollama 根地址'">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="llmForm.baseUrl"
|
v-model="llmForm.baseUrl"
|
||||||
:placeholder="llmForm.mode === 'openai' ? 'https://api.openai.com/v1/chat/completions' : 'http://127.0.0.1:11434(可留空使用 Jarvis 默认)'"
|
:placeholder="llmForm.mode === 'openai' ? 'https://api.openai.com/v1/chat/completions' : 'http://127.0.0.1:11434(可空)'"
|
||||||
clearable />
|
clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="模型名称">
|
<el-form-item label="模型名称">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="llmForm.model"
|
v-model="llmForm.model"
|
||||||
:placeholder="llmForm.mode === 'openai' ? '必填,如 gpt-4o-mini、deepseek-chat' : '可选,不填则用 Jarvis 默认模型'"
|
:placeholder="llmForm.mode === 'openai' ? '必填' : '可空'"
|
||||||
clearable />
|
clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="API 密钥">
|
<el-form-item label="API 密钥">
|
||||||
@@ -160,24 +222,37 @@
|
|||||||
type="password"
|
type="password"
|
||||||
show-password
|
show-password
|
||||||
autocomplete="new-password"
|
autocomplete="new-password"
|
||||||
placeholder="修改时填写新密钥;留空表示保持原密钥" />
|
:placeholder="llmDialogEditId ? '留空不修改;填写则覆盖' : '可选'" />
|
||||||
<span v-if="llmHasApiKey" class="llm-key-hint">当前已保存密钥:{{ llmApiKeyMasked || '****' }}</span>
|
<span v-if="llmDialogEditId && llmHasApiKey" class="llm-key-hint">已保存:{{ llmApiKeyMasked || '****' }}</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-if="llmHasApiKey">
|
<el-form-item v-if="llmDialogEditId && llmHasApiKey">
|
||||||
<el-checkbox v-model="llmClearApiKey">清除已保存的 API 密钥</el-checkbox>
|
<el-checkbox v-model="llmClearApiKey">清除已保存的密钥</el-checkbox>
|
||||||
</el-form-item>
|
|
||||||
<el-form-item>
|
|
||||||
<el-button type="primary" icon="el-icon-check" :loading="llmSaving" @click="handleSaveLlm">保存接入配置</el-button>
|
|
||||||
<el-button icon="el-icon-refresh-left" @click="handleLoadLlm">重新加载</el-button>
|
|
||||||
<el-button type="danger" plain icon="el-icon-delete" @click="handleResetLlm">恢复默认(清除 Redis 中的接入配置)</el-button>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="llmDialogVisible = false">取 消</el-button>
|
||||||
|
<el-button type="primary" :loading="llmSaving" @click="submitLlmDialog">保 存</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { listPromptTemplates, getPromptTemplate, savePromptTemplate, deletePromptTemplate, getLlmConfig, saveLlmConfig, resetLlmConfig } from '@/api/jarvis/socialMediaPrompt'
|
import {
|
||||||
|
listPromptTemplates,
|
||||||
|
getPromptTemplate,
|
||||||
|
savePromptTemplate,
|
||||||
|
deletePromptTemplate,
|
||||||
|
listLlmProfiles,
|
||||||
|
getLlmProfile,
|
||||||
|
createLlmProfile,
|
||||||
|
updateLlmProfile,
|
||||||
|
deleteLlmProfile,
|
||||||
|
setActiveLlmProfile,
|
||||||
|
clearActiveLlmProfile,
|
||||||
|
resetAllLlmConfig
|
||||||
|
} from '@/api/jarvis/socialMediaPrompt'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'SocialMediaPromptConfig',
|
name: 'SocialMediaPromptConfig',
|
||||||
@@ -187,8 +262,13 @@ export default {
|
|||||||
activeTab: 'keywords',
|
activeTab: 'keywords',
|
||||||
templates: {},
|
templates: {},
|
||||||
saving: {},
|
saving: {},
|
||||||
llmConfig: null,
|
llmSummary: null,
|
||||||
|
llmProfileRows: [],
|
||||||
|
llmListLoading: false,
|
||||||
|
llmDialogVisible: false,
|
||||||
|
llmDialogEditId: null,
|
||||||
llmForm: {
|
llmForm: {
|
||||||
|
name: '',
|
||||||
mode: 'ollama',
|
mode: 'ollama',
|
||||||
baseUrl: '',
|
baseUrl: '',
|
||||||
model: '',
|
model: '',
|
||||||
@@ -200,9 +280,15 @@ export default {
|
|||||||
llmSaving: false
|
llmSaving: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
llmActiveName() {
|
||||||
|
const r = this.llmProfileRows.find(p => p.active)
|
||||||
|
return r ? r.name : ''
|
||||||
|
}
|
||||||
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.loadTemplates()
|
this.loadTemplates()
|
||||||
this.loadLlmConfig()
|
this.loadLlmList()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/** 加载所有模板 */
|
/** 加载所有模板 */
|
||||||
@@ -309,54 +395,110 @@ export default {
|
|||||||
return labels[key] || key
|
return labels[key] || key
|
||||||
},
|
},
|
||||||
|
|
||||||
async loadLlmConfig() {
|
async loadLlmList() {
|
||||||
|
this.llmListLoading = true
|
||||||
try {
|
try {
|
||||||
const res = await getLlmConfig()
|
const res = await listLlmProfiles()
|
||||||
if (res.code === 200 && res.data) {
|
if (res.code === 200 && res.data) {
|
||||||
this.llmConfig = res.data
|
this.llmSummary = res.data
|
||||||
this.llmForm.mode = res.data.mode === 'openai' ? 'openai' : 'ollama'
|
this.llmProfileRows = Array.isArray(res.data.profiles) ? res.data.profiles : []
|
||||||
this.llmForm.baseUrl = res.data.baseUrl || ''
|
|
||||||
this.llmForm.model = res.data.model || ''
|
|
||||||
this.llmForm.apiKeyInput = ''
|
|
||||||
this.llmHasApiKey = !!res.data.hasApiKey
|
|
||||||
this.llmApiKeyMasked = res.data.apiKeyMasked || null
|
|
||||||
this.llmClearApiKey = false
|
|
||||||
} else {
|
} else {
|
||||||
this.$message.error(res.msg || '加载大模型配置失败')
|
this.$message.error(res.msg || '加载大模型配置失败')
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
this.$message.error('加载大模型配置失败:' + (e.message || '未知错误'))
|
this.$message.error('加载大模型配置失败:' + (e.message || '未知错误'))
|
||||||
|
} finally {
|
||||||
|
this.llmListLoading = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async handleSaveLlm() {
|
resetLlmDialogForm() {
|
||||||
|
this.llmDialogEditId = null
|
||||||
|
this.llmForm = {
|
||||||
|
name: '',
|
||||||
|
mode: 'ollama',
|
||||||
|
baseUrl: '',
|
||||||
|
model: '',
|
||||||
|
apiKeyInput: ''
|
||||||
|
}
|
||||||
|
this.llmHasApiKey = false
|
||||||
|
this.llmApiKeyMasked = null
|
||||||
|
this.llmClearApiKey = false
|
||||||
|
},
|
||||||
|
|
||||||
|
async openLlmDialog(edit, row) {
|
||||||
|
if (this.llmSummary && this.llmSummary.redisAvailable === false) {
|
||||||
|
this.$message.warning('Redis 未配置,无法保存')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.resetLlmDialogForm()
|
||||||
|
if (edit && row && row.id) {
|
||||||
|
this.llmDialogEditId = row.id
|
||||||
|
try {
|
||||||
|
const res = await getLlmProfile(row.id)
|
||||||
|
if (res.code !== 200 || !res.data) {
|
||||||
|
this.$message.error(res.msg || '加载失败')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const d = res.data
|
||||||
|
this.llmForm.name = d.name || ''
|
||||||
|
this.llmForm.mode = d.mode === 'openai' ? 'openai' : 'ollama'
|
||||||
|
this.llmForm.baseUrl = d.baseUrl || ''
|
||||||
|
this.llmForm.model = d.model || ''
|
||||||
|
this.llmHasApiKey = !!d.hasApiKey
|
||||||
|
this.llmApiKeyMasked = d.apiKeyMasked || null
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
this.$message.error('加载失败')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.llmDialogVisible = true
|
||||||
|
},
|
||||||
|
|
||||||
|
async submitLlmDialog() {
|
||||||
|
if (!this.llmForm.name || !this.llmForm.name.trim()) {
|
||||||
|
this.$message.warning('请填写配置名称')
|
||||||
|
return
|
||||||
|
}
|
||||||
if (this.llmForm.mode === 'openai') {
|
if (this.llmForm.mode === 'openai') {
|
||||||
if (!this.llmForm.baseUrl || !this.llmForm.baseUrl.trim()) {
|
if (!this.llmForm.baseUrl || !this.llmForm.baseUrl.trim()) {
|
||||||
this.$message.warning('OpenAI 兼容模式须填写完整 API 地址')
|
this.$message.warning('OpenAI 兼容须填写完整 API 地址')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!this.llmForm.model || !this.llmForm.model.trim()) {
|
if (!this.llmForm.model || !this.llmForm.model.trim()) {
|
||||||
this.$message.warning('OpenAI 兼容模式须填写模型名称')
|
this.$message.warning('OpenAI 兼容须填写模型名称')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const payload = {
|
const payload = {
|
||||||
|
name: this.llmForm.name.trim(),
|
||||||
mode: this.llmForm.mode,
|
mode: this.llmForm.mode,
|
||||||
baseUrl: (this.llmForm.baseUrl || '').trim(),
|
baseUrl: (this.llmForm.baseUrl || '').trim(),
|
||||||
model: (this.llmForm.model || '').trim()
|
model: (this.llmForm.model || '').trim()
|
||||||
}
|
}
|
||||||
|
if (this.llmDialogEditId) {
|
||||||
if (this.llmClearApiKey) {
|
if (this.llmClearApiKey) {
|
||||||
payload.clearApiKey = true
|
payload.clearApiKey = true
|
||||||
} else if (this.llmForm.apiKeyInput && this.llmForm.apiKeyInput.trim()) {
|
} else if (this.llmForm.apiKeyInput && this.llmForm.apiKeyInput.trim()) {
|
||||||
payload.apiKey = this.llmForm.apiKeyInput.trim()
|
payload.apiKey = this.llmForm.apiKeyInput.trim()
|
||||||
}
|
}
|
||||||
|
} else if (this.llmForm.apiKeyInput && this.llmForm.apiKeyInput.trim()) {
|
||||||
|
payload.apiKey = this.llmForm.apiKeyInput.trim()
|
||||||
|
}
|
||||||
this.llmSaving = true
|
this.llmSaving = true
|
||||||
try {
|
try {
|
||||||
const res = await saveLlmConfig(payload)
|
let res
|
||||||
|
if (this.llmDialogEditId) {
|
||||||
|
res = await updateLlmProfile(this.llmDialogEditId, payload)
|
||||||
|
} else {
|
||||||
|
res = await createLlmProfile(payload)
|
||||||
|
}
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
this.$message.success('大模型接入配置已保存')
|
this.$message.success('保存成功')
|
||||||
await this.loadLlmConfig()
|
this.llmDialogVisible = false
|
||||||
|
await this.loadLlmList()
|
||||||
} else {
|
} else {
|
||||||
this.$message.error(res.msg || '保存失败')
|
this.$message.error(res.msg || '保存失败')
|
||||||
}
|
}
|
||||||
@@ -368,18 +510,61 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async handleLoadLlm() {
|
async handleActivateLlm(row) {
|
||||||
await this.loadLlmConfig()
|
try {
|
||||||
this.$message.success('已重新加载')
|
const res = await setActiveLlmProfile(row.id)
|
||||||
|
if (res.code === 200) {
|
||||||
|
this.$message.success(res.msg || '已激活')
|
||||||
|
await this.loadLlmList()
|
||||||
|
} else {
|
||||||
|
this.$message.error(res.msg || '操作失败')
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
this.$message.error('操作失败:' + (e.message || '未知错误'))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async handleResetLlm() {
|
async handleDeleteLlm(row) {
|
||||||
try {
|
try {
|
||||||
await this.$confirm('将删除 Redis 中的大模型接入配置,Jarvis 恢复为 application.yml 默认 Ollama。是否继续?', '提示', { type: 'warning' })
|
await this.$confirm(`确定删除配置「${row.name || row.id}」?`, '提示', { type: 'warning' })
|
||||||
const res = await resetLlmConfig()
|
const res = await deleteLlmProfile(row.id)
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
this.$message.success(res.msg || '已恢复默认')
|
this.$message.success('已删除')
|
||||||
await this.loadLlmConfig()
|
await this.loadLlmList()
|
||||||
|
} else {
|
||||||
|
this.$message.error(res.msg || '删除失败')
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (e !== 'cancel') {
|
||||||
|
console.error(e)
|
||||||
|
this.$message.error('删除失败:' + (e.message || '未知错误'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async handleClearActiveLlm() {
|
||||||
|
try {
|
||||||
|
const res = await clearActiveLlmProfile()
|
||||||
|
if (res.code === 200) {
|
||||||
|
this.$message.success(res.msg || '已取消激活')
|
||||||
|
await this.loadLlmList()
|
||||||
|
} else {
|
||||||
|
this.$message.error(res.msg || '操作失败')
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
this.$message.error('操作失败:' + (e.message || '未知错误'))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async handleResetAllLlm() {
|
||||||
|
try {
|
||||||
|
await this.$confirm('将删除所有大模型接入配置及旧版单键,Jarvis 恢复为默认 Ollama。是否继续?', '提示', { type: 'warning' })
|
||||||
|
const res = await resetAllLlmConfig()
|
||||||
|
if (res.code === 200) {
|
||||||
|
this.$message.success(res.msg || '已清空')
|
||||||
|
await this.loadLlmList()
|
||||||
} else {
|
} else {
|
||||||
this.$message.error(res.msg || '操作失败')
|
this.$message.error(res.msg || '操作失败')
|
||||||
}
|
}
|
||||||
@@ -463,5 +648,22 @@ export default {
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #909399;
|
color: #909399;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.llm-active-hint {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.llm-toolbar-bottom {
|
||||||
|
margin-top: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.llm-toolbar-bottom .el-button {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.llm-del-btn {
|
||||||
|
color: #f56c6c;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user