electblake commited on
Commit
7de0174
·
1 Parent(s): 60d4ffd

feat(gradio): generate extraction templates from images

Browse files

Add an independent ZeroGPU template-generation pipeline using NuExtract3's grounded document mode. Wire a new input-column button to populate the existing editable template while preserving presets and structured extraction.

Files changed (2) hide show
  1. README.md +1 -1
  2. app/gradio.py +35 -1
README.md CHANGED
@@ -17,7 +17,7 @@ short_description: Extract structured JSON from documents with NuExtract3.
17
 
18
  NuMark is a Gradio app for extracting structured JSON from document images with [NuExtract3](https://huggingface.co/numind/NuExtract3).
19
 
20
- Upload a receipt, invoice, or other document image, optionally add accompanying text, and choose a JSON template for schema-guided structured extraction.
21
 
22
  The inference function uses Hugging Face ZeroGPU dynamic GPU allocation. Select ZeroGPU in the Space hardware settings before launching the app.
23
 
 
17
 
18
  NuMark is a Gradio app for extracting structured JSON from document images with [NuExtract3](https://huggingface.co/numind/NuExtract3).
19
 
20
+ Upload a receipt, invoice, or other document image, optionally add accompanying text, and choose a JSON template for schema-guided structured extraction. You can also generate a grounded template from the uploaded image before running extraction.
21
 
22
  The inference function uses Hugging Face ZeroGPU dynamic GPU allocation. Select ZeroGPU in the Space hardware settings before launching the app.
23
 
app/gradio.py CHANGED
@@ -236,7 +236,6 @@ model = (
236
  )
237
 
238
 
239
- @spaces.GPU
240
  def run_nuextract(messages, **chat_template_kwargs):
241
  inputs = processor.apply_chat_template(
242
  messages,
@@ -262,6 +261,7 @@ def run_nuextract(messages, **chat_template_kwargs):
262
  )[0].strip()
263
 
264
 
 
265
  def extract(image, text, template, enable_thinking):
266
  result = run_nuextract(
267
  [
@@ -281,6 +281,32 @@ def extract(image, text, template, enable_thinking):
281
  return json.loads(result)
282
 
283
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
284
  with gr.Blocks(title="NuMarkApp") as demo:
285
  gr.Markdown(
286
  "# NuMarkApp\n"
@@ -302,6 +328,7 @@ with gr.Blocks(title="NuMarkApp") as demo:
302
  label="JSON template preset",
303
  info="Choose a starting structure, then edit it below.",
304
  )
 
305
  with gr.Accordion("Structured JSON template", open=False):
306
  template = gr.Textbox(
307
  label="Structured JSON template",
@@ -389,6 +416,13 @@ with gr.Blocks(title="NuMarkApp") as demo:
389
  outputs=template,
390
  )
391
 
 
 
 
 
 
 
 
392
  run.click(
393
  extract,
394
  inputs=[image, text, template, enable_thinking],
 
236
  )
237
 
238
 
 
239
  def run_nuextract(messages, **chat_template_kwargs):
240
  inputs = processor.apply_chat_template(
241
  messages,
 
261
  )[0].strip()
262
 
263
 
264
+ @spaces.GPU
265
  def extract(image, text, template, enable_thinking):
266
  result = run_nuextract(
267
  [
 
281
  return json.loads(result)
282
 
283
 
284
+ @spaces.GPU
285
+ def generate_template(image):
286
+ result = run_nuextract(
287
+ [
288
+ {
289
+ "role": "user",
290
+ "content": [
291
+ {"type": "image", "image": image},
292
+ {
293
+ "type": "text",
294
+ "text": (
295
+ "Create a reusable structured extraction template grounded only "
296
+ "in the visible document. Include fields supported by the document, "
297
+ "represent repeated records as arrays, use NuExtract template leaf "
298
+ "types, and return only the JSON template."
299
+ ),
300
+ },
301
+ ],
302
+ }
303
+ ],
304
+ mode="template-generation",
305
+ )
306
+
307
+ return json.dumps(json.loads(result), indent=2)
308
+
309
+
310
  with gr.Blocks(title="NuMarkApp") as demo:
311
  gr.Markdown(
312
  "# NuMarkApp\n"
 
328
  label="JSON template preset",
329
  info="Choose a starting structure, then edit it below.",
330
  )
331
+ generate_template_button = gr.Button("Generate template from Image")
332
  with gr.Accordion("Structured JSON template", open=False):
333
  template = gr.Textbox(
334
  label="Structured JSON template",
 
416
  outputs=template,
417
  )
418
 
419
+ generate_template_button.click(
420
+ generate_template,
421
+ inputs=image,
422
+ outputs=template,
423
+ api_name="generate_template",
424
+ )
425
+
426
  run.click(
427
  extract,
428
  inputs=[image, text, template, enable_thinking],