eaglelandsonce commited on
Commit
fed29da
·
verified ·
1 Parent(s): 7427db1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +96 -86
app.py CHANGED
@@ -1,8 +1,8 @@
1
  import os
2
- import tempfile
3
  import gradio as gr
 
4
 
5
- # Azure AI Agents SDK
6
  from azure.core.credentials import AzureKeyCredential
7
  from azure.ai.agents import AgentsClient
8
  from azure.ai.agents.models import (
@@ -13,71 +13,70 @@ from azure.ai.agents.models import (
13
  )
14
 
15
 
16
- def init_agent(endpoint: str, api_key: str, model_deployment: str, data_file) -> dict:
 
 
 
 
 
 
 
17
  """
18
- Initialize an Azure AI Agent with optional data file for the Code Interpreter.
19
- Returns a session dict with client, agent, thread, and bookkeeping.
20
  """
21
  if not endpoint or not api_key or not model_deployment:
22
  raise ValueError("Please provide endpoint, key, and model deployment name.")
23
 
24
- # Create client (API key auth)
25
  client = AgentsClient(
26
  endpoint=endpoint.strip(),
27
  credential=AzureKeyCredential(api_key.strip()),
28
  )
29
 
30
- # Create a temporary file path if a file is provided
31
- temp_path = None
32
- if data_file is not None:
33
- # Gradio gives a tempfile-like object; persist it to a path for upload
34
- with tempfile.NamedTemporaryFile(delete=False) as tmp:
35
- tmp.write(data_file.read())
36
- temp_path = tmp.name
37
-
38
- with client:
39
- code_interpreter = None
40
-
41
- if temp_path:
42
- # Upload file for agent use
43
- up = client.files.upload_and_poll(file_path=temp_path, purpose=FilePurpose.AGENTS)
44
- # Create the tool bound to this file
45
- code_interpreter = CodeInterpreterTool(file_ids=[up.id])
46
-
47
- # Define the agent (attach tools if we created one)
48
- agent = client.create_agent(
49
- model=model_deployment,
50
- name="data-agent",
51
- instructions=(
52
- "You are an AI agent that analyzes the uploaded data when present. "
53
- "Use Python via the Code Interpreter to compute statistical metrics or produce "
54
- "text-based charts when asked. If no file is provided, proceed with normal reasoning."
55
- ),
56
- tools=(code_interpreter.definitions if code_interpreter else None),
57
- tool_resources=(code_interpreter.resources if code_interpreter else None),
58
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
 
60
- # Create a thread for the conversation
61
- thread = client.threads.create()
62
 
63
- # Keep the client open for subsequent calls (no context manager here)
64
- session = {
65
  "endpoint": endpoint.strip(),
66
  "api_key": api_key.strip(),
67
  "model": model_deployment.strip(),
68
  "client": client,
69
  "agent_id": agent.id,
70
  "thread_id": thread.id,
71
- "has_file": data_file is not None,
72
- "temp_path": temp_path, # to clean up later if we want
73
  }
74
- return session
75
 
76
 
77
- def send_message(user_msg: str, session: dict):
78
  """
79
- Send a user message to the existing thread and return the agent's latest reply
80
- as well as a printable conversation history.
 
81
  """
82
  if not session or "client" not in session:
83
  raise ValueError("Agent is not initialized. Click 'Connect & Prepare' first.")
@@ -86,28 +85,27 @@ def send_message(user_msg: str, session: dict):
86
  agent_id = session["agent_id"]
87
  thread_id = session["thread_id"]
88
 
89
- # Create the user message on the thread
90
  client.messages.create(
91
  thread_id=thread_id,
92
  role="user",
93
  content=user_msg,
94
  )
95
 
96
- # Run the agent on the thread and wait for completion
97
  run = client.runs.create_and_process(thread_id=thread_id, agent_id=agent_id)
98
-
99
  if getattr(run, "status", None) == "failed":
100
  last_error = getattr(run, "last_error", "Unknown error")
101
  return f"Run failed: {last_error}", ""
102
 
103
- # Get the last agent message text
104
  last_msg = client.messages.get_last_message_text_by_role(
105
  thread_id=thread_id,
106
  role=MessageRole.AGENT,
107
  )
108
  agent_reply = last_msg.text.value if last_msg else "(No reply text found.)"
109
 
110
- # Build a readable conversation history
111
  history_lines = []
112
  messages = client.messages.list(thread_id=thread_id, order=ListSortOrder.ASCENDING)
113
  for m in messages:
@@ -119,46 +117,34 @@ def send_message(user_msg: str, session: dict):
119
  return agent_reply, history_str
120
 
121
 
122
- def teardown(session: dict):
123
  """
124
- Delete the agent (and optionally the temp file) to avoid unnecessary Azure costs.
125
- Note: Threads are retained by service; you can delete agents to clean up.
126
  """
127
  if not session:
128
  return "Nothing to clean up."
129
 
130
- msg = []
131
  try:
132
  client: AgentsClient = session.get("client")
133
- if client:
134
- with client:
135
- agent_id = session.get("agent_id")
136
- if agent_id:
137
- client.delete_agent(agent_id)
138
- msg.append("Deleted agent.")
139
  except Exception as e:
140
- msg.append(f"Cleanup warning: {e}")
141
 
142
- # Remove temp file if created
143
- try:
144
- temp_path = session.get("temp_path")
145
- if temp_path and os.path.exists(temp_path):
146
- os.remove(temp_path)
147
- msg.append("Removed temp file.")
148
- except Exception as e:
149
- msg.append(f"Temp cleanup warning: {e}")
150
-
151
- return " ".join(msg) if msg else "Cleanup complete."
152
 
153
 
154
- # ----------------- Gradio UI -----------------
155
 
156
  with gr.Blocks(title="Azure AI Agent (Endpoint+Key) — Gradio") as demo:
157
  gr.Markdown(
158
  "## Azure AI Agent (Code Interpreter Ready)\n"
159
- "Enter your **Project Endpoint** and **Key**, select your **Model Deployment** (e.g., `gpt-4o`), "
160
- "optionally upload a data file (CSV/TXT), then chat.\n"
161
- "Click **Connect & Prepare** once, then send prompts in the chat."
162
  )
163
 
164
  with gr.Row():
@@ -167,15 +153,25 @@ with gr.Blocks(title="Azure AI Agent (Endpoint+Key) — Gradio") as demo:
167
 
168
  with gr.Row():
169
  model = gr.Textbox(label="Model Deployment Name", value="gpt-4o")
170
- data_file = gr.File(label="Optional data file for Code Interpreter (txt/csv)", file_types=[".txt", ".csv"], type="binary")
 
 
 
 
171
 
172
  session_state = gr.State(value=None)
173
 
174
  connect_btn = gr.Button("🔌 Connect & Prepare Agent", variant="primary")
175
  connect_status = gr.Markdown("")
176
 
 
177
  with gr.Row():
178
- chatbot = gr.Chatbot(height=420, label="Conversation").style(height=420)
 
 
 
 
 
179
  user_input = gr.Textbox(label="Your message", placeholder="Ask a question or request a chart…")
180
  with gr.Row():
181
  send_btn = gr.Button("Send ▶")
@@ -183,10 +179,11 @@ with gr.Blocks(title="Azure AI Agent (Endpoint+Key) — Gradio") as demo:
183
 
184
  history = gr.Textbox(label="Conversation Log (chronological)", lines=12)
185
 
186
- # Callbacks
187
- def on_connect(ep, key, mdl, f):
 
188
  try:
189
- sess = init_agent(ep, key, mdl, f)
190
  return sess, "✅ Connected. Agent and thread are ready."
191
  except Exception as e:
192
  return None, f"❌ Connection error: {e}"
@@ -197,20 +194,32 @@ with gr.Blocks(title="Azure AI Agent (Endpoint+Key) — Gradio") as demo:
197
  outputs=[session_state, connect_status],
198
  )
199
 
200
- def on_send(msg, session, chat_hist):
 
 
 
 
201
  if not msg:
202
- return gr.update(), chat_hist, gr.update(value="Please enter a message.")
 
203
  try:
204
- reply, log = send_message(msg, session)
205
- chat_hist = (chat_hist or []) + [[msg, reply]]
206
- return chat_hist, chat_hist, gr.update(value=log)
 
 
 
 
 
 
207
  except Exception as e:
208
- return chat_hist, chat_hist, gr.update(value=f"❌ Error: {e}")
 
209
 
210
  send_btn.click(
211
  fn=on_send,
212
  inputs=[user_input, session_state, chatbot],
213
- outputs=[chatbot, chatbot, history],
214
  )
215
 
216
  def on_cleanup(session):
@@ -227,4 +236,5 @@ with gr.Blocks(title="Azure AI Agent (Endpoint+Key) — Gradio") as demo:
227
  )
228
 
229
  if __name__ == "__main__":
 
230
  demo.launch()
 
1
  import os
 
2
  import gradio as gr
3
+ from typing import List, Dict, Tuple, Optional
4
 
5
+ # Azure AI Agents SDK (API key auth)
6
  from azure.core.credentials import AzureKeyCredential
7
  from azure.ai.agents import AgentsClient
8
  from azure.ai.agents.models import (
 
13
  )
14
 
15
 
16
+ # ----------------- Core Agent Helpers -----------------
17
+
18
+ def init_agent(
19
+ endpoint: str,
20
+ api_key: str,
21
+ model_deployment: str,
22
+ data_file_path: Optional[str],
23
+ ) -> dict:
24
  """
25
+ Initialize an Azure AI Agent with an optional data file for the Code Interpreter.
26
+ Returns a session dict containing client, agent_id, thread_id, etc.
27
  """
28
  if not endpoint or not api_key or not model_deployment:
29
  raise ValueError("Please provide endpoint, key, and model deployment name.")
30
 
 
31
  client = AgentsClient(
32
  endpoint=endpoint.strip(),
33
  credential=AzureKeyCredential(api_key.strip()),
34
  )
35
 
36
+ # Optionally upload file and bind it to a Code Interpreter tool
37
+ code_interpreter = None
38
+ if data_file_path:
39
+ uploaded = client.files.upload_and_poll(
40
+ file_path=data_file_path,
41
+ purpose=FilePurpose.AGENTS
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  )
43
+ code_interpreter = CodeInterpreterTool(file_ids=[uploaded.id])
44
+
45
+ # Create the agent (attach tools only if present)
46
+ agent = client.create_agent(
47
+ model=model_deployment.strip(),
48
+ name="data-agent",
49
+ instructions=(
50
+ "You are an AI agent that analyzes the uploaded data when present. "
51
+ "Use Python via the Code Interpreter to compute statistical metrics "
52
+ "or produce text-based charts when asked. If no file is provided, "
53
+ "proceed with normal reasoning."
54
+ ),
55
+ tools=(code_interpreter.definitions if code_interpreter else None),
56
+ tool_resources=(code_interpreter.resources if code_interpreter else None),
57
+ )
58
 
59
+ # Create a thread for the conversation
60
+ thread = client.threads.create()
61
 
62
+ # Session we keep in Gradio state
63
+ return {
64
  "endpoint": endpoint.strip(),
65
  "api_key": api_key.strip(),
66
  "model": model_deployment.strip(),
67
  "client": client,
68
  "agent_id": agent.id,
69
  "thread_id": thread.id,
70
+ "has_file": bool(data_file_path),
71
+ "uploaded_path": data_file_path,
72
  }
 
73
 
74
 
75
+ def send_to_agent(user_msg: str, session: dict) -> Tuple[str, str]:
76
  """
77
+ Send a message to the existing agent thread and return:
78
+ - agent_reply (str)
79
+ - history_str (str) readable, chronological log
80
  """
81
  if not session or "client" not in session:
82
  raise ValueError("Agent is not initialized. Click 'Connect & Prepare' first.")
 
85
  agent_id = session["agent_id"]
86
  thread_id = session["thread_id"]
87
 
88
+ # Add user message
89
  client.messages.create(
90
  thread_id=thread_id,
91
  role="user",
92
  content=user_msg,
93
  )
94
 
95
+ # Run and wait for completion
96
  run = client.runs.create_and_process(thread_id=thread_id, agent_id=agent_id)
 
97
  if getattr(run, "status", None) == "failed":
98
  last_error = getattr(run, "last_error", "Unknown error")
99
  return f"Run failed: {last_error}", ""
100
 
101
+ # Get last agent message text
102
  last_msg = client.messages.get_last_message_text_by_role(
103
  thread_id=thread_id,
104
  role=MessageRole.AGENT,
105
  )
106
  agent_reply = last_msg.text.value if last_msg else "(No reply text found.)"
107
 
108
+ # Build readable history (chronological)
109
  history_lines = []
110
  messages = client.messages.list(thread_id=thread_id, order=ListSortOrder.ASCENDING)
111
  for m in messages:
 
117
  return agent_reply, history_str
118
 
119
 
120
+ def teardown(session: dict) -> str:
121
  """
122
+ Delete the agent to reduce costs. (Threads are retained by service.)
 
123
  """
124
  if not session:
125
  return "Nothing to clean up."
126
 
127
+ messages = []
128
  try:
129
  client: AgentsClient = session.get("client")
130
+ agent_id = session.get("agent_id")
131
+ if client and agent_id:
132
+ client.delete_agent(agent_id)
133
+ messages.append("Deleted agent.")
 
 
134
  except Exception as e:
135
+ messages.append(f"Cleanup warning: {e}")
136
 
137
+ return " ".join(messages) if messages else "Cleanup complete."
 
 
 
 
 
 
 
 
 
138
 
139
 
140
+ # ----------------- Gradio App -----------------
141
 
142
  with gr.Blocks(title="Azure AI Agent (Endpoint+Key) — Gradio") as demo:
143
  gr.Markdown(
144
  "## Azure AI Agent (Code Interpreter Ready)\n"
145
+ "Enter your **Project Endpoint** and **Key**, set your **Model Deployment** (e.g., `gpt-4o`), "
146
+ "optionally upload a data file (TXT/CSV), then chat.\n"
147
+ "Click **Connect & Prepare Agent** once, then send prompts."
148
  )
149
 
150
  with gr.Row():
 
153
 
154
  with gr.Row():
155
  model = gr.Textbox(label="Model Deployment Name", value="gpt-4o")
156
+ data_file = gr.File(
157
+ label="Optional data file (txt/csv) for Code Interpreter",
158
+ file_types=[".txt", ".csv"],
159
+ type="filepath" # returns a filesystem path string
160
+ )
161
 
162
  session_state = gr.State(value=None)
163
 
164
  connect_btn = gr.Button("🔌 Connect & Prepare Agent", variant="primary")
165
  connect_status = gr.Markdown("")
166
 
167
+ # Use messages-format chatbot
168
  with gr.Row():
169
+ chatbot = gr.Chatbot(
170
+ label="Conversation",
171
+ height=420,
172
+ type="messages", # openai-style dicts: {"role": "...", "content": "..."}
173
+ )
174
+
175
  user_input = gr.Textbox(label="Your message", placeholder="Ask a question or request a chart…")
176
  with gr.Row():
177
  send_btn = gr.Button("Send ▶")
 
179
 
180
  history = gr.Textbox(label="Conversation Log (chronological)", lines=12)
181
 
182
+ # --------- Callbacks ---------
183
+
184
+ def on_connect(ep, key, mdl, fpath):
185
  try:
186
+ sess = init_agent(ep, key, mdl, fpath)
187
  return sess, "✅ Connected. Agent and thread are ready."
188
  except Exception as e:
189
  return None, f"❌ Connection error: {e}"
 
194
  outputs=[session_state, connect_status],
195
  )
196
 
197
+ def on_send(msg: str, session: dict, chat_msgs: List[Dict[str, str]]):
198
+ """
199
+ chat_msgs is a list of dicts with 'role' and 'content' (messages format).
200
+ We append the user's message and the assistant's reply in that same format.
201
+ """
202
  if not msg:
203
+ return gr.update(), gr.update(), gr.update(value="Please enter a message.")
204
+
205
  try:
206
+ agent_reply, log = send_to_agent(msg, session)
207
+
208
+ # Build updated chat message list
209
+ chat_msgs = (chat_msgs or []) + [
210
+ {"role": "user", "content": msg},
211
+ {"role": "assistant", "content": agent_reply},
212
+ ]
213
+
214
+ return chat_msgs, "", gr.update(value=log) # clear user input after send
215
  except Exception as e:
216
+ # Keep chat as-is, show error in history box
217
+ return chat_msgs, msg, gr.update(value=f"❌ Error: {e}")
218
 
219
  send_btn.click(
220
  fn=on_send,
221
  inputs=[user_input, session_state, chatbot],
222
+ outputs=[chatbot, user_input, history],
223
  )
224
 
225
  def on_cleanup(session):
 
236
  )
237
 
238
  if __name__ == "__main__":
239
+ # If deploying to spaces/containers you can set server_name/port via env if needed
240
  demo.launch()