File size: 6,829 Bytes
12304e1 f43073f 12304e1 f43073f 12304e1 3b0947d 12304e1 f43073f 12304e1 3b0947d f43073f e59f4bc 12304e1 f43073f 12304e1 f43073f 9b8da68 f43073f 12304e1 3b0947d 12304e1 3b0947d e59f4bc 3b0947d e59f4bc 3b0947d 12304e1 f43073f 12304e1 f43073f 12304e1 f43073f 12304e1 e59f4bc f43073f 12304e1 f43073f 12304e1 f43073f 12304e1 f43073f 12304e1 f43073f 12304e1 f43073f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | import os
import streamlit as st
import tempfile
from langchain_community.document_loaders import PyPDFLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import FAISS
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.llms import HuggingFaceHub
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate
# 1. إعدادات الصفحة ودعم الواجهة العربية (RTL)
st.set_page_config(page_title="مساعد الملفات الذكي المجاني", page_icon="🤖", layout="centered")
st.markdown("""
<style>
body, .main, .block-container, div[data-testid="stChatMessage"] {
direction: RTL;
text-align: right;
}
.stAlert {
direction: RTL;
text-align: right;
}
</style>
""", unsafe_allow_html=True)
st.title("🤖 مساعد المستندات الذكي المجاني (RAG App)")
st.subheader("ارفع ملفاتك واسألها مجاناً بالكامل عبر السحابة")
# زر جانبي لتنظيف الذاكرة في حال حدوث أي تداخل حسابي في المصفوفات
if st.sidebar.button("🔄 إعادة تهيئة التطبيق وتنظيف الذاكرة"):
st.session_state.chat_history = []
st.session_state.vector_store = None
st.rerun()
# 2. التحقق من وجود مفتاح Hugging Face
if "HF_TOKEN" not in os.environ:
st.error("⚠️ لم يتم العثور على مفتاح 'HF_TOKEN' في الإعدادات السحابية (Secrets) الخاصة بـ Space.")
st.stop()
# 3. تهيئة الذاكرة السحابية المؤقتة للمحادثة وقاعدة المتجهات
if "chat_history" not in st.session_state:
st.session_state.chat_history = []
if "vector_store" not in st.session_state:
st.session_state.vector_store = None
# 4. واجهة رفع ومعالجة الملفات سحابياً
uploaded_file = st.file_uploader("اختر ملف PDF لبدء المعالجة", type=["pdf"])
if uploaded_file and st.session_state.vector_store is None:
with st.spinner("جاري معالجة وتحليل الملف سحابياً عبر النماذج المجانية..."):
try:
# استخدام مسار مؤقت آمن لتفادي Permission Denied
with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as temp_file:
temp_file.write(uploaded_file.getbuffer())
temp_file_path = temp_file.name
loader = PyPDFLoader(temp_file_path)
docs = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
final_documents = text_splitter.split_documents(docs)
# 💡 تعديل أمني: تهيئة النموذج بخصائص تضمن توافق الأبعاد الحسابية للمتجهات ومنع تضارب الذاكرة
encode_kwargs = {'normalize_embeddings': True}
embeddings = HuggingFaceEmbeddings(
model_name="Alibaba-NLP/gte-multilingual-base",
model_kwargs={"trust_remote_code": True},
encode_kwargs=encode_kwargs
)
# بناء قاعدة البيانات مباشرة مع المتجهات المحدثة
st.session_state.vector_store = FAISS.from_documents(final_documents, embeddings)
if os.path.exists(temp_file_path):
os.remove(temp_file_path)
st.success("✅ تم تحليل المستند وبناء قاعدة البيانات المجانية بنجاح!")
except Exception as e:
st.error(f"❌ حدث خطأ أثناء معالجة الملف: {str(e)}")
# 5. نظام الاستعلام والـ RAG المجاني
if st.session_state.vector_store is not None:
for message in st.session_state.chat_history:
with st.chat_message(message["role"]):
st.write(message["content"])
user_query = st.chat_input("اسأل أي شيء حول المستند...")
if user_query:
with st.chat_message("user"):
st.write(user_query)
st.session_state.chat_history.append({"role": "user", "content": user_query})
with st.spinner("جاري استخراج الإجابة الذكية مجاناً..."):
try:
# استدعاء نموذج محادثة (Qwen-2.5) مجاناً بالكامل
llm = HuggingFaceHub(
repo_id="Qwen/Qwen2.5-7B-Instruct",
model_kwargs={"temperature": 0.1, "max_new_tokens": 512},
huggingfacehub_api_token=os.environ["HF_TOKEN"]
)
retriever = st.session_state.vector_store.as_retriever(search_kwargs={"k": 3})
system_prompt = (
"<|im_start|>system\n"
"أنت مساعد ذكي متخصص في الإجابة على الأسئلة بناءً على المستندات المرفقة فقط.\n"
"استخدم السياق التالي بدقة للإجابة على سؤال المستخدم باللغة العربية. إذا لم تجد الإجابة، قل لا أعرف ولطفاً لا تبتكر.\n\n"
"السياق:\n{context}<|im_end|>\n"
"<|im_start|>user\n{input}<|im_end|>\n"
"<|im_start|>assistant\n"
)
prompt = ChatPromptTemplate.from_messages([
("text", system_prompt)
])
question_answer_chain = create_stuff_documents_chain(llm, prompt)
rag_chain = create_retrieval_chain(retriever, question_answer_chain)
response = rag_chain.invoke({"input": user_query})
answer = response["answer"].split("<|im_start|>assistant\n")[-1].replace("<|im_end|>", "").strip()
with st.chat_message("assistant"):
st.write(answer)
st.session_state.chat_history.append({"role": "assistant", "content": answer})
except Exception as e:
st.error(f"⚠️ عذراً، حدث خطأ أثناء معالجة الطلب: {str(e)}")
else:
if not uploaded_file:
st.info("💡 يرجى رفع ملف PDF من الأعلى لتتمكن من البدء في طرح الأسئلة مجاناً.")
|