CCockrum commited on
Commit
258dcf5
Β·
verified Β·
1 Parent(s): 6db00e7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +50 -67
app.py CHANGED
@@ -1,10 +1,8 @@
1
  import os
2
  import re
3
  import random
4
- import subprocess
5
  import requests
6
  import streamlit as st
7
- import spacy # for additional NLP processing
8
  from langchain_huggingface import HuggingFaceEndpoint
9
  from langchain_core.prompts import PromptTemplate
10
  from langchain_core.output_parsers import StrOutputParser
@@ -19,7 +17,7 @@ NASA_API_KEY = os.getenv("NASA_API_KEY")
19
  if NASA_API_KEY is None:
20
  raise ValueError("NASA_API_KEY environment variable not set. Please set it in your Hugging Face Space settings.")
21
 
22
- # Must be the first Streamlit command!
23
  st.set_page_config(page_title="HAL - NASA ChatBot", page_icon="πŸš€")
24
 
25
  # --- Initialize Session State Variables ---
@@ -38,27 +36,17 @@ sentiment_analyzer = pipeline(
38
  revision="714eb0f"
39
  )
40
 
41
- # --- Helper to load spaCy model with fallback ---
42
- def load_spacy_model():
43
- try:
44
- return spacy.load("en_core_web_sm")
45
- except OSError:
46
- subprocess.run(["python", "-m", "spacy", "download", "en_core_web_sm"], check=True)
47
- return spacy.load("en_core_web_sm")
48
-
49
- nlp_spacy = load_spacy_model()
50
-
51
  def get_llm_hf_inference(model_id=model_id, max_new_tokens=128, temperature=0.7):
52
  return HuggingFaceEndpoint(
53
  repo_id=model_id,
54
  max_new_tokens=max_new_tokens,
55
  temperature=temperature,
56
- token=os.getenv("HF_TOKEN"),
57
  task="text-generation"
58
  )
59
 
60
  def get_nasa_apod():
61
- url = f"https://api.nasa.gov/planetary/apod?api_key={os.getenv('NASA_API_KEY')}"
62
  response = requests.get(url)
63
  if response.status_code == 200:
64
  data = response.json()
@@ -66,23 +54,6 @@ def get_nasa_apod():
66
  else:
67
  return "", "NASA Data Unavailable", "I couldn't fetch data from NASA right now. Please try again later."
68
 
69
- def analyze_sentiment(user_text):
70
- result = sentiment_analyzer(user_text)[0]
71
- return result['label']
72
-
73
- def predict_action(user_text):
74
- if "nasa" in user_text.lower() or "space" in user_text.lower():
75
- return "nasa_info"
76
- return "general_query"
77
-
78
- def extract_context(text):
79
- """
80
- Uses spaCy to extract named entities for additional context.
81
- """
82
- doc = nlp_spacy(text)
83
- entities = [ent.text for ent in doc.ents]
84
- return ", ".join(entities) if entities else ""
85
-
86
  def is_apod_query(user_text):
87
  """
88
  Checks if the user's question contains keywords indicating they are asking for
@@ -91,15 +62,25 @@ def is_apod_query(user_text):
91
  keywords = ["apod", "image", "picture", "photo", "astronomy picture"]
92
  return any(keyword in user_text.lower() for keyword in keywords)
93
 
 
 
 
 
 
 
 
 
 
94
  def generate_follow_up(user_text):
95
  """
96
  Generates two variant follow-up questions and randomly selects one.
 
97
  """
98
  prompt_text = (
99
  f"Based on the user's question: '{user_text}', generate two concise, friendly follow-up questions "
100
  "that invite further discussion. For example, one might be 'Would you like to know more about the six types of quarks?' "
101
- "and another 'Would you like to explore another aspect of quantum physics?'. Do not include extra commentary. "
102
- "Answer exclusively in English."
103
  )
104
  hf = get_llm_hf_inference(max_new_tokens=80, temperature=0.9)
105
  output = hf.invoke(input=prompt_text).strip()
@@ -109,16 +90,25 @@ def generate_follow_up(user_text):
109
  cleaned = ["Would you like to explore this topic further?"]
110
  return random.choice(cleaned)
111
 
112
- def get_response(system_message, chat_history, user_text, max_new_tokens=1024):
113
  """
