Skip to content

Commit 43dc4ce

Browse files
committed
Add support for new AI providers and enhance settings interface
- Integrated new AI providers: Groq, Together AI, Fireworks, DeepSeek, xAI, and Mistral, including their respective API keys and configurations. - Updated the Settings component to include new provider options with descriptions and placeholders for API keys. - Introduced a new ProviderIcon component to visually represent each provider in the settings interface. - Enhanced the API client and routing logic to accommodate the new providers, ensuring proper handling of requests and responses. - Refactored the provider management logic to streamline the addition of new providers and improve overall maintainability.
1 parent 0de3efc commit 43dc4ce

10 files changed

Lines changed: 1567 additions & 54 deletions

File tree

interface/bun.lock

Lines changed: 810 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

interface/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"@hookform/resolvers": "^5.2.2",
1818
"@hugeicons/core-free-icons": "^3.1.1",
1919
"@hugeicons/react": "^1.1.5",
20+
"@lobehub/icons": "^4.6.0",
2021
"@radix-ui/react-checkbox": "^1.3.3",
2122
"@radix-ui/react-dialog": "^1.1.15",
2223
"@radix-ui/react-dropdown-menu": "^2.1.16",

interface/src/api/client.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,12 @@ export interface ProviderStatus {
631631
openai: boolean;
632632
openrouter: boolean;
633633
zhipu: boolean;
634+
groq: boolean;
635+
together: boolean;
636+
fireworks: boolean;
637+
deepseek: boolean;
638+
xai: boolean;
639+
mistral: boolean;
634640
}
635641

636642
export interface ProvidersResponse {
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import Anthropic from "@lobehub/icons/es/Anthropic";
2+
import OpenAI from "@lobehub/icons/es/OpenAI";
3+
import OpenRouter from "@lobehub/icons/es/OpenRouter";
4+
import Groq from "@lobehub/icons/es/Groq";
5+
import Mistral from "@lobehub/icons/es/Mistral";
6+
import DeepSeek from "@lobehub/icons/es/DeepSeek";
7+
import Fireworks from "@lobehub/icons/es/Fireworks";
8+
import Together from "@lobehub/icons/es/Together";
9+
import XAI from "@lobehub/icons/es/XAI";
10+
import Zhipu from "@lobehub/icons/es/Zhipu";
11+
12+
interface IconProps {
13+
size?: number;
14+
className?: string;
15+
}
16+
17+
interface ProviderIconProps {
18+
provider: string;
19+
className?: string;
20+
size?: number;
21+
}
22+
23+
export function ProviderIcon({ provider, className = "text-ink-faint", size = 24 }: ProviderIconProps) {
24+
const iconProps: Partial<IconProps> = {
25+
size,
26+
className,
27+
};
28+
29+
const iconMap: Record<string, React.ComponentType<IconProps>> = {
30+
anthropic: Anthropic,
31+
openai: OpenAI,
32+
openrouter: OpenRouter,
33+
groq: Groq,
34+
mistral: Mistral,
35+
deepseek: DeepSeek,
36+
fireworks: Fireworks,
37+
together: Together,
38+
xai: XAI,
39+
zhipu: Zhipu,
40+
};
41+
42+
const IconComponent = iconMap[provider.toLowerCase()];
43+
44+
if (!IconComponent) {
45+
return <OpenAI {...iconProps} />;
46+
}
47+
48+
return <IconComponent {...iconProps} />;
49+
}

interface/src/routes/Settings.tsx

Lines changed: 100 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {api, type PlatformStatus} from "@/api/client";
44
import {Button, Input, SettingSidebarButton, Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, Select, SelectTrigger, SelectValue, SelectContent, SelectItem} from "@/ui";
55
import {useSearch, useNavigate} from "@tanstack/react-router";
66
import {PlatformIcon} from "@/lib/platformIcons";
7+
import {ProviderIcon} from "@/lib/providerIcons";
78

89
type SectionId = "providers" | "channels";
910

@@ -56,6 +57,48 @@ const PROVIDERS = [
5657
placeholder: "...",
5758
envVar: "ZHIPU_API_KEY",
5859
},
60+
{
61+
id: "groq",
62+
name: "Groq",
63+
description: "Fast inference for Llama, Mixtral models",
64+
placeholder: "gsk_...",
65+
envVar: "GROQ_API_KEY",
66+
},
67+
{
68+
id: "together",
69+
name: "Together AI",
70+
description: "Wide model selection with competitive pricing",
71+
placeholder: "...",
72+
envVar: "TOGETHER_API_KEY",
73+
},
74+
{
75+
id: "fireworks",
76+
name: "Fireworks AI",
77+
description: "Fast inference for popular OSS models",
78+
placeholder: "...",
79+
envVar: "FIREWORKS_API_KEY",
80+
},
81+
{
82+
id: "deepseek",
83+
name: "DeepSeek",
84+
description: "DeepSeek Chat and Reasoner models",
85+
placeholder: "sk-...",
86+
envVar: "DEEPSEEK_API_KEY",
87+
},
88+
{
89+
id: "xai",
90+
name: "xAI",
91+
description: "Grok models",
92+
placeholder: "xai-...",
93+
envVar: "XAI_API_KEY",
94+
},
95+
{
96+
id: "mistral",
97+
name: "Mistral AI",
98+
description: "Mistral Large, Small, Codestral models",
99+
placeholder: "...",
100+
envVar: "MISTRAL_API_KEY",
101+
},
59102
] as const;
60103

