teoo33 commited on
Commit
dc185ff
·
verified ·
1 Parent(s): d9dbd06

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +195 -219
app.py CHANGED
@@ -1,219 +1,195 @@
1
- import os
2
- import google.generativeai as genai
3
- import gradio as gr
4
- from langchain_google_genai import ChatGoogleGenerativeAI, GoogleGenerativeAIEmbeddings
5
- from langchain.prompts import PromptTemplate
6
- from langchain.chains import ConversationalRetrievalChain, LLMChain
7
- from langchain_community.document_loaders import PyPDFLoader
8
- from langchain.text_splitter import RecursiveCharacterTextSplitter
9
- from langchain_community.vectorstores import FAISS
10
- import time
11
- import concurrent.futures
12
- import logging
13
-
14
- # تنظیم لاگ‌گیری
15
- logging.basicConfig(level=logging.INFO,
16
- format="%(asctime)s - %(levelname)s - %(message)s")
17
- logger = logging.getLogger(name)
18
-
19
- # تنظیم API Key از متغیر محیطی
20
- gemini_api_key = os.environ.get('GEMINI_API_KEY')
21
- if not gemini_api_key:
22
- raise ValueError(
23
- "GOOGLE_API_KEY پیدا نشد. لطفاً آن را در تنظیمات Space تنظیم کنید.")
24
- genai.configure(api_key=gemini_api_key)
25
-
26
- # تست اتصال به Gemini
27
- try:
28
- test_model = genai.GenerativeModel('gemini-pro')
29
- test_response = test_model.generate_content("تست ساده")
30
- logger.info(f"تست API Gemini موفق: {test_response.text[:50]}...")
31
- except Exception as e:
32
- logger.error(f"خطا در تست API Gemini: {str(e)}")
33
- raise
34
-
35
- # بقیه توابع بدون تغییر
36
-
37
-
38
- def process_single_pdf(pdf_file):
39
- pdf_path = pdf_file.name if hasattr(pdf_file, 'name') else pdf_file
40
- logger.info(f"شروع پردازش فایل: {pdf_path}")
41
- if not os.path.isfile(pdf_path):
42
- logger.error(f"فایل {pdf_path} وجود ندارد.")
43
- return None
44
- text_splitter = RecursiveCharacterTextSplitter(
45
- chunk_size=800, chunk_overlap=150)
46
- loader = PyPDFLoader(pdf_path)
47
- try:
48
- pages = loader.load_and_split()
49
- docs = text_splitter.split_documents(pages)[:50]
50
- logger.info(f"پردازش فایل: {pdf_path} - تعداد تکه‌ها: {len(docs)}")
51
- return docs
52
- except Exception as e:
53
- logger.error(f"خطا در پردازش {pdf_path}: {str(e)}")
54
- return None
55
-
56
-
57
- def upload_and_process_pdf(pdf_files):
58
- if not pdf_files:
59
- return None, None, "لطفاً حداقل یک فایل PDF آپلود کنید."
60
- logger.info(f"تعداد فایل‌های ورودی: {len(pdf_files)}")
61
- all_docs = []
62
- with concurrent.futures.ThreadPoolExecutor() as executor:
63
- future_to_file = {executor.submit(
64
- process_single_pdf, pdf_file): pdf_file for pdf_file in pdf_files}
65
- for future in concurrent.futures.as_completed(future_to_file):
66
- docs = future.result()
67
- if docs:
68
- all_docs.extend(docs)
69
- else:
70
- pdf_file = future_to_file[future]
71
- return None, None, f"خطا در پردازش فایل: {pdf_file.name if hasattr(pdf_file, 'name') else pdf_file}"
72
- logger.info(f"تعداد کل اسناد پردازش‌شده: {len(all_docs)}")
73
- return None, all_docs, None
74
-
75
-
76
- def create_vector_db(docs):
77
- if not docs:
78
- return None, "هیچ محتوایی پردازش نشد."
79
- embeddings = GoogleGenerativeAIEmbeddings(model="models/embedding-001")
80
- try:
81
- logger.info("شروع ساخت FAISS بدون کش...")
82
- vector_store = FAISS.from_documents(docs, embedding=embeddings)
83
- logger.info(f"پایگاه داده وکتوری با {len(docs)} سند ساخته شد.")
84
- except Exception as e:
85
- logger.error(f"خطا در ایجاد پایگاه داده وکتوری: {str(e)}")
86
- return None, f"خطا در پردازش وکتوری: {str(e)}"
87
- return vector_store, None
88
-
89
-
90
- llm_gemini = ChatGoogleGenerativeAI(
91
- model="gemini-pro", convert_system_message_to_human=True, temperature=0.5)
92
-
93
- academic_analysis_prompt_template = """شما یک تحلیلگر آکادمیک حرفه‌ای و متخصص در بررسی پایان‌نامه‌های علمی هستید. وظیفه شما ارائه تحلیلی عمیق، دقیق و ساختارمند بر اساس محتوای ارائه‌شده است. پاسخ شما باید:
94
- 1. صرفاً بر اساس اطلاعات موجود در متن‌های مرتبط باشد.
95
- 2. شامل مرور موضوع اصلی، روش‌شناسی، یافته‌ها و نکات قابل انتقاد (در صورت وجود) باشد.
96
- 3. با زبانی رسمی و آکادمیک به {language} نوشته شود.
97
- 4. سطح جزئیات پاسخ {detail_level} باشد.
98
- 5. در صورت امکان، پیشنهادهایی برای بهبود یا تحقیقات آینده ارائه دهد.
99
-
100
- متن‌های مرتبط:
101
- {context}
102
-
103
- سوال کاربر: {question}
104
-
105
- تحلیل آکادمیک:
106
- """
107
- ACADEMIC_ANALYSIS_PROMPT = PromptTemplate(template=academic_analysis_prompt_template, input_variables=[
108
- "context", "question", "language", "detail_level"])
109
-
110
- general_qa_prompt_template = """شما یک دستیار هوشمند هستید. به سوالات کاربر به‌طور دقیق و به زبان {language} پاسخ دهید.
111
-
112
- سوال کاربر: {question}
113
-
114
- پاسخ:"""
115
- GENERAL_QA_PROMPT = PromptTemplate(
116
- template=general_qa_prompt_template, input_variables=["question", "language"])
117
-
118
-
119
- def create_conversation_chain(vector_store, docs, answer_source, language, detail_level):
120
- logger.info(f"ایجاد زنجیره - منبع: {answer_source}")
121
- if answer_source == "تحلیل آکادمیک پایان‌نامه (RAG)":
122
- retriever = vector_store.as_retriever(search_kwargs={"k": 3})
123
- logger.info("Retriever ساخته شد.")
124
- academic_chain = ConversationalRetrievalChain.from_llm(
125
- llm=llm_gemini,
126
- retriever=retriever,
127
- return_source_documents=True,
128
- combine_docs_chain_kwargs={"prompt": ACADEMIC_ANALYSIS_PROMPT.partial(
129
- language=language, detail_level=detail_level)},
130
- verbose=True
131
- )
132
- logger.info("زنجیره RAG ساخته شد.")
133
- return academic_chain
134
- else:
135
- general_chain = LLMChain(
136
- llm=llm_gemini, prompt=GENERAL_QA_PROMPT.partial(language=language))
137
- logger.info("زنجیره استاندارد ساخته شد.")
138
- return general_chain
139
-
140
-
141
- def academic_chatbot(pdf_file, answer_source, query, language, detail_level):
142
- start_time = time.time()
143
- logger.info(f"شروع پردازش - منبع: {answer_source}, سوال: {
144
- query}, زبان: {language}, جزئیات: {detail_level}")
145
-
146
- if len(query) > 500:
147
- return "❌ سوال شما بیش از حد طولانی است (حداکثر 500 کاراکتر)."
148
-
149
- if answer_source == "پاسخ استاندارد Gemini":
150
- logger.info("شروع پردازش استاندارد...")
151
- general_chain = create_conversation_chain(
152
- None, None, answer_source, language, detail_level)
153
- try:
154
- result = general_chain.invoke({"question": query})["text"]
155
- logger.info(f"پاسخ استاندارد تولید شد: {result[:50]}...")
156
- return f"{result}\n\n⏱ زمان پردازش: {time.time() - start_time:.2f} ثانیه"
157
- except Exception as e:
158
- logger.error(f"خطا در پردازش استاندارد: {str(e)}")
159
- return f"خطا در پردازش استاندارد: {str(e)}"
160
-
161
- logger.info("شروع پردازش RAG...")
162
- if not pdf_file:
163
- logger.error("هیچ فایلی آپلود نشده است.")
164
- return "لطفاً یک فایل PDF آپلود کنید."
165
-
166
- pdf_files = pdf_file if isinstance(pdf_file, list) else [pdf_file]
167
- logger.info(f"فایل‌های دریافت‌شده: {
168
- [f.name if hasattr(f, 'name') else f for f in pdf_files]}")
169
-
170
- for f in pdf_files:
171
- pdf_path = f.name if hasattr(f, 'name') else f
172
- if not os.path.isfile(pdf_path):
173
- logger.error(f"فایل {pdf_path} پیدا نشد.")
174
- return f"فایل {pdf_path} پیدا نشد. لطفاً مطمئن شوید که فایل به درستی آپلود شده است."
175
-
176
- pdf_path, docs, pdf_error = upload_and_process_pdf(pdf_files)
177
- if pdf_error:
178
- logger.error(f"خطای پردازش PDF: {pdf_error}")
179
- return pdf_error
180
-
181
- logger.info("ساخت پایگاه داده وکتوری...")
182
- vector_store, vectordb_error = create_vector_db(docs)
183
- if vectordb_error:
184
- logger.error(f"خطای Vector DB: {vectordb_error}")
185
- return vectordb_error
186
-
187
- logger.info("ایجاد زنجیره RAG...")
188
- academic_chain = create_conversation_chain(
189
- vector_store, docs, answer_source, language, detail_level)
190
- logger.info("فراخوانی زنجیره RAG...")
191
- try:
192
- result = academic_chain({"question": query, "chat_history": []})
193
- answer = result["answer"]
194
- logger.info(f"تحلیل آکادمیک تولید شد: {answer[:50]}...")
195
- return f"{answer}\n\n⏱ زمان پردازش: {time.time() - start_time:.2f} ثانیه"
196
- except Exception as e:
197
- logger.error(f"خطا در پردازش RAG: {str(e)}")
198
- return f"خطا در پردازش RAG: {str(e)}"
199
-
200
-
201
- iface = gr.Interface(
202
- fn=academic_chatbot,
203
- inputs=[
204
- gr.File(file_types=[
205
- '.pdf'], label="فایل‌های PDF پایان‌نامه را آپلود کنید", file_count="multiple"),
206
- gr.Radio(["تحلیل آکادمیک پایان‌نامه (RAG)", "پاسخ استاندارد Gemini"],
207
- label="نوع پاسخ", value="تحلیل آکادمیک پایان‌نامه (RAG)"),
208
- gr.Textbox(
209
- lines=3, placeholder="سوال یا درخواست تحل��ل خود را بنویسید...", label="سوال/تحلیل"),
210
- gr.Dropdown(["فارسی", "English"], label="زبان پاسخ", value="فارسی"),
211
- gr.Dropdown(["خلاصه", "جامع"], label="سطح جزئیات", value="جامع")
212
- ],
213
- outputs=[gr.Textbox(label="تحلیل یا پاسخ:")],
214
- title="تحلیلگر حرفه‌ای پایان‌نامه با Gemini",
215
- description="فایل‌های PDF پایان‌نامه خود را آپلود کنید و تحلیل آکادمیک یا پاسخ عمومی دریافت کنید."
216
- )
217
-
218
- if name == "main":
219
- iface.launch()
 
