Files
NyaHome/webui/src/components/aii/AiiModelAddModal.vue
T
MangoFanFanw 7df66bbc61 feat(webui): WebUI 管理后台新增 AII 管理栏目
在 WebUI NyaHome 管理后台中实现 AII 管理栏目,用于在线修改模型设置。
同时在后端补全了两个路由端点。
2026-06-01 20:42:16 +08:00

187 lines
5.6 KiB
Vue
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.
<script setup lang="ts">
import { type SelectOption, useMessage } from 'naive-ui'
import { computed, onMounted, ref, watch } from 'vue'
import AiiProviderAddModal from '@/components/aii/AiiProviderAddModal.vue'
import { aiiModelRules, check_remote_model } from '@/tools/avaliable-check.ts'
import { api } from '@/tools/web.js'
import type { AiiModelPublic, AiiProviderPublicWithoutKey } from '@/types/aii.js'
import type { ReturnDto } from '@/types/response.js'
const MESSAGE = useMessage()
const showModal = defineModel<boolean>('showModal', { required: true })
const { reload } = defineProps<{
noAddProvider?: boolean
reload?: () => void
}>()
const showAddProviderModal = ref(false)
const selectProvider = ref<number | null>(null)
const providers = ref<AiiProviderPublicWithoutKey[]>([])
const remoteModels = ref<string[]>([])
const addModelForm = ref({
id: 0,
model_name: '',
max_context_length: 0,
reasonable: false,
aii_provider_id: selectProvider.value,
})
watch(selectProvider, (newValue) => {
addModelForm.value.aii_provider_id = newValue
})
function loadProviders() {
api
.get('/aii/provider/')
.then((res) => res.data as AiiProviderPublicWithoutKey[])
.then((result) => {
providers.value = result
MESSAGE.success(`成功加载了 ${result.length} 个模型提供商。`)
})
.catch((err) => {
MESSAGE.error(`获取模型提供商列表失败:${err}`)
})
}
const providerOptions = computed<SelectOption[]>(() => {
const options = [] as SelectOption[]
for (const ap of providers.value) {
options.push({
label: `[${ap.id}] [ ${ap.name} ] ( ${ap.base_url} )`,
value: ap.id,
})
}
return options
})
onMounted(() => {
loadProviders()
})
function onGetRemoteModels() {
api
.get(`/aii/provider/${selectProvider.value}/remote/models/`)
.then((res) => res.data as ReturnDto)
.then((data) => {
if (data.success) {
return data.result as string[]
} else {
throw TypeError('由于未知原因,后端业务错误。')
}
})
.then((models) => {
remoteModels.value = models
MESSAGE.success(`成功获取模型提供商 ${selectProvider.value}${models.length} 个模型。`)
})
.catch((err) => {
MESSAGE.error(`获取提供商的模型列表失败:${err}`)
})
}
async function onCheck() {
if (selectProvider.value) {
if (await check_remote_model(selectProvider.value, addModelForm.value.model_name)) {
MESSAGE.success(`提供商的模型 ${addModelForm.value.model_name} 可用。`)
} else {
MESSAGE.warning(`提供商的模型 ${addModelForm.value.model_name} 不可用。`)
}
} else {
MESSAGE.warning('请选择模型提供商。')
}
}
function onConfirm() {
api
.post('/aii/model/', JSON.stringify(addModelForm.value))
.then((res) => res.data as AiiModelPublic)
.then(() => {
MESSAGE.success(`模型 ${addModelForm.value.model_name} 成功添加。`)
showModal.value = false
if (reload) reload()
})
.catch((err) => {
MESSAGE.error(`添加模型失败:${err}`)
})
}
</script>
<template>
<n-modal v-model:show="showModal" preset="card" title="添加模型">
<n-form
:model="addModelForm"
label-placement="left"
label-width="auto"
label-align="right"
:rules="aiiModelRules"
>
<n-form-item label="模型提供商" path="aii_provider_id">
<n-flex style="width: 100%" justify="right" align="center">
<n-select v-model:value="selectProvider" :options="providerOptions" />
<n-tag round type="info" v-if="!noAddProvider">修改已添加的提供商请前往管理中心</n-tag>
<n-button
secondary
type="success"
size="small"
round
@click="loadProviders()"
v-if="!noAddProvider"
>
刷新
</n-button>
<n-button
secondary
type="warning"
size="small"
round
@click="showAddProviderModal = true"
v-if="!noAddProvider"
>
添加
</n-button>
</n-flex>
</n-form-item>
<n-form-item label="模型名称" path="model_name">
<n-flex style="width: 100%" justify="right" align="center">
<n-input v-model:value="addModelForm.model_name" />
<n-flex style="overflow: auto">
<n-button
secondary
type="info"
size="small"
round
v-for="m in remoteModels"
v-bind:key="m"
@click="addModelForm.model_name = m"
>{{ m }}
</n-button>
</n-flex>
<n-button secondary type="success" size="small" round @click="onGetRemoteModels()"
>获取模型列表
</n-button>
</n-flex>
</n-form-item>
<n-form-item label="最大上下文" path="max_context_length">
<n-input-number v-model:value="addModelForm.max_context_length">
<template #suffix>K</template>
</n-input-number>
</n-form-item>
<n-form-item label="支持思考">
<n-switch v-model:value="addModelForm.reasonable" />
</n-form-item>
<n-form-item label="添加完成">
<n-flex>
<n-button secondary type="info" @click="onCheck()">检测</n-button>
<n-button secondary type="primary" @click="onConfirm()">确认</n-button>
</n-flex>
</n-form-item>
</n-form>
<aii-provider-add-modal v-model:show-modal="showAddProviderModal" />
</n-modal>
</template>
<style scoped></style>