Files
food-ai/backend/internal/domain/recognition/product_job.go
dbastrikin 5c5ed25e5b feat: improved receipt recognition, batch product add, and scan UX
- Rewrite receipt OCR prompt: completes truncated names, preserves fat%
  and flavour attributes, extracts weight/volume from line, infers
  typical package sizes for solid goods with quantity_confidence field
- Add quantity_confidence to RecognizedItem, EnrichedItem, and
  ProductJobResultItem; propagate through item enricher and worker
- Replace per-item create loop with single POST /user-products/batch call
  from RecognitionConfirmScreen
- Rebuild RecognitionConfirmScreen: amber qty border for low
  quantity_confidence, tappable product name → catalog picker,
  sort items by confidence, full L10n (no hardcoded strings)
- Add timestamps (HH:mm / d MMM HH:mm) to recent scan chips
- Show close-app hint on ProductJobWatchScreen (queued + processing)
- Refresh recentProductJobsProvider on watch screen init so new job
  appears without a manual pull-to-refresh
- App-level WidgetsBindingObserver refreshes product and dish job lists
  on resume, fixing stale lists after background/foreground transitions
- Add 9 new L10n keys across all 12 locales

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 23:09:57 +02:00

65 lines
2.0 KiB
Go

package recognition
import (
"time"
"github.com/food-ai/backend/internal/adapters/ai"
)
// Kafka topic names for product recognition.
const (
ProductTopicPaid = "ai.products.paid"
ProductTopicFree = "ai.products.free"
)
// ProductImagePayload is a single image stored in the product_recognition_jobs.images JSONB column.
type ProductImagePayload struct {
ImageBase64 string `json:"image_base64"`
MimeType string `json:"mime_type"`
}
// ProductJobResultItem is an enriched product item stored in the result JSONB.
type ProductJobResultItem struct {
Name string `json:"name"`
Quantity float64 `json:"quantity"`
Unit string `json:"unit"`
Category string `json:"category"`
Confidence float64 `json:"confidence"`
QuantityConfidence float64 `json:"quantity_confidence"`
MappingID *string `json:"mapping_id,omitempty"`
StorageDays int `json:"storage_days"`
}
// ProductJobResult is the JSONB payload stored in product_recognition_jobs.result.
type ProductJobResult struct {
JobType string `json:"job_type"`
Items []ProductJobResultItem `json:"items"`
Unrecognized []ai.UnrecognizedItem `json:"unrecognized,omitempty"`
}
// ProductJob represents an async product/receipt recognition task.
type ProductJob struct {
ID string
UserID string
UserPlan string
JobType string // "receipt" | "products"
Images []ProductImagePayload
Lang string
Status string
Result *ProductJobResult
Error *string
CreatedAt time.Time
StartedAt *time.Time
CompletedAt *time.Time
}
// ProductJobSummary is a lightweight record for list endpoints (omits image payloads).
type ProductJobSummary struct {
ID string `json:"id"`
JobType string `json:"job_type"`
Status string `json:"status"`
Result *ProductJobResult `json:"result,omitempty"`
Error *string `json:"error,omitempty"`
CreatedAt time.Time `json:"created_at"`
}