AlirezaHSZ commited on
Commit
2c2fb6b
·
verified ·
1 Parent(s): b619688

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +97 -143
app.py CHANGED
@@ -1,177 +1,131 @@
1
- import os
2
- import fitz # PyMuPDF
3
  import streamlit as st
 
 
 
 
 
4
  import google.generativeai as genai
5
- from dotenv import load_dotenv
6
- from google.api_core.exceptions import GoogleAPIError, InvalidArgument
7
-
8
- from langchain.text_splitter import RecursiveCharacterTextSplitter
9
- from langchain_google_genai import GoogleGenerativeAIEmbeddings, ChatGoogleGenerativeAI
10
  from langchain_community.vectorstores import FAISS
11
- from langchain.chains.question_answering import load_qa_chain
12
- from langchain.prompts import PromptTemplate
 
13
 
14
- # Load environment variables
 
 
15
  load_dotenv()
16
- api_key = os.getenv("GOOGLE_API_KEY")
17
- genai.configure(api_key=api_key)
18
 
 
19
 
20
- # ✅ Read all PDFs (supports Farsi + English)
21
- def get_pdf_text(pdf_docs):
 
 
22
  text = ""
23
- for pdf in pdf_docs:
24
- with fitz.open(stream=pdf.read(), filetype="pdf") as doc:
25
- for page in doc:
26
- page_text = page.get_text("text")
27
- if page_text:
28
- text += page_text + "\n"
29
  return text
30
 
31
-
32
- # Split text into chunks
33
- def get_text_chunks(text):
34
- splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
35
- return splitter.split_text(text)
36
-
37
-
38
- # ✅ Get embeddings + save vector store
39
- def get_vector_store(chunks):
40
- embeddings = GoogleGenerativeAIEmbeddings(model="models/text-embedding-004")
41
- vector_store = FAISS.from_texts(chunks, embedding=embeddings)
42
- vector_store.save_local("faiss_index")
43
-
44
-
45
- # ✅ Conversational chain
46
  def get_conversational_chain():
47
- map_prompt_template = """
48
- لطفاً بر اساس متن زیر فقط به سؤال پاسخ دهید.
49
- اگر جواب دقیق نبود، بگویید: "اطلاعات کافی در متن موجود نیست".
 
 
 
50
 
51
- --- متن:
52
- {context}
53
 
54
- --- سوال:
55
- {question}
56
 
57
- --- پاسخ:
58
- """
59
- combine_prompt_template = """
60
- شما یک دستیار هوشمند هستید. پاسخ نهایی را بر اساس نتایج تیکه‌های مختلف بنویس.
61
- اگر پاسخی در متن نبود، بگویید: "اطلاعات کافی در متن موجود نیست".
62
 
63
- --- نتایج جزئی:
64
- {summaries}
 
 
 
 
65
 
66
- --- سوال:
67
- {question}
68
 
69
- --- پاسخ نهایی:
70
- """
71
 
72
- model = ChatGoogleGenerativeAI(model="gemini-2.5-pro", client=genai, temperature=0.3)
 
 
73
 
74
- map_prompt = PromptTemplate(template=map_prompt_template, input_variables=["context", "question"])
75
- combine_prompt = PromptTemplate(template=combine_prompt_template, input_variables=["summaries", "question"])
76
 
77
- chain = load_qa_chain(
78
- llm=model,
79
- chain_type="map_reduce",
80
- map_prompt=map_prompt,
81
- combine_prompt=combine_prompt
82
  )
83
- return chain
84
 
 
 
 
 
 
 
 
 
 
85
 
 
86
 
87
- # ✅ Clear history
88
- def clear_chat_history():
89
- st.session_state.messages = [{"role": "assistant", "content": "در خدمتیم"}]
 
 
90
 
 
 
91
 
92
- # ✅ Handle user input
93
- def user_input(user_question):
94
- embeddings = GoogleGenerativeAIEmbeddings(model="models/text-embedding-004")
95
- new_db = FAISS.load_local("faiss_index", embeddings, allow_dangerous_deserialization=True)
96
- docs = new_db.similarity_search(user_question, k=8) # ⬅️ بیشتر شده
97
- chain = get_conversational_chain()
98
- response = chain({"input_documents": docs, "question": user_question}, return_only_outputs=True)
99
- return response
100
 
 
 
 
101
 
