fix: get LLM API key from DB instead of env var
- ai_proactive now reads API key from ai_providers table (like ai_assistant) - Falls back to API_KEY_OLLAMA_CLOUD env var if no provider found - Fixes: proactive engine could not generate suggestions because API key was empty
This commit is contained in:
@@ -187,23 +187,35 @@ async def deep_analysis(
|
|||||||
|
|
||||||
# Generate extended suggestion with deep analysis prompt
|
# Generate extended suggestion with deep analysis prompt
|
||||||
model = settings.model or "ollama/deepseek-v4"
|
model = settings.model or "ollama/deepseek-v4"
|
||||||
|
|
||||||
|
# Get API key from DB (like ai_assistant does) or fall back to env
|
||||||
|
from app.plugins.builtins.ai_proactive.services import _get_llm_api_key
|
||||||
|
api_key, api_base = await _get_llm_api_key(db, tid)
|
||||||
|
if not api_key:
|
||||||
|
api_key = os.environ.get('API_KEY_OLLAMA_CLOUD', '') or None
|
||||||
|
|
||||||
|
litellm_kwargs: dict[str, Any] = dict(
|
||||||
|
model=model,
|
||||||
|
messages=[
|
||||||
|
{"role": "system", "content": DEEP_SYSTEM_PROMPT},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": json.dumps(
|
||||||
|
extended_context, default=str, ensure_ascii=False
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
temperature=0.3,
|
||||||
|
max_tokens=800,
|
||||||
|
response_format={"type": "json_object"},
|
||||||
|
)
|
||||||
|
if api_key:
|
||||||
|
litellm_kwargs["api_key"] = api_key
|
||||||
|
if api_base:
|
||||||
|
litellm_kwargs["api_base"] = api_base
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = await litellm.acompletion(
|
response = await litellm.acompletion(**litellm_kwargs)
|
||||||
model=model,
|
|
||||||
messages=[
|
|
||||||
{"role": "system", "content": DEEP_SYSTEM_PROMPT},
|
|
||||||
{
|
|
||||||
"role": "user",
|
|
||||||
"content": json.dumps(
|
|
||||||
extended_context, default=str, ensure_ascii=False
|
|
||||||
),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
temperature=0.3,
|
|
||||||
max_tokens=800,
|
|
||||||
response_format={"type": "json_object"},
|
|
||||||
api_key=OLLAMA_API_KEY,
|
|
||||||
)
|
|
||||||
content = response.choices[0].message.content
|
content = response.choices[0].message.content
|
||||||
if not content:
|
if not content:
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -33,7 +33,22 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
litellm.suppress_debug_info = True
|
litellm.suppress_debug_info = True
|
||||||
|
|
||||||
OLLAMA_API_KEY = os.environ.get('API_KEY_OLLAMA_CLOUD', '')
|
async def _get_llm_api_key(db: AsyncSession, tenant_id: uuid.UUID) -> tuple[str | None, str | None]:
|
||||||
|
"""Get API key and base_url from the default AI provider in the DB.
|
||||||
|
|
||||||
|
Falls back to API_KEY_OLLAMA_CLOUD env var if no provider found.
|
||||||
|
Returns (api_key, base_url).
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
from app.plugins.builtins.ai_assistant.services import get_default_provider
|
||||||
|
provider = await get_default_provider(db, tenant_id)
|
||||||
|
if provider and provider.api_key:
|
||||||
|
return provider.api_key, provider.base_url
|
||||||
|
except Exception:
|
||||||
|
logger.debug("Failed to get provider from DB, falling back to env")
|
||||||
|
# Fallback to env var
|
||||||
|
env_key = os.environ.get('API_KEY_OLLAMA_CLOUD', '')
|
||||||
|
return (env_key if env_key else None), None
|
||||||
|
|
||||||
# ─── SSE Push Infrastructure ───
|
# ─── SSE Push Infrastructure ───
|
||||||
|
|
||||||
@@ -372,7 +387,8 @@ Antworte mit JSON:
|
|||||||
|
|
||||||
|
|
||||||
async def generate_suggestion(
|
async def generate_suggestion(
|
||||||
context_data: dict[str, Any], settings: ProactiveSettings
|
context_data: dict[str, Any], settings: ProactiveSettings,
|
||||||
|
db: AsyncSession | None = None, tenant_id: uuid.UUID | None = None,
|
||||||
) -> dict[str, Any] | None:
|
) -> dict[str, Any] | None:
|
||||||
"""LLM generates a suggestion from context data.
|
"""LLM generates a suggestion from context data.
|
||||||
|
|
||||||
@@ -380,21 +396,35 @@ async def generate_suggestion(
|
|||||||
or None on failure.
|
or None on failure.
|
||||||
"""
|
"""
|
||||||
model = settings.model or "ollama/deepseek-v4"
|
model = settings.model or "ollama/deepseek-v4"
|
||||||
|
|
||||||
|
# Get API key from DB (like ai_assistant does) or fall back to env
|
||||||
|
api_key = None
|
||||||
|
api_base = None
|
||||||
|
if db and tenant_id:
|
||||||
|
api_key, api_base = await _get_llm_api_key(db, tenant_id)
|
||||||
|
if not api_key:
|
||||||
|
api_key = os.environ.get('API_KEY_OLLAMA_CLOUD', '') or None
|
||||||
|
|
||||||
|
litellm_kwargs: dict[str, Any] = dict(
|
||||||
|
model=model,
|
||||||
|
messages=[
|
||||||
|
{"role": "system", "content": SYSTEM_PROMPT},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": json.dumps(context_data, default=str, ensure_ascii=False),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
temperature=0.3,
|
||||||
|
max_tokens=500,
|
||||||
|
response_format={"type": "json_object"},
|
||||||
|
)
|
||||||
|
if api_key:
|
||||||
|
litellm_kwargs["api_key"] = api_key
|
||||||
|
if api_base:
|
||||||
|
litellm_kwargs["api_base"] = api_base
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = await litellm.acompletion(
|
response = await litellm.acompletion(**litellm_kwargs)
|
||||||
model=model,
|
|
||||||
messages=[
|
|
||||||
{"role": "system", "content": SYSTEM_PROMPT},
|
|
||||||
{
|
|
||||||
"role": "user",
|
|
||||||
"content": json.dumps(context_data, default=str, ensure_ascii=False),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
temperature=0.3,
|
|
||||||
max_tokens=500,
|
|
||||||
response_format={"type": "json_object"},
|
|
||||||
api_key=OLLAMA_API_KEY,
|
|
||||||
)
|
|
||||||
content = response.choices[0].message.content
|
content = response.choices[0].message.content
|
||||||
if not content:
|
if not content:
|
||||||
return None
|
return None
|
||||||
@@ -481,7 +511,7 @@ async def handle_context_change(payload: dict[str, Any]) -> None:
|
|||||||
context_data = await gather_context(db, entity_type, entity_id, tenant_id)
|
context_data = await gather_context(db, entity_type, entity_id, tenant_id)
|
||||||
|
|
||||||
# Generate suggestion
|
# Generate suggestion
|
||||||
suggestion_data = await generate_suggestion(context_data, settings)
|
suggestion_data = await generate_suggestion(context_data, settings, db, tenant_id)
|
||||||
if suggestion_data is None:
|
if suggestion_data is None:
|
||||||
logger.debug("handle_context_change: no suggestion generated")
|
logger.debug("handle_context_change: no suggestion generated")
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user