hadadrjt commited on
Commit
76f7f20
·
1 Parent(s): b5e7375

ai: Update Next-Gen logic.

Browse files
Files changed (3) hide show
  1. app.py +1 -1
  2. src/client/chat_handler.py +182 -88
  3. src/ui/interface.py +2 -1
app.py CHANGED
@@ -16,4 +16,4 @@ if __name__ == "__main__":
16
 
17
  # Call the 'launch' method on the 'app' object to start the user interface.
18
  # This typically opens the UI window or begins the event loop, making the application interactive.
19
- app.queue(default_concurrency_limit=2).launch(show_api=False)
 
16
 
17
  # Call the 'launch' method on the 'app' object to start the user interface.
18
  # This typically opens the UI window or begins the event loop, making the application interactive.
19
+ app.queue(default_concurrency_limit=2).launch(show_api=False, quiet=True)
src/client/chat_handler.py CHANGED
@@ -16,51 +16,51 @@ from src.tools.deep_search import SearchTools # Import SearchTools class for de
16
  import gradio as gr # Import Gradio library for UI and request handling
17
 
18
  # Define an asynchronous function 'respond' to process user messages and generate AI responses
19
- # This version uses the "messages" style for chat history, where history is a list of dicts with "role" and "content" keys,
20
- # supporting content as strings, dicts with "path" keys, or Gradio components.
21
  async def respond(
22
  message, # Incoming user message, can be a string or a dictionary containing text and files
23
- history: List[Any], # List containing conversation history as pairs of user and assistant messages (tuples style)
24
- model_label, # Label/key to select the AI model from the available models
25
- temperature, # Sampling temperature controlling randomness of AI response generation
26
- top_k, # Number of highest probability tokens to keep for sampling
27
- min_p, # Minimum probability threshold for token sampling
28
- top_p, # Cumulative probability threshold for nucleus sampling
29
- repetition_penalty, # Penalty factor to reduce repetitive tokens in generated text
30
- thinking, # Boolean flag indicating if AI should operate in "thinking" mode
31
- image_gen, # Boolean flag to enable image generation commands
32
- audio_gen, # Boolean flag to enable audio generation commands
33
- search_gen, # Boolean flag to enable deep search commands
34
  request: gr.Request # Gradio request object to access session information such as session hash
35
  ):
36
- # Select the AI model based on the provided label, if label not found, fallback to the first model in the config
37
  selected_model = model.get(model_label, list(model.values())[0])
38
 
39
- # Instantiate SearchTools to enable deep search capabilities if requested
40
  search_tools = SearchTools()
41
 
42
- # Retrieve session ID from the Gradio request's session hash, generate a new UUID if none exists
43
  session_id = request.session_hash or str(uuid.uuid4())
44
 
45
- # Initialize an empty conversation history for this session if it does not already exist
46
  if session_id not in session:
47
  session[session_id] = []
48
 
49
  # Determine the mode string based on the 'thinking' flag, affects AI response generation behavior
50
  mode = "/think" if thinking else "/no_think"
51
 
52
- # Initialize variables for user input text and any attached files
53
  input = ""
54
  files = None
55
 
56
- # Check if the incoming message is a dictionary (which may contain text and files)
57
  if isinstance(message, dict):
58
  # Extract the text content from the message dictionary, default to empty string if missing
59
  input = message.get("text", "")
60
- # Extract the first file from the files list if present, otherwise, set files to None
61
  files = message.get("files")[0] if message.get("files") else None
62
  else:
63
- # If the message is a simple string, assign it directly to input
64
  input = message
65
 
66
  # Strip leading and trailing whitespace from the input for clean processing
@@ -68,7 +68,7 @@ async def respond(
68
  # Convert the stripped input to lowercase for case-insensitive command detection
69
  lowered_input = stripped_input.lower()
70
 
71
- # If the input is empty after stripping, yield an empty list and exit the function early
72
  if not stripped_input:
73
  yield []
74
  return
@@ -78,15 +78,14 @@ async def respond(
78
  yield []
79
  return
80
 
81
- # Prepare a new conversation history list formatted with roles and content for AI model consumption
82
- # Here we convert the old "tuples" style history (list of [user_msg, assistant_msg]) into "messages" style:
83
- # a flat list of dicts with "role" and "content" keys.
84
  new_history = []
85
  for entry in history:
86
  # Ensure the entry is a list with exactly two elements: user message and assistant message
87
  if isinstance(entry, list) and len(entry) == 2:
88
  user_msg, assistant_msg = entry
89
- # Append the user message with role 'user' to the new history if not None
90
  if user_msg is not None:
91
  new_history.append({"role": "user", "content": user_msg})
92
  # Append the assistant message with role 'assistant' if it exists and is not None
@@ -96,68 +95,100 @@ async def respond(
96
  # Update the global session dictionary with the newly formatted conversation history for this session
97
  session[session_id] = new_history
98
 
99
- # Handle audio generation command if enabled and input starts with '/audio'
100
  if audio_gen and lowered_input.startswith("/audio"):
101
  # Extract the audio instruction text after the '/audio' command prefix and strip whitespace
102
  audio_instruction = input[6:].strip()
103
- # If no instruction text is provided, yield empty and exit early
104
  if not audio_instruction:
105
  yield []
106
  return
107
  try:
108
  # Asynchronously create audio content based on the instruction using AudioGeneration class
109
  audio = await AudioGeneration.create_audio(audio_instruction)
110
- # Serialize the audio data and instruction into a JSON formatted string
111
  audio_generation_content = json.dumps({
112
  "audio": audio,
113
  "audio_instruction": audio_instruction
114
  })
115
- # Construct the conversation history including the audio generation result and detailed instructions
116
  audio_generation_result = (
117
  new_history
118
  + [
119
  {
120
  "role": "system",
121
  "content": (
122
- f"Audio generation result:\n\n{audio_generation_content}\n\n\n"
123
- "Show the audio using the following HTML audio tag format, where '{audio_link}' is the URL of the generated audio:\n\n"
124
- "<audio controls src='{audio_link}' style='width:100%; max-width:100%;'></audio>\n\n"
125
- "Please replace '{audio_link}' with the actual audio URL provided in the context.\n\n"
126
- "Then, describe the generated audio based on the above information.\n\n\n"
127
- "Use the same language as the previous user input or user request.\n"
128
- "For example, if the previous user input or user request is in Indonesian, explain in Indonesian.\n"
129
- "If it is in English, explain in English. This also applies to other languages.\n\n\n"
130
  )
131
  }
132
  ]
133
  )
134
 
135
- # Use async generator to get descriptive text about the generated audio
136
  async for audio_description in jarvis(
137
  session_id=session_id,
138
  model=selected_model,
139
  history=audio_generation_result,
140
  user_message=input,
141
- mode="/no_think", # Use no_think mode to avoid extra processing
142
- temperature=0.7, # Fixed temperature for audio description generation
143
- top_k=20, # Limit token sampling to top 20 tokens
144
- min_p=0, # Minimum probability threshold
145
- top_p=0.8, # Nucleus sampling threshold
146
  repetition_penalty=1 # No repetition penalty for this step
147
  ):
148
- # Yield the audio description wrapped in a tool role for UI display
149
- yield [{"role": "tool", "content": f'{audio_description}'}]
150
  return
151
  except Exception:
152
- # If audio generation fails, yield an error message and exit
153
- yield [{"role": "tool", "content": "Audio generation failed. Please wait 15 seconds before trying again."}]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
  return
155
 
156
- # Handle image generation command if enabled and input starts with '/image'
157
  if image_gen and lowered_input.startswith("/image"):
158
  # Extract the image generation instruction after the '/image' command prefix and strip whitespace
159
  generate_image_instruction = input[6:].strip()
160
- # If no instruction text is provided, yield empty and exit early
161
  if not generate_image_instruction:
162
  yield []
163
  return
@@ -165,58 +196,90 @@ async def respond(
165
  # Asynchronously create image content based on the instruction using ImageGeneration class
166
  image = await ImageGeneration.create_image(generate_image_instruction)
167
 
168
- # Serialize the image data and instruction into a JSON formatted string
169
  image_generation_content = json.dumps({
170
  "image": image,
171
  "generate_image_instruction": generate_image_instruction
172
  })
173
 
174
- # Construct the conversation history including the image generation result and detailed instructions
175
  image_generation_result = (
176
  new_history
177
  + [
178
  {
179
  "role": "system",
180
  "content": (
181
- f"Image generation result:\n\n{image_generation_content}\n\n\n"
182
- "Show the generated image using the following markdown syntax format, where '{image_link}' is the URL of the image:\n\n"
183
- "![Generated Image]({image_link})\n\n"
184
- "Please replace '{image_link}' with the actual image URL provided in the context.\n\n"
185
- "Then, describe the generated image based on the above information.\n\n\n"
186
- "Use the same language as the previous user input or user request.\n"
187
- "For example, if the previous user input or user request is in Indonesian, explain in Indonesian.\n"
188
- "If it is in English, explain in English. This also applies to other languages.\n\n\n"
189
  )
190
  }
191
  ]
192
  )
193
 
194
- # Use async generator to get descriptive text about the generated image
195
  async for image_description in jarvis(
196
  session_id=session_id,
197
  model=selected_model,
198
  history=image_generation_result,
199
  user_message=input,
200
- mode="/no_think", # Use no_think mode to avoid extra processing
201
- temperature=0.7, # Fixed temperature for image description generation
202
- top_k=20, # Limit token sampling to top 20 tokens
203
- min_p=0, # Minimum probability threshold
204
- top_p=0.8, # Nucleus sampling threshold
205
  repetition_penalty=1 # No repetition penalty for this step
206
  ):
207
- # Yield the image description wrapped in a tool role for UI display
208
- yield [{"role": "tool", "content": f"{image_description}"}]
209
  return
210
  except Exception:
211
- # If image generation fails, yield an error message and exit
212
- yield [{"role": "tool", "content": "Image generation failed. Please wait 15 seconds before trying again."}]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
  return
214
 
215
- # Handle deep search command if enabled and input starts with '/dp'
216
  if search_gen and lowered_input.startswith("/dp"):
217
  # Extract the search query after the '/dp' command prefix and strip whitespace
218
  search_query = input[3:].strip()
219
- # If no search query is provided, yield empty and exit early
220
  if not search_query:
221
  yield []
222
  return
@@ -238,15 +301,15 @@ async def respond(
238
  {
239
  "role": "system",
240
  "content": (
241
- f"Deep search results for query: '{search_query}':\n\n{search_content}\n\n\n"
242
- "Please analyze these search results and provide a comprehensive summary of the information.\n"
243
- "Identify the most relevant information related to the query.\n"
244
- "Format your response in a clear, structured way with appropriate headings and bullet points if needed.\n"
245
- "If the search results don't provide sufficient information, acknowledge this limitation.\n"
246
- "Please provide links or URLs from each of your search results.\n\n"
247
- "Use the same language as the previous user input or user request.\n"
248
- "For example, if the previous user input or user request is in Indonesian, explain in Indonesian.\n"
249
- "If it is in English, explain in English. This also applies to other languages.\n\n\n"
250
  )
251
  }
252
  ]
@@ -265,20 +328,51 @@ async def respond(
265
  top_p=top_p,
266
  repetition_penalty=repetition_penalty
267
  ):
268
- # Yield the search summary wrapped in a tool role for UI display
269
- yield [{"role": "tool", "content": f"{search_response}"}]
270
  return
271
 
272
  except Exception as e:
273
- # If deep search fails, yield an error message and exit
274
- yield [{"role": "tool", "content": "Search failed, please try again later."}]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
275
  return
276
 
277
- # For all other inputs that do not match special commands, use the jarvis function to generate a response
278
  async for response in jarvis(
279
  session_id=session_id,
280
  model=selected_model,
281
- history=new_history, # Pass the conversation history in "messages" style format
282
  user_message=input,
283
  mode=mode, # Use the mode determined by the thinking flag
284
  files=files, # Pass any attached files along with the message
@@ -288,5 +382,5 @@ async def respond(
288
  top_p=top_p,
289
  repetition_penalty=repetition_penalty
290
  ):
291
- # Yield each chunk of the response as it is generated
292
  yield response
 
16
  import gradio as gr # Import Gradio library for UI and request handling
17
 
18
  # Define an asynchronous function 'respond' to process user messages and generate AI responses
19
+ # This function handles various types of user inputs including text, commands, and file uploads
20
+ # It supports multiple AI models and generation modes with customizable parameters
21
  async def respond(
22
  message, # Incoming user message, can be a string or a dictionary containing text and files
23
+ history: List[Any], # List containing conversation history as pairs of user and assistant messages
24
+ model_label, # Label/key to select the specific AI model from available models configuration
25
+ temperature, # Sampling temperature parameter controlling randomness of AI response generation (0.0 to 2.0)
26
+ top_k, # Number of highest probability tokens to keep for sampling during text generation
27
+ min_p, # Minimum probability threshold for token sampling to filter low probability tokens
28
+ top_p, # Cumulative probability threshold for nucleus sampling technique
29
+ repetition_penalty, # Penalty factor to reduce repetitive tokens in generated text output
30
+ thinking, # Boolean flag indicating if AI should operate in "thinking" mode with deeper reasoning
31
+ image_gen, # Boolean flag to enable image generation commands using /image prefix
32
+ audio_gen, # Boolean flag to enable audio generation commands using /audio prefix
33
+ search_gen, # Boolean flag to enable deep search commands using /dp prefix
34
  request: gr.Request # Gradio request object to access session information such as session hash
35
  ):
36
+ # Select the AI model based on the provided label, fallback to first model if label not found
37
  selected_model = model.get(model_label, list(model.values())[0])
38
 
39
+ # Instantiate SearchTools class to enable deep search capabilities when requested by user
40
  search_tools = SearchTools()
41
 
42
+ # Retrieve session ID from the Gradio request's session hash, generate new UUID if none exists
43
  session_id = request.session_hash or str(uuid.uuid4())
44
 
45
+ # Initialize an empty conversation history list for this session if it does not already exist
46
  if session_id not in session:
47
  session[session_id] = []
48
 
49
  # Determine the mode string based on the 'thinking' flag, affects AI response generation behavior
50
  mode = "/think" if thinking else "/no_think"
51
 
52
+ # Initialize variables for storing user input text and any attached files
53
  input = ""
54
  files = None
55
 
56
+ # Check if the incoming message is a dictionary which may contain both text and file attachments
57
  if isinstance(message, dict):
58
  # Extract the text content from the message dictionary, default to empty string if missing
59
  input = message.get("text", "")
60
+ # Extract the first file from the files list if present, otherwise set files to None
61
  files = message.get("files")[0] if message.get("files") else None
62
  else:
63
+ # If the message is a simple string, assign it directly to input variable
64
  input = message
65
 
66
  # Strip leading and trailing whitespace from the input for clean processing
 
68
  # Convert the stripped input to lowercase for case-insensitive command detection
69
  lowered_input = stripped_input.lower()
70
 
71
+ # If the input is empty after stripping whitespace, yield an empty list and exit function early
72
  if not stripped_input:
73
  yield []
74
  return
 
78
  yield []
79
  return
80
 
81
+ # Convert conversation history from tuples style to messages style format for AI model consumption
82
+ # Transform list of [user_msg, assistant_msg] pairs into flat list of role-content dictionaries
 
83
  new_history = []
84
  for entry in history:
85
  # Ensure the entry is a list with exactly two elements: user message and assistant message
86
  if isinstance(entry, list) and len(entry) == 2:
87
  user_msg, assistant_msg = entry
88
+ # Append the user message with role 'user' to the new history if message is not None
89
  if user_msg is not None:
90
  new_history.append({"role": "user", "content": user_msg})
91
  # Append the assistant message with role 'assistant' if it exists and is not None
 
95
  # Update the global session dictionary with the newly formatted conversation history for this session
96
  session[session_id] = new_history
97
 
98
+ # Handle audio generation command if enabled and input starts with '/audio' prefix
99
  if audio_gen and lowered_input.startswith("/audio"):
100
  # Extract the audio instruction text after the '/audio' command prefix and strip whitespace
101
  audio_instruction = input[6:].strip()
102
+ # If no instruction text is provided after the command, yield empty and exit early
103
  if not audio_instruction:
104
  yield []
105
  return
106
  try:
107
  # Asynchronously create audio content based on the instruction using AudioGeneration class
108
  audio = await AudioGeneration.create_audio(audio_instruction)
109
+ # Serialize the audio data and instruction into a JSON formatted string for processing
110
  audio_generation_content = json.dumps({
111
  "audio": audio,
112
  "audio_instruction": audio_instruction
113
  })
114
+ # Construct the conversation history including the audio generation result and formatting instructions
115
  audio_generation_result = (
116
  new_history
117
  + [
118
  {
119
  "role": "system",
120
  "content": (
121
+ "Audio generation result:\n\n" + audio_generation_content + "\n\n\n"
122
+ "Show the audio using the following HTML audio tag format, where '{audio_link}' is the URL of the generated audio:\n\n"
123
+ "<audio controls src='{audio_link}' style='width:100%; max-width:100%;'></audio>\n\n"
124
+ "Please replace '{audio_link}' with the actual audio URL provided in the context.\n\n"
125
+ "Then, describe the generated audio based on the above information.\n\n\n"
126
+ "Use the same language as the previous user input or user request.\n"
127
+ "For example, if the previous user input or user request is in Indonesian, explain in Indonesian.\n"
128
+ "If it is in English, explain in English. This also applies to other languages.\n\n\n"
129
  )
130
  }
131
  ]
132
  )
133
 
134
+ # Use async generator to get descriptive text about the generated audio from AI
135
  async for audio_description in jarvis(
136
  session_id=session_id,
137
  model=selected_model,
138
  history=audio_generation_result,
139
  user_message=input,
140
+ mode="/no_think", # Use non-reasoning mode to avoid extra processing overhead
141
+ temperature=0.7, # Fixed temperature for consistent audio description generation
142
+ top_k=20, # Limit token sampling to top 20 most probable tokens
143
+ min_p=0, # Minimum probability threshold set to zero
144
+ top_p=0.8, # Nucleus sampling threshold for quality control
145
  repetition_penalty=1 # No repetition penalty for this step
146
  ):
147
+ # Yield the audio description wrapped in a tool role for proper UI display
148
+ yield [{"role": "tool", "content": audio_description}]
149
  return
150
  except Exception:
151
+ # If audio generation fails, let AI generate a contextual error message
152
+ generation_failed = (
153
+ new_history
154
+ + [
155
+ {
156
+ "role": "system",
157
+ "content": (
158
+ "Audio generation failed for the user's request. The user tried to generate audio with the instruction: '"
159
+ + audio_instruction + "'\n\n\n"
160
+ "Please explain to the user that audio generation failed and suggest they wait 15 seconds before trying again.\n"
161
+ "Be helpful and empathetic in your response.\n\n\n"
162
+ "Use the same language as the previous user input or user request.\n"
163
+ "For example, if the previous user input or user request is in Indonesian, explain in Indonesian.\n"
164
+ "If it is in English, explain in English. This also applies to other languages.\n\n\n"
165
+ )
166
+ }
167
+ ]
168
+ )
169
+
170
+ # Use AI to generate a contextual error message
171
+ async for error_response in jarvis(
172
+ session_id=session_id,
173
+ model=selected_model,
174
+ history=generation_failed,
175
+ user_message=input,
176
+ mode="/no_think", # Use non-reasoning mode for error handling
177
+ temperature=0.7, # Fixed temperature for more consistent error messages
178
+ top_k=20, # Limit token sampling
179
+ min_p=0, # Minimum probability threshold
180
+ top_p=0.8, # Nucleus sampling threshold
181
+ repetition_penalty=1 # No repetition penalty
182
+ ):
183
+ # Yield the AI-generated error response wrapped in tool role
184
+ yield [{"role": "tool", "content": error_response}]
185
  return
186
 
187
+ # Handle image generation command if enabled and input starts with '/image' prefix
188
  if image_gen and lowered_input.startswith("/image"):
189
  # Extract the image generation instruction after the '/image' command prefix and strip whitespace
190
  generate_image_instruction = input[6:].strip()
191
+ # If no instruction text is provided after the command, yield empty and exit early
192
  if not generate_image_instruction:
193
  yield []
194
  return
 
196
  # Asynchronously create image content based on the instruction using ImageGeneration class
197
  image = await ImageGeneration.create_image(generate_image_instruction)
198
 
199
+ # Serialize the image data and instruction into a JSON formatted string for processing
200
  image_generation_content = json.dumps({
201
  "image": image,
202
  "generate_image_instruction": generate_image_instruction
203
  })
204
 
205
+ # Construct the conversation history including the image generation result and formatting instructions
206
  image_generation_result = (
207
  new_history
208
  + [
209
  {
210
  "role": "system",
211
  "content": (
212
+ "Image generation result:\n\n" + image_generation_content + "\n\n\n"
213
+ "Show the generated image using the following markdown syntax format, where '{image_link}' is the URL of the image:\n\n"
214
+ "![Generated Image]({image_link})\n\n"
215
+ "Please replace '{image_link}' with the actual image URL provided in the context.\n\n"
216
+ "Then, describe the generated image based on the above information.\n\n\n"
217
+ "Use the same language as the previous user input or user request.\n"
218
+ "For example, if the previous user input or user request is in Indonesian, explain in Indonesian.\n"
219
+ "If it is in English, explain in English. This also applies to other languages.\n\n\n"
220
  )
221
  }
222
  ]
223
  )
224
 
225
+ # Use async generator to get descriptive text about the generated image from AI
226
  async for image_description in jarvis(
227
  session_id=session_id,
228
  model=selected_model,
229
  history=image_generation_result,
230
  user_message=input,
231
+ mode="/no_think", # Use non-reasoning mode to avoid extra processing overhead
232
+ temperature=0.7, # Fixed temperature for consistent image description generation
233
+ top_k=20, # Limit token sampling to top 20 most probable tokens
234
+ min_p=0, # Minimum probability threshold set to zero
235
+ top_p=0.8, # Nucleus sampling threshold for quality control
236
  repetition_penalty=1 # No repetition penalty for this step
237
  ):
238
+ # Yield the image description wrapped in a tool role for proper UI display
239
+ yield [{"role": "tool", "content": image_description}]
240
  return
241
  except Exception:
242
+ # If image generation fails, let AI generate a contextual error message
243
+ generation_failed = (
244
+ new_history
245
+ + [
246
+ {
247
+ "role": "system",
248
+ "content": (
249
+ "Image generation failed for the user's request. The user tried to generate an image with the instruction: '"
250
+ + generate_image_instruction + "'\n\n\n"
251
+ "Please explain to the user that image generation failed and suggest they wait 15 seconds before trying again.\n"
252
+ "Be helpful and empathetic in your response.\n\n\n"
253
+ "Use the same language as the previous user input or user request.\n"
254
+ "For example, if the previous user input or user request is in Indonesian, explain in Indonesian.\n"
255
+ "If it is in English, explain in English. This also applies to other languages.\n\n\n"
256
+ )
257
+ }
258
+ ]
259
+ )
260
+
261
+ # Use AI to generate a contextual error message
262
+ async for error_response in jarvis(
263
+ session_id=session_id,
264
+ model=selected_model,
265
+ history=generation_failed,
266
+ user_message=input,
267
+ mode="/no_think", # Use non-reasoning mode for error handling
268
+ temperature=0.7, # Fixed temperature for more consistent error messages
269
+ top_k=20, # Limit token sampling
270
+ min_p=0, # Minimum probability threshold
271
+ top_p=0.8, # Nucleus sampling threshold
272
+ repetition_penalty=1 # No repetition penalty
273
+ ):
274
+ # Yield the AI-generated error response wrapped in tool role
275
+ yield [{"role": "tool", "content": error_response}]
276
  return
277
 
278
+ # Handle deep search command if enabled and input starts with '/dp' prefix
279
  if search_gen and lowered_input.startswith("/dp"):
280
  # Extract the search query after the '/dp' command prefix and strip whitespace
281
  search_query = input[3:].strip()
282
+ # If no search query is provided after the command, yield empty and exit early
283
  if not search_query:
284
  yield []
285
  return
 
301
  {
302
  "role": "system",
303
  "content": (
304
+ "Deep search results for query: '" + search_query + "':\n\n\n" + search_content + "\n\n\n"
305
+ "Please analyze these search results and provide a comprehensive summary of the information.\n"
306
+ "Identify the most relevant information related to the query.\n"
307
+ "Format your response in a clear, structured way with appropriate headings and bullet points if needed.\n"
308
+ "If the search results don't provide sufficient information, acknowledge this limitation.\n"
309
+ "Please provide links or URLs from each of your search results.\n\n\n"
310
+ "Use the same language as the previous user input or user request.\n"
311
+ "For example, if the previous user input or user request is in Indonesian, explain in Indonesian.\n"
312
+ "If it is in English, explain in English. This also applies to other languages.\n\n\n"
313
  )
314
  }
315
  ]
 
328
  top_p=top_p,
329
  repetition_penalty=repetition_penalty
330
  ):
331
+ # Yield the search summary wrapped in a tool role for proper UI display
332
+ yield [{"role": "tool", "content": search_response}]
333
  return
334
 
335
  except Exception as e:
336
+ # If deep search fails, let AI generate a contextual error message
337
+ generation_failed = (
338
+ new_history
339
+ + [
340
+ {
341
+ "role": "system",
342
+ "content": (
343
+ "Deep search failed for the user's query: '" + search_query + "'\n\n\n"
344
+ "Please explain to the user that the search operation failed and suggest they try again later.\n"
345
+ "Be helpful and empathetic in your response. You can also suggest alternative approaches or workarounds.\n\n\n"
346
+ "Use the same language as the previous user input or user request.\n"
347
+ "For example, if the previous user input or user request is in Indonesian, explain in Indonesian.\n"
348
+ "If it is in English, explain in English. This also applies to other languages.\n\n\n"
349
+ )
350
+ }
351
+ ]
352
+ )
353
+
354
+ # Use AI to generate a contextual error message
355
+ async for error_response in jarvis(
356
+ session_id=session_id,
357
+ model=selected_model,
358
+ history=generation_failed,
359
+ user_message=input,
360
+ mode="/no_think", # Use non-reasoning mode for error handling
361
+ temperature=0.7, # Fixed temperature for more consistent error messages
362
+ top_k=20, # Limit token sampling
363
+ min_p=0, # Minimum probability threshold
364
+ top_p=0.8, # Nucleus sampling threshold
365
+ repetition_penalty=1 # No repetition penalty
366
+ ):
367
+ # Yield the AI-generated error response wrapped in tool role
368
+ yield [{"role": "tool", "content": error_response}]
369
  return
370
 
371
+ # For all other inputs that do not match special commands, use the jarvis function to generate a normal response
372
  async for response in jarvis(
373
  session_id=session_id,
374
  model=selected_model,
375
+ history=new_history, # Pass the conversation history
376
  user_message=input,
377
  mode=mode, # Use the mode determined by the thinking flag
378
  files=files, # Pass any attached files along with the message
 
382
  top_p=top_p,
383
  repetition_penalty=repetition_penalty
384
  ):
385
+ # Yield each chunk of the response as it is generated by the AI model
386
  yield response
src/ui/interface.py CHANGED
@@ -176,7 +176,8 @@ def ui():
176
  multimodal=False, # Disable support for multimodal inputs such as images or audio files
177
  fill_height=True, # Duplicate from Blocks to Chat Interface
178
  fill_width=True, # Duplicate from Blocks to Chat Interface
179
- head=meta_tags # Duplicate from Blocks to Chat Interface
 
180
  )
181
  # Return the complete Gradio app object for launching or embedding
182
  return app
 
176
  multimodal=False, # Disable support for multimodal inputs such as images or audio files
177
  fill_height=True, # Duplicate from Blocks to Chat Interface
178
  fill_width=True, # Duplicate from Blocks to Chat Interface
179
+ head=meta_tags, # Duplicate from Blocks to Chat Interface
180
+ show_progress="full" # Progress animation
181
  )
182
  # Return the complete Gradio app object for launching or embedding
183
  return app