102
- # Main Streamlit app
103
- def main():
104
- st.set_page_config(page_title="Chatbot", layout="wide", initial_sidebar_state="expanded")
105
 
106
- st.markdown(
107
- """
108
- <style>
109
- body { background-color: #000000; color: #ffffff; }
110
- .main { background-color: #333333; padding: 20px; border-radius: 10px; }
111
- .rtl { direction: rtl; text-align: right; }
112
- </style>
113
- """,
114
- unsafe_allow_html=True
115
- )
116
 
117
- if "uploaded" not in st.session_state:
118
- st.session_state.uploaded = False
119
-
120
- if not st.session_state.uploaded:
121
- # Upload Page
122
- st.title("دستیار شخصی شما ...")
123
- pdf_docs = st.file_uploader("فایل(های) PDF را آپلود کنید", accept_multiple_files=True)
124
- if st.button("تایید"):
125
- if pdf_docs:
126
- st.info("در حال پردازش ...")
127
- raw_text = get_pdf_text(pdf_docs)
128
- text_chunks = get_text_chunks(raw_text)
129
- get_vector_store(text_chunks)
130
- st.session_state.uploaded = True
131
- st.success("پردازش موفق شد ✅")
132
- else:
133
- st.error("لطفاً حداقل یک فایل انتخاب کنید")
134
- else:
135
- # Chat Page
136
- st.title("دستیار آماده است ...")
137
- st.write("سؤالتان را بپرسید 👇")
138
-
139
- if st.button("بازگشت به صفحه آپلود"):
140
- st.session_state.uploaded = False
141
- clear_chat_history()
142
- st.rerun()
143
-
144
- st.button('حذف مکالمه', on_click=clear_chat_history)
145
-
146
- if "messages" not in st.session_state:
147
- st.session_state.messages = [{"role": "assistant", "content": "در خدمتیم"}]
148
-
149
- # Show history
150
- for message in st.session_state.messages:
151
- with st.chat_message(message["role"]):
152
- # تشخیص ساده فارسی برای نمایش راست به چپ
153
- if any("\u0600" <= ch <= "\u06FF" for ch in message["content"]):
154
- st.markdown(f"<div class='rtl'>{message['content']}</div>", unsafe_allow_html=True)
155
- else:
156
- st.write(message["content"])
157
-
158
- if prompt := st.chat_input():
159
- st.session_state.messages.append({"role": "user", "content": prompt})
160
- with st.chat_message("user"):
161
- st.markdown(f"<div class='rtl'>{prompt}</div>", unsafe_allow_html=True) if any(
162
- "\u0600" <= ch <= "\u06FF" for ch in prompt) else st.write(prompt)
163
-
164
- if st.session_state.messages[-1]["role"] != "assistant":
165
- with st.chat_message("assistant"):
166
- response = user_input(prompt)
167
- if response:
168
- full_response = response['output_text']
169
- if any("\u0600" <= ch <= "\u06FF" for ch in full_response):
170
- st.markdown(f"<div class='rtl'>{full_response}</div>", unsafe_allow_html=True)
171
- else:
172
- st.write(full_response)
173
- st.session_state.messages.append({"role": "assistant", "content": full_response})
174
 
 
 
175
 
176
  if __name__ == "__main__":
177
  main()
 
 
 
1
  import streamlit as st
2
+ from PyPDF2 import PdfReader
3
+ from langchain.prompts import PromptTemplate
4
+ from langchain.chains import MapReduceDocumentsChain, ReduceDocumentsChain, StuffDocumentsChain
5
+ from langchain.chains.question_answering import load_qa_chain
6
+ from langchain_google_genai import ChatGoogleGenerativeAI
7
  import google.generativeai as genai
 
 
 
 
 
8
  from langchain_community.vectorstores import FAISS
9
+ from langchain.embeddings import HuggingFaceEmbeddings
10
+ import os
11
+ from dotenv import load_dotenv
12
 
13
+ # --------------------
14
+ # تنظیمات اولیه
15
+ # --------------------
16
  load_dotenv()
17
+ genai.configure(api_key=os.getenv("GOOGLE_API_KEY"))
 
18
 
19
+ st.set_page_config(page_title="چت‌بات اسناد PDF", layout="centered")
20
 
