File size: 7,150 Bytes
d016645
94d49c9
 
 
9578d72
a0342c6
9578d72
 
 
94d49c9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13df882
94d49c9
 
 
 
 
 
 
 
 
7a16b3c
94d49c9
 
 
 
 
7a16b3c
94d49c9
 
 
 
f6905f3
94d49c9
 
 
 
f6905f3
94d49c9
 
 
 
 
 
 
13df882
649e09f
 
 
 
 
94d49c9
9578d72
 
d016645
 
 
 
 
 
 
9578d72
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94d49c9
 
 
 
 
 
 
 
 
9578d72
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13df882
94d49c9
9578d72
 
 
2e44d20
9578d72
 
94d49c9
9578d72
 
 
 
2e44d20
9578d72
 
 
2e44d20
9578d72
649e09f
9578d72
 
 
649e09f
9578d72
 
 
 
649e09f
9578d72
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
import tempfile
import streamlit as st
import requests
import logging
from langchain.document_loaders import PDFPlumberLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.prompts import ChatPromptTemplate
from langchain.llms import HuggingFacePipeline
from transformers import pipeline

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# Page configuration
st.set_page_config(
    page_title="DeepSeek Chatbot - ruslanmv.com",
    page_icon="🤖",
    layout="centered"
)

# Initialize session state for chat history
if "messages" not in st.session_state:
    st.session_state.messages = []

# Sidebar configuration
with st.sidebar:
    st.header("Model Configuration")
    st.markdown("[Get HuggingFace Token](https://huggingface.co/settings/tokens)")

    # Dropdown to select model
    model_options = [
        "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B",
    ]
    selected_model = st.selectbox("Select Model", model_options, index=0)

    system_message = st.text_area(
        "System Message",
        value="You are a friendly chatbot created by ruslanmv.com. Provide clear, accurate, and brief answers. Keep responses polite, engaging, and to the point. If unsure, politely suggest alternatives.",
        height=100
    )

    max_tokens = st.slider(
        "Max Tokens",
        10, 4000, 100
    )

    temperature = st.slider(
        "Temperature",
        0.1, 4.0, 0.3
    )

    top_p = st.slider(
        "Top-p",
        0.1, 1.0, 0.6
    )

# Function to query the Hugging Face API
def query(payload, api_url):
    headers = {"Authorization": f"Bearer {st.secrets['HF_TOKEN']}"}
    logger.info(f"Sending request to {api_url} with payload: {payload}")
    response = requests.post(api_url, headers=headers, json=payload)
    logger.info(f"Received response: {response.status_code}, {response.text}")
    try:
        return response.json()
    except requests.exceptions.JSONDecodeError:
        logger.error(f"Failed to decode JSON response: {response.text}")
        return None

# Function to load and process PDF
def process_pdf(uploaded_file):
    # Save the uploaded file to a temporary file
    with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as temp_file:
        temp_file.write(uploaded_file.getvalue())
        temp_file_path = temp_file.name

    # Use PDFPlumberLoader to load the PDF from the temporary file
    loader = PDFPlumberLoader(temp_file_path)
    documents = loader.load()

    # Split the documents into chunks
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=1000,
        chunk_overlap=200,
        add_start_index=True
    )
    return text_splitter.split_documents(documents)

# Function to generate response using LangChain
def generate_response_with_langchain(question, context):
    prompt_template = """
    You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don't know the answer, just say that you don't know. Use three sentences maximum and keep the answer concise.
    Question: {question} 
    Context: {context} 
    Answer:
    """

    prompt = ChatPromptTemplate.from_template(prompt_template)
    model = HuggingFacePipeline(pipeline("text-generation", model=selected_model))

    # Use LangChain to generate an answer
    chain = prompt | model
    response = chain.invoke({"question": question, "context": context})
    return response

# Chat interface
st.title("🤖 DeepSeek Chatbot")
st.caption("Powered by Hugging Face Inference API - Configure in sidebar")

# Display chat history
for message in st.session_state.messages:
    with st.chat_message(message["role"]):
        st.markdown(message["content"])

# Handle input and PDF processing
uploaded_file = st.file_uploader("Upload PDF", type="pdf", accept_multiple_files=False)
if uploaded_file:
    documents = process_pdf(uploaded_file)
    context = "\n\n".join([doc.page_content for doc in documents])

    # Ask the user a question
    if prompt := st.chat_input("Type your message..."):
        st.session_state.messages.append({"role": "user", "content": prompt})

        with st.chat_message("user"):
            st.markdown(prompt)

        try:
            with st.spinner("Generating response..."):
                # Combine system message and user input into a single prompt
                full_prompt = f"{system_message}\n\nUser: {prompt}\nAssistant:"
                payload = {
                    "inputs": full_prompt,
                    "parameters": {
                        "max_new_tokens": max_tokens,
                        "temperature": temperature,
                        "top_p": top_p,
                        "return_full_text": False
                    }
                }

                # Dynamically construct the API URL based on the selected model
                api_url = f"https://api-inference.huggingface.co/models/{selected_model}"
                logger.info(f"Selected model: {selected_model}, API URL: {api_url}")

                # Query the Hugging Face API using the selected model
                output = query(payload, api_url)

                # Handle API response
                if output is not None and isinstance(output, list) and len(output) > 0:
                    if 'generated_text' in output[0]:
                        assistant_response = output[0]['generated_text'].strip()

                        # Check for and remove duplicate responses
                        responses = assistant_response.split("\n</think>\n")
                        unique_response = responses[0].strip()

                        logger.info(f"Generated response: {unique_response}")

                        # Append response to chat only once
                        with st.chat_message("assistant"):
                            st.markdown(unique_response)

                        st.session_state.messages.append({"role": "assistant", "content": unique_response})
                    else:
                        logger.error(f"Unexpected API response structure: {output}")
                        st.error("Error: Unexpected response from the model. Please try again.")
                else:
                    logger.error(f"Empty or invalid API response: {output}")
                    st.error("Error: Unable to generate a response. Please check the model and try again.")

        except Exception as e:
            logger.error(f"Application Error: {str(e)}", exc_info=True)
            st.error(f"Application Error: {str(e)}")

# Allow user to ask a question based on extracted PDF content
if prompt := st.chat_input("Ask a question about the PDF content"):
    if documents:
        context = "\n\n".join([doc.page_content for doc in documents])  # Get context from documents
        answer = generate_response_with_langchain(prompt, context)
        
        # Show the answer from LangChain model
        with st.chat_message("assistant"):
            st.markdown(answer)

        st.session_state.messages.append({"role": "assistant", "content": answer})