feat: improve AI resilience, add background enrichment loading states, and fix duplicate identifier in TagSelector
This commit is contained in:
105
.aiideas
105
.aiideas
@@ -1,28 +1,85 @@
|
||||
Act as a Senior TypeScript/Next.js Developer.
|
||||
´
|
||||
|
||||
I need a robust client-side image processing utility (an "Image Agent") to optimize user uploads before sending them to an LLM or Supabase.
|
||||
Act as a Senior Next.js Developer.
|
||||
|
||||
**Task:**
|
||||
Create a utility file `src/utils/image-processing.ts`.
|
||||
This file should export a function `processImageForAI` that uses the library `browser-image-compression`.
|
||||
Refactor the whisky analysis logic to optimize for perceived performance using a "Optimistic UI" approach.
|
||||
Split the current `analyzeBottle` logic into **two separate Server Actions**.
|
||||
|
||||
**Requirements:**
|
||||
1. **Input:** The function takes a raw `File` object (from an HTML input).
|
||||
2. **Processing Logic:**
|
||||
- Resize the image to a maximum of **1024x1024** pixels (maintain aspect ratio).
|
||||
- Convert the image to **WebP** format.
|
||||
- Limit the file size to approx **0.4MB**.
|
||||
- Enable `useWebWorker: true` to prevent UI freezing.
|
||||
3. **Output:** The function must return a Promise that resolves to an object with this interface:
|
||||
```typescript
|
||||
interface ProcessedImage {
|
||||
file: File; // The compressed WebP file (ready for Supabase storage)
|
||||
base64: string; // The Base64 string (ready for LLM API calls)
|
||||
originalFile: File; // Pass through the original file
|
||||
}
|
||||
```
|
||||
4. **Helper:** Include a helper function to convert the resulting Blob/File to a Base64 string correctly.
|
||||
5. **Edge Cases:** Handle errors gracefully (try/catch) and ensure the returned `file` has the correct `.webp` extension and mime type.
|
||||
### 1. Create `src/app/actions/scan-label.ts` (Fast OCR)
|
||||
This action handles the image upload via `FormData`.
|
||||
It must use the model with `safetySettings: BLOCK_NONE`.
|
||||
It must **NOT** generate flavor tags or search strings.
|
||||
|
||||
**Step 1:** Give me the `npm install` command to add the necessary library.
|
||||
**Step 2:** Write the complete `src/utils/image-processing.ts` code with proper JSDoc comments.
|
||||
**System Prompt for this Action:**
|
||||
```text
|
||||
ROLE: High-Precision OCR Engine for Whisky Labels.
|
||||
OBJECTIVE: Extract visible metadata strictly from the image.
|
||||
SPEED PRIORITY: Do NOT analyze flavor. Do NOT provide descriptions. Do NOT add tags.
|
||||
|
||||
TASK:
|
||||
1. Identify if the image contains a whisky/spirit bottle.
|
||||
2. Extract the following technical details into the JSON schema below.
|
||||
3. If a value is not visible or cannot be inferred with high certainty, use null.
|
||||
|
||||
EXTRACTION RULES:
|
||||
- Name: Combine Distillery + Age + Edition + Vintage (e.g., "Signatory Vintage Ben Nevis 2019 4 Year Old").
|
||||
- Distillery: The producer of the spirit.
|
||||
- Bottler: Independent bottler (e.g., "Signatory", "Gordon & MacPhail") if applicable.
|
||||
- Batch Info: Capture ALL Cask numbers, Batch IDs, Bottle numbers, Cask Types (e.g., "Refill Oloroso Sherry Butt, Bottle 1135").
|
||||
- Codes: Look for laser codes etched on glass/label (e.g., "L20394...").
|
||||
- Dates: Distinguish clearly between Vintage (distilled year), Bottled year, and Age.
|
||||
|
||||
OUTPUT SCHEMA (Strict JSON):
|
||||
{
|
||||
"name": "string",
|
||||
"distillery": "string",
|
||||
"bottler": "stringOrNull",
|
||||
"category": "string (e.g. Single Malt Scotch Whisky)",
|
||||
"abv": numberOrNull,
|
||||
"age": numberOrNull,
|
||||
"vintage": "stringOrNull",
|
||||
"distilled_at": "stringOrNull (Year/Date)",
|
||||
"bottled_at": "stringOrNull (Year/Date)",
|
||||
"batch_info": "stringOrNull",
|
||||
"bottleCode": "stringOrNull",
|
||||
"whiskybaseId": "stringOrNull",
|
||||
"is_whisky": boolean,
|
||||
"confidence": number
|
||||
}
|
||||
|
||||
2. Create src/app/actions/enrich-data.ts (Magic/Tags)
|
||||
|
||||
This action takes name and distillery (strings) as input. No image upload. It uses gemini-1.5-flash to retrieve knowledge-based data.
|
||||
|
||||
System Prompt for this Action:
|
||||
Plaintext
|
||||
|
||||
TASK: You are a Whisky Sommelier.
|
||||
INPUT: A whisky named "${name}" from distillery "${distillery}".
|
||||
|
||||
1. DATABASE LOOKUP:
|
||||
Retrieve the sensory profile and specific Whiskybase search string for this bottling.
|
||||
|
||||
2. TAGGING:
|
||||
Select the top 5-8 flavor tags strictly from this list:
|
||||
[${availableTags}]
|
||||
|
||||
3. SEARCH STRING:
|
||||
Create a precise search string for Whiskybase using: "site:whiskybase.com [Distillery] [Vintage/Age] [Bottler/Edition]"
|
||||
|
||||
OUTPUT JSON:
|
||||
{
|
||||
"suggested_tags": ["tag1", "tag2", "tag3"],
|
||||
"suggested_custom_tags": ["unique_note_if_missing_in_list"],
|
||||
"search_string": "string"
|
||||
}
|
||||
|
||||
3. Integration
|
||||
|
||||
Update the frontend component to:
|
||||
|
||||
Call scan-label first.
|
||||
|
||||
Update the UI state with the metadata immediately.
|
||||
|
||||
If the scan was successful, automatically trigger enrich-data in the background to fetch tags and search string.
|
||||
Reference in New Issue
Block a user