import json
from typing import Generator, List
import gradio as gr
from openai import OpenAI
from crop_utils import get_image_crop
from prompts import (
get_chat_system_prompt,
get_live_event_system_prompt,
get_live_event_user_prompt,
get_street_interview_prompt,
get_street_interview_system_prompt,
)
from transcript import TranscriptProcessor
from utils import css, get_transcript_for_url, head
from utils import openai_tools as tools
from utils import setup_openai_key
client = OpenAI()
def get_initial_analysis(
transcript_processor: TranscriptProcessor, cid, rsid, origin, ct, uid
) -> Generator[str, None, None]:
"""Perform initial analysis of the transcript using OpenAI."""
hardcoded_messages = {
(
"9v3b-j426-kxxv_2024-11-19T204924",
"2024-11-19T223131",
): f"""**Mala Ramakrishnan**
1. [Introduction and Event Overview
40s at 03:25
]({origin}/collab/{cid}/{rsid}?st={205}&et={240}&uid={uid})
2. [Advice for Startup Founders 30s at 26:10
]({origin}/collab/{cid}/{rsid}?st={1570}&et={1600}&uid={uid})
**Raymond Lee**
1. [Event Introduction and Agenda 120s at 00:39
]({origin}/collab/{cid}/{rsid}?st={39}&et={159}&uid={uid})
2. [Introduction of Mala Ramakrishnan 20s at 02:51
]({origin}/collab/{cid}/{rsid}?st={171}&et={191}&uid={uid})
**Vince Lane**
1. [Introduction and Background 60s at 04:42
]({origin}/collab/{cid}/{rsid}?st={282}&et={342}&uid={uid})
2. [Advice for Founders 60s at 19:48
]({origin}/collab/{cid}/{rsid}?st={1188}&et={1248}&uid={uid})
**Marriott Wharton**
1. [Introduction and Investment Focus 60s at 06:36
]({origin}/collab/{cid}/{rsid}?st={396}&et={456}&uid={uid})
2. [AI as a Fundamental Tool 60s at 08:39
]({origin}/collab/{cid}/{rsid}?st={519}&et={579}&uid={uid})
**spk_2**
1. [Introduction and Investment Focus 60s at 05:56
]({origin}/collab/{cid}/{rsid}?st={356}&et={416}&uid={uid})
2. [Caution in AI Investments 60s at 10:50
]({origin}/collab/{cid}/{rsid}?st={650}&et={710}&uid={uid})
""",
(
"9v3b-j426-kxxv_2024-11-19T204924",
"2024-11-19T230912",
): f"""**Napoleon Paxton**
1. [Introduction and Background 68s at 00:49
](/collab/{cid}/{rsid}?st=49&et=117&uid={uid})
2. [AI Squared's Business Model 52s at 15:18
](/collab/{cid}/{rsid}?st=918&et=970&uid={uid})
3. [Federal Space and Networking 88s at 24:35
](/collab/{cid}/{rsid}?st=1475&et=1563&uid={uid})
**Lauren Hidalgo**
1. [Introduction and Experience 77s at 03:01
](/collab/{cid}/{rsid}?st=181&et=258&uid={uid})
2. [AI Implementation Approach 108s at 11:50
](/collab/{cid}/{rsid}?st=710&et=818&uid={uid})
**Priti Padmanaban**
1. [Introduction and AI Marketing 66s at 06:17
](/collab/{cid}/{rsid}?st=377&et=443&uid={uid})
2. [Responsible AI Framework 109s at 08:15
](/collab/{cid}/{rsid}?st=495&et=604&uid={uid})
3. [AI in Climate Tech 72s at 31:30
](/collab/{cid}/{rsid}?st=1890&et=1962&uid={uid})
**Rishi Sawane**
1. [Introduction and Background 98s at 04:17
](/collab/{cid}/{rsid}?st=257&et=355&uid={uid})
2. [AI and Recruitment Automation 56s at 32:52
](/collab/{cid}/{rsid}?st=1972&et=2028&uid={uid})""",
(
"9v3b-j426-kxxv_2024-10-10T145749",
"2024-10-10T160643",
): f"""**Mahesh**
1. [Zoom's AI Adoption Journey 60s at 05:42
](/collab/{cid}/{rsid}?st=342&et=402&uid={uid})
2. [AI's Impact on Business Metrics 60s at 07:49
](/collab/{cid}/{rsid}?st=469&et=529&uid={uid})
3. [AI's Role in Enterprise Adoption 60s at 13:02
](/collab/{cid}/{rsid}?st=782&et=842&uid={uid})
**Ben**
1. [AI in Enterprise Content Management 60s at 04:18
](/collab/{cid}/{rsid}?st=258&et=318&uid={uid})
2. [Challenges in AI Adoption 60s at 11:00
](/collab/{cid}/{rsid}?st=660&et=720&uid={uid})
3. [Trust and AI Implementation 60s at 31:02
](/collab/{cid}/{rsid}?st=1862&et=1922&uid={uid})
**Jennifer Lee**
1. [Introduction to Enterprise AI 60s at 01:49
](/collab/{cid}/{rsid}?st=109&et=169&uid={uid})
2. [Investor's Perspective on AI 60s at 17:18
](/collab/{cid}/{rsid}?st=1038&et=1098&uid={uid})
3. [Closing Remarks and Thanks 60s at 58:57
](/collab/{cid}/{rsid}?st=3537&et=3597&uid={uid})
**Robert**
1. [AI's Role in Customer Support 60s at 08:34
](/collab/{cid}/{rsid}?st=514&et=574&uid={uid})
2. [Challenges in AI Implementation 60s at 32:11
](/collab/{cid}/{rsid}?st=1931&et=1991&uid={uid})
3. [AI's Impact on Business Processes 60s at 54:01
](/collab/{cid}/{rsid}?st=3241&et=3301&uid={uid})""",
(
"9v3b-j426-kxxv_2025-01-08T195932",
"2025-01-08T201511",
): f"""**Paul Sutchman**
1. [Introduction and Purpose of the Panel 46s at 00:11
](/collab/{cid}/{rsid}?st=11&et=57&uid={uid})
2. [Closing Remarks and Excitement for 2025 60s at 30:05
](/collab/{cid}/{rsid}?st=1805&et=1865&uid={uid})
**Tomas**
1. [Introduction to Alembic Platform 106s at 01:31
](/collab/{cid}/{rsid}?st=91&et=197&uid={uid})
2. [Challenges in Marketing Measurement 84s at 15:15
](/collab/{cid}/{rsid}?st=915&et=999&uid={uid})
3. [Data Analysis and Customization 112s at 23:16
](/collab/{cid}/{rsid}?st=1396&et=1508&uid={uid})
**Jeffrey**
1. [Investment Perspective on Alembic 130s at 03:37
](/collab/{cid}/{rsid}?st=217&et=347&uid={uid})
2. [Delta's Strategic Importance 69s at 04:57
](/collab/{cid}/{rsid}?st=297&et=366&uid={uid})
**Alicia**
1. [Importance of Measurement in Marketing 120s at 09:36
](/collab/{cid}/{rsid}?st=576&et=696&uid={uid})
2. [Pilot with Alembic and Results 120s at 12:10
](/collab/{cid}/{rsid}?st=730&et=850&uid={uid})
3. [Collaboration and Building Together 120s at 27:13
](/collab/{cid}/{rsid}?st=1633&et=1740&uid={uid})""",
}
if (cid, rsid) in hardcoded_messages:
if "localhost" in origin:
link_start = "http"
else:
link_start = "https"
hardcoded_message = hardcoded_messages[(cid, rsid)]
collected_message = ""
chunks = [
hardcoded_message[i : i + 10] for i in range(0, len(hardcoded_message), 10)
]
import time
for chunk in chunks:
collected_message += chunk
yield collected_message
time.sleep(0.05)
return
try:
transcript = transcript_processor.get_transcript()
speaker_mapping = transcript_processor.speaker_mapping
client = OpenAI()
if "localhost" in origin:
link_start = "http"
else:
link_start = "https"
if ct == "si": # street interview
user_prompt = get_street_interview_prompt(transcript, uid, rsid, link_start)
system_prompt = get_street_interview_system_prompt(cid, rsid, origin, ct)
completion = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt},
],
stream=True,
temperature=0.1,
)
else:
system_prompt = get_live_event_system_prompt(
cid, rsid, origin, ct, speaker_mapping, transcript
)
user_prompt = get_live_event_user_prompt(uid, link_start)
completion = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt},
],
stream=True,
temperature=0.1,
)
collected_messages = []
# Iterate through the stream
for chunk in completion:
if chunk.choices[0].delta.content is not None:
chunk_message = chunk.choices[0].delta.content
collected_messages.append(chunk_message)
# Yield the accumulated message so far
yield "".join(collected_messages)
except Exception as e:
print(f"Error in initial analysis: {str(e)}")
yield "An error occurred during initial analysis. Please check your API key and file path."
def chat(
message: str,
chat_history: List,
transcript_processor: TranscriptProcessor,
cid,
rsid,
origin,
ct,
uid,
):
try:
client = OpenAI()
if "localhost" in origin:
link_start = "http"
else:
link_start = "https"
speaker_mapping = transcript_processor.speaker_mapping
system_prompt = get_chat_system_prompt(
cid=cid,
rsid=rsid,
origin=origin,
ct=ct,
speaker_mapping=speaker_mapping,
transcript=transcript_processor.get_transcript(),
link_start=link_start,
)
messages = [{"role": "system", "content": system_prompt}]
for user_msg, assistant_msg in chat_history:
if user_msg is not None:
messages.append({"role": "user", "content": user_msg})
if assistant_msg is not None:
messages.append({"role": "assistant", "content": assistant_msg})
# Add the current message
messages.append({"role": "user", "content": message})
completion = client.chat.completions.create(
model="gpt-4o",
messages=messages,
tools=tools,
stream=True,
temperature=0.3,
)
collected_messages = []
tool_calls_detected = False
for chunk in completion:
if chunk.choices[0].delta.tool_calls:
tool_calls_detected = True
# Handle tool calls without streaming
response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
tools=tools,
)
if response.choices[0].message.tool_calls:
tool_call = response.choices[0].message.tool_calls[0]
if tool_call.function.name == "get_image":
# Return the image directly in the chat
image_data = get_image_crop(cid, rsid, uid, ct)
print(response.choices[0].message)
messages.append(response.choices[0].message)
function_call_result_message = {
"role": "tool",
"content": "Here are the Image Crops",
"name": tool_call.function.name,
"tool_call_id": tool_call.id,
}
messages.append(function_call_result_message)
yield image_data
return
if tool_call.function.name == "correct_speaker_name_with_url":
args = eval(tool_call.function.arguments)
url = args.get("url", None)
if url:
transcript_processor.correct_speaker_mapping_with_agenda(
url
)
corrected_speaker_mapping = (
transcript_processor.speaker_mapping
)
messages.append(response.choices[0].message)
function_call_result_message = {
"role": "tool",
"content": json.dumps(
{
"speaker_mapping": f"Corrected Speaker Mapping... {corrected_speaker_mapping}"
}
),
"name": tool_call.function.name,
"tool_call_id": tool_call.id,
}
messages.append(function_call_result_message)
# Get final response after tool call
final_response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
stream=True,
)
collected_chunk = ""
for final_chunk in final_response:
if final_chunk.choices[0].delta.content:
collected_chunk += final_chunk.choices[
0
].delta.content
yield collected_chunk
return
else:
function_call_result_message = {
"role": "tool",
"content": "No URL Provided",
"name": tool_call.function.name,
"tool_call_id": tool_call.id,
}
elif tool_call.function.name == "correct_call_type":
args = eval(tool_call.function.arguments)
call_type = args.get("call_type", None)
if call_type:
# Stream the analysis for corrected call type
for content in get_initial_analysis(
transcript_processor,
call_type,
rsid,
origin,
call_type,
uid,
):
yield content
return
break # Exit streaming loop if tool calls detected
if not tool_calls_detected and chunk.choices[0].delta.content is not None:
chunk_message = chunk.choices[0].delta.content
collected_messages.append(chunk_message)
yield "".join(collected_messages)
except Exception as e:
print(f"Unexpected error in chat: {str(e)}")
import traceback
print(f"Traceback: {traceback.format_exc()}")
yield "Sorry, there was an error processing your request."
def create_chat_interface():
"""Create and configure the chat interface."""
with gr.Blocks(
fill_height=True,
fill_width=True,
css=css,
head=head,
theme=gr.themes.Default(
font=[gr.themes.GoogleFont("Inconsolata"), "Arial", "sans-serif"]
),
) as demo:
chatbot = gr.Chatbot(
elem_id="chatbot_box",
layout="bubble",
show_label=False,
show_share_button=False,
show_copy_all_button=False,
show_copy_button=False,
render=True,
)
msg = gr.Textbox(elem_id="chatbot_textbox", show_label=False)
transcript_processor_state = gr.State() # maintain state of imp things
call_id_state = gr.State()
colab_id_state = gr.State()
origin_state = gr.State()
ct_state = gr.State()
turl_state = gr.State()
uid_state = gr.State()
iframe_html = ""
gr.HTML(value=iframe_html) # Add iframe to the UI
def respond(
message: str,
chat_history: List,
transcript_processor,
cid,
rsid,
origin,
ct,
uid,
):
if not transcript_processor:
bot_message = "Transcript processor not initialized."
chat_history.append((message, bot_message))
return "", chat_history
chat_history.append((message, ""))
for chunk in chat(
message,
chat_history[:-1], # Exclude the current incomplete message
transcript_processor,
cid,
rsid,
origin,
ct,
uid,
):
chat_history[-1] = (message, chunk)
yield "", chat_history
msg.submit(
respond,
[
msg,
chatbot,
transcript_processor_state,
call_id_state,
colab_id_state,
origin_state,
ct_state,
uid_state,
],
[msg, chatbot],
)
# Handle initial loading with streaming
def on_app_load(request: gr.Request):
turls = None
cid = request.query_params.get("cid", None)
rsid = request.query_params.get("rsid", None)
origin = request.query_params.get("origin", None)
ct = request.query_params.get("ct", None)
turl = request.query_params.get("turl", None)
uid = request.query_params.get("uid", None)
pnames = request.query_params.get("pnames", None)
required_params = ["cid", "rsid", "origin", "ct", "turl", "uid"]
missing_params = [
param
for param in required_params
if request.query_params.get(param) is None
]
if missing_params:
error_message = (
f"Missing required parameters: {', '.join(missing_params)}"
)
chatbot_value = [(None, error_message)]
return [chatbot_value, None, None, None, None, None, None, None]
if ct == "rp":
# split turls based on ,
turls = turl.split(",")
pnames = [pname.replace("_", " ") for pname in pnames.split(",")]
try:
if turls:
transcript_data = []
for turl in turls:
print("Getting Transcript for URL")
transcript_data.append(get_transcript_for_url(turl))
print("Now creating Processor")
transcript_processor = TranscriptProcessor(
transcript_data=transcript_data,
call_type=ct,
person_names=pnames,
)
else:
transcript_data = get_transcript_for_url(turl)
transcript_processor = TranscriptProcessor(
transcript_data=transcript_data, call_type=ct
)
# Initialize with empty message
chatbot_value = [(None, "")]
# Return initial values with the transcript processor
return [
chatbot_value,
transcript_processor,
cid,
rsid,
origin,
ct,
turl,
uid,
]
except Exception as e:
print(e)
error_message = f"Error processing call_id {cid}: {str(e)}"
chatbot_value = [(None, error_message)]
return [chatbot_value, None, None, None, None, None, None, None]
def display_processing_message(chatbot_value):
"""Display the processing message while maintaining state."""
# Create new chatbot value with processing message
new_chatbot_value = [
(None, "Video is being processed. Please wait for the results...")
]
# Return all states to maintain them
return new_chatbot_value
def stream_initial_analysis(
chatbot_value, transcript_processor, cid, rsid, origin, ct, uid
):
if not transcript_processor:
return chatbot_value
try:
for chunk in get_initial_analysis(
transcript_processor, cid, rsid, origin, ct, uid
):
# Update the existing message instead of creating a new one
chatbot_value[0] = (None, chunk)
yield chatbot_value
except Exception as e:
chatbot_value[0] = (None, f"Error during analysis: {str(e)}")
yield chatbot_value
demo.load(
on_app_load,
inputs=None,
outputs=[
chatbot,
transcript_processor_state,
call_id_state,
colab_id_state,
origin_state,
ct_state,
turl_state,
uid_state,
],
).then(
display_processing_message,
inputs=[chatbot],
outputs=[chatbot],
).then(
stream_initial_analysis,
inputs=[
chatbot,
transcript_processor_state,
call_id_state,
colab_id_state,
origin_state,
ct_state,
uid_state,
],
outputs=[chatbot],
)
return demo
def main():
"""Main function to run the application."""
try:
setup_openai_key()
demo = create_chat_interface()
demo.launch(share=True)
except Exception as e:
print(f"Error starting application: {str(e)}")
raise
if __name__ == "__main__":
main()