File size: 8,894 Bytes
4d65b38
6574244
14505b3
 
80552c3
4d65b38
 
80552c3
14505b3
 
 
4d65b38
14505b3
 
 
 
 
6574244
 
 
 
 
 
80552c3
4d65b38
 
6574244
 
 
 
 
14505b3
6574244
 
 
 
 
4d65b38
 
 
 
14505b3
 
6574244
4d65b38
14505b3
6574244
 
 
4d65b38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6574244
4d65b38
 
14505b3
 
4d65b38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14505b3
 
 
6574244
 
 
 
 
80552c3
6574244
 
 
14505b3
6574244
14505b3
6574244
 
 
 
14505b3
 
 
6574244
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4d65b38
 
6574244
 
 
 
 
4d65b38
6574244
 
 
 
 
 
14505b3
6574244
4d65b38
 
 
6574244
 
 
 
4d65b38
6574244
 
 
 
4d65b38
6574244
 
4d65b38
 
 
 
 
6574244
e916879
6574244
 
e916879
 
 
 
6574244
 
 
e916879
6574244
 
 
e916879
4d65b38
e916879
6574244
 
 
 
 
 
 
 
 
 
 
 
4d65b38
 
 
 
 
23c62ec
 
 
 
 
 
 
 
b840602
23c62ec
6574244
 
4d65b38
 
 
 
 
 
 
 
 
 
23c62ec
e916879
 
 
 
 
 
 
b840602
e916879
 
 
14505b3
6574244
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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# app.py (Simplified & Robust Meeting Summarizer)
import gradio as gr
import threading
import queue
import time
import wave
import os
from datetime import datetime
from analyzer import MeetingAnalyzer
from integrations import Notifier
import config
import speech_recognition as sr

class MeetingProcessor:
    def __init__(self):
        self.analyzer = MeetingAnalyzer()
        self.notifier = Notifier()
        self.running = False
        self.start_time = None
        self.transcript_history = []
        self.summary = ""
        self.action_items = []
        self.urgent_alerts = []
        self.transcript_queue = queue.Queue()
        self.recording_file = None
        self.recognizer = sr.Recognizer()
        
    def start_processing(self):
        if self.running:
            return "Already running!"
            
        self.running = True
        self.start_time = time.time()
        self.transcript_history = []
        self.summary = ""
        self.action_items = []
        self.urgent_alerts = []
        
        # Create a unique filename for this recording
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        self.recording_file = f"meeting_{timestamp}.wav"
        
        # Start processing threads
        threading.Thread(target=self._audio_capture_thread, daemon=True).start()
        threading.Thread(target=self._transcription_thread, daemon=True).start()
        
        return "Meeting processing started! 🎤"
    
    def _audio_capture_thread(self):
        """Capture audio from microphone and save to file"""
        try:
            with sr.Microphone() as source:
                print("Adjusting for ambient noise...")
                self.recognizer.adjust_for_ambient_noise(source, duration=1)
                print("Microphone ready! Recording meeting...")
                
                # Start recording
                audio = self.recognizer.listen(source, timeout=None, phrase_time_limit=300)
                
                # Save audio to file
                with open(self.recording_file, "wb") as f:
                    f.write(audio.get_wav_data())
                
                # Add to queue for processing
                self.transcript_queue.put(self.recording_file)
                
        except Exception as e:
            print(f"Audio capture error: {str(e)}")
    
    def _transcription_thread(self):
        """Transcribe audio files as they become available"""
        while self.running:
            try:
                audio_file = self.transcript_queue.get(timeout=1.0)
                if audio_file:
                    # Transcribe the audio file
                    with sr.AudioFile(audio_file) as source:
                        audio = self.recognizer.record(source)
                        try:
                            text = self.recognizer.recognize_google(audio)
                            self.transcript_history.append(text)
                            self.analyzer.process_chunk(text)
                            
                            # Generate interim summary
                            if len(self.transcript_history) % 3 == 0:
                                self.summary = self.analyzer.generate_summary()
                                self.action_items = self.analyzer.extract_action_items()
                            
                            # Check for urgent items
                            urgent_items = self.analyzer.detect_urgent_action_items()
                            if urgent_items:
                                self.urgent_alerts.extend(urgent_items)
                                self.notifier.send_urgent_alert(urgent_items)
                                
                        except sr.UnknownValueError:
                            print("Speech recognition could not understand audio")
                        except sr.RequestError as e:
                            print(f"Speech recognition error: {str(e)}")
                
            except queue.Empty:
                continue
    
    def stop_processing(self):
        if not self.running:
            return "Not running!"
            
        self.running = False
        
        # Generate final analysis
        self.summary = self.analyzer.generate_summary()
        self.action_items = self.analyzer.extract_action_items()
        
        # Send final report
        self.notifier.send_comprehensive_report(
            summary=self.summary,
            action_items=self.action_items,
            decisions=self.analyzer.extract_decisions(),
            transcript="\n".join(self.transcript_history),
            recipients=config.NOTIFICATION_RECIPIENTS
        )
        
        return "Meeting processing stopped! Report sent. ✅"
    
    def get_current_status(self):
        if not self.running:
            return {
                "status": "Stopped",
                "duration": "00:00",
                "transcript": "",
                "summary": self.summary,
                "action_items": self.action_items,
                "alerts": self.urgent_alerts
            }
        
        elapsed = time.time() - self.start_time
        mins, secs = divmod(int(elapsed), 60)
        
        # Only show last 3 transcript entries
        recent_transcript = "\n".join(self.transcript_history[-3:])
        
        return {
            "status": "Recording",
            "duration": f"{mins:02d}:{secs:02d}",
            "transcript": recent_transcript,
            "summary": self.summary if self.summary else "Summary will appear during meeting",
            "action_items": self.action_items,
            "alerts": self.urgent_alerts
        }

