Update app.py
Browse files
app.py
CHANGED
@@ -1,302 +1,107 @@
|
|
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 |
-
# Add the current prompt
|
110 |
-
messages.append({
|
111 |
-
"role": "user",
|
112 |
-
"content": prompt
|
113 |
-
})
|
114 |
-
|
115 |
-
# Call OpenAI API
|
116 |
-
response = client.chat.completions.create(
|
117 |
-
model="gpt-3.5-turbo",
|
118 |
-
messages=messages,
|
119 |
-
temperature=0.7,
|
120 |
-
max_tokens=500,
|
121 |
-
stream=False
|
122 |
-
)
|
123 |
-
|
124 |
-
# Extract the response
|
125 |
-
return response.choices[0].message.content
|
126 |
-
|
127 |
-
except Exception as e:
|
128 |
-
st.error(f"An error occurred: {str(e)}")
|
129 |
-
return "I'm sorry, I encountered an error while processing your request. Please check your OpenAI API key or try again later."
|
130 |
-
|
131 |
-
# Demo mode responses for when no API key is available
|
132 |
-
def get_demo_response(prompt):
|
133 |
-
prompt_lower = prompt.lower()
|
134 |
-
|
135 |
-
# Simple response templates
|
136 |
-
greetings = [
|
137 |
-
"Hello! How can I assist you today?",
|
138 |
-
"Hi there! I'm a demo AI assistant. What can I help you with?",
|
139 |
-
"Greetings! I'm running in demo mode. Feel free to ask simple questions."
|
140 |
-
]
|
141 |
-
|
142 |
-
farewells = [
|
143 |
-
"Goodbye! Have a great day!",
|
144 |
-
"Farewell! Come back soon!",
|
145 |
-
"Take care! It was nice chatting with you."
|
146 |
-
]
|
147 |
-
|
148 |
-
info_responses = [
|
149 |
-
"I'm a simple AI assistant running in demo mode. To use the full features, please provide an OpenAI API key.",
|
150 |
-
"This is a demo version with limited capabilities. For a better experience, add your OpenAI API key.",
|
151 |
-
"I'm just demonstrating basic functionality. Get a free API key from OpenAI to unlock my full potential!"
|
152 |
-
]
|
153 |
-
|
154 |
-
reasoning_examples = [
|
155 |
-
"This is a demonstration of how I would process a reasoning task. In a real scenario with the full model, I would analyze the problem step by step, consider multiple angles, and provide a detailed explanation.",
|
156 |
-
"When solving problems, I would typically break them down into smaller parts, examine each component, and build towards a comprehensive solution. This demo just simulates that process.",
|
157 |
-
"Reasoning typically involves identifying key facts, applying logical rules, and drawing conclusions based on available information. With a proper API key, I could demonstrate this more effectively."
|
158 |
-
]
|
159 |
-
|
160 |
-
# Simple pattern matching
|
161 |
-
if any(word in prompt_lower for word in ["hello", "hi", "hey", "greetings"]):
|
162 |
-
return random.choice(greetings)
|
163 |
-
elif any(word in prompt_lower for word in ["bye", "goodbye", "farewell", "see you"]):
|
164 |
-
return random.choice(farewells)
|
165 |
-
elif any(phrase in prompt_lower for phrase in ["who are you", "what are you", "tell me about yourself", "what can you do"]):
|
166 |
-
return random.choice(info_responses)
|
167 |
-
elif any(word in prompt_lower for word in ["think", "reason", "analyze", "solve", "explain", "why", "how"]):
|
168 |
-
return random.choice(reasoning_examples)
|
169 |
-
elif "weather" in prompt_lower:
|
170 |
-
return "I'm sorry, I don't have access to real-time weather data in demo mode."
|
171 |
-
elif any(word in prompt_lower for word in ["help", "assist", "support"]):
|
172 |
-
return "To get better assistance, please add your OpenAI API key. You can get one for free at https://platform.openai.com/account/api-keys."
|
173 |
-
else:
|
174 |
-
return "I'm running in demo mode with limited responses. For a full conversation experience, please add your OpenAI API key above."
|
175 |
-
|
176 |
-
# Function to create a new conversation
|
177 |
-
def create_new_chat():
|
178 |
-
new_id = str(uuid.uuid4())
|
179 |
-
st.session_state.current_conversation_id = new_id
|
180 |
-
st.session_state.conversations[new_id] = {
|
181 |
-
"title": f"New chat {datetime.now().strftime('%H:%M')}",
|
182 |
-
"messages": []
|
183 |
-
}
|
184 |
-
|
185 |
-
# Function to update conversation title based on first message
|
186 |
-
def update_conversation_title(conv_id, user_message):
|
187 |
-
current_title = st.session_state.conversations[conv_id]["title"]
|
188 |
-
if current_title.startswith("New chat"):
|
189 |
-
# Limit title length to prevent overflow
|
190 |
-
new_title = user_message[:30] + "..." if len(user_message) > 30 else user_message
|
191 |
-
st.session_state.conversations[conv_id]["title"] = new_title
|
192 |
-
|
193 |
-
# Function to delete a conversation
|
194 |
-
def delete_conversation(conv_id):
|
195 |
-
if conv_id in st.session_state.conversations:
|
196 |
-
del st.session_state.conversations[conv_id]
|
197 |
-
# If we deleted the current conversation, set a new one
|
198 |
-
if conv_id == st.session_state.current_conversation_id:
|
199 |
-
if st.session_state.conversations:
|
200 |
-
st.session_state.current_conversation_id = next(iter(st.session_state.conversations))
|
201 |
-
else:
|
202 |
-
create_new_chat()
|
203 |
-
|
204 |
-
# Create a two-column layout
|
205 |
-
sidebar, main_content = st.columns([1, 3])
|
206 |
-
|
207 |
-
# Sidebar (conversation history)
|
208 |
-
with sidebar:
|
209 |
-
st.sidebar.title("Conversations")
|
210 |
-
|
211 |
-
# Add a new chat button
|
212 |
-
if st.sidebar.button("+ New Chat", use_container_width=True):
|
213 |
-
create_new_chat()
|
214 |
-
st.rerun()
|
215 |
-
|
216 |
-
st.sidebar.markdown("---")
|
217 |
-
|
218 |
-
# API token input in sidebar if not available
|
219 |
-
if not openai_api_key:
|
220 |
-
st.sidebar.info("⚠️ No OpenAI API key found.", icon="ℹ️")
|
221 |
-
entered_token = st.sidebar.text_input("Enter OpenAI API Key", type="password")
|
222 |
-
if entered_token:
|
223 |
-
openai_api_key = entered_token
|
224 |
-
client = openai.OpenAI(api_key=openai_api_key)
|
225 |
-
|
226 |
-
st.sidebar.markdown("---")
|
227 |
-
|
228 |
-
# Display conversation history
|
229 |
-
for conv_id, conv_data in st.session_state.conversations.items():
|
230 |
-
col1, col2 = st.sidebar.columns([4, 1])
|
231 |
-
is_active = conv_id == st.session_state.current_conversation_id
|
232 |
-
|
233 |
-
with col1:
|
234 |
-
if st.button(
|
235 |
-
conv_data["title"],
|
236 |
-
key=f"conv_{conv_id}",
|
237 |
-
use_container_width=True,
|
238 |
-
type="secondary" if is_active else "tertiary"
|
239 |
-
):
|
240 |
-
st.session_state.current_conversation_id = conv_id
|
241 |
-
st.rerun()
|
242 |
-
|
243 |
-
with col2:
|
244 |
-
if st.button("🗑️", key=f"del_{conv_id}"):
|
245 |
-
delete_conversation(conv_id)
|
246 |
-
st.rerun()
|
247 |
-
|
248 |
-
# Main content area
|
249 |
-
with main_content:
|
250 |
-
st.write("") # Add some space at the top
|
251 |
-
|
252 |
-
# Get current conversation
|
253 |
-
current_id = st.session_state.current_conversation_id
|
254 |
-
current_conv = st.session_state.conversations.get(current_id, {"messages": []})
|
255 |
-
messages = current_conv["messages"]
|
256 |
-
|
257 |
-
# Create a container for the chat area (scrollable)
|
258 |
-
chat_container = st.container()
|
259 |
-
|
260 |
-
# Display chat messages
|
261 |
-
with chat_container:
|
262 |
-
for i, message in enumerate(messages):
|
263 |
-
with st.chat_message(message["role"]):
|
264 |
-
st.markdown(message["content"])
|
265 |
-
|
266 |
-
# Chat input at the bottom
|
267 |
-
prompt = st.chat_input("What's on your mind?")
|
268 |
-
|
269 |
-
if prompt:
|
270 |
-
# Add user message to the current conversation
|
271 |
-
messages.append({"role": "user", "content": prompt})
|
272 |
-
|
273 |
-
# Update conversation title if this is the first message
|
274 |
-
if len(messages) == 1:
|
275 |
-
update_conversation_title(current_id, prompt)
|
276 |
-
|
277 |
-
# Display user message
|
278 |
-
with st.chat_message("user"):
|
279 |
-
st.markdown(prompt)
|
280 |
-
|
281 |
-
# Display assistant response with typing animation
|
282 |
-
with st.chat_message("assistant"):
|
283 |
-
message_placeholder = st.empty()
|
284 |
-
|
285 |
-
# Get response from AI
|
286 |
-
full_response = get_ai_response(prompt, messages[:-1])
|
287 |
-
|
288 |
-
# Simulate typing
|
289 |
-
displayed_response = ""
|
290 |
-
for i in range(len(full_response)):
|
291 |
-
displayed_response += full_response[i]
|
292 |
-
message_placeholder.markdown(displayed_response + "▌")
|
293 |
-
time.sleep(0.005) # Slightly faster typing
|
294 |
-
|
295 |
-
# Display final response
|
296 |
-
message_placeholder.markdown(full_response)
|
297 |
-
|
298 |
-
# Add assistant response to the conversation
|
299 |
-
messages.append({"role": "assistant", "content": full_response})
|
300 |
-
|
301 |
-
# Force a rerun to update the sidebar with the new conversation title
|
302 |
-
st.rerun()
|
|
|
1 |
+
---
|
2 |
+
title: GPT-Style Chat Assistant
|
3 |
+
emoji: 🤖
|
4 |
+
colorFrom: blue
|
5 |
+
colorTo: green
|
6 |
+
sdk: streamlit
|
7 |
+
sdk_version: 1.24.0
|
8 |
+
app_file: app.py
|
9 |
+
pinned: false
|
10 |
+
---
|
11 |
+
|
12 |
+
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
13 |
+
|
14 |
+
# GPT-Style Chat Assistant
|
15 |
+
|
16 |
+
A sophisticated Streamlit app that mimics the ChatGPT interface, using OpenAI's GPT models for advanced reasoning capabilities.
|
17 |
+
|
18 |
+