114
- Generates HAL's detailed, in-depth answer and a follow-up question.
115
- Incorporates sentiment analysis, additional NLP context, and style instructions.
 
116
  """
117
  sentiment = analyze_sentiment(user_text)
118
  action = predict_action(user_text)
119
 
120
- # If the user's NASA-related query is specifically an APOD query, handle it specially.
121
- if action == "nasa_info" and is_apod_query(user_text):
 
 
 
 
 
 
 
 
122
  nasa_url, nasa_title, nasa_explanation = get_nasa_apod()
123
  response = f"**{nasa_title}**\n\n{nasa_explanation}"
124
  chat_history.append({'role': 'user', 'content': user_text})
@@ -126,8 +116,7 @@ def get_response(system_message, chat_history, user_text, max_new_tokens=1024):
126
  follow_up = generate_follow_up(user_text)
127
  chat_history.append({'role': 'assistant', 'content': follow_up})
128
  return response, follow_up, chat_history, nasa_url
129
-
130
- # Otherwise, treat NASA-related queries as general queries.
131
  hf = get_llm_hf_inference(max_new_tokens=max_new_tokens, temperature=0.9)
132
  filtered_history = ""
133
  for message in chat_history:
@@ -135,34 +124,27 @@ def get_response(system_message, chat_history, user_text, max_new_tokens=1024):
135
  continue
136
  filtered_history += f"{message['role']}: {message['content']}\n"
137
 
138
- # Extract style instructions if provided.
139
- style_instruction = ""
140
- lower_text = user_text.lower()
141
- if "in the voice of" in lower_text or "speaking as" in lower_text:
142
- match = re.search(r"(in the voice of|speaking as)(.*)", lower_text)
143
- if match:
144
- style_instruction = match.group(2).strip().capitalize()
145
- style_instruction = f" Please respond in the voice of {style_instruction}."
146
-
147
- context_info = extract_context(user_text)
148
- context_clause = f" The key topics here are: {context_info}." if context_info else ""
149
- language_clause = " Answer exclusively in English."
150
-
151
  style_clause = style_instruction if style_instruction else ""
152
 
 
153
  prompt = PromptTemplate.from_template(
154
  (
155
  "[INST] {system_message}\n\nCurrent Conversation:\n{chat_history}\n\n"
156
  "User: {user_text}.\n [/INST]\n"
157
- "AI: Please provide a detailed, in-depth answer in a friendly, conversational tone that thoroughly covers the topic."
158
- + style_clause + context_clause + language_clause +
 
 
159
  "\nHAL:"
160
  )
161
  )
162
 
163
  chat = prompt | hf.bind(skip_prompt=True) | StrOutputParser(output_key='content')
164
- raw_output = chat.invoke(input=dict(system_message=system_message, user_text=user_text, chat_history=filtered_history))
165
- response = raw_output.split("HAL:")[-1].strip()
 
 
 
166
  if not response:
167
  response = "Certainly, here is an in-depth explanation: [Fallback explanation]."
168
 
@@ -182,13 +164,14 @@ def get_response(system_message, chat_history, user_text, max_new_tokens=1024):
182
  st.title("πŸš€ HAL - Your NASA AI Assistant")
183
  st.markdown("🌌 *Ask me about space, NASA, and beyond!*")
184
 
 
185
  if st.sidebar.button("Reset Chat"):
186
  st.session_state.chat_history = [{"role": "assistant", "content": "Hello! How can I assist you today?"}]
187
  st.session_state.response_ready = False
188
  st.session_state.follow_up = ""
189
  st.experimental_rerun()
190
 
191
- # --- Appearance CSS ---
192
  st.markdown("""
