refactor: 将模型测试功能从 ModelsTab 移到 KeyAllowedModelsDialog

This commit is contained in:
fawney19
2025-12-29 17:44:02 +08:00
parent 599b3d4c95
commit fd3a5a5afe
2 changed files with 45 additions and 50 deletions

View File

@@ -116,6 +116,19 @@
{{ model.global_model_name }} {{ model.global_model_name }}
</div> </div>
</div> </div>
<!-- 测试按钮 -->
<Button
variant="ghost"
size="icon"
class="h-7 w-7 shrink-0"
title="测试模型连接"
:disabled="testingModelName === model.global_model_name"
@click.stop="testModelConnection(model)"
>
<Loader2 v-if="testingModelName === model.global_model_name" class="w-3.5 h-3.5 animate-spin" />
<Play v-else class="w-3.5 h-3.5" />
</Button>
</div> </div>
</div> </div>
</div> </div>
@@ -148,16 +161,17 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, watch } from 'vue' import { ref, computed, watch } from 'vue'
import { Box, Loader2, Settings2 } from 'lucide-vue-next' import { Box, Loader2, Settings2, Play } from 'lucide-vue-next'
import { Dialog } from '@/components/ui' import { Dialog } from '@/components/ui'
import Button from '@/components/ui/button.vue' import Button from '@/components/ui/button.vue'
import Badge from '@/components/ui/badge.vue' import Badge from '@/components/ui/badge.vue'
import Checkbox from '@/components/ui/checkbox.vue' import Checkbox from '@/components/ui/checkbox.vue'
import { useToast } from '@/composables/useToast' import { useToast } from '@/composables/useToast'
import { parseApiError } from '@/utils/errorParser' import { parseApiError, parseTestModelError } from '@/utils/errorParser'
import { import {
updateEndpointKey, updateEndpointKey,
getProviderAvailableSourceModels, getProviderAvailableSourceModels,
testModel,
type EndpointAPIKey, type EndpointAPIKey,
type ProviderAvailableSourceModel type ProviderAvailableSourceModel
} from '@/api/endpoints' } from '@/api/endpoints'
@@ -181,6 +195,7 @@ const loadingModels = ref(false)
const availableModels = ref<ProviderAvailableSourceModel[]>([]) const availableModels = ref<ProviderAvailableSourceModel[]>([])
const selectedModels = ref<string[]>([]) const selectedModels = ref<string[]>([])
const initialModels = ref<string[]>([]) const initialModels = ref<string[]>([])
const testingModelName = ref<string | null>(null)
// 监听对话框打开 // 监听对话框打开
watch(() => props.open, (open) => { watch(() => props.open, (open) => {
@@ -268,6 +283,32 @@ function clearModels() {
selectedModels.value = [] selectedModels.value = []
} }
// 测试模型连接
async function testModelConnection(model: ProviderAvailableSourceModel) {
if (!props.providerId || !props.apiKey || testingModelName.value) return
testingModelName.value = model.global_model_name
try {
const result = await testModel({
provider_id: props.providerId,
model_name: model.provider_model_name,
api_key_id: props.apiKey.id,
message: "hello"
})
if (result.success) {
success(`模型 "${model.display_name}" 测试成功`)
} else {
showError(`模型测试失败: ${parseTestModelError(result)}`)
}
} catch (err: any) {
const errorMsg = err.response?.data?.detail || err.message || '测试请求失败'
showError(`模型测试失败: ${errorMsg}`)
} finally {
testingModelName.value = null
}
}
function areArraysEqual(a: string[], b: string[]): boolean { function areArraysEqual(a: string[], b: string[]): boolean {
if (a.length !== b.length) return false if (a.length !== b.length) return false
const sortedA = [...a].sort() const sortedA = [...a].sort()

View File

@@ -156,17 +156,6 @@
</td> </td>
<td class="align-top px-4 py-3"> <td class="align-top px-4 py-3">
<div class="flex justify-center gap-1.5"> <div class="flex justify-center gap-1.5">
<Button
variant="ghost"
size="icon"
class="h-8 w-8"
title="测试模型"
:disabled="testingModelId === model.id"
@click="testModelConnection(model)"
>
<Loader2 v-if="testingModelId === model.id" class="w-3.5 h-3.5 animate-spin" />
<Play v-else class="w-3.5 h-3.5" />
</Button>
<Button <Button
variant="ghost" variant="ghost"
size="icon" size="icon"
@@ -220,14 +209,13 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, onMounted } from 'vue' import { ref, computed, onMounted } from 'vue'
import { Box, Edit, Trash2, Layers, Eye, Wrench, Zap, Brain, Power, Copy, Image, Loader2, Play } from 'lucide-vue-next' import { Box, Edit, Trash2, Layers, Eye, Wrench, Zap, Brain, Power, Copy, Image } from 'lucide-vue-next'
import Card from '@/components/ui/card.vue' import Card from '@/components/ui/card.vue'
import Button from '@/components/ui/button.vue' import Button from '@/components/ui/button.vue'
import { useToast } from '@/composables/useToast' import { useToast } from '@/composables/useToast'
import { useClipboard } from '@/composables/useClipboard' import { useClipboard } from '@/composables/useClipboard'
import { getProviderModels, testModel, type Model } from '@/api/endpoints' import { getProviderModels, type Model } from '@/api/endpoints'
import { updateModel } from '@/api/endpoints/models' import { updateModel } from '@/api/endpoints/models'
import { parseTestModelError } from '@/utils/errorParser'
const props = defineProps<{ const props = defineProps<{
provider: any provider: any
@@ -246,7 +234,6 @@ const { copyToClipboard } = useClipboard()
const loading = ref(false) const loading = ref(false)
const models = ref<Model[]>([]) const models = ref<Model[]>([])
const togglingModelId = ref<string | null>(null) const togglingModelId = ref<string | null>(null)
const testingModelId = ref<string | null>(null)
// 按名称排序的模型列表 // 按名称排序的模型列表
const sortedModels = computed(() => { const sortedModels = computed(() => {
@@ -390,39 +377,6 @@ async function toggleModelActive(model: Model) {
} }
} }
// 测试模型连接性
async function testModelConnection(model: Model) {
if (testingModelId.value) return
testingModelId.value = model.id
try {
const result = await testModel({
provider_id: props.provider.id,
model_name: model.provider_model_name,
message: "hello"
})
if (result.success) {
showSuccess(`模型 "${model.provider_model_name}" 测试成功`)
// 如果有响应内容,可以显示更多信息
if (result.data?.response?.choices?.[0]?.message?.content) {
const content = result.data.response.choices[0].message.content
showSuccess(`测试成功,响应: ${content.substring(0, 100)}${content.length > 100 ? '...' : ''}`)
} else if (result.data?.content_preview) {
showSuccess(`流式测试成功,预览: ${result.data.content_preview}`)
}
} else {
showError(`模型测试失败: ${parseTestModelError(result)}`)
}
} catch (err: any) {
const errorMsg = err.response?.data?.detail || err.message || '测试请求失败'
showError(`模型测试失败: ${errorMsg}`)
} finally {
testingModelId.value = null
}
}
onMounted(() => { onMounted(() => {
loadModels() loadModels()
}) })