69 lines
2.0 KiB
Python
69 lines
2.0 KiB
Python
import time
|
|
|
|
from asgiref.sync import sync_to_async
|
|
from django.utils import timezone
|
|
from openai import AsyncOpenAI
|
|
|
|
from core.models import AI, AIRunLog
|
|
|
|
|
|
def _prompt_metrics(prompt: list[dict]) -> tuple[int, int]:
|
|
rows = list(prompt or [])
|
|
message_count = len(rows)
|
|
prompt_chars = 0
|
|
for row in rows:
|
|
content = ""
|
|
if isinstance(row, dict):
|
|
content = str(row.get("content") or "")
|
|
else:
|
|
content = str(row or "")
|
|
prompt_chars += len(content)
|
|
return message_count, prompt_chars
|
|
|
|
|
|
async def run_prompt(
|
|
prompt: list[dict],
|
|
ai: AI,
|
|
operation: str = "",
|
|
):
|
|
started_monotonic = time.perf_counter()
|
|
message_count, prompt_chars = _prompt_metrics(prompt)
|
|
run_log = await sync_to_async(AIRunLog.objects.create)(
|
|
user=ai.user,
|
|
ai=ai,
|
|
operation=str(operation or "").strip(),
|
|
model=str(ai.model or ""),
|
|
base_url=str(ai.base_url or ""),
|
|
status="running",
|
|
message_count=message_count,
|
|
prompt_chars=prompt_chars,
|
|
)
|
|
cast = {"api_key": ai.api_key}
|
|
if ai.base_url is not None:
|
|
cast["base_url"] = ai.base_url
|
|
client = AsyncOpenAI(**cast)
|
|
try:
|
|
response = await client.chat.completions.create(
|
|
model=ai.model,
|
|
messages=prompt,
|
|
)
|
|
content = response.choices[0].message.content
|
|
duration_ms = int((time.perf_counter() - started_monotonic) * 1000)
|
|
await sync_to_async(AIRunLog.objects.filter(id=run_log.id).update)(
|
|
status="ok",
|
|
response_chars=len(str(content or "")),
|
|
finished_at=timezone.now(),
|
|
duration_ms=duration_ms,
|
|
error="",
|
|
)
|
|
return content
|
|
except Exception as exc:
|
|
duration_ms = int((time.perf_counter() - started_monotonic) * 1000)
|
|
await sync_to_async(AIRunLog.objects.filter(id=run_log.id).update)(
|
|
status="failed",
|
|
finished_at=timezone.now(),
|
|
duration_ms=duration_ms,
|
|
error=str(exc),
|
|
)
|
|
raise
|