193
  <style>
194
  .user-msg {
@@ -220,14 +203,6 @@ st.markdown("""
220
  </style>
221
  """, unsafe_allow_html=True)
222
 
223
- st.markdown("<div class='container'>", unsafe_allow_html=True)
224
- for message in st.session_state.chat_history:
225
- if message["role"] == "user":
226
- st.markdown(f"<div class='user-msg'><strong>You:</strong> {message['content']}</div>", unsafe_allow_html=True)
227
- else:
228
- st.markdown(f"<div class='assistant-msg'><strong>HAL:</strong> {message['content']}</div>", unsafe_allow_html=True)
229
- st.markdown("</div>", unsafe_allow_html=True)
230
-
231
  user_input = st.chat_input("Type your message here...")
232
 
233
  if user_input:
@@ -240,3 +215,11 @@ if user_input:
240
  st.image(image_url, caption="NASA Image of the Day")
241
  st.session_state.follow_up = follow_up
242
  st.session_state.response_ready = True
 
 
 
 
 
 
 
 
 
1
  import os
2
  import re
3
  import random
 
4
  import requests
5
  import streamlit as st
 
6
  from langchain_huggingface import HuggingFaceEndpoint
7
  from langchain_core.prompts import PromptTemplate
8
  from langchain_core.output_parsers import StrOutputParser
 
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 ---
 
36
  revision="714eb0f"
37
  )
38
 
 
 
 
 
 
 
 
 
 
 
39
  def get_llm_hf_inference(model_id=model_id, max_new_tokens=128, temperature=0.7):
40
  return HuggingFaceEndpoint(
41
  repo_id=model_id,
42
  max_new_tokens=max_new_tokens,
43
  temperature=temperature,
44
+ token=HF_TOKEN,
45
  task="text-generation"
46
  )
47
 
48
  def get_nasa_apod():
49
+ url = f"https://api.nasa.gov/planetary/apod?api_key={NASA_API_KEY}"
50
  response = requests.get(url)
51
  if response.status_code == 200:
52
  data = response.json()
 
54
  else:
55
  return "", "NASA Data Unavailable", "I couldn't fetch data from NASA right now. Please try again later."
56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  def is_apod_query(user_text):
58
  """
59
  Checks if the user's question contains keywords indicating they are asking for
 
62
  keywords = ["apod", "image", "picture", "photo", "astronomy picture"]
63
  return any(keyword in user_text.lower() for keyword in keywords)
64
 
65
+ def analyze_sentiment(user_text):
66
+ result = sentiment_analyzer(user_text)[0]
67
+ return result['label']
68
+
69
+ def predict_action(user_text):
70
+ if "NASA" in user_text or "space" in user_text:
71
+ return "nasa_info"
72
+ return "general_query"
73
+
74
  def generate_follow_up(user_text):
75
  """
76
  Generates two variant follow-up questions and randomly selects one.
77
+ It also cleans up any unwanted quotation marks or extra meta commentary.
78
  """
79
  prompt_text = (
80
  f"Based on the user's question: '{user_text}', generate two concise, friendly follow-up questions "
81
  "that invite further discussion. For example, one might be 'Would you like to know more about the six types of quarks?' "
82
+ "and another might be 'Would you like to explore another aspect of quantum physics?' Do not include extra commentary ."
83
+ "Answer exclusively in English, and do not include extra commentary."
84
  )
85
  hf = get_llm_hf_inference(max_new_tokens=80, temperature=0.9)
86
  output = hf.invoke(input=prompt_text).strip()
 
90
  cleaned = ["Would you like to explore this topic further?"]
91
  return random.choice(cleaned)
92
 
93
+ def get_response(system_message, chat_history, user_text, max_new_tokens=512):
94
  """
