From e3ac0b032069d631a40463afa6b4dde63b665f32 Mon Sep 17 00:00:00 2001 From: Landry Simo <86841267+LandPix200@users.noreply.github.com> Date: Sat, 1 Jul 2023 13:05:57 +0100 Subject: [PATCH] hugging face --- lib/apis/keys/ninja.dart | 1 - lib/apis/services/hugging_face.dart | 49 +++++++++++++ lib/apis/services/ninja.dart | 59 ---------------- lib/main.dart | 2 +- lib/models/recipe/recipe.dart | 53 +++++++------- lib/modules/home/components/buttons.dart | 9 +-- lib/modules/home/components/recipe_list.dart | 0 lib/modules/home/components/search.dart | 4 +- lib/modules/home/home.dart | 72 +++++--------------- lib/modules/recipe/recipe.dart | 53 ++------------ 10 files changed, 106 insertions(+), 196 deletions(-) create mode 100644 lib/apis/services/hugging_face.dart delete mode 100644 lib/apis/services/ninja.dart delete mode 100644 lib/modules/home/components/recipe_list.dart diff --git a/lib/apis/keys/ninja.dart b/lib/apis/keys/ninja.dart index eb43929..f30ebd7 100644 --- a/lib/apis/keys/ninja.dart +++ b/lib/apis/keys/ninja.dart @@ -1,4 +1,3 @@ class ApiKeys { - static const ninja = "MqP1o6xY70Aq40AyhCkZ6g==Ydp5zzxo1Zr5qSUB"; static const huggingFace = "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"; } diff --git a/lib/apis/services/hugging_face.dart b/lib/apis/services/hugging_face.dart new file mode 100644 index 0000000..98edf55 --- /dev/null +++ b/lib/apis/services/hugging_face.dart @@ -0,0 +1,49 @@ +import 'dart:convert'; + +import 'package:http/http.dart' as http; +import 'package:translator/translator.dart'; + +import '../../models/recipe/recipe.dart'; +import '../keys/ninja.dart'; + +class HuggingFace { + static final HuggingFace _instance = HuggingFace._internal(); + + factory HuggingFace() { + return _instance; + } + + HuggingFace._internal(); + + static const modelsUrl = "https://api-inference.huggingface.co/models/"; + + Uri _getModel(String modelName) { + return Uri.parse(modelsUrl + modelName); + } + + Future? getRecipe(List ingredients) async { + try { + String translatedIngredients = + (await ingredients.join(",").translate()).text; + + var r = await http.post( + _getModel("flax-community/t5-recipe-generation"), + headers: _getHds, + body: translatedIngredients, + ); + + return Recipe.from(jsonDecode(r.body)[0]["generated_text"]); + } catch (e) { + print(e); + return "Une erreur est survenue \n$e"; + } + } + + Map get _getHds { + return { + 'Authorization': "Bearer ${ApiKeys.huggingFace}", + "Accept": "*/*", + "Content-Type": "application/json", + }; + } +} diff --git a/lib/apis/services/ninja.dart b/lib/apis/services/ninja.dart deleted file mode 100644 index 63113da..0000000 --- a/lib/apis/services/ninja.dart +++ /dev/null @@ -1,59 +0,0 @@ -import 'dart:convert'; - -import 'package:http/http.dart' as http; -import 'package:recipe_finder/models/recipe/recipe.dart'; -import 'package:translator/translator.dart'; - -import '../../utils/logic.dart'; -import '../keys/ninja.dart'; - -class Ninja { - static Future>? getRecipes(String word) async { - try { - String translatedWord = (await word.translate()).text; - - var r = - await http.get(getEndPoint("recipe?query=$translatedWord"), headers: { - 'X-Api-Key': ApiKeys.ninja, - }); - - List recipes = - List.from(jsonDecode(r.body)).map((e) => Recipe.fromJson(e)).toList(); - return recipes; - } catch (e) { - return []; - } - } - - static Future? getFullRecipes(List words) async { - try { - List recipes = []; - - for (var word in words) { - recipes.addAll((await getRecipes(word))!.toList()); - } - recipes.shuffle(); - if (recipes.isEmpty) { - return "Aucun résultat trouvé !"; - } - return recipes; - } catch (e) { - return "Une erreur est survenue !"; - } - } - - static Recipe getRandomRecipe(List recipes, List words) { - List rps = []; - - for (var recipe in recipes) { - for (var word in words) { - if (recipe.containsIngredient(word.toLowerCase())) { - rps.add(recipe); - } - } - } - - rps.shuffle(); - return rps.first; - } -} diff --git a/lib/main.dart b/lib/main.dart index a54c6cd..ecebd0e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -12,7 +12,7 @@ class MainApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( - title: "Recipe Discover", + title: "Recipe Generator", debugShowCheckedModeBanner: false, home: const HomePage(), theme: ThemeData( diff --git a/lib/models/recipe/recipe.dart b/lib/models/recipe/recipe.dart index 9108f37..24249d4 100644 --- a/lib/models/recipe/recipe.dart +++ b/lib/models/recipe/recipe.dart @@ -1,36 +1,37 @@ class Recipe { - String? title; - String? ingredients; - String? servings; - String? instructions; + String title; + String ingredients; + String directions; Recipe({ - this.title, - this.ingredients, - this.servings, - this.instructions, + required this.title, + required this.ingredients, + required this.directions, }); - Map toJson() => { - 'title': title, - 'ingredients': ingredients, - 'servings': servings, - 'instructions': instructions, - }; + factory Recipe.from(String text) { + List results = ["", "", ""]; + + List words = text.split(" "); + int index = 0; + for (var word in words) { + if (word == "title:") { + index = 0; + } else if (word == "ingredients:") { + index = 1; + } else if (word == "directions:") { + index = 2; + } + if (["title:", "ingredients:", "directions:"].contains(word)) { + continue; + } + results[index] += "$word "; + } - factory Recipe.fromJson(Map json) { return Recipe( - title: json['title'], - ingredients: json['ingredients'], - servings: json['servings'], - instructions: json['instructions'], + title: results[0], + ingredients: results[1], + directions: results[2], ); } - - bool containsIngredient(String word) { - return ingredients!.contains(word) || - instructions!.contains(word) || - servings!.contains(word) || - title!.contains(word); - } } diff --git a/lib/modules/home/components/buttons.dart b/lib/modules/home/components/buttons.dart index 574f916..eb2ef4e 100644 --- a/lib/modules/home/components/buttons.dart +++ b/lib/modules/home/components/buttons.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; - -import '../../../apis/services/ninja.dart'; +import 'package:recipe_finder/apis/services/hugging_face.dart'; class FindButton extends StatelessWidget { const FindButton({ @@ -16,11 +15,13 @@ class FindButton extends StatelessWidget { Widget build(BuildContext context) { return FilledButton.icon( style: const ButtonStyle( - fixedSize: MaterialStatePropertyAll(Size(double.maxFinite, 50)), + fixedSize: MaterialStatePropertyAll( + Size(double.maxFinite, 50), + ), ), onPressed: () { onTap!("Nous cherchons ta recette..."); - Ninja.getFullRecipes(ingredients)?.then((value) { + HuggingFace().getRecipe(ingredients)?.then((value) { onTap!(value); }); }, diff --git a/lib/modules/home/components/recipe_list.dart b/lib/modules/home/components/recipe_list.dart deleted file mode 100644 index e69de29..0000000 diff --git a/lib/modules/home/components/search.dart b/lib/modules/home/components/search.dart index 7dbad1f..0d977da 100644 --- a/lib/modules/home/components/search.dart +++ b/lib/modules/home/components/search.dart @@ -17,14 +17,14 @@ class SearchInput extends StatelessWidget { contentPadding: const EdgeInsets.only(left: 10), border: OutlineInputBorder( gapPadding: 0, - borderRadius: BorderRadius.circular(15), + borderRadius: BorderRadius.circular(12), ), hintText: "Ajoute ton ingredient ici", suffixIcon: IconButton.filled( style: const ButtonStyle( shape: MaterialStatePropertyAll(RoundedRectangleBorder( borderRadius: - BorderRadius.horizontal(right: Radius.circular(15)))), + BorderRadius.horizontal(right: Radius.circular(12)))), ), onPressed: () { onSearch!(controller.text); diff --git a/lib/modules/home/home.dart b/lib/modules/home/home.dart index 63023f0..6ca2488 100644 --- a/lib/modules/home/home.dart +++ b/lib/modules/home/home.dart @@ -1,9 +1,7 @@ import 'package:flutter/material.dart'; import 'package:recipe_finder/models/recipe/recipe.dart'; import 'package:recipe_finder/modules/recipe/recipe.dart'; -import 'package:recipe_finder/widgets/texts.dart'; -import '../../utils/logic.dart'; import 'components/buttons.dart'; import 'components/search.dart'; @@ -17,28 +15,21 @@ class HomePage extends StatefulWidget { class _HomePageState extends State { List ingredients = []; - List? recipes; + Recipe? recipe; String? helperText; @override Widget build(BuildContext context) { return Scaffold( + appBar: AppBar( + title: const Text("Recipe Generator"), + ), + backgroundColor: Colors.orange.shade50, body: Padding( padding: const EdgeInsets.all(8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const SizedBox( - height: 30, - ), - const Text( - "Trouve ta recette avec ce que tu as dans ton frigo !", - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - const Divider(), SearchInput( onSearch: (text) { setState(() { @@ -65,15 +56,13 @@ class _HomePageState extends State { .toList(), ), Expanded( - child: recipes != null || (recipes ?? []).isNotEmpty - ? RecipeList(recipes: recipes ?? []) - : Center( - child: Text( - helperText ?? "", - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), + child: recipe == null + ? Center(child: Text(helperText ?? "")) + : SingleChildScrollView( + child: RecipeCard( + title: recipe!.title, + ingredients: recipe!.ingredients, + instructions: recipe!.directions, ), ), ), @@ -89,11 +78,11 @@ class _HomePageState extends State { } void _searchRecipe(value) { - helperText == null; - recipes = null; - if (value is List) { + helperText == "Nous concevons une belle recette..."; + recipe = null; + if (value is Recipe) { setState(() { - recipes = value; + recipe = value; }); } if (value is String) { @@ -103,34 +92,9 @@ class _HomePageState extends State { } if (value == null) { setState(() { - helperText = "Voire les recettes trouvées !"; + helperText = + "Le cuisinier est occupé, veuillez patientez et réessayer dans une minute !"; }); } } } - -class RecipeList extends StatelessWidget { - const RecipeList({super.key, required this.recipes}); - - final List recipes; - - @override - Widget build(BuildContext context) { - return ListView.separated( - itemBuilder: (context, index) { - return ListTile( - leading: const Icon(Icons.food_bank_outlined), - onTap: () { - Nav.push(context, RecipePage(recipe: recipes[index])); - }, - title: TextTr( - recipes[index].title!, - ), - ); - }, - separatorBuilder: (context, index) { - return const Divider(); - }, - itemCount: recipes.length); - } -} diff --git a/lib/modules/recipe/recipe.dart b/lib/modules/recipe/recipe.dart index ce2db40..bc8b251 100644 --- a/lib/modules/recipe/recipe.dart +++ b/lib/modules/recipe/recipe.dart @@ -20,48 +20,28 @@ class RecipePage extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - // _buildHeadText("Ingredients :"), - // IngredientsWidget(ingredients: recipe!.ingredients!), - // const SizedBox( - // height: 15, - // ), - // _buildHeadText("Instructions :"), - // InstructionsWidget(instructions: recipe!.instructions!), RecipeCard( - title: recipe!.title!, - ingredients: recipe!.ingredients!, - servings: recipe!.servings!, - instructions: recipe!.instructions!), + title: recipe!.title, + ingredients: recipe!.ingredients, + instructions: recipe!.directions, + ), ], ), ), ), ); } - - // Text _buildHeadText(String text) { - // return Text( - // text, - // style: TextStyle( - // fontSize: 16, - // fontWeight: FontWeight.bold, - // color: Colors.orange.shade800, - // ), - // ); - // } } class RecipeCard extends StatelessWidget { final String title; final String ingredients; - final String servings; final String instructions; const RecipeCard({ super.key, required this.title, required this.ingredients, - required this.servings, required this.instructions, }); @@ -77,18 +57,6 @@ class RecipeCard extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - children: [ - const Spacer(), - IconButton( - - onPressed: () { - Navigator.pop(context); - }, - icon: const Icon(Icons.close, color: Colors.red), - ) - ], - ), TextTr( title, style: const TextStyle( @@ -107,19 +75,6 @@ class RecipeCard extends StatelessWidget { const SizedBox(height: 8.0), IngredientsWidget(ingredients: ingredients), const SizedBox(height: 16.0), - const TextTr( - 'Servings:', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 8.0), - TextTr( - servings, - style: const TextStyle(fontSize: 16), - ), - const SizedBox(height: 16.0), const TextTr( 'Instructions:', style: TextStyle(