import os import shutil import logging import gradio as gr from langchain_community.document_loaders import PyPDFLoader # تغییر به PyPDFLoader from langchain_community.embeddings import OpenAIEmbeddings from langchain_community.vectorstores import FAISS from langchain_community.chat_models import ChatOpenAI # تنظیمات لاگ‌گیری logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # تنظیمات مسیرها UPLOAD_FOLDER = "uploaded_files" DATABASE_FILE = "/home/user/app/vector_database" # بدون پسوند .pkl os.makedirs(UPLOAD_FOLDER, exist_ok=True) # بررسی و بارگذاری دیتابیس برداری def load_database(): try: if os.path.exists(DATABASE_FILE): embeddings = OpenAIEmbeddings(openai_api_key=os.getenv("My_huggingface_key")) vector_db = FAISS.load_local(DATABASE_FILE, embeddings) logger.info(f"✅ دیتابیس بارگذاری شد: {DATABASE_FILE}") return vector_db else: logger.warning(f"❌ دیتابیس در مسیر `{DATABASE_FILE}` وجود ندارد.") return None except Exception as e: logger.error(f"❌ خطا در بارگذاری دیتابیس: {e}") return None def save_database(vector_db): try: vector_db.save_local(DATABASE_FILE) logger.info(f"✅ دیتابیس ذخیره شد: {DATABASE_FILE}") except Exception as e: logger.error(f"❌ خطا در ذخیره دیتابیس: {e}") raise e global_vector_db = load_database() # پردازش و ذخیره‌سازی فایل‌های PDF def process_and_store_pdfs(file_paths): texts = [] for file_path in file_paths: try: logger.info(f"در حال پردازش فایل: {file_path}") if file_path.endswith(".pdf"): # استفاده از PyPDFLoader به جای PDFMinerLoader loader = PyPDFLoader(file_path) documents = loader.load() texts.extend(documents) logger.info(f"✅ تعداد صفحات پردازش شده: {len(documents)}") else: logger.warning(f"فرمت فایل {file_path} پشتیبانی نمی‌شود.") except Exception as e: logger.error(f"خطا در پردازش فایل {file_path}: {e}") try: logger.info("در حال ایجاد embeddings و ذخیره‌سازی در FAISS...") openai_api_key = os.getenv("My_huggingface_key") if not openai_api_key: logger.error("❌ کلید API مقداردهی نشده است!") raise ValueError("❌ کلید OpenAI API یافت نشد.") embeddings = OpenAIEmbeddings(openai_api_key=openai_api_key) vector_db = FAISS.from_documents(texts, embeddings) logger.info(f"✅ ذخیره‌سازی در FAISS با موفقیت انجام شد. تعداد اسناد: {vector_db.index.ntotal}") return vector_db except Exception as e: logger.error(f"خطا در ایجاد embeddings یا ذخیره‌سازی در FAISS: {e}") return None # پاسخ‌گویی بر اساس اسناد بارگذاری‌شده def chat_with_doc(query): try: global global_vector_db if not global_vector_db: return "❌ لطفاً یک فایل مرتبط آپلود کنید." if not query.strip(): return "❌ لطفاً سوال خود را وارد کنید." # بازیابی اسناد مرتبط retriever = global_vector_db.as_retriever(search_kwargs={"k": 5}) docs = retriever.get_relevant_documents(query) # لاگ‌گیری برای بررسی اسناد بازیابی شده logger.info(f"تعداد اسناد بازیابی شده: {len(docs)}") for doc in docs: logger.info(f"سند بازیابی شده: {doc.page_content[:100]}...") # نمایش بخشی از متن سند context = "\n\n".join([doc.page_content for doc in docs]) if not context: return "هیچ اطلاعات مرتبطی یافت نشد." # استفاده از مدل gpt-3.5-turbo به جای gpt-4 (در صورت عدم دسترسی به GPT-4) llm = ChatOpenAI(model_name="gpt-3.5-turbo", openai_api_key=os.getenv("My_huggingface_key")) # ساختار درخواست ساده‌تر prompt = f"""سوال: {query}\n\nاطلاعات مرتبط:\n{context}\n\nلطفاً به سوال پاسخ دهید:""" response = llm.predict(prompt) final_response = f"پاسخ:\n{response}\n\nمنابع:\n" for doc in docs: final_response += f"- {doc.metadata.get('source', 'نامشخص')}, صفحه {doc.metadata.get('page', 'نامشخص')}\n" return final_response except Exception as e: logger.error(f"خطا در پاسخ‌گویی بر اساس سند: {e}") return f"❌ خطایی رخ داده است: {e}" # ذخیره فایل آپلود شده def save_uploaded_file(file): try: file_name = os.path.basename(file) file_path = os.path.join(UPLOAD_FOLDER, file_name) shutil.copy(file, file_path) global global_vector_db global_vector_db = process_and_store_pdfs([file_path]) if global_vector_db: save_database(global_vector_db) return f"✅ فایل ذخیره شد: {file_path}" except Exception as e: return f"❌ خطا در ذخیره فایل: {e}" # دباگ موقت def debug_temp(): debug_results = [] # بررسی مقدار کلید API openai_api_key = os.getenv("My_huggingface_key") if openai_api_key: debug_results.append(f"✅ کلید API مقداردهی شده: {openai_api_key[:5]}********") else: debug_results.append("❌ کلید API مقداردهی نشده است!") # بررسی نسخه langchain_community try: import langchain_community version = langchain_community.__version__ debug_results.append(f"✅ نسخه langchain_community: {version}") except Exception as e: debug_results.append(f"❌ خطا در بررسی نسخه langchain_community: {e}") # بررسی فایل‌های PDF در مسیر آپلود try: pdf_files = [f for f in os.listdir(UPLOAD_FOLDER) if f.endswith(".pdf")] if pdf_files: file_paths = [os.path.join(UPLOAD_FOLDER, f) for f in pdf_files] debug_results.append(f"✅ فایل‌های PDF در مسیر `{UPLOAD_FOLDER}`:") # بررسی تعداد صفحات هر فایل for file_path in file_paths: try: loader = PyPDFLoader(file_path) # استفاده از PyPDFLoader documents = loader.load() debug_results.append(f" - {os.path.basename(file_path)}: {len(documents)} صفحه") except Exception as e: debug_results.append(f"❌ خطا در بررسی صفحات {file_path}: {str(e)}") else: debug_results.append(f"❌ هیچ فایل PDF در مسیر `{UPLOAD_FOLDER}` وجود ندارد.") except Exception as e: debug_results.append(f"❌ خطا در بررسی پوشه `{UPLOAD_FOLDER}`: {e}") # بررسی وضعیت دیتابیس try: if os.path.exists(DATABASE_FILE): debug_results.append(f"✅ دیتابیس در مسیر `{DATABASE_FILE}` وجود دارد.") # بررسی تعداد اسناد ذخیره شده if global_vector_db: debug_results.append(f" - تعداد اسناد در دیتابیس: {global_vector_db.index.ntotal}") else: debug_results.append("❌ دیتابیس در حافظه بارگذاری نشده است") else: debug_results.append(f"❌ دیتابیس در مسیر `{DATABASE_FILE}` وجود ندارد.") except Exception as e: debug_results.append(f"❌ خطا در بررسی دیتابیس: {e}") return "\n".join(debug_results) # رابط کاربری با Gradio with gr.Blocks() as demo: gr.Markdown("# هوش مصنوعی همراه کارشناسان توزیع برق ایران") query = gr.Textbox(label="سوال خود را بپرسید", lines=2) response = gr.Textbox(label="پاسخ", lines=10, interactive=False) submit_btn = gr.Button("ارسال سوال") file = gr.File(label="📎 آپلود فایل", file_types=[".pdf"]) upload_status = gr.Textbox(label="وضعیت آپلود", interactive=False) upload_btn = gr.Button("ارسال فایل") debug_btn = gr.Button("🔍 بررسی دباگ موقت") debug_output = gr.Textbox(label="نتایج دباگ", lines=10, interactive=False) upload_btn.click(save_uploaded_file, inputs=[file], outputs=[upload_status]) submit_btn.click(chat_with_doc, inputs=[query], outputs=[response]) debug_btn.click(debug_temp, outputs=debug_output) demo.launch()