Spaces:
Running
Running
Ashwin V. Mohanan
commited on
Commit
·
b8077d0
1
Parent(s):
3216119
Add first rough version
Browse files- LICENSE +0 -0
- app/__init__.py +0 -0
- app/content/main_sub_title.md +3 -0
- app/content/main_title.md +1 -0
- app/gradio_config.py +118 -0
- app/main.py +95 -0
- app/tabs/__init__.py +0 -0
- app/tabs/submit.py +245 -0
- pyproject.toml +2 -1
- uv.lock +0 -0
LICENSE
CHANGED
The diff for this file is too large to render.
See raw diff
|
|
app/__init__.py
ADDED
File without changes
|
app/content/main_sub_title.md
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
<a href="https://dawsonia.readthedocs.io">
|
2 |
+
<img src="https://git.smhi.se/ai-for-obs/dawsonia/-/raw/main/docs/source/_static/smhi_logo_black_8mm.png" width="17%" align="right" margin-right="200" />
|
3 |
+
</a>
|
app/content/main_title.md
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
<h1><center> Dawsonia 🔍 App </center></h1>
|
app/gradio_config.py
ADDED
@@ -0,0 +1,118 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
|
3 |
+
theme = gr.themes.Default(
|
4 |
+
primary_hue="blue",
|
5 |
+
secondary_hue="blue",
|
6 |
+
neutral_hue="slate",
|
7 |
+
# font=[
|
8 |
+
# gr.themes.GoogleFont("Open Sans"),
|
9 |
+
# "ui-sans-serif",
|
10 |
+
# "system-ui",
|
11 |
+
# "sans-serif",
|
12 |
+
# ],
|
13 |
+
)
|
14 |
+
|
15 |
+
css = """
|
16 |
+
.svg-image {
|
17 |
+
height: auto;
|
18 |
+
width: 100%;
|
19 |
+
margin: auto;
|
20 |
+
}
|
21 |
+
|
22 |
+
.transcription {
|
23 |
+
font-size: large;
|
24 |
+
position: sticky;
|
25 |
+
top: 20px;
|
26 |
+
}
|
27 |
+
|
28 |
+
.transcription-column {
|
29 |
+
height: 100vh;
|
30 |
+
}
|
31 |
+
|
32 |
+
/* this is needed in order to make the transcription sticky */
|
33 |
+
.app {
|
34 |
+
overflow: visible;
|
35 |
+
}
|
36 |
+
|
37 |
+
/* style of textline svg elements */
|
38 |
+
.textline {
|
39 |
+
fill: transparent;
|
40 |
+
stroke: blue;
|
41 |
+
stroke-width: 10;
|
42 |
+
stroke-opacity: 0.2;
|
43 |
+
}
|
44 |
+
|
45 |
+
.highlighted polygon {
|
46 |
+
fill:blue;
|
47 |
+
fill-opacity: 0.2;
|
48 |
+
}
|
49 |
+
|
50 |
+
span.highlighted {
|
51 |
+
background-color: rgba(0%, 0%, 100%, 0.2);
|
52 |
+
font-size: large;
|
53 |
+
}
|
54 |
+
|
55 |
+
hr.region-divider {
|
56 |
+
margin-top: 0.5em;
|
57 |
+
margin-bottom: 0.5em;
|
58 |
+
}
|
59 |
+
|
60 |
+
.pipeline-panel {
|
61 |
+
background: none;
|
62 |
+
border: solid 1px;
|
63 |
+
border-color: var(--block-border-color);
|
64 |
+
}
|
65 |
+
|
66 |
+
.pipeline-help {
|
67 |
+
padding: 5px 0 0 0;
|
68 |
+
font-weight: var(--block-info-text-weight);
|
69 |
+
font-size: var(--block-info-text-size);
|
70 |
+
color: var(--block-info-text-color);
|
71 |
+
}
|
72 |
+
|
73 |
+
.pipeline-info {
|
74 |
+
padding: 0 0 0 2px;
|
75 |
+
font-weight: var(--block-info-text-weight);
|
76 |
+
font-size: var(--block-info-text-size);
|
77 |
+
color: var(--block-info-text-color);
|
78 |
+
}
|
79 |
+
|
80 |
+
.pipeline-help a {
|
81 |
+
color: var(--secondary-400);
|
82 |
+
}
|
83 |
+
|
84 |
+
.pipeline-help a:hover {
|
85 |
+
color: var(--secondary-500);
|
86 |
+
}
|
87 |
+
|
88 |
+
.pipeline-header {
|
89 |
+
padding: 2px 0px 0px 2px;
|
90 |
+
color: var(--body-text-color);
|
91 |
+
}
|
92 |
+
|
93 |
+
.pipeline-description {
|
94 |
+
margin: auto;
|
95 |
+
color: var(--body-text-color);
|
96 |
+
}
|
97 |
+
|
98 |
+
.button-group-viz {
|
99 |
+
margin: auto;
|
100 |
+
display: flex;
|
101 |
+
justify-content: center;
|
102 |
+
gap: 1rem;
|
103 |
+
text-align: center;
|
104 |
+
}
|
105 |
+
|
106 |
+
.modal-block {
|
107 |
+
width: 60%;
|
108 |
+
padding: 1rem;
|
109 |
+
}
|
110 |
+
|
111 |
+
@media (max-width: 1024px) { /* mobile and standing iPads */
|
112 |
+
.modal-block {
|
113 |
+
width: 100%;
|
114 |
+
}
|
115 |
+
}
|
116 |
+
|
117 |
+
|
118 |
+
"""
|
app/main.py
ADDED
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import logging
|
2 |
+
import os
|
3 |
+
|
4 |
+
import gradio as gr
|
5 |
+
# from htrflow.models.huggingface.trocr import TrOCR
|
6 |
+
|
7 |
+
from app.gradio_config import css, theme
|
8 |
+
|
9 |
+
# from app.tabs.export import collection as collection_export_state
|
10 |
+
# from app.tabs.export import export
|
11 |
+
from app.tabs.submit import collection_submit_state, submit
|
12 |
+
|
13 |
+
# from app.tabs.visualizer import collection as collection_viz_state
|
14 |
+
# from app.tabs.visualizer import visualizer
|
15 |
+
|
16 |
+
# Suppress transformers logging
|
17 |
+
logging.getLogger("transformers").setLevel(logging.ERROR)
|
18 |
+
|
19 |
+
|
20 |
+
TEMPLATE_YAML_FOLDER = "app/assets/templates"
|
21 |
+
gr.set_static_paths(paths=[TEMPLATE_YAML_FOLDER])
|
22 |
+
|
23 |
+
|
24 |
+
def load_markdown(language, section, content_dir="app/content"):
|
25 |
+
"""Load markdown content from files."""
|
26 |
+
if language is None:
|
27 |
+
file_path = os.path.join(content_dir, f"{section}.md")
|
28 |
+
else:
|
29 |
+
file_path = os.path.join(content_dir, language, f"{section}.md")
|
30 |
+
|
31 |
+
if os.path.exists(file_path):
|
32 |
+
with open(file_path, "r", encoding="utf-8") as f:
|
33 |
+
return f.read()
|
34 |
+
return f"## Content missing for {file_path} in {language}"
|
35 |
+
|
36 |
+
|
37 |
+
def activate_tab(collection):
|
38 |
+
return gr.update(interactive=collection is not None)
|
39 |
+
|
40 |
+
|
41 |
+
html_header = ""
|
42 |
+
|
43 |
+
|
44 |
+
with gr.Blocks(title="Dawsonia Demo", theme=theme, css=css, head=html_header) as demo:
|
45 |
+
with gr.Row():
|
46 |
+
with gr.Column(scale=1):
|
47 |
+
pass
|
48 |
+
with gr.Column(scale=2):
|
49 |
+
gr.Markdown(load_markdown(None, "main_title"))
|
50 |
+
with gr.Column(scale=1):
|
51 |
+
gr.Markdown(load_markdown(None, "main_sub_title"))
|
52 |
+
|
53 |
+
with gr.Tabs(elem_classes="top-navbar") as navbar:
|
54 |
+
with gr.Tab(label="Upload") as tab_submit:
|
55 |
+
submit.render()
|
56 |
+
|
57 |
+
# with gr.Tab(label="Result", interactive=False, id="result") as tab_visualizer:
|
58 |
+
# visualizer.render()
|
59 |
+
#
|
60 |
+
# with gr.Tab(label="Export", interactive=False) as tab_export:
|
61 |
+
# export.render()
|
62 |
+
|
63 |
+
# @demo.load()
|
64 |
+
# def inital_trocr_load():
|
65 |
+
# TrOCR("Riksarkivet/trocr-base-handwritten-hist-swe-2")
|
66 |
+
|
67 |
+
def sync_gradio_object_state(input_value, state_value):
|
68 |
+
"""Synchronize the Collection."""
|
69 |
+
state_value = input_value
|
70 |
+
return state_value if state_value is not None else gr.skip()
|
71 |
+
|
72 |
+
# collection_submit_state.change(
|
73 |
+
# activate_tab, collection_submit_state, tab_visualizer
|
74 |
+
# )
|
75 |
+
# collection_submit_state.change(activate_tab, collection_submit_state, tab_export)
|
76 |
+
collection_submit_state.change(lambda: gr.Tabs(selected="result"), outputs=navbar)
|
77 |
+
|
78 |
+
# tab_visualizer.select(
|
79 |
+
# inputs=[collection_submit_state, collection_viz_state],
|
80 |
+
# outputs=[collection_viz_state],
|
81 |
+
# fn=sync_gradio_object_state,
|
82 |
+
# )
|
83 |
+
#
|
84 |
+
# tab_export.select(
|
85 |
+
# inputs=[collection_submit_state, collection_export_state],
|
86 |
+
# outputs=[collection_export_state],
|
87 |
+
# fn=sync_gradio_object_state,
|
88 |
+
# )
|
89 |
+
|
90 |
+
demo.queue()
|
91 |
+
|
92 |
+
if __name__ == "__main__":
|
93 |
+
demo.launch(
|
94 |
+
server_name="0.0.0.0", server_port=7860, enable_monitoring=True, show_api=False
|
95 |
+
)
|
app/tabs/__init__.py
ADDED
File without changes
|
app/tabs/submit.py
ADDED
@@ -0,0 +1,245 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import logging
|
2 |
+
import os
|
3 |
+
import time
|
4 |
+
|
5 |
+
import numpy as np
|
6 |
+
import pandas as pd
|
7 |
+
from pathlib import Path
|
8 |
+
from dawsonia import io
|
9 |
+
from dawsonia import digitize
|
10 |
+
from dawsonia.ml import ml
|
11 |
+
import pooch
|
12 |
+
import gradio as gr
|
13 |
+
import yaml
|
14 |
+
from gradio_modal import Modal
|
15 |
+
|
16 |
+
logger = logging.getLogger(__name__)
|
17 |
+
|
18 |
+
# Max number of images a user can upload at once
|
19 |
+
MAX_IMAGES = int(os.environ.get("MAX_IMAGES", 5))
|
20 |
+
|
21 |
+
# Setup the cache directory to point to the directory where the example images
|
22 |
+
# are located. The images must lay in the cache directory because otherwise they
|
23 |
+
# have to be reuploaded when drag-and-dropped to the input image widget.
|
24 |
+
GRADIO_CACHE = ".gradio_cache"
|
25 |
+
DATA_CACHE = os.path.join(GRADIO_CACHE, "data")
|
26 |
+
EXAMPLES_DIRECTORY = os.path.join(os.getcwd(), "examples")
|
27 |
+
|
28 |
+
# Example books
|
29 |
+
PIPELINES: dict[str, dict[str, str]] = {
|
30 |
+
"bjuröklubb": dict(
|
31 |
+
url="https://git.smhi.se/ai-for-obs/data/-/raw/688c04f13e8e946962792fe4b4e0ded98800b154/raw_zarr/BJUR%C3%96KLUBB/DAGBOK_Bjur%C3%B6klubb_Station_Jan-Dec_1928.zarr.zip",
|
32 |
+
known_hash="sha256:6d87b7f79836ae6373cfab11260fe28787d93fe16199fefede6697ccd750f71a",
|
33 |
+
)
|
34 |
+
}
|
35 |
+
|
36 |
+
if os.environ.get("GRADIO_CACHE_DIR", GRADIO_CACHE) != GRADIO_CACHE:
|
37 |
+
os.environ["GRADIO_CACHE_DIR"] = GRADIO_CACHE
|
38 |
+
logger.warning("Setting GRADIO_CACHE_DIR to '%s' (overriding a previous value).")
|
39 |
+
|
40 |
+
|
41 |
+
def run_dawsonia(
|
42 |
+
table_fmt_config_override, batch_image_gallery, book, progress=gr.Progress()
|
43 |
+
):
|
44 |
+
if None in (batch_image_gallery, book) or len(batch_image_gallery) == 0:
|
45 |
+
raise ValueError("You need to select / upload the pages to digitize")
|
46 |
+
progress(0, desc="Dawsonia: starting")
|
47 |
+
|
48 |
+
model_path = Path("data/models/dawsonia/2024-07-02")
|
49 |
+
output_path = Path(GRADIO_CACHE, "output")
|
50 |
+
|
51 |
+
print("Dawsonia: digitizing", book)
|
52 |
+
table_fmt = book.table_format
|
53 |
+
|
54 |
+
output_path_book = output_path / book.station_name / book._name
|
55 |
+
output_path_book.mkdir(exist_ok=True, parents=True)
|
56 |
+
(output_path_book / "probablities").mkdir(exist_ok=True)
|
57 |
+
|
58 |
+
init_data: list[dict[str, NDArray]] = [
|
59 |
+
{
|
60 |
+
key: np.empty(len(table_fmt.rows), dtype="O")
|
61 |
+
for key in table_fmt.columns[table_idx]
|
62 |
+
}
|
63 |
+
for table_idx in table_fmt.preproc.idx_tables_size_verify
|
64 |
+
]
|
65 |
+
|
66 |
+
for page_number in range(len(batch_image_gallery)):
|
67 |
+
output_path_page = output_path_book / str(page_number)
|
68 |
+
results = [
|
69 |
+
digitize.digitize_page_and_write_output(
|
70 |
+
book,
|
71 |
+
init_data,
|
72 |
+
page_number=page_number + 3,
|
73 |
+
date_str="2022-02-02",
|
74 |
+
model_path=model_path,
|
75 |
+
model_predict=ml.model_predict,
|
76 |
+
prob_thresh=0.5,
|
77 |
+
output_path_page=output_path_page,
|
78 |
+
output_text_fmt=True,
|
79 |
+
debug=True,
|
80 |
+
)
|
81 |
+
]
|
82 |
+
|
83 |
+
collection = []
|
84 |
+
time.sleep(1)
|
85 |
+
gr.Info("Pages were succesfully digitized ✨")
|
86 |
+
|
87 |
+
yield collection, gr.skip()
|
88 |
+
|
89 |
+
|
90 |
+
def all_example_images() -> list[str]:
|
91 |
+
"""
|
92 |
+
Get paths to all example images.
|
93 |
+
"""
|
94 |
+
examples = [
|
95 |
+
os.path.join(EXAMPLES_DIRECTORY, f"{pipeline}.png") for pipeline in PIPELINES
|
96 |
+
]
|
97 |
+
return examples
|
98 |
+
|
99 |
+
|
100 |
+
def get_selected_example_image(
|
101 |
+
first_page, last_page, event: gr.SelectData
|
102 |
+
) -> tuple[str, io.Book] | None:
|
103 |
+
"""
|
104 |
+
Get the name of the pipeline that corresponds to the selected image.
|
105 |
+
"""
|
106 |
+
# for name, details in PIPELINES.items():
|
107 |
+
name, _ext = event.value["image"]["orig_name"].split(".")
|
108 |
+
|
109 |
+
if name in PIPELINES:
|
110 |
+
book_path = pooch.retrieve(**PIPELINES[name], path=DATA_CACHE)
|
111 |
+
first, last, book = io.read_book(book_path)
|
112 |
+
book._name = name
|
113 |
+
book.size_cell = [1.0, 1.0, 1.0, 1.0]
|
114 |
+
return [book.read_image(pg) for pg in range(first_page, last_page)], book
|
115 |
+
|
116 |
+
|
117 |
+
table_fmt_config_override_placeholder = (
|
118 |
+
"""\
|
119 |
+
[default]
|
120 |
+
version = 0
|
121 |
+
|
122 |
+
# Default values, but wrote explicitly here. See PreprocConfig class
|
123 |
+
[default.preproc]
|
124 |
+
table_modif = true
|
125 |
+
corr_rotate = true
|
126 |
+
row_idx_unit = "HOURS"
|
127 |
+
idx_tables_size_verify = [0, 1]
|
128 |
+
|
129 |
+
[version.0]
|
130 |
+
columns = [
|
131 |
+
[
|
132 |
+
"term_på_baro",
|
133 |
+
"barom",
|
134 |
+
"torra_term",
|
135 |
+
"våta_term",
|
136 |
+
"moln_slag_lägre",
|
137 |
+
"moln_mängd_lägre",
|
138 |
+
"moln_slag_medel",
|
139 |
+
"moln_slag_högre"
|
140 |
+
],
|
141 |
+
[
|
142 |
+
"moln_het_sol_dimma_nederbörd_total",
|
143 |
+
"vind_riktning",
|
144 |
+
"vind_beaufort",
|
145 |
+
"vind_m_sek",
|
146 |
+
"sikt",
|
147 |
+
"sjögang",
|
148 |
+
"maximi_term",
|
149 |
+
"minimi_term",
|
150 |
+
"nederbörd_mängd",
|
151 |
+
"nederbörd_slag"
|
152 |
+
]
|
153 |
+
]
|
154 |
+
name_idx = "tid"
|
155 |
+
rows = [2, 8, 14, 19, 21]
|
156 |
+
tables = [
|
157 |
+
[5, 8],
|
158 |
+
[5, 10],
|
159 |
+
[3, 1],
|
160 |
+
[4, 2],
|
161 |
+
[4, 5]
|
162 |
+
]
|
163 |
+
""",
|
164 |
+
)
|
165 |
+
|
166 |
+
with gr.Blocks() as submit:
|
167 |
+
gr.Markdown("# Upload")
|
168 |
+
gr.Markdown(
|
169 |
+
"Select or upload the image you want to transcribe. You can upload up to five images at a time."
|
170 |
+
)
|
171 |
+
|
172 |
+
batch_book_state = gr.State()
|
173 |
+
collection_submit_state = gr.State()
|
174 |
+
|
175 |
+
with gr.Group():
|
176 |
+
with gr.Row(equal_height=True):
|
177 |
+
with gr.Column(scale=5):
|
178 |
+
batch_image_gallery = gr.Gallery(
|
179 |
+
file_types=["image"],
|
180 |
+
label="Image to digitize",
|
181 |
+
interactive=True,
|
182 |
+
object_fit="scale-down",
|
183 |
+
scale=10,
|
184 |
+
)
|
185 |
+
|
186 |
+
with gr.Column(scale=2):
|
187 |
+
first_page = gr.Number(3, label="First page of the book", precision=0)
|
188 |
+
last_page = gr.Number(4, label="Last page of the book", precision=0)
|
189 |
+
examples = gr.Gallery(
|
190 |
+
all_example_images(),
|
191 |
+
label="Examples",
|
192 |
+
interactive=False,
|
193 |
+
allow_preview=False,
|
194 |
+
object_fit="scale-down",
|
195 |
+
min_width=250,
|
196 |
+
)
|
197 |
+
|
198 |
+
with Modal(visible=False) as edit_table_fmt_modal:
|
199 |
+
with gr.Column():
|
200 |
+
gr.Markdown(
|
201 |
+
"## Table format configuration\n"
|
202 |
+
"Write a custom table format, overriding the default one. "
|
203 |
+
"Close [x] the popup when you are done."
|
204 |
+
)
|
205 |
+
table_fmt_config_override = gr.Code("", language="python")
|
206 |
+
gr.HTML(
|
207 |
+
(
|
208 |
+
"<a href='https://dawsonia.readthedocs.io/en/latest/user_guide/misc.html#table-formats' target='_blank'>"
|
209 |
+
"Read the docs for the table-formats spec"
|
210 |
+
"</a>. "
|
211 |
+
),
|
212 |
+
padding=False,
|
213 |
+
elem_classes="pipeline-help",
|
214 |
+
)
|
215 |
+
|
216 |
+
with gr.Row():
|
217 |
+
run_button = gr.Button("Digitize", variant="primary", scale=0, min_width=200)
|
218 |
+
edit_table_fmt_button = gr.Button(
|
219 |
+
"Edit table format", variant="secondary", scale=0, min_width=200
|
220 |
+
)
|
221 |
+
|
222 |
+
# All events interactions below
|
223 |
+
|
224 |
+
examples.select(
|
225 |
+
get_selected_example_image,
|
226 |
+
(first_page, last_page),
|
227 |
+
(batch_image_gallery, batch_book_state),
|
228 |
+
)
|
229 |
+
|
230 |
+
@batch_image_gallery.upload(
|
231 |
+
inputs=batch_image_gallery,
|
232 |
+
outputs=[batch_image_gallery],
|
233 |
+
)
|
234 |
+
def validate_images(images):
|
235 |
+
if len(images) > MAX_IMAGES:
|
236 |
+
gr.Warning(f"Maximum images you can upload is set to: {MAX_IMAGES}")
|
237 |
+
return gr.update(value=None)
|
238 |
+
return images
|
239 |
+
|
240 |
+
run_button.click(
|
241 |
+
fn=run_dawsonia,
|
242 |
+
inputs=[table_fmt_config_override, batch_image_gallery, batch_book_state],
|
243 |
+
outputs=[collection_submit_state, batch_image_gallery],
|
244 |
+
)
|
245 |
+
edit_table_fmt_button.click(lambda: Modal(visible=True), None, edit_table_fmt_modal)
|
pyproject.toml
CHANGED
@@ -6,7 +6,8 @@ readme = "README.md"
|
|
6 |
requires-python = ">=3.10"
|
7 |
dependencies = [
|
8 |
"dawsonia[cuda]",
|
9 |
-
"
|
|
|
10 |
"pyarrow>=19.0.0",
|
11 |
"typer<0.14",
|
12 |
]
|
|
|
6 |
requires-python = ">=3.10"
|
7 |
dependencies = [
|
8 |
"dawsonia[cuda]",
|
9 |
+
"gradio>=5.15.0",
|
10 |
+
"gradio-modal>=0.0.4",
|
11 |
"pyarrow>=19.0.0",
|
12 |
"typer<0.14",
|
13 |
]
|
uv.lock
CHANGED
The diff for this file is too large to render.
See raw diff
|
|