Free AI web copilot to create summaries, insights and extended knowledge, download it at here
20508
Abstract
"⬅️ Please introduce an API Key to continue..."</span>)</pre></div><ul><li>Add the new model to the list of available models whenever the user has introduced the Anthropic API key:</li></ul><div id="0101"><pre> <span class="hljs-comment"># Side bar model options and inputs</span>
<span class="hljs-keyword">with</span> st.sidebar:
st.divider()
available_models = [] + (anthropic_models <span class="hljs-keyword">if</span> anthropic_api_key <span class="hljs-keyword">else</span> []) + (google_models <span class="hljs-keyword">if</span> google_api_key <span class="hljs-keyword">else</span> []) + (openai_models <span class="hljs-keyword">if</span> openai_api_key <span class="hljs-keyword">else</span> [])
model = st.selectbox(<span class="hljs-string">"Select a model:"</span>, available_models, index=<span class="hljs-number">0</span>)
model_type = <span class="hljs-literal">None</span>
<span class="hljs-keyword">if</span> model.startswith(<span class="hljs-string">"gpt"</span>): model_type = <span class="hljs-string">"openai"</span>
<span class="hljs-keyword">elif</span> model.startswith(<span class="hljs-string">"gemini"</span>): model_type = <span class="hljs-string">"google"</span>
<span class="hljs-keyword">elif</span> model <span class="hljs-keyword">in</span> anthropic_models: model_type = <span class="hljs-string">"anthropic"</span></pre></div><ul><li>Finally, we will add a new dictionary to map better every model type with its API key, and we will adapt accordingly how we call the stream_llm_response() function from main() to get the model response as a stream of text:</li></ul><div id="a0a6"><pre> <span class="hljs-keyword">with</span> st.chat_message(<span class="hljs-string">"assistant"</span>):
model2key = {
<span class="hljs-string">"openai"</span>: openai_api_key,
<span class="hljs-string">"google"</span>: google_api_key,
<span class="hljs-string">"anthropic"</span>: anthropic_api_key,
}
st.write_stream(
stream_llm_response(
model_params=model_params,
model_type=model_type,
api_key=model2key[model_type]
)
)</pre></div><p id="b3f9">And those are the modifications to add in our previously developed multimodal chatbot app. Let’s see how the final code of <i>app.py</i> looks like now:</p><div id="7802"><pre><span class="hljs-keyword">import</span> streamlit <span class="hljs-keyword">as</span> st
<span class="hljs-keyword">from</span> openai <span class="hljs-keyword">import</span> OpenAI
<span class="hljs-keyword">import</span> dotenv
<span class="hljs-keyword">import</span> os
<span class="hljs-keyword">from</span> PIL <span class="hljs-keyword">import</span> Image
<span class="hljs-keyword">from</span> audio_recorder_streamlit <span class="hljs-keyword">import</span> audio_recorder
<span class="hljs-keyword">import</span> base64
<span class="hljs-keyword">from</span> io <span class="hljs-keyword">import</span> BytesIO
<span class="hljs-keyword">import</span> google.generativeai <span class="hljs-keyword">as</span> genai
<span class="hljs-keyword">import</span> random
<span class="hljs-keyword">import</span> anthropic
dotenv.load_dotenv()
anthropic_models = [
<span class="hljs-string">"claude-3-5-sonnet-20240620"</span>
]
google_models = [
<span class="hljs-string">"gemini-1.5-flash"</span>,
<span class="hljs-string">"gemini-1.5-pro"</span>,
]
openai_models = [
<span class="hljs-string">"gpt-4o"</span>,
<span class="hljs-string">"gpt-4-turbo"</span>,
<span class="hljs-string">"gpt-3.5-turbo-16k"</span>,
<span class="hljs-string">"gpt-4"</span>,
<span class="hljs-string">"gpt-4-32k"</span>,
]
<span class="hljs-comment"># Function to convert the messages format from OpenAI and Streamlit to Gemini</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">messages_to_gemini</span>(<span class="hljs-params">messages</span>):
gemini_messages = []
prev_role = <span class="hljs-literal">None</span>
<span class="hljs-keyword">for</span> message <span class="hljs-keyword">in</span> messages:
<span class="hljs-keyword">if</span> prev_role <span class="hljs-keyword">and</span> (prev_role == message[<span class="hljs-string">"role"</span>]):
gemini_message = gemini_messages[-<span class="hljs-number">1</span>]
<span class="hljs-keyword">else</span>:
gemini_message = {
<span class="hljs-string">"role"</span>: <span class="hljs-string">"model"</span> <span class="hljs-keyword">if</span> message[<span class="hljs-string">"role"</span>] == <span class="hljs-string">"assistant"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">"user"</span>,
<span class="hljs-string">"parts"</span>: [],
}
<span class="hljs-keyword">for</span> content <span class="hljs-keyword">in</span> message[<span class="hljs-string">"content"</span>]:
<span class="hljs-keyword">if</span> content[<span class="hljs-string">"type"</span>] == <span class="hljs-string">"text"</span>:
gemini_message[<span class="hljs-string">"parts"</span>].append(content[<span class="hljs-string">"text"</span>])
<span class="hljs-keyword">elif</span> content[<span class="hljs-string">"type"</span>] == <span class="hljs-string">"image_url"</span>:
gemini_message[<span class="hljs-string">"parts"</span>].append(base64_to_image(content[<span class="hljs-string">"image_url"</span>][<span class="hljs-string">"url"</span>]))
<span class="hljs-keyword">elif</span> content[<span class="hljs-string">"type"</span>] == <span class="hljs-string">"video_file"</span>:
gemini_message[<span class="hljs-string">"parts"</span>].append(genai.upload_file(content[<span class="hljs-string">"video_file"</span>]))
<span class="hljs-keyword">elif</span> content[<span class="hljs-string">"type"</span>] == <span class="hljs-string">"audio_file"</span>:
gemini_message[<span class="hljs-string">"parts"</span>].append(genai.upload_file(content[<span class="hljs-string">"audio_file"</span>]))
<span class="hljs-keyword">if</span> prev_role != message[<span class="hljs-string">"role"</span>]:
gemini_messages.append(gemini_message)
prev_role = message[<span class="hljs-string">"role"</span>]
<span class="hljs-keyword">return</span> gemini_messages
<span class="hljs-comment"># Function to convert the messages format from OpenAI and Streamlit to Anthropic (the only difference is in the image messages)</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">messages_to_anthropic</span>(<span class="hljs-params">messages</span>):
anthropic_messages = []
prev_role = <span class="hljs-literal">None</span>
<span class="hljs-keyword">for</span> message <span class="hljs-keyword">in</span> messages:
<span class="hljs-keyword">if</span> prev_role <span class="hljs-keyword">and</span> (prev_role == message[<span class="hljs-string">"role"</span>]):
anthropic_message = anthropic_messages[-<span class="hljs-number">1</span>]
<span class="hljs-keyword">else</span>:
anthropic_message = {
<span class="hljs-string">"role"</span>: message[<span class="hljs-string">"role"</span>] ,
<span class="hljs-string">"content"</span>: [],
}
<span class="hljs-keyword">if</span> message[<span class="hljs-string">"content"</span>][<span class="hljs-number">0</span>][<span class="hljs-string">"type"</span>] == <span class="hljs-string">"image_url"</span>:
anthropic_message[<span class="hljs-string">"content"</span>].append(
{
<span class="hljs-string">"type"</span>: <span class="hljs-string">"image"</span>,
<span class="hljs-string">"source"</span>:{
<span class="hljs-string">"type"</span>: <span class="hljs-string">"base64"</span>,
<span class="hljs-string">"media_type"</span>: message[<span class="hljs-string">"content"</span>][<span class="hljs-number">0</span>][<span class="hljs-string">"image_url"</span>][<span class="hljs-string">"url"</span>].split(<span class="hljs-string">";"</span>)[<span class="hljs-number">0</span>].split(<span class="hljs-string">":"</span>)[<span class="hljs-number">1</span>],
<span class="hljs-string">"data"</span>: message[<span class="hljs-string">"content"</span>][<span class="hljs-number">0</span>][<span class="hljs-string">"image_url"</span>][<span class="hljs-string">"url"</span>].split(<span class="hljs-string">","</span>)[<span class="hljs-number">1</span>]
<span class="hljs-comment"># f"data:{img_type};base64,{img}"</span>
}
}
)
<span class="hljs-keyword">else</span>:
anthropic_message[<span class="hljs-string">"content"</span>].append(message[<span class="hljs-string">"content"</span>][<span class="hljs-number">0</span>])
<span class="hljs-keyword">if</span> prev_role != message[<span class="hljs-string">"role"</span>]:
anthropic_messages.append(anthropic_message)
prev_role = message[<span class="hljs-string">"role"</span>]
<span class="hljs-keyword">return</span> anthropic_messages
<span class="hljs-comment"># Function to query and stream the response from the LLM</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">stream_llm_response</span>(<span class="hljs-params">model_params, model_type=<span class="hljs-string">"openai"</span>, api_key=<span class="hljs-literal">None</span></span>):
response_message = <span class="hljs-string">""</span>
<span class="hljs-keyword">if</span> model_type == <span class="hljs-string">"openai"</span>:
client = OpenAI(api_key=api_key)
<span class="hljs-keyword">for</span> chunk <span class="hljs-keyword">in</span> client.chat.completions.create(
model=model_params[<span class="hljs-string">"model"</span>] <span class="hljs-keyword">if</span> <span class="hljs-string">"model"</span> <span class="hljs-keyword">in</span> model_params <span class="hljs-keyword">else</span> <span class="hljs-string">"gpt-4o"</span>,
messages=st.session_state.messages,
temperature=model_params[<span class="hljs-string">"temperature"</span>] <span class="hljs-keyword">if</span> <span class="hljs-string">"temperature"</span> <span class="hljs-keyword">in</span> model_params <span class="hljs-keyword">else</span> <span class="hljs-number">0.3</span>,
max_tokens=<span class="hljs-number">4096</span>,
stream=<span class="hljs-literal">True</span>,
):
chunk_text = chunk.choices[<span class="hljs-number">0</span>].delta.content <span class="hljs-keyword">or</span> <span class="hljs-string">""</span>
response_message += chunk_text
<span class="hljs-keyword">yield</span> chunk_text
<span class="hljs-keyword">elif</span> model_type == <span class="hljs-string">"google"</span>:
genai.configure(api_key=api_key)
model = genai.GenerativeModel(
model_name = model_params[<span class="hljs-string">"model"</span>],
generation_config={
<span class="hljs-string">"temperature"</span>: model_params[<span class="hljs-string">"temperature"</span>] <span class="hljs-keyword">if</span> <span class="hljs-string">"temperature"</span> <span class="hljs-keyword">in</span> model_params <span class="hljs-keyword">else</span> <span class="hljs-number">0.3</span>,
}
)
gemini_messages = messages_to_gemini(st.session_state.messages)
<span class="hljs-keyword">for</span> chunk <span class="hljs-keyword">in</span> model.generate_content(
contents=gemini_messages,
stream=<span class="hljs-literal">True</span>,
):
chunk_text = chunk.text <span class="hljs-keyword">or</span> <span class="hljs-string">""</span>
response_message += chunk_text
<span class="hljs-keyword">yield</span> chunk_text
<span class="hljs-keyword">elif</span> model_type == <span class="hljs-string">"anthropic"</span>:
client = anthropic.Anthropic(api_key=api_key)
<span class="hljs-keyword">with</span> client.messages.stream(
model=model_params[<span class="hljs-string">"model"</span>] <span class="hljs-keyword">if</span> <span class="hljs-string">"model"</span> <span class="hljs-keyword">in</span> model_params <span class="hljs-keyword">else</span> <span class="hljs-string">"claude-3-5-sonnet-20240620"</span>,
messages=messages_to_anthropic(st.session_state.messages),
temperature=model_params[<span class="hljs-string">"temperature"</span>] <span class="hljs-keyword">if</span> <span class="hljs-string">"temperature"</span> <span class="hljs-keyword">in</span> model_params <span class="hljs-keyword">else</span> <span class="hljs-number">0.3</span>,
max_tokens=<span class="hljs-number">4096</span>,
) <span class="hljs-keyword">as</span> stream:
<span class="hljs-keyword">for</span> text <span class="hljs-keyword">in</span> stream.text_stream:
response_message += text
<span class="hljs-keyword">yield</span> text
st.session_state.messages.append({
<span class="hljs-string">"role"</span>: <span class="hljs-string">"assistant"</span>,
<span class="hljs-string">"content"</span>: [
{
<span class="hljs-string">"type"</span>: <span class="hljs-string">"text"</span>,
<span class="hljs-string">"text"</span>: response_message,
}
]})
<span class="hljs-comment"># Function to convert file to base64</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">get_image_base64</span>(<span class="hljs-params">image_raw</span>):
buffered = BytesIO()
image_raw.save(buffered, <span class="hljs-built_in">format</span>=image_raw.<span class="hljs-built_in">format</span>)
img_byte = buffered.getvalue()
<span class="hljs-keyword">return</span> base64.b64encode(img_byte).decode(<span class="hljs-string">'utf-8'</span>)
<span class="hljs-keyword">def</span> <span class="hljs-title function_">file_to_base64</span>(<span class="hljs-params">file</span>):
<span class="hljs-keyword">with</span> <span class="hljs-built_in">open</span>(file, <span class="hljs-string">"rb"</span>) <span class="hljs-keyword">as</span> f:
<span class="hljs-keyword">return</span> base64.b64encode(f.read()).decode(<span class="hljs-string">'utf-8'</span>)
<span class="hljs-keyword">def</span> <span class="hljs-title function_">base64_to_image</span>(<span class="hljs-params">base64_string</span>):
base64_string = base64_string.split(<span class="hljs-string">","</span>)[<span class="hljs-number">1</span>]
<span class="hljs-keyword">return</span> Image.<span class="hljs-built_in">open</span>(BytesIO(base64.b64decode(base64_string)))
<span class="hljs-keyword">def</span> <span class="hljs-title function_">main</span>():
<span class="hljs-comment"># --- Page Config ---</span>
st.set_page_config(
page_title=<span class="hljs-string">"The OmniChat"</span>,
page_icon=<span class="hljs-string">"🤖"</span>,
layout=<span class="hljs-string">"centered"</span>,
initial_sidebar_state=<span class="hljs-string">"expanded"</span>,
)
<span class="hljs-comment"># --- Header ---</span>
st.html(<span class="hljs-string">"""<h1 style="text-align: center; color: #6ca395;">🤖 <i>The OmniChat</i> 💬</h1>"""</span>)
<span class="hljs-comment"># --- Side Bar ---</span>
<span class="hljs-keyword">with</span> st.sidebar:
cols_keys = st.columns(<span class="hljs-number">2</span>)
<span class="hljs-keyword">with</span> cols_keys[<span class="hljs-number">0</span>]:
default_openai_api_key = os.getenv(<span class="hljs-string">"OPENAI_API_KEY"</span>) <span class="hljs-keyword">if</span> os.getenv(<span class="hljs-string">"OPENAI_API_KEY"</span>) <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">None</span> <span class="hljs-keyword">else</span> <span class="hljs-string">""</span> <span class="hljs-comment"># only for development environment, otherwise it should return None</span>
<span class="hljs-keyword">with</span> st.popover(<span class="hljs-string">"🔐 OpenAI"</span>):
openai_api_key = st.text_input(<span class="hljs-string">"Introduce your OpenAI API Key (https://platform.openai.com/)"</span>, value=default_openai_api_key, <span class="hljs-built_in">type</span>=<span class="hljs-string">"password"</span>)
<span class="hljs-keyword">with</span> cols_keys[<span class="hljs-number">1</span>]:
default_google_api_key = os.getenv(<span class="hljs-string">"GOOGLE_API_KEY"</span>) <span class="hljs-keyword">if</span> os.getenv(<span class="hljs-string">"GOOGLE_API_KEY"</span>) <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">None</span> <span class="hljs-keyword">else</span> <span class="hljs-string">""</span>
<span class="hljs-keyword">with</span> st.popover(<span class="hljs-string">"🔐 Google"</span>):
google_api_key = st.text_input(<span class="hljs-string">"Introduce your Google API Key (https://aistudio.google.com/app/apikey)"</span>, value=default_google_api_key, <span class="hljs-built_in">type</span>=<span class="hljs-string">"password"</span>)
default_anthropic_api_key = os.getenv(<span class="hljs-string">"ANTHROPIC_API_KEY"</span>) <span class="hljs-keyword">if</span> os.getenv(<span class="hljs-string">"ANTHROPIC_API_KEY"</span>) <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">None</span> <span class="hljs-keyword">else</span> <span class="hljs-string">""</span>
<span class="hljs-keyword">with</span> st.popover(<span class="hljs-string">"🔐 Anthropic"</span>):
anthropic_api_key = st.text_input(<span class="hljs-string">"Introduce your Anthropic API Key (https://console.anthropic.com/)"</span>, value=default_anthropic_api_key, <span class="hljs-built_in">type</span>=<span class="hljs-string">"password"</span>)
<span class="hljs-comment"># --- Main Content ---</span>
<span class="hljs-comment"># Checking if the user has introduced the OpenAI API Key, if not, a warning is displayed</span>
<span class="hljs-keyword">if</span> (openai_api_key == <span class="hljs-string">""</span> <span class="hljs-keyword">or</span> openai_api_key <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>) <span class="hljs-keyword">and</span> (google_api_key == <span class="hljs-string">""</span> <span class="hljs-keyword">or</span> google_api_key <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>) <span class="hljs-keyword">and</span> (anthropic_api_key == <span class="hljs-string">""</span> <span class="hljs-keyword">or</span> anthropic_api_key <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>):
st.write(<span class="hljs-string">"#"</span>)
st.warning(<span class="hljs-string">"⬅️ Please introduce an API Key to continue..."</span>)
<span class="hljs-keyword">with</span> st.sidebar:
st.write(<span class="hljs-string">"#"</span>)
st.write(<span class="hljs-string">"#"</span>)
st.video(<span class="hljs-string">"https://www.youtube.com/watch?v=7i9j8M_zidA"</span>)
st.write(<span class="hljs-string">"📋[Medium Blog: OpenAI GPT-4o](https://readmedium.com/code-the-omnichat-app-integrating-gpt-4o-your-python-chatgpt-d399b90d178
Options
e)"</span>)
st.video(<span class="hljs-string">"https://www.youtube.com/watch?v=1IQmWVFNQEs"</span>)
st.write(<span class="hljs-string">"📋Medium Blog: Google Gemini"</span>)
<span class="hljs-keyword">else</span>:
client = OpenAI(api_key=openai_api_key)
<span class="hljs-keyword">if</span> <span class="hljs-string">"messages"</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> st.session_state:
st.session_state.messages = []
<span class="hljs-comment"># Displaying the previous messages if there are any</span>
<span class="hljs-keyword">for</span> message <span class="hljs-keyword">in</span> st.session_state.messages:
<span class="hljs-keyword">with</span> st.chat_message(message[<span class="hljs-string">"role"</span>]):
<span class="hljs-keyword">for</span> content <span class="hljs-keyword">in</span> message[<span class="hljs-string">"content"</span>]:
<span class="hljs-keyword">if</span> content[<span class="hljs-string">"type"</span>] == <span class="hljs-string">"text"</span>:
st.write(content[<span class="hljs-string">"text"</span>])
<span class="hljs-keyword">elif</span> content[<span class="hljs-string">"type"</span>] == <span class="hljs-string">"image_url"</span>:
st.image(content[<span class="hljs-string">"image_url"</span>][<span class="hljs-string">"url"</span>])
<span class="hljs-keyword">elif</span> content[<span class="hljs-string">"type"</span>] == <span class="hljs-string">"video_file"</span>:
st.video(content[<span class="hljs-string">"video_file"</span>])
<span class="hljs-keyword">elif</span> content[<span class="hljs-string">"type"</span>] == <span class="hljs-string">"audio_file"</span>:
st.audio(content[<span class="hljs-string">"audio_file"</span>])
<span class="hljs-comment"># Side bar model options and inputs</span>
<span class="hljs-keyword">with</span> st.sidebar:
st.divider()
available_models = [] + (anthropic_models <span class="hljs-keyword">if</span> anthropic_api_key <span class="hljs-keyword">else</span> []) + (google_models <span class="hljs-keyword">if</span> google_api_key <span class="hljs-keyword">else</span> []) + (openai_models <span class="hljs-keyword">if</span> openai_api_key <span class="hljs-keyword">else</span> [])
model = st.selectbox(<span class="hljs-string">"Select a model:"</span>, available_models, index=<span class="hljs-number">0</span>)
model_type = <span class="hljs-literal">None</span>
<span class="hljs-keyword">if</span> model.startswith(<span class="hljs-string">"gpt"</span>): model_type = <span class="hljs-string">"openai"</span>
<span class="hljs-keyword">elif</span> model.startswith(<span class="hljs-string">"gemini"</span>): model_type = <span class="hljs-string">"google"</span>
<span class="hljs-keyword">elif</span> model <span class="hljs-keyword">in</span> anthropic_models: model_type = <span class="hljs-string">"anthropic"</span>
<span class="hljs-keyword">with</span> st.popover(<span class="hljs-string">"⚙️ Model parameters"</span>):
model_temp = st.slider(<span class="hljs-string">"Temperature"</span>, min_value=<span class="hljs-number">0.0</span>, max_value=<span class="hljs-number">2.0</span>, value=<span class="hljs-number">0.3</span>, step=<span class="hljs-number">0.1</span>)
audio_response = st.toggle(<span class="hljs-string">"Audio response"</span>, value=<span class="hljs-literal">False</span>)
<span class="hljs-keyword">if</span> audio_response:
cols = st.columns(<span class="hljs-number">2</span>)
<span class="hljs-keyword">with</span> cols[<span class="hljs-number">0</span>]:
tts_voice = st.selectbox(<span class="hljs-string">"Select a voice:"</span>, [<span class="hljs-string">"alloy"</span>, <span class="hljs-string">"echo"</span>, <span class="hljs-string">"fable"</span>, <span class="hljs-string">"onyx"</span>, <span class="hljs-string">"nova"</span>, <span class="hljs-string">"shimmer"</span>])
<span class="hljs-keyword">with</span> cols[<span class="hljs-number">1</span>]:
tts_model = st.selectbox(<span class="hljs-string">"Select a model:"</span>, [<span class="hljs-string">"tts-1"</span>, <span class="hljs-string">"tts-1-hd"</span>], index=<span class="hljs-number">1</span>)
model_params = {
<span class="hljs-string">"model"</span>: model,
<span class="hljs-string">"temperature"</span>: model_temp,
}
<span class="hljs-keyword">def</span> <span class="hljs-title function_">reset_conversation</span>():
<span class="hljs-keyword">if</span> <span class="hljs-string">"messages"</span> <span class="hljs-keyword">in</span> st.session_state <span class="hljs-keyword">and</span> <span class="hljs-built_in">len</span>(st.session_state.messages) > <span class="hljs-number">0</span>:
st.session_state.pop(<span class="hljs-string">"messages"</span>, <span class="hljs-literal">None</span>)
st.button(
<span class="hljs-string">"🗑️ Reset conversation"</span>,
on_click=reset_conversation,
)
st.divider()
<span class="hljs-comment"># Image Upload</span>
<span class="hljs-keyword">if</span> model <span class="hljs-keyword">in</span> [<span class="hljs-string">"gpt-4o"</span>, <span class="hljs-string">"gpt-4-turbo"</span>, <span class="hljs-string">"gemini-1.5-flash"</span>, <span class="hljs-string">"gemini-1.5-pro"</span>, <span class="hljs-string">"claude-3-5-sonnet-20240620"</span>]:
st.write(<span class="hljs-string">f"### **🖼️ Add an image<span class="hljs-subst">{<span class="hljs-string">' or a video file'</span> <span class="hljs-keyword">if</span> model_type==<span class="hljs-string">'google'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>}</span>:**"</span>)
<span class="hljs-keyword">def</span> <span class="hljs-title function_">add_image_to_messages</span>():
<span class="hljs-keyword">if</span> st.session_state.uploaded_img <span class="hljs-keyword">or</span> (<span class="hljs-string">"camera_img"</span> <span class="hljs-keyword">in</span> st.session_state <span class="hljs-keyword">and</span> st.session_state.camera_img):
img_type = st.session_state.uploaded_img.<span class="hljs-built_in">type</span> <span class="hljs-keyword">if</span> st.session_state.uploaded_img <span class="hljs-keyword">else</span> <span class="hljs-string">"image/jpeg"</span>
<span class="hljs-keyword">if</span> img_type == <span class="hljs-string">"video/mp4"</span>:
<span class="hljs-comment"># save the video file</span>
video_id = random.randint(<span class="hljs-number">100000</span>, <span class="hljs-number">999999</span>)
<span class="hljs-keyword">with</span> <span class="hljs-built_in">open</span>(<span class="hljs-string">f"video_<span class="hljs-subst">{video_id}</span>.mp4"</span>, <span class="hljs-string">"wb"</span>) <span class="hljs-keyword">as</span> f:
f.write(st.session_state.uploaded_img.read())
st.session_state.messages.append(
{
<span class="hljs-string">"role"</span>: <span class="hljs-string">"user"</span>,
<span class="hljs-string">"content"</span>: [{
<span class="hljs-string">"type"</span>: <span class="hljs-string">"video_file"</span>,
<span class="hljs-string">"video_file"</span>: <span class="hljs-string">f"video_<span class="hljs-subst">{video_id}</span>.mp4"</span>,
}]
}
)
<span class="hljs-keyword">else</span>:
raw_img = Image.<span class="hljs-built_in">open</span>(st.session_state.uploaded_img <span class="hljs-keyword">or</span> st.session_state.camera_img)
img = get_image_base64(raw_img)
st.session_state.messages.append(
{
<span class="hljs-string">"role"</span>: <span class="hljs-string">"user"</span>,
<span class="hljs-string">"content"</span>: [{
<span class="hljs-string">"type"</span>: <span class="hljs-string">"image_url"</span>,
<span class="hljs-string">"image_url"</span>: {<span class="hljs-string">"url"</span>: <span class="hljs-string">f"data:<span class="hljs-subst">{img_type}</span>;base64,<span class="hljs-subst">{img}</span>"</span>}
}]
}
)
cols_img = st.columns(<span class="hljs-number">2</span>)
<span class="hljs-keyword">with</span> cols_img[<span class="hljs-number">0</span>]:
<span class="hljs-keyword">with</span> st.popover(<span class="hljs-string">"📁 Upload"</span>):
st.file_uploader(
<span class="hljs-string">f"Upload an image<span class="hljs-subst">{<span class="hljs-string">' or a video'</span> <span class="hljs-keyword">if</span> model_type == <span class="hljs-string">'google'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>}</span>:"</span>,
<span class="hljs-built_in">type</span>=[<span class="hljs-string">"png"</span>, <span class="hljs-string">"jpg"</span>, <span class="hljs-string">"jpeg"</span>] + ([<span class="hljs-string">"mp4"</span>] <span class="hljs-keyword">if</span> model_type == <span class="hljs-string">"google"</span> <span class="hljs-keyword">else</span> []),
accept_multiple_files=<span class="hljs-literal">False</span>,
key=<span class="hljs-string">"uploaded_img"</span>,
on_change=add_image_to_messages,
)
<span class="hljs-keyword">with</span> cols_img[<span class="hljs-number">1</span>]:
<span class="hljs-keyword">with</span> st.popover(<span class="hljs-string">"📸 Camera"</span>):
activate_camera = st.checkbox(<span class="hljs-string">"Activate camera"</span>)
<span class="hljs-keyword">if</span> activate_camera:
st.camera_input(
<span class="hljs-string">"Take a picture"</span>,
key=<span class="hljs-string">"camera_img"</span>,
on_change=add_image_to_messages,
)
<span class="hljs-comment"># Audio Upload</span>
st.write(<span class="hljs-string">"#"</span>)
st.write(<span class="hljs-string">f"### **🎤 Add an audio<span class="hljs-subst">{<span class="hljs-string">' (Speech To Text)'</span> <span class="hljs-keyword">if</span> model_type == <span class="hljs-string">'openai'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>}</span>:**"</span>)
audio_prompt = <span class="hljs-literal">None</span>
audio_file_added = <span class="hljs-literal">False</span>
<span class="hljs-keyword">if</span> <span class="hljs-string">"prev_speech_hash"</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> st.session_state:
st.session_state.prev_speech_hash = <span class="hljs-literal">None</span>
speech_input = audio_recorder(<span class="hljs-string">"Press to talk:"</span>, icon_size=<span class="hljs-string">"3x"</span>, neutral_color=<span class="hljs-string">"#6ca395"</span>, )
<span class="hljs-keyword">if</span> speech_input <span class="hljs-keyword">and</span> st.session_state.prev_speech_hash != <span class="hljs-built_in">hash</span>(speech_input):
st.session_state.prev_speech_hash = <span class="hljs-built_in">hash</span>(speech_input)
<span class="hljs-keyword">if</span> model_type != <span class="hljs-string">"google"</span>:
transcript = client.audio.transcriptions.create(
model=<span class="hljs-string">"whisper-1"</span>,
file=(<span class="hljs-string">"audio.wav"</span>, speech_input),
)
audio_prompt = transcript.text
<span class="hljs-keyword">else</span>:
<span class="hljs-comment"># save the audio file</span>
audio_id = random.randint(<span class="hljs-number">100000</span>, <span class="hljs-number">999999</span>)
<span class="hljs-keyword">with</span> <span class="hljs-built_in">open</span>(<span class="hljs-string">f"audio_<span class="hljs-subst">{audio_id}</span>.wav"</span>, <span class="hljs-string">"wb"</span>) <span class="hljs-keyword">as</span> f:
f.write(speech_input)
st.session_state.messages.append(
{
<span class="hljs-string">"role"</span>: <span class="hljs-string">"user"</span>,
<span class="hljs-string">"content"</span>: [{
<span class="hljs-string">"type"</span>: <span class="hljs-string">"audio_file"</span>,
<span class="hljs-string">"audio_file"</span>: <span class="hljs-string">f"audio_<span class="hljs-subst">{audio_id}</span>.wav"</span>,
}]
}
)
audio_file_added = <span class="hljs-literal">True</span>
st.divider()
st.video(<span class="hljs-string">"https://www.youtube.com/watch?v=7i9j8M_zidA"</span>)
st.write(<span class="hljs-string">"📋[Medium Blog: OpenAI GPT-4o](https://readmedium.com/code-the-omnichat-app-integrating-gpt-4o-your-python-chatgpt-d399b90d178e)"</span>)
st.video(<span class="hljs-string">"https://www.youtube.com/watch?v=1IQmWVFNQEs"</span>)
st.write(<span class="hljs-string">"📋[Medium Blog: Google Gemini](https://readmedium.com/how-i-add-gemini-1-5-pro-api-to-my-app-chat-with-videos-images-and-audios-f42171606143)"</span>)
<span class="hljs-comment"># Chat input</span>
<span class="hljs-keyword">if</span> prompt := st.chat_input(<span class="hljs-string">"Hi! Ask me anything..."</span>) <span class="hljs-keyword">or</span> audio_prompt <span class="hljs-keyword">or</span> audio_file_added:
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> audio_file_added:
st.session_state.messages.append(
{
<span class="hljs-string">"role"</span>: <span class="hljs-string">"user"</span>,
<span class="hljs-string">"content"</span>: [{
<span class="hljs-string">"type"</span>: <span class="hljs-string">"text"</span>,
<span class="hljs-string">"text"</span>: prompt <span class="hljs-keyword">or</span> audio_prompt,
}]
}
)
<span class="hljs-comment"># Display the new messages</span>
<span class="hljs-keyword">with</span> st.chat_message(<span class="hljs-string">"user"</span>):
st.markdown(prompt)
<span class="hljs-keyword">else</span>:
<span class="hljs-comment"># Display the audio file</span>
<span class="hljs-keyword">with</span> st.chat_message(<span class="hljs-string">"user"</span>):
st.audio(<span class="hljs-string">f"audio_<span class="hljs-subst">{audio_id}</span>.wav"</span>)
<span class="hljs-keyword">with</span> st.chat_message(<span class="hljs-string">"assistant"</span>):
model2key = {
<span class="hljs-string">"openai"</span>: openai_api_key,
<span class="hljs-string">"google"</span>: google_api_key,
<span class="hljs-string">"anthropic"</span>: anthropic_api_key,
}
st.write_stream(
stream_llm_response(
model_params=model_params,
model_type=model_type,
api_key=model2key[model_type]
)
)
<span class="hljs-comment"># --- Added Audio Response (optional) ---</span>
<span class="hljs-keyword">if</span> audio_response:
response = client.audio.speech.create(
model=tts_model,
voice=tts_voice,
<span class="hljs-built_in">input</span>=st.session_state.messages[-<span class="hljs-number">1</span>][<span class="hljs-string">"content"</span>][<span class="hljs-number">0</span>][<span class="hljs-string">"text"</span>],
)
audio_base64 = base64.b64encode(response.content).decode(<span class="hljs-string">'utf-8'</span>)
audio_html = <span class="hljs-string">f"""
<audio controls autoplay>
<source src="data:audio/wav;base64,<span class="hljs-subst">{audio_base64}</span>" type="audio/mp3">
</audio>
"""</span>
st.html(audio_html)
<span class="hljs-keyword">if</span> name==<span class="hljs-string">"main"</span>:
main()</pre></div><p id="287f">You can check it also in the <a href="https://github.com/enricd/the_omnichat">GitHub repo</a> of the project and clone it from there to get the <i>requirements.txt</i> dependencies. You will need to install all the libraries from it with the following command:</p><div id="ff4f"><pre><span class="hljs-comment"># You can create and activate a virtual environment first if you prefer</span>
$ git <span class="hljs-built_in">clone</span> <project-url>
$ <span class="hljs-built_in">cd</span> the_omnichat
pip install -r requirements.txt</pre></div><p id="1bca">Now, you can try to run the app locally (remember to manually add the <i>.env</i> file with your api keys defined as environment variables in there first):</p><div id="f2f9"><pre> streamlit run app.py</pre></div><p id="e448">It should show up a new tab in your browser with the app running in localhost:8501.</p><figure id="3c6e"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*XM52RoIJ4x_7W-3BkTMd0g.png"><figcaption></figcaption></figure><p id="69a7">So we can try to chat with it with text and images and see if it really works.</p><p id="337e">Finally, as we already deployed this webiste into the Streamlit Cloud for free, linking our Streamlit account to our GitHub repo, if we commit and push these new changes, they will be automatically applied in our online The OmniChat app available from any device connected to the internet: <a href="https://the-omnichat.streamlit.app/">https://the-omnichat.streamlit.app/</a></p><p id="1b5f">I hope you enjoyed this content! Consider leaving an applause, a like to the video and subcribing to my channel 🤗. Feel free to leave any comment or question and see you in the next one!! 🚀</p></article></body>