|
|
import { GoogleGenAI, Type, Schema } from "@google/genai"; |
|
|
import { AnalysisReport } from "../types"; |
|
|
|
|
|
|
|
|
|
|
|
const ai = new GoogleGenAI({ apiKey: process.env.API_KEY }); |
|
|
|
|
|
const MODEL_NAME = "gemini-2.5-flash"; |
|
|
|
|
|
const analysisSchema: Schema = { |
|
|
type: Type.OBJECT, |
|
|
properties: { |
|
|
isCompliant: { type: Type.BOOLEAN, description: "Whether the image is suitable for a public lock screen." }, |
|
|
overallScore: { type: Type.INTEGER, description: "A quality score from 0 to 100." }, |
|
|
checks: { |
|
|
type: Type.ARRAY, |
|
|
items: { |
|
|
type: Type.OBJECT, |
|
|
properties: { |
|
|
name: { type: Type.STRING, description: "The name of the criterion being checked." }, |
|
|
passed: { type: Type.BOOLEAN, description: "Whether the check passed." }, |
|
|
reason: { type: Type.STRING, description: "Brief explanation of the result." } |
|
|
}, |
|
|
required: ["name", "passed", "reason"] |
|
|
} |
|
|
} |
|
|
}, |
|
|
required: ["isCompliant", "overallScore", "checks"] |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const fileToGenerativePart = async (file: File): Promise<string> => { |
|
|
return new Promise((resolve, reject) => { |
|
|
const reader = new FileReader(); |
|
|
reader.onloadend = () => { |
|
|
const base64String = reader.result as string; |
|
|
|
|
|
const base64Data = base64String.split(',')[1]; |
|
|
resolve(base64Data); |
|
|
}; |
|
|
reader.onerror = reject; |
|
|
reader.readAsDataURL(file); |
|
|
}); |
|
|
}; |
|
|
|
|
|
export const analyzeLockScreen = async (file: File): Promise<AnalysisReport> => { |
|
|
try { |
|
|
const base64Data = await fileToGenerativePart(file); |
|
|
|
|
|
const systemPrompt = ` |
|
|
You are Prism, an AI expert for Samsung Glance lock screen compliance. |
|
|
Analyze the provided image against the following strict criteria: |
|
|
1. Image Quality: Must be high resolution, not blurry, no artifacts. |
|
|
2. Ribbon Detection: Ensure no promotional ribbons, watermarks, or text overlays covering the subject. |
|
|
3. Text Legibility: If there is text, is it legible? (Prefer no text for wallpapers). |
|
|
4. Safe Content: No offensive, violent, or adult content. |
|
|
5. Subject Centering: The main subject should be well-positioned for a mobile lock screen (portrait aspect). |
|
|
|
|
|
Return the result as a structured JSON object. |
|
|
`; |
|
|
|
|
|
const response = await ai.models.generateContent({ |
|
|
model: MODEL_NAME, |
|
|
contents: { |
|
|
parts: [ |
|
|
{ inlineData: { mimeType: file.type, data: base64Data } }, |
|
|
{ text: systemPrompt } |
|
|
] |
|
|
}, |
|
|
config: { |
|
|
responseMimeType: "application/json", |
|
|
responseSchema: analysisSchema, |
|
|
temperature: 0.2, |
|
|
} |
|
|
}); |
|
|
|
|
|
if (response.text) { |
|
|
return JSON.parse(response.text) as AnalysisReport; |
|
|
} else { |
|
|
throw new Error("No response text from Gemini."); |
|
|
} |
|
|
|
|
|
} catch (error) { |
|
|
console.error("Gemini Analysis Failed:", error); |
|
|
|
|
|
return { |
|
|
isCompliant: false, |
|
|
overallScore: 0, |
|
|
checks: [ |
|
|
{ name: "System Error", passed: false, reason: "Failed to connect to AI service." } |
|
|
] |
|
|
}; |
|
|
} |
|
|
}; |