jzou19950715 commited on
Commit
b5fdd97
·
verified ·
1 Parent(s): 8e8b790

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +132 -93
app.py CHANGED
@@ -4,6 +4,7 @@ import requests
4
  import json
5
  from typing import List, Dict, Optional, Tuple
6
  import random
 
7
 
8
  class GifChatBot:
9
  def __init__(self):
@@ -13,46 +14,68 @@ class GifChatBot:
13
  self.is_initialized = False
14
  self.session = requests.Session()
15
 
16
- # Define size constraints
17
- self.MINIMUM_FILE_SIZE = 500 * 1024 # 500KB in bytes
18
- self.MAXIMUM_FILE_SIZE = 5 * 1024 * 1024 # 5MB in bytes
19
- self.MAX_RETRIES = 10 # Maximum number of retries for finding a good GIF
20
 
21
- def verify_gif_size(self, gif_url: str) -> bool:
22
- """Verify if GIF meets size requirements"""
23
  try:
24
- # Do HEAD request to get content length
25
- response = self.session.head(gif_url, timeout=3)
26
- if response.status_code != 200:
27
- return False
28
-
29
- # Get content length
30
- content_length = response.headers.get('content-length')
31
- if not content_length:
32
- return False
33
-
34
- file_size = int(content_length)
35
- return self.MINIMUM_FILE_SIZE <= file_size <= self.MAXIMUM_FILE_SIZE
36
-
37
  except Exception as error:
38
- print(f"Size verification error: {error}")
39
- return False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
  def get_gif(self, search_query: str) -> Optional[str]:
42
- """Get a GIF meeting size requirements with retries"""
43
- for attempt in range(self.MAX_RETRIES):
 
 
 
 
 
 
44
  try:
45
- # Calculate offset based on attempt number to get different results
46
- offset = attempt * 10
47
 
48
  params = {
49
  'api_key': self.giphy_key,
50
  'q': search_query,
51
- 'limit': 10,
52
  'offset': offset,
53
  'rating': 'pg-13'
54
  }
55
 
 
 
