@@ -119,15 +119,10 @@ def generate_response_with_ui(prompt, current_chat):
119
119
reasoning_placeholder = st .empty ()
120
120
answer_placeholder = st .empty ()
121
121
stop_container = st .container ()
122
+ loading_placeholder = st .empty ()
122
123
123
- # Show stop button
124
- with stop_container :
125
- stop_button_placeholder = st .empty ()
126
- with stop_button_placeholder .container ():
127
- col1 , col2 = st .columns ([10 , 1 ])
128
- with col2 :
129
- if st .button ("⏹" , key = f"stop_gen_{ hash (prompt )} " , help = "Stop generation" ):
130
- st .session_state .stop_generation = True
124
+ # Prepare for aligned loading message and stop button
125
+ stop_button_placeholder = st .empty ()
131
126
132
127
# Generate response with streaming
133
128
full_response = ""
@@ -136,6 +131,7 @@ def generate_response_with_ui(prompt, current_chat):
136
131
reasoning_started = False
137
132
in_reasoning = False
138
133
generation_stopped = False
134
+ first_chunk_received = False
139
135
140
136
# Use direct ollama streaming with RAG context
141
137
system_prompt = PromptBuilder .create_system_prompt (context_text , is_rag = True )
@@ -148,6 +144,7 @@ def generate_response_with_ui(prompt, current_chat):
148
144
ollama_base_url = get_ollama_base_url ()
149
145
in_docker = is_running_in_docker ()
150
146
147
+ # Create chat stream
151
148
if in_docker :
152
149
client = ollama .Client (host = ollama_base_url )
153
150
chat_stream = client .chat (
@@ -162,11 +159,30 @@ def generate_response_with_ui(prompt, current_chat):
162
159
stream = True
163
160
)
164
161
162
+ # Show loading message and stop button aligned
163
+ with loading_placeholder .container ():
164
+ col1 , col2 = st .columns ([10 , 1 ])
165
+ with col1 :
166
+ st .write ("⏳ Processing..." )
167
+ with col2 :
168
+ if st .button ("⏹" , key = f"stop_gen_{ hash (prompt )} " , help = "Stop generation" ):
169
+ st .session_state .stop_generation = True
170
+
165
171
# Handle streaming response with reasoning support
166
172
chunk_count = 0
173
+ has_content = False
167
174
for chunk in chat_stream :
168
175
chunk_count += 1
169
176
177
+ # Check if this chunk has actual content
178
+ if chunk ['message' ]['content' ]:
179
+ has_content = True
180
+
181
+ # Clear loading spinner on first chunk with actual content
182
+ if has_content and not first_chunk_received :
183
+ first_chunk_received = True
184
+ loading_placeholder .empty () # Clear the spinner
185
+
170
186
# Check if user wants to stop on every chunk for responsiveness
171
187
if st .session_state .get ('stop_generation' , False ):
172
188
generation_stopped = True
@@ -218,6 +234,10 @@ def generate_response_with_ui(prompt, current_chat):
218
234
219
235
# Handle stopped generation
220
236
if generation_stopped or st .session_state .get ('stop_generation' , False ):
237
+ # Clear loading spinner if still showing when stopped
238
+ if not first_chunk_received :
239
+ loading_placeholder .empty ()
240
+
221
241
final_answer = answer_content if reasoning_started else full_response
222
242
if final_answer .strip ():
223
243
final_answer += "\n \n *[Generation stopped by user]*"
@@ -230,14 +250,11 @@ def generate_response_with_ui(prompt, current_chat):
230
250
elif not reasoning_started :
231
251
answer_placeholder .markdown (final_answer )
232
252
233
- # Show stopped message and remove stop button
253
+ # Show stopped message
234
254
with stop_container :
235
- stop_button_placeholder .empty ()
236
255
st .info ("🛑 Generation stopped by user" )
237
- else :
238
- # Clear stop button when generation completes normally
239
- with stop_container :
240
- stop_button_placeholder .empty ()
256
+ # Clear the entire loading container (which includes the stop button)
257
+ # This happens for both stopped and completed generation
241
258
242
259
# Show method information
243
260
st .info ("🔍 Response generated using RAG (semantic search)" )
@@ -255,12 +272,17 @@ def generate_response_with_ui(prompt, current_chat):
255
272
return final_answer
256
273
257
274
except Exception as e :
275
+ # Clear loading spinner if still showing in case of error
276
+ if not first_chunk_received :
277
+ loading_placeholder .empty ()
258
278
st .error (f"Error generating response: { e } " )
259
279
return ""
260
280
finally :
261
281
# Reset generation state
262
282
st .session_state .generating = False
263
283
st .session_state .stop_generation = False
284
+ # Ensure loading spinner is cleared
285
+ loading_placeholder .empty ()
264
286
265
287
266
288
def render_chat_interface ():
0 commit comments