95
+ Generates HAL's answer with depth and a follow-up question.
96
+ The prompt instructs the model to provide a detailed explanation and then generate a follow-up.
97
+ If the answer comes back empty, a fallback answer is used.
98
  """
99
  sentiment = analyze_sentiment(user_text)
100
  action = predict_action(user_text)
101
 
102
+ # Extract style instruction if present
103
+ style_instruction = ""
104
+ lower_text = user_text.lower()
105
+ if "in the voice of" in lower_text or "speaking as" in lower_text:
106
+ match = re.search(r"(in the voice of|speaking as)(.*)", lower_text)
107
+ if match:
108
+ style_instruction = match.group(2).strip().capitalize()
109
+ style_instruction = f" Please respond in the voice of {style_instruction}."
110
+
111
+ if action == "nasa_info":
112
  nasa_url, nasa_title, nasa_explanation = get_nasa_apod()
113
  response = f"**{nasa_title}**\n\n{nasa_explanation}"
114
  chat_history.append({'role': 'user', 'content': user_text})
 
116
  follow_up = generate_follow_up(user_text)
117
  chat_history.append({'role': 'assistant', 'content': follow_up})
118
  return response, follow_up, chat_history, nasa_url
119
+
 
120
  hf = get_llm_hf_inference(max_new_tokens=max_new_tokens, temperature=0.9)
121
  filtered_history = ""
122
  for message in chat_history:
 
124
  continue
125
  filtered_history += f"{message['role']}: {message['content']}\n"
126
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  style_clause = style_instruction if style_instruction else ""
128
 
129
+ # Instruct the model to generate a detailed, in-depth answer.
130
  prompt = PromptTemplate.from_template(
131
  (
132
  "[INST] {system_message}\n\nCurrent Conversation:\n{chat_history}\n\n"
133
  "User: {user_text}.\n [/INST]\n"
134
+ "AI: Please provide a detailed explanation in depth. "
135
+ "Ensure your response covers the topic thoroughly and is written in a friendly, conversational style, "
136
+ "starting with a phrase like 'Certainly!', 'Of course!', or 'Great question!'."
137
+ "Answer exclusively in English, and do not include extra commentary."+ style_clause +
138
  "\nHAL:"
139
  )
140
  )
141
 
142
  chat = prompt | hf.bind(skip_prompt=True) | StrOutputParser(output_key='content')
143
+ response = chat.invoke(input=dict(system_message=system_message, user_text=user_text, chat_history=filtered_history))
144
+ # Remove any extra markers if present.
145
+ response = response.split("HAL:")[-1].strip()
146
+
147
+ # Fallback in case the generated answer is empty
148
  if not response:
149
  response = "Certainly, here is an in-depth explanation: [Fallback explanation]."
150
 
 
164
  st.title("πŸš€ HAL - Your NASA AI Assistant")
165
  st.markdown("🌌 *Ask me about space, NASA, and beyond!*")
166
 
167
+ #Reset Button
168
  if st.sidebar.button("Reset Chat"):
169
  st.session_state.chat_history = [{"role": "assistant", "content": "Hello! How can I assist you today?"}]
170
  st.session_state.response_ready = False
171
  st.session_state.follow_up = ""
172
  st.experimental_rerun()
173
 
174
+ #Style and Appearance
175
  st.markdown("""
176
  <style>
177
  .user-msg {
 
203
  </style>
204
  """, unsafe_allow_html=True)
205
 
 
 
 
 
 
 
 
 
206
  user_input = st.chat_input("Type your message here...")
207
 
208
  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
218
+
219
+ st.markdown("<div class='container'>", unsafe_allow_html=True)
220
+ for message in st.session_state.chat_history:
221
+ if message["role"] == "user":
222
+ st.markdown(f"<div class='user-msg'><strong>You:</strong> {message['content']}</div>", unsafe_allow_html=True)
223
+ else:
224
+ st.markdown(f"<div class='assistant-msg'><strong>HAL:</strong> {message['content']}</div>", unsafe_allow_html=True)
225
+ st.markdown("</div>", unsafe_allow_html=True)