feat(byok): fetch live models dynamically from provider api with user api key on input
Some checks failed
CI / Deploy production (on server) (push) Has been cancelled
CI / Lint, Unit Tests & Build (push) Has been cancelled

This commit is contained in:
Antigravity
2026-05-28 21:49:32 +00:00
parent 6703e75bf3
commit 7cc2a9ea3b
3 changed files with 177 additions and 11 deletions

View File

@@ -53,6 +53,10 @@ export function ByokSettingsPanel() {
const [customModel, setCustomModel] = useState('')
const [isCustomModel, setIsCustomModel] = useState(false)
// Dynamic models fetched directly via user's API Key
const [liveModels, setLiveModels] = useState<string[]>([])
const [isFetchingLiveModels, setIsFetchingLiveModels] = useState(false)
const { data, isLoading, error } = useQuery({
queryKey: ['user', 'api-keys'],
queryFn: fetchByokKeys,
@@ -62,13 +66,46 @@ export function ByokSettingsPanel() {
const handleProviderChange = (p: string) => {
setProvider(p)
const sug = providerModels[p] || []
if (sug.length > 0) {
setModel(sug[0])
setApiKey('')
setLiveModels([])
setIsCustomModel(false)
setModel('')
setCustomModel('')
}
// Triggered dynamically to fetch models when user enters/pastes their API key
const fetchLiveModels = async (p: string, key: string) => {
if (!p || !key || key.length < 8) return;
setIsFetchingLiveModels(true)
try {
const query = new URLSearchParams({ provider: p, key })
const res = await fetch(`/api/user/api-keys/live-models?${query.toString()}`)
if (res.ok) {
const body = await res.json()
if (body.success && Array.isArray(body.models)) {
setLiveModels(body.models)
if (body.models.length > 0) {
setModel(body.models[0])
setIsCustomModel(false)
} else {
setIsCustomModel(true)
}
return;
}
}
} catch (err) {
console.error('[fetchLiveModels] Failed:', err)
} finally {
setIsFetchingLiveModels(false)
}
// Fallback if request fails
const fallbackList = providerModels[p] || []
setLiveModels(fallbackList)
if (fallbackList.length > 0) {
setModel(fallbackList[0])
setIsCustomModel(false)
} else {
setModel('')
setCustomModel('')
setIsCustomModel(true)
}
}
@@ -104,6 +141,7 @@ export function ByokSettingsPanel() {
setProvider('')
setModel('')
setCustomModel('')
setLiveModels([])
setIsCustomModel(false)
invalidate()
},
@@ -230,8 +268,15 @@ export function ByokSettingsPanel() {
{provider && (
<div className="grid gap-4 sm:grid-cols-2 pt-2 border-t border-border/40">
<div className="space-y-2">
<Label htmlFor="byok-model-select" className="text-[10px] font-bold uppercase tracking-widest text-concrete">Modèle de l'IA (Optionnel)</Label>
{providerModels[provider] && providerModels[provider].length > 0 ? (
<Label htmlFor="byok-model-select" className="text-[10px] font-bold uppercase tracking-widest text-concrete">
Modèle de l'IA (Optionnel)
</Label>
{isFetchingLiveModels ? (
<div className="flex items-center gap-2 text-xs text-concrete py-2">
<Loader2 className="h-3 w-3 animate-spin text-brand-accent" />
Récupération de vos modèles disponibles...
</div>
) : liveModels && liveModels.length > 0 ? (
<Select
value={isCustomModel ? 'custom' : model}
onValueChange={(val) => {
@@ -248,7 +293,7 @@ export function ByokSettingsPanel() {
<SelectValue placeholder="Choisir un modèle..." />
</SelectTrigger>
<SelectContent>
{providerModels[provider].map((m) => (
{liveModels.map((m) => (
<SelectItem key={m} value={m}>
{m}
</SelectItem>
@@ -258,12 +303,12 @@ export function ByokSettingsPanel() {
</Select>
) : (
<div className="text-xs text-concrete py-2 italic">
Spécifiez le modèle ci-contre si besoin.
Entrez votre clé API ci-dessous pour charger vos modèles.
</div>
)}
</div>
{(isCustomModel || !(providerModels[provider] && providerModels[provider].length > 0)) && (
{(isCustomModel || (!isFetchingLiveModels && !(liveModels && liveModels.length > 0))) && (
<div className="space-y-2">
<Label htmlFor="byok-model-custom" className="text-[10px] font-bold uppercase tracking-widest text-concrete">Saisir le nom du modèle</Label>
<Input
@@ -290,7 +335,11 @@ export function ByokSettingsPanel() {
type="password"
autoComplete="off"
value={apiKey}
onChange={(e) => setApiKey(e.target.value)}
onChange={(e) => {
const val = e.target.value
setApiKey(val)
fetchLiveModels(provider, val)
}}
placeholder={t('byokSettings.apiKeyPlaceholder')}
disabled={saveMutation.isPending}
/>