File size: 3,963 Bytes
02a2d80
11503ab
 
8a8d9dd
 
b0a7f96
11503ab
 
 
 
 
49c2234
11503ab
 
 
 
 
 
 
c14d65f
11503ab
c14d65f
 
33aae2c
11503ab
 
 
 
 
9e59998
11503ab
 
 
755689d
21bd98b
 
 
 
755689d
 
11503ab
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
597f25d
02a2d80
 
 
 
 
 
11503ab
80d2c6b
 
 
02a2d80
11503ab
 
02a2d80
 
 
 
 
 
11503ab
02a2d80
 
26608f4
11503ab
26608f4
11503ab
 
 
7fb2b42
11503ab
02a2d80
26608f4
 
 
33aae2c
11503ab
7fb2b42
26608f4
 
 
 
 
 
 
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
import streamlit as st
import time
import numpy as np
from langchain.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_together import TogetherEmbeddings
from langchain.chat_models import ChatOpenAI
from sklearn.metrics.pairwise import cosine_similarity

# ------------------ بارگذاری چانک‌ها و امبدینگ‌ها ------------------

@st.cache_resource
def load_chunks_and_embeddings():
    with st.spinner('📄 در حال پردازش PDF و ساخت امبدینگ‌ها...'):
        loader = PyPDFLoader('test1.pdf')
        pages = loader.load()

        splitter = RecursiveCharacterTextSplitter(chunk_size=300, chunk_overlap=0)
        chunks = splitter.split_documents(pages)

        embeddings_model = TogetherEmbeddings(
            api_key="0291f33aee03412a47fa5d8e562e515182dcc5d9aac5a7fb5eefdd1759005979"
        )

        chunk_texts = [chunk.page_content for chunk in chunks]
        chunk_embeddings = embeddings_model.embed_documents(chunk_texts)

        st.success(f"✅ تعداد {len(chunk_texts)} چانک ساخته شد.")
        return chunk_texts, chunk_embeddings, embeddings_model

chunk_texts, chunk_embeddings, embeddings_model = load_chunks_and_embeddings()

# ------------------ ساخت مدل LLM ------------------

llm = ChatOpenAI(
    base_url="https://api.together.xyz/v1",
    api_key='0291f33aee03412a47fa5d8e562e515182dcc5d9aac5a7fb5eefdd1759005979',
    model="meta-llama/Llama-3.3-70B-Instruct-Turbo-Free"
)

# ------------------ تابع پاسخ به سوال از طریق نزدیک‌ترین چانک ------------------

def answer_from_pdf(question):
    # ۱- امبد سوال
    question_embedding = embeddings_model.embed_query(question)

    # ۲- شباهت پیدا کن
    similarities = cosine_similarity(
        [question_embedding],
        chunk_embeddings
    )

    # ۳- نزدیک‌ترین چانک
    best_idx = np.argmax(similarities)
    best_chunk = chunk_texts[best_idx]

    # ۴- ساخت پرامپت
    prompt = f"""بر اساس متن زیر فقط به زبان فارسی پاسخ بده:

    متن:
    {best_chunk}

    سوال:
    {question}

    پاسخ:"""

    response = llm.invoke(prompt)
    return response.content

# ------------------ Chat Streamlit UI ------------------

st.title('📚 چت با PDF')

if 'messages' not in st.session_state:
    st.session_state.messages = []

if 'pending_prompt' not in st.session_state:
    st.session_state.pending_prompt = None

# نمایش هیستوری چت
for msg in st.session_state.messages:
    with st.chat_message(msg['role']):
        st.markdown(f"🗨️ {msg['content']}", unsafe_allow_html=True)

# گرفتن سوال از کاربر
prompt = st.chat_input("سوال خود را وارد کنید...")

if prompt:
    st.session_state.messages.append({'role': 'user', 'content': prompt})
    st.session_state.pending_prompt = prompt
    st.rerun()

# وقتی سوال جدید داری
if st.session_state.pending_prompt:
    with st.chat_message('ai'):
        thinking = st.empty()
        thinking.markdown("🤖 در حال پردازش...")

        # پاسخ بر اساس نزدیک‌ترین چانک
        response = answer_from_pdf(st.session_state.pending_prompt)
        answer = response.strip()
        if not answer:
            answer = "متاسفم، اطلاعات دقیقی در این مورد ندارم."

        thinking.empty()
        full_response = ""
        placeholder = st.empty()

        # تدریجی نشون دادن پاسخ
        for word in answer.split():
            full_response += word + " "
            placeholder.markdown(full_response + "▌")
            time.sleep(0.03)

        placeholder.markdown(full_response)
        st.session_state.messages.append({'role': 'ai', 'content': full_response})
        st.session_state.pending_prompt = None