CCockrum commited on
Commit
e3d3d36
Β·
verified Β·
1 Parent(s): 391ca85

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +83 -87
app.py CHANGED
@@ -8,72 +8,27 @@ from langchain_core.prompts import PromptTemplate
8
  from langchain_core.output_parsers import StrOutputParser
9
  from transformers import pipeline
10
 
11
- # Must be the first Streamlit command!
 
 
 
 
 
 
 
 
 
12
  st.set_page_config(page_title="HAL - NASA ChatBot", page_icon="πŸš€")
13
 
14
- # Appearance settings (optional): you can modify these as needed
15
- user_bg_color = "#0078D7"
16
- assistant_bg_color = "#333333"
17
- text_color = "#FFFFFF"
18
- font_choice = "sans serif"
19
-
20
- # Inject custom CSS for appearance
21
- custom_css = f"""
22
- <style>
23
- .user-msg {{
24
- background-color: {user_bg_color};
25
- color: {text_color};
26
- padding: 10px;
27
- border-radius: 10px;
28
- margin-bottom: 5px;
29
- width: fit-content;
30
- max-width: 80%;
31
- font-family: {font_choice};
32
- }}
33
- .assistant-msg {{
34
- background-color: {assistant_bg_color};
35
- color: {text_color};
36
- padding: 10px;
37
- border-radius: 10px;
38
- margin-bottom: 5px;
39
- width: fit-content;
40
- max-width: 80%;
41
- font-family: {font_choice};
42
- }}
43
- .container {{
44
- display: flex;
45
- flex-direction: column;
46
- align-items: flex-start;
47
- }}
48
- @media (max-width: 600px) {{
49
- .user-msg, .assistant-msg {{
50
- font-size: 16px;
51
- max-width: 100%;
52
- }}
53
- }}
54
- </style>
55
- """
56
- st.markdown(custom_css, unsafe_allow_html=True)
57
-
58
- # Initialize session state variables
59
  if "chat_history" not in st.session_state:
60
  st.session_state.chat_history = [{"role": "assistant", "content": "Hello! How can I assist you today?"}]
61
  if "response_ready" not in st.session_state:
62
  st.session_state.response_ready = False
63
  if "follow_up" not in st.session_state:
64
  st.session_state.follow_up = ""
65
- if "saved_conversations" not in st.session_state:
66
- st.session_state.saved_conversations = {} # dict mapping conv_id -> chat_history
67
-
68
- # Set up keys from environment variables
69
- HF_TOKEN = os.getenv("HF_TOKEN")
70
- if not HF_TOKEN:
71
- raise ValueError("HF_TOKEN environment variable not set.")
72
- NASA_API_KEY = os.getenv("NASA_API_KEY")
73
- if not NASA_API_KEY:
74
- raise ValueError("NASA_API_KEY environment variable not set.")
75
 
76
- # --- Model & API functions ---
77
  model_id = "mistralai/Mistral-7B-Instruct-v0.3"
