Spaces:
Running
Running
Commit
·
21057c0
1
Parent(s):
a4fc8e5
update: dyanmic input for call id, rsid, session id, transcript url
Browse files
app.py
CHANGED
@@ -8,8 +8,6 @@ import requests
|
|
8 |
from bs4 import BeautifulSoup
|
9 |
from openai import OpenAI
|
10 |
|
11 |
-
street_interview = False
|
12 |
-
|
13 |
|
14 |
@dataclass
|
15 |
class TranscriptSegment:
|
@@ -21,15 +19,23 @@ class TranscriptSegment:
|
|
21 |
|
22 |
|
23 |
class TranscriptProcessor:
|
24 |
-
def __init__(self, transcript_file: str):
|
25 |
self.transcript_file = transcript_file
|
26 |
-
self.transcript_data =
|
27 |
self.formatted_transcript = None
|
28 |
self.segments = []
|
29 |
self.text_windows = []
|
30 |
self.window_size = 2
|
31 |
self.speaker_mapping = {}
|
32 |
-
self.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
self._process_transcript()
|
34 |
self.map_speaker_ids_to_names()
|
35 |
|
@@ -273,13 +279,55 @@ def setup_openai_key() -> None:
|
|
273 |
# )
|
274 |
|
275 |
|
276 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
277 |
"""Perform initial analysis of the transcript using OpenAI."""
|
278 |
try:
|
279 |
transcript = transcript_processor.get_transcript()
|
280 |
-
# print("Transcript is: ", transcript)
|
281 |
client = OpenAI()
|
282 |
-
if
|
283 |
prompt = f"""This is a transcript for a street interview. Transcript: {transcript}
|
284 |
In this street interview, the host asks multiple questions to the interviewees.
|
285 |
The interviewee can repeat a single answer multiple time to get the best take.
|
@@ -289,19 +337,28 @@ Question 1 should always be the introduction if the speaker has introduced thems
|
|
289 |
Return format is:
|
290 |
1. Question: question
|
291 |
Number of takes: number
|
292 |
-
Best Answer timestamp: start_time - end_time
|
293 |
-
|
|
|
|
|
294 |
"""
|
295 |
else:
|
296 |
prompt = f"""Given the transcript {transcript}, For All the speakers, short list all people, news, events, trends, and source that are discussed by speakers along with the start time of that topic and end time of that topic from the transcript. Rank all topics based on what would make for the best social clips. I need atleast 3 topics per speaker.
|
297 |
-
You should mention the Speaker Name first, then 3 posts with their timestamps, and so on.
|
298 |
-
Return format is:
|
|
|
|
|
|
|
|
|
|
|
299 |
|
300 |
-
print(prompt)
|
301 |
completion = client.chat.completions.create(
|
302 |
model="gpt-4o-mini",
|
303 |
messages=[
|
304 |
-
{
|
|
|
|
|
|
|
305 |
{"role": "user", "content": prompt},
|
306 |
],
|
307 |
)
|
@@ -311,33 +368,28 @@ Return format is: Speaker Name\n1.Topic: topic, Start Time: start_time, End Time
|
|
311 |
return "An error occurred during initial analysis. Please check your API key and file path."
|
312 |
|
313 |
|
314 |
-
call_id = "20240226t210135"
|
315 |
-
colab_id = "1231412431212"
|
316 |
-
|
317 |
-
|
318 |
-
def generate_call_link(start_time: str) -> str:
|
319 |
-
"""Generate a link to the call at a specific timestamp."""
|
320 |
-
formatted_time = start_time.replace(":", ".")
|
321 |
-
return f"https://roll.ai/{call_id}/{colab_id}?t={formatted_time}"
|
322 |
-
|
323 |
-
|
324 |
def chat(
|
325 |
-
message: str,
|
|
|
|
|
|
|
|
|
|
|
|
|
326 |
) -> str:
|
327 |
try:
|
328 |
client = OpenAI()
|
329 |
-
# if street_interview:
|
330 |
-
# prompt = f"""You are a helpful assistant analyzing transcripts and generating timestamps and URL. Call ID is {call_id} and Colab ID is {colab_id}.
|
331 |
-
# Transcript: {transcript_processor.get_transcript()}
|
332 |
-
# If a user asks t
|
333 |
-
# """
|
334 |
-
# else:
|
335 |
-
prompt = f"""You are a helpful assistant analyzing transcripts and generating timestamps and URL. Call ID is {call_id} and Colab ID is {colab_id}.
|
336 |
-
Transcript: {transcript_processor.get_transcript()}
|
337 |
-
If a user asks timestamps for a specific topic, find the start time and end time of that specific topic and return answer in the format: 'Timestamp: start_time - end_time'.
|
338 |
-
You can visit the call segment on this URL: https://roll.ai/call_id/colab_id?starttime=start_time?endtime=end_time."
|
339 |
-
If a user requests a link to a specific segment topic, generate a link to that segment using the following format: https://roll.ai/call_id/colab_id?starttime=start_time?endtime=end_time."""
|
340 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
341 |
messages = [{"role": "system", "content": prompt}]
|
342 |
|
343 |
for user_msg, assistant_msg in chat_history:
|
@@ -366,31 +418,122 @@ If a user requests a link to a specific segment topic, generate a link to that s
|
|
366 |
return "Sorry, there was an error processing your request."
|
367 |
|
368 |
|
369 |
-
def create_chat_interface(
|
370 |
"""Create and configure the chat interface."""
|
371 |
-
|
372 |
-
def respond(message: str, chat_history: List) -> Tuple[str, List]:
|
373 |
-
if not message:
|
374 |
-
return "", chat_history
|
375 |
-
|
376 |
-
bot_message = chat(message, chat_history, transcript_processor)
|
377 |
-
new_history = list(chat_history)
|
378 |
-
new_history.append((message, bot_message))
|
379 |
-
return "", new_history
|
380 |
-
|
381 |
with gr.Blocks() as demo:
|
382 |
chatbot = gr.Chatbot()
|
383 |
msg = gr.Textbox()
|
384 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
385 |
|
386 |
-
|
387 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
388 |
|
389 |
-
def
|
390 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
391 |
|
392 |
-
|
393 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
394 |
|
395 |
return demo
|
396 |
|
@@ -399,22 +542,8 @@ def main():
|
|
399 |
"""Main function to run the application."""
|
400 |
try:
|
401 |
setup_openai_key()
|
402 |
-
|
403 |
-
current_dir = os.path.dirname(os.path.abspath(__file__))
|
404 |
-
transcript_file = os.path.join(current_dir, "step_take19AWS.json")
|
405 |
-
|
406 |
-
if not os.path.exists(transcript_file):
|
407 |
-
raise FileNotFoundError(
|
408 |
-
"Transcript file not found. Please check the file path."
|
409 |
-
)
|
410 |
-
|
411 |
-
transcript_processor = TranscriptProcessor(transcript_file)
|
412 |
-
transcript_processor.correct_speaker_mapping_with_agenda(
|
413 |
-
"https://lu.ma/STEPSF24"
|
414 |
-
)
|
415 |
-
demo = create_chat_interface(transcript_processor)
|
416 |
demo.launch(share=True)
|
417 |
-
|
418 |
except Exception as e:
|
419 |
print(f"Error starting application: {str(e)}")
|
420 |
raise
|
|
|
8 |
from bs4 import BeautifulSoup
|
9 |
from openai import OpenAI
|
10 |
|
|
|
|
|
11 |
|
12 |
@dataclass
|
13 |
class TranscriptSegment:
|
|
|
19 |
|
20 |
|
21 |
class TranscriptProcessor:
|
22 |
+
def __init__(self, transcript_file: str = None, transcript_data: dict = None):
|
23 |
self.transcript_file = transcript_file
|
24 |
+
self.transcript_data = transcript_data
|
25 |
self.formatted_transcript = None
|
26 |
self.segments = []
|
27 |
self.text_windows = []
|
28 |
self.window_size = 2
|
29 |
self.speaker_mapping = {}
|
30 |
+
if self.transcript_file:
|
31 |
+
self._load_transcript()
|
32 |
+
elif self.transcript_data:
|
33 |
+
pass # transcript_data is already set
|
34 |
+
else:
|
35 |
+
raise ValueError(
|
36 |
+
"Either transcript_file or transcript_data must be provided."
|
37 |
+
)
|
38 |
+
|
39 |
self._process_transcript()
|
40 |
self.map_speaker_ids_to_names()
|
41 |
|
|
|
279 |
# )
|
280 |
|
281 |
|
282 |
+
def get_transcript_for_url(url: str) -> dict:
|
283 |
+
"""
|
284 |
+
This function fetches the transcript data for a signed URL.
|
285 |
+
If the URL results in a direct download, it processes the downloaded content.
|
286 |
+
|
287 |
+
:param url: Signed URL for the JSON file
|
288 |
+
:return: Parsed JSON data as a dictionary
|
289 |
+
"""
|
290 |
+
headers = {
|
291 |
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
|
292 |
+
}
|
293 |
+
|
294 |
+
try:
|
295 |
+
response = requests.get(url, headers=headers)
|
296 |
+
response.raise_for_status()
|
297 |
+
|
298 |
+
if "application/json" in response.headers.get("Content-Type", ""):
|
299 |
+
return response.json() # Parse and return JSON directly
|
300 |
+
|
301 |
+
# If not JSON, assume it's a file download (e.g., content-disposition header)
|
302 |
+
content_disposition = response.headers.get("Content-Disposition", "")
|
303 |
+
if "attachment" in content_disposition:
|
304 |
+
# Process the content as JSON
|
305 |
+
return json.loads(response.content)
|
306 |
+
|
307 |
+
return json.loads(response.content)
|
308 |
+
|
309 |
+
except requests.exceptions.HTTPError as http_err:
|
310 |
+
print(f"HTTP error occurred: {http_err}")
|
311 |
+
except requests.exceptions.RequestException as req_err:
|
312 |
+
print(f"Request error occurred: {req_err}")
|
313 |
+
except json.JSONDecodeError as json_err:
|
314 |
+
print(f"JSON decoding error: {json_err}")
|
315 |
+
|
316 |
+
return {}
|
317 |
+
|
318 |
+
|
319 |
+
def get_initial_analysis(
|
320 |
+
transcript_processor: TranscriptProcessor,
|
321 |
+
cid,
|
322 |
+
rsid,
|
323 |
+
origin,
|
324 |
+
ct,
|
325 |
+
) -> str:
|
326 |
"""Perform initial analysis of the transcript using OpenAI."""
|
327 |
try:
|
328 |
transcript = transcript_processor.get_transcript()
|
|
|
329 |
client = OpenAI()
|
330 |
+
if ct == "si": # street interview
|
331 |
prompt = f"""This is a transcript for a street interview. Transcript: {transcript}
|
332 |
In this street interview, the host asks multiple questions to the interviewees.
|
333 |
The interviewee can repeat a single answer multiple time to get the best take.
|
|
|
337 |
Return format is:
|
338 |
1. Question: question
|
339 |
Number of takes: number
|
340 |
+
Best Answer timestamp: [Timestamp: start_time - end_time](https://{{origin}}/collab/{{cid}}/{{rsid}}&st={{start_time_in_sec}}&et={{end_time_in_sec}}"').
|
341 |
+
For Example:
|
342 |
+
If the start time is 10:13 and end time is 10:18, the url will be:
|
343 |
+
https://roll.ai/colab/1234aq_12314/51234151?st=613&et=618
|
344 |
"""
|
345 |
else:
|
346 |
prompt = f"""Given the transcript {transcript}, For All the speakers, short list all people, news, events, trends, and source that are discussed by speakers along with the start time of that topic and end time of that topic from the transcript. Rank all topics based on what would make for the best social clips. I need atleast 3 topics per speaker.
|
347 |
+
You should mention the Speaker Name first, then atleast 3 posts with their timestamps, and so on.
|
348 |
+
Return format is:
|
349 |
+
Speaker Name
|
350 |
+
1.Topic: topic,
|
351 |
+
[Timestamp: start_time - end_time](https://{{origin}}/collab/{{cid}}/{{rsid}}&st={{start_time_in_sec}}&et={{end_time_in_sec}}"').
|
352 |
+
2....
|
353 |
+
"""
|
354 |
|
|
|
355 |
completion = client.chat.completions.create(
|
356 |
model="gpt-4o-mini",
|
357 |
messages=[
|
358 |
+
{
|
359 |
+
"role": "system",
|
360 |
+
"content": f"You are a helpful assistant who is analyzing the transcript. The transcript is for Call ID: {cid}, Session ID: {rsid}, Origin: {origin}, Call Type: {ct}.",
|
361 |
+
},
|
362 |
{"role": "user", "content": prompt},
|
363 |
],
|
364 |
)
|
|
|
368 |
return "An error occurred during initial analysis. Please check your API key and file path."
|
369 |
|
370 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
371 |
def chat(
|
372 |
+
message: str,
|
373 |
+
chat_history: List,
|
374 |
+
transcript_processor: TranscriptProcessor,
|
375 |
+
cid,
|
376 |
+
rsid,
|
377 |
+
origin,
|
378 |
+
ct,
|
379 |
) -> str:
|
380 |
try:
|
381 |
client = OpenAI()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
382 |
|
383 |
+
prompt = f"""You are a helpful assistant analyzing transcripts and generating timestamps and URL. Call ID is {cid}, Session ID is {rsid}, origin is {origin}, Call Type is {ct}.
|
384 |
+
Transcript:\n{transcript_processor.get_transcript()}
|
385 |
+
If a user asks timestamps for a specific topic, find the start time and end time of that specific topic and return answer in the format:
|
386 |
+
Answer format:
|
387 |
+
Topic: Heading [Timestamp: start_time - end_time](https://{{origin}}/collab/{{cid}}/{{rsid}}&st={{start_time_in_sec}}&et={{end_time_in_sec}}"').
|
388 |
+
|
389 |
+
For Example:
|
390 |
+
If the start time is 10:13 and end time is 10:18, the url will be:
|
391 |
+
https://roll.ai/colab/1234aq_12314/51234151?st=613&et=618
|
392 |
+
"""
|
393 |
messages = [{"role": "system", "content": prompt}]
|
394 |
|
395 |
for user_msg, assistant_msg in chat_history:
|
|
|
418 |
return "Sorry, there was an error processing your request."
|
419 |
|
420 |
|
421 |
+
def create_chat_interface():
|
422 |
"""Create and configure the chat interface."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
423 |
with gr.Blocks() as demo:
|
424 |
chatbot = gr.Chatbot()
|
425 |
msg = gr.Textbox()
|
426 |
+
transcript_processor_state = gr.State() # maintain state of imp things
|
427 |
+
call_id_state = gr.State()
|
428 |
+
colab_id_state = gr.State()
|
429 |
+
origin_state = gr.State()
|
430 |
+
ct_state = gr.State()
|
431 |
+
turl_state = gr.State()
|
432 |
+
|
433 |
+
def on_app_load(request: gr.Request):
|
434 |
+
cid = request.query_params.get("cid", None)
|
435 |
+
rsid = request.query_params.get("rsid", None)
|
436 |
+
origin = request.query_params.get("origin", None)
|
437 |
+
ct = request.query_params.get("ct", None)
|
438 |
+
turl = request.query_params.get("turl", None)
|
439 |
+
|
440 |
+
# if any param is missing, return error
|
441 |
+
if not cid or not rsid or not origin or not ct or not turl:
|
442 |
+
error_message = "Error processing"
|
443 |
+
chatbot_value = [(None, error_message)]
|
444 |
+
return [
|
445 |
+
chatbot_value,
|
446 |
+
None,
|
447 |
+
None,
|
448 |
+
None,
|
449 |
+
None,
|
450 |
+
None,
|
451 |
+
None,
|
452 |
+
]
|
453 |
+
|
454 |
+
try:
|
455 |
+
transcript_data = get_transcript_for_url(turl)
|
456 |
+
transcript_processor = TranscriptProcessor(
|
457 |
+
transcript_data=transcript_data
|
458 |
+
)
|
459 |
+
initial_analysis = get_initial_analysis(
|
460 |
+
transcript_processor, cid, rsid, origin, ct
|
461 |
+
)
|
462 |
+
|
463 |
+
chatbot_value = [
|
464 |
+
(None, initial_analysis)
|
465 |
+
] # initialized with initial analysis and assistant is None
|
466 |
+
return [
|
467 |
+
chatbot_value,
|
468 |
+
transcript_processor,
|
469 |
+
cid,
|
470 |
+
rsid,
|
471 |
+
origin,
|
472 |
+
ct,
|
473 |
+
turl,
|
474 |
+
]
|
475 |
+
except Exception as e:
|
476 |
+
error_message = f"Error processing call_id {cid}: {str(e)}"
|
477 |
+
chatbot_value = [(None, error_message)]
|
478 |
+
return [
|
479 |
+
chatbot_value,
|
480 |
+
None,
|
481 |
+
None,
|
482 |
+
None,
|
483 |
+
None,
|
484 |
+
None,
|
485 |
+
None,
|
486 |
+
]
|
487 |
|
488 |
+
demo.load(
|
489 |
+
on_app_load,
|
490 |
+
inputs=None,
|
491 |
+
outputs=[
|
492 |
+
chatbot,
|
493 |
+
transcript_processor_state,
|
494 |
+
call_id_state,
|
495 |
+
colab_id_state,
|
496 |
+
origin_state,
|
497 |
+
ct_state,
|
498 |
+
turl_state,
|
499 |
+
],
|
500 |
+
)
|
501 |
|
502 |
+
def respond(
|
503 |
+
message: str,
|
504 |
+
chat_history: List,
|
505 |
+
transcript_processor,
|
506 |
+
cid,
|
507 |
+
rsid,
|
508 |
+
origin,
|
509 |
+
ct,
|
510 |
+
):
|
511 |
+
if not transcript_processor:
|
512 |
+
bot_message = "Transcript processor not initialized."
|
513 |
+
else:
|
514 |
+
bot_message = chat(
|
515 |
+
message,
|
516 |
+
chat_history,
|
517 |
+
transcript_processor,
|
518 |
+
cid,
|
519 |
+
rsid,
|
520 |
+
origin,
|
521 |
+
ct,
|
522 |
+
)
|
523 |
+
chat_history.append((message, bot_message))
|
524 |
+
return "", chat_history
|
525 |
|
526 |
+
msg.submit(
|
527 |
+
respond,
|
528 |
+
[
|
529 |
+
msg,
|
530 |
+
chatbot,
|
531 |
+
transcript_processor_state,
|
532 |
+
call_id_state,
|
533 |
+
colab_id_state,
|
534 |
+
],
|
535 |
+
[msg, chatbot],
|
536 |
+
)
|
537 |
|
538 |
return demo
|
539 |
|
|
|
542 |
"""Main function to run the application."""
|
543 |
try:
|
544 |
setup_openai_key()
|
545 |
+
demo = create_chat_interface()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
546 |
demo.launch(share=True)
|
|
|
547 |
except Exception as e:
|
548 |
print(f"Error starting application: {str(e)}")
|
549 |
raise
|