Fix: ai_provider reads actual DB schema (config_key/config_value rows)
Root cause: ai_provider.py assumed a single JSON blob in an 'encrypted_value' column, but IntegrationConfig stores each credential as a separate row with config_key + config_value columns. Fixes: - Query groups rows by provider, decrypts each config_value separately - Correct decrypt_value(secret_key, ciphertext) argument order - Filter by user_id so providers are per-user - Callers (ai_chat.py, chat()) now pass user_id through
This commit is contained in:
parent
5294745704
commit
f2954af400
2 changed files with 24 additions and 12 deletions
|
|
@ -54,7 +54,7 @@ async def ai_status(
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_db),
|
||||||
):
|
):
|
||||||
"""Check which AI provider is configured."""
|
"""Check which AI provider is configured."""
|
||||||
provider = await ai_provider.get_active_ai_provider(db)
|
provider = await ai_provider.get_active_ai_provider(db, user_id=user.id)
|
||||||
if provider:
|
if provider:
|
||||||
return {
|
return {
|
||||||
"configured": True,
|
"configured": True,
|
||||||
|
|
|
||||||
|
|
@ -55,22 +55,34 @@ RULES:
|
||||||
- Never fabricate data — only reference what's in the context."""
|
- Never fabricate data — only reference what's in the context."""
|
||||||
|
|
||||||
|
|
||||||
async def get_active_ai_provider(db: AsyncSession) -> dict | None:
|
async def get_active_ai_provider(db: AsyncSession, user_id=None) -> dict | None:
|
||||||
"""Find the first configured AI provider."""
|
"""Find the first configured AI provider for the given user."""
|
||||||
result = await db.execute(
|
query = select(IntegrationConfig).where(
|
||||||
select(IntegrationConfig).where(
|
IntegrationConfig.provider.in_(list(AI_PRESETS.keys()))
|
||||||
IntegrationConfig.provider.in_(list(AI_PRESETS.keys()))
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
configs = result.scalars().all()
|
if user_id is not None:
|
||||||
|
query = query.where(IntegrationConfig.user_id == user_id)
|
||||||
|
|
||||||
for config in configs:
|
result = await db.execute(query)
|
||||||
provider_name = config.provider
|
rows = result.scalars().all()
|
||||||
|
|
||||||
|
# Group rows by provider: {"gemini": {"api_key": "decrypted_value"}}
|
||||||
|
providers: dict[str, dict[str, str]] = {}
|
||||||
|
for row in rows:
|
||||||
|
if row.provider not in providers:
|
||||||
|
providers[row.provider] = {}
|
||||||
try:
|
try:
|
||||||
creds = json.loads(decrypt_value(config.encrypted_value, settings.secret_key))
|
providers[row.provider][row.config_key] = decrypt_value(
|
||||||
|
settings.secret_key, row.config_value
|
||||||
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Return the first provider that has at least one credential
|
||||||
|
for provider_name, creds in providers.items():
|
||||||
|
if not creds:
|
||||||
|
continue
|
||||||
|
|
||||||
preset = AI_PRESETS.get(provider_name, AI_PRESETS["custom_ai"])
|
preset = AI_PRESETS.get(provider_name, AI_PRESETS["custom_ai"])
|
||||||
api_key = creds.get("api_key", "")
|
api_key = creds.get("api_key", "")
|
||||||
base_url = creds.get("endpoint_url", preset["base_url"]) or preset["base_url"]
|
base_url = creds.get("endpoint_url", preset["base_url"]) or preset["base_url"]
|
||||||
|
|
@ -127,7 +139,7 @@ async def chat(
|
||||||
db: AsyncSession,
|
db: AsyncSession,
|
||||||
) -> AsyncGenerator[str, None]:
|
) -> AsyncGenerator[str, None]:
|
||||||
"""Route chat to the configured AI provider with streaming."""
|
"""Route chat to the configured AI provider with streaming."""
|
||||||
provider = await get_active_ai_provider(db)
|
provider = await get_active_ai_provider(db, user_id=user_id)
|
||||||
if not provider:
|
if not provider:
|
||||||
yield "No AI provider configured. Go to Settings → Integrations to connect one (OpenAI, OpenRouter, Ollama, etc.)."
|
yield "No AI provider configured. Go to Settings → Integrations to connect one (OpenAI, OpenRouter, Ollama, etc.)."
|
||||||
return
|
return
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue