From b98af29449a3f21583950e44b82c333362fafc7b Mon Sep 17 00:00:00 2001 From: wangwei Date: Tue, 16 Jun 2026 16:10:37 +0800 Subject: [PATCH] feat: add LLMProfile pydantic models --- tests/webapp/test_profile_manager.py | 28 ++++++++++++++++++ webapp/models.py | 44 ++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 tests/webapp/test_profile_manager.py diff --git a/tests/webapp/test_profile_manager.py b/tests/webapp/test_profile_manager.py new file mode 100644 index 0000000..39ece6a --- /dev/null +++ b/tests/webapp/test_profile_manager.py @@ -0,0 +1,28 @@ +import pytest +from webapp.models import LLMProfile, ProfileApplyRequest, ProfileApplyResponse + +def test_llm_profile_defaults(): + p = LLMProfile( + profile_id="abc", + name="Test", + model="gpt-4", + base_url="http://localhost/v1", + api_key="sk-test", + ) + assert p.timeout_seconds == 30 + assert p.created_at != "" + assert p.updated_at != "" + +def test_profile_apply_request_fields(): + req = ProfileApplyRequest( + scenario_path="scenarios/offline/sample.yaml", + judge_profile_id="id1", + answer_profile_id="id2", + dataset_profile_id=None, + ) + assert req.judge_profile_id == "id1" + assert req.dataset_profile_id is None + +def test_profile_apply_response(): + resp = ProfileApplyResponse(scenario_path="scenarios/offline/sample.yaml", patched_fields=["judge_model"]) + assert "judge_model" in resp.patched_fields diff --git a/webapp/models.py b/webapp/models.py index 03dd6a9..908b297 100644 --- a/webapp/models.py +++ b/webapp/models.py @@ -2,11 +2,16 @@ from __future__ import annotations +from datetime import datetime, timezone from typing import Any from pydantic import BaseModel, Field +def _utcnow_iso() -> str: + return datetime.now(timezone.utc).isoformat() + + class RunSummary(BaseModel): """Compact description of a single evaluation run for list views.""" @@ -114,6 +119,45 @@ class TriggerEvaluationResponse(BaseModel): task_id: str +class LLMProfile(BaseModel): + """A named LLM connection configuration that can be reused across tasks.""" + + profile_id: str + name: str + model: str + base_url: str + api_key: str + timeout_seconds: int = 30 + created_at: str = Field(default_factory=_utcnow_iso) + updated_at: str = Field(default_factory=_utcnow_iso) + + +class CreateProfileRequest(BaseModel): + """Request body for creating or updating an LLM profile.""" + + name: str + model: str + base_url: str + api_key: str + timeout_seconds: int = 30 + + +class ProfileApplyRequest(BaseModel): + """Request body to patch LLM profile selections into a scenario YAML.""" + + scenario_path: str + judge_profile_id: str | None = None + answer_profile_id: str | None = None + dataset_profile_id: str | None = None + + +class ProfileApplyResponse(BaseModel): + """Response after patching a scenario YAML with profile settings.""" + + scenario_path: str + patched_fields: list[str] = Field(default_factory=list) + + def jsonable(value: Any) -> Any: """Convert NaN/inf floats into None so the payload stays valid JSON.""" import math