Rajhuggingface4253 commited on
Commit
f6b0635
Β·
verified Β·
1 Parent(s): 1e1ac6b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +145 -101
app.py CHANGED
@@ -1,47 +1,64 @@
1
- from fastapi import FastAPI, HTTPException
2
  from fastapi.responses import HTMLResponse, JSONResponse
3
  import httpx
4
  import asyncio
5
  import time
6
  from datetime import datetime
7
  from typing import Dict, List
8
- import os
9
-
10
- app = FastAPI(title="FastAPI Pinger", description="High-performance server warming service")
11
 
12
  # Configuration
13
  PING_INTERVAL = 300 # 5 minutes
14
  HEALTH_CHECK_INTERVAL = 1800 # 30 minutes
15
 
16
- # List of other pinger Spaces (add your Space URLs here)
17
  pinger_spaces = [
18
- "https://rajhuggingface4253-ping2.hf.space",
19
-
20
  ]
21
 
22
- # Your target servers to keep warm
23
- target_servers = [
24
- "https://rajhuggingface4253-qwen.hf.space",
25
- "https://rajhuggingface4253-qwen2.hf.space",
26
- "https://rajhuggingface4253-qwen3.hf.space",
27
  "https://rajhuggingface4253-backend-compressorpro.hf.space",
28
  "https://rajhuggingface4253-backend-compressorpro2.hf.space",
29
  "https://rajhuggingface4253-compressor3pro.hf.space",
30
  "https://rajhuggingface4253-koko.hf.space"
31
  ]
32
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  # Global state
34
  ping_results: Dict[str, Dict] = {}
 
35
  health_results: Dict[str, Dict] = {}
36
  last_ping_run: datetime = None
 
37
 
38
  async def ping_server(url: str) -> Dict:
39
- """Ping a single server asynchronously"""
40
  try:
41
  start_time = time.time()
42
  async with httpx.AsyncClient(timeout=10.0) as client:
43
- full_url = url if '://' in url else f'https://{url}'
44
- response = await client.get(full_url)
45
  response_time = round((time.time() - start_time) * 1000, 1)
46
 
47
  return {
@@ -57,27 +74,88 @@ async def ping_server(url: str) -> Dict:
57
  'timestamp': datetime.now().isoformat()
58
  }
59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  async def ping_all_servers():
61
- """Ping all target servers concurrently"""
62
  global ping_results, last_ping_run
63
 
64
- tasks = [ping_server(server) for server in target_servers]
 
 
 
65
  results = await asyncio.gather(*tasks)
66
 
67
- # Store results
68
- for i, server in enumerate(target_servers):
69
  ping_results[server] = results[i]
70
 
71
  last_ping_run = datetime.now()
72
 
73
- # Log results
74
  success_count = sum(1 for result in results if result['status'] == 'success')
75
- print(f"{datetime.now().strftime('%H:%M:%S')} - {success_count}/{len(target_servers)} servers OK")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
 
77
  return results
78
 
79
  async def ping_health_endpoints():
80
- """Ping other pinger Spaces concurrently"""
81
  global health_results
82
 
83
  async with httpx.AsyncClient(timeout=10.0) as client:
@@ -101,79 +179,72 @@ async def ping_single_health(client: httpx.AsyncClient, space_url: str, health_u
101
  'status_code': response.status_code,
102
  'last_ping': datetime.now().isoformat()
103
  }
104
- print(f"βœ… Health ping to {space_url}: {response_time}ms")
105
  except Exception as e:
106
  health_results[space_url] = {
107
  'status': 'error',
108
  'error': str(e),
109
  'last_ping': datetime.now().isoformat()
110
  }
111
- print(f"❌ Health ping failed for {space_url}: {e}")
112
 
113
  async def continuous_pinging():
114
- """Main pinging loop"""
115
- print("πŸš€ FastAPI Pinger Started!")
116
- print(f"πŸ“Š Monitoring {len(target_servers)} target servers")
117
- print(f"πŸ”— Connected to {len(pinger_spaces)} pinger spaces")
118
- print(f"⏰ Pinging every {PING_INTERVAL//60} minutes")
 
119
 
120
  last_health_check = 0
121
 
122
  while True:
123
  try:
124
- # Ping target servers
125
- await ping_all_servers()
 
 
 
 
 
126
 
127
- # Ping health endpoints every 30 minutes
128
  current_time = time.time()
129
- if current_time - last_health_check >= HEALTH_CHECK_INTERVAL:
130
- if pinger_spaces:
131
- print("πŸ”„ Pinging other pinger spaces...")
132
- await ping_health_endpoints()
133
  last_health_check = current_time
