Commit
·
9e46f6d
1
Parent(s):
89ce915
First functional version
Browse files- .gitattributes +0 -1
- README.md +3 -3
- app.py +158 -0
- requirements.txt +3 -0
- resources.py +17 -0
.gitattributes
CHANGED
|
@@ -21,7 +21,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 21 |
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 22 |
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 23 |
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 24 |
-
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 25 |
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 26 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 27 |
*.zstandard filter=lfs diff=lfs merge=lfs -text
|
|
|
|
| 21 |
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 22 |
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 23 |
*.tgz filter=lfs diff=lfs merge=lfs -text
|
|
|
|
| 24 |
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 25 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 26 |
*.zstandard filter=lfs diff=lfs merge=lfs -text
|
README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
| 1 |
---
|
| 2 |
title: Gastronomia_para_to2
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: gradio
|
| 7 |
sdk_version: 2.9.0
|
| 8 |
app_file: app.py
|
|
|
|
| 1 |
---
|
| 2 |
title: Gastronomia_para_to2
|
| 3 |
+
emoji: 👩🏻🍳🍳🍳🧑🏻🍳
|
| 4 |
+
colorFrom: yellow
|
| 5 |
+
colorTo: gray
|
| 6 |
sdk: gradio
|
| 7 |
sdk_version: 2.9.0
|
| 8 |
app_file: app.py
|
app.py
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
from transformers import AutoTokenizer, AutoModelForCausalLM
|
| 3 |
+
import re
|
| 4 |
+
from resources import banner, error_html_response
|
| 5 |
+
|
| 6 |
+
model_checkpoint = 'gastronomia-para-to2/gastronomia_para_to2'
|
| 7 |
+
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)
|
| 8 |
+
model = AutoModelForCausalLM.from_pretrained(model_checkpoint)
|
| 9 |
+
|
| 10 |
+
special_tokens = [
|
| 11 |
+
'<INPUT_START>',
|
| 12 |
+
'<NEXT_INPUT>',
|
| 13 |
+
'<INPUT_END>',
|
| 14 |
+
'<TITLE_START>',
|
| 15 |
+
'<TITLE_END>',
|
| 16 |
+
'<INGR_START>',
|
| 17 |
+
'<NEXT_INGR>',
|
| 18 |
+
'<INGR_END>',
|
| 19 |
+
'<INSTR_START>',
|
| 20 |
+
'<NEXT_INSTR>',
|
| 21 |
+
'<INSTR_END>']
|
| 22 |
+
|
| 23 |
+
def frame_html_response(html_response):
|
| 24 |
+
return f"""<iframe style="width: 100%; height: 800px" name="result" allow="midi; geolocation; microphone; camera;
|
| 25 |
+
display-capture; encrypted-media;" sandbox="allow-modals allow-forms
|
| 26 |
+
allow-scripts allow-same-origin allow-popups
|
| 27 |
+
allow-top-navigation-by-user-activation allow-downloads" allowfullscreen=""
|
| 28 |
+
allowpaymentrequest="" frameborder="0" srcdoc='{html_response}'></iframe>"""
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def check_special_tokens_order(pre_output):
|
| 32 |
+
return (pre_output.find('<INPUT_START>') <
|
| 33 |
+
pre_output.find('<NEXT_INPUT>') <=
|
| 34 |
+
pre_output.rfind('<NEXT_INPUT>') <
|
| 35 |
+
pre_output.find('<INPUT_END>') <
|
| 36 |
+
pre_output.find('<INGR_START>') <
|
| 37 |
+
pre_output.find('<NEXT_INGR>') <=
|
| 38 |
+
pre_output.rfind('<NEXT_INGR>') <
|
| 39 |
+
pre_output.find('<INGR_END>') <
|
| 40 |
+
pre_output.find('<INSTR_START>') <
|
| 41 |
+
pre_output.find('<NEXT_INSTR>') <=
|
| 42 |
+
pre_output.rfind('<NEXT_INSTR>') <
|
| 43 |
+
pre_output.find('<INSTR_END>') <
|
| 44 |
+
pre_output.find('<TITLE_START>') <
|
| 45 |
+
pre_output.find('<TITLE_END>'))
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def make_html_response(title, ingredients, instructions):
|
| 49 |
+
ingredients_html_list = '<ul><li>' + '</li><li>'.join(ingredients) + '</li></ul>'
|
| 50 |
+
instructions_html_list = '<ol><li>' + '</li><li>'.join(instructions) + '</li></ol>'
|
| 51 |
+
|
| 52 |
+
html_response = f'''
|
| 53 |
+
<!DOCTYPE html>
|
| 54 |
+
<html>
|
| 55 |
+
<body>
|
| 56 |
+
<h1>{title}</h1>
|
| 57 |
+
|
| 58 |
+
<h2>Ingredientes</h2>
|
| 59 |
+
{ingredients_html_list}
|
| 60 |
+
|
| 61 |
+
<h2>Instrucciones</h2>
|
| 62 |
+
{instructions_html_list}
|
| 63 |
+
|
| 64 |
+
</body>
|
| 65 |
+
</html>
|
| 66 |
+
'''
|
| 67 |
+
return html_response
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
def rerun_model_output(pre_output):
|
| 71 |
+
if pre_output is None:
|
| 72 |
+
return True
|
| 73 |
+
elif not '<RECIPE_END>' in pre_output:
|
| 74 |
+
print('<RECIPE_END> not in pre_output')
|
| 75 |
+
return True
|
| 76 |
+
pre_output_trimmed = pre_output[:pre_output.find('<RECIPE_END>')]
|
| 77 |
+
if not all(special_token in pre_output_trimmed for special_token in special_tokens):
|
| 78 |
+
print('Not all special tokens are in preoutput')
|
| 79 |
+
return True
|
| 80 |
+
elif not check_special_tokens_order(pre_output_trimmed):
|
| 81 |
+
print('Special tokens are unordered in preoutput')
|
| 82 |
+
return True
|
| 83 |
+
elif len(pre_output_trimmed.split())<75:
|
| 84 |
+
print('Length of the recipe is <75')
|
| 85 |
+
return True
|
| 86 |
+
else:
|
| 87 |
+
return False
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
def generate_output(tokenized_input):
|
| 91 |
+
pre_output = None
|
| 92 |
+
while rerun_model_output(pre_output):
|
| 93 |
+
output = model.generate(**tokenized_input,
|
| 94 |
+
max_length=600,
|
| 95 |
+
do_sample=True,
|
| 96 |
+
top_p=0.92,
|
| 97 |
+
top_k=50,
|
| 98 |
+
# no_repeat_ngram_size=2,
|
| 99 |
+
num_return_sequences=3)
|
| 100 |
+
pre_output = tokenizer.decode(output[0], skip_special_tokens=False)
|
| 101 |
+
pre_output_trimmed = pre_output[:pre_output.find('<RECIPE_END>')]
|
| 102 |
+
return pre_output_trimmed
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
def check_wrong_ingredients(ingredients):
|
| 106 |
+
if ingredients is None:
|
| 107 |
+
return True
|
| 108 |
+
if any(ingredient.startswith('De') for ingredient in ingredients):
|
| 109 |
+
print('At least one ingredient starts with De')
|
| 110 |
+
return True
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
def make_recipe(input_ingredients):
|
| 114 |
+
input_ingredients = re.sub(' y ', ', ', input_ingredients)
|
| 115 |
+
input = '<RECIPE_START> '
|
| 116 |
+
input += '<INPUT_START> ' + ' <NEXT_INPUT> '.join(input_ingredients.split(', ')) + ' <INPUT_END> '
|
| 117 |
+
input += '<INGR_START> '
|
| 118 |
+
tokenized_input = tokenizer(input, return_tensors='pt')
|
| 119 |
+
|
| 120 |
+
output_ingredients = None
|
| 121 |
+
i = 0
|
| 122 |
+
while check_wrong_ingredients(output_ingredients):
|
| 123 |
+
if i == 4:
|
| 124 |
+
return frame_html_response(error_html_response)
|
| 125 |
+
pre_output_trimmed = generate_output(tokenized_input)
|
| 126 |
+
output_ingredients = re.search('<INGR_START> (.*) <INGR_END>', pre_output_trimmed).group(1)
|
| 127 |
+
output_ingredients = output_ingredients.split(' <NEXT_INGR> ')
|
| 128 |
+
output_ingredients = list(set([output_ingredient.strip() for output_ingredient in output_ingredients]))
|
| 129 |
+
output_ingredients = [output_ing.capitalize() for output_ing in output_ingredients]
|
| 130 |
+
i += 1
|
| 131 |
+
|
| 132 |
+
output_title = re.search('<TITLE_START> (.*) <TITLE_END>', pre_output_trimmed).group(1).strip().capitalize()
|
| 133 |
+
output_instructions = re.search('<INSTR_START> (.*) <INSTR_END>', pre_output_trimmed).group(1)
|
| 134 |
+
output_instructions = output_instructions.split(' <NEXT_INSTR> ')
|
| 135 |
+
|
| 136 |
+
html_response = make_html_response(output_title, output_ingredients, output_instructions)
|
| 137 |
+
|
| 138 |
+
return frame_html_response(html_response)
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
iface = gr.Interface(
|
| 142 |
+
fn=make_recipe,
|
| 143 |
+
inputs=
|
| 144 |
+
[
|
| 145 |
+
gr.inputs.Textbox(lines=1, placeholder='ingrediente_1, ingrediente_2, ..., ingrediente_n',
|
| 146 |
+
label='Dime con qué ingredientes quieres que cocinemos hoy y te sugeriremos una receta tan pronto como nuestros fogones estén libres'),
|
| 147 |
+
],
|
| 148 |
+
outputs=
|
| 149 |
+
[
|
| 150 |
+
gr.outputs.HTML(label="¡Esta es mi propuesta para ti! ¡Buen provecho!")
|
| 151 |
+
],
|
| 152 |
+
examples=
|
| 153 |
+
[
|
| 154 |
+
['salmón, zumo de naranja, aceite de oliva, sal, pimienta'],
|
| 155 |
+
['harina, azúcar, huevos, chocolate, levadura Royal']
|
| 156 |
+
],
|
| 157 |
+
description=banner)
|
| 158 |
+
iface.launch(enable_queue=True)
|
requirements.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio
|
| 2 |
+
transformers
|
| 3 |
+
torch
|
resources.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
banner = """
|
| 2 |
+
<img src="https://huggingface.co/spaces/gastronomia-para-to2/gastronomia_para_to2/resolve/main/Gastronomia_para_to2_logo.jpg" style="max-width: 100%; max-height: 90%; object-fit: fill">
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
error_html_response = f'''
|
| 6 |
+
<!DOCTYPE html>
|
| 7 |
+
<html>
|
| 8 |
+
<body>
|
| 9 |
+
<h2>Ups... </h2>
|
| 10 |
+
|
| 11 |
+
Nuestro chef está encontrando dificultades para crear una receta con los ingredientes que has indicado.
|
| 12 |
+
Echa un vistazo a tu nevera y prueba a añadir algún ingrediente más.
|
| 13 |
+
¡Seguro que esta vez conseguimos sugerirte una receta exquisita!
|
| 14 |
+
|
| 15 |
+
</body>
|
| 16 |
+
</html>
|
| 17 |
+
'''
|