Fix: simplify fetchOpenAICompatibleModelsInfo function
- fix clickoutside on inputwithselect component - Add type-search on inputwithselect
This commit is contained in:
1 parent
074336fa53
commit
4edf9fe85b
2 files changed
+52
-50
No files matched your search
@@ -531,62 +531,25 @@ export class LLMService implements ILLMService {
|
||||
const response = await openai.models.list();
|
||||
console.log('API返回的原始模型列表:', response);
|
||||
|
||||
// 检查响应格式
|
||||
// 只处理标准 OpenAI 格式
|
||||
if (response && response.data && Array.isArray(response.data)) {
|
||||
// 标准 OpenAI 格式
|
||||
return response.data
|
||||
.map(model => ({
|
||||
id: model.id,
|
||||
name: model.id
|
||||
}))
|
||||
.sort((a, b) => a.id.localeCompare(b.id));
|
||||
} else if (response && Array.isArray(response)) {
|
||||
// 可能是一个简单的模型 ID 数组
|
||||
return response
|
||||
.map(modelId => ({
|
||||
id: typeof modelId === 'string' ? modelId :
|
||||
typeof modelId === 'object' && modelId !== null ?
|
||||
(modelId.id || modelId.name || String(modelId)) : String(modelId),
|
||||
name: typeof modelId === 'string' ? modelId :
|
||||
typeof modelId === 'object' && modelId !== null ?
|
||||
(modelId.name || modelId.id || String(modelId)) : String(modelId)
|
||||
}))
|
||||
.sort((a, b) => a.id.localeCompare(b.id));
|
||||
} else if (response && typeof response === 'object') {
|
||||
// 尝试从对象中提取有用信息
|
||||
const possibleArrayProps = ['models', 'data', 'items', 'results', 'list'];
|
||||
|
||||
for (const prop of possibleArrayProps) {
|
||||
if (response[prop as keyof typeof response] &&
|
||||
Array.isArray(response[prop as keyof typeof response])) {
|
||||
const modelArray = response[prop as keyof typeof response] as any[];
|
||||
return modelArray
|
||||
.map(model => {
|
||||
// 处理不同类型的模型对象
|
||||
if (typeof model === 'string') {
|
||||
return { id: model, name: model };
|
||||
} else if (typeof model === 'object' && model !== null) {
|
||||
const id = model.id || model.name || model.model || String(model);
|
||||
const name = model.name || model.id || model.model || String(model);
|
||||
return { id: String(id), name: String(name) };
|
||||
} else {
|
||||
return { id: String(model), name: String(model) };
|
||||
}
|
||||
})
|
||||
.sort((a, b) => a.id.localeCompare(b.id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果无法解析响应格式,记录并返回空数组
|
||||
console.warn('无法解析API响应格式:', response);
|
||||
// 如果格式不匹配标准格式,记录并返回空数组
|
||||
console.warn('API返回格式与预期不符:', response);
|
||||
return [];
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('获取模型列表失败:', error);
|
||||
console.log('错误详情:', error.response?.data || error.message);
|
||||
|
||||
// 对于自定义接口,返回空数组
|
||||
// 发生错误时返回空数组
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<template>
|
||||
<div class="relative">
|
||||
<div ref="componentRef" class="relative">
|
||||
<div class="flex">
|
||||
<input
|
||||
ref="inputRef"
|
||||
:value="modelValue"
|
||||
@input="$emit('update:modelValue', $event.target.value)"
|
||||
@input="handleInput"
|
||||
:type="type"
|
||||
:required="required"
|
||||
:placeholder="placeholder"
|
||||
@@ -53,12 +54,12 @@
|
||||
<div v-if="isLoading" class="p-2 text-center theme-manager-text-secondary">
|
||||
{{ loadingText }}
|
||||
</div>
|
||||
<div v-else-if="options.length === 0" class="p-2 text-center theme-manager-text-secondary">
|
||||
<div v-else-if="filteredOptions.length === 0" class="p-2 text-center theme-manager-text-secondary">
|
||||
{{ noOptionsText }}
|
||||
</div>
|
||||
<ul v-else class="py-1">
|
||||
<li
|
||||
v-for="option in options"
|
||||
v-for="option in filteredOptions"
|
||||
:key="option.value"
|
||||
@click="selectOption(option)"
|
||||
:class="[
|
||||
@@ -74,7 +75,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, defineProps, defineEmits, onMounted, onUnmounted } from 'vue';
|
||||
import { ref, defineProps, defineEmits, onMounted, onUnmounted, computed } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
@@ -126,14 +127,38 @@ const props = defineProps({
|
||||
const emit = defineEmits(['update:modelValue', 'select', 'fetchOptions']);
|
||||
|
||||
const isOpen = ref(false);
|
||||
const inputRef = ref(null);
|
||||
const searchText = ref('');
|
||||
|
||||
// 根据输入内容筛选选项
|
||||
const filteredOptions = computed(() => {
|
||||
if (!searchText.value) return props.options;
|
||||
return props.options.filter(option =>
|
||||
option.label.toLowerCase().includes(searchText.value.toLowerCase()) ||
|
||||
option.value.toLowerCase().includes(searchText.value.toLowerCase())
|
||||
);
|
||||
});
|
||||
|
||||
// 处理输入事件
|
||||
const handleInput = (event) => {
|
||||
const value = event.target.value;
|
||||
emit('update:modelValue', value);
|
||||
searchText.value = value;
|
||||
};
|
||||
|
||||
// Toggle dropdown visibility
|
||||
const toggleDropdown = async () => {
|
||||
isOpen.value = !isOpen.value;
|
||||
|
||||
// If dropdown is being opened and we have a fetch function, call it
|
||||
// 如果打开下拉菜单,聚焦到输入框
|
||||
if (isOpen.value) {
|
||||
emit('fetchOptions');
|
||||
// 等待DOM更新后聚焦
|
||||
setTimeout(() => {
|
||||
if (inputRef.value) {
|
||||
inputRef.value.focus();
|
||||
}
|
||||
}, 10);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -142,25 +167,39 @@ const selectOption = (option) => {
|
||||
emit('update:modelValue', option.value);
|
||||
emit('select', option);
|
||||
isOpen.value = false;
|
||||
searchText.value = '';
|
||||
};
|
||||
|
||||
// Close dropdown when clicking outside
|
||||
const handleClickOutside = (event) => {
|
||||
if (isOpen.value && !event.target.closest('.relative')) {
|
||||
console.log('Click detected', {
|
||||
isOpen: isOpen.value,
|
||||
isComponent: componentRef.value && componentRef.value.contains(event.target),
|
||||
target: event.target
|
||||
});
|
||||
|
||||
// 只有在下拉菜单打开且点击的是组件外部时才关闭下拉菜单
|
||||
if (isOpen.value && componentRef.value && !componentRef.value.contains(event.target)) {
|
||||
console.log('Closing dropdown');
|
||||
isOpen.value = false;
|
||||
searchText.value = '';
|
||||
}
|
||||
};
|
||||
|
||||
// 组件引用
|
||||
const componentRef = ref(null);
|
||||
|
||||
// Add and remove event listener
|
||||
onMounted(() => {
|
||||
if (typeof document !== 'undefined') {
|
||||
document.addEventListener('click', handleClickOutside);
|
||||
// 使用捕获阶段以确保事件能够被正确捕获
|
||||
document.addEventListener('mousedown', handleClickOutside, true);
|
||||
}
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (typeof document !== 'undefined') {
|
||||
document.removeEventListener('click', handleClickOutside);
|
||||
document.removeEventListener('mousedown', handleClickOutside, true);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in new issue
Block a user