feat: AI photo analysis for skin snapshots
Add POST /skincare/analyze-photos endpoint that accepts 1–3 skin photos, sends them to Gemini vision, and returns a structured SkinPhotoAnalysisResponse for pre-filling the snapshot form. Extract shared Gemini client setup into innercontext/llm.py (get_gemini_client) so both products and skincare use a single default model (gemini-flash-latest) and API key check. Frontend: AI photo card on /skin page with file picker, previews, and auto-fill of all form fields from the analysis result. New fields (skin_type, sebum_tzone, sebum_cheeks) added to form and server action. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
cc25ac4e65
commit
66ee473deb
8 changed files with 356 additions and 21 deletions
|
|
@ -1,17 +1,16 @@
|
|||
import json
|
||||
import os
|
||||
from datetime import date
|
||||
from typing import Optional
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from google import genai
|
||||
from google.genai import types as genai_types
|
||||
from pydantic import ValidationError
|
||||
from sqlmodel import Session, SQLModel, select
|
||||
|
||||
from db import get_session
|
||||
from innercontext.api.utils import get_or_404
|
||||
from innercontext.llm import get_gemini_client
|
||||
from innercontext.models import (
|
||||
Product,
|
||||
ProductBase,
|
||||
|
|
@ -350,11 +349,7 @@ OUTPUT SCHEMA (all fields optional — omit what you cannot determine):
|
|||
|
||||
@router.post("/parse-text", response_model=ProductParseResponse)
|
||||
def parse_product_text(data: ProductParseRequest) -> ProductParseResponse:
|
||||
api_key = os.environ.get("GEMINI_API_KEY")
|
||||
if not api_key:
|
||||
raise HTTPException(status_code=503, detail="GEMINI_API_KEY not configured")
|
||||
model = os.environ.get("GEMINI_MODEL", "gemini-flash-latest")
|
||||
client = genai.Client(api_key=api_key)
|
||||
client, model = get_gemini_client()
|
||||
response = client.models.generate_content(
|
||||
model=model,
|
||||
contents=f"Extract product data from this text:\n\n{data.text}",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue