Upload 2 files
Browse files- app.py +126 -60
- chatbot.py +27 -0
app.py
CHANGED
|
@@ -1,64 +1,130 @@
|
|
| 1 |
-
import
|
| 2 |
-
from
|
| 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 |
-
max_tokens=max_tokens,
|
| 33 |
-
stream=True,
|
| 34 |
-
temperature=temperature,
|
| 35 |
-
top_p=top_p,
|
| 36 |
-
):
|
| 37 |
-
token = message.choices[0].delta.content
|
| 38 |
-
|
| 39 |
-
response += token
|
| 40 |
-
yield response
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
"""
|
| 44 |
-
For information on how to customize the ChatInterface, peruse the gradio docs: https://www.gradio.app/docs/chatinterface
|
| 45 |
-
"""
|
| 46 |
-
demo = gr.ChatInterface(
|
| 47 |
-
respond,
|
| 48 |
-
additional_inputs=[
|
| 49 |
-
gr.Textbox(value="You are a friendly Chatbot.", label="System message"),
|
| 50 |
-
gr.Slider(minimum=1, maximum=2048, value=512, step=1, label="Max new tokens"),
|
| 51 |
-
gr.Slider(minimum=0.1, maximum=4.0, value=0.7, step=0.1, label="Temperature"),
|
| 52 |
-
gr.Slider(
|
| 53 |
-
minimum=0.1,
|
| 54 |
-
maximum=1.0,
|
| 55 |
-
value=0.95,
|
| 56 |
-
step=0.05,
|
| 57 |
-
label="Top-p (nucleus sampling)",
|
| 58 |
-
),
|
| 59 |
],
|
|
|
|
| 60 |
)
|
| 61 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
|
| 63 |
-
|
| 64 |
-
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
from PIL import Image
|
| 3 |
+
import time
|
| 4 |
+
from chatbot import chat_with_image
|
| 5 |
+
|
| 6 |
+
USER_AVATAR = "👤"
|
| 7 |
+
BOT_AVATAR = '<img src="https://img.icons8.com/emoji/48/robot-emoji.png" width="20"/>'
|
| 8 |
+
|
| 9 |
+
st.set_page_config(page_title="Gemini 2.5 Image Chatbot", layout="wide")
|
| 10 |
+
|
| 11 |
+
st.sidebar.header("🌐 Language Settings")
|
| 12 |
+
selected_language = st.sidebar.selectbox(
|
| 13 |
+
"Select response language",
|
| 14 |
+
[
|
| 15 |
+
"Afrikaans", "Albanian", "Amharic", "Arabic", "Armenian", "Assamese", "Azerbaijani",
|
| 16 |
+
"Basque", "Belarusian", "Bengali", "Bosnian", "Bulgarian", "Burmese",
|
| 17 |
+
"Catalan", "Cebuano", "Chinese", "Corsican", "Croatian", "Czech",
|
| 18 |
+
"Danish", "Dutch", "English", "Esperanto", "Estonian",
|
| 19 |
+
"Finnish", "French", "Frisian",
|
| 20 |
+
"Galician", "Georgian", "German", "Greek", "Gujarati",
|
| 21 |
+
"Haitian Creole", "Hausa", "Hawaiian", "Hebrew", "Hindi", "Hmong", "Hungarian",
|
| 22 |
+
"Icelandic", "Igbo", "Indonesian", "Irish", "Italian",
|
| 23 |
+
"Japanese", "Javanese", "Kannada", "Kazakh", "Khmer", "Kinyarwanda", "Korean", "Kurdish",
|
| 24 |
+
"Kyrgyz", "Lao", "Latin", "Latvian", "Lithuanian", "Luxembourgish",
|
| 25 |
+
"Macedonian", "Malagasy", "Malay", "Malayalam", "Maltese", "Maori", "Marathi", "Mongolian",
|
| 26 |
+
"Nepali", "Norwegian", "Nyanja", "Odia", "Pashto", "Persian", "Polish", "Portuguese",
|
| 27 |
+
"Punjabi", "Quechua", "Romanian", "Russian", "Samoan", "Scots Gaelic", "Serbian", "Sesotho",
|
| 28 |
+
"Shona", "Sindhi", "Sinhala", "Slovak", "Slovenian", "Somali", "Spanish", "Sundanese",
|
| 29 |
+
"Swahili", "Swedish", "Tagalog", "Tajik", "Tamil", "Tatar", "Telugu", "Thai",
|
| 30 |
+
"Tigrinya", "Turkish", "Turkmen", "Ukrainian", "Urdu", "Uyghur", "Uzbek", "Vietnamese",
|
| 31 |
+
"Welsh", "Xhosa", "Yiddish", "Yoruba", "Zulu"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
],
|
| 33 |
+
index=21
|
| 34 |
)
|
| 35 |
|
| 36 |
+
st.markdown("<h1 style='text-align: center;'>Welcome, Gemini 2.5 Flash Image Chatbot 2.0</h1>", unsafe_allow_html=True)
|
| 37 |
+
|
| 38 |
+
if "history" not in st.session_state:
|
| 39 |
+
st.session_state.history = []
|
| 40 |
+
if "images" not in st.session_state:
|
| 41 |
+
st.session_state.images = []
|
| 42 |
+
if "current_image_index" not in st.session_state:
|
| 43 |
+
st.session_state.current_image_index = None
|
| 44 |
+
if "last_animated_index" not in st.session_state:
|
| 45 |
+
st.session_state.last_animated_index = None
|
| 46 |
+
|
| 47 |
+
left_col, right_col = st.columns([1, 5])
|
| 48 |
+
|
| 49 |
+
with left_col:
|
| 50 |
+
st.header("📁 Upload Image")
|
| 51 |
+
uploaded_file = st.file_uploader(
|
| 52 |
+
"Drop an image here",
|
| 53 |
+
type=["jpg", "jpeg", "png"],
|
| 54 |
+
accept_multiple_files=False,
|
| 55 |
+
label_visibility="collapsed"
|
| 56 |
+
)
|
| 57 |
+
|
| 58 |
+
if uploaded_file:
|
| 59 |
+
image = Image.open(uploaded_file).convert("RGB")
|
| 60 |
+
st.session_state.images = [image]
|
| 61 |
+
st.session_state.current_image_index = 0
|
| 62 |
+
st.image(image, caption="Uploaded Image", use_container_width=True)
|
| 63 |
+
else:
|
| 64 |
+
st.session_state.images = []
|
| 65 |
+
st.session_state.current_image_index = None
|
| 66 |
+
|
| 67 |
+
with right_col:
|
| 68 |
+
if st.session_state.images and st.session_state.current_image_index is not None:
|
| 69 |
+
current_image = st.session_state.images[st.session_state.current_image_index]
|
| 70 |
+
|
| 71 |
+
st.markdown("### Chat With Image:")
|
| 72 |
+
st.markdown(f"#### Language : `{selected_language}`")
|
| 73 |
+
|
| 74 |
+
history = st.session_state.history
|
| 75 |
+
|
| 76 |
+
latest_index = None
|
| 77 |
+
for idx in reversed(range(len(history))):
|
| 78 |
+
msg = history[idx]
|
| 79 |
+
if (
|
| 80 |
+
msg["sender"] == "Gemini" and
|
| 81 |
+
msg["image_index"] == st.session_state.current_image_index and
|
| 82 |
+
idx != st.session_state.last_animated_index
|
| 83 |
+
):
|
| 84 |
+
latest_index = idx
|
| 85 |
+
break
|
| 86 |
+
|
| 87 |
+
for i, msg in enumerate(history):
|
| 88 |
+
if msg["image_index"] != st.session_state.current_image_index:
|
| 89 |
+
continue
|
| 90 |
+
|
| 91 |
+
if msg["sender"] == "You":
|
| 92 |
+
st.markdown(f"""
|
| 93 |
+
<div style="background-color: #f1f1f1; padding: 10px; border-radius: 8px; margin-bottom: 10px;">
|
| 94 |
+
<strong>{USER_AVATAR} :</strong> {msg['message']}
|
| 95 |
+
</div>
|
| 96 |
+
""", unsafe_allow_html=True)
|
| 97 |
+
|
| 98 |
+
elif msg["sender"] == "Gemini":
|
| 99 |
+
if i == latest_index:
|
| 100 |
+
st.session_state.last_animated_index = i
|
| 101 |
+
placeholder = st.empty()
|
| 102 |
+
full_response = msg["message"]
|
| 103 |
+
for j in range(1, len(full_response) + 1):
|
| 104 |
+
placeholder.markdown(f"{BOT_AVATAR} : {full_response[:j]}", unsafe_allow_html=True)
|
| 105 |
+
time.sleep(0.002)
|
| 106 |
+
else:
|
| 107 |
+
st.markdown(f"{BOT_AVATAR} : {msg['message']}", unsafe_allow_html=True)
|
| 108 |
+
|
| 109 |
+
user_prompt = st.chat_input("Ask About Image")
|
| 110 |
+
if user_prompt:
|
| 111 |
+
full_prompt = f"{user_prompt}\n\nPlease respond in {selected_language}."
|
| 112 |
+
try:
|
| 113 |
+
gemini_response = chat_with_image(full_prompt, current_image)
|
| 114 |
+
except Exception as e:
|
| 115 |
+
gemini_response = f"Gemini failed to respond: {e}"
|
| 116 |
+
|
| 117 |
+
st.session_state.history.append({
|
| 118 |
+
"sender": "You",
|
| 119 |
+
"message": user_prompt,
|
| 120 |
+
"image_index": st.session_state.current_image_index
|
| 121 |
+
})
|
| 122 |
+
st.session_state.history.append({
|
| 123 |
+
"sender": "Gemini",
|
| 124 |
+
"message": gemini_response,
|
| 125 |
+
"image_index": st.session_state.current_image_index
|
| 126 |
+
})
|
| 127 |
|
| 128 |
+
st.rerun()
|
| 129 |
+
else:
|
| 130 |
+
st.info("Please upload an image to start chatting.")
|
chatbot.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import base64
|
| 2 |
+
import io
|
| 3 |
+
from PIL import Image
|
| 4 |
+
from langchain_google_genai import ChatGoogleGenerativeAI
|
| 5 |
+
from langchain_core.messages import HumanMessage
|
| 6 |
+
|
| 7 |
+
llm = ChatGoogleGenerativeAI(model="gemini-2.5-flash", temperature=0.1)
|
| 8 |
+
|
| 9 |
+
def image_to_base64(image: Image.Image) -> str:
|
| 10 |
+
buffered = io.BytesIO()
|
| 11 |
+
image.save(buffered, format="JPEG")
|
| 12 |
+
return base64.b64encode(buffered.getvalue()).decode("utf-8")
|
| 13 |
+
|
| 14 |
+
def chat_with_image(user_prompt: str, image: Image.Image) -> str:
|
| 15 |
+
img_base64 = image_to_base64(image)
|
| 16 |
+
message = [
|
| 17 |
+
HumanMessage(content=[
|
| 18 |
+
{"type": "text", "text": user_prompt},
|
| 19 |
+
{
|
| 20 |
+
"type": "media",
|
| 21 |
+
"mime_type": "image/jpeg",
|
| 22 |
+
"data": img_base64
|
| 23 |
+
}
|
| 24 |
+
])
|
| 25 |
+
]
|
| 26 |
+
response = llm.invoke(message)
|
| 27 |
+
return response.content
|