File size: 9,458 Bytes
c82da72
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
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)