update models settings, add custom openai compatible

This commit is contained in:
duanfuxiang 2025-03-18 09:39:25 +08:00
parent 9977b4ee77
commit 76288377c3
2 changed files with 67 additions and 44 deletions

View File

@ -44,6 +44,7 @@ class LLMManager implements LLMManagerInterface {
private siliconflowProvider: OpenAICompatibleProvider
private alibabaQwenProvider: OpenAICompatibleProvider
private ollamaProvider: OllamaProvider
private openaiCompatibleProvider: OpenAICompatibleProvider
private isInfioEnabled: boolean
constructor(settings: InfioSettings) {
@ -57,6 +58,7 @@ class LLMManager implements LLMManagerInterface {
this.googleProvider = new GeminiProvider(settings.googleProvider.apiKey)
this.groqProvider = new GroqProvider(settings.groqProvider.apiKey)
this.ollamaProvider = new OllamaProvider(settings.groqProvider.baseUrl)
this.openaiCompatibleProvider = new OpenAICompatibleProvider(settings.openaicompatibleProvider.apiKey, settings.openaicompatibleProvider.baseUrl)
this.isInfioEnabled = !!settings.infioProvider.apiKey
}
@ -160,6 +162,8 @@ class LLMManager implements LLMManagerInterface {
return await this.groqProvider.streamResponse(model, request, options)
case ApiProvider.Ollama:
return await this.ollamaProvider.streamResponse(model, request, options)
case ApiProvider.OpenAICompatible:
return await this.openaiCompatibleProvider.streamResponse(model, request, options)
}
}
}

View File

@ -160,10 +160,10 @@ export const ComboBoxComponent: React.FC<ComboBoxComponentProps> = ({
isEmbedding = false,
updateModel,
}) => {
// 提供商选择状态
// provider state
const [modelProvider, setModelProvider] = useState(provider);
// 搜索输入状态
// search state
const [searchTerm, setSearchTerm] = useState("");
const [isOpen, setIsOpen] = useState(false);
const [selectedIndex, setSelectedIndex] = useState(0);
@ -175,12 +175,12 @@ export const ComboBoxComponent: React.FC<ComboBoxComponentProps> = ({
// Replace useMemo with useEffect for async fetching
useEffect(() => {
const fetchModelIds = async () => {
const ids = isEmbedding
? GetEmbeddingProviderModelIds(modelProvider)
const ids = isEmbedding
? GetEmbeddingProviderModelIds(modelProvider)
: await GetProviderModelIds(modelProvider);
setModelIds(ids);
};
fetchModelIds();
}, [modelProvider, isEmbedding]);
@ -191,7 +191,7 @@ export const ComboBoxComponent: React.FC<ComboBoxComponentProps> = ({
}))
}, [modelIds])
// 初始化 fuse用于模糊搜索简单配置 threshold 可按需调整
// fuse, used for fuzzy search, simple configuration threshold can be adjusted as needed
const fuse: Fuse<SearchableItem> = useMemo(() => {
return new Fuse<SearchableItem>(searchableItems, {
keys: ["html"],
@ -218,7 +218,7 @@ export const ComboBoxComponent: React.FC<ComboBoxComponentProps> = ({
const listRef = useRef<HTMLDivElement>(null);
const itemRefs = useRef<Array<HTMLDivElement | null>>([]);
// 当选中项发生变化时,滚动到可视区域内
// when selected index changes, scroll to visible area
useEffect(() => {
if (itemRefs.current[selectedIndex]) {
itemRefs.current[selectedIndex]?.scrollIntoView({
@ -234,7 +234,7 @@ export const ComboBoxComponent: React.FC<ComboBoxComponentProps> = ({
<Popover.Root modal={false} open={isOpen} onOpenChange={setIsOpen}>
<Popover.Trigger asChild>
<div className="infio-llm-setting-item-control">
<span className="infio-llm-setting-model-id">{modelId}</span>
<span className="infio-llm-setting-model-id">[{modelProvider}]{modelId}</span>
</div>
</Popover.Trigger>
<Popover.Content
@ -260,45 +260,64 @@ export const ComboBoxComponent: React.FC<ComboBoxComponentProps> = ({
</option>
))}
</select>
<input
type="text"
className="infio-llm-setting-item-search"
placeholder="search model..."
value={searchTerm}
onChange={(e) => {
setSearchTerm(e.target.value);
setSelectedIndex(0);
}}
onKeyDown={(e) => {
switch (e.key) {
case "ArrowDown":
e.preventDefault();
setSelectedIndex((prev) =>
Math.min(prev + 1, filteredOptions.length - 1)
);
break;
case "ArrowUp":
e.preventDefault();
setSelectedIndex((prev) => Math.max(prev - 1, 0));
break;
case "Enter": {
e.preventDefault();
const selectedOption = filteredOptions[selectedIndex];
if (selectedOption) {
updateModel(modelProvider, selectedOption.id);
{modelIds.length > 0 ? (
<input
type="text"
className="infio-llm-setting-item-search"
placeholder="search model..."
value={searchTerm}
onChange={(e) => {
setSearchTerm(e.target.value);
setSelectedIndex(0);
}}
onKeyDown={(e) => {
switch (e.key) {
case "ArrowDown":
e.preventDefault();
setSelectedIndex((prev) =>
Math.min(prev + 1, filteredOptions.length - 1)
);
break;
case "ArrowUp":
e.preventDefault();
setSelectedIndex((prev) => Math.max(prev - 1, 0));
break;
case "Enter": {
e.preventDefault();
const selectedOption = filteredOptions[selectedIndex];
if (selectedOption) {
updateModel(modelProvider, selectedOption.id);
setSearchTerm("");
setIsOpen(false);
}
break;
}
case "Escape":
e.preventDefault();
setIsOpen(false);
setSearchTerm("");
break;
}
}}
/>
) : (
<input
type="text"
className="infio-llm-setting-item-search"
placeholder="input custom model name"
value={searchTerm}
onChange={(e) => {
setSearchTerm(e.target.value);
}}
onKeyDown={(e) => {
if (e.key === "Enter") {
e.preventDefault();
updateModel(modelProvider, searchTerm);
setIsOpen(false);
}
break;
}
case "Escape":
e.preventDefault();
setIsOpen(false);
setSearchTerm("");
break;
}
}}
/>
}}
/>
)}
</div>
{filteredOptions.map((option, index) => (
<Popover.Close key={option.id} asChild>