sheikhcoders commited on
Commit
c49574c
·
verified ·
1 Parent(s): 8631163

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +428 -10
app.py CHANGED
@@ -1,25 +1,443 @@
1
- from fastapi import FastAPI
 
 
2
  from datetime import datetime
 
 
 
3
 
4
- app = FastAPI()
5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  @app.get("/")
7
  async def root():
8
- return {"message": "AI Agent Space", "status": "running", "timestamp": datetime.now().isoformat()}
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
  @app.get("/health")
11
  async def health():
12
- return {"status": "healthy"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
- @app.get("/agentic")
15
- async def agentic():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  return {
17
- "reasoning_details": "Interleaved thinking enabled",
18
- "content": "Agentic model ready",
19
- "tool_calls": [],
20
- "status": "success"
21
  }
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  if __name__ == "__main__":
24
  import uvicorn
25
  uvicorn.run(app, host="0.0.0.0", port=7860)
 
1
+ from fastapi import FastAPI, HTTPException
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from pydantic import BaseModel
4
  from datetime import datetime
5
+ from typing import List, Dict, Any, Optional
6
+ import json
7
+ import re
8
 
9
+ app = FastAPI(title="AI Agent with Anthropic/OpenAI SDK Support", version="2.0.0")
10
 
11
+ # Enable CORS
12
+ app.add_middleware(
13
+ CORSMiddleware,
14
+ allow_origins=["*"],
15
+ allow_credentials=True,
16
+ allow_methods=["*"],
17
+ allow_headers=["*"],
18
+ )
19
+
20
+ # Data Models for SDK Compatibility
21
+ class ToolDefinition(BaseModel):
22
+ name: str
23
+ description: str
24
+ parameters: Dict[str, Any]
25
+
26
+ class AnthropicRequest(BaseModel):
27
+ messages: List[Dict[str, Any]]
28
+ tools: Optional[List[ToolDefinition]] = None
29
+ model: Optional[str] = "claude-3-sonnet-20240229"
30
+ max_tokens: Optional[int] = 1024
31
+ temperature: Optional[float] = 0.7
32
+ reasoning_split: Optional[bool] = False
33
+
34
+ class OpenAIRequest(BaseModel):
35
+ messages: List[Dict[str, Any]]
36
+ tools: Optional[List[ToolDefinition]] = None
37
+ model: Optional[str] = "gpt-4"
38
+ max_tokens: Optional[int] = 1024
39
+ temperature: Optional[float] = 0.7
40
+ reasoning_split: Optional[bool] = False
41
+
42
+ class AgenticRequest(BaseModel):
43
+ task: str
44
+ context: Optional[str] = ""
45
+ conversation_history: Optional[List[Dict[str, Any]]] = []
46
+ tools: Optional[List[ToolDefinition]] = None
47
+ reasoning_split: Optional[bool] = False
48
+
49
+ # Available Tools
50
+ AVAILABLE_TOOLS = {
51
+ "search_web": {
52
+ "name": "search_web",
53
+ "description": "Search the web for information based on a query",
54
+ "parameters": {
55
+ "type": "object",
56
+ "properties": {
57
+ "query": {"type": "string", "description": "Search query to look up information"}
58
+ },
59
+ "required": ["query"]
60
+ }
61
+ },
62
+ "analyze_code": {
63
+ "name": "analyze_code",
64
+ "description": "Analyze code for understanding, structure, and suggestions",
65
+ "parameters": {
66
+ "type": "object",
67
+ "properties": {
68
+ "code": {"type": "string", "description": "Code to analyze"},
69
+ "task": {"type": "string", "description": "Analysis task (comprehensive_analysis, optimization, debugging)"}
70
+ },
71
+ "required": ["code"]
72
+ }
73
+ },
74
+ "get_weather": {
75
+ "name": "get_weather",
76
+ "description": "Get current weather information for a location",
77
+ "parameters": {
78
+ "type": "object",
79
+ "properties": {
80
+ "location": {"type": "string", "description": "Location to get weather for"},
81
+ "units": {"type": "string", "enum": ["celsius", "fahrenheit"], "default": "celsius"}
82
+ },
83
+ "required": ["location"]
84
+ }
85
+ },
86
+ "math_calc": {
87
+ "name": "math_calc",
88
+ "description": "Perform mathematical calculations",
89
+ "parameters": {
90
+ "type": "object",
91
+ "properties": {
92
+ "expression": {"type": "string", "description": "Mathematical expression to calculate"},
93
+ "precision": {"type": "integer", "default": 6, "description": "Number of decimal places"}
94
+ },
95
+ "required": ["expression"]
96
+ }
97
+ },
98
+ "text_analyzer": {
99
+ "name": "text_analyzer",
100
+ "description": "Analyze text for sentiment, keywords, and insights",
101
+ "parameters": {
102
+ "type": "object",
103
+ "properties": {
104
+ "text": {"type": "string", "description": "Text to analyze"},
105
+ "analysis_type": {"type": "string", "enum": ["sentiment", "keywords", "summary"], "default": "sentiment"}
106
+ },
107
+ "required": ["text"]
108
+ }
109
+ }
110
+ }
111
+
112
+ def determine_tools_needed(task: str) -> List[Dict[str, Any]]:
113
+ """Determine which tools are needed based on task analysis"""
114
+ task_lower = task.lower()
115
+ selected_tools = []
116
+
117
+ # Search tools
118
+ if any(keyword in task_lower for keyword in ["search", "find", "look up", "research", "information"]):
119
+ selected_tools.append(AVAILABLE_TOOLS["search_web"])
120
+
121
+ # Code analysis tools
122
+ if any(keyword in task_lower for keyword in ["code", "function", "program", "debug", "optimize"]):
123
+ selected_tools.append(AVAILABLE_TOOLS["analyze_code"])
124
+
125
+ # Weather tools
126
+ if any(keyword in task_lower for keyword in ["weather", "temperature", "climate"]):
127
+ selected_tools.append(AVAILABLE_TOOLS["get_weather"])
128
+
129
+ # Math tools
130
+ if any(keyword in task_lower for keyword in ["calculate", "math", "+", "-", "*", "/", "="]) or re.search(r'\d+\s*[+\-*/=]\s*\d+', task_lower):
131
+ selected_tools.append(AVAILABLE_TOOLS["math_calc"])
132
+
133
+ # Text analysis tools
134
+ if any(keyword in task_lower for keyword in ["analyze", "sentiment", "summary", "text"]):
135
+ selected_tools.append(AVAILABLE_TOOLS["text_analyzer"])
136
+
137
+ return selected_tools
138
+
139
+ def generate_tool_calls(task: str, context: str = "") -> List[Dict[str, Any]]:
140
+ """Generate appropriate tool calls based on task"""
141
+ tool_calls = []
142
+ current_time = datetime.now().strftime('%Y%m%d_%H%M%S')
143
+
144
+ if "search" in task.lower() or "find" in task.lower():
145
+ query = task.replace("search for", "").replace("find", "").replace("look up", "").strip()
146
+ tool_calls.append({
147
+ "id": f"search_{current_time}",
148
+ "function": {
149
+ "name": "search_web",
150
+ "arguments": json.dumps({"query": query or task})
151
+ }
152
+ })
153
+
154
+ elif "code" in task.lower():
155
+ tool_calls.append({
156
+ "id": f"code_analysis_{current_time}",
157
+ "function": {
158
+ "name": "analyze_code",
159
+ "arguments": json.dumps({
160
+ "code": context or "Sample code for analysis",
161
+ "task": "comprehensive_analysis"
162
+ })
163
+ }
164
+ })
165
+
166
+ elif "weather" in task.lower():
167
+ location = context or "current location"
168
+ tool_calls.append({
169
+ "id": f"weather_{current_time}",
170
+ "function": {
171
+ "name": "get_weather",
172
+ "arguments": json.dumps({"location": location})
173
+ }
174
+ })
175
+
176
+ elif any(char.isdigit() for char in task) and any(op in task for op in ["+", "-", "*", "/"]):
177
+ tool_calls.append({
178
+ "id": f"math_{current_time}",
179
+ "function": {
180
+ "name": "math_calc",
181
+ "arguments": json.dumps({"expression": task})
182
+ }
183
+ })
184
+
185
+ elif "analyze" in task.lower():
186
+ tool_calls.append({
187
+ "id": f"text_analysis_{current_time}",
188
+ "function": {
189
+ "name": "text_analyzer",
190
+ "arguments": json.dumps({
191
+ "text": context or task,
192
+ "analysis_type": "sentiment"
193
+ })
194
+ }
195
+ })
196
+
197
+ return tool_calls
198
+
199
+ def create_anthropic_response(task: str, reasoning_split: bool = False) -> Dict[str, Any]:
200
+ """Create Anthropic SDK compatible response"""
201
+ tool_calls = generate_tool_calls(task)
202
+ reasoning = f"Analyzing task: '{task}'. I need to determine the best approach. "
203
+
204
+ if tool_calls:
205
+ reasoning += f"I will use the {tool_calls[0]['function']['name']} tool to help with this task."
206
+ else:
207
+ reasoning += "This appears to be a general reasoning task that doesn't require specific tools."
208
+
209
+ content_blocks = []
210
+
211
+ if reasoning_split:
212
+ content_blocks.append({
213
+ "type": "thinking",
214
+ "text": reasoning
215
+ })
216
+
217
+ if tool_calls:
218
+ content_blocks.append({
219
+ "type": "tool_use",
220
+ "id": tool_calls[0]["id"],
221
+ "name": tool_calls[0]["function"]["name"],
222
+ "input": json.loads(tool_calls[0]["function"]["arguments"])
223
+ })
224
+
225
+ content_blocks.append({
226
+ "type": "text",
227
+ "text": f"I've analyzed your task: '{task}'. I'm ready to proceed with the best approach."
228
+ })
229
+
230
+ return {
231
+ "id": f"msg_{datetime.now().strftime('%Y%m%d_%H%M%S')}",
232
+ "type": "message",
233
+ "role": "assistant",
234
+ "content": content_blocks,
235
+ "model": "claude-3-sonnet-20240229",
236
+ "stop_reason": "tool_use" if tool_calls else "end_turn"
237
+ }
238
+
239
+ def create_openai_response(task: str, reasoning_split: bool = False) -> Dict[str, Any]:
240
+ """Create OpenAI SDK compatible response"""
241
+ tool_calls = generate_tool_calls(task)
242
+
243
+ reasoning = f"I'm analyzing the task: '{task}'. "
244
+ if tool_calls:
245
+ reasoning += f"I need to use the {tool_calls[0]['function']['name']} tool to help complete this."
246
+ else:
247
+ reasoning += "This is a reasoning task that requires my cognitive abilities."
248
+
249
+ return {
250
+ "id": f"chatcmpl-{datetime.now().strftime('%Y%m%d_%H%M%S')}",
251
+ "object": "chat.completion",
252
+ "created": int(datetime.now().timestamp()),
253
+ "model": "gpt-4",
254
+ "choices": [
255
+ {
256
+ "index": 0,
257
+ "message": {
258
+ "role": "assistant",
259
+ "content": f"Working on your task: '{task}'. Let me proceed with the analysis." if not reasoning_split else None,
260
+ "function_call": None,
261
+ "tool_calls": tool_calls if tool_calls else None
262
+ },
263
+ "finish_reason": "tool_calls" if tool_calls else "stop"
264
+ }
265
+ ],
266
+ "usage": {
267
+ "prompt_tokens": 10,
268
+ "completion_tokens": 50,
269
+ "total_tokens": 60
270
+ },
271
+ "reasoning_details": reasoning if reasoning_split else None
272
+ }
273
+
274
+ # API Endpoints
275
  @app.get("/")
276
  async def root():
277
+ return {
278
+ "message": "AI Agent with Anthropic/OpenAI SDK Support",
279
+ "version": "2.0.0",
280
+ "status": "running",
281
+ "timestamp": datetime.now().isoformat(),
282
+ "endpoints": [
283
+ "/",
284
+ "/health",
285
+ "/agentic",
286
+ "/anthropic/compatible",
287
+ "/openai/compatible"
288
+ ]
289
+ }
290
 
291
  @app.get("/health")
292
  async def health():
293
+ return {"status": "healthy", "timestamp": datetime.now().isoformat()}
294
+
295
+ @app.get("/models")
296
+ async def get_models():
297
+ return {
298
+ "models": [
299
+ {
300
+ "name": "anthropic-claude",
301
+ "status": "loaded",
302
+ "description": "Anthropic SDK compatible agentic model"
303
+ },
304
+ {
305
+ "name": "openai-gpt4",
306
+ "status": "loaded",
307
+ "description": "OpenAI SDK compatible agentic model"
308
+ }
309
+ ]
310
+ }
311
+
312
+ @app.post("/agentic")
313
+ async def agentic_endpoint(request: AgenticRequest):
314
+ """General agentic endpoint with interleaved thinking"""
315
+ tools = request.tools or list(AVAILABLE_TOOLS.values())
316
+ tool_calls = generate_tool_calls(request.task, request.context)
317
+
318
+ reasoning = f"I need to analyze the task: '{request.task}'. "
319
+ if tool_calls:
320
+ reasoning += f"This task requires using the {tool_calls[0]['function']['name']} tool. "
321
+
322
+ reasoning += "I'm reasoning through each step to determine the best approach for tool use."
323
+
324
+ return {
325
+ "reasoning_details": reasoning if request.reasoning_split else None,
326
+ "content": f"Working on your task: '{request.task}'. I have the tools I need to assist.",
327
+ "tool_calls": tool_calls,
328
+ "status": "success",
329
+ "thinking_process": "Interleaved thinking enabled - reasoning performed between tool interactions",
330
+ "tools_available": len(tools),
331
+ "conversation_length": len(request.conversation_history) if request.conversation_history else 0
332
+ }
333
 
334
+ @app.post("/anthropic/compatible")
335
+ async def anthropic_endpoint(request: AnthropicRequest):
336
+ """Anthropic SDK compatible endpoint with interleaved thinking"""
337
+ # Get the latest user message
338
+ latest_message = request.messages[-1] if request.messages else {"content": "Hello"}
339
+ user_content = latest_message.get("content", "")
340
+
341
+ if isinstance(user_content, list):
342
+ user_text = " ".join([item.get("text", "") for item in user_content if item.get("type") == "text"])
343
+ else:
344
+ user_text = str(user_content)
345
+
346
+ response = create_anthropic_response(user_text, request.reasoning_split)
347
+
348
+ # Add available tools if specified
349
+ if request.tools:
350
+ available_tools = [tool for tool in AVAILABLE_TOOLS.values() if tool["name"] in [t.name for t in request.tools]]
351
+ else:
352
+ available_tools = list(AVAILABLE_TOOLS.values())
353
+
354
  return {
355
+ **response,
356
+ "available_tools": available_tools,
357
+ "reasoning_split": request.reasoning_split
 
358
  }
359
 
360
+ @app.post("/openai/compatible")
361
+ async def openai_endpoint(request: OpenAIRequest):
362
+ """OpenAI SDK compatible endpoint with interleaved thinking"""
363
+ # Get the latest user message
364
+ latest_message = request.messages[-1] if request.messages else {"content": "Hello"}
365
+ user_content = latest_message.get("content", "")
366
+
367
+ if isinstance(user_content, list):
368
+ user_text = " ".join([item.get("text", "") for item in user_content if item.get("type") == "text"])
369
+ else:
370
+ user_text = str(user_content)
371
+
372
+ response = create_openai_response(user_text, request.reasoning_split)
373
+
374
+ # Add available tools if specified
375
+ if request.tools:
376
+ available_tools = [tool for tool in AVAILABLE_TOOLS.values() if tool["name"] in [t.name for t in request.tools]]
377
+ else:
378
+ available_tools = list(AVAILABLE_TOOLS.values())
379
+
380
+ return {
381
+ **response,
382
+ "available_tools": available_tools,
383
+ "reasoning_split": request.reasoning_split
384
+ }
385
+
386
+ @app.get("/tools")
387
+ async def list_tools():
388
+ """List all available tools"""
389
+ return {
390
+ "tools": list(AVAILABLE_TOOLS.values()),
391
+ "count": len(AVAILABLE_TOOLS)
392
+ }
393
+
394
+ @app.post("/tools/search")
395
+ async def simulate_tool_use(tool_name: str, arguments: Dict[str, Any]):
396
+ """Simulate tool use for demonstration"""
397
+ if tool_name not in AVAILABLE_TOOLS:
398
+ raise HTTPException(status_code=400, detail=f"Tool '{tool_name}' not found")
399
+
400
+ # Simulate tool responses
401
+ if tool_name == "search_web":
402
+ return {
403
+ "tool": tool_name,
404
+ "result": f"Search results for '{arguments.get('query', 'unknown')}': Found relevant information.",
405
+ "status": "success"
406
+ }
407
+ elif tool_name == "analyze_code":
408
+ return {
409
+ "tool": tool_name,
410
+ "result": "Code analysis complete: Found 2 functions, 1 class, good structure overall.",
411
+ "status": "success"
412
+ }
413
+ elif tool_name == "get_weather":
414
+ return {
415
+ "tool": tool_name,
416
+ "result": f"Weather for {arguments.get('location', 'unknown')}: 22°C, partly cloudy",
417
+ "status": "success"
418
+ }
419
+ elif tool_name == "math_calc":
420
+ try:
421
+ expression = arguments.get("expression", "0")
422
+ result = eval(expression)
423
+ return {
424
+ "tool": tool_name,
425
+ "result": f"Calculation result: {result}",
426
+ "status": "success"
427
+ }
428
+ except:
429
+ return {
430
+ "tool": tool_name,
431
+ "result": "Error: Invalid mathematical expression",
432
+ "status": "error"
433
+ }
434
+ elif tool_name == "text_analyzer":
435
+ return {
436
+ "tool": tool_name,
437
+ "result": "Text analysis complete: Positive sentiment, found 3 key topics",
438
+ "status": "success"
439
+ }
440
+
441
  if __name__ == "__main__":
442
  import uvicorn
443
  uvicorn.run(app, host="0.0.0.0", port=7860)