61104
export function Settings() {
@@ -193,52 +236,22 @@ export function Settings() {
193236
</div>
194237
) : (
195238
<div className="flex flex-col gap-3">
196-
{PROVIDERS.map((provider) => {
197-
const configured = isConfigured(provider.id);
198-
199-
return (
200-
<div
201-
key={provider.id}
202-
className="rounded-lg border border-app-line bg-app-box p-4"
203-
>
204-
<div className="flex items-center justify-between">
205-
<div className="flex-1">
206-
<span className="text-sm font-medium text-ink">
207-
{provider.name}
208-
</span>
209-
<p className="mt-0.5 text-sm text-ink-dull">
210-
{provider.description}
211-
</p>
212-
</div>
213-
<div className="flex gap-2">
214-
<Button
215-
onClick={() => {
216-
setEditingProvider(provider.id);
217-
setKeyInput("");
218-
setMessage(null);
219-
}}
220-
variant="outline"
221-
size="sm"
222-
>
223-
{configured ? "Update" : "Add key"}
224-
</Button>
225-
{configured && (
226-
<Button
227-
onClick={() =>
228-
removeMutation.mutate(provider.id)
229-
}
230-
variant="outline"
231-
size="sm"
232-
loading={removeMutation.isPending}
233-
>
234-
Remove
235-
</Button>
236-
)}
237-
</div>
238-
</div>
239-
</div>
240-
);
241-
})}
239+
{PROVIDERS.map((provider) => (
240+
<ProviderCard
241+
key={provider.id}
242+
provider={provider.id}
243+
name={provider.name}
244+
description={provider.description}
245+
configured={isConfigured(provider.id)}
246+
onEdit={() => {
247+
setEditingProvider(provider.id);
248+
setKeyInput("");
249+
setMessage(null);
250+
}}
251+
onRemove={() => removeMutation.mutate(provider.id)}
252+
removing={removeMutation.isPending}
253+
/>
254+
))}
242255
</div>
243256
)}
244257

@@ -1039,3 +1052,44 @@ function PlatformCard({ platform, name, description, status, disabled = false, o
10391052
</div>
10401053
);
10411054
}
1055+
1056+
interface ProviderCardProps {
1057+
provider: string;
1058+
name: string;
1059+
description: string;
1060+
configured: boolean;
1061+
onEdit: () => void;
1062+
onRemove: () => void;
1063+
removing: boolean;
1064+
}
1065+
1066+
function ProviderCard({ provider, name, description, configured, onEdit, onRemove, removing }: ProviderCardProps) {
1067+
return (
1068+
<div className="rounded-lg border border-app-line bg-app-box p-4">
1069+
<div className="flex items-center gap-3">
1070+
<ProviderIcon provider={provider} size={32} />
1071+
<div className="flex-1">
1072+
<div className="flex items-center gap-2">
1073+
<span className="text-sm font-medium text-ink">{name}</span>
1074+
{configured && (
1075+
<span className="text-tiny text-green-400">
1076+
● Configured
1077+
</span>
1078+
)}
1079+
</div>
1080+
<p className="mt-0.5 text-sm text-ink-dull">{description}</p>
1081+
</div>
1082+
<div className="flex gap-2">
1083+
<Button onClick={onEdit} variant="outline" size="sm">
1084+
{configured ? "Update" : "Add key"}
1085+
</Button>
1086+
{configured && (
1087+
<Button onClick={onRemove} variant="outline" size="sm" loading={removing}>
1088+
Remove
1089+
</Button>
1090+
)}
1091+
</div>
1092+
</div>
1093+
</div>
1094+
);
1095+
}

0 commit comments

Comments
 (0)