|
19 |
+
|
20 |
+
## Features
|
21 |
+
|
22 |
+
- **ChatGPT-like interface** with conversation sidebar
|
23 |
+
- **Multiple conversation management**:
|
24 |
+
- Create new chats
|
25 |
+
- Switch between conversations
|
26 |
+
- Delete old conversations
|
27 |
+
- **Model selection** - choose between different OpenAI models:
|
28 |
+
- GPT-3.5-Turbo (default)
|
29 |
+
- GPT-4
|
30 |
+
- GPT-3.5-Turbo-16k (for longer conversations)
|
31 |
+
- GPT-4-Turbo
|
32 |
+
- **Conversation history** preserved between sessions
|
33 |
+
- **Demo mode** that works without an API key
|
34 |
+
- **Responsive design** that adapts to different screen sizes
|
35 |
+
|
36 |
+
## Setup
|
37 |
+
|
38 |
+
1. Clone this repository
|
39 |
+
2. Install the required packages:
|
40 |
+
```
|
41 |
+
pip install -r requirements.txt
|
42 |
+
```
|
43 |
+
3. (Required for full functionality) Get an OpenAI API key:
|
44 |
+
- Create an account at [OpenAI](https://platform.openai.com/signup)
|
45 |
+
- Go to [API Keys](https://platform.openai.com/account/api-keys)
|
46 |
+
- Create a new API key
|
47 |
+
- Add it to a `.env` file in the root directory:
|
48 |
+
```
|
49 |
+
OPENAI_API_KEY=your_api_key_here
|
50 |
+
```
|
51 |
+
|
52 |
+
## Running Locally
|
53 |
+
|
54 |
+
Run the app with the following command:
|
55 |
+
|
56 |
+
```
|
57 |
+
streamlit run app.py
|
58 |
+
```
|
59 |
+
|
60 |
+
If you're having trouble with the `streamlit` command not being found, you can use the full path to the executable:
|
61 |
+
```
|
62 |
+
python -m streamlit run app.py
|
63 |
+
```
|
64 |
+
|
65 |
+
Or use the provided runner script:
|
66 |
+
```
|
67 |
+
python run_app.py
|
68 |
+
```
|
69 |
+
|
70 |
+
This will start the app and open it in your default browser.
|
71 |
+
|
72 |
+
## Demo Mode
|
73 |
+
|
74 |
+
The app includes a demo mode that works without an API key. In this mode:
|
75 |
+
- The assistant will provide pre-defined responses to common questions
|
76 |
+
- You'll see a text field in the sidebar where you can optionally enter an OpenAI API key
|
77 |
+
- For a full chatbot experience with reasoning capabilities, it's recommended to add your OpenAI API key
|
78 |
+
|
79 |
+
## Deploying to Hugging Face Spaces
|
80 |
+
|
81 |
+
1. Create a new Space on Hugging Face Spaces (https://huggingface.co/spaces)
|
82 |
+
2. Choose Streamlit as the SDK
|
83 |
+
3. Link your GitHub repository or upload the files directly
|
84 |
+
4. Add your OpenAI API key as a secret:
|
85 |
+
- Go to Settings > Repository Secrets
|
86 |
+
- Add a secret named `OPENAI_API_KEY` with your key
|
87 |
+
|
88 |
+
The app will automatically deploy and be available at your Hugging Face Spaces URL.
|
89 |
+
|
90 |
+
## About the Model
|
91 |
+
|
92 |
+
This app lets you select from multiple OpenAI models:
|
93 |
+
|
94 |
+
- **GPT-3.5-Turbo**: Fast and cost-effective, suitable for most tasks
|
95 |
+
- **GPT-4**: More capable but slower and more expensive
|
96 |
+
- **GPT-3.5-Turbo-16k**: Supports longer conversations with extended context window
|
97 |
+
- **GPT-4-Turbo**: OpenAI's most advanced model with significantly larger context window
|
98 |
+
|
99 |
+
You can select your preferred model in the sidebar. Note that model availability depends on your OpenAI API key permissions and subscription tier.
|
100 |
+
|
101 |
+
## Customization
|
102 |
+
|
103 |
+
You can easily customize the app by:
|
104 |
+
- Changing the model parameters in the `AVAILABLE_MODELS` dictionary
|
105 |
+
- Adjusting the styling in the CSS section
|
106 |
+
- Adding more features to the sidebar
|
107 |
+
- Creating additional response templates for the demo mode
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|