fix: ensure AI provider config is saved correctly in admin
URGENT FIX: Admin form was not properly saving AI provider configuration, causing 'AI_PROVIDER_TAGS is not configured' error even after setting OpenAI. Changes: - admin-settings-form.tsx: Added validation and error handling - admin-settings.ts: Filter empty values before saving to DB - setup-openai.ts: Script to initialize OpenAI as default provider This fixes the critical bug where users couldn't use the app after configuring OpenAI in the admin interface. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -75,43 +75,63 @@ export function AdminSettingsForm({ config }: { config: Record<string, string> }
|
||||
setIsSaving(true)
|
||||
const data: Record<string, string> = {}
|
||||
|
||||
// Tags provider configuration
|
||||
const tagsProv = formData.get('AI_PROVIDER_TAGS') as AIProvider
|
||||
data.AI_PROVIDER_TAGS = tagsProv
|
||||
data.AI_MODEL_TAGS = formData.get('AI_MODEL_TAGS') as string
|
||||
try {
|
||||
// Tags provider configuration
|
||||
const tagsProv = formData.get('AI_PROVIDER_TAGS') as AIProvider
|
||||
if (!tagsProv) throw new Error('AI_PROVIDER_TAGS is required')
|
||||
data.AI_PROVIDER_TAGS = tagsProv
|
||||
|
||||
if (tagsProv === 'ollama') {
|
||||
data.OLLAMA_BASE_URL = formData.get('OLLAMA_BASE_URL_TAGS') as string
|
||||
} else if (tagsProv === 'openai') {
|
||||
data.OPENAI_API_KEY = formData.get('OPENAI_API_KEY') as string
|
||||
} else if (tagsProv === 'custom') {
|
||||
data.CUSTOM_OPENAI_API_KEY = formData.get('CUSTOM_OPENAI_API_KEY_TAGS') as string
|
||||
data.CUSTOM_OPENAI_BASE_URL = formData.get('CUSTOM_OPENAI_BASE_URL_TAGS') as string
|
||||
}
|
||||
const tagsModel = formData.get('AI_MODEL_TAGS') as string
|
||||
if (tagsModel) data.AI_MODEL_TAGS = tagsModel
|
||||
|
||||
// Embeddings provider configuration
|
||||
const embedProv = formData.get('AI_PROVIDER_EMBEDDING') as AIProvider
|
||||
data.AI_PROVIDER_EMBEDDING = embedProv
|
||||
data.AI_MODEL_EMBEDDING = formData.get('AI_MODEL_EMBEDDING') as string
|
||||
if (tagsProv === 'ollama') {
|
||||
const ollamaUrl = formData.get('OLLAMA_BASE_URL_TAGS') as string
|
||||
if (ollamaUrl) data.OLLAMA_BASE_URL = ollamaUrl
|
||||
} else if (tagsProv === 'openai') {
|
||||
const openaiKey = formData.get('OPENAI_API_KEY') as string
|
||||
if (openaiKey) data.OPENAI_API_KEY = openaiKey
|
||||
} else if (tagsProv === 'custom') {
|
||||
const customKey = formData.get('CUSTOM_OPENAI_API_KEY_TAGS') as string
|
||||
const customUrl = formData.get('CUSTOM_OPENAI_BASE_URL_TAGS') as string
|
||||
if (customKey) data.CUSTOM_OPENAI_API_KEY = customKey
|
||||
if (customUrl) data.CUSTOM_OPENAI_BASE_URL = customUrl
|
||||
}
|
||||
|
||||
if (embedProv === 'ollama') {
|
||||
data.OLLAMA_BASE_URL = formData.get('OLLAMA_BASE_URL_EMBEDDING') as string
|
||||
} else if (embedProv === 'openai') {
|
||||
data.OPENAI_API_KEY = formData.get('OPENAI_API_KEY') as string
|
||||
} else if (embedProv === 'custom') {
|
||||
data.CUSTOM_OPENAI_API_KEY = formData.get('CUSTOM_OPENAI_API_KEY_EMBEDDING') as string
|
||||
data.CUSTOM_OPENAI_BASE_URL = formData.get('CUSTOM_OPENAI_BASE_URL_EMBEDDING') as string
|
||||
}
|
||||
// Embeddings provider configuration
|
||||
const embedProv = formData.get('AI_PROVIDER_EMBEDDING') as AIProvider
|
||||
if (!embedProv) throw new Error('AI_PROVIDER_EMBEDDING is required')
|
||||
data.AI_PROVIDER_EMBEDDING = embedProv
|
||||
|
||||
const result = await updateSystemConfig(data)
|
||||
setIsSaving(false)
|
||||
const embedModel = formData.get('AI_MODEL_EMBEDDING') as string
|
||||
if (embedModel) data.AI_MODEL_EMBEDDING = embedModel
|
||||
|
||||
if (result.error) {
|
||||
toast.error('Failed to update AI settings')
|
||||
} else {
|
||||
toast.success('AI Settings updated')
|
||||
setTagsProvider(tagsProv)
|
||||
setEmbeddingsProvider(embedProv)
|
||||
if (embedProv === 'ollama') {
|
||||
const ollamaUrl = formData.get('OLLAMA_BASE_URL_EMBEDDING') as string
|
||||
if (ollamaUrl) data.OLLAMA_BASE_URL = ollamaUrl
|
||||
} else if (embedProv === 'openai') {
|
||||
const openaiKey = formData.get('OPENAI_API_KEY') as string
|
||||
if (openaiKey) data.OPENAI_API_KEY = openaiKey
|
||||
} else if (embedProv === 'custom') {
|
||||
const customKey = formData.get('CUSTOM_OPENAI_API_KEY_EMBEDDING') as string
|
||||
const customUrl = formData.get('CUSTOM_OPENAI_BASE_URL_EMBEDDING') as string
|
||||
if (customKey) data.CUSTOM_OPENAI_API_KEY = customKey
|
||||
if (customUrl) data.CUSTOM_OPENAI_BASE_URL = customUrl
|
||||
}
|
||||
|
||||
console.log('Saving AI config:', data)
|
||||
const result = await updateSystemConfig(data)
|
||||
setIsSaving(false)
|
||||
|
||||
if (result.error) {
|
||||
toast.error('Failed to update AI settings: ' + result.error)
|
||||
} else {
|
||||
toast.success('AI Settings updated successfully')
|
||||
setTagsProvider(tagsProv)
|
||||
setEmbeddingsProvider(embedProv)
|
||||
}
|
||||
} catch (error: any) {
|
||||
setIsSaving(false)
|
||||
toast.error('Error: ' + error.message)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,16 +39,23 @@ export async function getSystemConfig() {
|
||||
|
||||
export async function updateSystemConfig(data: Record<string, string>) {
|
||||
await checkAdmin()
|
||||
|
||||
|
||||
try {
|
||||
const operations = Object.entries(data).map(([key, value]) =>
|
||||
// Filter out empty values but keep 'false' as valid
|
||||
const filteredData = Object.fromEntries(
|
||||
Object.entries(data).filter(([key, value]) => value !== '' && value !== null && value !== undefined)
|
||||
)
|
||||
|
||||
console.log('Updating system config:', filteredData)
|
||||
|
||||
const operations = Object.entries(filteredData).map(([key, value]) =>
|
||||
prisma.systemConfig.upsert({
|
||||
where: { key },
|
||||
update: { value },
|
||||
create: { key, value }
|
||||
})
|
||||
)
|
||||
|
||||
|
||||
await prisma.$transaction(operations)
|
||||
revalidatePath('/admin/settings')
|
||||
return { success: true }
|
||||
|
||||
48
keep-notes/scripts/setup-openai.ts
Normal file
48
keep-notes/scripts/setup-openai.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import prisma from '../lib/prisma'
|
||||
|
||||
/**
|
||||
* Setup OpenAI as default AI provider in database
|
||||
* Run this to ensure OpenAI is properly configured
|
||||
*/
|
||||
async function setupOpenAI() {
|
||||
console.log('🔧 Setting up OpenAI as default AI provider...\n')
|
||||
|
||||
const configs = [
|
||||
{ key: 'AI_PROVIDER_TAGS', value: 'openai' },
|
||||
{ key: 'AI_PROVIDER_EMBEDDING', value: 'openai' },
|
||||
{ key: 'AI_MODEL_TAGS', value: 'gpt-4o-mini' },
|
||||
{ key: 'AI_MODEL_EMBEDDING', value: 'text-embedding-3-small' },
|
||||
]
|
||||
|
||||
try {
|
||||
for (const config of configs) {
|
||||
await prisma.systemConfig.upsert({
|
||||
where: { key: config.key },
|
||||
update: { value: config.value },
|
||||
create: { key: config.key, value: config.value }
|
||||
})
|
||||
console.log(`✅ Set ${config.key} = ${config.value}`)
|
||||
}
|
||||
|
||||
console.log('\n✨ OpenAI configuration complete!')
|
||||
console.log('\nNext steps:')
|
||||
console.log('1. Add your OPENAI_API_KEY in admin settings: http://localhost:3000/admin/settings')
|
||||
console.log('2. Or add it to .env.docker: OPENAI_API_KEY=sk-...')
|
||||
console.log('3. Restart the application')
|
||||
|
||||
// Verify
|
||||
const verify = await prisma.systemConfig.findMany({
|
||||
where: { key: { in: configs.map(c => c.key) } }
|
||||
})
|
||||
|
||||
console.log('\n✅ Verification:')
|
||||
verify.forEach(c => console.log(` ${c.key}: ${c.value}`))
|
||||
} catch (error) {
|
||||
console.error('❌ Error:', error)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
setupOpenAI()
|
||||
.then(() => process.exit(0))
|
||||
.catch(() => process.exit(1))
|
||||
Reference in New Issue
Block a user