Etend le pipeline de detection de techniques (tech-step-matcher.ts) pour resoudre, par clause, les metadonnees qui accompagnent une technique detectee : - Ingredients : nouvelle fonction findIngredientMentions (ingredient-matcher.ts) qui scanne le texte d'une clause contre le catalogue Ingredient existant (reutilise INGREDIENT_LABELS_FR/EN deja utilise par matchIngredientName), avec extraction best-effort de la quantite+unite immediatement avant la mention. - Ustensiles : nouveau catalogue Utensil (Prisma) + second PhraseMatcher cote service Python (intent_service/utensil_vocabulary.py), independant du textcat des techniques (pas d'interpretation necessaire pour un ustensile). POST /v1/process distingue desormais chaque entite via un champ kind (technique|utensil). - Persistance : deux nouvelles tables StepTechStepIngredient/ StepTechStepUtensil, liees a StepTechStep par sa cle composite (stepId, order), peuplees au moment du matching (recipe.service.ts) et exposees via StepTechStepView (packages/shared). Aucune analyse syntaxique ajoutee (le parser spaCy reste exclu du pipeline) : l'association se fait par appartenance a la clause deja calculee par splitIntoClauses. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
71 lines
1.7 KiB
TypeScript
71 lines
1.7 KiB
TypeScript
import { wrapAsyncHandler } from "@batch-cooking/express-tools";
|
|
import { Router } from "express";
|
|
import {
|
|
getAllergies,
|
|
getDiets,
|
|
getIngredients,
|
|
getSources,
|
|
getTechSteps,
|
|
getUnits,
|
|
getUtensils,
|
|
} from "./reference.service.js";
|
|
|
|
/**
|
|
* Router mounted at `/reference` in app.ts. Every route is deliberately
|
|
* public (no `requireAuth`) — this is static reference data, not
|
|
* per-household state, and the signup wizard (household/regime/allergen
|
|
* steps) needs to read it before an account — and therefore a session —
|
|
* exists. `/ingredients` follows the same reasoning even though it's only
|
|
* consumed post-login (the recipe catalog) — it's still non-administrable
|
|
* reference data, no reason to require a session to read it.
|
|
*/
|
|
export const referenceRouter = Router();
|
|
|
|
referenceRouter.get(
|
|
"/diets",
|
|
wrapAsyncHandler(async (_req, res) => {
|
|
res.status(200).json(await getDiets());
|
|
}),
|
|
);
|
|
|
|
referenceRouter.get(
|
|
"/allergies",
|
|
wrapAsyncHandler(async (_req, res) => {
|
|
res.status(200).json(await getAllergies());
|
|
}),
|
|
);
|
|
|
|
referenceRouter.get(
|
|
"/ingredients",
|
|
wrapAsyncHandler(async (_req, res) => {
|
|
res.status(200).json(await getIngredients());
|
|
}),
|
|
);
|
|
|
|
referenceRouter.get(
|
|
"/units",
|
|
wrapAsyncHandler(async (_req, res) => {
|
|
res.status(200).json(await getUnits());
|
|
}),
|
|
);
|
|
|
|
referenceRouter.get(
|
|
"/tech-steps",
|
|
wrapAsyncHandler(async (_req, res) => {
|
|
res.status(200).json(await getTechSteps());
|
|
}),
|
|
);
|
|
|
|
referenceRouter.get(
|
|
"/utensils",
|
|
wrapAsyncHandler(async (_req, res) => {
|
|
res.status(200).json(await getUtensils());
|
|
}),
|
|
);
|
|
|
|
referenceRouter.get(
|
|
"/sources",
|
|
wrapAsyncHandler(async (_req, res) => {
|
|
res.status(200).json(await getSources());
|
|
}),
|
|
);
|