import os import streamlit as st from dotenv import load_dotenv import PyPDF2 import numpy as np from openai import OpenAI import openai # لا نستورد error مباشرة # Load environment load_dotenv() OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") st.set_page_config( page_title="📚 المكتبة المريدية الذكية", page_icon="🚀", layout="wide" ) # RTL + Styling st.markdown(""" """, unsafe_allow_html=True) # Sidebar with st.sidebar: st.header("⚙️ الإعدادات / Settings") language = st.radio("اختر اللغة / Choose Language / Choisir la langue:", ["العربية", "English", "Français"]) temperature = st.slider("Creativity / الإبداع", 0.0, 1.0, 0.2) st.markdown("---") st.info("قم برفع ملفات PDF الخاصة بك وابدأ بالبحث") # PDF Upload uploaded_files = st.file_uploader("📄 Upload PDF(s) / رفع ملفات PDF", type="pdf", accept_multiple_files=True) # Simple VectorStore class SimpleVectorStore: def __init__(self): self.embeddings = [] self.documents = [] def add_document(self, content, embedding): self.documents.append(content) self.embeddings.append(embedding) def query(self, query_embedding, top_k=4): if not self.embeddings: return [] sims = np.dot(np.array(self.embeddings), query_embedding) top_indices = sims.argsort()[-top_k:][::-1] return [self.documents[i] for i in top_indices] # Extract text def extract_text_from_pdf(file): reader = PyPDF2.PdfReader(file) text = "" for page in reader.pages: text += page.extract_text() + "\n" return text # Build VectorStore @st.cache_resource def build_vectorstore(files): vectorstore = SimpleVectorStore() client = OpenAI(api_key=OPENAI_API_KEY) for file in files: text = extract_text_from_pdf(file) chunks = [text[i:i+1000] for i in range(0, len(text), 1000)] for chunk in chunks: try: embedding = client.embeddings.create( input=chunk, model="text-embedding-3-small" )['data'][0]['embedding'] vectorstore.add_document(chunk, np.array(embedding)) except Exception as e: # بديل عن RateLimitError st.warning(f"⚠️ بعض المستندات لم تُعالج: {str(e)}") return vectorstore # Chat Memory if "messages" not in st.session_state: st.session_state.messages = [] # Main Logic if uploaded_files: vectorstore = build_vectorstore(uploaded_files) client = OpenAI(api_key=OPENAI_API_KEY) for msg in st.session_state.messages: with st.chat_message(msg["role"]): st.markdown(msg["content"]) if prompt := st.chat_input("اكتب سؤالك هنا / Type your question:"): st.session_state.messages.append({"role": "user", "content": prompt}) with st.chat_message("user"): st.markdown(prompt) with st.chat_message("assistant"): with st.spinner("🤖 جاري معالجة السؤال..."): try: query_embedding = client.embeddings.create( input=prompt, model="text-embedding-3-small" )['data'][0]['embedding'] top_docs = vectorstore.query(np.array(query_embedding), top_k=4) context = "\n\n".join(top_docs) response = client.chat.completions.create( model="gpt-4o-mini", messages=[ {"role": "system", "content": "أنت مساعد بحثي."}, {"role": "user", "content": f"استعن بالنصوص التالية للإجابة:\n{context}\n\nسؤال: {prompt}"} ], temperature=temperature ) answer = response.choices[0].message.content st.markdown(answer) with st.expander("📚 المصادر / Sources"): for i, doc in enumerate(top_docs): st.write(f"المصدر {i+1}: {doc[:500]}...") st.session_state.messages.append({"role": "assistant", "content": answer}) except Exception as e: st.error(f"⚠️ حدث خطأ أثناء الاتصال بـ OpenAI: {str(e)}") else: st.warning("📂 الرجاء رفع ملف PDF واحد على الأقل للبدء.")