1
0
Fork 0
mirror of https://github.com/mealie-recipes/mealie.git synced 2025-07-23 15:19:41 +02:00

feat: Recipe Finder (aka Cocktail Builder) (#4542)

This commit is contained in:
Michael Genson 2024-12-03 07:27:41 -06:00 committed by GitHub
parent d26e29d1c5
commit 4e0cf985bc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 1959 additions and 151 deletions

View file

@ -1,6 +1,6 @@
import { BaseCRUDAPIReadOnly } from "~/lib/api/base/base-clients";
import { route } from "../../base";
import { Recipe } from "~/lib/api/types/recipe";
import { Recipe, RecipeSuggestionQuery, RecipeSuggestionResponse } from "~/lib/api/types/recipe";
import { ApiRequestInstance, PaginationData } from "~/lib/api/types/non-generated";
import { RecipeSearchQuery } from "../../user/recipes/recipe";
@ -23,4 +23,10 @@ export class PublicRecipeApi extends BaseCRUDAPIReadOnly<Recipe> {
async search(rsq: RecipeSearchQuery) {
return await this.requests.get<PaginationData<Recipe>>(route(routes.recipesGroupSlug(this.groupSlug), rsq));
}
async getSuggestions(q: RecipeSuggestionQuery, foods: string[] | null = null, tools: string[]| null = null) {
return await this.requests.get<RecipeSuggestionResponse>(
route(`${this.baseRoute}/suggestions`, { ...q, foods, tools })
);
}
}

View file

@ -7,6 +7,8 @@
export type ExportTypes = "json";
export type RegisteredParser = "nlp" | "brute" | "openai";
export type OrderByNullPosition = "first" | "last";
export type OrderDirection = "asc" | "desc";
export type TimelineEventType = "system" | "info" | "comment";
export type TimelineEventImage = "has image" | "does not have image";
@ -380,6 +382,26 @@ export interface RecipeShareTokenSummary {
export interface RecipeSlug {
slug: string;
}
export interface RecipeSuggestionQuery {
orderBy?: string | null;
orderByNullPosition?: OrderByNullPosition | null;
orderDirection?: OrderDirection;
queryFilter?: string | null;
paginationSeed?: string | null;
limit?: number;
maxMissingFoods?: number;
maxMissingTools?: number;
includeFoodsOnHand?: boolean;
includeToolsOnHand?: boolean;
}
export interface RecipeSuggestionResponse {
items: RecipeSuggestionResponseItem[];
}
export interface RecipeSuggestionResponseItem {
recipe: RecipeSummary;
missingFoods: IngredientFood[];
missingTools: RecipeTool[];
}
export interface RecipeTagResponse {
name: string;
id: string;
@ -519,3 +541,10 @@ export interface UnitFoodBase {
export interface UpdateImageResponse {
image: string;
}
export interface RequestQuery {
orderBy?: string | null;
orderByNullPosition?: OrderByNullPosition | null;
orderDirection?: OrderDirection;
queryFilter?: string | null;
paginationSeed?: string | null;
}

View file

@ -20,13 +20,13 @@ export interface FileTokenResponse {
fileToken: string;
}
export interface PaginationQuery {
page?: number;
perPage?: number;
orderBy?: string | null;
orderByNullPosition?: OrderByNullPosition | null;
orderDirection?: OrderDirection;
queryFilter?: string | null;
paginationSeed?: string | null;
page?: number;
perPage?: number;
}
export interface QueryFilterJSON {
parts?: QueryFilterJSONPart[];
@ -47,6 +47,13 @@ export interface RecipeSearchQuery {
requireAllFoods?: boolean;
search?: string | null;
}
export interface RequestQuery {
orderBy?: string | null;
orderByNullPosition?: OrderByNullPosition | null;
orderDirection?: OrderDirection;
queryFilter?: string | null;
paginationSeed?: string | null;
}
export interface SuccessResponse {
message: string;
error?: boolean;

View file

@ -11,6 +11,8 @@ import {
UpdateImageResponse,
RecipeZipTokenResponse,
RecipeLastMade,
RecipeSuggestionQuery,
RecipeSuggestionResponse,
RecipeTimelineEventIn,
RecipeTimelineEventOut,
RecipeTimelineEventUpdate,
@ -31,6 +33,7 @@ const prefix = "/api";
const routes = {
recipesCreate: `${prefix}/recipes/create`,
recipesBase: `${prefix}/recipes`,
recipesSuggestions: `${prefix}/recipes/suggestions`,
recipesTestScrapeUrl: `${prefix}/recipes/test-scrape-url`,
recipesCreateUrl: `${prefix}/recipes/create/url`,
recipesCreateUrlBulk: `${prefix}/recipes/create/url/bulk`,
@ -109,6 +112,12 @@ export class RecipeAPI extends BaseCRUDAPI<CreateRecipe, Recipe, Recipe> {
});
}
async getSuggestions(q: RecipeSuggestionQuery, foods: string[] | null = null, tools: string[]| null = null) {
return await this.requests.get<RecipeSuggestionResponse>(
route(routes.recipesSuggestions, { ...q, foods, tools })
);
}
async createAsset(recipeSlug: string, payload: CreateAsset) {
const formData = new FormData();
formData.append("file", payload.file);