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()