refactor(products): remove obsolete interaction fields across stack

This commit is contained in:
Piotr Oleszczyk 2026-03-04 12:42:12 +01:00
parent 1d8a8eafb8
commit c5ea38880c
16 changed files with 32 additions and 278 deletions

View file

@ -38,7 +38,6 @@ from innercontext.models.product import (
ActiveIngredient,
ProductContext,
ProductEffectProfile,
ProductInteraction,
)
router = APIRouter()
@ -91,8 +90,6 @@ class ProductUpdate(SQLModel):
ph_min: Optional[float] = None
ph_max: Optional[float] = None
incompatible_with: Optional[list[ProductInteraction]] = None
synergizes_with: Optional[list[str]] = None
context_rules: Optional[ProductContext] = None
min_interval_hours: Optional[int] = None
@ -140,8 +137,6 @@ class ProductParseResponse(SQLModel):
product_effect_profile: Optional[ProductEffectProfile] = None
ph_min: Optional[float] = None
ph_max: Optional[float] = None
incompatible_with: Optional[list[ProductInteraction]] = None
synergizes_with: Optional[list[str]] = None
context_rules: Optional[ProductContext] = None
min_interval_hours: Optional[int] = None
max_frequency_per_week: Optional[int] = None
@ -347,8 +342,6 @@ actives[].functions (array, pick applicable):
actives[].strength_level: 1 (low) | 2 (medium) | 3 (high)
actives[].irritation_potential: 1 (low) | 2 (medium) | 3 (high)
incompatible_with[].scope: "same_step" | "same_day" | "same_period"
OUTPUT SCHEMA (all fields optional omit what you cannot determine):
{
"name": string,
@ -402,10 +395,6 @@ OUTPUT SCHEMA (all fields optional — omit what you cannot determine):
},
"ph_min": number,
"ph_max": number,
"incompatible_with": [
{"target": string, "scope": string, "reason": string}
],
"synergizes_with": [string, ...],
"context_rules": {
"safe_after_shaving": boolean,
"safe_after_acids": boolean,
@ -721,7 +710,6 @@ def _build_safety_rules_tool_handler(products: list[Product]):
return {
"id": pid,
"name": product.name,
"incompatible_with": (ctx.get("incompatible_with") or [])[:24],
"contraindications": (ctx.get("contraindications") or [])[:24],
"context_rules": ctx.get("context_rules") or {},
"safety": ctx.get("safety") or {},
@ -755,7 +743,7 @@ _SAFETY_RULES_FUNCTION_DECLARATION = genai_types.FunctionDeclaration(
name="get_product_safety_rules",
description=(
"Return safety and compatibility rules for selected product UUIDs, "
"including incompatible_with, contraindications, context_rules and safety flags."
"including contraindications, context_rules and safety flags."
),
parameters=genai_types.Schema(
type=genai_types.Type.OBJECT,

View file

@ -378,8 +378,6 @@ def _build_products_context(
notable = {k: v for k, v in profile.items() if v and v > 0}
if notable:
entry += f" effects={notable}"
if ctx.get("incompatible_with"):
entry += f" incompatible_with={ctx['incompatible_with']}"
if ctx.get("contraindications"):
entry += f" contraindications={ctx['contraindications']}"
if ctx.get("context_rules"):
@ -501,7 +499,6 @@ def _build_safety_rules_tool_handler(
return {
"id": pid,
"name": product.name,
"incompatible_with": (ctx.get("incompatible_with") or [])[:24],
"contraindications": (ctx.get("contraindications") or [])[:24],
"context_rules": ctx.get("context_rules") or {},
"safety": ctx.get("safety") or {},
@ -630,7 +627,7 @@ _SAFETY_RULES_FUNCTION_DECLARATION = genai_types.FunctionDeclaration(
name="get_product_safety_rules",
description=(
"Return safety and compatibility rules for selected product UUIDs: "
"incompatible_with, contraindications, context_rules and safety flags."
"contraindications, context_rules and safety flags."
),
parameters=genai_types.Schema(
type=genai_types.Type.OBJECT,
@ -688,8 +685,7 @@ WYMAGANIA ODPOWIEDZI:
ZASADY PLANOWANIA:
- Kolejność warstw: cleanser -> toner -> essence -> serum -> moisturizer -> [SPF dla AM].
- Respektuj: incompatible_with (same_step / same_day / same_period), context_rules,
min_interval_hours, max_frequency_per_week, usage_notes.
- Respektuj: context_rules, min_interval_hours, max_frequency_per_week, usage_notes.
- Zarządzanie inwentarzem:
- Preferuj produkty już otwarte (miękka preferencja).
- Unikaj funkcjonalnej redundancji (np. wielokrotne źródła panthenolu, ceramidów lub niacynamidu w tej samej rutynie),

View file

@ -7,7 +7,6 @@ from .enums import (
EvidenceLevel,
GroomingAction,
IngredientFunction,
InteractionScope,
MedicationKind,
OverallSkinState,
PartOfDay,
@ -29,7 +28,6 @@ from .product import (
ProductBase,
ProductContext,
ProductEffectProfile,
ProductInteraction,
ProductInventory,
ProductPublic,
ProductWithInventory,
@ -53,7 +51,6 @@ __all__ = [
"EvidenceLevel",
"GroomingAction",
"IngredientFunction",
"InteractionScope",
"MedicationKind",
"OverallSkinState",
"PartOfDay",
@ -77,7 +74,6 @@ __all__ = [
"ProductBase",
"ProductContext",
"ProductEffectProfile",
"ProductInteraction",
"ProductInventory",
"ProductPublic",
"ProductWithInventory",

View file

@ -131,12 +131,6 @@ class EvidenceLevel(str, Enum):
HIGH = "high"
class InteractionScope(str, Enum):
SAME_STEP = "same_step"
SAME_DAY = "same_day"
SAME_PERIOD = "same_period"
# ---------------------------------------------------------------------------
# Health
# ---------------------------------------------------------------------------

View file

@ -12,7 +12,6 @@ from .enums import (
AbsorptionSpeed,
DayTime,
IngredientFunction,
InteractionScope,
PriceTier,
ProductCategory,
SkinConcern,
@ -57,12 +56,6 @@ class ActiveIngredient(SQLModel):
irritation_potential: StrengthLevel | None = None
class ProductInteraction(SQLModel):
target: str
scope: InteractionScope
reason: str | None = None
class ProductContext(SQLModel):
safe_after_shaving: bool | None = None
safe_after_acids: bool | None = None
@ -128,8 +121,6 @@ class ProductBase(SQLModel):
ph_min: float | None = Field(default=None, ge=0, le=14)
ph_max: float | None = Field(default=None, ge=0, le=14)
incompatible_with: list[ProductInteraction] | None = None
synergizes_with: list[str] | None = None
context_rules: ProductContext | None = None
min_interval_hours: int | None = Field(default=None, ge=0)
@ -181,12 +172,6 @@ class Product(ProductBase, table=True):
sa_column=Column(JSON, nullable=False),
)
incompatible_with: list[ProductInteraction] | None = Field(
default=None, sa_column=Column(JSON, nullable=True)
)
synergizes_with: list[str] | None = Field(
default=None, sa_column=Column(JSON, nullable=True)
)
context_rules: ProductContext | None = Field(
default=None, sa_column=Column(JSON, nullable=True)
)
@ -302,26 +287,6 @@ class Product(ProductBase, table=True):
if nonzero:
ctx["effect_profile"] = nonzero
if self.incompatible_with:
parts = []
for inc in self.incompatible_with:
if isinstance(inc, dict):
scope = inc.get("scope", "")
target = inc.get("target", "")
reason = inc.get("reason")
else:
scope = _ev(inc.scope)
target = inc.target
reason = inc.reason
msg = f"avoid {target} ({scope})"
if reason:
msg += f": {reason}"
parts.append(msg)
ctx["incompatible_with"] = parts
if self.synergizes_with:
ctx["synergizes_with"] = self.synergizes_with
if self.context_rules is not None:
cr = self.context_rules
if isinstance(cr, dict):