Shoraky commited on
Commit
ef7986f
·
1 Parent(s): d689491

Log analysis session database failures

Browse files
Files changed (2) hide show
  1. app.py +19 -1
  2. src/analysis.ts +8 -2
app.py CHANGED
@@ -21,6 +21,8 @@ from zipfile import ZipFile
21
  import httpx
22
  import numpy as np
23
  import cv2
 
 
24
  from dotenv import load_dotenv
25
  from fastapi import FastAPI, File, Form, HTTPException, Request, UploadFile
26
  from fastapi.responses import FileResponse, JSONResponse
@@ -125,6 +127,8 @@ app = FastAPI(title="Sporalize AI", lifespan=lifespan)
125
  @app.exception_handler(httpx.HTTPStatusError)
126
  async def backend_error(request: Request, error: httpx.HTTPStatusError):
127
  status = error.response.status_code
 
 
128
  return JSONResponse({"detail": "Backend request failed"}, status_code=status if status < 500 else 502)
129
 
130
 
@@ -167,6 +171,19 @@ def drive_file_id(link):
167
  return next(group for group in match.groups() if group)
168
 
169
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  async def download_drive_file(link, destination):
171
  file_id = drive_file_id(link)
172
  url = f"https://drive.google.com/uc?export=download&confirm=t&id={file_id}"
@@ -275,10 +292,11 @@ def probe_drive(payload: dict):
275
  file_id = drive_file_id(str(link))
276
  with httpx.stream("GET", f"https://drive.google.com/uc?export=download&confirm=t&id={file_id}", follow_redirects=True, timeout=30) as response:
277
  content_type = response.headers.get("content-type", "")
 
278
  size = int(response.headers.get("content-length", "0") or 0)
279
  if not response.is_success or "text/html" in content_type.lower():
280
  raise ValueError("File is not publicly downloadable")
281
- result.update(ok=True, fileId=file_id, fileName=f"{file_id}.mp4", sizeBytes=size or None, contentType=content_type)
282
  except Exception as error:
283
  result.update(ok=False, code="unavailable", error=str(error))
284
  results.append(result)
 
21
  import httpx
22
  import numpy as np
23
  import cv2
24
+ from email.message import Message
25
+ from email.utils import collapse_rfc2231_value
26
  from dotenv import load_dotenv
27
  from fastapi import FastAPI, File, Form, HTTPException, Request, UploadFile
28
  from fastapi.responses import FileResponse, JSONResponse
 
127
  @app.exception_handler(httpx.HTTPStatusError)
128
  async def backend_error(request: Request, error: httpx.HTTPStatusError):
129
  status = error.response.status_code
130
+ logger.error("Analysis backend request failed: path=%s status=%s response=%s",
131
+ request.url.path, status, error.response.text[:500])
132
  return JSONResponse({"detail": "Backend request failed"}, status_code=status if status < 500 else 502)
133
 
134
 
 
171
  return next(group for group in match.groups() if group)
172
 
173
 
174
+ def drive_file_name(content_disposition, file_id):
175
+ message = Message()
176
+ if content_disposition:
177
+ message["content-disposition"] = content_disposition
178
+ name = message.get_filename()
179
+ if isinstance(name, tuple):
180
+ name = collapse_rfc2231_value(name)
181
+ name = (name or f"{file_id}.mp4").replace("\\", "/")
182
+ name = Path(name).name
183
+ name = "".join(character for character in name if character.isprintable()).strip()
184
+ return name[:255] or f"{file_id}.mp4"
185
+
186
+
187
  async def download_drive_file(link, destination):
188
  file_id = drive_file_id(link)
189
  url = f"https://drive.google.com/uc?export=download&confirm=t&id={file_id}"
 
292
  file_id = drive_file_id(str(link))
293
  with httpx.stream("GET", f"https://drive.google.com/uc?export=download&confirm=t&id={file_id}", follow_redirects=True, timeout=30) as response:
294
  content_type = response.headers.get("content-type", "")
295
+ content_disposition = response.headers.get("content-disposition", "")
296
  size = int(response.headers.get("content-length", "0") or 0)
297
  if not response.is_success or "text/html" in content_type.lower():
298
  raise ValueError("File is not publicly downloadable")
299
+ result.update(ok=True, fileId=file_id, fileName=drive_file_name(content_disposition, file_id), sizeBytes=size or None, contentType=content_type)
300
  except Exception as error:
301
  result.update(ok=False, code="unavailable", error=str(error))
302
  results.append(result)
src/analysis.ts CHANGED
@@ -51,7 +51,10 @@ export function analysisRouter(db: SupabaseClient, secret: string) {
51
  p_reference: playerId.success ? null : input.playerId,
52
  p_name: input.name || `Session ${input.clientId.slice(0, 8)}`,
53
  });
54
- if (error) return res.status(error.code === "P0001" ? 409 : 503).json({ error: "Unable to prepare analysis session" });
 
 
 
55
  return res.json(data);
56
  } catch (error) { next(error); }
57
  });
@@ -76,7 +79,10 @@ export function analysisRouter(db: SupabaseClient, secret: string) {
76
  p_session_id: sessionId, p_user_id: res.locals.userId, p_status: input.status,
77
  p_path: input.status === "completed" ? input.path : null, p_actions: actions,
78
  });
79
- if (error) return res.status(error.code === "P0001" ? 409 : 503).json({ error: "Unable to save analysis" });
 
 
 
80
  return res.json({ ok: true });
81
  } catch (error) { next(error); }
82
  });
 
51
  p_reference: playerId.success ? null : input.playerId,
52
  p_name: input.name || `Session ${input.clientId.slice(0, 8)}`,
53
  });
54
+ if (error) {
55
+ console.error("Unable to prepare analysis session", { code: error.code, message: error.message });
56
+ return res.status(error.code === "P0001" ? 409 : 503).json({ error: "Unable to prepare analysis session" });
57
+ }
58
  return res.json(data);
59
  } catch (error) { next(error); }
60
  });
 
79
  p_session_id: sessionId, p_user_id: res.locals.userId, p_status: input.status,
80
  p_path: input.status === "completed" ? input.path : null, p_actions: actions,
81
  });
82
+ if (error) {
83
+ console.error("Unable to save analysis results", { code: error.code, message: error.message });
84
+ return res.status(error.code === "P0001" ? 409 : 503).json({ error: "Unable to save analysis" });
85
+ }
86
  return res.json({ ok: true });
87
  } catch (error) { next(error); }
88
  });