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

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +219 -0
  2. requirements.txt +10 -0
app.py ADDED
@@ -0,0 +1,219 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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()
requirements.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ gradio
2
+ langchain
3
+ langchain-community
4
+ pypdf
5
+ pypdf2
6
+ sentence-transformers
7
+ faiss-cpu
8
+ google-generativeai
9
+ langchain-google-genai
10
+ rank_bm25