aiqcamp commited on
Commit
826ffd7
·
verified ·
1 Parent(s): 9809596

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +238 -1
app.py CHANGED
@@ -1,3 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  if isinstance(message_input, str):
2
  user_message = message_input
3
  print(f"\n=== New Request (Text) ===")
@@ -5,4 +39,207 @@
5
  if not user_message.strip(): # Check if text message is empty or whitespace
6
  messages.append(ChatMessage(role="assistant", content="Please input a text message or upload a file. Empty input is not allowed."))
7
  yield messages
8
- return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ from gradio import ChatMessage
4
+ from typing import Iterator
5
+ import google.generativeai as genai
6
+
7
+ # get Gemini API Key from the environ variable
8
+ GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
9
+ genai.configure(api_key=GEMINI_API_KEY)
10
+
11
+ # we will be using the Gemini 2.0 Flash model with Thinking capabilities
12
+ model = genai.GenerativeModel("gemini-2.0-flash-thinking-exp-1219") # Consider Gemini Pro Vision for Image input
13
+
14
+ def format_chat_history(messages: list) -> list:
15
+ """
16
+ Formats the chat history into a structure Gemini can understand
17
+ """
18
+ formatted_history = []
19
+ for message in messages:
20
+ # Skip thinking messages (messages with metadata)
21
+ if not (message.get("role") == "assistant" and "metadata" in message):
22
+ formatted_history.append({
23
+ "role": "user" if message.get("role") == "user" else "assistant",
24
+ "parts": [message.get("content", "")]
25
+ })
26
+ return formatted_history
27
+
28
+ def stream_gemini_response(message_input: str|gr.File, messages: list) -> Iterator[list]:
29
+ """
30
+ Streams thoughts and response with conversation history support, handling text or file input.
31
+ """
32
+ user_message = ""
33
+ input_file = None
34
+
35
  if isinstance(message_input, str):
36
  user_message = message_input
37
  print(f"\n=== New Request (Text) ===")
 
39
  if not user_message.strip(): # Check if text message is empty or whitespace
40
  messages.append(ChatMessage(role="assistant", content="Please input a text message or upload a file. Empty input is not allowed."))
41
  yield messages
