feat: split photo-import into vision recognition + text generation
The photo-import flow used one vision-capable model to both read the photo and structure the full recipe (quantities, steps, timing) in a single call. Split it into two: a vision model recognizes what's in the picture, then a text model reconstructs the recipe from that description — same pattern the pantry photo-scan already uses for recognition, and lets structuring use whichever model is actually configured for text generation. Still counts as one AI-quota unit. v0.37.0
This commit is contained in:
@@ -13,6 +13,8 @@ export function PhotoImportButton() {
|
||||
const router = useRouter();
|
||||
const fileRef = useRef<HTMLInputElement>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [stage, setStage] = useState<"recognizing" | "generating">("recognizing");
|
||||
const stageTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
function handleClick() {
|
||||
fileRef.current?.click();
|
||||
@@ -23,6 +25,12 @@ export function PhotoImportButton() {
|
||||
if (!file) return;
|
||||
|
||||
setLoading(true);
|
||||
setStage("recognizing");
|
||||
// The photo-import flow is two sequential AI calls (vision recognition,
|
||||
// then text generation) behind a single request/response — there's no
|
||||
// real progress signal to react to, so this just approximates the
|
||||
// handoff point for the loading copy.
|
||||
stageTimerRef.current = setTimeout(() => setStage("generating"), 5000);
|
||||
|
||||
try {
|
||||
const base64 = await new Promise<string>((resolve, reject) => {
|
||||
@@ -57,6 +65,7 @@ export function PhotoImportButton() {
|
||||
} catch (err) {
|
||||
toast.error(err instanceof Error ? err.message : t("photoImportFailed"));
|
||||
} finally {
|
||||
if (stageTimerRef.current) clearTimeout(stageTimerRef.current);
|
||||
setLoading(false);
|
||||
// Reset input so the same file can be re-selected
|
||||
if (fileRef.current) fileRef.current.value = "";
|
||||
@@ -80,7 +89,11 @@ export function PhotoImportButton() {
|
||||
)}
|
||||
{t("importFromPhoto")}
|
||||
</Button>
|
||||
<FakeProgressBar active={loading} durationMs={12000} label={loading ? t("analyzingPhoto") : undefined} />
|
||||
<FakeProgressBar
|
||||
active={loading}
|
||||
durationMs={12000}
|
||||
label={loading ? (stage === "recognizing" ? t("recognizingPhoto") : t("writingRecipe")) : undefined}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user