LiamKhoaLe commited on
Commit
1cad201
·
1 Parent(s): 3685b45

Upd img rendering APIs services

Browse files
api/__pycache__/chatbot.cpython-311.pyc ADDED
Binary file (23.6 kB). View file
 
api/__pycache__/routes.cpython-311.pyc ADDED
Binary file (17.2 kB). View file
 
api/chatbot.py CHANGED
@@ -179,17 +179,234 @@ class CookingTutorChatbot:
179
  if video_mode and video_results:
180
  response_data['videos'] = video_results
181
 
182
- # Add images if available
183
  if source_aggregation and 'images' in source_aggregation:
184
  images = source_aggregation['images']
185
  if images:
186
- response_data['images'] = images[:3] # Limit to 3 images
 
 
 
 
 
 
 
 
 
187
 
188
  # Return structured response if we have media, otherwise just text
189
  if len(response_data) > 1:
190
  return response_data
191
  return response.strip()
192
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  def _process_citations(self, response: str, url_mapping: Dict[int, str]) -> str:
194
  """Replace citation tags with actual URLs, handling both single and multiple references"""
195
 
 
179
  if video_mode and video_results:
180
  response_data['videos'] = video_results
181
 
182
+ # Process and integrate images for optimal frontend display
183
  if source_aggregation and 'images' in source_aggregation:
184
  images = source_aggregation['images']
185
  if images:
186
+ # Create enhanced image data with better frontend integration
187
+ enhanced_images = self._enhance_images_for_frontend(images[:3], user_query)
188
+ response_data['images'] = enhanced_images
189
+
190
+ # Create structured content with image placement suggestions
191
+ structured_content = self._create_structured_content(response.strip(), enhanced_images)
192
+ response_data['structured_content'] = structured_content
193
+
194
+ # Keep original text for backward compatibility
195
+ response_data['text'] = response.strip()
196
 
197
  # Return structured response if we have media, otherwise just text
198
  if len(response_data) > 1:
199
  return response_data
200
  return response.strip()
201
 
202
+ def _enhance_images_for_frontend(self, images: List[Dict], query: str) -> List[Dict]:
203
+ """Enhance image data for optimal frontend display"""
204
+ enhanced_images = []
205
+
206
+ for i, image in enumerate(images):
207
+ # Extract key information
208
+ image_url = image.get('url', '')
209
+ title = image.get('title', '')
210
+ source_url = image.get('source_url', '')
211
+ source = image.get('source', 'unknown')
212
+
213
+ # Generate contextual alt text and caption
214
+ alt_text = self._generate_image_alt_text(title, query, i)
215
+ caption = self._generate_image_caption(title, query, i)
216
+
217
+ # Determine image placement context
218
+ placement_context = self._determine_image_placement(query, i)
219
+
220
+ enhanced_image = {
221
+ 'id': f"img_{i+1}",
222
+ 'url': image_url,
223
+ 'alt_text': alt_text,
224
+ 'caption': caption,
225
+ 'title': title,
226
+ 'source_url': source_url,
227
+ 'source': source,
228
+ 'placement_context': placement_context,
229
+ 'display_order': i + 1,
230
+ 'aspect_ratio': '16:9', # Default, can be detected later
231
+ 'loading': 'lazy', # For performance
232
+ 'type': 'cooking_image'
233
+ }
234
+
235
+ enhanced_images.append(enhanced_image)
236
+
237
+ return enhanced_images
238
+
239
+ def _generate_image_alt_text(self, title: str, query: str, index: int) -> str:
240
+ """Generate descriptive alt text for accessibility"""
241
+ if title and len(title) > 10:
242
+ return f"Cooking image: {title}"
243
+
244
+ # Generate based on query context
245
+ query_lower = query.lower()
246
+ if 'recipe' in query_lower or 'cook' in query_lower:
247
+ return f"Recipe demonstration image {index + 1}"
248
+ elif 'ingredient' in query_lower:
249
+ return f"Ingredient showcase image {index + 1}"
250
+ elif 'technique' in query_lower or 'method' in query_lower:
251
+ return f"Cooking technique illustration {index + 1}"
252
+ else:
253
+ return f"Related cooking image {index + 1}"
254
+
255
+ def _generate_image_caption(self, title: str, query: str, index: int) -> str:
256
+ """Generate contextual caption for the image"""
257
+ if title and len(title) > 5:
258
+ return title
259
+
260
+ # Generate contextual captions
261
+ query_lower = query.lower()
262
+ if 'pad thai' in query_lower:
263
+ return f"Pad Thai cooking example {index + 1}"
264
+ elif 'fusion' in query_lower:
265
+ return f"Fusion cooking inspiration {index + 1}"
266
+ elif 'western' in query_lower:
267
+ return f"Western cooking technique {index + 1}"
268
+ else:
269
+ return f"Related cooking example {index + 1}"
270
+
271
+ def _determine_image_placement(self, query: str, index: int) -> str:
272
+ """Determine where the image should be placed in the text"""
273
+ query_lower = query.lower()
274
+
275
+ if index == 0:
276
+ if 'recipe' in query_lower or 'ingredient' in query_lower:
277
+ return 'after_ingredients'
278
+ elif 'technique' in query_lower or 'method' in query_lower:
279
+ return 'after_technique_intro'
280
+ else:
281
+ return 'after_intro'
282
+ elif index == 1:
283
+ return 'after_instructions'
284
+ else:
285
+ return 'after_tips'
286
+
287
+ def _integrate_images_inline(self, text: str, images: List[Dict]) -> str:
288
+ """Integrate images inline with text using placeholders for frontend rendering"""
289
+ if not images:
290
+ return text
291
+
292
+ # Split text into logical sections
293
+ sections = self._split_text_into_sections(text)
294
+
295
+ # Insert image placeholders at appropriate positions
296
+ enhanced_text = self._insert_image_placeholders(sections, images)
297
+
298
+ return enhanced_text
299
+
300
+ def _split_text_into_sections(self, text: str) -> List[Dict]:
301
+ """Split text into logical sections for image placement"""
302
+ sections = []
303
+ lines = text.split('\n')
304
+ current_section = {'type': 'intro', 'content': '', 'images': []}
305
+
306
+ for line in lines:
307
+ line_lower = line.lower().strip()
308
+
309
+ # Detect section types
310
+ if any(keyword in line_lower for keyword in ['ingredients:', 'ingredient list:', 'what you need:']):
311
+ if current_section['content'].strip():
312
+ sections.append(current_section)
313
+ current_section = {'type': 'ingredients', 'content': line + '\n', 'images': []}
314
+ elif any(keyword in line_lower for keyword in ['instructions:', 'directions:', 'how to cook:', 'steps:']):
315
+ if current_section['content'].strip():
316
+ sections.append(current_section)
317
+ current_section = {'type': 'instructions', 'content': line + '\n', 'images': []}
318
+ elif any(keyword in line_lower for keyword in ['tips:', 'troubleshooting:', 'notes:', 'variations:']):
319
+ if current_section['content'].strip():
320
+ sections.append(current_section)
321
+ current_section = {'type': 'tips', 'content': line + '\n', 'images': []}
322
+ else:
323
+ current_section['content'] += line + '\n'
324
+
325
+ if current_section['content'].strip():
326
+ sections.append(current_section)
327
+
328
+ return sections
329
+
330
+ def _insert_image_placeholders(self, sections: List[Dict], images: List[Dict]) -> str:
331
+ """Insert image placeholders at appropriate positions in sections"""
332
+ enhanced_sections = []
333
+ image_index = 0
334
+
335
+ for section in sections:
336
+ enhanced_sections.append(section['content'])
337
+
338
+ # Determine if this section should have an image
339
+ should_place_image = False
340
+ if image_index < len(images):
341
+ placement_context = images[image_index]['placement_context']
342
+
343
+ if (section['type'] == 'ingredients' and placement_context == 'after_ingredients') or \
344
+ (section['type'] == 'instructions' and placement_context == 'after_instructions') or \
345
+ (section['type'] == 'tips' and placement_context == 'after_tips') or \
346
+ (section['type'] == 'intro' and placement_context == 'after_intro'):
347
+ should_place_image = True
348
+
349
+ if should_place_image and image_index < len(images):
350
+ image = images[image_index]
351
+ # Insert image placeholder that frontend can replace
352
+ image_placeholder = f"\n\n[IMAGE_PLACEHOLDER:{image['id']}]\n\n"
353
+ enhanced_sections.append(image_placeholder)
354
+ image_index += 1
355
+
356
+ return ''.join(enhanced_sections)
357
+
358
+ def _create_structured_content(self, text: str, images: List[Dict]) -> List[Dict]:
359
+ """Create structured content blocks for optimal frontend rendering"""
360
+ if not images:
361
+ return [{'type': 'text', 'content': text}]
362
+
363
+ # Split text into logical sections
364
+ sections = self._split_text_into_sections(text)
365
+ structured_blocks = []
366
+
367
+ image_index = 0
368
+
369
+ for section in sections:
370
+ # Add text section
371
+ structured_blocks.append({
372
+ 'type': 'text',
373
+ 'content': section['content'].strip(),
374
+ 'section_type': section['type']
375
+ })
376
+
377
+ # Check if we should add an image after this section
378
+ if image_index < len(images):
379
+ image = images[image_index]
380
+ placement_context = image['placement_context']
381
+
382
+ should_add_image = (
383
+ (section['type'] == 'ingredients' and placement_context == 'after_ingredients') or
384
+ (section['type'] == 'instructions' and placement_context == 'after_instructions') or
385
+ (section['type'] == 'tips' and placement_context == 'after_tips') or
386
+ (section['type'] == 'intro' and placement_context == 'after_intro')
387
+ )
388
+
389
+ if should_add_image:
390
+ structured_blocks.append({
391
+ 'type': 'image',
392
+ 'image_data': image,
393
+ 'placement': 'after_section',
394
+ 'section_type': section['type']
395
+ })
396
+ image_index += 1
397
+
398
+ # Add any remaining images at the end
399
+ while image_index < len(images):
400
+ image = images[image_index]
401
+ structured_blocks.append({
402
+ 'type': 'image',
403
+ 'image_data': image,
404
+ 'placement': 'end'
405
+ })
406
+ image_index += 1
407
+
408
+ return structured_blocks
409
+
410
  def _process_citations(self, response: str, url_mapping: Dict[int, str]) -> str:
