- Update config.py with DEEPSEEK_API_KEY, DEEPSEEK_MODEL, DEEPSEEK_BASE_URL - Update ai.py to use DeepSeek endpoint (OpenAI-compatible) - Update docker-compose.yml environment variables
118 lines
4.0 KiB
Python
118 lines
4.0 KiB
Python
from typing import Any, Optional
|
|
|
|
import httpx
|
|
|
|
from app.config import get_settings
|
|
from app.context import FlowContext
|
|
from app.nodes.base import NodeExecutor
|
|
|
|
settings = get_settings()
|
|
|
|
|
|
class AIResponseExecutor(NodeExecutor):
|
|
"""Generate AI response using DeepSeek API"""
|
|
|
|
async def execute(
|
|
self, config: dict, context: FlowContext, session: Any
|
|
) -> Optional[str]:
|
|
prompt = context.interpolate(config.get("prompt", ""))
|
|
system_prompt = config.get("system_prompt", "Eres un asistente útil.")
|
|
output_variable = config.get("output_variable", "_ai_response")
|
|
max_tokens = config.get("max_tokens", 500)
|
|
temperature = config.get("temperature", 0.7)
|
|
|
|
if not settings.DEEPSEEK_API_KEY:
|
|
context.set("_ai_error", "DeepSeek API key not configured")
|
|
return "error"
|
|
|
|
if not prompt:
|
|
return "error"
|
|
|
|
messages = [
|
|
{"role": "system", "content": system_prompt},
|
|
{"role": "user", "content": prompt},
|
|
]
|
|
|
|
if config.get("include_history", False):
|
|
history = context.get("_conversation_history") or []
|
|
messages = (
|
|
[{"role": "system", "content": system_prompt}]
|
|
+ history
|
|
+ [{"role": "user", "content": prompt}]
|
|
)
|
|
|
|
async with httpx.AsyncClient() as client:
|
|
response = await client.post(
|
|
f"{settings.DEEPSEEK_BASE_URL}/v1/chat/completions",
|
|
headers={
|
|
"Authorization": f"Bearer {settings.DEEPSEEK_API_KEY}",
|
|
"Content-Type": "application/json",
|
|
},
|
|
json={
|
|
"model": settings.DEEPSEEK_MODEL,
|
|
"messages": messages,
|
|
"max_tokens": max_tokens,
|
|
"temperature": temperature,
|
|
},
|
|
timeout=30,
|
|
)
|
|
|
|
if response.status_code != 200:
|
|
context.set("_ai_error", response.text)
|
|
return "error"
|
|
|
|
data = response.json()
|
|
ai_response = data["choices"][0]["message"]["content"]
|
|
context.set(output_variable, ai_response)
|
|
return "success"
|
|
|
|
|
|
class AISentimentExecutor(NodeExecutor):
|
|
"""Analyze sentiment of user message using DeepSeek"""
|
|
|
|
async def execute(
|
|
self, config: dict, context: FlowContext, session: Any
|
|
) -> Optional[str]:
|
|
text = context.get(config.get("variable", "")) or context.message.get(
|
|
"content", ""
|
|
)
|
|
output_variable = config.get("output_variable", "_sentiment")
|
|
|
|
if not settings.DEEPSEEK_API_KEY or not text:
|
|
return "neutral"
|
|
|
|
async with httpx.AsyncClient() as client:
|
|
response = await client.post(
|
|
f"{settings.DEEPSEEK_BASE_URL}/v1/chat/completions",
|
|
headers={
|
|
"Authorization": f"Bearer {settings.DEEPSEEK_API_KEY}",
|
|
"Content-Type": "application/json",
|
|
},
|
|
json={
|
|
"model": settings.DEEPSEEK_MODEL,
|
|
"messages": [
|
|
{
|
|
"role": "system",
|
|
"content": "Analyze the sentiment. Reply with only one word: positive, negative, or neutral",
|
|
},
|
|
{"role": "user", "content": text},
|
|
],
|
|
"max_tokens": 10,
|
|
"temperature": 0,
|
|
},
|
|
timeout=15,
|
|
)
|
|
|
|
if response.status_code != 200:
|
|
return "neutral"
|
|
|
|
data = response.json()
|
|
sentiment = data["choices"][0]["message"]["content"].lower().strip()
|
|
context.set(output_variable, sentiment)
|
|
|
|
if "positive" in sentiment:
|
|
return "positive"
|
|
if "negative" in sentiment:
|
|
return "negative"
|
|
return "neutral"
|