134
 
135
- # Wait for next cycle
136
  await asyncio.sleep(PING_INTERVAL)
137
 
138
  except Exception as e:
139
- print(f"❌ Error in pinging loop: {e}")
140
- await asyncio.sleep(60) # Wait 1 minute before retrying
141
 
142
- @app.on_event("startup")
143
- async def startup_event():
144
- """Start the pinging loop when the app starts"""
 
145
  asyncio.create_task(continuous_pinging())
 
 
 
 
 
146
 
147
  @app.get("/", response_class=HTMLResponse)
148
  async def home():
149
- """Main dashboard"""
150
- success_count = sum(1 for result in ping_results.values() if result.get('status') == 'success')
151
- health_success = sum(1 for result in health_results.values() if result.get('status') == 'success')
 
152
 
153
  html_content = f"""
154
  <html>
155
- <head>
156
- <title>FastAPI Pinger</title>
157
- <style>
158
- body {{ font-family: Arial, sans-serif; margin: 40px; }}
159
- .success {{ color: green; }}
160
- .error {{ color: red; }}
161
- .container {{ max-width: 800px; margin: 0 auto; }}
162
- </style>
163
- </head>
164
  <body>
165
- <div class="container">
166
- <h1>⚑ FastAPI Pinger</h1>
167
- <p><strong>Target Servers:</strong> {len(target_servers)}</p>
168
- <p><strong>Pinger Network:</strong> {len(pinger_spaces)}</p>
169
- <p><strong>Last Run:</strong> {last_ping_run.strftime('%Y-%m-%d %H:%M:%S') if last_ping_run else 'Not yet'}</p>
170
- <p><strong>Status:</strong> {success_count}/{len(target_servers)} servers OK β€’ {health_success}/{len(pinger_spaces)} pingers OK</p>
171
-
172
- <h3>Endpoints:</h3>
173
- <ul>
174
- <li><a href="error</a></li>
175
- </ul>
176
- </div>
177
  </body>
178
  </html>
179
  """
@@ -181,49 +252,22 @@ async def home():
181
 
182
  @app.get("/health")
183
  async def health():
184
- """Health endpoint for other pingers"""
185
  return JSONResponse({
186
  "status": "healthy",
187
- "service": "fastapi-pinger",
188
- "timestamp": datetime.now().isoformat(),
189
- "server_count": len(target_servers),
190
- "network_count": len(pinger_spaces),
191
- "last_ping": last_ping_run.isoformat() if last_ping_run else None
192
  })
193
 
194
- @app.get("/results")
195
- async def get_results():
196
- """Get current ping results"""
197
  return JSONResponse({
198
- "last_run": last_ping_run.isoformat() if last_ping_run else None,
199
- "target_servers": ping_results,
200
- "pinger_network": health_results,
201
  "timestamp": datetime.now().isoformat()
202
  })
203
 
204
- @app.get("/ping-now")
205
- async def ping_now():
206
- """Manually trigger a ping cycle"""
207
- results = await ping_all_servers()
208
- if pinger_spaces:
209
- await ping_health_endpoints()
210
-
211
- success_count = sum(1 for result in results if result['status'] == 'success')
212
- health_success = sum(1 for result in health_results.values() if result.get('status') == 'success')
213
-
214
- return JSONResponse({
215
- "message": "Manual ping completed",
216
- "servers_ok": f"{success_count}/{len(target_servers)}",
217
- "pingers_ok": f"{health_success}/{len(pinger_spaces)}",
218
- "timestamp": datetime.now().isoformat()
219
- })
220
-
221
- @app.get("/docs")
222
- async def get_docs():
223
- """Redirect to interactive docs"""
224
- from fastapi.responses import RedirectResponse
225
- return RedirectResponse(url="/docs")
226
-
227
  if __name__ == "__main__":
228
  import uvicorn
229
  uvicorn.run(app, host="0.0.0.0", port=7860)
 
1
+ from fastapi import FastAPI
2
  from fastapi.responses import HTMLResponse, JSONResponse
3
  import httpx
4
  import asyncio
5
  import time
6
  from datetime import datetime
7
  from typing import Dict, List
8
+ from contextlib import asynccontextmanager
 
 
9
 
10
  # Configuration
11
  PING_INTERVAL = 300 # 5 minutes
12
  HEALTH_CHECK_INTERVAL = 1800 # 30 minutes
13
 
14
+ # List of other pinger Spaces
15
  pinger_spaces = [
16
+ "https://rajhuggingface4253-ping.hf.space",
 
17
  ]