1
+ import os
2
+ import google.generativeai as genai
3
+ import gradio as gr
4
+ from langchain_google_genai import ChatGoogleGenerativeAI, GoogleGenerativeAIEmbeddings
5
+ from langchain.prompts import PromptTemplate
6
+ from langchain.chains import ConversationalRetrievalChain, LLMChain
7
+ from langchain_community.document_loaders import PyPDFLoader
8
+ from langchain.text_splitter import RecursiveCharacterTextSplitter
9
+ from langchain_community.vectorstores import FAISS
10
+ import time
11
+ import concurrent.futures
12
+ import logging
13
+
14
+ # تنظیم لاگ‌گیری
15
+ logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
16
+ logger = logging.getLogger(__name__)
17
+
18
+ # تنظیم API Key از متغیر محیطی
19
+ gemini_api_key = os.environ.get('GEMINI_API_KEY')
20
+ if not gemini_api_key:
21
+ raise ValueError("GOOGLE_API_KEY پیدا نشد. لطفاً آن را در تنظیمات Space تنظیم کنید.")
22
+ genai.configure(api_key=gemini_api_key)
23
+
24
+ # تست اتصال به Gemini
25
+ try:
26
+ test_model = genai.GenerativeModel('gemini-pro')
27
+ test_response = test_model.generate_content("تست ساده")
28
+ logger.info(f"تست API Gemini موفق: {test_response.text[:50]}...")
29
+ except Exception as e:
30
+ logger.error(f"خطا در تست API Gemini: {str(e)}")
31
+ raise
32
+
33
+ def process_single_pdf(pdf_file):
34
+ pdf_path = pdf_file.name if hasattr(pdf_file, 'name') else pdf_file
35
+ logger.info(f"شروع پردازش فایل: {pdf_path}")
36
+ if not os.path.isfile(pdf_path):
37
+ logger.error(f"فایل {pdf_path} وجود ندارد.")
38
+ return None
39
+ text_splitter = RecursiveCharacterTextSplitter(chunk_size=800, chunk_overlap=150)
40
+ loader = PyPDFLoader(pdf_path)
41
+ try:
42
+ pages = loader.load_and_split()
43
+ docs = text_splitter.split_documents(pages)[:50]
44
+ logger.info(f"پردازش فایل: {pdf_path} - تعداد تکه‌ها: {len(docs)}")
45
+ return docs
46
+ except Exception as e:
47
+ logger.error(f"خطا در پردازش {pdf_path}: {str(e)}")
48
+ return None
49
+
50
+ def upload_and_process_pdf(pdf_files):
51
+ if not pdf_files:
52
+ return None, None, "لطفاً حداقل یک فایل PDF آپلود کنید."
53
+ logger.info(f"تعداد فایل‌های ورودی: {len(pdf_files)}")
54
+ all_docs = []
55
+ with concurrent.futures.ThreadPoolExecutor() as executor:
56
+ future_to_file = {executor.submit(process_single_pdf, pdf_file): pdf_file for pdf_file in pdf_files}
57
+ for future in concurrent.futures.as_completed(future_to_file):
58
+ docs = future.result()
59
+ if docs:
60
+ all_docs.extend(docs)
61
+ else:
62
+ pdf_file = future_to_file[future]
63
+ return None, None, f"خطا در پردازش فایل: {pdf_file.name if hasattr(pdf_file, 'name') else pdf_file}"
64
+ logger.info(f"تعداد کل اسناد پردازش‌شده: {len(all_docs)}")
65
+ return None, all_docs, None
66
+
67
+ def create_vector_db(docs):
68
+ if not docs:
69
+ return None, "هیچ محتوایی پردازش نشد."
70
+ embeddings = GoogleGenerativeAIEmbeddings(model="models/embedding-001")
71
+ try:
72
+ logger.info("شروع ساخت FAISS بدون کش...")
73
+ vector_store = FAISS.from_documents(docs, embedding=embeddings)
74
+ logger.info(f"پایگاه داده وکتوری با {len(docs)} سند ساخته شد.")
75
+ except Exception as e:
76
+ logger.error(f"خطا در ایجاد پایگاه داده وکتوری: {str(e)}")
77
+ return None, f"خطا در پردازش وکتوری: {str(e)}"
78
+ return vector_store, None
79
+
80
+ llm_gemini = ChatGoogleGenerativeAI(model="gemini-pro", convert_system_message_to_human=True, temperature=0.5)
81
+
82
+ academic_analysis_prompt_template = """شما یک تحلیلگر آکادمیک حرفه‌ای و متخصص در بررسی پایان‌نامه‌های علمی هستید. وظیفه شما ارائه تحلیلی عمیق، دقیق و ساختارمند بر اساس محتوای ارائه‌شده است. پاسخ شما باید:
83
+ 1. صرفاً بر اساس اطلاعات موجود در متن‌های مرتبط باشد.
84
+ 2. شامل مرور موضوع اصلی، روش‌شناسی، یافته‌ها و نکات قابل انتقاد (در صورت وجود) باشد.
85
+ 3. با زبانی رسمی و آکادمیک به {language} نوشته شود.
86
+ 4. سطح جزئیات پاسخ {detail_level} باشد.
87
+ 5. در صورت امکان، پیشنهادهایی برای بهبود یا تحقیقات آینده ارائه دهد.
88
+
89
+ **متن‌های مرتبط:**
90
+ {context}
91
+
92
+ **سوال کاربر:** {question}
93
+
94
+ **تحلیل آکادمیک:**
95
+ """
96
+ ACADEMIC_ANALYSIS_PROMPT = PromptTemplate(template=academic_analysis_prompt_template, input_variables=["context", "question", "language", "detail_level"])
97
+
98
+ general_qa_prompt_template = """شما یک دستیار هوشمند هستید. به سوالات کاربر به‌طور دقیق و به زبان {language} پاسخ دهید.
99
+
100
+ **سوال کاربر:** {question}
101
+
102
+ پاسخ:"""
103
+ GENERAL_QA_PROMPT = PromptTemplate(template=general_qa_prompt_template, input_variables=["question", "language"])
104
+
105
+ def create_conversation_chain(vector_store, docs, answer_source, language, detail_level):
106
+ logger.info(f"ایجاد زنجیره - منبع: {answer_source}")
107
+ if answer_source == "تحلیل آکادمیک پایان‌نامه (RAG)":
108
+ retriever = vector_store.as_retriever(search_kwargs={"k": 3})
109
+ logger.info("Retriever ساخته شد.")
110
+ academic_chain = ConversationalRetrievalChain.from_llm(
111
+ llm=llm_gemini,
112
+ retriever=retriever,
113
+ return_source_documents=True,
114
+ combine_docs_chain_kwargs={"prompt": ACADEMIC_ANALYSIS_PROMPT.partial(language=language, detail_level=detail_level)},
115
+ verbose=True
116
+ )
117
+ logger.info("زنجیره RAG ساخته شد.")
118
+ return academic_chain
119
+ else:
120
+ general_chain = LLMChain(llm=llm_gemini, prompt=GENERAL_QA_PROMPT.partial(language=language))
121
+ logger.info("زنجیره استاندارد ساخته شد.")
122
+ return general_chain
123
+
124
+ def academic_chatbot(pdf_file, answer_source, query, language, detail_level):
125
+ start_time = time.time()
126
+ # خط اصلاح‌شده
127
+ logger.info(f"شروع پردازش - منبع: {answer_source}, سوال: {query}, زبان: {language}, جزئیات: {detail_level}")
128
+
129
+ if len(query) > 500:
130
+ return "❌ سوال شما بیش از حد طولانی است (حداکثر 500 کاراکتر)."
131
+
132
+ if answer_source == "پاسخ استاندارد Gemini":
133
+ logger.info("شروع پردازش استاندارد...")
134
+ general_chain = create_conversation_chain(None, None, answer_source, language, detail_level)
135
+ try:
136
+ result = general_chain.invoke({"question": query})["text"]
137
+ logger.info(f"پاسخ استاندارد تولید شد: {result[:50]}...")
138
+ return f"{result}\n\n⏱ زمان پردازش: {time.time() - start_time:.2f} ثانیه"
139
+ except Exception as e:
140
+ logger.error(f"خطا در پردازش استاندارد: {str(e)}")
141
+ return f"خطا در پردازش استاندارد: {str(e)}"
142
+
143
+ logger.info("شروع پردازش RAG...")
144
+ if not pdf_file:
145
+ logger.error("هیچ فایلی آپلود نشده است.")
146
+ return "لطفاً یک فایل PDF آپلود کنید."
147
+
148
+ pdf_files = pdf_file if isinstance(pdf_file, list) else [pdf_file]
149
+ logger.info(f"فایل‌های دریافت‌شده: {[f.name if hasattr(f, 'name') else f for f in pdf_files]}")
150
+
151
+ for f in pdf_files:
152
+ pdf_path = f.name if hasattr(f, 'name') else f
153
+ if not os.path.isfile(pdf_path):
154
+ logger.error(f"فایل {pdf_path} پیدا نشد.")
155
+ return f"فایل {pdf_path} پیدا نشد. لطفاً مطمئن شوید که فایل به درستی آپلود شده است."
156
+
157
+ pdf_path, docs, pdf_error = upload_and_process_pdf(pdf_files)
158
+ if pdf_error:
159
+ logger.error(f"خطای پردازش PDF: {pdf_error}")
160
+ return pdf_error
161
+
162
+ logger.info("ساخت پایگاه داده وکتوری...")
163
+ vector_store, vectordb_error = create_vector_db(docs)
164
+ if vectordb_error:
165
+ logger.error(f"خطای Vector DB: {vectordb_error}")
166
+ return vectordb_error
167
+
168
+ logger.info("ایجاد زنجیره RAG...")
169
+ academic_chain = create_conversation_chain(vector_store, docs, answer_source, language, detail_level)
170
+ logger.info("فراخوانی زنجیره RAG...")
171
+ try:
172
+ result = academic_chain({"question": query, "chat_history": []})
173
+ answer = result["answer"]
174
+ logger.info(f"تحلیل آکادمیک تولید شد: {answer[:50]}...")
175
+ return f"{answer}\n\n⏱ زمان پردازش: {time.time() - start_time:.2f} ثانیه"
176
+ except Exception as e:
177
+ logger.error(f"خطا در پردازش RAG: {str(e)}")
178
+ return f"خطا در پردازش RAG: {str(e)}"
179
+
180
+ iface = gr.Interface(
181
+ fn=academic_chatbot,
182
+ inputs=[
183
+ gr.File(file_types=['.pdf'], label="فایل‌های PDF پایان‌نامه را آپلود کنید", file_count="multiple"),
184
+ gr.Radio(["تحلیل آکادمیک پایان‌نامه (RAG)", "پاسخ استاندار�� Gemini"], label="نوع پاسخ", value="تحلیل آکادمیک پایان‌نامه (RAG)"),
185
+ gr.Textbox(lines=3, placeholder="سوال یا درخواست تحلیل خود را بنویسید...", label="سوال/تحلیل"),
186
+ gr.Dropdown(["فارسی", "English"], label="زبان پاسخ", value="فارسی"),
187
+ gr.Dropdown(["خلاصه", "جامع"], label="سطح جزئیات", value="جامع")
188
+ ],
189
+ outputs=[gr.Textbox(label="تحلیل یا پاسخ:")],
190
+ title="تحلیلگر حرفه‌ای پایان‌نامه با Gemini",
191
+ description="فایل‌های PDF پایان‌نامه خود را آپلود کنید و تحلیل آکادمیک یا پاسخ عمومی دریافت کنید."
192
+ )
193
+
194
+ if __name__ == "__main__":
195
+ iface.launch()