# Initialize processor
processor = MeetingProcessor()

# Create Gradio interface
with gr.Blocks(title="Meeting Notes Generator", theme="soft") as app:
    gr.Markdown("# 📝 Meeting Notes Generator")
    gr.Markdown("Start this during any meeting to automatically capture notes and action items")
    
    with gr.Row():
        start_btn = gr.Button("Start Meeting", variant="primary")
        stop_btn = gr.Button("Stop Meeting", variant="stop")
        status_text = gr.Textbox(label="Status", interactive=False, value="Ready to start meeting")
    
    with gr.Row():
        with gr.Column():
            duration_display = gr.Textbox(label="Duration", interactive=False)
            transcript_box = gr.Textbox(label="Live Transcript", lines=6, interactive=False)
        
        with gr.Column():
            summary_box = gr.Textbox(label="Meeting Summary", lines=6, interactive=False)
    
    with gr.Row():
        action_items_box = gr.Textbox(label="Action Items", lines=4, interactive=False)
        alerts_box = gr.Textbox(label="Urgent Alerts", lines=4, interactive=False)
    
    # Update function for components
    def update_components():
        current_status = processor.get_current_status()
        return [
            current_status["duration"],
            current_status["transcript"],
            "\n".join(
                f"• {item['task']} (Owner: {item['owner']}, Deadline: {item['deadline']})"
                for item in current_status["action_items"]
            ),
            "\n".join(
                f"🚨 {item['task']} (Owner: {item['owner']}, Deadline: {item['deadline']})"
                for item in current_status["alerts"]
            ) if current_status["alerts"] else "No urgent alerts",
            current_status["summary"],
            current_status["status"]
        ]
    
    # Button actions
    start_btn.click(
        fn=processor.start_processing,
        inputs=[],
        outputs=[status_text]
    )
    
    stop_btn.click(
        fn=processor.stop_processing,
        inputs=[],
        outputs=[status_text]
    )
    
    # Manual refresh button
    refresh_btn = gr.Button("Refresh View", variant="secondary")
    refresh_btn.click(
        update_components,
        inputs=[],
        outputs=[
            duration_display, 
            transcript_box,
            action_items_box,
            alerts_box,
            summary_box,
            status_text
        ]
    )
    
    # Instructions
    gr.Markdown("### How to use:")
    gr.Markdown("1. Click **Start Meeting** when your meeting begins")
    gr.Markdown("2. Continue with your meeting as normal")
    gr.Markdown("3. Click **Stop Meeting** when finished")
    gr.Markdown("4. View your meeting summary and action items below")
    gr.Markdown("5. Click **Refresh View** to update the display")
    
    # Initialize with current status
    app.load(
        update_components,
        inputs=[],
        outputs=[
            duration_display, 
            transcript_box,
            action_items_box,
            alerts_box,
            summary_box,
            status_text
        ]
    )
    
if __name__ == "__main__":
    app.launch()