Shami96 commited on
Commit
b8f3d48
Β·
verified Β·
1 Parent(s): 266f6ca

Upload server.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. server.py +243 -0
server.py ADDED
@@ -0,0 +1,243 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Shami's Deep Agent β€” FastAPI server for HuggingFace Spaces.
3
+
4
+ Exposes a simple chat API that wraps Deep Agents with Groq backend.
5
+ Accessible from anywhere via the HF Spaces URL.
6
+ """
7
+
8
+ import os
9
+ import json
10
+ import asyncio
11
+ from datetime import datetime
12
+ from pathlib import Path
13
+ from contextlib import asynccontextmanager
14
+
15
+ from fastapi import FastAPI, HTTPException
16
+ from fastapi.responses import HTMLResponse, StreamingResponse
17
+ from pydantic import BaseModel
18
+
19
+ # ── Agent setup ──────────────────────────────────────────────────────────────
20
+
21
+ AGENT = None
22
+ CONVERSATIONS: dict[str, list[dict]] = {}
23
+
24
+
25
+ def create_agent():
26
+ """Create the Deep Agent with Groq backend."""
27
+ try:
28
+ from deepagents import create_deep_agent
29
+
30
+ agents_md = Path("AGENTS.md").read_text()
31
+
32
+ agent = create_deep_agent(
33
+ model="groq:llama-3.3-70b-versatile",
34
+ system_prompt=agents_md,
35
+ )
36
+ return agent
37
+ except Exception as e:
38
+ print(f"[WARN] Could not create Deep Agent: {e}")
39
+ print("[INFO] Falling back to direct Groq API mode")
40
+ return None
41
+
42
+
43
+ def get_groq_client():
44
+ """Direct Groq client as fallback when Deep Agents SDK isn't compatible."""
45
+ try:
46
+ from groq import Groq
47
+ return Groq(api_key=os.environ.get("GROQ_API_KEY"))
48
+ except ImportError:
49
+ return None
50
+
51
+
52
+ async def chat_with_groq(message: str, conversation_id: str) -> str:
53
+ """Simple Groq chat as fallback."""
54
+ client = get_groq_client()
55
+ if not client:
56
+ return "Error: Groq client not available. Check GROQ_API_KEY."
57
+
58
+ # Load AGENTS.md as system prompt
59
+ system_prompt = Path("AGENTS.md").read_text() if Path("AGENTS.md").exists() else "You are a helpful assistant."
60
+ # Strip YAML frontmatter
61
+ if system_prompt.startswith("---"):
62
+ end = system_prompt.find("---", 3)
63
+ if end != -1:
64
+ system_prompt = system_prompt[end + 3:].strip()
65
+
66
+ if conversation_id not in CONVERSATIONS:
67
+ CONVERSATIONS[conversation_id] = []
68
+
69
+ history = CONVERSATIONS[conversation_id]
70
+ messages = [{"role": "system", "content": system_prompt}] + history + [{"role": "user", "content": message}]
71
+
72
+ try:
73
+ response = client.chat.completions.create(
74
+ model="llama-3.3-70b-versatile",
75
+ messages=messages,
76
+ max_tokens=4096,
77
+ temperature=0.7,
78
+ )
79
+ reply = response.choices[0].message.content or ""
80
+ history.append({"role": "user", "content": message})
81
+ history.append({"role": "assistant", "content": reply})
82
+ # Keep history manageable
83
+ if len(history) > 40:
84
+ CONVERSATIONS[conversation_id] = history[-20:]
85
+ return reply
86
+ except Exception as e:
87
+ return f"Error: {e}"
88
+
89
+
90
+ # ── FastAPI app ──────────────────────────────────────────────────────────────
91
+
92
+ @asynccontextmanager
93
+ async def lifespan(app: FastAPI):
94
+ global AGENT
95
+ print(f"[{datetime.now().isoformat()}] Starting Shami's Deep Agent...")
96
+ print(f" GROQ_API_KEY: {'SET' if os.environ.get('GROQ_API_KEY') else 'MISSING'}")
97
+ AGENT = create_agent()
98
+ if AGENT:
99
+ print(" Mode: Deep Agents SDK")
100
+ else:
101
+ print(" Mode: Direct Groq API (fallback)")
102
+ yield
103
+ print("Shutting down...")
104
+
105
+
106
+ app = FastAPI(
107
+ title="Shami's Deep Agent",
108
+ description="Personal AI agent powered by Groq + Deep Agents",
109
+ lifespan=lifespan,
110
+ )
111
+
112
+
113
+ class ChatRequest(BaseModel):
114
+ message: str
115
+ conversation_id: str = "default"
116
+
117
+
118
+ class ChatResponse(BaseModel):
119
+ reply: str
120
+ conversation_id: str
121
+ model: str = "groq/llama-3.3-70b-versatile"
122
+ timestamp: str
123
+
124
+
125
+ @app.get("/", response_class=HTMLResponse)
126
+ async def home():
127
+ return """
128
+ <!DOCTYPE html>
129
+ <html>
130
+ <head>
131
+ <title>Shami's Deep Agent</title>
132
+ <meta name="viewport" content="width=device-width, initial-scale=1">
133
+ <style>
134
+ * { margin: 0; padding: 0; box-sizing: border-box; }
135
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: #0a0a0a; color: #e0e0e0; height: 100vh; display: flex; flex-direction: column; }
136
+ .header { padding: 16px 24px; border-bottom: 1px solid #222; background: #111; }
137
+ .header h1 { font-size: 18px; color: #fff; }
138
+ .header p { font-size: 12px; color: #666; margin-top: 4px; }
139
+ .chat { flex: 1; overflow-y: auto; padding: 24px; display: flex; flex-direction: column; gap: 16px; }
140
+ .msg { max-width: 80%; padding: 12px 16px; border-radius: 12px; line-height: 1.5; font-size: 14px; white-space: pre-wrap; }
141
+ .msg.user { align-self: flex-end; background: #1a3a5c; color: #e0e0e0; }
142
+ .msg.assistant { align-self: flex-start; background: #1a1a1a; border: 1px solid #333; }
143
+ .msg.assistant pre { background: #0d0d0d; padding: 8px; border-radius: 6px; overflow-x: auto; margin: 8px 0; }
144
+ .msg.assistant code { font-family: 'SF Mono', monospace; font-size: 13px; }
145
+ .input-area { padding: 16px 24px; border-top: 1px solid #222; background: #111; display: flex; gap: 12px; }
146
+ .input-area input { flex: 1; padding: 12px 16px; background: #1a1a1a; border: 1px solid #333; border-radius: 8px; color: #e0e0e0; font-size: 14px; outline: none; }
147
+ .input-area input:focus { border-color: #4a9eff; }
148
+ .input-area button { padding: 12px 24px; background: #4a9eff; color: #fff; border: none; border-radius: 8px; font-size: 14px; cursor: pointer; }
149
+ .input-area button:hover { background: #3a8eef; }
150
+ .input-area button:disabled { background: #333; cursor: not-allowed; }
151
+ .typing { color: #666; font-style: italic; }
152
+ </style>
153
+ </head>
154
+ <body>
155
+ <div class="header">
156
+ <h1>Shami's Deep Agent</h1>
157
+ <p>Groq / llama-3.3-70b-versatile &middot; Research &middot; Coding &middot; Planning</p>
158
+ </div>
159
+ <div class="chat" id="chat">
160
+ <div class="msg assistant">Hey! I'm Shami's personal AI agent. Ask me anything β€” coding, research, planning, writing. Powered by Groq for fast responses.</div>
161
+ </div>
162
+ <div class="input-area">
163
+ <input type="text" id="input" placeholder="Ask anything..." autofocus />
164
+ <button id="send" onclick="sendMessage()">Send</button>
165
+ </div>
166
+ <script>
167
+ const chat = document.getElementById('chat');
168
+ const input = document.getElementById('input');
169
+ const sendBtn = document.getElementById('send');
170
+ const convId = 'web-' + Date.now();
171
+
172
+ input.addEventListener('keydown', (e) => { if (e.key === 'Enter' && !sendBtn.disabled) sendMessage(); });
173
+
174
+ async function sendMessage() {
175
+ const msg = input.value.trim();
176
+ if (!msg) return;
177
+ input.value = '';
178
+ sendBtn.disabled = true;
179
+
180
+ chat.innerHTML += `<div class="msg user">${escapeHtml(msg)}</div>`;
181
+ chat.innerHTML += `<div class="msg assistant typing" id="typing">Thinking...</div>`;
182
+ chat.scrollTop = chat.scrollHeight;
183
+
184
+ try {
185
+ const res = await fetch('/chat', {
186
+ method: 'POST',
187
+ headers: { 'Content-Type': 'application/json' },
188
+ body: JSON.stringify({ message: msg, conversation_id: convId })
189
+ });
190
+ const data = await res.json();
191
+ document.getElementById('typing')?.remove();
192
+ chat.innerHTML += `<div class="msg assistant">${formatMarkdown(data.reply)}</div>`;
193
+ } catch (e) {
194
+ document.getElementById('typing')?.remove();
195
+ chat.innerHTML += `<div class="msg assistant">Error: ${e.message}</div>`;
196
+ }
197
+ chat.scrollTop = chat.scrollHeight;
198
+ sendBtn.disabled = false;
199
+ input.focus();
200
+ }
201
+
202
+ function escapeHtml(s) { return s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;'); }
203
+ function formatMarkdown(s) {
204
+ return escapeHtml(s)
205
+ .replace(/```(\\w+)?\\n([\\s\\S]*?)```/g, '<pre><code>$2</code></pre>')
206
+ .replace(/`([^`]+)`/g, '<code>$1</code>')
207
+ .replace(/\\*\\*([^*]+)\\*\\*/g, '<strong>$1</strong>')
208
+ .replace(/\\n/g, '<br>');
209
+ }
210
+ </script>
211
+ </body>
212
+ </html>
213
+ """
214
+
215
+
216
+ @app.post("/chat", response_model=ChatResponse)
217
+ async def chat_endpoint(req: ChatRequest):
218
+ reply = await chat_with_groq(req.message, req.conversation_id)
219
+ return ChatResponse(
220
+ reply=reply,
221
+ conversation_id=req.conversation_id,
222
+ timestamp=datetime.now().isoformat(),
223
+ )
224
+
225
+
226
+ @app.get("/health")
227
+ async def health():
228
+ return {
229
+ "status": "ok",
230
+ "mode": "deep_agents" if AGENT else "groq_direct",
231
+ "model": "groq/llama-3.3-70b-versatile",
232
+ "timestamp": datetime.now().isoformat(),
233
+ }
234
+
235
+
236
+ @app.get("/api/models")
237
+ async def list_models():
238
+ return {"models": ["groq/llama-3.3-70b-versatile"]}
239
+
240
+
241
+ if __name__ == "__main__":
242
+ import uvicorn
243
+ uvicorn.run(app, host="0.0.0.0", port=7860)