HonestGrad commited on
Commit
651347d
·
verified ·
1 Parent(s): a63e687

Update app.py

Browse files

Fix UI/UX and check if NEBIUS_API_KEY is the issue

Files changed (1) hide show
  1. app.py +129 -72
app.py CHANGED
@@ -2,96 +2,153 @@ import gradio as gr
2
  import PyPDF2
3
  import os
4
  from openai import OpenAI
 
5
 
6
- # Function to extract text from PDF
7
- def extract_text_from_pdf(pdf_file):
8
- reader = PyPDF2.PdfReader(pdf_file)
9
- text = ""
10
- for page in reader.pages:
11
- if page == reader.pages[0]:
12
- continue
13
- text += page.extract_text() + "\n"
14
- return text
15
-
16
- # Mock LLM response function
17
- # Replace this with your actual LLM integration
18
 
 
 
19
  client = OpenAI(
20
  base_url="https://api.studio.nebius.com/v1/",
21
- api_key=os.getenv("NEBIUS_API_KEY")
22
  )
23
 
24
- def answer_question(pdf_text, question, history):
25
- # You may want to truncate pdf_text if it's too long for the model
26
- context = pdf_text[:16000] # adjust as needed
27
- messages = [
28
- {"role": "system", "content": '''You are a helpful assistant who specializes in body composition, diet, and exercise.
29
- Answer questions based on the provided document. Encourage the user to seek a professional if they have serious concerns whenever appropriate.'''},
30
- {"role": "user", "content": f"Document: {context}"},
31
- {"role": "user", "content": f"Question: {question}"}
32
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  if history:
34
- for msg in history:
35
- if msg["role"] in ["user", "assistant"]:
36
- messages.append(msg)
37
- # Add the new user question
38
- messages.append({"role": "user", "content": question})
39
-
40
- response = client.chat.completions.create(
41
- model="meta-llama/Meta-Llama-3.1-70B-Instruct",
42
- temperature=0.6,
43
- top_p=0.95,
44
- messages=messages
45
- )
46
- return response.choices[0].message.content
47
 
48
- # Gradio chatbot logic
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  class PDFChatbot:
50
  def __init__(self):
51
  self.pdf_text = None
 
52
 
53
  def upload_pdf(self, pdf_file):
54
  if pdf_file is None:
55
- return "No PDF uploaded."
 
56
  self.pdf_text = extract_text_from_pdf(pdf_file)
57
- return "PDF uploaded and processed. You can now ask questions."
58
-
59
- def chat(self, message, history):
60
- if self.pdf_text is None:
61
- return "Please upload a PDF first.", history
62
- # Ensure history is a list of dicts with 'role' and 'content'
63
- if history is None:
64
- history = []
65
- # Only keep user/assistant messages for context
66
- context_history = [msg for msg in history if msg["role"] in ["user", "assistant"]]
67
- answer = answer_question(self.pdf_text, message, context_history)
68
- print("User:", message)
69
- print("LLM Answer:", answer)
70
- history = history + [
71
- {"role": "user", "content": message},
72
- {"role": "assistant", "content": answer}
73
- ]
74
- return "", history
75
 
76
- pdf_bot = PDFChatbot()
 
 
 
77
 
78
- with gr.Blocks() as demo:
79
- gr.Markdown("Body Composition Agent\nUpload a PDF of your recent body spec or any other document you use to track your body composition and ask questions about its content.")
80
- pdf_file = gr.File(label="Upload PDF", file_types=[".pdf"])
81
- upload_btn = gr.Button("Process PDF")
82
- upload_status = gr.Textbox(label="Status", interactive=False)
83
- chatbot = gr.Chatbot(type="messages")
84
- msg = gr.Textbox(label="Your question:")
85
- submit_btn = gr.Button("Submit")
86
 
87
- def handle_upload(pdf):
88
- return pdf_bot.upload_pdf(pdf)
 
 
 
 
 
 
 
 
 
89
 
90
- def handle_chat(message, history):
91
- return pdf_bot.chat(message, history)
 
 
 
 
 
 
 
 
 
 
 
 
 
92
 
93
- upload_btn.click(handle_upload, inputs=pdf_file, outputs=upload_status)
94
- submit_btn.click(handle_chat, inputs=[msg, chatbot], outputs=[msg, chatbot])
95
- msg.submit(handle_chat, inputs=[msg, chatbot], outputs=[msg, chatbot])
 
 
 
 
 
 
 
 
 
 
96
 
97
- demo.launch()
 
 
2
  import PyPDF2
3
  import os
4
  from openai import OpenAI
5
+ import sys # Import sys to write to stderr
6
 
7
+ # --- Configuration & Client Initialization ---
8
+ # It's good practice to check for the API key at startup.
9
+ # This provides a clear error if the secret isn't set in Hugging Face Spaces.
10
+ NEBIUS_API_KEY = os.getenv("NEBIUS_API_KEY")
11
+ if not NEBIUS_API_KEY:
12
+ # Use a more descriptive error message.
13
+ raise ValueError("API Key not found. Please set the NEBIUS_API_KEY secret in your Hugging Face Space settings.")
 
 
 
 
 
14
 
15
+ # Initialize the OpenAI client with your custom endpoint.
16
+ # Ensure this base_url is correct and publicly accessible.
17
  client = OpenAI(
18
  base_url="https://api.studio.nebius.com/v1/",
19
+ api_key=NEBIUS_API_KEY
20
  )
21
 
22
+ # --- Core Functions ---
23
+
24
+ def extract_text_from_pdf(pdf_file):
25
+ """Extracts text from an uploaded PDF file object."""
26
+ # pdf_file is a temporary file object from Gradio.
27
+ if not pdf_file:
28
+ return ""
29
+ try:
30
+ reader = PyPDF2.PdfReader(pdf_file.name)
31
+ text = ""
32
+ # Extract text from all pages except the first one.
33
+ for i, page in enumerate(reader.pages):
34
+ if i == 0:
35
+ continue
36
+ page_text = page.extract_text()
37
+ if page_text:
38
+ text += page_text + "\n"
39
+ return text
40
+ except Exception as e:
41
+ print(f"Error reading PDF: {e}", file=sys.stderr)
42
+ return ""
43
+
44
+
45
+ def get_llm_answer(pdf_text, question, history):
46
+ """
47
+ Sends the context, history, and question to the LLM and returns the answer.
48
+ """
49
+ # Truncate the PDF text to avoid exceeding the model's context limit.
50
+ context = pdf_text[:16000]
51
+
52
+ # The system prompt guides the model's behavior.
53
+ system_prompt = '''You are a helpful assistant who specializes in body composition, diet, and exercise.
54
+ Answer questions based on the provided document. Encourage the user to seek a professional
55
+ if they have serious concerns whenever appropriate.'''
56
+
57
+ # Construct the message payload for the API.
58
+ messages = [{"role": "system", "content": system_prompt}]
59
+
60
+ # Add document context if available.
61
+ if context:
62
+ messages.append({"role": "user", "content": f"Use the following document to answer my question:\n\n{context}"})
63
+
64
+ # Add the conversation history.
65
  if history:
66
+ messages.extend(history)
67
+
68
+ # Add the latest user question.
69
+ messages.append({"role": "user", "content": question})
 
 
 
 
 
 
 
 
 
70
 
71
+ try:
72
+ response = client.chat.completions.create(
73
+ model="meta-llama/Meta-Llama-3.1-70B-Instruct",
74
+ temperature=0.6,
75
+ top_p=0.95,
76
+ messages=messages
77
+ )
78
+ return response.choices[0].message.content
79
+ except Exception as e:
80
+ print(f"Error calling OpenAI API: {e}", file=sys.stderr)
81
+ # Return a user-friendly error message.
82
+ return "Sorry, I encountered an error while trying to generate a response. Please check the logs."
83
+
84
+
85
+ # --- Gradio Interface Logic ---
86
+
87
+ # Use a class to manage state (the extracted PDF text).
88
  class PDFChatbot:
89
  def __init__(self):
90
  self.pdf_text = None
91
+ self.pdf_filename = None
92
 
93
  def upload_pdf(self, pdf_file):
94
  if pdf_file is None:
95
+ return "Status: No PDF uploaded."
96
+
97
  self.pdf_text = extract_text_from_pdf(pdf_file)
98
+ self.pdf_filename = os.path.basename(pdf_file.name)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
 
100
+ if not self.pdf_text:
101
+ return f"Status: Could not extract text from {self.pdf_filename}. It might be empty, scanned, or protected."
102
+
103
+ return f"Status: Successfully processed {self.pdf_filename}. You can now ask questions."
104
 
105
+ def chat(self, user_message, history):
106
+ if not self.pdf_text:
107
+ # Add an instruction to the chatbot window if no PDF is uploaded.
108
+ history.append([user_message, "Please upload a PDF document first."])
109
+ return "", history
 
 
 
110
 
111
+ # Get the answer from the LLM.
112
+ answer = get_llm_answer(self.pdf_text, user_message, history)
113
+
114
+ # Append the user message and the assistant's answer to the history.
115
+ history.append([user_message, answer])
116
+
117
+ # Return an empty string to clear the input textbox and the updated history.
118
+ return "", history
119
+
120
+ # Instantiate the bot.
121
+ pdf_bot = PDFChatbot()
122
 
123
+ # Build the Gradio UI.
124
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
125
+ gr.Markdown("# Body Composition Agent\nUpload a document about your body composition and ask questions about its content.")
126
+
127
+ with gr.Row():
128
+ with gr.Column(scale=1):
129
+ pdf_file = gr.File(label="Upload PDF", file_types=[".pdf"])
130
+ upload_btn = gr.Button("Process PDF", variant="primary")
131
+ upload_status = gr.Textbox(label="Status", interactive=False, value="Status: Waiting for PDF...")
132
+
133
+ with gr.Column(scale=2):
134
+ chatbot = gr.Chatbot(label="Chat History", bubble_full_width=False, height=500)
135
+ msg_textbox = gr.Textbox(label="Your Question:", interactive=True, placeholder="Type your question here...")
136
+ # Clear button is useful for starting a new conversation.
137
+ clear_btn = gr.ClearButton([msg_textbox, chatbot], value="Clear Chat")
138
 
139
+ # Wire up the event listeners.
140
+ upload_btn.click(
141
+ fn=pdf_bot.upload_pdf,
142
+ inputs=[pdf_file],
143
+ outputs=[upload_status]
144
+ )
145
+
146
+ # Allow submitting questions with Enter key or the button.
147
+ msg_textbox.submit(
148
+ fn=pdf_bot.chat,
149
+ inputs=[msg_textbox, chatbot],
150
+ outputs=[msg_textbox, chatbot]
151
+ )
152
 
153
+ # Launch the app.
154
+ demo.launch(debug=True) # Use debug=True to see errors in the console.