18
 
19
+ # Regular servers to ping
20
+ regular_servers = [
 
 
 
21
  "https://rajhuggingface4253-backend-compressorpro.hf.space",
22
  "https://rajhuggingface4253-backend-compressorpro2.hf.space",
23
  "https://rajhuggingface4253-compressor3pro.hf.space",
24
  "https://rajhuggingface4253-koko.hf.space"
25
  ]
26
 
27
+ # Chat models that need warmup messages
28
+ chat_models = [
29
+ {
30
+ "url": "https://rajhuggingface4253-qwen.hf.space",
31
+ "api_endpoint": "/chat", # Adjust based on your API
32
+ "warmup_message": "Say 'active' in one word?",
33
+ "type": "qwen"
34
+ },
35
+ {
36
+ "url": "https://rajhuggingface4253-qwen2.hf.space",
37
+ "api_endpoint": "/chat",
38
+ "warmup_message": "Say 'active' in one word",
39
+ "type": "qwen2"
40
+ },
41
+ {
42
+ "url": "https://rajhuggingface4253-qwen3.hf.space",
43
+ "api_endpoint": "/chat",
44
+ "warmup_message": "Just say OK",
45
+ "type": "qwen3"
46
+ }
47
+ ]
48
+
49
  # Global state
50
  ping_results: Dict[str, Dict] = {}
51
+ chat_warmup_results: Dict[str, Dict] = {}
52
  health_results: Dict[str, Dict] = {}
53
  last_ping_run: datetime = None
54
+ last_chat_warmup: datetime = None
55
 
56
  async def ping_server(url: str) -> Dict:
57
+ """Ping a regular server"""
58
  try:
59
  start_time = time.time()
60
  async with httpx.AsyncClient(timeout=10.0) as client:
61
+ response = await client.get(url)
 
62
  response_time = round((time.time() - start_time) * 1000, 1)
63
 
64
  return {
 
74
  'timestamp': datetime.now().isoformat()
75
  }
76
 
77
+ async def warmup_chat_model(model_config: Dict) -> Dict:
78
+ """Send a warmup message to a chat model"""
79
+ try:
80
+ start_time = time.time()
81
+ async with httpx.AsyncClient(timeout=30.0) as client:
82
+ if model_config["type"].startswith("qwen"):
83
+ payload = {
84
+ "message": model_config["warmup_message"],
85
+ "max_tokens": 10
86
+ }
87
+ else:
88
+ payload = {
89
+ "messages": [{"role": "user", "content": model_config["warmup_message"]}],
90
+ "max_tokens": 10
91
+ }
92
+
93
+ api_url = f"{model_config['url']}{model_config['api_endpoint']}"
94
+ response = await client.post(
95
+ api_url,
96
+ json=payload,
97
+ headers={"Content-Type": "application/json"}
98
+ )
99
+
100
+ response_time = round((time.time() - start_time) * 1000, 1)
101
+
102
+ return {
103
+ 'status': 'success',
104
+ 'response_time_ms': response_time,
105
+ 'status_code': response.status_code,
106
+ 'response_preview': str(response.text)[:100],
107
+ 'timestamp': datetime.now().isoformat()
108
+ }
109
+
110
+ except Exception as e:
111
+ return {
112
+ 'status': 'error',
113
+ 'error': str(e),
114
+ 'timestamp': datetime.now().isoformat()
115
+ }
116
+
117
  async def ping_all_servers():
118
+ """Ping all regular servers"""
119
  global ping_results, last_ping_run
120
 
121
+ if not regular_servers:
122
+ return []
123
+
124
+ tasks = [ping_server(server) for server in regular_servers]
125
  results = await asyncio.gather(*tasks)
126
 
127
+ for i, server in enumerate(regular_servers):
 
128
  ping_results[server] = results[i]
129
 
130
  last_ping_run = datetime.now()
131
 
 
132
  success_count = sum(1 for result in results if result['status'] == 'success')
133
+ print(f"🌐 {datetime.now().strftime('%H:%M:%S')} - Regular servers: {success_count}/{len(regular_servers)} OK")
134
+
135
+ return results
136
+
137
+ async def warmup_all_chat_models():
138
+ """Warm up all chat models with actual messages"""
139
+ global chat_warmup_results, last_chat_warmup
140
+
141
+ if not chat_models:
142
+ return []
143
+
144
+ tasks = [warmup_chat_model(model) for model in chat_models]
145
+ results = await asyncio.gather(*tasks)
146
+
147
+ for i, model in enumerate(chat_models):
148
+ chat_warmup_results[model['url']] = results[i]
149
+
150
+ last_chat_warmup = datetime.now()
151
+
152
+ success_count = sum(1 for result in results if result['status'] == 'success')
153
+ print(f"πŸ€– {datetime.now().strftime('%H:%M:%S')} - Chat models: {success_count}/{len(chat_models)} Warmed up")
154
 