56
  response = self.session.get(
57
  "https://api.giphy.com/v1/gifs/search",
58
  params=params,
@@ -61,32 +84,52 @@ class GifChatBot:
61
 
62
  if response.status_code == 200:
63
  data = response.json()
64
- if data["data"]:
65
- # Shuffle results for variety
66
- gifs = list(data["data"])
67
- random.shuffle(gifs)
68
-
69
- # Try each GIF until we find one meeting size requirements
70
- for gif in gifs:
71
- gif_url = gif["images"]["original"]["url"]
72
- if self.verify_gif_size(gif_url):
73
- print(f"Found valid GIF on attempt {attempt + 1}")
74
- return gif_url
75
-
76
- print(f"No valid GIFs found in attempt {attempt + 1}, retrying...")
77
- else:
78
  print("No GIFs found in search")
79
  break
80
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  except Exception as error:
82
- print(f"Error in attempt {attempt + 1}: {error}")
83
- continue
84
 
85
  # If we get here, try trending as last resort
 
86
  return self._get_trending_gif()
87
 
88
  def _get_trending_gif(self) -> Optional[str]:
89
- """Get a trending GIF meeting size requirements"""
 
 
90
  try:
91
  params = {
92
  'api_key': self.giphy_key,
@@ -94,6 +137,8 @@ class GifChatBot:
94
  'rating': 'pg-13'
95
  }
96
 
 
 
97
  response = self.session.get(
98
  "https://api.giphy.com/v1/gifs/trending",
99
  params=params,
@@ -102,53 +147,39 @@ class GifChatBot:
102
 
103
  if response.status_code == 200:
104
  data = response.json()
105
- if data["data"]:
106
- gifs = list(data["data"])
107
- random.shuffle(gifs)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
 
109
- for gif in gifs:
110
- gif_url = gif["images"]["original"]["url"]
111
- if self.verify_gif_size(gif_url):
112
- print("Found valid trending GIF")
113
- return gif_url
114
-
115
  except Exception as error:
116
  print(f"Trending GIF error: {error}")
 
 
117
  return None
118
 
119
- def setup_keys(self, openai_key: str, giphy_key: str) -> str:
120
- """Initialize API clients with user's keys"""
121
- try:
122
- self.openai_client = OpenAI(api_key=openai_key)
123
- self.giphy_key = giphy_key
124
- self._test_giphy_key()
125
- self._test_openai_key()
126
- self.is_initialized = True
127
- return "✅ Setup successful! Let's chat!"
128
- except Exception as error:
129
- self.is_initialized = False
130
- return f"❌ Error setting up: {str(error)}"
131
-
132
- def _test_giphy_key(self):
133
- """Test if GIPHY key is valid"""
134
- response = self.session.get(
135
- "https://api.giphy.com/v1/gifs/trending",
136
- params={"api_key": self.giphy_key, "limit": 1}
137
- )
138
- if response.status_code != 200:
139
- raise Exception("Invalid GIPHY API key")
140
-
141
- def _test_openai_key(self):
142
- """Test if OpenAI key is valid"""
143
- try:
144
- self.openai_client.chat.completions.create(
145
- model="gpt-4o-mini",
146
- messages=[{"role": "user", "content": "test"}],
147
- max_tokens=5
148
- )
149
- except Exception:
150
- raise Exception("Invalid OpenAI API key")
151
-
152
  def reset_chat(self) -> Tuple[List[Dict[str, str]], str]:
153
  """Reset the chat history"""
154
  self.chat_history = []
@@ -167,7 +198,7 @@ class GifChatBot:
167
  return message, history, ""
168
 
169
  try:
170
- # System message emphasizing natural GIF usage
171
  system_message = """You are a supportive, empathetic friend who uses GIFs naturally in conversation.
172
  When using GIFs, keep search terms simple and contextual:
173
 
@@ -179,10 +210,11 @@ class GifChatBot:
179
 
180
  Keep your responses:
181
  1. Empathetic and natural
182
- 2. Context-aware (reference previous messages)
183
- 3. Use GIFs that match the emotion
184
 
185
- Use 0-1 GIFs per message unless the moment really calls for more."""
 
186
 
187
  # Prepare conversation history
188
  messages = [{"role": "system", "content": system_message}]
@@ -202,6 +234,7 @@ class GifChatBot:
202
  ai_message = response.choices[0].message.content
203
  final_response = ""
204
 
 
205
  parts = ai_message.split("[GIF:")
206
  final_response += parts[0]
207
 
@@ -209,19 +242,23 @@ class GifChatBot:
209
  gif_desc_end = part.find("]")
210
  if gif_desc_end != -1:
211
  gif_desc = part[:gif_desc_end].strip()
212
- print(f"Searching for GIF: {gif_desc}")
213
  gif_url = self.get_gif(gif_desc)
214
  if gif_url:
215
  final_response += f"\n![GIF]({gif_url})\n"
216
- print(f"Added GIF: {gif_url}")
 
 
217
  final_response += part[gif_desc_end + 1:]
218
 
 
219
  history.append(self.format_message("user", message))
220
  history.append(self.format_message("assistant", final_response))
221
  return "", history, ""
222
 
223
  except Exception as error:
224
  error_message = f"Oops! Something went wrong: {str(error)}"
 
225
  return message, history, error_message
226
 
227
  def create_interface():
@@ -258,7 +295,7 @@ def create_interface():
258
  label="Chat",
259
  bubble_full_width=False,
260
  height=450,
261
- type="messages"
262
  )
263
 
264
  with gr.Row():
@@ -298,6 +335,8 @@ def create_interface():
298
  - 💭 The conversation is context-aware
299
  - 🎯 GIFs are chosen to match the emotion
300
  - 🔄 Use 'Clear Chat' to start fresh
 
 
301
  """)
302
 
303
  return interface
 
4
  import json
5
  from typing import List, Dict, Optional, Tuple
6
  import random
7
+ import time
8
 
9
  class GifChatBot:
10
  def __init__(self):
 
14
  self.is_initialized = False
15
  self.session = requests.Session()
16
 
17
+ # Configure session for better performance
18
+ self.session.headers.update({
19
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
20
+ })
21
 
22
+ def setup_keys(self, openai_key: str, giphy_key: str) -> str:
23
+ """Initialize API clients with user's keys"""
24
  try:
25
+ self.openai_client = OpenAI(api_key=openai_key)
26
+ self.giphy_key = giphy_key
27
+ # Test both keys
28
+ self._test_giphy_key()
29
+ self._test_openai_key()
30
+ self.is_initialized = True
31
+ return "✅ Setup successful! Let's chat!"
 
 
 
 
 
 
32
  except Exception as error:
33
+ self.is_initialized = False
34
+ return f"❌ Error setting up: {str(error)}"
35
+
36
+ def _test_giphy_key(self):
37
+ """Test if GIPHY key is valid"""
38
+ response = self.session.get(
39
+ "https://api.giphy.com/v1/gifs/trending",
40
+ params={"api_key": self.giphy_key, "limit": 1}
41
+ )
42
+ if response.status_code != 200:
43
+ raise Exception("Invalid GIPHY API key")
44
+
45
+ def _test_openai_key(self):
46
+ """Test if OpenAI key is valid"""
47
+ try:
48
+ self.openai_client.chat.completions.create(
49
+ model="gpt-4o-mini",
50
+ messages=[{"role": "user", "content": "test"}],
51
+ max_tokens=5
52
+ )
53
+ except Exception:
54
+ raise Exception("Invalid OpenAI API key")
55
 
56
  def get_gif(self, search_query: str) -> Optional[str]:
57
+ """Search for a GIF with strict size requirements"""
58
+ total_attempts = 0
59
+ max_total_attempts = 3 # Maximum pagination attempts
60
+ minimum_size_bytes = 500000 # 500KB in bytes
61
+
62
+ print(f"\nSearching for GIF: {search_query}")
63
+
64
+ while total_attempts < max_total_attempts:
65
  try:
66
+ # Calculate offset for pagination
67
+ offset = total_attempts * 25
68
 
69
  params = {
70
  'api_key': self.giphy_key,
71
  'q': search_query,
72
+ 'limit': 25,
73
  'offset': offset,
74
  'rating': 'pg-13'
75
  }
76
 
77
+ print(f"Attempt {total_attempts + 1} with offset {offset}")
78
+
79
  response = self.session.get(
80
  "https://api.giphy.com/v1/gifs/search",
81
  params=params,
 
84
 
85
  if response.status_code == 200:
86
  data = response.json()
87
+ if not data.get("data"):
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  print("No GIFs found in search")
89
  break
90
+
91
+ print(f"Found {len(data['data'])} GIFs, filtering by size...")
92
+
93
+ # Filter GIFs by size first
94
+ valid_gifs = []
95
+ for gif in data["data"]:
96
+ try:
97
+ # Get size from original image data
98
+ size_str = gif["images"]["original"]["size"]
99
+ if size_str and size_str.isdigit():
100
+ size_bytes = int(size_str)
101
+ if size_bytes >= minimum_size_bytes:
102
+ valid_gifs.append(gif)
103
+ print(f"Found valid GIF: {size_bytes / 1024:.2f}KB")
104
+ except (KeyError, ValueError) as e:
105
+ print(f"Size parsing error for GIF: {e}")
106
+ continue
107
+
108
+ if valid_gifs:
109
+ # Randomly select from valid GIFs
110
+ chosen_gif = random.choice(valid_gifs)
111
+ url = chosen_gif["images"]["original"]["url"]
112
+ size = int(chosen_gif["images"]["original"]["size"])
113
+ print(f"Selected GIF URL: {url}")
114
+ print(f"Selected GIF size: {size / 1024:.2f}KB")
115
+ return url
116
+
117
+ print(f"No GIFs >= 500KB found in attempt {total_attempts + 1}")
118
+
119
+ total_attempts += 1
120
+
121
  except Exception as error:
122
+ print(f"Error in attempt {total_attempts + 1}: {error}")
123
+ total_attempts += 1
124
 
125
  # If we get here, try trending as last resort
126
+ print("No suitable GIFs found in search, trying trending...")
127
  return self._get_trending_gif()
128
 
129
  def _get_trending_gif(self) -> Optional[str]:
130
+ """Get a trending GIF with size verification"""
131
+ minimum_size_bytes = 500000 # 500KB in bytes
132
+
133
  try:
134
  params = {
135
  'api_key': self.giphy_key,
 
137
  'rating': 'pg-13'
138
  }
139
 
140
+ print("Fetching trending GIFs...")
141
+
142
  response = self.session.get(
143
  "https://api.giphy.com/v1/gifs/trending",
144
  params=params,
 
147
 
148
  if response.status_code == 200:
149
  data = response.json()
150
+ if data.get("data"):
151
+ print(f"Found {len(data['data'])} trending GIFs, filtering by size...")
152
+
153
+ # Filter by size first
154
+ valid_gifs = []
155
+ for gif in data["data"]:
156
+ try:
157
+ size_str = gif["images"]["original"]["size"]
158
+ if size_str and size_str.isdigit():
159
+ size_bytes = int(size_str)
160
+ if size_bytes >= minimum_size_bytes:
161
+ valid_gifs.append(gif)
162
+ print(f"Found valid trending GIF: {size_bytes / 1024:.2f}KB")
163
+ except (KeyError, ValueError) as e:
164
+ print(f"Size parsing error for trending GIF: {e}")
165
+ continue
166
+
167
+ if valid_gifs:
168
+ chosen_gif = random.choice(valid_gifs)
169
+ url = chosen_gif["images"]["original"]["url"]
170
+ size = int(chosen_gif["images"]["original"]["size"])
171
+ print(f"Selected trending GIF URL: {url}")
172
+ print(f"Selected trending GIF size: {size / 1024:.2f}KB")
173
+ return url
174
 
175
+ print("No valid trending GIFs found")
176
+
 
 
 
 
177
  except Exception as error:
178
  print(f"Trending GIF error: {error}")
179
+
180
+ print("Failed to find any suitable GIFs")
181
  return None
182
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
  def reset_chat(self) -> Tuple[List[Dict[str, str]], str]:
184
  """Reset the chat history"""
185
  self.chat_history = []
 
198
  return message, history, ""
199
 
200
  try:
201
+ # System message for the AI
202
  system_message = """You are a supportive, empathetic friend who uses GIFs naturally in conversation.
203
  When using GIFs, keep search terms simple and contextual:
204
 
 
210
 
211
  Keep your responses:
212
  1. Empathetic and natural
213
+ 2. Context-aware (reference previous messages when relevant)
214
+ 3. Use GIFs that match the emotional context
215
 
216
+ Use 0-1 GIFs per message unless the moment really calls for more.
217
+ Keep search terms simple and universal for better GIF matching."""
218
 
219
  # Prepare conversation history
220
  messages = [{"role": "system", "content": system_message}]
 
234
  ai_message = response.choices[0].message.content
235
  final_response = ""
236
 
237
+ # Split by GIF markers and process
238
  parts = ai_message.split("[GIF:")
239
  final_response += parts[0]
240
 
 
242
  gif_desc_end = part.find("]")
243
  if gif_desc_end != -1:
244
  gif_desc = part[:gif_desc_end].strip()
245
+ print(f"\nProcessing GIF request: {gif_desc}")
246
  gif_url = self.get_gif(gif_desc)
247
  if gif_url:
248
  final_response += f"\n![GIF]({gif_url})\n"
249
+ print(f"Successfully added GIF: {gif_url}")
250
+ else:
251
+ print("Failed to find suitable GIF")
252
  final_response += part[gif_desc_end + 1:]
253
 
254
+ # Update history with new messages
255
  history.append(self.format_message("user", message))
256
  history.append(self.format_message("assistant", final_response))
257
  return "", history, ""
258
 
259
  except Exception as error:
260
  error_message = f"Oops! Something went wrong: {str(error)}"
261
+ print(f"Chat error: {error}")
262
  return message, history, error_message
263
 
264
  def create_interface():
 
295
  label="Chat",
296
  bubble_full_width=False,
297
  height=450,
298
+ type="messages" # Use new message format
299
  )
300
 
301
  with gr.Row():
 
335
  - 💭 The conversation is context-aware
336
  - 🎯 GIFs are chosen to match the emotion
337
  - 🔄 Use 'Clear Chat' to start fresh
338
+
339
+ Note: GIFs are carefully validated to ensure quality (minimum 500KB size).
340
  """)
341
 
342
  return interface