From 3ef1f249b679269de03cda2b931fae7444b9cb40 Mon Sep 17 00:00:00 2001 From: Piotr Oleszczyk Date: Fri, 6 Mar 2026 10:34:51 +0100 Subject: [PATCH] fix(api): handle dict vs object in build_product_context_summary When products are loaded from PostgreSQL, JSON columns (effect_profile, context_rules) are deserialized as plain dicts, not Pydantic models. The build_product_context_summary function was accessing these fields as object attributes (.safe_with_compromised_barrier) which caused: AttributeError: 'dict' object has no attribute 'safe_with_compromised_barrier' Fix: Add isinstance(dict) checks like build_product_context_detailed already does. Handle both dict (from DB) and object (from Pydantic) cases. Traceback from production: File "llm_context.py", line 91, in build_product_context_summary if product.context_rules.safe_with_compromised_barrier: AttributeError: 'dict' object has no attribute... --- backend/innercontext/api/llm_context.py | 49 ++++++++++++++++++------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/backend/innercontext/api/llm_context.py b/backend/innercontext/api/llm_context.py index 8c063a6..6b9b19e 100644 --- a/backend/innercontext/api/llm_context.py +++ b/backend/innercontext/api/llm_context.py @@ -72,26 +72,47 @@ def build_product_context_summary(product: Product, has_inventory: bool = False) if hasattr(product, "effect_profile") and product.effect_profile: profile = product.effect_profile # Only include notable effects (score > 0) - if profile.hydration_immediate and profile.hydration_immediate > 0: - effects.append(f"hydration={profile.hydration_immediate}") - if profile.exfoliation_strength and profile.exfoliation_strength > 0: - effects.append(f"exfoliation={profile.exfoliation_strength}") - if profile.retinoid_strength and profile.retinoid_strength > 0: - effects.append(f"retinoid={profile.retinoid_strength}") - if profile.irritation_risk and profile.irritation_risk > 0: - effects.append(f"irritation_risk={profile.irritation_risk}") - if profile.barrier_disruption_risk and profile.barrier_disruption_risk > 0: - effects.append(f"barrier_risk={profile.barrier_disruption_risk}") + # Handle both dict (from DB) and object (from Pydantic) + if isinstance(profile, dict): + if profile.get("hydration_immediate", 0) > 0: + effects.append(f"hydration={profile['hydration_immediate']}") + if profile.get("exfoliation_strength", 0) > 0: + effects.append(f"exfoliation={profile['exfoliation_strength']}") + if profile.get("retinoid_strength", 0) > 0: + effects.append(f"retinoid={profile['retinoid_strength']}") + if profile.get("irritation_risk", 0) > 0: + effects.append(f"irritation_risk={profile['irritation_risk']}") + if profile.get("barrier_disruption_risk", 0) > 0: + effects.append(f"barrier_risk={profile['barrier_disruption_risk']}") + else: + if profile.hydration_immediate and profile.hydration_immediate > 0: + effects.append(f"hydration={profile.hydration_immediate}") + if profile.exfoliation_strength and profile.exfoliation_strength > 0: + effects.append(f"exfoliation={profile.exfoliation_strength}") + if profile.retinoid_strength and profile.retinoid_strength > 0: + effects.append(f"retinoid={profile.retinoid_strength}") + if profile.irritation_risk and profile.irritation_risk > 0: + effects.append(f"irritation_risk={profile.irritation_risk}") + if profile.barrier_disruption_risk and profile.barrier_disruption_risk > 0: + effects.append(f"barrier_risk={profile.barrier_disruption_risk}") effects_str = f" effects={{{','.join(effects)}}}" if effects else "" # Safety flags safety_flags = [] if hasattr(product, "context_rules") and product.context_rules: - if product.context_rules.safe_with_compromised_barrier: - safety_flags.append("barrier_ok") - if not product.context_rules.safe_after_shaving: - safety_flags.append("!post_shave") + rules = product.context_rules + # Handle both dict (from DB) and object (from Pydantic) + if isinstance(rules, dict): + if rules.get("safe_with_compromised_barrier"): + safety_flags.append("barrier_ok") + if not rules.get("safe_after_shaving", True): + safety_flags.append("!post_shave") + else: + if rules.safe_with_compromised_barrier: + safety_flags.append("barrier_ok") + if not rules.safe_after_shaving: + safety_flags.append("!post_shave") safety_str = f" safety={{{','.join(safety_flags)}}}" if safety_flags else ""