invincible-jha commited on
Commit
e8513b3
·
verified ·
1 Parent(s): 08fd160

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +323 -0
  2. requirements.txt +14 -0
app.py ADDED
@@ -0,0 +1,323 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import whisper
3
+ import pandas as pd
4
+ from datetime import datetime
5
+ import tempfile
6
+ import os
7
+ import torch
8
+ from transformers import (
9
+ AutoModelForCausalLM,
10
+ AutoTokenizer,
11
+ pipeline,
12
+ BitsAndBytesConfig
13
+ )
14
+ import gc
15
+ from typing import Optional, Dict, Any, List
16
+ import logging
17
+ import json
18
+ import numpy as np
19
+ from dataclasses import dataclass, asdict
20
+ import queue
21
+ import threading
22
+ from collections import defaultdict
23
+
24
+ # Configure logging
25
+ logging.basicConfig(level=logging.INFO)
26
+ logger = logging.getLogger(__name__)
27
+
28
+ @dataclass
29
+ class VCStyle:
30
+ """Store VC's personal style preferences"""
31
+ name: str
32
+ note_format: Dict[str, Any]
33
+ key_interests: List[str]
34
+ custom_sections: List[str]
35
+ insight_preferences: Dict[str, float]
36
+
37
+ @dataclass
38
+ class LiveCallContext:
39
+ """Store context for live calls"""
40
+ meeting_id: str
41
+ participants: List[str]
42
+ topics: List[str]
43
+ key_points: List[str]
44
+ questions_asked: List[str]
45
+ action_items: List[str]
46
+
47
+ class RealTimeProcessor:
48
+ """Handle real-time audio processing and analysis"""
49
+
50
+ def __init__(self, whisper_model, llm_pipeline):
51
+ self.whisper_model = whisper_model
52
+ self.llm_pipeline = llm_pipeline
53
+ self.audio_buffer = queue.Queue()
54
+ self.transcript_buffer = queue.Queue()
55
+ self.context = defaultdict(list)
56
+
57
+ def process_audio_chunk(self, audio_chunk):
58
+ """Process incoming audio chunk"""
59
+ try:
60
+ # Simulate real-time processing for Spaces
61
+ result = self.whisper_model.transcribe(audio_chunk)
62
+ return result["text"]
63
+ except Exception as e:
64
+ logger.error(f"Error processing audio chunk: {e}")
65
+ return None
66
+
67
+ def generate_live_insights(self, transcript: str, vc_style: VCStyle) -> Dict[str, Any]:
68
+ """Generate real-time insights based on transcript"""
69
+ prompt = f"""Given this conversation transcript and VC's interests, provide real-time insights:
70
+ Transcript: {transcript}
71
+ VC Interests: {vc_style.key_interests}
72
+
73
+ Provide insights in these areas:
74
+ 1. Key Discussion Points
75
+ 2. Potential Red Flags
76
+ 3. Follow-up Questions
77
+ 4. Market Insights
78
+ """
79
+
80
+ try:
81
+ response = self.llm_pipeline(prompt, max_length=512)
82
+ return json.loads(response[0]['generated_text'])
83
+ except Exception as e:
84
+ logger.error(f"Error generating insights: {e}")
85
+ return {}
86
+
87
+ def update_context(self, transcript: str, insights: Dict[str, Any]):
88
+ """Update call context with new information"""
89
+ self.context['transcripts'].append(transcript)
90
+ self.context['insights'].extend(insights.get('key_points', []))
91
+ self.context['questions'].extend(insights.get('questions', []))
92
+
93
+ class DynamicTemplate:
94
+ """Handle dynamic template management"""
95
+
96
+ def __init__(self):
97
+ self.default_template = {
98
+ "product": {"problem": "", "solution": "", "other": ""},
99
+ "finances": {
100
+ "capital_raised": "", "cash_on_hand": "",
101
+ "monthly_burn": "", "gross_margin": "",
102
+ "deal_dynamics": ""
103
+ },
104
+ "market": {
105
+ "revenue": "", "yoy_growth": "", "tam": "",
106
+ "pricing": "", "acv_arpa": "", "churn": "",
107
+ "gtm": "", "competition": "", "other": ""
108
+ },
109
+ "concerns": {"risks": "", "mitigations": "", "other": ""},
110
+ "free_form": "",
111
+ "spv_actions": []
112
+ }
113
+ self.active_templates = {}
114
+
115
+ def create_custom_template(self, vc_style: VCStyle) -> Dict[str, Any]:
116
+ """Create a template based on VC's style"""
117
+ template = self.default_template.copy()
118
+
119
+ # Add custom sections
120
+ for section in vc_style.custom_sections:
121
+ template[section] = {"notes": "", "actions": []}
122
+
123
+ return template
124
+
125
+ def update_template(self, template_id: str, section: str, content: str):
126
+ """Update template content in real-time"""
127
+ if template_id in self.active_templates:
128
+ try:
129
+ section_path = section.split('.')
130
+ target = self.active_templates[template_id]
131
+ for key in section_path[:-1]:
132
+ target = target[key]
133
+ target[section_path[-1]] = content
134
+ except Exception as e:
135
+ logger.error(f"Error updating template: {e}")
136
+
137
+ class StyleManager:
138
+ """Manage VC's personal styles and preferences"""
139
+
140
+ def __init__(self):
141
+ self.styles = {}
142
+
143
+ def create_style(self, vc_name: str, preferences: Dict[str, Any]) -> VCStyle:
144
+ """Create or update VC style"""
145
+ style = VCStyle(
146
+ name=vc_name,
147
+ note_format=preferences.get('note_format', {}),
148
+ key_interests=preferences.get('key_interests', []),
149
+ custom_sections=preferences.get('custom_sections', []),
150
+ insight_preferences=preferences.get('insight_preferences', {})
151
+ )
152
+ self.styles[vc_name] = style
153
+ return style
154
+
155
+ def get_style(self, vc_name: str) -> Optional[VCStyle]:
156
+ """Retrieve VC's style"""
157
+ return self.styles.get(vc_name)
158
+
159
+ class LiveCallManager:
160
+ """Manage live call processing and analysis"""
161
+
162
+ def __init__(self, processor: RealTimeProcessor, template_manager: DynamicTemplate):
163
+ self.processor = processor
164
+ self.template_manager = template_manager
165
+ self.active_calls = {}
166
+
167
+ def start_call(self, meeting_id: str, vc_style: VCStyle) -> str:
168
+ """Initialize a new call session"""
169
+ self.active_calls[meeting_id] = {
170
+ 'context': LiveCallContext(
171
+ meeting_id=meeting_id,
172
+ participants=[],
173
+ topics=[],
174
+ key_points=[],
175
+ questions_asked=[],
176
+ action_items=[]
177
+ ),
178
+ 'template': self.template_manager.create_custom_template(vc_style),
179
+ 'style': vc_style
180
+ }
181
+ return meeting_id
182
+
183
+ def process_call_segment(self, meeting_id: str, audio_chunk) -> Dict[str, Any]:
184
+ """Process a segment of the call"""
185
+ if meeting_id not in self.active_calls:
186
+ raise ValueError("Invalid meeting ID")
187
+
188
+ # Process audio
189
+ transcript = self.processor.process_audio_chunk(audio_chunk)
190
+ if not transcript:
191
+ return {}
192
+
193
+ # Generate insights
194
+ call_data = self.active_calls[meeting_id]
195
+ insights = self.processor.generate_live_insights(
196
+ transcript,
197
+ call_data['style']
198
+ )
199
+
200
+ # Update template
201
+ self.update_call_notes(meeting_id, transcript, insights)
202
+
203
+ return {
204
+ 'transcript': transcript,
205
+ 'insights': insights,
206
+ 'template': call_data['template']
207
+ }
208
+
209
+ def update_call_notes(self, meeting_id: str, transcript: str, insights: Dict[str, Any]):
210
+ """Update call notes with new information"""
211
+ call_data = self.active_calls[meeting_id]
212
+ template = call_data['template']
213
+
214
+ # Update relevant sections based on insights
215
+ for key, value in insights.items():
216
+ if key in template:
217
+ if isinstance(template[key], dict):
218
+ template[key].update(value)
219
+ else:
220
+ template[key] = value
221
+
222
+ def main():
223
+ st.set_page_config(page_title="VC Call Assistant", layout="wide")
224
+
225
+ # Initialize managers
226
+ style_manager = StyleManager()
227
+ template_manager = DynamicTemplate()
228
+
229
+ # Sidebar for VC profile
230
+ with st.sidebar:
231
+ st.header("VC Profile")
232
+ vc_name = st.text_input("VC Name")
233
+
234
+ # Style preferences
235
+ st.subheader("Style Preferences")
236
+ note_format = st.multiselect(
237
+ "Preferred Note Format",
238
+ ["Bullet Points", "Paragraphs", "Q&A Format"],
239
+ default=["Bullet Points"]
240
+ )
241
+
242
+ key_interests = st.multiselect(
243
+ "Key Interest Areas",
244
+ ["Technical", "Financial", "Market", "Team", "Product"],
245
+ default=["Financial", "Market"]
246
+ )
247
+
248
+ custom_sections = st.multiselect(
249
+ "Custom Sections",
250
+ ["Competition Deep Dive", "Technical Assessment", "Team Background"],
251
+ default=[]
252
+ )
253
+
254
+ # Main content area
255
+ st.title("VC Call Assistant")
256
+
257
+ # Create tabs for different modes
258
+ tab1, tab2 = st.tabs(["Live Call", "Batch Processing"])
259
+
260
+ with tab1:
261
+ st.header("Live Call Analysis")
262
+
263
+ # Initialize call managers if VC profile exists
264
+ if vc_name:
265
+ # Create/update VC style
266
+ vc_style = style_manager.create_style(
267
+ vc_name,
268
+ {
269
+ 'note_format': note_format,
270
+ 'key_interests': key_interests,
271
+ 'custom_sections': custom_sections,
272
+ 'insight_preferences': {'technical': 0.8, 'financial': 0.9}
273
+ }
274
+ )
275
+
276
+ # Audio input (simulated for Spaces)
277
+ uploaded_file = st.file_uploader(
278
+ "Upload audio segment",
279
+ type=['wav', 'mp3', 'm4a']
280
+ )
281
+
282
+ if uploaded_file:
283
+ # Process audio in chunks (simulated)
284
+ with st.spinner("Processing audio..."):
285
+ # Initialize processors
286
+ whisper_model = whisper.load_model("base")
287
+ llm = load_llm("Mixtral-8x7B-Instruct") # Function from previous code
288
+ processor = RealTimeProcessor(whisper_model, llm)
289
+ live_call_manager = LiveCallManager(processor, template_manager)
290
+
291
+ # Start call session
292
+ meeting_id = live_call_manager.start_call(
293
+ str(datetime.now()),
294
+ vc_style
295
+ )
296
+
297
+ # Process call
298
+ results = live_call_manager.process_call_segment(
299
+ meeting_id,
300
+ uploaded_file
301
+ )
302
+
303
+ # Display results
304
+ col1, col2 = st.columns(2)
305
+ with col1:
306
+ st.subheader("Live Transcript")
307
+ st.write(results.get('transcript', ''))
308
+
309
+ st.subheader("Real-time Insights")
310
+ st.write(results.get('insights', {}))
311
+
312
+ with col2:
313
+ st.subheader("Smart Notes")
314
+ st.write(results.get('template', {}))
315
+ else:
316
+ st.warning("Please enter VC profile information in the sidebar")
317
+
318
+ with tab2:
319
+ st.header("Batch Processing")
320
+ # Previous batch processing code here
321
+
322
+ if __name__ == "__main__":
323
+ main()
requirements.txt ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ streamlit==1.24.0
2
+ whisper-openai==1.0.0
3
+ pandas==1.5.3
4
+ numpy==1.23.5
5
+ torch==2.0.1
6
+ transformers==4.35.2
7
+ accelerate==0.24.1
8
+ bitsandbytes==0.41.1
9
+ scipy==1.11.3
10
+ sentencepiece==0.1.99
11
+ huggingface-hub==0.19.4
12
+ python-dotenv==1.0.0
13
+ dataclasses-json==0.5.7
14
+ queue==1.0.2