xxyyy123 commited on
Commit
5bda61a
·
verified ·
1 Parent(s): d4d6abb

Use dynamic ZeroGPU duration for PDF batches

Browse files
README.md CHANGED
@@ -27,9 +27,11 @@ visual-region crops. Model tokens stream into the interface as they are generate
27
  PDFs are rasterized locally and processed one page at a time in Base mode. Up to
28
  four pages share one streamed GPU request by default, while each page is still
29
  inferred independently and sequentially. The browser merges the results, so long
30
- documents do not have to fit inside one ZeroGPU lease. If a Gradio stream closes
31
- without an explicit backend error, the browser resumes once from the first
32
- unfinished page while retaining every completed page. This demo
 
 
33
  intentionally does not expose a separate Long mode.
34
 
35
  The five packaged examples cover two financial tables, two Chinese handwriting
@@ -107,7 +109,10 @@ completed pages.
107
  - `OVISOCR_PDF_RENDER_SCALE`: PDF rasterization scale, defaults to `2.0`.
108
  - `OVISOCR_STREAM_MIN_CHARS`: minimum new characters between stream updates, defaults to `64`.
109
  - `OVISOCR_STREAM_MAX_INTERVAL`: maximum seconds between available stream updates, defaults to `0.25`.
110
- - `OVISOCR_GPU_DURATION`: per-group ZeroGPU reservation in seconds, defaults to `300`.
 
 
 
111
  - `OVISOCR_ATTN_IMPLEMENTATION`: defaults to `sdpa`.
112
  - `OVISOCR_DSW_ID`: generates the Hangzhou DSW proxy root using the active `PORT`.
113
  - `OVISOCR_ROOT_PATH`: explicit proxy URL or ASGI path prefix; overrides `OVISOCR_DSW_ID`.
 
27
  PDFs are rasterized locally and processed one page at a time in Base mode. Up to
28
  four pages share one streamed GPU request by default, while each page is still
29
  inferred independently and sequentially. The browser merges the results, so long
30
+ documents do not have to fit inside one ZeroGPU lease. GPU duration is estimated
31
+ from the number of pages that actually remain in each group, so a short second
32
+ group does not reserve the same ZeroGPU quota as a four-page group. If a Gradio
33
+ stream closes without an explicit backend error, the browser reconnects from the
34
+ first unfinished page while retaining every completed page. This demo
35
  intentionally does not expose a separate Long mode.
36
 
37
  The five packaged examples cover two financial tables, two Chinese handwriting
 
109
  - `OVISOCR_PDF_RENDER_SCALE`: PDF rasterization scale, defaults to `2.0`.
110
  - `OVISOCR_STREAM_MIN_CHARS`: minimum new characters between stream updates, defaults to `64`.
111
  - `OVISOCR_STREAM_MAX_INTERVAL`: maximum seconds between available stream updates, defaults to `0.25`.
112
+ - `OVISOCR_GPU_SECONDS_PER_PAGE`: duration-estimation budget, defaults to `30` seconds per page.
113
+ - `OVISOCR_GPU_DURATION_FLOOR`: minimum per-group ZeroGPU reservation, defaults to `45` seconds.
114
+ - `OVISOCR_GPU_DURATION_CEILING`: maximum estimated per-group reservation, defaults to `120` seconds.
115
+ - `OVISOCR_GPU_DURATION`: optional fixed per-group override; unset by default so dynamic duration is used.
116
  - `OVISOCR_ATTN_IMPLEMENTATION`: defaults to `sdpa`.
117
  - `OVISOCR_DSW_ID`: generates the Hangzhou DSW proxy root using the active `PORT`.
118
  - `OVISOCR_ROOT_PATH`: explicit proxy URL or ASGI path prefix; overrides `OVISOCR_DSW_ID`.
app.py CHANGED
@@ -56,6 +56,12 @@ MAX_PDF_PAGES = int(os.getenv("OVISOCR_MAX_PDF_PAGES", "50"))
56
  PAGES_PER_GPU_REQUEST = max(
57
  1, min(5, int(os.getenv("OVISOCR_PAGES_PER_GPU_REQUEST", "4")))
58
  )
 
 
 
 
 
 
59
  PDF_RENDER_SCALE = float(os.getenv("OVISOCR_PDF_RENDER_SCALE", "2.0"))
60
  STREAM_MIN_CHARS = int(os.getenv("OVISOCR_STREAM_MIN_CHARS", "64"))
61
  STREAM_MAX_INTERVAL = float(os.getenv("OVISOCR_STREAM_MAX_INTERVAL", "0.25"))
@@ -461,7 +467,25 @@ def _gpu_duration(
461
  image_path: FileData | dict[str, Any], page_index: int = 0,
462
  page_count: int = PAGES_PER_GPU_REQUEST,
463
  ) -> int:
464
- return int(os.getenv("OVISOCR_GPU_DURATION", "300"))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
465
 
466
 
467
  _load_model()
@@ -606,6 +630,9 @@ def healthz() -> JSONResponse:
606
  "loaded": TEST_MODE or (processor is not None and model is not None),
607
  "max_pdf_pages": MAX_PDF_PAGES,
608
  "pages_per_gpu_request": PAGES_PER_GPU_REQUEST,
 
 
 
609
  "root_path": ROOT_PATH,
610
  "public_url": PUBLIC_URL,
611
  }
 
56
  PAGES_PER_GPU_REQUEST = max(
57
  1, min(5, int(os.getenv("OVISOCR_PAGES_PER_GPU_REQUEST", "4")))
58
  )
59
+ GPU_SECONDS_PER_PAGE = max(15, int(os.getenv("OVISOCR_GPU_SECONDS_PER_PAGE", "30")))
60
+ GPU_DURATION_FLOOR = max(15, int(os.getenv("OVISOCR_GPU_DURATION_FLOOR", "45")))
61
+ GPU_DURATION_CEILING = max(
62
+ GPU_DURATION_FLOOR,
63
+ int(os.getenv("OVISOCR_GPU_DURATION_CEILING", "120")),
64
+ )
65
  PDF_RENDER_SCALE = float(os.getenv("OVISOCR_PDF_RENDER_SCALE", "2.0"))
66
  STREAM_MIN_CHARS = int(os.getenv("OVISOCR_STREAM_MIN_CHARS", "64"))
67
  STREAM_MAX_INTERVAL = float(os.getenv("OVISOCR_STREAM_MAX_INTERVAL", "0.25"))
 
467
  image_path: FileData | dict[str, Any], page_index: int = 0,
468
  page_count: int = PAGES_PER_GPU_REQUEST,
469
  ) -> int:
470
+ configured_duration = os.getenv("OVISOCR_GPU_DURATION", "").strip()
471
+ if configured_duration:
472
+ return int(configured_duration)
473
+
474
+ requested_count = max(1, min(PAGES_PER_GPU_REQUEST, int(page_count)))
475
+ try:
476
+ path = _file_path(image_path)
477
+ _, total_pages = document_info(path)
478
+ remaining_pages = max(1, total_pages - int(page_index))
479
+ requested_count = min(requested_count, remaining_pages)
480
+ except Exception:
481
+ # Duration estimation must never prevent a request from reaching the
482
+ # endpoint. The endpoint performs the authoritative file validation.
483
+ pass
484
+
485
+ return max(
486
+ GPU_DURATION_FLOOR,
487
+ min(GPU_DURATION_CEILING, requested_count * GPU_SECONDS_PER_PAGE),
488
+ )
489
 
490
 
491
  _load_model()
 
630
  "loaded": TEST_MODE or (processor is not None and model is not None),
631
  "max_pdf_pages": MAX_PDF_PAGES,
632
  "pages_per_gpu_request": PAGES_PER_GPU_REQUEST,
633
+ "gpu_seconds_per_page": GPU_SECONDS_PER_PAGE,
634
+ "gpu_duration_floor": GPU_DURATION_FLOOR,
635
+ "gpu_duration_ceiling": GPU_DURATION_CEILING,
636
  "root_path": ROOT_PATH,
637
  "public_url": PUBLIC_URL,
638
  }
dist/assets/{index-BuDpKXhW.js → index-uj7s2XQX.js} RENAMED
The diff for this file is too large to render. See raw diff
 
dist/index.html CHANGED
@@ -22,7 +22,7 @@
22
  };
23
  </script>
24
  <script defer src="./vendor/mathjax/tex-chtml-full.js"></script>
25
- <script type="module" crossorigin src="./assets/index-BuDpKXhW.js"></script>
26
  <link rel="stylesheet" crossorigin href="./assets/index-CQtDzYS-.css">
27
  </head>
28
  <body>
 
22
  };
23
  </script>
24
  <script defer src="./vendor/mathjax/tex-chtml-full.js"></script>
25
+ <script type="module" crossorigin src="./assets/index-uj7s2XQX.js"></script>
26
  <link rel="stylesheet" crossorigin href="./assets/index-CQtDzYS-.css">
27
  </head>
28
  <body>