Update ui_components.py
Browse files- ui_components.py +141 -0
ui_components.py
CHANGED
|
@@ -5,6 +5,7 @@ import gradio as gr
|
|
| 5 |
from gradio import ChatMessage
|
| 6 |
from typing import Tuple, List, Dict, Any
|
| 7 |
import os
|
|
|
|
| 8 |
import logging
|
| 9 |
import traceback
|
| 10 |
from openai import OpenAI
|
|
@@ -133,6 +134,146 @@ class UIComponents:
|
|
| 133 |
|
| 134 |
# Status display
|
| 135 |
self.api_status = gr.Markdown("⚪ Select provider and model to begin", container=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 136 |
|
| 137 |
def _create_server_management_section(self):
|
| 138 |
"""Create the server management section with checkboxes and guidance"""
|
|
|
|
| 5 |
from gradio import ChatMessage
|
| 6 |
from typing import Tuple, List, Dict, Any
|
| 7 |
import os
|
| 8 |
+
import json
|
| 9 |
import logging
|
| 10 |
import traceback
|
| 11 |
from openai import OpenAI
|
|
|
|
| 134 |
|
| 135 |
# Status display
|
| 136 |
self.api_status = gr.Markdown("⚪ Select provider and model to begin", container=True)
|
| 137 |
+
|
| 138 |
+
# Advanced generation parameters (OpenAI-compatible)
|
| 139 |
+
with gr.Row():
|
| 140 |
+
self.temperature_slider = gr.Slider(minimum=0.0, maximum=2.0, value=0.3, step=0.01, label="Temperature")
|
| 141 |
+
self.top_p_slider = gr.Slider(minimum=0.0, maximum=1.0, value=1.0, step=0.01, label="Top-p")
|
| 142 |
+
self.top_logprobs = gr.Slider(minimum=0, maximum=5, value=0, step=1, label="Top logprobs")
|
| 143 |
+
with gr.Row():
|
| 144 |
+
self.max_tokens_box = gr.Number(value=8192, precision=0, label="Max tokens")
|
| 145 |
+
self.seed_box = gr.Number(value=None, precision=0, label="Seed")
|
| 146 |
+
with gr.Row():
|
| 147 |
+
self.frequency_penalty = gr.Slider(minimum=-2.0, maximum=2.0, value=0.0, step=0.01, label="Frequency penalty")
|
| 148 |
+
self.presence_penalty = gr.Slider(minimum=-2.0, maximum=2.0, value=0.0, step=0.01, label="Presence penalty")
|
| 149 |
+
with gr.Row():
|
| 150 |
+
self.logprobs_chk = gr.Checkbox(value=False, label="Return logprobs")
|
| 151 |
+
self.stream_chk = gr.Checkbox(value=False, label="Stream responses (not yet supported in UI)")
|
| 152 |
+
self.stream_include_usage = gr.Checkbox(value=False, label="Stream include usage")
|
| 153 |
+
self.stop_sequences = gr.Textbox(label="Stop sequences (comma-separated)", placeholder="e.g. \n\n, User:")
|
| 154 |
+
|
| 155 |
+
# Reasoning effort (GPT-OSS)
|
| 156 |
+
self.reasoning_effort = gr.Radio(choices=["low", "medium", "high"], value=AppConfig.DEFAULT_REASONING_EFFORT, label="Reasoning effort (GPT‑OSS)")
|
| 157 |
+
|
| 158 |
+
# Response format controls
|
| 159 |
+
with gr.Row():
|
| 160 |
+
self.response_format = gr.Dropdown(choices=["text", "json_object", "json_schema"], value="text", label="Response format")
|
| 161 |
+
with gr.Group(visible=False) as self.json_schema_group:
|
| 162 |
+
self.json_schema_name = gr.Textbox(label="JSON schema name", placeholder="my_schema")
|
| 163 |
+
self.json_schema_description = gr.Textbox(label="JSON schema description", placeholder="Describe the expected JSON")
|
| 164 |
+
self.json_schema_editor = gr.Textbox(label="JSON schema (object)", lines=8, placeholder='{"type":"object","properties":{...},"required":[...]}' )
|
| 165 |
+
self.json_schema_strict = gr.Checkbox(value=False, label="Strict schema adherence")
|
| 166 |
+
|
| 167 |
+
# Tools & tool choice
|
| 168 |
+
with gr.Row():
|
| 169 |
+
self.tool_choice = gr.Dropdown(choices=["auto", "none", "required", "function"], value="auto", label="Tool choice")
|
| 170 |
+
self.tool_function_name = gr.Textbox(label="Function name (when tool_choice=function)")
|
| 171 |
+
self.tool_prompt = gr.Textbox(label="Tool prompt", placeholder="Optional prompt appended before the tools")
|
| 172 |
+
self.tools_json = gr.Textbox(label="Tools (JSON array)", lines=8, placeholder='[{"type":"function","function":{"name":"fn","description":"...","parameters":{}}}]')
|
| 173 |
+
|
| 174 |
+
def _on_response_format_change(fmt):
|
| 175 |
+
return gr.Group(visible=(fmt == "json_schema"))
|
| 176 |
+
self.response_format.change(_on_response_format_change, inputs=[self.response_format], outputs=[self.json_schema_group])
|
| 177 |
+
|
| 178 |
+
def update_generation_params(
|
| 179 |
+
temperature, top_p, top_logprobs, max_tokens, seed,
|
| 180 |
+
frequency_penalty, presence_penalty, logprobs, stream,
|
| 181 |
+
stop_sequences, reasoning_effort, response_format,
|
| 182 |
+
json_schema_name, json_schema_description, json_schema_editor, json_schema_strict,
|
| 183 |
+
tool_choice, tool_function_name, tool_prompt, tools_json, stream_include_usage
|
| 184 |
+
):
|
| 185 |
+
params = {
|
| 186 |
+
"temperature": float(temperature) if temperature is not None else None,
|
| 187 |
+
"top_p": float(top_p) if top_p is not None else None,
|
| 188 |
+
"top_logprobs": int(top_logprobs) if top_logprobs else None,
|
| 189 |
+
"max_tokens": int(max_tokens) if max_tokens else None,
|
| 190 |
+
"seed": int(seed) if seed not in (None, "") else None,
|
| 191 |
+
"frequency_penalty": float(frequency_penalty) if frequency_penalty is not None else None,
|
| 192 |
+
"presence_penalty": float(presence_penalty) if presence_penalty is not None else None,
|
| 193 |
+
"logprobs": bool(logprobs),
|
| 194 |
+
# Prevent enabling streaming until UI supports it end-to-end
|
| 195 |
+
"stream": False,
|
| 196 |
+
# stop: list[str]
|
| 197 |
+
"stop": [s.strip() for s in stop_sequences.split(",") if s.strip()] if stop_sequences else None,
|
| 198 |
+
# GPT-OSS specific control stored separately; mcp_client merges it
|
| 199 |
+
"reasoning_effort": reasoning_effort,
|
| 200 |
+
}
|
| 201 |
+
# stream options
|
| 202 |
+
if stream_include_usage:
|
| 203 |
+
params["stream_options"] = {"include_usage": True}
|
| 204 |
+
|
| 205 |
+
# response_format
|
| 206 |
+
if response_format == "json_object":
|
| 207 |
+
params["response_format"] = {"type": "json_object"}
|
| 208 |
+
elif response_format == "json_schema":
|
| 209 |
+
try:
|
| 210 |
+
schema_obj = json.loads(json_schema_editor) if json_schema_editor else {}
|
| 211 |
+
except Exception as e:
|
| 212 |
+
return gr.Markdown(f"❌ Invalid JSON schema: {e}", visible=True)
|
| 213 |
+
json_fmt = {
|
| 214 |
+
"type": "json_schema",
|
| 215 |
+
"json_schema": {
|
| 216 |
+
"name": json_schema_name or "schema",
|
| 217 |
+
"schema": schema_obj,
|
| 218 |
+
},
|
| 219 |
+
}
|
| 220 |
+
if json_schema_description:
|
| 221 |
+
json_fmt["json_schema"]["description"] = json_schema_description
|
| 222 |
+
if json_schema_strict:
|
| 223 |
+
json_fmt["json_schema"]["strict"] = True
|
| 224 |
+
params["response_format"] = json_fmt
|
| 225 |
+
|
| 226 |
+
# tools
|
| 227 |
+
tools = None
|
| 228 |
+
if tools_json and tools_json.strip():
|
| 229 |
+
try:
|
| 230 |
+
parsed = json.loads(tools_json)
|
| 231 |
+
if isinstance(parsed, list):
|
| 232 |
+
tools = parsed
|
| 233 |
+
else:
|
| 234 |
+
return gr.Markdown("❌ Tools must be a JSON array.", visible=True)
|
| 235 |
+
except Exception as e:
|
| 236 |
+
return gr.Markdown(f"❌ Invalid tools JSON: {e}", visible=True)
|
| 237 |
+
if tools is not None:
|
| 238 |
+
params["tools"] = tools
|
| 239 |
+
|
| 240 |
+
# tool_choice
|
| 241 |
+
if tool_choice in ("auto", "none", "required"):
|
| 242 |
+
params["tool_choice"] = tool_choice
|
| 243 |
+
elif tool_choice == "function" and tool_function_name:
|
| 244 |
+
params["tool_choice"] = {"type": "function", "function": {"name": tool_function_name}}
|
| 245 |
+
|
| 246 |
+
# tool_prompt
|
| 247 |
+
if tool_prompt and tool_prompt.strip():
|
| 248 |
+
params["tool_prompt"] = tool_prompt.strip()
|
| 249 |
+
self.mcp_client.set_generation_params(params)
|
| 250 |
+
return gr.Markdown("✅ Inference parameters updated.")
|
| 251 |
+
|
| 252 |
+
self.gen_param_status = gr.Markdown(visible=False)
|
| 253 |
+
|
| 254 |
+
# Wire updates on change
|
| 255 |
+
for comp in [
|
| 256 |
+
self.temperature_slider, self.top_p_slider, self.top_logprobs,
|
| 257 |
+
self.max_tokens_box, self.seed_box, self.frequency_penalty,
|
| 258 |
+
self.presence_penalty, self.logprobs_chk, self.stream_chk,
|
| 259 |
+
self.stop_sequences, self.reasoning_effort, self.response_format,
|
| 260 |
+
self.json_schema_name, self.json_schema_description, self.json_schema_editor, self.json_schema_strict,
|
| 261 |
+
self.tool_choice, self.tool_function_name, self.tool_prompt, self.tools_json,
|
| 262 |
+
self.stream_include_usage
|
| 263 |
+
]:
|
| 264 |
+
comp.change(
|
| 265 |
+
update_generation_params,
|
| 266 |
+
inputs=[
|
| 267 |
+
self.temperature_slider, self.top_p_slider, self.top_logprobs,
|
| 268 |
+
self.max_tokens_box, self.seed_box, self.frequency_penalty,
|
| 269 |
+
self.presence_penalty, self.logprobs_chk, self.stream_chk,
|
| 270 |
+
self.stop_sequences, self.reasoning_effort, self.response_format,
|
| 271 |
+
self.json_schema_name, self.json_schema_description, self.json_schema_editor, self.json_schema_strict,
|
| 272 |
+
self.tool_choice, self.tool_function_name, self.tool_prompt, self.tools_json,
|
| 273 |
+
self.stream_include_usage
|
| 274 |
+
],
|
| 275 |
+
outputs=[self.gen_param_status]
|
| 276 |
+
)
|
| 277 |
|
| 278 |
def _create_server_management_section(self):
|
| 279 |
"""Create the server management section with checkboxes and guidance"""
|