155
  return results
156
 
157
  async def ping_health_endpoints():
158
+ """Ping other pinger Spaces"""
159
  global health_results
160
 
161
  async with httpx.AsyncClient(timeout=10.0) as client:
 
179
  'status_code': response.status_code,
180
  'last_ping': datetime.now().isoformat()
181
  }
 
182
  except Exception as e:
183
  health_results[space_url] = {
184
  'status': 'error',
185
  'error': str(e),
186
  'last_ping': datetime.now().isoformat()
187
  }
 
188
 
189
  async def continuous_pinging():
190
+ """Main pinging loop with chat model warming"""
191
+ print("πŸš€ Chat Model Warmer Started!")
192
+ print(f"🌐 Regular servers: {len(regular_servers)}")
193
+ print(f"πŸ€– Chat models: {len(chat_models)}")
194
+ print(f"πŸ”— Pinger network: {len(pinger_spaces)}")
195
+ print("⏰ Chat warmup every 5 minutes")
196
 
197
  last_health_check = 0
198
 
199
  while True:
200
  try:
201
+ # Ping regular servers
202
+ if regular_servers:
203
+ await ping_all_servers()
204
+
205
+ # Warm up chat models (most important!)
206
+ if chat_models:
207
+ await warmup_all_chat_models()
208
 
209
+ # Ping health endpoints every 30 minutes (FIXED: use the defined constant)
210
  current_time = time.time()
211
+ if current_time - last_health_check >= HEALTH_CHECK_INTERVAL and pinger_spaces:
212
+ await ping_health_endpoints()
 
 
213
  last_health_check = current_time
214
 
 
215
  await asyncio.sleep(PING_INTERVAL)
216
 
217
  except Exception as e:
218
+ print(f"❌ Error: {e}")
219
+ await asyncio.sleep(60)
220
 
221
+ @asynccontextmanager
222
+ async def lifespan(app: FastAPI):
223
+ # Startup
224
+ print("Starting up Chat Model Warmer...")
225
  asyncio.create_task(continuous_pinging())
226
+ yield
227
+ # Shutdown
228
+ print("Shutting down...")
229
+
230
+ app = FastAPI(title="Chat Model Warmer", lifespan=lifespan)
231
 
232
  @app.get("/", response_class=HTMLResponse)
233
  async def home():
234
+ """Minimal dashboard"""
235
+ regular_success = sum(1 for r in ping_results.values() if r.get('status') == 'success')
236
+ chat_success = sum(1 for r in chat_warmup_results.values() if r.get('status') == 'success')
237
+ health_success = sum(1 for r in health_results.values() if r.get('status') == 'success')
238
 
239
  html_content = f"""
240
  <html>
241
+ <head><title>Chat Model Warmer</title></head>
 
 
 
 
 
 
 
 
242
  <body>
243
+ <h1>πŸ€– Chat Model Warmer</h1>
244
+ <p><strong>Regular Servers:</strong> {regular_success}/{len(regular_servers)} OK</p>
245
+ <p><strong>Chat Models:</strong> {chat_success}/{len(chat_models)} Warmed up</p>
246
+ <p><strong>Last Chat Warmup:</strong> {last_chat_warmup.strftime('%H:%M:%S') if last_chat_warmup else 'Never'}</p>
247
+ <p><strong>Network:</strong> {health_success}/{len(pinger_spaces)} OK</p>
 
 
 
 
 
 
 
248
  </body>
249
  </html>
250
  """
 
252
 
253
  @app.get("/health")
254
  async def health():
 
255
  return JSONResponse({
256
  "status": "healthy",
257
+ "service": "chat-model-warmer",
258
+ "regular_servers": len(regular_servers),
259
+ "chat_models": len(chat_models),
260
+ "last_chat_warmup": last_chat_warmup.isoformat() if last_chat_warmup else None
 
261
  })
262
 
263
+ @app.get("/status")
264
+ async def status():
 
265
  return JSONResponse({
266
+ "regular_servers": ping_results,
267
+ "chat_models": chat_warmup_results,
 
268
  "timestamp": datetime.now().isoformat()
269
  })
270
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271
  if __name__ == "__main__":
272
  import uvicorn
273
  uvicorn.run(app, host="0.0.0.0", port=7860)