78
  sentiment_analyzer = pipeline(
79
  "sentiment-analysis",
@@ -97,20 +52,26 @@ def get_nasa_apod():
97
  data = response.json()
98
  return data.get("url", ""), data.get("title", ""), data.get("explanation", "")
99
  else:
100
- return "", "NASA Data Unavailable", "I couldn't fetch data from NASA right now."
101
 
102
  def analyze_sentiment(user_text):
103
  result = sentiment_analyzer(user_text)[0]
104
  return result['label']
105
 
106
  def predict_action(user_text):
107
- return "nasa_info" if ("nasa" in user_text.lower() or "space" in user_text.lower()) else "general_query"
 
 
108
 
109
  def generate_follow_up(user_text):
 
 
 
 
110
  prompt_text = (
111
- f"Based on the user's question: '{user_text}', generate two concise, friendly follow-up questions that invite further discussion. "
112
- "For example, one could be 'Would you like to know more about the six types of quarks?' and another 'Would you like to explore another aspect of quantum physics?'. "
113
- "Return only the questions, separated by a newline."
114
  )
115
  hf = get_llm_hf_inference(max_new_tokens=80, temperature=0.9)
116
  output = hf.invoke(input=prompt_text).strip()
@@ -121,8 +82,15 @@ def generate_follow_up(user_text):
121
  return random.choice(cleaned)
122
 
123
  def get_response(system_message, chat_history, user_text, max_new_tokens=256):
 
 
 
 
 
124
  sentiment = analyze_sentiment(user_text)
125
  action = predict_action(user_text)
 
 
126
  style_instruction = ""
127
  lower_text = user_text.lower()
128
  if "in the voice of" in lower_text or "speaking as" in lower_text:
@@ -131,7 +99,6 @@ def get_response(system_message, chat_history, user_text, max_new_tokens=256):
131
  style_instruction = match.group(2).strip().capitalize()
132
  style_instruction = f" Please respond in the voice of {style_instruction}."
133
 
134
- # Handle NASA queries separately
135
  if action == "nasa_info":
136
  nasa_url, nasa_title, nasa_explanation = get_nasa_apod()
137
  response = f"**{nasa_title}**\n\n{nasa_explanation}"
@@ -140,7 +107,7 @@ def get_response(system_message, chat_history, user_text, max_new_tokens=256):
140
  follow_up = generate_follow_up(user_text)
141
  chat_history.append({'role': 'assistant', 'content': follow_up})
142
  return response, follow_up, chat_history, nasa_url
143
-
144
  hf = get_llm_hf_inference(max_new_tokens=max_new_tokens, temperature=0.9)
145
  filtered_history = ""
146
  for message in chat_history:
@@ -149,43 +116,41 @@ def get_response(system_message, chat_history, user_text, max_new_tokens=256):
149
  filtered_history += f"{message['role']}: {message['content']}\n"
150
 
151
  style_clause = style_instruction if style_instruction else ""
 
 
152
  prompt = PromptTemplate.from_template(
153
  (
154
  "[INST] {system_message}\n\nCurrent Conversation:\n{chat_history}\n\n"
155
  "User: {user_text}.\n [/INST]\n"
156
- "AI: Please provide a detailed, in-depth answer in a friendly, conversational tone. "
157
- "Begin with a phrase like 'Certainly!', 'Of course!', or 'Great question!'." + style_clause +
 
158
  "\nHAL:"
159
  )
160
  )
 
161
  chat = prompt | hf.bind(skip_prompt=True) | StrOutputParser(output_key='content')
162
  response = chat.invoke(input=dict(system_message=system_message, user_text=user_text, chat_history=filtered_history))
 
163
  response = response.split("HAL:")[-1].strip()
 
 
164
  if not response:
165
  response = "Certainly, here is an in-depth explanation: [Fallback explanation]."
 
166
  chat_history.append({'role': 'user', 'content': user_text})
167
  chat_history.append({'role': 'assistant', 'content': response})
 
168
  if sentiment == "NEGATIVE" and not user_text.strip().endswith("?"):
169
  response = "I'm sorry you're feeling this way. I'm here to help. What can I do to assist you further?"
170
  chat_history[-1]['content'] = response
 
171
  follow_up = generate_follow_up(user_text)
172
  chat_history.append({'role': 'assistant', 'content': follow_up})
173
- return response, follow_up, chat_history, None
174
-
175
- # --- Sidebar: Save/Load Conversations ---
176
- st.sidebar.header("Saved Conversations")
177
- if st.sidebar.button("Save Current Conversation"):
178
- conv_id = f"Conv {len(st.session_state.saved_conversations) + 1}"
179
- st.session_state.saved_conversations[conv_id] = st.session_state.chat_history.copy()
180
- st.sidebar.success(f"Conversation saved as {conv_id}.")
181
 
182
- if st.session_state.saved_conversations:
183
- for conv_id in st.session_state.saved_conversations:
184
- if st.sidebar.button(f"Load {conv_id}"):
185
- st.session_state.chat_history = st.session_state.saved_conversations[conv_id].copy()
186
- st.sidebar.info(f"Loaded {conv_id}.")
187
 
188
- # --- Main Chat UI ---
189
  st.title("πŸš€ HAL - Your NASA AI Assistant")
190
  st.markdown("🌌 *Ask me about space, NASA, and beyond!*")
191
 
@@ -195,13 +160,36 @@ if st.sidebar.button("Reset Chat"):
195
  st.session_state.follow_up = ""
196
  st.experimental_rerun()
197
 
198
- st.markdown("<div class='container'>", unsafe_allow_html=True)
199
- for message in st.session_state.chat_history:
200
- if message["role"] == "user":
201
- st.markdown(f"<div class='user-msg'><strong>You:</strong> {message['content']}</div>", unsafe_allow_html=True)
202
- else:
203
- st.markdown(f"<div class='assistant-msg'><strong>HAL:</strong> {message['content']}</div>", unsafe_allow_html=True)
204
- st.markdown("</div>", unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
205
 
206
  user_input = st.chat_input("Type your message here...")
207
 
@@ -215,3 +203,11 @@ if user_input:
215
  st.image(image_url, caption="NASA Image of the Day")
216
  st.session_state.follow_up = follow_up
217
  st.session_state.response_ready = True
 
 
 
 
 
 
 
 
 
8
  from langchain_core.output_parsers import StrOutputParser
9
  from transformers import pipeline
10
 
11
+ # Use environment variables for keys
12
+ HF_TOKEN = os.getenv("HF_TOKEN")
13
+ if HF_TOKEN is None:
14
+ raise ValueError("HF_TOKEN environment variable not set. Please set it in your Hugging Face Space settings.")
15
+
16
+ NASA_API_KEY = os.getenv("NASA_API_KEY")
17
+ if NASA_API_KEY is None:
18
+ raise ValueError("NASA_API_KEY environment variable not set. Please set it in your Hugging Face Space settings.")
19
+
20
+ # Set up Streamlit UI
21
  st.set_page_config(page_title="HAL - NASA ChatBot", page_icon="πŸš€")
22
 
23
+ # --- Initialize Session State Variables ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  if "chat_history" not in st.session_state:
25
  st.session_state.chat_history = [{"role": "assistant", "content": "Hello! How can I assist you today?"}]
26
  if "response_ready" not in st.session_state:
27
  st.session_state.response_ready = False
28
  if "follow_up" not in st.session_state:
29
  st.session_state.follow_up = ""
 
 
 
 
 
 
 
 
 
 
30
 
31
+ # --- Set Up Model & API Functions ---
32
  model_id = "mistralai/Mistral-7B-Instruct-v0.3"
33
  sentiment_analyzer = pipeline(
34
  "sentiment-analysis",
 
52
  data = response.json()
53
  return data.get("url", ""), data.get("title", ""), data.get("explanation", "")
54
  else:
55
+ return "", "NASA Data Unavailable", "I couldn't fetch data from NASA right now. Please try again later."
56
 
57
  def analyze_sentiment(user_text):
58
  result = sentiment_analyzer(user_text)[0]
59
  return result['label']
60
 
61
  def predict_action(user_text):
62
+ if "NASA" in user_text or "space" in user_text:
63
+ return "nasa_info"
64
+ return "general_query"
65
 
66
  def generate_follow_up(user_text):
67
+ """
68
+ Generates two variant follow-up questions and randomly selects one.
69
+ It also cleans up any unwanted quotation marks or extra meta commentary.
70
+ """
71
  prompt_text = (
72
+ f"Based on the user's question: '{user_text}', generate two concise, friendly follow-up questions "
73
+ "that invite further discussion. For example, one might be 'Would you like to know more about the six types of quarks?' "
74
+ "and another might be 'Would you like to explore another aspect of quantum physics?' Do not include extra commentary."
75
  )
76
  hf = get_llm_hf_inference(max_new_tokens=80, temperature=0.9)
77
  output = hf.invoke(input=prompt_text).strip()
 
82
  return random.choice(cleaned)
83
 
84
  def get_response(system_message, chat_history, user_text, max_new_tokens=256):
85
+ """
86
+ Generates HAL's answer with depth and a follow-up question.
87
+ The prompt instructs the model to provide a detailed explanation and then generate a follow-up.
88
+ If the answer comes back empty, a fallback answer is used.
89
+ """
90
  sentiment = analyze_sentiment(user_text)
91
  action = predict_action(user_text)
92
+
93
+ # Extract style instruction if present
94
  style_instruction = ""
95
  lower_text = user_text.lower()
96
  if "in the voice of" in lower_text or "speaking as" in lower_text:
 
99
  style_instruction = match.group(2).strip().capitalize()
100
  style_instruction = f" Please respond in the voice of {style_instruction}."
101
 
 
102
  if action == "nasa_info":
103
  nasa_url, nasa_title, nasa_explanation = get_nasa_apod()
104
  response = f"**{nasa_title}**\n\n{nasa_explanation}"
 
107
  follow_up = generate_follow_up(user_text)
108
  chat_history.append({'role': 'assistant', 'content': follow_up})
109
  return response, follow_up, chat_history, nasa_url
110
+
111
  hf = get_llm_hf_inference(max_new_tokens=max_new_tokens, temperature=0.9)
112
  filtered_history = ""
113
  for message in chat_history:
 
116
  filtered_history += f"{message['role']}: {message['content']}\n"
117
 
118
  style_clause = style_instruction if style_instruction else ""
119
+
120
+ # Instruct the model to generate a detailed, in-depth answer.
121
  prompt = PromptTemplate.from_template(
122
  (
123
  "[INST] {system_message}\n\nCurrent Conversation:\n{chat_history}\n\n"
124
  "User: {user_text}.\n [/INST]\n"
125
+ "AI: Please provide a detailed explanation in depth. "
126
+ "Ensure your response covers the topic thoroughly and is written in a friendly, conversational style, "
127
+ "starting with a phrase like 'Certainly!', 'Of course!', or 'Great question!'." + style_clause +
128
  "\nHAL:"
129
  )
130
  )
131
+
132
  chat = prompt | hf.bind(skip_prompt=True) | StrOutputParser(output_key='content')
133
  response = chat.invoke(input=dict(system_message=system_message, user_text=user_text, chat_history=filtered_history))
134
+ # Remove any extra markers if present.
135
  response = response.split("HAL:")[-1].strip()
136
+
137
+ # Fallback in case the generated answer is empty
138
  if not response:
139
  response = "Certainly, here is an in-depth explanation: [Fallback explanation]."
140
+
141
  chat_history.append({'role': 'user', 'content': user_text})
142
  chat_history.append({'role': 'assistant', 'content': response})
143
+
144
  if sentiment == "NEGATIVE" and not user_text.strip().endswith("?"):
145
  response = "I'm sorry you're feeling this way. I'm here to help. What can I do to assist you further?"
146
  chat_history[-1]['content'] = response
147
+
148
  follow_up = generate_follow_up(user_text)
149
  chat_history.append({'role': 'assistant', 'content': follow_up})
 
 
 
 
 
 
 
 
150
 
151
+ return response, follow_up, chat_history, None
 
 
 
 
152
 
153
+ # --- Chat UI ---
154
  st.title("πŸš€ HAL - Your NASA AI Assistant")
155
  st.markdown("🌌 *Ask me about space, NASA, and beyond!*")
156
 
 
160
  st.session_state.follow_up = ""
161
  st.experimental_rerun()
162
 
163
+ st.markdown("""
164
+ <style>
165
+ .user-msg {
166
+ background-color: #696969;
167
+ color: white;
168
+ padding: 10px;
169
+ border-radius: 10px;
170
+ margin-bottom: 5px;
171
+ width: fit-content;
172
+ max-width: 80%;
173
+ }
174
+ .assistant-msg {
175
+ background-color: #333333;
176
+ color: white;
177
+ padding: 10px;
178
+ border-radius: 10px;
179
+ margin-bottom: 5px;
180
+ width: fit-content;
181
+ max-width: 80%;
182
+ }
183
+ .container {
184
+ display: flex;
185
+ flex-direction: column;
186
+ align-items: flex-start;
187
+ }
188
+ @media (max-width: 600px) {
189
+ .user-msg, .assistant-msg { font-size: 16px; max-width: 100%; }
190
+ }
191
+ </style>
192
+ """, unsafe_allow_html=True)
193
 
194
  user_input = st.chat_input("Type your message here...")
195
 
 
203
  st.image(image_url, caption="NASA Image of the Day")
204
  st.session_state.follow_up = follow_up
205
  st.session_state.response_ready = True
206
+
207
+ st.markdown("<div class='container'>", unsafe_allow_html=True)
208
+ for message in st.session_state.chat_history:
209
+ if message["role"] == "user":
210
+ st.markdown(f"<div class='user-msg'><strong>You:</strong> {message['content']}</div>", unsafe_allow_html=True)
211
+ else:
212
+ st.markdown(f"<div class='assistant-msg'><strong>HAL:</strong> {message['content']}</div>", unsafe_allow_html=True)
213
+ st.markdown("</div>", unsafe_allow_html=True)