JatsTheAIGen commited on
Commit
06947bf
·
1 Parent(s): 26401b4
Files changed (5) hide show
  1. app.py +2 -0
  2. app.py.bak +98 -0
  3. app_gradio.py +19 -12
  4. app_gradio.py.bak +221 -0
  5. patch_gradio_jsonschema.py +66 -0
app.py CHANGED
@@ -1,3 +1,5 @@
 
 
1
  import patch_gradio_jsonschema # MUST be first - patches boolean JSON Schema handling\n
2
  # app.py (Updated with Triage Orchestration)
3
 
 
1
+ import patch_gradio_jsonschema # MUST be first - patches boolean JSON Schema handling
2
+ import patch_gradio_jsonschema # MUST be first - patches boolean JSON Schema handling
3
  import patch_gradio_jsonschema # MUST be first - patches boolean JSON Schema handling\n
4
  # app.py (Updated with Triage Orchestration)
5
 
app.py.bak ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py (Updated with Triage Orchestration)
2
+
3
+ import os
4
+ import math
5
+ from flask import Flask, render_template, request, jsonify
6
+ from dotenv import load_dotenv
7
+ from graph import triage_app, planner_app, main_app # Import all three compiled apps
8
+ from utils import generate_mermaid_diagram
9
+
10
+ load_dotenv()
11
+ app = Flask(__name__)
12
+
13
+ # Create necessary directories on startup
14
+ os.makedirs("outputs", exist_ok=True)
15
+ os.makedirs("uploads", exist_ok=True)
16
+ os.makedirs("memory", exist_ok=True)
17
+ os.makedirs("logs", exist_ok=True)
18
+
19
+
20
+ @app.route('/')
21
+ def index():
22
+ return render_template('index.html')
23
+
24
+
25
+ @app.route('/estimate', methods=['POST'])
26
+ def estimate():
27
+ data = request.json
28
+ user_input = data.get('message', '').strip()
29
+ if not user_input:
30
+ return jsonify({"error": "Message cannot be empty."}), 400
31
+
32
+ # --- NEW TRIAGE STEP ---
33
+ # First, check if the input is a simple greeting
34
+ triage_inputs = {"userInput": user_input}
35
+ triage_result = triage_app.invoke(triage_inputs)
36
+
37
+ # If the triage agent provided a direct response, it's a greeting.
38
+ if triage_result.get("draftResponse"):
39
+ # We add a special key to let the frontend know to just display the message
40
+ return jsonify({"is_greeting": True, "response": triage_result["draftResponse"]})
41
+
42
+ # --- If not a greeting, proceed to the planner ---
43
+ planner_inputs = {"userInput": user_input}
44
+ try:
45
+ estimate_result = planner_app.invoke(planner_inputs)
46
+ estimate_result['pmPlan']['is_greeting'] = False
47
+ return jsonify(estimate_result.get('pmPlan', {}))
48
+ except Exception as e:
49
+ return jsonify({"error": "An unexpected error occurred during planning."}), 500
50
+
51
+
52
+ @app.route('/chat', methods=['POST'])
53
+ def chat():
54
+ data = request.json
55
+ user_input = data.get('message', '').strip()
56
+
57
+ try:
58
+ user_budget = float(data.get('user_budget', 0.0))
59
+ cost_per_loop = float(data.get('cost_per_loop', 0.05))
60
+ except (ValueError, TypeError):
61
+ return jsonify({"error": "Invalid budget or cost format."}), 400
62
+
63
+ if not user_input:
64
+ return jsonify({"error": "Message cannot be empty."}), 400
65
+
66
+ if cost_per_loop > 0:
67
+ total_runs_affordable = max(1, math.floor(user_budget / cost_per_loop))
68
+ max_loops_calibrated = total_runs_affordable - 1
69
+ else:
70
+ max_loops_calibrated = 0
71
+
72
+ initial_state = {
73
+ "userInput": user_input, "chatHistory": [], "coreObjectivePrompt": "",
74
+ "retrievedMemory": "", "pmPlan": {}, "experimentCode": None,
75
+ "experimentResults": None, "draftResponse": "", "qaFeedback": None,
76
+ "approved": False, "execution_path": [], "rework_cycles": 0,
77
+ "max_loops": max_loops_calibrated
78
+ }
79
+
80
+ try:
81
+ final_state = main_app.invoke(initial_state)
82
+ except Exception as e:
83
+ return jsonify({"response": "An unexpected error occurred during execution. Please check the logs."}), 500
84
+
85
+ run_path = final_state.get('execution_path', [])
86
+ if run_path:
87
+ mermaid_syntax = generate_mermaid_diagram(run_path)
88
+ with open("outputs/last_run_flow.md", "w") as f:
89
+ f.write("# Last Run Execution Flow\n\n")
90
+ f.write("```mermaid\n")
91
+ f.write(mermaid_syntax)
92
+ f.write("```\n")
93
+
94
+ response = final_state.get('draftResponse', "An error occurred, and no response was generated.")
95
+ return jsonify({"response": response})
96
+
97
+ if __name__ == '__main__':
98
+ app.run(debug=True, port=5001)
app_gradio.py CHANGED
@@ -1,3 +1,5 @@
 
 
1
  import patch_gradio_jsonschema # MUST be first - patches boolean JSON Schema handling\n
2
  # app_gradio.py (Final Version)
3
 
@@ -95,7 +97,7 @@ def update_artifact_list():
95
  def start_estimation(message, history, state):
96
  log.info(f"Starting estimation for: '{message}'")
97
  state["original_user_message"] = message
98
- history.append({"role": "user", "content": message})
99
 
100
  yield history, state, gr.update(value="", interactive=False), gr.update(visible=False), gr.update(), "Analyzing request..."
101
 
@@ -103,7 +105,7 @@ def start_estimation(message, history, state):
103
  triage_result = triage_app.invoke(triage_inputs)
104
 
105
  if triage_result.get("draftResponse"):
106
- history.append({"role": "assistant", "content": triage_result["draftResponse"]})
107
  yield history, state, gr.update(interactive=True), gr.update(visible=False), gr.update(), "Ready."
108
  return
109
 
@@ -114,7 +116,7 @@ def start_estimation(message, history, state):
114
 
115
  if estimate.get("error"):
116
  error_msg = f"Error during planning: {estimate['error']}"
117
- history.append({"role": "assistant", "content": error_msg})
118
  yield history, state, gr.update(interactive=True), gr.update(visible=False), gr.update(value=0.10), error_msg
119
  else:
120
  plan_text = "\n".join([f"- {step}" for step in estimate.get('plan', [])])
@@ -126,7 +128,7 @@ def execute_main_task(history, state, budget):
126
 
127
  yield history, state, gr.update(visible=False), gr.update(value="", interactive=False), "Task approved. Starting execution..."
128
 
129
- history.append({"role": "assistant", "content": "..."})
130
 
131
  cost_per_loop = state["estimate"].get('cost_per_loop_usd', 0.05)
132
  if cost_per_loop > 0:
@@ -153,11 +155,11 @@ def execute_main_task(history, state, budget):
153
  if "draftResponse" in node_output and node_output["draftResponse"]:
154
  final_response = node_output["draftResponse"]
155
 
156
- history[-1] = {"role": "assistant", "content": final_response}
157
  yield history, state, gr.update(visible=False), gr.update(interactive=True), "Task complete. Ready."
158
 
159
  def cancel_task(history, state):
160
- history.append({"role": "assistant", "content": "Task cancelled."})
161
  return history, state, gr.update(visible=False), gr.update(interactive=True), "Task cancelled. Ready."
162
 
163
  # --- Gradio UI Definition ---
@@ -214,9 +216,14 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Autonomous AI Lab") as demo:
214
 
215
  # --- Launch Configuration ---
216
  if __name__ == "__main__":
217
- demo.launch(
218
- share=False,
219
- server_name="0.0.0.0",
220
- auth=[(user, pwd) for user, pwd in USERS.items()],
221
- auth_message="Enter your credentials to access the Autonomous AI Lab."
222
- )
 
 
 
 
 
 
1
+ import patch_gradio_jsonschema # MUST be first - patches boolean JSON Schema handling
2
+ import patch_gradio_jsonschema # MUST be first - patches boolean JSON Schema handling
3
  import patch_gradio_jsonschema # MUST be first - patches boolean JSON Schema handling\n