42
+ return
43
+
44
+
45
+ elif isinstance(message_input, gr.File): #gr.File directly should be used with newer gradio versions (v4+)
46
+ input_file = message_input.name # Access the temporary file path
47
+ file_type = message_input.original_name.split('.')[-1].lower() #Get original filename's extension
48
+ print(f"\n=== New Request (File) ===")
49
+ print(f"File uploaded: {input_file}, type: {file_type}")
50
+
51
+ try:
52
+ with open(input_file, "rb") as f: #Open file in binary mode for universal handling
53
+ file_data = f.read()
54
+
55
+ if file_type in ['png', 'jpg', 'jpeg', 'gif']: #Example Image Types - expand as needed
56
+ user_message = {"inline_data": {"mime_type": f"image/{file_type}", "data": file_data}} #Prepare image part for Gemini
57
+ elif file_type == 'csv':
58
+ user_message = {"inline_data": {"mime_type": "text/csv", "data": file_data}} #Prepare csv part
59
+
60
+ except Exception as e:
61
+ print(f"Error reading file: {e}")
62
+ messages.append(ChatMessage(role="assistant", content=f"Error reading file: {e}"))
63
+ yield messages
64
+ return
65
+ else:
66
+ messages.append(ChatMessage(role="assistant", content="Sorry, I cannot understand this input format."))
67
+ yield messages
68
+ return
69
+
70
+
71
+ try:
72
+ # Format chat history for Gemini
73
+ chat_history = format_chat_history(messages)
74
+
75
+ # Initialize Gemini chat
76
+ chat = model.start_chat(history=chat_history)
77
+ response = chat.send_message(user_message, stream=True) #Send the message part as is
78
+
79
+ # Initialize buffers and flags - same as before
80
+ thought_buffer = ""
81
+ response_buffer = ""
82
+ thinking_complete = False
83
+
84
+
85
+ # Add initial thinking message - same as before
86
+ messages.append(
87
+ ChatMessage(
88
+ role="assistant",
89
+ content="",
90
+ metadata={"title": "⚙️ Thinking: *The thoughts produced by the model are experimental"}
91
+ )
92
+ )
93
+
94
+ for chunk in response: #streaming logic - same as before
95
+ parts = chunk.candidates[0].content.parts
96
+ current_chunk = parts[0].text
97
+
98
+ if len(parts) == 2 and not thinking_complete:
99
+ # Complete thought and start response
100
+ thought_buffer += current_chunk
101
+ print(f"\n=== Complete Thought ===\n{thought_buffer}")
102
+
103
+ messages[-1] = ChatMessage(
104
+ role="assistant",
105
+ content=thought_buffer,
106
+ metadata={"title": "⚙️ Thinking: *The thoughts produced by the model are experimental"}
107
+ )
108
+ yield messages
109
+
110
+ # Start response
111
+ response_buffer = parts[1].text
112
+ print(f"\n=== Starting Response ===\n{response_buffer}")
113
+
114
+ messages.append(
115
+ ChatMessage(
116
+ role="assistant",
117
+ content=response_buffer
118
+ )
119
+ )
120
+ thinking_complete = True
121
+
122
+ elif thinking_complete:
123
+ # Stream response
124
+ response_buffer += current_chunk
125
+ print(f"\n=== Response Chunk ===\n{current_chunk}")
126
+
127
+ messages[-1] = ChatMessage(
128
+ role="assistant",
129
+ content=response_buffer
130
+ )
131
+
132
+ else:
133
+ # Stream thinking
134
+ thought_buffer += current_chunk
135
+ print(f"\n=== Thinking Chunk ===\n{thought_buffer}")
136
+
137
+ messages[-1] = ChatMessage(
138
+ role="assistant",
139
+ content=thought_buffer,
140
+ metadata={"title": "⚙️ Thinking: *The thoughts produced by the model are experimental"}
141
+ )
142
+
143
+ yield messages
144
+
145
+ print(f"\n=== Final Response ===\n{response_buffer}")
146
+
147
+
148
+ except Exception as e:
149
+ print(f"\n=== Error ===\n{str(e)}")
150
+ messages.append(
151
+ ChatMessage(
152
+ role="assistant",
153
+ content=f"I apologize, but I encountered an error: {str(e)}"
154
+ )
155
+ )
156
+ yield messages
157
+
158
+ def user_message(message_text, file_upload, history: list) -> tuple[str, None, list]:
159
+ """Adds user message to chat history"""
160
+ msg = message_text if message_text else file_upload
161
+ history.append(ChatMessage(role="user", content=msg if isinstance(msg, str) else msg.name)) #Store message or filename in history.
162
+ return "", None, history #clear both input fields
163
+
164
+ # Create the Gradio interface
165
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue="teal", secondary_hue="slate", neutral_hue="neutral")) as demo:
166
+ gr.Markdown("# Gemini 2.0 Flash 'Thinking' Chatbot 💭")
167
+
168
+ chatbot = gr.Chatbot(
169
+ type="messages",
170
+ label="Gemini2.0 'Thinking' Chatbot",
171
+ render_markdown=True,
172
+ scale=1,
173
+ avatar_images=(None,"https://lh3.googleusercontent.com/oxz0sUBF0iYoN4VvhqWTmux-cxfD1rxuYkuFEfm1SFaseXEsjjE4Je_C_V3UQPuJ87sImQK3HfQ3RXiaRnQetjaZbjJJUkiPL5jFJ1WRl5FKJZYibUA=w214-h214-n-nu")
174
+ )
175
+
176
+ with gr.Row(equal_height=True):
177
+ input_box = gr.Textbox(
178
+ lines=1,
179
+ label="Chat Message",
180
+ placeholder="Type your message here...",
181
+ scale=3
182
+ )
183
+ file_upload = gr.File(label="Upload File", file_types=["image", ".csv"], scale=2) # Allow image and CSV files
184
+
185
+ clear_button = gr.Button("Clear Chat", scale=1)
186
+
187
+ # Set up event handlers
188
+ msg_store = gr.State("") # Store for preserving user message
189
+
190
+
191
+ input_box.submit(
192
+ user_message,
193
+ inputs=[input_box, file_upload, chatbot],
194
+ outputs=[input_box, file_upload, chatbot],
195
+ queue=False
196
+ ).then(
197
+ stream_gemini_response,
198
+ inputs=[input_box, chatbot], # Input either from text box or file, logic inside stream_gemini_response
199
+ outputs=chatbot
200
+ )
201
+
202
+ file_upload.upload(
203
+ user_message,
204
+ inputs=[input_box, file_upload, chatbot], # even textbox is input here so clearing both will work
205
+ outputs=[input_box, file_upload, chatbot],
206
+ queue=False
207
+ ).then(
208
+ stream_gemini_response,
209
+ inputs=[file_upload, chatbot], # Input is now the uploaded file.
210
+ outputs=chatbot
211
+ )
212
+
213
+
214
+ clear_button.click(
215
+ lambda: ([], "", ""),
216
+ outputs=[chatbot, input_box, msg_store],
217
+ queue=False
218
+ )
219
+
220
+ gr.Markdown( # Description moved to the bottom
221
+ """
222
+ <br><br><br> <!-- Add some vertical space -->
223
+ ---
224
+ ### About this Chatbot
225
+ This chatbot demonstrates the experimental 'thinking' capability of the **Gemini 2.0 Flash** model.
226
+ You can observe the model's thought process as it generates responses, displayed with the "⚙️ Thinking" prefix.
227
+ **Key Features:**
228
+ * Powered by Google's **Gemini 2.0 Flash** model.
229
+ * Shows the model's **thoughts** before the final answer (experimental feature).
230
+ * Supports **conversation history** for multi-turn chats.
231
+ * Supports **Image and CSV file uploads** for analysis.
232
+ * Uses **streaming** for a more interactive experience.
233
+ **Instructions:**
234
+ 1. Type your message in the input box or Upload a file below.
235
+ 2. Press Enter/Submit or Upload to send.
236
+ 3. Observe the chatbot's "Thinking" process followed by the final response.
237
+ 4. Use the "Clear Chat" button to start a new conversation.
238
+ *Please note*: The 'thinking' feature is experimental and the quality of thoughts may vary. File analysis capabilities may be limited depending on the model's experimental features.
239
+ """
240
+ )
241
+
242
+
243
+ # Launch the interface
244
+ if __name__ == "__main__":
245
+ demo.launch(debug=True)