Brk45 commited on
Commit
8419c9b
·
1 Parent(s): 939124f

Initial commit

Browse files
.DS_Store ADDED
Binary file (6.15 kB). View file
 
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ chroma_db/** filter=lfs diff=lfs merge=lfs -text
app.py ADDED
@@ -0,0 +1,216 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import os
3
+ import datetime
4
+ from fpdf import FPDF
5
+ from openai import OpenAI
6
+ from langchain.chat_models import ChatOpenAI
7
+ from langchain.memory import ConversationBufferMemory
8
+ from langchain.vectorstores import Chroma
9
+ from langchain.embeddings import OpenAIEmbeddings
10
+ from langchain.chains import LLMChain
11
+ from langchain.prompts import PromptTemplate
12
+
13
+ # ========== SETUP ==========
14
+ st.set_page_config(page_title="Papill’IA - Assistant Recette", page_icon="🍳")
15
+
16
+ # ========== CONFIG OPENAI ==========
17
+ openai_api_key = "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"
18
+ openai_client = OpenAI(api_key=openai_api_key)
19
+
20
+ # ========== DOSSIERS ==========
21
+ DATA_DIR = "data"
22
+ os.makedirs(DATA_DIR, exist_ok=True)
23
+ PERSO_PATH = os.path.join(DATA_DIR, "recettes_perso.txt")
24
+
25
+ # ========== CHROMA & LangChain Setup ==========
26
+ @st.cache_resource
27
+ def load_resources():
28
+ vectordb = Chroma(
29
+ collection_name="recipes",
30
+ persist_directory="chroma_db",
31
+ embedding_function=OpenAIEmbeddings(openai_api_key=openai_api_key)
32
+ )
33
+ retriever = vectordb.as_retriever(search_kwargs={"k": 3})
34
+ memory = ConversationBufferMemory(
35
+ memory_key="chat_history",
36
+ return_messages=True,
37
+ output_key="answer"
38
+ )
39
+ llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0.7, openai_api_key=openai_api_key)
40
+ return vectordb, retriever, memory, llm
41
+
42
+ vectordb, retriever, memory, llm = load_resources()
43
+
44
+ # ========== INTERFACE ==========
45
+ st.title("👨‍🍳 Papill’IA – Ton assistant de cuisine intelligent")
46
+ tabs = st.tabs(["💬 Discuter avec Papill’IA", "📚 Mes favoris", "📖 Mes recettes perso", "➕ Contribuer une recette"])
47
+
48
+ # ===== TAB 1 : CHAT =====
49
+ with tabs[0]:
50
+ st.subheader("💬 Discuter avec Papill’IA")
51
+
52
+ if st.button("🔄 Réinitialiser la conversation"):
53
+ st.session_state.chat_history = []
54
+ st.session_state.last_reply = ""
55
+ fav_path = os.path.join(DATA_DIR, "recettes_favorites.txt")
56
+ if os.path.exists(fav_path):
57
+ os.remove(fav_path)
58
+ st.success("💬 Conversation et favoris réinitialisés.")
59
+
60
+ if "chat_history" not in st.session_state:
61
+ st.session_state.chat_history = []
62
+ if "last_reply" not in st.session_state:
63
+ st.session_state["last_reply"] = ""
64
+
65
+ with st.expander("⚙️ Options de personnalisation"):
66
+ portions = st.slider("👥 Nombre de personnes", 1, 10, 2)
67
+ regimes = st.multiselect("📜 Régimes alimentaires", ["Végétarien", "Vegan", "Sans gluten", "Sans lactose", "Keto", "Halal"])
68
+
69
+ for msg in st.session_state.chat_history:
70
+ with st.chat_message(msg["role"]):
71
+ st.markdown(msg["content"])
72
+
73
+ user_msg = st.chat_input("Pose ta question ou demande une recette personnalisée...")
74
+
75
+ if user_msg:
76
+ last_recipe = st.session_state["last_reply"]
77
+ modif_keywords = ["sans", "retire", "enlève", "j’aime pas", "j'aime pas", "enlever", "supprime", "remplace"]
78
+ is_modification = any(k in user_msg.lower() for k in modif_keywords)
79
+
80
+ if is_modification and last_recipe:
81
+ full_query = f"""
82
+ Tu es Papill’IA, un chef cuisinier français expert et créatif.
83
+ Voici une recette à modifier selon les indications de l'utilisateur.
84
+
85
+ 🧰 Recette actuelle :
86
+ {last_recipe}
87
+
88
+ 🔄 Demande de modification :
89
+ {user_msg}
90
+
91
+ Consignes :
92
+ - Ne propose PAS une nouvelle recette sauf si expressément demandé.
93
+ - Modifie uniquement ce qui est demandé (par exemple : juste l'accompagnement).
94
+ - Garde le reste identique sauf si incohérent.
95
+ - Réponds avec une recette complète modifiée.
96
+ """
97
+ else:
98
+ full_query = f"""
99
+ Tu es Papill’IA, un chef cuisinier français expert, drôle et bienveillant.
100
+ Tu proposes des recettes personnalisées en respectant les consignes suivantes :
101
+ - Adapter aux préférences : {portions} personne(s), régimes : {', '.join(regimes) if regimes else 'aucun'}
102
+ - Proposer un accompagnement adapté et des astuces de chef.
103
+ - Fournir une estimation nutritionnelle.
104
+ - Être flexible et inventif même si la demande est floue ou étrange.
105
+
106
+ Demande utilisateur :
107
+ {user_msg}
108
+ """
109
+
110
+ st.session_state.chat_history.append({"role": "user", "content": user_msg})
111
+ with st.chat_message("user"):
112
+ st.markdown(user_msg)
113
+
114
+ with st.spinner("Papill’IA réfléchit..."):
115
+ docs = retriever.get_relevant_documents(full_query)
116
+ if docs:
117
+ prompt_template = PromptTemplate.from_template("""{question}""")
118
+ qa_chain = LLMChain(llm=llm, prompt=prompt_template)
119
+ reply = qa_chain.invoke({"question": full_query})["text"]
120
+ else:
121
+ reply = llm.invoke(full_query).content
122
+
123
+ st.session_state.chat_history.append({"role": "assistant", "content": reply})
124
+ st.session_state["last_reply"] = reply
125
+
126
+ with st.chat_message("assistant"):
127
+ st.markdown(reply)
128
+
129
+ # ===== PDF & FAVORIS =====
130
+ def save_pdf(text):
131
+ pdf = FPDF()
132
+ pdf.add_page()
133
+ pdf.set_font("Arial", size=12)
134
+ for line in text.split('\n'):
135
+ pdf.multi_cell(0, 10, line)
136
+ filename = f"recette_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.pdf"
137
+ filepath = os.path.join(DATA_DIR, filename)
138
+ pdf.output(filepath)
139
+ return filepath
140
+
141
+ def save_favorite(text):
142
+ fav_path = os.path.join(DATA_DIR, "recettes_favorites.txt")
143
+ with open(fav_path, "a", encoding="utf-8") as f:
144
+ f.write("\n" + "="*60 + "\n")
145
+ f.write(text.strip() + "\n")
146
+ st.success("✅ Recette sauvegardée dans les favoris !")
147
+
148
+ col1, col2 = st.columns(2)
149
+ with col1:
150
+ if st.button("📄 Télécharger en PDF"):
151
+ pdf_path = save_pdf(reply)
152
+ with open(pdf_path, "rb") as file:
153
+ st.download_button("📅 Télécharger le PDF", file, pdf_path, mime="application/pdf")
154
+
155
+ with col2:
156
+ if st.button("❤️ Ajouter aux favoris"):
157
+ save_favorite(reply)
158
+
159
+ # ====== TAB 2 : FAVORIS ======
160
+ with tabs[1]:
161
+ st.subheader("📚 Mes recettes favorites")
162
+ fav_path = os.path.join(DATA_DIR, "recettes_favorites.txt")
163
+ if os.path.exists(fav_path):
164
+ with open(fav_path, "r", encoding="utf-8") as f:
165
+ favoris = f.read().strip()
166
+ if favoris:
167
+ st.text_area("📜 Recettes sauvegardées :", favoris, height=400)
168
+ else:
169
+ st.info("Aucune recette sauvegardée pour le moment.")
170
+ else:
171
+ st.info("Le fichier des favoris n’existe pas encore. Sauvegarde une recette pour le créer.")
172
+
173
+ # ====== TAB 3 : RECETTES PERSO ======
174
+ with tabs[2]:
175
+ st.subheader("📖 Mes recettes perso")
176
+ if os.path.exists(PERSO_PATH):
177
+ with open(PERSO_PATH, "r", encoding="utf-8") as f:
178
+ perso = f.read().strip()
179
+ if perso:
180
+ st.text_area("📝 Recettes personnelles :", perso, height=400)
181
+ else:
182
+ st.info("Aucune recette personnelle ajoutée pour le moment.")
183
+ else:
184
+ st.info("Tu n’as pas encore contribué de recette.")
185
+
186
+ # ====== TAB 4 : CONTRIBUTION ======
187
+ with tabs[3]:
188
+ st.subheader("➕ Ajouter une recette personnelle")
189
+
190
+ option = st.radio("Méthode d'ajout", ["✍️ Écrire la recette", "📄 Importer un PDF"])
191
+
192
+ if option == "✍️ Écrire la recette":
193
+ titre = st.text_input("Nom de la recette")
194
+ contenu = st.text_area("Écris ici ta recette complète")
195
+ if st.button("✅ Ajouter à la base"):
196
+ if titre and contenu.strip():
197
+ vectordb.add_texts([contenu], ids=[titre])
198
+ with open(PERSO_PATH, "a", encoding="utf-8") as f:
199
+ f.write(f"\n{'='*40}\n{titre}\n{contenu.strip()}\n")
200
+ st.success("🎉 Recette ajoutée avec succès à la base de données !")
201
+ st.chat_message("assistant").markdown(f"✅ Recette **{titre}** ajoutée !")
202
+ else:
203
+ st.warning("Merci de remplir les deux champs.")
204
+
205
+ elif option == "📄 Importer un PDF":
206
+ pdf_file = st.file_uploader("📄 Dépose ton fichier PDF", type=["pdf"])
207
+ if pdf_file and st.button("✅ Importer le PDF"):
208
+ from PyPDF2 import PdfReader
209
+ reader = PdfReader(pdf_file)
210
+ texte = "\n".join([page.extract_text() for page in reader.pages])
211
+ titre = os.path.splitext(pdf_file.name)[0]
212
+ vectordb.add_texts([texte], ids=[titre])
213
+ with open(PERSO_PATH, "a", encoding="utf-8") as f:
214
+ f.write(f"\n{'='*40}\n{titre}\n{texte.strip()}\n")
215
+ st.success(f"📚 PDF '{titre}' indexé avec succès dans la base !")
216
+ st.chat_message("assistant").markdown(f"✅ Recette **{titre}** ajoutée via PDF !")
chroma_db/ad4f4931-3d96-4e9c-a3c8-04cd4fbb0ce5/data_level0.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:bb41acbe3c1b8607508173321e7ebad22da8c1cf81b42d99158c6cab8ab27aef
3
+ size 106828000
chroma_db/ad4f4931-3d96-4e9c-a3c8-04cd4fbb0ce5/header.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:636ae6d5d386e835b6249d1a233a3b30d0c8e13c55225dd0aaf9581cc3850b49
3
+ size 100
chroma_db/ad4f4931-3d96-4e9c-a3c8-04cd4fbb0ce5/index_metadata.pickle ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:199e8f3b67bc853a37095d8c6020c9b8bcf1e9cbce2c8f6a1274e620a32d1117
3
+ size 470407
chroma_db/ad4f4931-3d96-4e9c-a3c8-04cd4fbb0ce5/length.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a81139698ef3acae3a92638a6a26b313290dab405952c60f9013c7c0d2fc9b04
3
+ size 68000
chroma_db/ad4f4931-3d96-4e9c-a3c8-04cd4fbb0ce5/link_lists.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d0b5839e8b4a750768b4237d6680419925345f22d0656845281894a580e7bed4
3
+ size 147492
chroma_db/chroma.sqlite3 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c615b4fab26523a6b5a8afbd3da06e22d29e3b8fbb6116441be7db14436ccb52
3
+ size 89743360
data/.DS_Store ADDED
Binary file (6.15 kB). View file
 
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ streamlit
2
+ fpdf
3
+ requests
4
+ chromadb
5
+ sentence-transformers