4
  # app_gradio.py (Final Version)
5
 
 
97
  def start_estimation(message, history, state):
98
  log.info(f"Starting estimation for: '{message}'")
99
  state["original_user_message"] = message
100
+ history.append([message, None])
101
 
102
  yield history, state, gr.update(value="", interactive=False), gr.update(visible=False), gr.update(), "Analyzing request..."
103
 
 
105
  triage_result = triage_app.invoke(triage_inputs)
106
 
107
  if triage_result.get("draftResponse"):
108
+ history.append(["", triage_result["draftResponse"]])
109
  yield history, state, gr.update(interactive=True), gr.update(visible=False), gr.update(), "Ready."
110
  return
111
 
 
116
 
117
  if estimate.get("error"):
118
  error_msg = f"Error during planning: {estimate['error']}"
119
+ history.append(["", error_msg])
120
  yield history, state, gr.update(interactive=True), gr.update(visible=False), gr.update(value=0.10), error_msg
121
  else:
122
  plan_text = "\n".join([f"- {step}" for step in estimate.get('plan', [])])
 
128
 
129
  yield history, state, gr.update(visible=False), gr.update(value="", interactive=False), "Task approved. Starting execution..."
130
 
131
+ history.append(["", "..."])
132
 
133
  cost_per_loop = state["estimate"].get('cost_per_loop_usd', 0.05)
134
  if cost_per_loop > 0:
 
155
  if "draftResponse" in node_output and node_output["draftResponse"]:
156
  final_response = node_output["draftResponse"]
157
 
158
+ history[-1] = ["", final_response]
159
  yield history, state, gr.update(visible=False), gr.update(interactive=True), "Task complete. Ready."
160
 
161
  def cancel_task(history, state):
162
+ history.append(["", "Task cancelled."])
163
  return history, state, gr.update(visible=False), gr.update(interactive=True), "Task cancelled. Ready."
164
 
165
  # --- Gradio UI Definition ---
 
216
 
217
  # --- Launch Configuration ---
218
  if __name__ == "__main__":
219
+
220
+ # --- recommended Gradio launch for Hugging Face Spaces ---
221
+ import os
222
+ server_port = int(os.environ.get("PORT", 7860))
223
+ demo.launch(
224
+ server_name="0.0.0.0",
225
+ server_port=server_port,
226
+ share=False,
227
+ inbrowser=False,
228
+ )
229
+ # --- end snippet ---
app_gradio.py.bak ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app_gradio.py (Final Version)
2
+
3
+ import gradio as gr
4
+ import math
5
+ import os
6
+ import json
7
+ from datetime import datetime
8
+ from dotenv import load_dotenv
9
+
10
+ # Import your existing agentic logic
11
+ from graph import triage_app, planner_app, main_app
12
+ from logging_config import get_logger
13
+
14
+ # --- Setup & Configuration ---
15
+ load_dotenv()
16
+ log = get_logger(__name__)
17
+
18
+ # Create necessary directories on startup
19
+ os.makedirs("outputs", exist_ok=True)
20
+ os.makedirs("uploads", exist_ok=True)
21
+ os.makedirs("conversations", exist_ok=True)
22
+
23
+ # --- Authentication ---
24
+ USERS = {
25
+ "tester1": "pass123",
26
+ "researcher": "lab456",
27
+ "admin": "admin789"
28
+ }
29
+
30
+ # --- State Management ---
31
+ def get_default_state():
32
+ """Initializes a new session state."""
33
+ return {
34
+ "original_user_message": "",
35
+ "estimate": {},
36
+ "current_conversation_file": None,
37
+ }
38
+
39
+ # --- Conversation Management ---
40
+ def save_conversation(history, state):
41
+ if not history:
42
+ return "Nothing to save.", gr.update()
43
+
44
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
45
+ filename = f"conv_{timestamp}.json"
46
+ filepath = os.path.join("conversations", filename)
47
+
48
+ with open(filepath, 'w', encoding='utf-8') as f:
49
+ json.dump(history, f, indent=2)
50
+
51
+ state["current_conversation_file"] = filepath
52
+ log.info(f"Conversation saved to {filepath}")
53
+ return f"Saved to {filename}", gr.update(choices=get_saved_conversations())
54
+
55
+ def load_conversation(filepath, state):
56
+ if not filepath:
57
+ return [], state
58
+
59
+ with open(filepath, 'r', encoding='utf-8') as f:
60
+ history = json.load(f)
61
+
62
+ state["current_conversation_file"] = filepath
63
+ log.info(f"Conversation loaded from {filepath}")
64
+ return history, state
65
+
66
+ def get_saved_conversations():
67
+ return [os.path.join("conversations", f) for f in os.listdir("conversations") if f.endswith(".json")]
68
+
69
+ def clear_conversation():
70
+ return [], get_default_state(), "Conversation cleared.", "No artifacts generated yet."
71
+
72
+ # --- Artifact Management ---
73
+ def handle_file_upload(file):
74
+ if file is None:
75
+ return "No file uploaded."
76
+
77
+ basename = os.path.basename(file.name)
78
+ destination_path = os.path.join("uploads", basename)
79
+ os.rename(file.name, destination_path)
80
+ log.info(f"File uploaded to {destination_path}")
81
+ return f"Uploaded: {basename}"
82
+
83
+ def update_artifact_list():
84
+ output_files = os.listdir("outputs")
85
+ if not output_files:
86
+ return "No artifacts generated yet."
87
+
88
+ markdown_list = "### Generated Artifacts:\n"
89
+ for f in output_files:
90
+ markdown_list += f"- `{f}` (in your 'outputs' folder)\n"
91
+ return markdown_list
92
+
93
+ # --- Core Logic Functions ---
94
+ def start_estimation(message, history, state):
95
+ log.info(f"Starting estimation for: '{message}'")
96
+ state["original_user_message"] = message
97
+ history.append({"role": "user", "content": message})
98
+
99
+ yield history, state, gr.update(value="", interactive=False), gr.update(visible=False), gr.update(), "Analyzing request..."
100
+
101
+ triage_inputs = {"userInput": message}
102
+ triage_result = triage_app.invoke(triage_inputs)
103
+
104
+ if triage_result.get("draftResponse"):
105
+ history.append({"role": "assistant", "content": triage_result["draftResponse"]})
106
+ yield history, state, gr.update(interactive=True), gr.update(visible=False), gr.update(), "Ready."
107
+ return
108
+
109
+ planner_inputs = {"userInput": message}
110
+ estimate_result = planner_app.invoke(planner_inputs)
111
+ estimate = estimate_result.get('pmPlan', {})
112
+ state["estimate"] = estimate
113
+
114
+ if estimate.get("error"):
115
+ error_msg = f"Error during planning: {estimate['error']}"
116
+ history.append({"role": "assistant", "content": error_msg})
117
+ yield history, state, gr.update(interactive=True), gr.update(visible=False), gr.update(value=0.10), error_msg
118
+ else:
119
+ plan_text = "\n".join([f"- {step}" for step in estimate.get('plan', [])])
120
+ approval_text_md = (f"**Here is my plan:**\n{plan_text}\n\nThis may require up to **{estimate.get('max_loops_initial', 0) + 1} attempts** and could cost approximately **${estimate.get('estimated_cost_usd', 0.0)}**.")
121
+ yield history, state, gr.update(interactive=False), gr.update(visible=True, value=approval_text_md), gr.update(value=estimate.get('estimated_cost_usd', 0.10)), "Awaiting your approval to proceed."
122
+
123
+ def execute_main_task(history, state, budget):
124
+ log.info(f"Executing main task with budget: ${budget}")
125
+
126
+ yield history, state, gr.update(visible=False), gr.update(value="", interactive=False), "Task approved. Starting execution..."
127
+
128
+ history.append({"role": "assistant", "content": "..."})
129
+
130
+ cost_per_loop = state["estimate"].get('cost_per_loop_usd', 0.05)
131
+ if cost_per_loop > 0:
132
+ total_runs_affordable = max(1, math.floor(float(budget) / cost_per_loop))
133
+ max_loops_calibrated = total_runs_affordable - 1
134
+ else:
135
+ max_loops_calibrated = 0
136
+
137
+ initial_state = {
138
+ "userInput": state["original_user_message"],
139
+ "chatHistory": [],
140
+ "max_loops": max_loops_calibrated,
141
+ "status_update": "Task approved. Starting execution..."
142
+ }
143
+
144
+ final_response = "An error occurred during execution."
145
+ for step in main_app.stream(initial_state):
146
+ node_name = list(step.keys())[0]
147
+ node_output = step[node_name]
148
+
149
+ status = node_output.get("status_update", "Processing...")
150
+ yield history, state, gr.update(visible=False), gr.update(interactive=False), status
151
+
152
+ if "draftResponse" in node_output and node_output["draftResponse"]:
153
+ final_response = node_output["draftResponse"]
154
+
155
+ history[-1] = {"role": "assistant", "content": final_response}
156
+ yield history, state, gr.update(visible=False), gr.update(interactive=True), "Task complete. Ready."
157
+
158
+ def cancel_task(history, state):
159
+ history.append({"role": "assistant", "content": "Task cancelled."})
160
+ return history, state, gr.update(visible=False), gr.update(interactive=True), "Task cancelled. Ready."
161
+
162
+ # --- Gradio UI Definition ---
163
+ with gr.Blocks(theme=gr.themes.Soft(), title="Autonomous AI Lab") as demo:
164
+ state = gr.State(value=get_default_state())
165
+
166
+ gr.Markdown("# Autonomous AI Lab")
167
+
168
+ with gr.Row():
169
+ with gr.Column(scale=1):
170
+ gr.Markdown("### Controls")
171
+ clear_btn = gr.Button("🗑️ New Conversation")
172
+ gr.Markdown("### Saved Chats")
173
+ saved_chats_dropdown = gr.Dropdown(label="Load a past conversation", choices=get_saved_conversations(), interactive=True)
174
+ save_chat_btn = gr.Button("💾 Save Current Chat")
175
+ save_status_text = gr.Textbox(label="Save Status", interactive=False)
176
+ gr.Markdown("### Artifacts")
177
+ file_uploader = gr.File(label="Upload a file")
178
+ upload_status_text = gr.Textbox(label="Upload Status", interactive=False)
179
+ refresh_artifacts_btn = gr.Button("🔄 Refresh Artifacts List")
180
+ artifact_list_display = gr.Markdown("No artifacts generated yet.")
181
+
182
+ with gr.Column(scale=4):
183
+ chatbot = gr.Chatbot(label="Conversation", height=600, avatar_images=(None, "https://i.imgur.com/b5OqI32.png"))
184
+ status_display = gr.Markdown("Status: Ready.")
185
+ with gr.Group(visible=False) as approval_box:
186
+ approval_text = gr.Markdown()
187
+ with gr.Row():
188
+ budget_input = gr.Number(label="Set your maximum budget ($)", value=0.10, minimum=0.01, step=0.05)
189
+ with gr.Row():
190
+ proceed_btn = gr.Button("✅ Approve & Proceed", variant="primary")
191
+ cancel_btn = gr.Button("❌ Cancel")
192
+
193
+ with gr.Row():
194
+ msg_textbox = gr.Textbox(label="Your Message", placeholder="Ask a question or describe a task...", scale=7)
195
+ submit_btn = gr.Button("Send", variant="primary", scale=1)
196
+
197
+ # --- Event Handlers ---
198
+ estimation_outputs = [chatbot, state, msg_textbox, approval_box, budget_input, status_display]
199
+ execution_outputs = [chatbot, state, approval_box, msg_textbox, status_display]
200
+ cancel_outputs = [chatbot, state, approval_box, msg_textbox, status_display]
201
+ clear_outputs = [chatbot, state, save_status_text, artifact_list_display]
202
+
203
+ msg_textbox.submit(fn=start_estimation, inputs=[msg_textbox, chatbot, state], outputs=estimation_outputs)
204
+ submit_btn.click(fn=start_estimation, inputs=[msg_textbox, chatbot, state], outputs=estimation_outputs)
205
+ proceed_btn.click(fn=execute_main_task, inputs=[chatbot, state, budget_input], outputs=execution_outputs)
206
+ cancel_btn.click(fn=cancel_task, inputs=[chatbot, state], outputs=cancel_outputs)
207
+
208
+ clear_btn.click(fn=clear_conversation, inputs=[], outputs=clear_outputs)
209
+ save_chat_btn.click(fn=save_conversation, inputs=[chatbot, state], outputs=[save_status_text, saved_chats_dropdown])
210
+ saved_chats_dropdown.change(fn=load_conversation, inputs=[saved_chats_dropdown, state], outputs=[chatbot, state])
211
+ file_uploader.upload(fn=handle_file_upload, inputs=[file_uploader], outputs=[upload_status_text])
212
+ refresh_artifacts_btn.click(fn=update_artifact_list, inputs=[], outputs=[artifact_list_display])
213
+
214
+ # --- Launch Configuration ---
215
+ if __name__ == "__main__":
216
+ demo.launch(
217
+ share=True,
218
+ server_name="0.0.0.0",
219
+ auth=[(user, pwd) for user, pwd in USERS.items()],
220
+ auth_message="Enter your credentials to access the Autonomous AI Lab."
221
+ )
patch_gradio_jsonschema.py CHANGED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # patch_gradio_jsonschema.py
2
+ """
3
+ Runtime monkeypatch to make gradio_client JSON Schema handling robust to boolean schemas.
4
+ Import this BEFORE importing gradio or gradio_client (so do it at the top of your entrypoint).
5
+ """
6
+
7
+ try:
8
+ import gradio_client.utils as _gc_utils
9
+ except Exception:
10
+ _gc_utils = None
11
+
12
+ def _is_bool_schema(x):
13
+ return isinstance(x, bool)
14
+
15
+ def _bool_to_safe_schema(b: bool):
16
+ if b:
17
+ return {}
18
+ else:
19
+ return {"type": "___boolean_schema_false___"}
20
+
21
+ def _wrap_get_type(orig):
22
+ def wrapper(schema):
23
+ if _is_bool_schema(schema):
24
+ schema = _bool_to_safe_schema(schema)
25
+ return orig(schema)
26
+ return wrapper
27
+
28
+ def _wrap_json_schema_to_python_type(orig):
29
+ def wrapper(schema, defs=None):
30
+ if _is_bool_schema(schema):
31
+ schema = _bool_to_safe_schema(schema)
32
+ return orig(schema, defs)
33
+ return wrapper
34
+
35
+ def apply_patch():
36
+ global _gc_utils
37
+ if _gc_utils is None:
38
+ try:
39
+ import gradio_client.utils as _gc_utils
40
+ except Exception:
41
+ return False
42
+
43
+ if hasattr(_gc_utils, "get_type"):
44
+ _gc_utils.get_type = _wrap_get_type(_gc_utils.get_type)
45
+
46
+ if hasattr(_gc_utils, "_json_schema_to_python_type"):
47
+ _gc_utils._json_schema_to_python_type = _wrap_json_schema_to_python_type(
48
+ _gc_utils._json_schema_to_python_type
49
+ )
50
+
51
+ if hasattr(_gc_utils, "json_schema_to_python_type"):
52
+ orig_public = _gc_utils.json_schema_to_python_type
53
+ def public_wrapper(schema, defs=None):
54
+ if _is_bool_schema(schema):
55
+ schema = _bool_to_safe_schema(schema)
56
+ return orig_public(schema, defs)
57
+ _gc_utils.json_schema_to_python_type = public_wrapper
58
+
59
+ return True
60
+
61
+ apply_patch()
62
+ # diagnostic print
63
+ try:
64
+ print("patch_gradio_jsonschema applied")
65
+ except Exception:
66
+ pass