S-Dreamer commited on
Commit
2893fbd
·
verified ·
1 Parent(s): 1460ed3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +244 -107
app.py CHANGED
@@ -1,125 +1,262 @@
1
- import sys
2
- import subprocess
3
- import logging
4
  import gradio as gr
5
  import requests
6
- import os
7
- from typing import Dict, Tuple
 
 
 
 
8
 
 
9
  logging.basicConfig(level=logging.INFO)
10
  logger = logging.getLogger(__name__)
11
 
12
- def install(package):
13
- subprocess.check_call([sys.executable, "-m", "pip", "install", package])
14
 
15
- required_packages = ['gradio', 'requests']
16
- for package in required_packages:
17
- try:
18
- __import__(package)
19
- except ImportError:
20
- print(f"{package} not found. Installing...")
21
- install(package)
22
-
23
- if not os.environ.get("CODEPAL_API_KEY"):
24
- print("Error: CODEPAL_API_KEY environment variable is not set.")
25
- print("Please set it and try again.")
26
- sys.exit(1)
27
-
28
- # Constants
29
- DEFAULTS = {
30
- "SYSTEM_MESSAGE": "You are CodePal.ai, an expert AI assistant specialized in helping programmers. You generate clean, efficient, and well-documented code based on user requirements.",
31
- "MAX_TOKENS": 4000,
32
- "TEMPERATURE": 0.7,
33
- "TOP_P": 0.95,
34
  }
35
 
36
- API_URLS = {
37
- "CODE_GENERATOR": "https://api.codepal.ai/v1/code-generator/query",
38
- "CODE_FIXER": "https://api.codepal.ai/v1/code-fixer/query",
39
- "CODE_EXTENDER": "https://api.codepal.ai/v1/code-extender/query",
40
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
- def check_api_endpoints():
43
- for name, url in API_URLS.items():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  try:
45
- response = requests.head(url)
46
- if response.status_code == 200:
47
- print(f"{name} API endpoint is accessible.")
48
- else:
49
- print(f"Warning: {name} API endpoint returned status code {response.status_code}")
50
- except requests.RequestException as e:
51
- print(f"Error accessing {name} API endpoint: {str(e)}")
52
-
53
- check_api_endpoints()
54
-
55
- def get_api_key() -> str:
56
- """Fetch API key from environment variables."""
57
- return os.environ.get("CODEPAL_API_KEY", "")
58
-
59
- def is_api_key_valid() -> bool:
60
- """Validate if the API key is set and not a placeholder."""
61
- api_key = get_api_key()
62
- return bool(api_key) and api_key != "YOUR_API_KEY"
63
-
64
- def build_request_data(language: str, instructions: str, flavor: str, max_tokens: int, temperature: float, top_p: float) -> Dict:
65
- """Construct the request data for API calls."""
66
- return {
67
- "language": language,
68
- "instructions": instructions,
69
- "flavor": flavor,
70
- "max_tokens": max_tokens,
71
- "temperature": temperature,
72
- "top_p": top_p
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  }
 
 
 
 
 
74
 
75
- def handle_api_response(response) -> Tuple[bool, str]:
76
- """Handle API response and return success status and result."""
77
- if response.status_code != 200:
78
- error_message = "API request failed"
79
- try:
80
- error_data = response.json()
81
- error_message = error_data.get("error", error_message)
82
- except Exception:
83
- error_message = f"API request failed with status code {response.status_code}"
84
- return False, f"Error: {error_message}"
85
-
86
- result = response.json()
87
- if "error" in result:
88
- return False, f"Error: {result['error']}"
89
-
90
- return True, result["result"]
91
-
92
- def generate_code(language: str, requirements: str, code_style: str, include_tests: bool,
93
- max_tokens: int = DEFAULTS["MAX_TOKENS"],
94
- temperature: float = DEFAULTS["TEMPERATURE"],
95
- top_p: float = DEFAULTS["TOP_P"]) -> Tuple[bool, str]:
96
- """Generate code using CodePal.ai API."""
97
  try:
98
- if not is_api_key_valid():
99
- return False, "Error: CodePal.ai API key is not configured. Please set the CODEPAL_API_KEY environment variable."
100
-
101
- flavor = {
102
- "minimal": "minimal",
103
- "verbose": "documented"
104
- }.get(code_style, "standard") if code_style in ["minimal", "verbose"] else "tests" if include_tests else "standard"
105
-
106
- api_key = get_api_key()
107
- headers = {
108
- "Authorization": f"Bearer {api_key}",
109
- "Content-Type": "application/json"
110
- }
111
-
112
- data = build_request_data(language, requirements, flavor, max_tokens, temperature, top_p)
113
- response = requests.post(API_URLS["CODE_GENERATOR"], headers=headers, json=data)
114
- return handle_api_response(response)
115
  except Exception as e:
116
- logger.error(f"Error in generate_code: {str(e)}")
117
- return False, f"Error: {str(e)}"
118
 
119
- # Launch the app (if applicable)
120
- if __name__ == "__main__":
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  try:
122
- app.launch(share=True) # Modify based on your application's entry point
 
 
123
  except Exception as e:
124
- print(f"Error starting the Gradio application: {str(e)}")
125
- sys.exit(1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from typing import Optional
 
3
  import gradio as gr
4
  import requests
5
+ from smolagents import CodeAgent, Tool
6
+ from smolagents.models import HfApiModel
7
+ from smolagents.monitoring import LogLevel
8
+ from gradio import ChatMessage
9
+ import logging
10
+ from functools import lru_cache
11
 
12
+ # Configure logging
13
  logging.basicConfig(level=logging.INFO)
14
  logger = logging.getLogger(__name__)
15
 
16
+ DEFAULT_MODEL = "Qwen/Qwen2.5-Coder-32B-Instruct"
17
+ HF_API_TOKEN = os.getenv("HF_TOKEN")
18
 
19
+ # Tool descriptions for the UI
20
+ TOOL_DESCRIPTIONS = {
21
+ "Hub Collections": "Add tool collections from Hugging Face Hub.",
22
+ "Spaces": "Add tools from Hugging Face Spaces.",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  }
24
 
25
+ @lru_cache(maxsize=128)
26
+ def search_spaces(query, limit=1):
27
+ """
28
+ Search for Hugging Face Spaces using the API.
29
+ Returns the first result or None if no results.
30
+ """
31
+ try:
32
+ url = f"https://huggingface.co/api/spaces?search={query}&limit={limit}"
33
+ response = requests.get(
34
+ url, headers={"Authorization": f"Bearer {HF_API_TOKEN}"}
35
+ )
36
+ response.raise_for_status()
37
+ spaces = response.json()
38
+ if not spaces:
39
+ return None
40
+ return extract_space_info(spaces[0])
41
+ except requests.RequestException as e:
42
+ logger.error(f"Error searching spaces: {e}")
43
+ return None
44
 
45
+ def extract_space_info(space):
46
+ space_id = space["id"]
47
+ title = space_id.split("/")[-1]
48
+ description = f"Tool from {space_id}"
49
+ if "title" in space:
50
+ title = space["title"]
51
+ elif "cardData" in space and "title" in space["cardData"]:
52
+ title = space["cardData"]["title"]
53
+ if "description" in space:
54
+ description = space["description"]
55
+ elif "cardData" in space and "description" in space["cardData"]:
56
+ description = space["cardData"]["description"]
57
+ return {"id": space_id, "title": title, "description": description}
58
+
59
+ def get_space_metadata(space_id):
60
+ """
61
+ Get metadata for a specific Hugging Face Space.
62
+ """
63
+ try:
64
+ url = f"https://huggingface.co/api/spaces/{space_id}"
65
+ response = requests.get(
66
+ url, headers={"Authorization": f"Bearer {HF_API_TOKEN}"}
67
+ )
68
+ response.raise_for_status()
69
+ space = response.json()
70
+ return extract_space_info(space)
71
+ except requests.RequestException as e:
72
+ logger.error(f"Error getting space metadata: {e}")
73
+ return None
74
+
75
+ def create_agent(model_name, space_tools=None):
76
+ """
77
+ Create a CodeAgent with the specified model and tools.
78
+ """
79
+ if not space_tools:
80
+ space_tools = []
81
+ try:
82
+ tools = [Tool.from_space(
83
+ tool_info["id"],
84
+ name=tool_info.get("name", tool_info["id"]),
85
+ description=tool_info.get("description", ""),
86
+ ) for tool_info in space_tools]
87
+ model = HfApiModel(model_id=model_name, token=HF_API_TOKEN)
88
+ agent = CodeAgent(
89
+ tools=tools,
90
+ model=model,
91
+ additional_authorized_imports=["PIL", "requests"],
92
+ verbosity_level=LogLevel.DEBUG,
93
+ )
94
+ logger.info(f"Agent created successfully with {len(tools)} tools")
95
+ return agent
96
+ except Exception as e:
97
+ logger.error(f"Error creating agent: {e}")
98
  try:
99
+ logger.info("Trying fallback model...")
100
+ fallback_model = HfApiModel(
101
+ model_id="Qwen/Qwen2.5-Coder-7B-Instruct", token=HF_API_TOKEN
102
+ )
103
+ agent = CodeAgent(
104
+ tools=tools,
105
+ model=fallback_model,
106
+ additional_authorized_imports=["PIL", "requests"],
107
+ verbosity_level=LogLevel.DEBUG,
108
+ )
109
+ logger.info("Agent created successfully with fallback model")
110
+ return agent
111
+ except Exception as e:
112
+ logger.error(f"Error creating agent with fallback model: {e}")
113
+ return None
114
+
115
+ # Event handler functions
116
+ def on_search_spaces(query):
117
+ if not query:
118
+ return "Please enter a search term.", "", "", ""
119
+ try:
120
+ space_info = search_spaces(query)
121
+ if space_info is None:
122
+ return "No spaces found.", "", "", ""
123
+ results_md = f"### Search Results:\n- ID: `{space_info['id']}`\n- Title: {space_info['title']}\n- Description: {space_info['description']}\n"
124
+ return results_md, space_info["id"], space_info["title"], space_info["description"]
125
+ except Exception as e:
126
+ logger.error(f"Error in search: {e}")
127
+ return f"Error: {str(e)}", "", "", ""
128
+
129
+ def on_validate_space(space_id):
130
+ if not space_id:
131
+ return "Please enter a space ID or search term.", "", ""
132
+ try:
133
+ space_info = get_space_metadata(space_id)
134
+ if space_info is None:
135
+ space_info = search_spaces(space_id)
136
+ if space_info is None:
137
+ return f"No spaces found for '{space_id}'.", "", ""
138
+ result_md = f"### Found Space via Search:\n- ID: `{space_info['id']}`\n- Title: {space_info['title']}\n- Description: {space_info['description']}\n"
139
+ return result_md, space_info["title"], space_info["description"]
140
+ result_md = f"### Space Validated Successfully:\n- ID: `{space_info['id']}`\n- Title: {space_info['title']}\n- Description: {space_info['description']}\n"
141
+ return result_md, space_info["title"], space_info["description"]
142
+ except Exception as e:
143
+ logger.error(f"Error validating space: {e}")
144
+ return f"Error: {str(e)}", "", ""
145
+
146
+ def on_add_tool(space_id, space_name, space_description, current_tools):
147
+ if not space_id:
148
+ return current_tools, "Please enter a space ID."
149
+ for tool in current_tools:
150
+ if tool["id"] == space_id:
151
+ return current_tools, f"Tool '{space_id}' is already added."
152
+ new_tool = {
153
+ "id": space_id,
154
+ "name": space_name if space_name else space_id,
155
+ "description": space_description if space_description else "No description",
156
  }
157
+ updated_tools = current_tools + [new_tool]
158
+ tools_md = "### Added Tools:\n"
159
+ for i, tool in enumerate(updated_tools, 1):
160
+ tools_md += f"{i}. **{tool['name']}** (`{tool['id']}`)\n {tool['description']}\n\n"
161
+ return updated_tools, tools_md
162
 
163
+ def on_create_agent(model, space_tools):
164
+ if not space_tools:
165
+ return None, [], "", "Please add at least one tool before creating an agent.", "No agent created yet."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  try:
167
+ agent = create_agent(model, space_tools)
168
+ if agent is None:
169
+ return None, [], "", "Failed to create agent. Please try again with different tools or model.", "No agent created yet."
170
+ tools_str = ", ".join([f"{tool['name']} ({tool['id']})" for tool in space_tools])
171
+ agent_status = update_agent_status(agent)
172
+ return agent, [], "", f"✅ Agent created successfully with {model}!\nTools: {tools_str}", agent_status
 
 
 
 
 
 
 
 
 
 
 
173
  except Exception as e:
174
+ logger.error(f"Error creating agent: {e}")
175
+ return None, [], "", f"Error creating agent: {str(e)}", "No agent created yet."
176
 
177
+ def add_user_message(message, chat_history):
178
+ if not message:
179
+ return "", chat_history
180
+ chat_history = chat_history + [ChatMessage(role="user", content=message)]
181
+ return message, chat_history
182
+
183
+ def stream_to_gradio(agent, task: str, reset_agent_memory: bool = False, additional_args: Optional[dict] = None):
184
+ from smolagents.gradio_ui import pull_messages_from_step, handle_agent_output_types
185
+ from smolagents.agent_types import AgentAudio, AgentImage, AgentText
186
+ for step_log in agent.run(task, stream=True, reset=reset_agent_memory, additional_args=additional_args):
187
+ for message in pull_messages_from_step(step_log):
188
+ yield message
189
+ final_answer = step_log
190
+ final_answer = handle_agent_output_types(final_answer)
191
+ if isinstance(final_answer, AgentImage):
192
+ yield gr.ChatMessage(role="assistant", content={"path": final_answer.to_string(), "mime_type": "image/png"})
193
+ elif isinstance(final_answer, AgentText) and os.path.exists(final_answer.to_string()):
194
+ yield gr.ChatMessage(role="assistant", content=gr.Image(final_answer.to_string()))
195
+ elif isinstance(final_answer, AgentAudio):
196
+ yield gr.ChatMessage(role="assistant", content={"path": final_answer.to_string(), "mime_type": "audio/wav"})
197
+ else:
198
+ yield gr.ChatMessage(role="assistant", content=f"**Final answer:** {str(final_answer)}")
199
+
200
+ def stream_agent_response(agent, message, chat_history):
201
+ if not message or agent is None:
202
+ return chat_history
203
+ yield chat_history
204
  try:
205
+ for msg in stream_to_gradio(agent, message):
206
+ chat_history = chat_history + [msg]
207
+ yield chat_history
208
  except Exception as e:
209
+ error_msg = f"Error: {str(e)}"
210
+ chat_history = chat_history + [ChatMessage(role="assistant", content=error_msg)]
211
+ yield chat_history
212
+
213
+ def on_clear(agent=None):
214
+ return agent, [], "", "Agent cleared. Create a new one to continue.", "", gr.update(interactive=False)
215
+
216
+ def update_agent_status(agent):
217
+ if agent is None:
218
+ return "No agent created yet. Add a Space tool to get started."
219
+ tools = agent.tools if hasattr(agent, "tools") else []
220
+ tool_count = len(tools)
221
+ status = f"Agent ready with {tool_count} tools"
222
+ return status
223
+
224
+ # Create the Gradio app
225
+ with gr.Blocks(title="AI Agent Builder") as app:
226
+ gr.Markdown("# AI Agent Builder with smolagents")
227
+ gr.Markdown("Build your own AI agent by selecting tools from Hugging Face Spaces.")
228
+ agent_state = gr.State(None)
229
+ last_message = gr.State("")
230
+ space_tools_state = gr.State([])
231
+ msg_store = gr.State("")
232
+ with gr.Row():
233
+ with gr.Column(scale=1):
234
+ gr.Markdown("## Tool Configuration")
235
+ gr.Markdown("Add multiple Hugging Face Spaces as tools for your agent:")
236
+ model_input = gr.Textbox(value=DEFAULT_MODEL, label="Model", visible=False)
237
+ with gr.Group():
238
+ gr.Markdown("### Add Space as Tool")
239
+ space_tool_input = gr.Textbox(label="Space ID or Search Term", placeholder=("Enter a Space ID or search term"), info="Enter a Space ID (username/space-name) or search term")
240
+ space_name_input = gr.Textbox(label="Tool Name (optional)", placeholder="Enter a name for this tool")
241
+ space_description_input = gr.Textbox(label="Tool Description (optional)", placeholder="Enter a description for this tool", lines=2)
242
+ add_tool_button = gr.Button("Add Tool", variant="primary")
243
+ gr.Markdown("### Added Tools")
244
+ tools_display = gr.Markdown("No tools added yet. Add at least one tool before creating an agent.")
245
+ create_button = gr.Button("Create Agent with Selected Tools", variant="secondary", size="lg")
246
+ status_msg = gr.Markdown("")
247
+ agent_status = gr.Markdown("No agent created yet.")
248
+ with gr.Column(scale=2):
249
+ chatbot = gr.Chatbot(label="Agent Chat", height=600, show_copy_button=True, avatar_images=("👤", "🤖"), type="messages")
250
+ msg = gr.Textbox(label="Your message", placeholder="Type a message to your agent...", interactive=True)
251
+ with gr.Row():
252
+ with gr.Column(scale=1, min_width=60):
253
+ clear = gr.Button("🗑️", scale=1)
254
+ with gr.Column(scale=8):
255
+ pass
256
+ space_tool_input.submit(on_validate_space, inputs=[space_tool_input], outputs=[status_msg, space_name_input, space_description_input])
257
+ add_tool_button.click(on_add_tool, inputs=[space_tool_input, space_name_input, space_description_input, space_tools_state], outputs=[space_tools_state, tools_display])
258
+ create_button.click(on_create_agent, inputs=[model_input, space_tools_state], outputs=[agent_state, chatbot, msg, status_msg, agent_status])
259
+ msg.submit(lambda message: (message, message, ""), inputs=[msg], outputs=[msg_store, msg, msg], queue=False).then(add_user_message, inputs=[msg_store, chatbot], outputs=[msg_store, chatbot], queue=False).then(stream_agent_response, inputs=[agent_state, msg_store, chatbot], outputs=chatbot, queue=True)
260
+
261
+ if __name__ == "__main__":
262
+ app.queue().launch()