-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.py
454 lines (334 loc) · 14.8 KB
/
app.py
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
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
import pyaudio
import wave
import os
import datetime
import subprocess
import shutil
from openai import OpenAI
from docx import Document
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
import threading
import platform
from dotenv import load_dotenv
# Load environment variables from .env
load_dotenv()
openai_api_key = os.environ['OpenAI_API_KEY']
meetings_folder = "meetings"
# Global variabler
global stream, frames, audio, recording, is_paused, content_length
stream = None
frames = []
audio = None
recording = False
is_paused = False # Ny kontrolvariabel til pauser
def set_content_length(data):
global content_length
content_length = data
print(content_length)
def record_loop():
global stream, frames, recording, is_paused
count = 0
print("Optager LOOP")
while recording:
if not is_paused:
try:
data = stream.read(1024, exception_on_overflow=False)
frames.append(data)
except OSError as e:
count += 1
def toggle_pause():
global is_paused, stream
is_paused = not is_paused
# Luk og genåbn audio stream ved pause/genoptag
if is_paused:
stream.stop_stream()
stream.close()
else:
audio = pyaudio.PyAudio()
stream = audio.open(format=pyaudio.paInt16, channels=1, rate=44100, input=True, frames_per_buffer=1024)
def start_recording():
global stream, frames, audio, recording, is_paused
print("Starter nu")
frames = []
is_paused = False
audio = pyaudio.PyAudio()
stream = audio.open(format=pyaudio.paInt16, channels=1, rate=44100, input=True, frames_per_buffer=1024)
recording = True
recording_thread = threading.Thread(target=record_loop)
recording_thread.start()
def stop_recording(audio_folder):
if not os.path.exists(audio_folder):
os.makedirs(audio_folder)
print(f"{audio_folder} has been created.")
else:
print(f"{audio_folder} already exists.")
global stream, frames, audio, recording, file_path, date_str
print("Stopper nu")
# Stopper optagelsesloopet
recording = False
# Lukker og afslutter audio stream
stream.stop_stream()
stream.close()
audio.terminate()
# Behandler og gemmer den optagede lydfil
date_str = datetime.datetime.now().strftime('%d-%m-%Y-%H-%M-%S')
file_path = os.path.join(audio_folder, date_str + ".wav")
with wave.open(file_path, "wb") as audio_file:
audio_file.setnchannels(1)
audio_file.setsampwidth(audio.get_sample_size(pyaudio.paInt16))
audio_file.setframerate(44100)
audio_file.writeframes(b''.join(frames))
print("Audio file created successfully")
date_dir, new_file_path = date_dir_create(meetings_folder)
mp3_file_path = convert_audio(new_file_path, date_dir)
output_dir = split_audio(date_dir, mp3_file_path)
transcribe_audio_files(output_dir, date_dir)
generate_meeting_report(date_dir)
# send_email(date_dir)
return file_path
def date_dir_create(meetings_folder):
date_str = datetime.datetime.now().strftime('%d-%m-%Y-%H-%M-%S')
#Making a date folder and copying the audio file into the folder
date_dir = os.path.join(meetings_folder, date_str)
os.makedirs(date_dir, exist_ok=True)
print("Made a mew folder in the meetings folder called: " + date_dir)
new_file_path = shutil.copy2(file_path, date_dir)
return date_dir, new_file_path
def convert_audio(new_file_path, date_dir):
# Rename the audio file in the meetings folder to Part_full.wav
new_file_name = os.path.join(date_dir, "Part_Full.wav")
os.rename(new_file_path, new_file_name)
# Convert the WAV to MP3
mp3_file_path = os.path.splitext(new_file_name)[0] + ".mp3"
command = ["ffmpeg", "-i", new_file_name, "-vn", "-acodec", "libmp3lame", "-q:a", "2", mp3_file_path]
subprocess.run(command, check=True)
#makes the new Dir for the mp3 file and deletes the old audio file
os.remove(new_file_name)
print("Wav file converted into MP3 file successfully")
return mp3_file_path
def split_audio(date_dir, mp3_file_path):
#makes a dir called audio_files
output_dir = os.path.join(date_dir, "audio_files")
os.makedirs(output_dir)
print("Output_dir called audio_files made")
#Splitting audio
# Set segment time to 5 minutes in seconds to aim for <10MB segments
segment_time_seconds = 60 * 10
output_path = os.path.join(output_dir + "/audio_part_%03d" + ".mp3")
command = ["ffmpeg", "-i", mp3_file_path, "-f", "segment", "-segment_time", str(segment_time_seconds), "-c", "copy", output_path]
subprocess.run(command, check=True)
# Print the size of each segment
for segment_file in os.listdir(output_dir):
segment_path = os.path.join(output_dir, segment_file)
segment_size = os.path.getsize(segment_path)
print(f"Segment {segment_file}: {segment_size}")
return output_dir
def transcribe_audio_files(output_dir, date_dir):
client = OpenAI(api_key=openai_api_key)
text_output = [] # List to store transcriptions
audio_files = [f for f in os.listdir(output_dir)]
total_files = len(audio_files)
# Iterate through each audio file in the directory
for index, audio_file in enumerate(audio_files, start=1):
audio_path = os.path.join(output_dir, audio_file)
print(f"Transcribing file {index} of {total_files}: {audio_file}...")
with open(audio_path, "rb") as f:
transcript_response = client.audio.transcriptions.create(model="whisper-1", file=f)
# Access the text attribute directly
transcript_text = transcript_response.text
text_output.append(transcript_text)
# Save the combined transcriptions to a file
with open(os.path.join(date_dir, 'transcription.txt'), 'w', encoding='utf-8') as f:
f.write("\n".join(text_output))
print("Transcription completed!")
def split_transcript_into_parts(date_dir):
with open(os.path.join(date_dir, "transcription.txt"), "r", encoding="utf-8") as file:
transcript_text = file.read()
total_length = len(transcript_text)
part_length = total_length // 3
parts = [
transcript_text[:part_length],
transcript_text[part_length:2*part_length],
transcript_text[2*part_length:]
]
print("Splitting of txt file done")
return parts
def generate_meeting_report(date_dir):
client = OpenAI(api_key=openai_api_key)
# client = OpenAI(base_url="https://openrouter.ai/api/v1", api_key="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",)
# Split the transcript into three parts
transcript_parts = split_transcript_into_parts(date_dir)
messages = [{
"role": "system",
"content": "You are about to receive parts of a transcribed meeting. Please process them sequentially."
}]
# Provide transcript parts to GPT-4
for idx, part in enumerate(transcript_parts):
print(f"Sending TXT data to API: {idx + 1}...")
messages.append({
"role": "user",
"content": part
})
# Initialize conversation with GPT-4
# response = client.chat.completions.create(model="openai/gpt-4-32k", # Optional (user controls the default)
# messages=messages,
# extra_headers={
# "HTTP-Referer": "http://localhost:3000", # To identify your app. Can be set to e.g. http://localhost:3000 for testing
# "X-Title": "AI_Meeting", # Optional. Shows on openrouter.ai
# })
# Now, command GPT-4 to provide a headline
global content_length
if content_length == "Short":
word_length = 250
elif content_length == "Medium":
word_length = 500
elif content_length == "Long":
word_length = 750
messages.append(
{
"role": "system",
"content": f"You are a proficient AI with a specialty in distilling information into key points. Based on the following text, identify and list the main points that were discussed or brought up. These should be the most important ideas, findings, or topics that are crucial to the essence of the discussion. Your goal is to provide a usefull information that someone could read to quickly understand what was talked about. Is important that you at all time use the same langauge as transcripted. I need you to first of all make a headline thats is fitting for the meeting. Then i want you to make a very short summart in bullet point format. Then i want you to write a more detailed summary about the whole meeting where you focus on including key points and you are very good at gathering conclusions, dates and numbers I want you to make it easy to read with good spaces and headlines in the summary. This response should max be {word_length} words long. Its very important that you check what language the transcript is in and use the same language in your summary. The most common languange is Danish and english."
}
)
completion = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=messages
)
# response = client.chat.completions.create(model="openai/gpt-4-32k", messages=messages, extra_headers={
# "HTTP-Referer": "http://localhost:3000", # To identify your app. Can be set to e.g. http://localhost:3000 for testing
# "X-Title": "AI_Meeting", # Optional. Shows on openrouter.ai
# })
Summary = completion.choices[0].message.content
print("Done with summery. Saving to Docx file")
save_to_docx(Summary, date_dir)
def save_to_docx(Summary, date_dir):
doc = Document()
doc.add_heading('Møde referat', level=0)
doc.add_paragraph(Summary)
# Save the doc in date_dir
doc.save(os.path.join(date_dir, "meeting_summary.docx"))
print('File uploaded successfully')
def send_email(date_dir, r_email):
print("mail", date_dir)
# r_email = "kontakt@crosscompany.dk"
s_email = "crossitlemvig@gmail.com"
app_password = "wrgndlzevuruadye"
subject = "Mødereferat: " + date_dir
message = "Her er mødereferatet fra mødet der lige har været afholdt"
# Set up MIME
msg = MIMEMultipart()
msg['From'] = s_email
msg['To'] = r_email
msg['Subject'] = subject
msg.attach(MIMEText(message, 'plain'))
# Attach the file
docx_filename = "meeting_summary.docx"
docx_filepath = os.path.join(f'./meetings/{date_dir}', docx_filename)
print(docx_filepath)
with open(docx_filepath, "rb") as attachment:
part = MIMEBase('application', 'octet-stream')
part.set_payload(attachment.read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', "attachment; filename= %s" % docx_filename)
msg.attach(part)
# Convert the message to string
text = msg.as_string()
# Connect to Gmail's SMTP server
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login(s_email, app_password)
server.sendmail(s_email, r_email, text)
print("Email has been sent to " + r_email)
server.quit()
# function to establish a new connection
def createNewConnection(name, SSID, password):
config = """<?xml version=\"1.0\"?>
<WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">
<name>"""+name+"""</name>
<SSIDConfig>
<SSID>
<name>"""+SSID+"""</name>
</SSID>
</SSIDConfig>
<connectionType>ESS</connectionType>
<connectionMode>auto</connectionMode>
<MSM>
<security>
<authEncryption>
<authentication>WPA2PSK</authentication>
<encryption>AES</encryption>
<useOneX>false</useOneX>
</authEncryption>
<sharedKey>
<keyType>passPhrase</keyType>
<protected>false</protected>
<keyMaterial>"""+password+"""</keyMaterial>
</sharedKey>
</security>
</MSM>
</WLANProfile>"""
command = "netsh wlan add profile filename=\""+name+".xml\""+" interface=Wi-Fi"
with open(name+".xml", 'w') as file:
file.write(config)
os.system(command)
# function to connect to a network
def connect(name, SSID):
command = "netsh wlan connect name=\""+name+"\" ssid=\""+SSID+"\" interface=Wi-Fi"
os.system(command)
# function to display avavilabe Wifi networks
def displayAvailableNetworks():
command = "netsh wlan show networks interface=Wi-Fi"
os.system(command)
def get_wifi_status():
os_type = platform.system()
if os_type == 'Linux':
result = subprocess.run(['iwgetid'], capture_output=True, text=True)
elif os_type == 'Windows':
result = subprocess.run(['netsh', 'wlan', 'show', 'interfaces'], capture_output=True, text=True)
else:
return "Unsupported operating system"
# Check the return code of the subprocess
return result.returncode == 0
def get_meeting_list():
directory_path = './meetings'
try:
directory_contents = os.listdir(directory_path)
return directory_contents
except FileNotFoundError:
print(f"The directory at path '{directory_path}' does not exist or could not be found.")
return [] # Return an empty list to signify that no contents were found
def delete_meeting_data(folder_name):
# Specify the path of the folder you want to delete
audio_path = f'./Audio_Recordings/{folder_name}.wav'
delete_file(audio_path)
meeting_path = f'./meetings/{folder_name}'
meeting_audio_path = f'./meetings/{folder_name}/audio_files'
meeting_audio_file_list = os.listdir(meeting_audio_path)
for file_name in meeting_audio_file_list:
delete_file(f'./meetings/{folder_name}/audio_files/{file_name}')
delete_folder(meeting_audio_path)
meeting_file_list = os.listdir(meeting_path)
for file_name in meeting_file_list:
delete_file(f'./meetings/{folder_name}/{file_name}')
delete_folder(meeting_path)
def delete_folder(folder_path):
# Check if the folder exists before attempting to delete it
if os.path.exists(folder_path):
try:
os.rmdir(folder_path)
print(f"The folder at {folder_path} has been deleted.")
except OSError as e:
print(f"Error: {folder_path} : {e.strerror}")
else:
print(f"The folder at {folder_path} does not exist.")
def delete_file(file_path):
# Check if the file exists before attempting to remove it
if os.path.exists(file_path):
os.remove(file_path)
print(f"The file at {file_path} has been removed.")
else:
print(f"The file at {file_path} does not exist.")