julien-c HF staff commited on
Commit
33e958f
1 Parent(s): 504d550

Also allow conversion from POST upload

Browse files
Files changed (1) hide show
  1. app.py +42 -25
app.py CHANGED
@@ -1,4 +1,4 @@
1
- import os
2
  import httpx
3
  import nbformat
4
  from nbformat import NotebookNode, ValidationError
@@ -21,47 +21,63 @@ async def healthz(_):
21
  return JSONResponse({"success": True})
22
 
23
 
24
- async def convert(req: Request):
25
- url = req.query_params.get("url")
26
- if not url:
27
- raise HTTPException(400, "Param url is missing")
28
- print("\n===", url)
29
- theme = req.query_params.get("theme")
30
- r = await client.get(
31
- url,
32
- follow_redirects=True,
33
- # httpx no follow redirect by default
34
- )
35
- if r.status_code != 200:
36
- raise HTTPException(
37
- 400, f"Got an error {r.status_code} when fetching remote file"
38
- )
39
-
40
  # Capture potential validation error:
41
  try:
42
  notebook_node: NotebookNode = nbformat.reads(
43
- r.text,
44
  as_version=nbformat.current_nbformat,
45
  )
46
  except nbformat.reader.NotJSONError:
47
- print(400, f"Notebook is not JSON ({url})")
48
- raise HTTPException(400, f"Notebook is not JSON ({url})")
49
  except ValidationError as e:
50
  print(
51
  400,
52
- f"Notebook is invalid according to nbformat: {e} ({url})",
53
  )
54
  raise HTTPException(
55
  400,
56
- f"Notebook is invalid according to nbformat: {e} ({url})",
57
  )
58
 
59
  print(f"Input: nbformat v{notebook_node.nbformat}.{notebook_node.nbformat_minor}")
60
- html_exporter.theme = "dark" if theme == "dark" else "light"
61
  body, _ = html_exporter.from_notebook_node(notebook_node)
62
  # TODO(customize or simplify template?)
63
  # TODO(also check source code for jupyter/nbviewer)
64
- return HTMLResponse(body)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
 
66
 
67
  app = Starlette(
@@ -69,6 +85,7 @@ app = Starlette(
69
  routes=[
70
  Route("/", homepage),
71
  Route("/healthz", healthz),
72
- Route("/convert", convert),
 
73
  ],
74
  )
 
1
+ from typing import Literal
2
  import httpx
3
  import nbformat
4
  from nbformat import NotebookNode, ValidationError
 
21
  return JSONResponse({"success": True})
22
 
23
 
24
+ def convert(s: str, theme: Literal["light", "dark"], debug_info: str) -> str:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  # Capture potential validation error:
26
  try:
27
  notebook_node: NotebookNode = nbformat.reads(
28
+ s,
29
  as_version=nbformat.current_nbformat,
30
  )
31
  except nbformat.reader.NotJSONError:
32
+ print(400, f"Notebook is not JSON. {debug_info}")
33
+ raise HTTPException(400, f"Notebook is not JSON. {debug_info}")
34
  except ValidationError as e:
35
  print(
36
  400,
37
+ f"Notebook is invalid according to nbformat: {e}. {debug_info}",
38
  )
39
  raise HTTPException(
40
  400,
41
+ f"Notebook is invalid according to nbformat: {e}. {debug_info}",
42
  )
43
 
44
  print(f"Input: nbformat v{notebook_node.nbformat}.{notebook_node.nbformat_minor}")
45
+ html_exporter.theme = theme
46
  body, _ = html_exporter.from_notebook_node(notebook_node)
47
  # TODO(customize or simplify template?)
48
  # TODO(also check source code for jupyter/nbviewer)
49
+ return body
50
+
51
+
52
+ async def convert_from_url(req: Request):
53
+ url = req.query_params.get("url")
54
+ theme = "dark" if req.query_params.get("theme") == "dark" else "light"
55
+
56
+ if not url:
57
+ raise HTTPException(400, "Param url is missing")
58
+ print("\n===", url)
59
+ r = await client.get(
60
+ url,
61
+ follow_redirects=True,
62
+ # httpx no follow redirect by default
63
+ )
64
+ if r.status_code != 200:
65
+ raise HTTPException(
66
+ 400, f"Got an error {r.status_code} when fetching remote file"
67
+ )
68
+
69
+ return HTMLResponse(content=convert(r.text, theme=theme, debug_info=f"url={url}"))
70
+
71
+
72
+ async def convert_from_upload(req: Request):
73
+ theme = "dark" if req.query_params.get("theme") == "dark" else "light"
74
+
75
+ s = (await req.body()).decode("utf-8")
76
+ return HTMLResponse(
77
+ content=convert(
78
+ s, theme=theme, debug_info=f"upload_from={req.headers.get('user-agent')}"
79
+ )
80
+ )
81
 
82
 
83
  app = Starlette(
 
85
  routes=[
86
  Route("/", homepage),
87
  Route("/healthz", healthz),
88
+ Route("/convert", convert_from_url),
89
+ Route("/upload", convert_from_upload, methods=["POST"]),
90
  ],
91
  )