Spaces:
Sleeping
Sleeping
| from gtts import gTTS | |
| import io | |
| import gradio as gr | |
| from datetime import datetime, timedelta | |
| import json | |
| class MemoryHandler: | |
| def __init__(self): | |
| self.conversation_history = [] | |
| self.max_history = 5 # Keep last 5 interactions | |
| self.context_timeout = timedelta(minutes=2) # Context expires after 2 minutes | |
| self.last_interaction_time = None | |
| self.partial_info = { | |
| 'project_number': None, | |
| 'project_name': None, | |
| 'amount': None, | |
| 'reason': None, | |
| 'timestamp': None | |
| } | |
| self.confidence_scores = { | |
| 'project_number': 0.0, | |
| 'project_name': 0.0, | |
| 'amount': 0.0, | |
| 'reason': 0.0 | |
| } | |
| def add_interaction(self, text: str, extracted_info: dict = None) -> None: | |
| """ | |
| Add a new interaction to the conversation history and update partial information | |
| Args: | |
| text: The text from the voice/text input | |
| extracted_info: Dictionary containing extracted request details | |
| """ | |
| current_time = datetime.now() | |
| # Check if we should clear context due to timeout | |
| if self.last_interaction_time and \ | |
| (current_time - self.last_interaction_time) > self.context_timeout: | |
| self.clear_partial_info() | |
| # Update conversation history | |
| if text: | |
| # Add timestamp to conversation history | |
| self.conversation_history.append({ | |
| 'text': text, | |
| 'timestamp': current_time.isoformat(), | |
| 'extracted_info': extracted_info | |
| }) | |
| if len(self.conversation_history) > self.max_history: | |
| self.conversation_history.pop(0) | |
| # Update partial information if provided | |
| if extracted_info: | |
| self._update_partial_info(extracted_info, current_time) | |
| self.last_interaction_time = current_time | |
| def _update_partial_info(self, extracted_info: dict, current_time: datetime) -> None: | |
| """ | |
| Update partial information with confidence scoring | |
| """ | |
| for key in self.partial_info: | |
| if key in extracted_info and extracted_info[key]: | |
| new_value = extracted_info[key] | |
| current_value = self.partial_info[key] | |
| # Update if empty or higher confidence | |
| if (current_value is None or | |
| extracted_info.get(f'{key}_confidence', 0.5) > | |
| self.confidence_scores.get(key, 0)): | |
| self.partial_info[key] = new_value | |
| self.confidence_scores[key] = extracted_info.get(f'{key}_confidence', 0.5) | |
| self.partial_info['timestamp'] = current_time | |
| def get_context(self) -> str: | |
| """ | |
| Get the current conversation context including partial information | |
| """ | |
| # Start with the most recent conversation history | |
| context_parts = [] | |
| # Add conversation history with timestamps | |
| for entry in self.conversation_history: | |
| timestamp = datetime.fromisoformat(entry['timestamp']).strftime('%H:%M:%S') | |
| context_parts.append(f"[{timestamp}] {entry['text']}") | |
| context = " ".join(context_parts) | |
| # Add partial information to context if available | |
| partial_context = [] | |
| for key, value in self.partial_info.items(): | |
| if value and key != 'timestamp': | |
| confidence = self.confidence_scores.get(key, 0) | |
| partial_context.append(f"{key}: {value} (confidence: {confidence:.2f})") | |
| if partial_context: | |
| context += "\nPartial information: " + ", ".join(partial_context) | |
| return context | |
| def get_partial_info(self) -> dict: | |
| """Get current partial information with confidence scores""" | |
| info = {k: v for k, v in self.partial_info.items() | |
| if k != 'timestamp' and v is not None} | |
| info['confidence_scores'] = self.confidence_scores | |
| return info | |
| def merge_partial_info(self, new_info: dict) -> None: | |
| """ | |
| Merge new information with existing partial info based on confidence scores | |
| """ | |
| for key in self.partial_info: | |
| if key in new_info and new_info[key] is not None: | |
| new_confidence = new_info.get(f'{key}_confidence', 0.5) | |
| if (self.partial_info[key] is None or | |
| new_confidence > self.confidence_scores.get(key, 0)): | |
| self.partial_info[key] = new_info[key] | |
| self.confidence_scores[key] = new_confidence | |
| def clear_partial_info(self) -> None: | |
| """Clear partial information and confidence scores""" | |
| self.partial_info = { | |
| 'project_number': None, | |
| 'project_name': None, | |
| 'amount': None, | |
| 'reason': None, | |
| 'timestamp': None | |
| } | |
| self.confidence_scores = { | |
| 'project_number': 0.0, | |
| 'project_name': 0.0, | |
| 'amount': 0.0, | |
| 'reason': 0.0 | |
| } | |
| def clear_memory(self) -> None: | |
| """Clear all conversation history and partial information""" | |
| self.conversation_history = [] | |
| self.clear_partial_info() | |
| self.last_interaction_time = None | |
| return "Memory cleared!" | |
| def get_missing_fields(self) -> list: | |
| """Get list of missing required fields with confidence thresholds""" | |
| missing = [] | |
| confidence_threshold = 0.5 # Minimum confidence required | |
| for field in ['project_number', 'project_name', 'amount', 'reason']: | |
| if (self.partial_info.get(field) is None or | |
| self.confidence_scores.get(field, 0) < confidence_threshold): | |
| missing.append(field) | |
| return missing | |
| def text_to_speech(self, text: str) -> tuple[str, str]: | |
| """Convert text to speech and return audio path""" | |
| try: | |
| tts = gTTS(text=text, lang='en') | |
| audio_path = "temp_audio.mp3" | |
| tts.save(audio_path) | |
| return audio_path, None | |
| except Exception as e: | |
| return None, f"Error generating audio: {str(e)}" | |
| def create_confirmation_audio(self, project_number: str, project_name: str, | |
| amount: float, reason: str) -> tuple[str, str]: | |
| """Create confirmation message audio with confidence information""" | |
| confidence_info = "\n".join([ | |
| f"{field}: {self.confidence_scores.get(field, 0):.2f} confidence" | |
| for field in ['project_number', 'project_name', 'amount', 'reason'] | |
| ]) | |
| confirmation_text = ( | |
| f"You are going to add request money for project ID: {project_number}, " | |
| f"Project name: {project_name}, request amount: {amount}, " | |
| f"reason: {reason}.\n\nConfidence scores:\n{confidence_info}\n" | |
| f"Are you sure you want to proceed?" | |
| ) | |
| return self.text_to_speech(confirmation_text) | |
| def get_prompt_for_missing_info(self) -> str: | |
| """Generate a prompt for missing information with confidence scores""" | |
| missing = self.get_missing_fields() | |
| if not missing: | |
| return "All required information has been provided with sufficient confidence." | |
| current_info = self.get_partial_info() | |
| prompt = "Current information:\n" | |
| # Show current information with confidence scores | |
| for key, value in current_info.items(): | |
| if key != 'confidence_scores' and value is not None: | |
| confidence = self.confidence_scores.get(key, 0) | |
| prompt += f"- {key}: {value} (confidence: {confidence:.2f})\n" | |
| prompt += "\nPlease provide or clarify the following information:\n" | |
| for field in missing: | |
| current_confidence = self.confidence_scores.get(field, 0) | |
| if current_confidence > 0: | |
| prompt += f"- {field} (current confidence: {current_confidence:.2f}, needs improvement)\n" | |
| else: | |
| prompt += f"- {field} (missing)\n" | |
| return prompt | |
| def to_json(self) -> str: | |
| """Serialize the memory state to JSON""" | |
| return json.dumps({ | |
| 'conversation_history': self.conversation_history, | |
| 'partial_info': self.partial_info, | |
| 'confidence_scores': self.confidence_scores, | |
| 'last_interaction_time': self.last_interaction_time.isoformat() if self.last_interaction_time else None | |
| }) | |
| def from_json(self, json_str: str) -> None: | |
| """Restore memory state from JSON""" | |
| data = json.loads(json_str) | |
| self.conversation_history = data['conversation_history'] | |
| self.partial_info = data['partial_info'] | |
| self.confidence_scores = data['confidence_scores'] | |
| self.last_interaction_time = (datetime.fromisoformat(data['last_interaction_time']) | |
| if data['last_interaction_time'] else None) |