21
+ # --------------------
22
+ # بارگذاری PDF ها
23
+ # --------------------
24
+ def load_pdfs(pdf_files):
25
  text = ""
26
+ for pdf_file in pdf_files:
27
+ pdf_reader = PdfReader(pdf_file)
28
+ for page in pdf_reader.pages:
29
+ text += page.extract_text() or ""
 
 
30
  return text
31
 
32
+ # --------------------
33
+ # ساخت زنجیره پرسش‌و‌پاسخ
34
+ # --------------------
 
 
 
 
 
 
 
 
 
 
 
 
35
  def get_conversational_chain():
36
+ # پرامپت برای هر تیکه (map)
37
+ map_prompt = PromptTemplate(
38
+ input_variables=["context", "question"],
39
+ template="""
40
+ لطفاً بر اساس متن زیر فقط به سؤال پاسخ دهید.
41
+ اگر جواب دقیق نبود، بگویید: "اطلاعات کافی در متن موجود نیست".
42
 
43
+ --- متن:
44
+ {context}
45
 
46
+ --- سوال:
47
+ {question}
48
 
49
+ --- پاسخ:
50
+ """
51
+ )
 
 
52
 
53
+ # پرامپت برای جمع‌بندی (combine)
54
+ combine_prompt = PromptTemplate(
55
+ input_variables=["summaries", "question"],
56
+ template="""
57
+ شما یک دستیار هوشمند هستید. پاسخ نهایی را بر اساس نتایج تیکه‌های مختلف بنویس.
58
+ اگر پاسخی در متن نبود، بگویید: "اطلاعات کافی در متن موجود نیست".
59
 
60
+ --- نتایج جزئی:
61
+ {summaries}
62
 
63
+ --- سوال:
64
+ {question}
65
 
66
+ --- پاسخ نهایی:
67
+ """
68
+ )
69
 
70
+ # مدل Gemini
71
+ model = ChatGoogleGenerativeAI(model="gemini-2.0-pro", temperature=0.3)
72
 
73
+ # chain برای combine (مرحله آخر)
74
+ combine_documents_chain = StuffDocumentsChain(
75
+ llm_chain=load_qa_chain(model, chain_type="stuff", prompt=combine_prompt),
76
+ document_variable_name="summaries"
 
77
  )
 
78
 
79
+ # chain اصلی (map → reduce)
80
+ chain = MapReduceDocumentsChain(
81
+ llm_chain=load_qa_chain(model, chain_type="stuff", prompt=map_prompt),
82
+ reduce_documents_chain=ReduceDocumentsChain(
83
+ combine_documents_chain=combine_documents_chain
84
+ ),
85
+ document_variable_name="context",
86
+ return_intermediate_steps=False,
87
+ )
88
 
89
+ return chain
90
 
91
+ # --------------------
92
+ # اینترفیس استریم‌لیت
93
+ # --------------------
94
+ def main():
95
+ st.title("🤖 چت‌بات PDF با Gemini")
96
 
97
+ # بارگذاری فایل‌ها
98
+ pdf_files = st.file_uploader("📂 فایل‌های PDF خود را بارگذاری کنید", type="pdf", accept_multiple_files=True)
99
 
100
+ if pdf_files:
101
+ text = load_pdfs(pdf_files)
 
 
 
 
 
 
102
 
103
+ if text.strip() == "":
104
+ st.warning("❌ هیچ متنی از PDF استخراج نشد.")
105
+ return
106
 
107
+ # دریافت سؤال کاربر
108
+ question = st.text_input("❓ پرسش خود را وارد کنید:")
 
109
 
110
+ if question:
111
+ with st.spinner("در حال پردازش..."):
112
+ try:
113
+ chain = get_conversational_chain()
114
+ docs = [{"page_content": text}] # کل متن به عنوان یک داکیومنت
115
+
116
+ response = chain.invoke({
117
+ "input_documents": docs,
118
+ "question": question
119
+ })
120
 
121
+ st.markdown(
122
+ f"<div style='direction: rtl; text-align: right; font-size: 16px;'>"
123
+ f"{response['output_text']}</div>",
124
+ unsafe_allow_html=True
125
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
 
127
+ except Exception as e:
128
+ st.error(f"⚠️ خطا: {e}")
129
 
130
  if __name__ == "__main__":
131
  main()