update models settings, add custom openai compatible
This commit is contained in:
parent
9977b4ee77
commit
76288377c3
@ -44,6 +44,7 @@ class LLMManager implements LLMManagerInterface {
|
|||||||
private siliconflowProvider: OpenAICompatibleProvider
|
private siliconflowProvider: OpenAICompatibleProvider
|
||||||
private alibabaQwenProvider: OpenAICompatibleProvider
|
private alibabaQwenProvider: OpenAICompatibleProvider
|
||||||
private ollamaProvider: OllamaProvider
|
private ollamaProvider: OllamaProvider
|
||||||
|
private openaiCompatibleProvider: OpenAICompatibleProvider
|
||||||
private isInfioEnabled: boolean
|
private isInfioEnabled: boolean
|
||||||
|
|
||||||
constructor(settings: InfioSettings) {
|
constructor(settings: InfioSettings) {
|
||||||
@ -57,6 +58,7 @@ class LLMManager implements LLMManagerInterface {
|
|||||||
this.googleProvider = new GeminiProvider(settings.googleProvider.apiKey)
|
this.googleProvider = new GeminiProvider(settings.googleProvider.apiKey)
|
||||||
this.groqProvider = new GroqProvider(settings.groqProvider.apiKey)
|
this.groqProvider = new GroqProvider(settings.groqProvider.apiKey)
|
||||||
this.ollamaProvider = new OllamaProvider(settings.groqProvider.baseUrl)
|
this.ollamaProvider = new OllamaProvider(settings.groqProvider.baseUrl)
|
||||||
|
this.openaiCompatibleProvider = new OpenAICompatibleProvider(settings.openaicompatibleProvider.apiKey, settings.openaicompatibleProvider.baseUrl)
|
||||||
this.isInfioEnabled = !!settings.infioProvider.apiKey
|
this.isInfioEnabled = !!settings.infioProvider.apiKey
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,6 +162,8 @@ class LLMManager implements LLMManagerInterface {
|
|||||||
return await this.groqProvider.streamResponse(model, request, options)
|
return await this.groqProvider.streamResponse(model, request, options)
|
||||||
case ApiProvider.Ollama:
|
case ApiProvider.Ollama:
|
||||||
return await this.ollamaProvider.streamResponse(model, request, options)
|
return await this.ollamaProvider.streamResponse(model, request, options)
|
||||||
|
case ApiProvider.OpenAICompatible:
|
||||||
|
return await this.openaiCompatibleProvider.streamResponse(model, request, options)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -160,10 +160,10 @@ export const ComboBoxComponent: React.FC<ComboBoxComponentProps> = ({
|
|||||||
isEmbedding = false,
|
isEmbedding = false,
|
||||||
updateModel,
|
updateModel,
|
||||||
}) => {
|
}) => {
|
||||||
// 提供商选择状态
|
// provider state
|
||||||
const [modelProvider, setModelProvider] = useState(provider);
|
const [modelProvider, setModelProvider] = useState(provider);
|
||||||
|
|
||||||
// 搜索输入状态
|
// search state
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
const [searchTerm, setSearchTerm] = useState("");
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [selectedIndex, setSelectedIndex] = useState(0);
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
||||||
@ -175,12 +175,12 @@ export const ComboBoxComponent: React.FC<ComboBoxComponentProps> = ({
|
|||||||
// Replace useMemo with useEffect for async fetching
|
// Replace useMemo with useEffect for async fetching
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchModelIds = async () => {
|
const fetchModelIds = async () => {
|
||||||
const ids = isEmbedding
|
const ids = isEmbedding
|
||||||
? GetEmbeddingProviderModelIds(modelProvider)
|
? GetEmbeddingProviderModelIds(modelProvider)
|
||||||
: await GetProviderModelIds(modelProvider);
|
: await GetProviderModelIds(modelProvider);
|
||||||
setModelIds(ids);
|
setModelIds(ids);
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchModelIds();
|
fetchModelIds();
|
||||||
}, [modelProvider, isEmbedding]);
|
}, [modelProvider, isEmbedding]);
|
||||||
|
|
||||||
@ -191,7 +191,7 @@ export const ComboBoxComponent: React.FC<ComboBoxComponentProps> = ({
|
|||||||
}))
|
}))
|
||||||
}, [modelIds])
|
}, [modelIds])
|
||||||
|
|
||||||
// 初始化 fuse,用于模糊搜索,简单配置 threshold 可按需调整
|
// fuse, used for fuzzy search, simple configuration threshold can be adjusted as needed
|
||||||
const fuse: Fuse<SearchableItem> = useMemo(() => {
|
const fuse: Fuse<SearchableItem> = useMemo(() => {
|
||||||
return new Fuse<SearchableItem>(searchableItems, {
|
return new Fuse<SearchableItem>(searchableItems, {
|
||||||
keys: ["html"],
|
keys: ["html"],
|
||||||
@ -218,7 +218,7 @@ export const ComboBoxComponent: React.FC<ComboBoxComponentProps> = ({
|
|||||||
const listRef = useRef<HTMLDivElement>(null);
|
const listRef = useRef<HTMLDivElement>(null);
|
||||||
const itemRefs = useRef<Array<HTMLDivElement | null>>([]);
|
const itemRefs = useRef<Array<HTMLDivElement | null>>([]);
|
||||||
|
|
||||||
// 当选中项发生变化时,滚动到可视区域内
|
// when selected index changes, scroll to visible area
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (itemRefs.current[selectedIndex]) {
|
if (itemRefs.current[selectedIndex]) {
|
||||||
itemRefs.current[selectedIndex]?.scrollIntoView({
|
itemRefs.current[selectedIndex]?.scrollIntoView({
|
||||||
@ -234,7 +234,7 @@ export const ComboBoxComponent: React.FC<ComboBoxComponentProps> = ({
|
|||||||
<Popover.Root modal={false} open={isOpen} onOpenChange={setIsOpen}>
|
<Popover.Root modal={false} open={isOpen} onOpenChange={setIsOpen}>
|
||||||
<Popover.Trigger asChild>
|
<Popover.Trigger asChild>
|
||||||
<div className="infio-llm-setting-item-control">
|
<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>
|
</div>
|
||||||
</Popover.Trigger>
|
</Popover.Trigger>
|
||||||
<Popover.Content
|
<Popover.Content
|
||||||
@ -260,45 +260,64 @@ export const ComboBoxComponent: React.FC<ComboBoxComponentProps> = ({
|
|||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
<input
|
{modelIds.length > 0 ? (
|
||||||
type="text"
|
<input
|
||||||
className="infio-llm-setting-item-search"
|
type="text"
|
||||||
placeholder="search model..."
|
className="infio-llm-setting-item-search"
|
||||||
value={searchTerm}
|
placeholder="search model..."
|
||||||
onChange={(e) => {
|
value={searchTerm}
|
||||||
setSearchTerm(e.target.value);
|
onChange={(e) => {
|
||||||
setSelectedIndex(0);
|
setSearchTerm(e.target.value);
|
||||||
}}
|
setSelectedIndex(0);
|
||||||
onKeyDown={(e) => {
|
}}
|
||||||
switch (e.key) {
|
onKeyDown={(e) => {
|
||||||
case "ArrowDown":
|
switch (e.key) {
|
||||||
e.preventDefault();
|
case "ArrowDown":
|
||||||
setSelectedIndex((prev) =>
|
e.preventDefault();
|
||||||
Math.min(prev + 1, filteredOptions.length - 1)
|
setSelectedIndex((prev) =>
|
||||||
);
|
Math.min(prev + 1, filteredOptions.length - 1)
|
||||||
break;
|
);
|
||||||
case "ArrowUp":
|
break;
|
||||||
e.preventDefault();
|
case "ArrowUp":
|
||||||
setSelectedIndex((prev) => Math.max(prev - 1, 0));
|
e.preventDefault();
|
||||||
break;
|
setSelectedIndex((prev) => Math.max(prev - 1, 0));
|
||||||
case "Enter": {
|
break;
|
||||||
e.preventDefault();
|
case "Enter": {
|
||||||
const selectedOption = filteredOptions[selectedIndex];
|
e.preventDefault();
|
||||||
if (selectedOption) {
|
const selectedOption = filteredOptions[selectedIndex];
|
||||||
updateModel(modelProvider, selectedOption.id);
|
if (selectedOption) {
|
||||||
|
updateModel(modelProvider, selectedOption.id);
|
||||||
|
setSearchTerm("");
|
||||||
|
setIsOpen(false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "Escape":
|
||||||
|
e.preventDefault();
|
||||||
|
setIsOpen(false);
|
||||||
setSearchTerm("");
|
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);
|
setIsOpen(false);
|
||||||
}
|
}
|
||||||
break;
|
}}
|
||||||
}
|
/>
|
||||||
case "Escape":
|
)}
|
||||||
e.preventDefault();
|
|
||||||
setIsOpen(false);
|
|
||||||
setSearchTerm("");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
{filteredOptions.map((option, index) => (
|
{filteredOptions.map((option, index) => (
|
||||||
<Popover.Close key={option.id} asChild>
|
<Popover.Close key={option.id} asChild>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user