refactor(skin): replace trend with texture field on SkinConditionSnapshot
Remove the derived `trend` field (better computed from history by the MCP agent) and add `texture: smooth|rough|flaky|bumpy` which LLM can reliably assess from photos. Updates model, API, system prompt, tests, and frontend. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
abf9593857
commit
4954d4f449
8 changed files with 30 additions and 31 deletions
|
|
@ -20,7 +20,7 @@ from innercontext.models.enums import (
|
|||
BarrierState,
|
||||
OverallSkinState,
|
||||
SkinConcern,
|
||||
SkinTrend,
|
||||
SkinTexture,
|
||||
SkinType,
|
||||
)
|
||||
|
||||
|
|
@ -39,8 +39,8 @@ class SnapshotCreate(SkinConditionSnapshotBase):
|
|||
class SnapshotUpdate(SQLModel):
|
||||
snapshot_date: Optional[date] = None
|
||||
overall_state: Optional[OverallSkinState] = None
|
||||
trend: Optional[SkinTrend] = None
|
||||
skin_type: Optional[SkinType] = None
|
||||
texture: Optional[SkinTexture] = None
|
||||
|
||||
hydration_level: Optional[int] = None
|
||||
sebum_tzone: Optional[int] = None
|
||||
|
|
@ -57,8 +57,8 @@ class SnapshotUpdate(SQLModel):
|
|||
|
||||
class SkinPhotoAnalysisResponse(SQLModel):
|
||||
overall_state: Optional[OverallSkinState] = None
|
||||
trend: Optional[SkinTrend] = None
|
||||
skin_type: Optional[SkinType] = None
|
||||
texture: Optional[SkinTexture] = None
|
||||
hydration_level: Optional[int] = None
|
||||
sebum_tzone: Optional[int] = None
|
||||
sebum_cheeks: Optional[int] = None
|
||||
|
|
@ -85,14 +85,13 @@ RULES:
|
|||
- Omit any field you cannot confidently determine from the photos. Do not guess.
|
||||
- All enum values must exactly match the allowed strings listed below.
|
||||
- Numeric metrics use a 1–5 scale (1 = minimal, 5 = maximal).
|
||||
- For trends: only populate if you have strong visual cues; otherwise omit.
|
||||
- risks and priorities: short English phrases, max 10 words each.
|
||||
- notes: 2–4 sentence paragraph describing key observations.
|
||||
|
||||
ENUM VALUES:
|
||||
overall_state: "excellent" | "good" | "fair" | "poor"
|
||||
trend: "improving" | "stable" | "worsening" | "fluctuating"
|
||||
skin_type: "dry" | "oily" | "combination" | "sensitive" | "normal" | "acne_prone"
|
||||
texture: "smooth" | "rough" | "flaky" | "bumpy"
|
||||
barrier_state: "intact" | "mildly_compromised" | "compromised"
|
||||
active_concerns: "acne" | "rosacea" | "hyperpigmentation" | "aging" | "dehydration" |
|
||||
"redness" | "damaged_barrier" | "pore_visibility" | "uneven_texture" | "sebum_excess"
|
||||
|
|
@ -104,7 +103,7 @@ sebum_cheeks: 1=very dry cheeks → 5=very oily cheeks
|
|||
sensitivity_level: 1=no visible signs → 5=severe redness/reactivity
|
||||
|
||||
OUTPUT (all fields optional):
|
||||
{"overall_state":…, "trend":…, "skin_type":…, "hydration_level":…,
|
||||
{"overall_state":…, "skin_type":…, "texture":…, "hydration_level":…,
|
||||
"sebum_tzone":…, "sebum_cheeks":…, "sensitivity_level":…,
|
||||
"barrier_state":…, "active_concerns":[…], "risks":[…], "priorities":[…], "notes":…}
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ from .enums import (
|
|||
ResultFlag,
|
||||
RoutineRole,
|
||||
SkinConcern,
|
||||
SkinTrend,
|
||||
SkinTexture,
|
||||
SkinType,
|
||||
StrengthLevel,
|
||||
TextureType,
|
||||
|
|
@ -59,7 +59,7 @@ __all__ = [
|
|||
"ResultFlag",
|
||||
"RoutineRole",
|
||||
"SkinConcern",
|
||||
"SkinTrend",
|
||||
"SkinTexture",
|
||||
"SkinType",
|
||||
"StrengthLevel",
|
||||
"TextureType",
|
||||
|
|
|
|||
|
|
@ -186,11 +186,11 @@ class OverallSkinState(str, Enum):
|
|||
POOR = "poor"
|
||||
|
||||
|
||||
class SkinTrend(str, Enum):
|
||||
IMPROVING = "improving"
|
||||
STABLE = "stable"
|
||||
WORSENING = "worsening"
|
||||
FLUCTUATING = "fluctuating"
|
||||
class SkinTexture(str, Enum):
|
||||
SMOOTH = "smooth"
|
||||
ROUGH = "rough"
|
||||
FLAKY = "flaky"
|
||||
BUMPY = "bumpy"
|
||||
|
||||
|
||||
class BarrierState(str, Enum):
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ from sqlmodel import Field, SQLModel
|
|||
|
||||
from .base import utc_now
|
||||
from .domain import Domain
|
||||
from .enums import BarrierState, OverallSkinState, SkinConcern, SkinTrend, SkinType
|
||||
from .enums import BarrierState, OverallSkinState, SkinConcern, SkinTexture, SkinType
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Base model (pure Python types, no sa_column, no id/created_at)
|
||||
|
|
@ -20,8 +20,8 @@ class SkinConditionSnapshotBase(SQLModel):
|
|||
snapshot_date: date
|
||||
|
||||
overall_state: OverallSkinState | None = None
|
||||
trend: SkinTrend | None = None
|
||||
skin_type: SkinType | None = None
|
||||
texture: SkinTexture | None = None
|
||||
|
||||
# Metryki wizualne (1 = minimalne, 5 = maksymalne nasilenie)
|
||||
hydration_level: int | None = Field(default=None, ge=1, le=5)
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ def test_create_snapshot_full(client):
|
|||
json={
|
||||
"snapshot_date": "2026-02-20",
|
||||
"overall_state": "good",
|
||||
"trend": "improving",
|
||||
"skin_type": "combination",
|
||||
"texture": "rough",
|
||||
"hydration_level": 3,
|
||||
"sebum_tzone": 4,
|
||||
"sebum_cheeks": 2,
|
||||
|
|
@ -32,7 +32,7 @@ def test_create_snapshot_full(client):
|
|||
assert r.status_code == 201
|
||||
data = r.json()
|
||||
assert data["overall_state"] == "good"
|
||||
assert data["trend"] == "improving"
|
||||
assert data["texture"] == "rough"
|
||||
assert "acne" in data["active_concerns"]
|
||||
assert data["hydration_level"] == 3
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue