Download event_service.py from imkrish/chatbot: direct link, hf CLI and curl.
- Browser
- Download file 4.81 kB
-
https://huggingface.co/spaces/imkrish/chatbot/resolve/main/event_service.py
- Command line
-
hf download hf://spaces/imkrish/chatbot/event_service.py
-
curl -L -o event_service.py https://huggingface.co/spaces/imkrish/chatbot/resolve/main/event_service.py
4.81 kB
| """ | |
| Event Discovery Service | |
| Fetches and searches events from the backend API | |
| """ | |
| import requests | |
| import logging | |
| from typing import List, Dict, Optional | |
| from sentence_transformers import SentenceTransformer | |
| import numpy as np | |
| from sklearn.metrics.pairwise import cosine_similarity | |
| logger = logging.getLogger("chatbot.events") | |
| class EventService: | |
| def __init__(self, backend_url: str, model: SentenceTransformer): | |
| self.backend_url = backend_url | |
| self.model = model | |
| self.events_cache = [] | |
| self.events_embeddings = None | |
| def fetch_events(self) -> List[Dict]: | |
| """Fetch all approved public events from backend""" | |
| try: | |
| response = requests.get(f"{self.backend_url}/api/events", timeout=5) | |
| if response.status_code == 200: | |
| data = response.json() | |
| self.events_cache = data.get("data", {}).get("events", []) | |
| logger.info(f"Fetched {len(self.events_cache)} events from backend") | |
| # Pre-compute embeddings for all events | |
| self._compute_event_embeddings() | |
| return self.events_cache | |
| else: | |
| logger.error(f"Failed to fetch events: {response.status_code}") | |
| return [] | |
| except Exception as e: | |
| logger.error(f"Error fetching events: {e}") | |
| return [] | |
| def _compute_event_embeddings(self): | |
| """Compute embeddings for all events""" | |
| if not self.events_cache: | |
| return | |
| event_texts = [] | |
| for event in self.events_cache: | |
| # Combine title, description, and tags for better matching | |
| text = f"{event.get('title', '')} {event.get('description', '')} {' '.join(event.get('tags', []))}" | |
| event_texts.append(text) | |
| self.events_embeddings = self.model.encode(event_texts, convert_to_tensor=False) | |
| logger.info(f"Computed embeddings for {len(event_texts)} events") | |
| def search_events(self, query: str, top_k: int = 5) -> List[Dict]: | |
| """Search events using semantic similarity""" | |
| if not self.events_cache or self.events_embeddings is None: | |
| self.fetch_events() | |
| if not self.events_cache: | |
| logger.warning("No events available in cache") | |
| return [] | |
| # Encode user query | |
| query_embedding = self.model.encode([query], convert_to_tensor=False) | |
| # Calculate cosine similarity | |
| similarities = cosine_similarity(query_embedding, self.events_embeddings)[0] | |
| # Log similarity scores for debugging | |
| logger.info(f"Query: {query}") | |
| logger.info(f"Similarity scores: min={similarities.min():.3f}, max={similarities.max():.3f}, mean={similarities.mean():.3f}") | |
| # Get top k indices | |
| top_indices = np.argsort(similarities)[::-1][:top_k] | |
| # Filter events with similarity > threshold (lowered to 0.15 for better recall) | |
| results = [] | |
| for idx in top_indices: | |
| score = similarities[idx] | |
| if score > 0.15: # Lowered threshold | |
| event = self.events_cache[idx].copy() | |
| event['similarity_score'] = float(score) | |
| results.append(event) | |
| logger.info(f" Event '{event.get('title', 'Untitled')}' matched with score {score:.3f}") | |
| logger.info(f"Found {len(results)} matching events for query: {query}") | |
| return results | |
| def format_event_response(self, events: List[Dict]) -> str: | |
| """Format events into a conversational response""" | |
| if not events: | |
| return "Sorry, I couldn't find any events matching your query. Try searching for something like 'hackathon', 'AI workshop', or 'coding competition'." | |
| response = f"I found {len(events)} event(s) for you:\n\n" | |
| for i, event in enumerate(events, 1): | |
| title = event.get('title', 'Untitled Event') | |
| date = event.get('date', 'TBA')[:10] if event.get('date') else 'TBA' | |
| description = event.get('description', '') | |
| # Truncate description | |
| if len(description) > 100: | |
| description = description[:97] + "..." | |
| response += f"{i}. **{title}**\n" | |
| response += f" ๐ Date: {date}\n" | |
| if description: | |
| response += f" ๐ {description}\n" | |
| # Add website link if available | |
| if event.get('socialLinks', {}).get('website'): | |
| response += f" ๐ [More Info]({event['socialLinks']['website']})\n" | |
| response += "\n" | |
| return response.strip() | |