File size: 5,059 Bytes
936d254
c259257
c9a21eb
59be948
282d1fe
3bc7125
 
c259257
546bec9
c9a21eb
 
 
c259257
546bec9
5a0beb1
c9a21eb
c259257
 
3bc7125
287c85c
c9a21eb
546bec9
 
975a47e
546bec9
 
 
c9a21eb
287c85c
c259257
3bc7125
c9a21eb
546bec9
 
 
c9a21eb
546bec9
c5f63ef
5a0beb1
3bc7125
c9a21eb
282d1fe
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3bc7125
59be948
282d1fe
59be948
282d1fe
59be948
 
 
3bc7125
c9a21eb
c5f63ef
282d1fe
546bec9
c5f63ef
59be948
282d1fe
 
546bec9
 
 
 
 
 
3bc7125
 
c5f63ef
 
5a0beb1
c5f63ef
 
 
3bc7125
c5f63ef
 
282d1fe
 
5a0beb1
 
 
c9a21eb
546bec9
c5f63ef
 
 
c9a21eb
c5f63ef
546bec9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3bc7125
 
c9a21eb
c5f63ef
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
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("""
<style>
body { direction: rtl; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background-color: #f9fafb; }
.stButton>button { border-radius: 12px; background-color: #2563eb; color: white; font-weight: bold; }
.stTextInput>div>div>input { border-radius: 10px; }
h1, h2, h3 { color: #1e3a8a; }
.stChatMessage { direction: rtl; }
.stExpanderHeader { font-weight: bold; color: #1e40af; }
</style>
""", 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 واحد على الأقل للبدء.")