411
  """Replace citation tags with actual URLs, handling both single and multiple references"""
412
 
api/routes.py CHANGED
@@ -59,15 +59,17 @@ async def chat_endpoint(req: Request):
59
  )
60
  elapsed = time.time() - start
61
 
62
- # Handle response format (might be string or dict with videos/images)
63
  if isinstance(answer, dict):
64
  response_text = answer.get('text', '')
65
  video_data = answer.get('videos', [])
66
  image_data = answer.get('images', [])
 
67
  else:
68
  response_text = answer
69
  video_data = []
70
  image_data = []
 
71
 
72
  # Final response
73
  response_data = {"response": f"{response_text}\n\n(Response time: {elapsed:.2f}s)"}
@@ -80,6 +82,10 @@ async def chat_endpoint(req: Request):
80
  if image_data:
81
  response_data["images"] = image_data
82
 
 
 
 
 
83
  return JSONResponse(response_data)
84
 
85
  except Exception as e:
 
59
  )
60
  elapsed = time.time() - start
61
 
62
+ # Handle response format (might be string or dict with videos/images/structured content)
63
  if isinstance(answer, dict):
64
  response_text = answer.get('text', '')
65
  video_data = answer.get('videos', [])
66
  image_data = answer.get('images', [])
67
+ structured_content = answer.get('structured_content', [])
68
  else:
69
  response_text = answer
70
  video_data = []
71
  image_data = []
72
+ structured_content = []
73
 
74
  # Final response
75
  response_data = {"response": f"{response_text}\n\n(Response time: {elapsed:.2f}s)"}
 
82
  if image_data:
83
  response_data["images"] = image_data
84
 
85
+ # Include structured content for optimal frontend rendering
86
+ if structured_content:
87
+ response_data["structured_content"] = structured_content
88
+
89
  return JSONResponse(response_data)
90
 
91
  except Exception as e: