User commited on
Commit
922248b
·
1 Parent(s): ff65373

User's custom AI Agent deploy

Browse files
Files changed (3) hide show
  1. Dockerfile +20 -5
  2. app.py +167 -153
  3. requirements.txt +4 -4
Dockerfile CHANGED
@@ -1,8 +1,23 @@
1
- FROM python:3.11-slim
2
- RUN apt-get update -qq && apt-get install -y -qq curl wget git build-essential && rm -rf /var/lib/apt/lists/*
 
 
 
 
 
 
 
3
  WORKDIR /app
 
 
4
  COPY requirements.txt .
5
- RUN pip3 install --no-cache-dir -r requirements.txt
6
- COPY app.py .
 
 
 
 
7
  EXPOSE 7860
8
- CMD ["python3", "app.py"]
 
 
 
1
+ FROM python:3.10-slim
2
+
3
+ # System dependencies (Web browsing aur tools ke liye jaruri packages)
4
+ RUN apt-get update && apt-get install -y \
5
+ curl \
6
+ gcc \
7
+ python3-dev \
8
+ && rm -rf /var/lib/apt/lists/*
9
+
10
  WORKDIR /app
11
+
12
+ # Dependencies install karein
13
  COPY requirements.txt .
14
+ RUN pip install --no-cache-dir -r requirements.txt
15
+
16
+ # Pura code copy karein
17
+ COPY . .
18
+
19
+ # Hugging Face Space default port 7860 use karta hai
20
  EXPOSE 7860
21
+ ENV GRADIO_SERVER_NAME="0.0.0.0"
22
+
23
+ CMD ["python", "app.py"]
app.py CHANGED
@@ -1,172 +1,186 @@
1
- """
2
- AIAGENT - Aapka Personal AI Agent
3
- smolagents + Gradio on Hugging Face Spaces
4
- """
5
-
6
  import gradio as gr
7
- from smolagents import CodeAgent, InferenceClientModel, tool, DuckDuckGoSearchTool
8
- import subprocess, os
9
- from datetime import datetime
10
-
11
- HF_TOKEN = os.environ.get("HF_TOKEN", None)
12
 
13
- @tool
14
- def execute_python(code: str) -> str:
15
- """Python code execute karo.
 
16
 
17
- Args:
18
- code: Python code to execute.
 
19
 
20
- Returns:
21
- Output string with results or error.
22
- """
23
- fname = f"/tmp/agent_{datetime.now().strftime('%Y%m%d_%H%M%S')}.py"
24
- with open(fname, "w") as f:
25
- f.write(code)
26
  try:
27
- r = subprocess.run(["python3", fname], capture_output=True, text=True, timeout=30)
28
- o = ""
29
- if r.stdout: o += f"OUTPUT:\n{r.stdout}\n"
30
- if r.stderr: o += f"ERRORS:\n{r.stderr}\n"
31
- return o if o else "Done (no output)"
32
  except Exception as e:
33
- return f"Error: {str(e)}"
34
- finally:
35
- if os.path.exists(fname): os.remove(fname)
36
-
37
- @tool
38
- def create_file(filename: str, content: str) -> str:
39
- """Create a file with content.
40
-
41
- Args:
42
- filename: File path like hello.py.
43
- content: Content to write.
44
-
45
- Returns:
46
- Success message.
47
- """
48
- os.makedirs(os.path.dirname(os.path.abspath(filename)) or ".", exist_ok=True)
49
- with open(filename, "w") as f:
50
- f.write(content)
51
- return f"Created: {filename} ({len(content)}b)"
52
-
53
- @tool
54
- def read_file(filename: str) -> str:
55
- """Read content of a file.
56
-
57
- Args:
58
- filename: File path to read.
59
-
60
- Returns:
61
- File content or error.
62
- """
63
- if not os.path.exists(filename):
64
- return f"Not found: {filename}"
65
- with open(filename, "r") as f:
66
- return f.read()
67
-
68
- @tool
69
- def run_shell(command: str) -> str:
70
- """Run a Linux shell command.
71
-
72
- Args:
73
- command: Shell command to execute.
74
-
75
- Returns:
76
- Command output.
77
- """
78
- r = subprocess.run(command, shell=True, capture_output=True, text=True, timeout=30)
79
- o = ""
80
- if r.stdout: o += r.stdout
81
- if r.stderr: o += f"\n[stderr] {r.stderr}"
82
- return o if o else "Done"
83
-
84
- @tool
85
- def install_package(pkg: str) -> str:
86
- """Install a Python package with pip.
87
 
88
- Args:
89
- pkg: Package name like requests.
90
-
91
- Returns:
92
- Installation output.
93
- """
94
- r = subprocess.run(["pip3", "install", pkg], capture_output=True, text=True, timeout=60)
95
- return (r.stdout + "\n" + r.stderr).strip() or "Installed"
96
-
97
- @tool
98
- def list_files(path: str = ".") -> str:
99
- """List files in a directory.
100
-
101
- Args:
102
- path: Directory path, default is current.
103
-
104
- Returns:
105
- File listing as string.
106
- """
107
  try:
108
- files = os.listdir(path)
109
- if not files: return "(empty)"
110
- result = []
111
- for f in sorted(files):
112
- full = os.path.join(path, f)
113
- if os.path.isfile(full):
114
- result.append(f" {f} ({os.path.getsize(full):,}b)")
115
- else:
116
- result.append(f"/ {f}/")
117
- return "\n".join(result)
118
  except Exception as e:
119
- return f"Error: {str(e)}"
120
 
121
- # Agent setup
122
- model = InferenceClientModel(
123
- model_id="Qwen/Qwen2.5-72B-Instruct",
124
- token=HF_TOKEN
125
- )
 
 
 
 
 
126
 
127
- tools = [
128
- DuckDuckGoSearchTool(), execute_python, create_file,
129
- read_file, run_shell, install_package, list_files,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  ]
131
 
132
- agent = CodeAgent(
133
- tools=tools, model=model, max_steps=15,
134
- additional_authorized_imports=[
135
- "requests","json","os","datetime","math","random","re",
136
- ]
137
- )
138
-
139
- def chat_fn(msg, history):
140
- if not msg.strip():
141
- return "", history
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
  try:
143
- result = agent.run(f"User: {msg}")
144
- history.append((msg, str(result)))
145
- return "", history
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
  except Exception as e:
147
- import traceback
148
- history.append((msg, f"Error: {str(e)}\n{traceback.format_exc()}"))
149
- return "", history
150
 
151
- def clear_fn():
152
- return [], ""
 
153
 
154
- with gr.Blocks(theme=gr.themes.Soft()) as demo:
155
- gr.HTML("""
156
- <div style="text-align:center;margin-bottom:10px">
157
- <h1 style="background:linear-gradient(135deg,#667eea,#764ba2);-webkit-background-clip:text;-webkit-text-fill-color:transparent;font-size:2em">AIAGENT</h1>
158
- <p style="color:#666">Python Code | Web Search | Files | Shell</p>
159
- </div>
160
- """)
161
- chatbot = gr.Chatbot(height=450, bubble_full_width=False, avatar_images=(None, "AI"))
162
- with gr.Row():
163
- msg = gr.Textbox(label="", placeholder="Kuch bhi likho...", scale=4, container=False)
164
- btn = gr.Button("Send", variant="primary", scale=1)
165
- with gr.Row():
166
- clr = gr.Button("Clear", variant="secondary", size="sm")
167
- msg.submit(chat_fn, [msg, chatbot], [msg, chatbot])
168
- btn.click(chat_fn, [msg, chatbot], [msg, chatbot])
169
- clr.click(clear_fn, None, [chatbot, msg])
170
 
171
  if __name__ == "__main__":
172
- demo.launch(server_name="0.0.0.0", server_port=7860)
 
1
+ import os
2
+ import json
3
+ import io
4
+ import sys
5
+ import requests
6
  import gradio as gr
7
+ from duckduckgo_search import DDGS
8
+ from bs4 import BeautifulSoup
 
 
 
9
 
10
+ # Hugging Face Token Space Settings -> Secrets mein 'HF_TOKEN' naam se save karein
11
+ HF_TOKEN = os.environ.get("HF_TOKEN")
12
+ API_URL = "https://api-inference.huggingface.co/models/Qwen/Qwen2.5-72B-Instruct/v1/chat/completions"
13
+ HEADERS = {"Authorization": f"Bearer {HF_TOKEN}"}
14
 
15
+ # ==========================================
16
+ # 1. CORE TOOLS DEFINITIONS (LobeHub style)
17
+ # ==========================================
18
 
19
+ def web_search(query: str) -> str:
20
+ """Internet par live search karne ke liye."""
 
 
 
 
21
  try:
22
+ with DDGS() as ddgs:
23
+ results = list(ddgs.text(query, max_results=3))
24
+ return json.dumps([{"title": r['title'], "snippet": r['body'], "link": r['href']} for r in results])
 
 
25
  except Exception as e:
26
+ return f"Search failed: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
+ def read_webpage(url: str) -> str:
29
+ """Kisi bhi URL ka text content padhne ke liye."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  try:
31
+ resp = requests.get(url, timeout=10, headers={"User-Agent": "Mozilla/5.0"})
32
+ soup = BeautifulSoup(resp.text, 'html.parser')
33
+ text = ' '.join(soup.stripped_strings)[:3000] # Token limit ke liye truncate
34
+ return text
 
 
 
 
 
 
35
  except Exception as e:
36
+ return f"Could not read webpage: {str(e)}"
37
 
38
+ def calculator(expression: str) -> str:
39
+ """Complex maths calculations solve karne ke liye."""
40
+ try:
41
+ # Sanitize input for basic security
42
+ allowed_chars = "0123456789+-*/(). "
43
+ if all(c in allowed_chars for c in expression):
44
+ return str(eval(expression, {"__builtins__": {}}, {}))
45
+ return "Error: Invalid characters in math expression."
46
+ except Exception as e:
47
+ return f"Math error: {str(e)}"
48
 
49
+ def python_interpreter(code: str) -> str:
50
+ """Python code run karke logic execute karne ke liye (Sandbox)."""
51
+ old_stdout = sys.stdout
52
+ redirected_output = sys.stdout = io.StringIO()
53
+ try:
54
+ # Docker container ke andar safe execution environment
55
+ exec(code, {"__builtins__": __builtins__}, {})
56
+ sys.stdout = old_stdout
57
+ return redirected_output.getvalue() or "Code executed successfully with no output."
58
+ except Exception as e:
59
+ sys.stdout = old_stdout
60
+ return f"Execution Error: {str(e)}"
61
+
62
+ # ==========================================
63
+ # 2. LLM TOOL SCHEMA (JSON Format)
64
+ # ==========================================
65
+
66
+ TOOLS = [
67
+ {
68
+ "type": "function",
69
+ "function": {
70
+ "name": "web_search",
71
+ "description": "Use this tool to search the internet for current events, news, or general info.",
72
+ "parameters": {
73
+ "type": "object",
74
+ "properties": {"query": {"type": "string", "description": "The search query"}},
75
+ "required": ["query"]
76
+ }
77
+ }
78
+ },
79
+ {
80
+ "type": "function",
81
+ "function": {
82
+ "name": "read_webpage",
83
+ "description": "Extract raw text content from a given website URL.",
84
+ "parameters": {
85
+ "type": "object",
86
+ "properties": {"url": {"type": "string", "description": "The full web URL"}},
87
+ "required": ["url"]
88
+ }
89
+ }
90
+ },
91
+ {
92
+ "type": "function",
93
+ "function": {
94
+ "name": "calculator",
95
+ "description": "Evaluate mathematical expressions. Input should only contain numbers and basic operators.",
96
+ "parameters": {
97
+ "type": "object",
98
+ "properties": {"expression": {"type": "string", "description": "The math expression, e.g. (55 * 4) + 12"}},
99
+ "required": ["expression"]
100
+ }
101
+ }
102
+ },
103
+ {
104
+ "type": "function",
105
+ "function": {
106
+ "name": "python_interpreter",
107
+ "description": "Execute Python code to solve complex logical problems, data manipulation, or algorithms.",
108
+ "parameters": {
109
+ "type": "object",
110
+ "properties": {"code": {"type": "string", "description": "Clean Python code block"}},
111
+ "required": ["code"]
112
+ }
113
+ }
114
+ }
115
  ]
116
 
117
+ def execute_tool(name, args):
118
+ if name == "web_search": return web_search(args.get("query"))
119
+ if name == "read_webpage": return read_webpage(args.get("url"))
120
+ if name == "calculator": return calculator(args.get("expression"))
121
+ if name == "python_interpreter": return python_interpreter(args.get("code"))
122
+ return "Unknown tool"
123
+
124
+ # ==========================================
125
+ # 3. AGENT CORE LOOP
126
+ # ==========================================
127
+
128
+ def run_agent(message, history):
129
+ # Chat history formatting
130
+ messages = [{"role": "system", "content": "You are a helpful AI Agent equipped with advanced tools. Use them whenever necessary to give accurate answers."}]
131
+ for user, bot in history:
132
+ messages.append({"role": "user", "content": user})
133
+ if bot: messages.append({"role": "assistant", "content": bot})
134
+ messages.append({"role": "user", "content": message})
135
+
136
+ payload = {
137
+ "model": "Qwen/Qwen2.5-72B-Instruct",
138
+ "messages": messages,
139
+ "tools": TOOLS,
140
+ "tool_choice": "auto"
141
+ }
142
+
143
  try:
144
+ response = requests.post(API_URL, headers=HEADERS, json=payload).json()
145
+ choice = response["choices"][0]["message"]
146
+
147
+ # Check if LLM wants to use a tool
148
+ if choice.get("tool_calls"):
149
+ tool_call = choice["tool_calls"][0]
150
+ func_name = tool_call["function"]["name"]
151
+ func_args = json.loads(tool_call["function"]["arguments"])
152
+
153
+ # Execute selected tool
154
+ tool_output = execute_tool(func_name, func_args)
155
+
156
+ # Feed tool result back to LLM
157
+ messages.append(choice)
158
+ messages.append({
159
+ "role": "tool",
160
+ "name": func_name,
161
+ "content": tool_output,
162
+ "tool_call_id": tool_call.get("id", "call_1")
163
+ })
164
+
165
+ # Final LLM call to generate user response
166
+ final_payload = {"model": "Qwen/Qwen2.5-72B-Instruct", "messages": messages}
167
+ final_response = requests.post(API_URL, headers=HEADERS, json=final_payload).json()
168
+ return final_response["choices"][0]["message"]["content"]
169
+
170
+ return choice["content"]
171
  except Exception as e:
172
+ return f"API Error: Kripya check karein ki HF_TOKEN correctly set hai ya nahi. Details: {str(e)}"
 
 
173
 
174
+ # ==========================================
175
+ # 4. GRADIO INTERFACE
176
+ # ==========================================
177
 
178
+ demo = gr.ChatInterface(
179
+ fn=run_agent,
180
+ title="📦 LobeHub-Style Docker Agent",
181
+ description="Docker container backend ke sath chalne wala Agent: Search, Browser, Math aur Python Interpreter sab free!",
182
+ theme="soft"
183
+ )
 
 
 
 
 
 
 
 
 
 
184
 
185
  if __name__ == "__main__":
186
+ demo.launch()
requirements.txt CHANGED
@@ -1,4 +1,4 @@
1
- gradio>=5.0.0
2
- smolagents>=1.0.0
3
- huggingface-hub>=0.20.0
4
- requests>=2.31.0
 
1
+ gradio
2
+ requests
3
+ beautifulsoup4
4
+ duckduckgo-search