CalmeBouquetin76 commited on
Commit
9c3290c
·
verified ·
1 Parent(s): 410b151

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +111 -0
app.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import pdfplumber
3
+ import streamlit as st
4
+ import time
5
+ from dotenv import load_dotenv, find_dotenv
6
+
7
+ from langchain_ollama import OllamaEmbeddings
8
+ from langchain_chroma import Chroma
9
+ from langchain_core.documents import Document
10
+ from langchain_text_splitters import RecursiveCharacterTextSplitter
11
+
12
+ from langchain_groq.chat_models import ChatGroq
13
+ from langchain.prompts import PromptTemplate
14
+ from langchain.chains import RetrievalQA
15
+
16
+ # ------------------ CONFIG ------------------
17
+
18
+ load_dotenv(find_dotenv())
19
+ PDF_PATH = os.path.join(os.path.dirname(__file__), "docs", "document.pdf")
20
+ CHROMA_DIR = "chroma_db"
21
+ EMBED_MODEL = "all-minilm"
22
+ GROQ_MODEL = "llama3-70b-8192"
23
+
24
+ # ------------------ UTILS ------------------
25
+
26
+ @st.cache_resource
27
+ def load_vectorstore():
28
+ embedding = OllamaEmbeddings(model=EMBED_MODEL)
29
+
30
+ if not os.path.exists(CHROMA_DIR):
31
+ with pdfplumber.open(PDF_PATH) as pdf:
32
+ full_text = ""
33
+ for page in pdf.pages:
34
+ full_text += page.extract_text() + "\n"
35
+
36
+ if not full_text.strip():
37
+ st.error("❌ Le PDF est vide ou illisible.")
38
+ st.stop()
39
+
40
+ cleaned = " ".join(full_text.split())
41
+ doc = Document(page_content=cleaned, metadata={"file": os.path.basename(PDF_PATH)})
42
+
43
+ splitter = RecursiveCharacterTextSplitter(chunk_size=2000, chunk_overlap=100)
44
+ chunks = splitter.split_documents([doc])
45
+ return Chroma.from_documents(chunks, embedding=embedding, persist_directory=CHROMA_DIR)
46
+ else:
47
+ return Chroma(persist_directory=CHROMA_DIR, embedding_function=embedding)
48
+
49
+ def create_qa_chain(db):
50
+ retriever = db.as_retriever(search_type="mmr", search_kwargs={"k": 5})
51
+ llm = ChatGroq(model=GROQ_MODEL, api_key=os.getenv("GROQ_API_KEY"))
52
+
53
+ prompt = PromptTemplate(
54
+ template="""
55
+ Tu es un assistant agricole expert francophone nommé Terr'Y, créé par Terr'O.
56
+ Tu ne dois répondre qu'à partir du document fourni. Si la réponse n'est pas dans le document, dis-le honnêtement.
57
+ Ta mission est de répondre **uniquement** à partir du contenu du document fourni.
58
+
59
+ Si la réponse contient des éléments structurés (ex : primes, cultures, conditions, barèmes, dates, etc.), tu dois les présenter sous forme de **tableau clair**.
60
+
61
+ Consignes :
62
+ - Utilise un ton clair, professionnel et en français.
63
+ - Réponds exclusivement à partir des documents.
64
+ - Ne complète jamais avec des données absentes.
65
+ - Si l’information n’est pas présente, indique-le simplement.
66
+ - Tu t'appelles Terr'Y l'assistant agricole créé par Terr'O.
67
+
68
+ Question : {question}
69
+ Contenu : {context}
70
+ """,
71
+ input_variables=["question", "context"]
72
+ )
73
+
74
+ return RetrievalQA.from_chain_type(
75
+ llm=llm,
76
+ retriever=retriever,
77
+ chain_type="stuff",
78
+ chain_type_kwargs={"prompt": prompt}
79
+ )
80
+
81
+ def typewriter(text, delay=0.03):
82
+ container = st.empty()
83
+ words = text.split(" ")
84
+ typed = ""
85
+ for word in words:
86
+ typed += word + " "
87
+ container.markdown(typed)
88
+ time.sleep(delay)
89
+
90
+ # ------------------ INTERFACE STREAMLIT ------------------
91
+
92
+ st.set_page_config(page_title="Terr'Y - Assistant Collecte", page_icon="🌾", layout="wide")
93
+
94
+ col1, col2 = st.columns([1, 6])
95
+ with col1:
96
+ st.image("images/terrY.png", width=100)
97
+ with col2:
98
+ st.title("🌾 Terr'Y - Assistant Agricole")
99
+ st.markdown("Pose une question sur le livret de campagne collecte 2024 📘")
100
+
101
+
102
+ question = st.text_input("Ta question ici :", placeholder="Ex. : Quelles sont les primes pour le blé tendre ?")
103
+
104
+ if question:
105
+ with st.spinner("Terr'Y réfléchit..."):
106
+ db = load_vectorstore()
107
+ qa = create_qa_chain(db)
108
+ response = qa.invoke(question)
109
+ answer = response["result"]
110
+ st.markdown("### 🧠 Réponse")
111
+ typewriter(answer)