DrValera commited on
Commit
1e77917
·
verified ·
1 Parent(s): 18f2760

Updated output for modelfit_chat

Browse files
Files changed (1) hide show
  1. main.py +111 -9
main.py CHANGED
@@ -283,6 +283,111 @@ async def _forward(path: str, method: str = "GET", json_body=None, user_token: s
283
  # Fallback: return short text envelope if non-JSON
284
  return JSONResponse(status_code=r.status_code, content={"text": r.text[:1000]})
285
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
286
  async def _forward_stream(path: str, files=None, data=None, user_token: str | None = None, method: str = "POST"):
287
  url = f"{UPSTREAM_URL}{path}"
288
  headers = {
@@ -590,8 +695,7 @@ async def modelfit_chat(
590
  """
591
  Fetch training data from data_url (HTTPS), infer schema from column order, then call /modelfit/ on the API.
592
  Column order: 1st = id_col, 2nd = time_col, 3rd..second-to-last = current_features, last = y.
593
- All other parameters use defaults. On success returns a minimal JSON (ok, message) to stay under
594
- chat platform response size limits; errors are returned in full.
595
  """
596
  user_token = _extract_user_token(req)
597
  if not user_token:
@@ -619,13 +723,11 @@ async def modelfit_chat(
619
  "meanvar_test": False,
620
  "signif": 0.05,
621
  }
622
- return await _forward(
623
- "/modelfit/",
624
- "POST",
625
- json_body=payload,
626
- user_token=user_token,
627
- success_response_override={"ok": True, "message": "Model fitted. Call modelforecast_chat with your forecast data URL next."},
628
- )
629
 
630
 
631
  @app.post("/modelforecast_chat/")
 
283
  # Fallback: return short text envelope if non-JSON
284
  return JSONResponse(status_code=r.status_code, content={"text": r.text[:1000]})
285
 
286
+
287
+ async def _forward_and_get_body(path: str, method: str = "GET", json_body=None, user_token: str | None = None) -> tuple[int, dict | list | None]:
288
+ """Same as _forward but returns (status_code, parsed_json_body) so caller can build a custom response."""
289
+ url = f"{UPSTREAM_URL}{path}"
290
+ headers = {
291
+ "Authorization": f"Bearer {HF_TOKEN}",
292
+ "Accept": "application/json",
293
+ }
294
+ if user_token:
295
+ headers["X-API-Key"] = user_token
296
+ ping_url = f"{UPSTREAM_URL}/secure-ping/"
297
+ ping_headers = {"Authorization": f"Bearer {HF_TOKEN}"}
298
+ if user_token:
299
+ ping_headers["X-API-Key"] = user_token
300
+ timeout = httpx.Timeout(UPSTREAM_TIMEOUT)
301
+ r = None
302
+
303
+ async def do_request():
304
+ nonlocal r
305
+ async with httpx.AsyncClient(timeout=timeout) as client:
306
+ r = await client.request(method, url, headers=headers, json=json_body)
307
+
308
+ request_task = asyncio.create_task(do_request())
309
+ wait_sec = PING_INTERVAL if PING_INTERVAL > 0 else 0.0
310
+ try:
311
+ while not request_task.done():
312
+ if wait_sec <= 0:
313
+ await request_task
314
+ break
315
+ ping_sleep = asyncio.create_task(asyncio.sleep(wait_sec))
316
+ done, pending = await asyncio.wait(
317
+ {request_task, ping_sleep},
318
+ return_when=asyncio.FIRST_COMPLETED,
319
+ timeout=UPSTREAM_TIMEOUT + 10,
320
+ )
321
+ for t in pending:
322
+ if t is not request_task:
323
+ t.cancel()
324
+ try:
325
+ await t
326
+ except asyncio.CancelledError:
327
+ pass
328
+ if request_task in done:
329
+ break
330
+ async with httpx.AsyncClient(timeout=10.0) as c:
331
+ if SELF_URL:
332
+ try:
333
+ await c.get(f"{SELF_URL}/keep-alive")
334
+ except Exception:
335
+ pass
336
+ try:
337
+ await c.get(ping_url, headers=ping_headers)
338
+ except Exception:
339
+ pass
340
+ if not request_task.done():
341
+ request_task.cancel()
342
+ try:
343
+ await request_task
344
+ except asyncio.CancelledError:
345
+ pass
346
+ await request_task
347
+ except asyncio.CancelledError:
348
+ request_task.cancel()
349
+ try:
350
+ await request_task
351
+ except asyncio.CancelledError:
352
+ pass
353
+ raise
354
+ exc = request_task.exception()
355
+ if exc is not None:
356
+ raise exc
357
+ if r is None:
358
+ raise RuntimeError("Upstream request did not complete")
359
+
360
+ ct = r.headers.get("content-type", "")
361
+ if "application/json" in ct:
362
+ try:
363
+ return (r.status_code, r.json())
364
+ except Exception:
365
+ return (r.status_code, {"error": r.text[:500]})
366
+ return (r.status_code, {"text": r.text[:1000]})
367
+
368
+
369
+ def _build_modelfit_chat_minimal(body: dict) -> dict:
370
+ """Extract formula, alpha, beta, and Performance subset (col 2, rows 3,4,5) for chat response."""
371
+ out = {"ok": True, "formula": body.get("formula")}
372
+ out["alpha"] = body.get("alpha")
373
+ out["beta"] = body.get("beta")
374
+ perf = body.get("Performance")
375
+ if isinstance(perf, list) and len(perf) >= 5:
376
+ keys = list(perf[0].keys()) if perf[0] else []
377
+ # Col 2 (1-based) = index 1; if only one column use index 0. Rows 3,4,5 = indices 2,3,4.
378
+ col_idx = 1 if len(keys) > 1 else 0
379
+ col2_name = keys[col_idx] if keys else None
380
+ if col2_name is not None:
381
+ row_names = ["R2 overall", "MSE", "MAE"]
382
+ values = [perf[i].get(col2_name) for i in [2, 3, 4]]
383
+ out["Performance_subset"] = {"metric_names": row_names, "column": col2_name, "values": values}
384
+ else:
385
+ out["Performance_subset"] = None
386
+ else:
387
+ out["Performance_subset"] = None
388
+ return out
389
+
390
+
391
  async def _forward_stream(path: str, files=None, data=None, user_token: str | None = None, method: str = "POST"):
392
  url = f"{UPSTREAM_URL}{path}"
393
  headers = {
 
695
  """
696
  Fetch training data from data_url (HTTPS), infer schema from column order, then call /modelfit/ on the API.
697
  Column order: 1st = id_col, 2nd = time_col, 3rd..second-to-last = current_features, last = y.
698
+ On success returns a small informative JSON: formula, alpha, beta, Performance_subset (col 2, rows 3–5).
 
699
  """
700
  user_token = _extract_user_token(req)
701
  if not user_token:
 
723
  "meanvar_test": False,
724
  "signif": 0.05,
725
  }
726
+ status, body = await _forward_and_get_body("/modelfit/", "POST", json_body=payload, user_token=user_token)
727
+ if status != 200 or not isinstance(body, dict):
728
+ return JSONResponse(status_code=status, content=body if isinstance(body, dict) else {"error": str(body)})
729
+ minimal = _build_modelfit_chat_minimal(body)
730
+ return JSONResponse(status_code=200, content=minimal)
 
 
731
 
732
 
733
  @app.post("/modelforecast_chat/")