Spaces:
Running on Zero
Running on Zero
api
Browse files- apitest.py +9 -0
- app.py +99 -19
- pytest.ini +1 -0
- tests/test_markup.py +22 -0
- tests/test_online_api.py +14 -0
apitest.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from gradio_client import Client
|
| 2 |
+
|
| 3 |
+
client = Client("al1808th/macronizer")
|
| 4 |
+
result = client.predict(
|
| 5 |
+
text="νεανίας ἀάατός ἐστιν καὶ καλός. τὰ παῖδες τὰ καλά",
|
| 6 |
+
model_label="Macronizer Mega v1 (Pretrained ModernBERT)",
|
| 7 |
+
api_name="/render_results",
|
| 8 |
+
)
|
| 9 |
+
print(result)
|
app.py
CHANGED
|
@@ -499,6 +499,14 @@ def render_results(text: str, model_label: str):
|
|
| 499 |
return html_result, "\n".join(plain_lines)
|
| 500 |
|
| 501 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 502 |
examples = [
|
| 503 |
"νεανίας ἀάατός ἐστιν καὶ καλός. τὰ παῖδες τὰ καλά\nκαλὰ μὲν ἠέξευ, καλὰ δ᾽ ἔτραφες, οὐράνιε Ζεῦ,",
|
| 504 |
"Ἆρες, Ἄρες βροτολοιγὲ μιαιφόνε τειχεσιπλῆτα\nἈτρεΐδαι τε καὶ ἄλλοι ἐϋκνήμιδες Ἀχαιοί",
|
|
@@ -542,7 +550,9 @@ CSS = """
|
|
| 542 |
}
|
| 543 |
|
| 544 |
html.dark-mode,
|
| 545 |
-
body.dark-mode
|
|
|
|
|
|
|
| 546 |
--bg-start: #050506;
|
| 547 |
--bg-end: #101015;
|
| 548 |
--ink: #f3f3f8;
|
|
@@ -558,7 +568,9 @@ body.dark-mode {
|
|
| 558 |
}
|
| 559 |
|
| 560 |
html.light-mode,
|
| 561 |
-
body.light-mode
|
|
|
|
|
|
|
| 562 |
--bg-start: #f5f0e8;
|
| 563 |
--bg-end: #e8edf4;
|
| 564 |
--ink: #23242a;
|
|
@@ -576,14 +588,27 @@ body.light-mode {
|
|
| 576 |
.gradio-container {
|
| 577 |
font-family: 'Space Grotesk', sans-serif;
|
| 578 |
background: radial-gradient(circle at top left, var(--bg-start), var(--bg-end));
|
| 579 |
-
color: var(--ink);
|
| 580 |
transition: background-color 0.3s, color 0.3s;
|
|
|
|
| 581 |
}
|
| 582 |
|
| 583 |
-
|
| 584 |
-
position: fixed;
|
| 585 |
top: 20px;
|
| 586 |
right: 20px;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 587 |
background: var(--paper);
|
| 588 |
border: 2px solid var(--ink);
|
| 589 |
color: var(--ink);
|
|
@@ -593,15 +618,28 @@ body.light-mode {
|
|
| 593 |
font-weight: 600;
|
| 594 |
font-family: 'Space Grotesk', sans-serif;
|
| 595 |
font-size: 0.95rem;
|
| 596 |
-
|
|
|
|
|
|
|
| 597 |
transition: all 0.3s;
|
| 598 |
}
|
| 599 |
|
| 600 |
-
|
|
|
|
|
|
|
| 601 |
transform: scale(1.05);
|
| 602 |
opacity: 0.9;
|
| 603 |
}
|
| 604 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 605 |
.title h1 {
|
| 606 |
font-family: 'Cormorant Garamond', serif;
|
| 607 |
font-size: 3rem;
|
|
@@ -629,7 +667,12 @@ body.light-mode {
|
|
| 629 |
.panel .gr-markdown,
|
| 630 |
.panel .gradio-markdown,
|
| 631 |
.panel .gr-form label,
|
| 632 |
-
.panel .gr-form span
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 633 |
color: var(--ink) !important;
|
| 634 |
}
|
| 635 |
|
|
@@ -641,7 +684,10 @@ body.light-mode {
|
|
| 641 |
.panel .gr-radio,
|
| 642 |
.panel .gr-radio label,
|
| 643 |
.panel .gr-box,
|
| 644 |
-
.panel .gr-form
|
|
|
|
|
|
|
|
|
|
| 645 |
color: var(--ink) !important;
|
| 646 |
}
|
| 647 |
|
|
@@ -659,7 +705,7 @@ body.light-mode {
|
|
| 659 |
|
| 660 |
.dark-mode .panel .gr-button,
|
| 661 |
.dark-mode .panel button {
|
| 662 |
-
color:
|
| 663 |
border-color: rgba(232, 228, 220, 0.28) !important;
|
| 664 |
}
|
| 665 |
|
|
@@ -669,6 +715,10 @@ body.light-mode {
|
|
| 669 |
color: #f7f9ff !important;
|
| 670 |
}
|
| 671 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 672 |
.legend {
|
| 673 |
display: flex;
|
| 674 |
align-items: center;
|
|
@@ -755,11 +805,10 @@ body.light-mode {
|
|
| 755 |
|
| 756 |
@media (max-width: 820px) {
|
| 757 |
.title h1 { font-size: 2.2rem; }
|
| 758 |
-
|
| 759 |
-
position:
|
| 760 |
-
top:
|
| 761 |
-
right:
|
| 762 |
-
margin-bottom: 1rem;
|
| 763 |
}
|
| 764 |
}
|
| 765 |
"""
|
|
@@ -770,9 +819,11 @@ THEME_INIT_JS = """
|
|
| 770 |
const isDark = mode === 'dark';
|
| 771 |
document.documentElement.classList.toggle('dark-mode', isDark);
|
| 772 |
document.documentElement.classList.toggle('light-mode', !isDark);
|
|
|
|
| 773 |
if (document.body) {
|
| 774 |
document.body.classList.toggle('dark-mode', isDark);
|
| 775 |
document.body.classList.toggle('light-mode', !isDark);
|
|
|
|
| 776 |
}
|
| 777 |
return isDark ? 'Light Mode' : 'Dark Mode';
|
| 778 |
}
|
|
@@ -791,9 +842,11 @@ THEME_TOGGLE_JS = """
|
|
| 791 |
const isDark = mode === 'dark';
|
| 792 |
document.documentElement.classList.toggle('dark-mode', isDark);
|
| 793 |
document.documentElement.classList.toggle('light-mode', !isDark);
|
|
|
|
| 794 |
if (document.body) {
|
| 795 |
document.body.classList.toggle('dark-mode', isDark);
|
| 796 |
document.body.classList.toggle('light-mode', !isDark);
|
|
|
|
| 797 |
}
|
| 798 |
localStorage.setItem('themeMode', mode);
|
| 799 |
return isDark ? 'Light Mode' : 'Dark Mode';
|
|
@@ -816,7 +869,10 @@ with gr.Blocks() as demo:
|
|
| 816 |
"""
|
| 817 |
<div class="title">
|
| 818 |
<h1>Ancient Greek Macronizer</h1>
|
| 819 |
-
<p>
|
|
|
|
|
|
|
|
|
|
| 820 |
</div>
|
| 821 |
"""
|
| 822 |
)
|
|
@@ -836,14 +892,38 @@ with gr.Blocks() as demo:
|
|
| 836 |
with gr.Row():
|
| 837 |
classify_btn = gr.Button("Classify", variant="primary")
|
| 838 |
clear_btn = gr.Button("Clear")
|
| 839 |
-
gr.Examples(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 840 |
|
| 841 |
with gr.Column(elem_classes=["panel"]):
|
| 842 |
html_output = gr.HTML(label="Styled Results")
|
| 843 |
text_output = gr.Textbox(label="Plain Output", lines=12, buttons=["copy"])
|
| 844 |
|
| 845 |
-
|
| 846 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 847 |
theme_toggle.click(fn=None, inputs=None, outputs=theme_toggle, js=THEME_TOGGLE_JS)
|
| 848 |
demo.load(fn=None, inputs=None, outputs=theme_toggle, js=THEME_INIT_JS)
|
| 849 |
|
|
|
|
| 499 |
return html_result, "\n".join(plain_lines)
|
| 500 |
|
| 501 |
|
| 502 |
+
def render_plain_output(text: str) -> str:
|
| 503 |
+
lines = [line.strip() for line in text.splitlines() if line.strip()]
|
| 504 |
+
if not lines:
|
| 505 |
+
return ""
|
| 506 |
+
|
| 507 |
+
return "\n".join(_render_plain_line_per_word(line, DEFAULT_MODEL_ID) for line in lines)
|
| 508 |
+
|
| 509 |
+
|
| 510 |
examples = [
|
| 511 |
"νεανίας ἀάατός ἐστιν καὶ καλός. τὰ παῖδες τὰ καλά\nκαλὰ μὲν ἠέξευ, καλὰ δ᾽ ἔτραφες, οὐράνιε Ζεῦ,",
|
| 512 |
"Ἆρες, Ἄρες βροτολοιγὲ μιαιφόνε τειχεσιπλῆτα\nἈτρεΐδαι τε καὶ ἄλλοι ἐϋκνήμιδες Ἀχαιοί",
|
|
|
|
| 550 |
}
|
| 551 |
|
| 552 |
html.dark-mode,
|
| 553 |
+
body.dark-mode,
|
| 554 |
+
html[data-theme="dark"],
|
| 555 |
+
body[data-theme="dark"] {
|
| 556 |
--bg-start: #050506;
|
| 557 |
--bg-end: #101015;
|
| 558 |
--ink: #f3f3f8;
|
|
|
|
| 568 |
}
|
| 569 |
|
| 570 |
html.light-mode,
|
| 571 |
+
body.light-mode,
|
| 572 |
+
html[data-theme="light"],
|
| 573 |
+
body[data-theme="light"] {
|
| 574 |
--bg-start: #f5f0e8;
|
| 575 |
--bg-end: #e8edf4;
|
| 576 |
--ink: #23242a;
|
|
|
|
| 588 |
.gradio-container {
|
| 589 |
font-family: 'Space Grotesk', sans-serif;
|
| 590 |
background: radial-gradient(circle at top left, var(--bg-start), var(--bg-end));
|
| 591 |
+
color: var(--ink) !important;
|
| 592 |
transition: background-color 0.3s, color 0.3s;
|
| 593 |
+
min-height: 100vh;
|
| 594 |
}
|
| 595 |
|
| 596 |
+
#dark-mode-toggle {
|
| 597 |
+
position: fixed !important;
|
| 598 |
top: 20px;
|
| 599 |
right: 20px;
|
| 600 |
+
width: auto !important;
|
| 601 |
+
min-width: 0 !important;
|
| 602 |
+
max-width: max-content !important;
|
| 603 |
+
flex: 0 0 auto !important;
|
| 604 |
+
display: inline-flex !important;
|
| 605 |
+
z-index: 1000;
|
| 606 |
+
}
|
| 607 |
+
|
| 608 |
+
#dark-mode-toggle button,
|
| 609 |
+
#dark-mode-toggle .gr-button,
|
| 610 |
+
.dark-mode-toggle button,
|
| 611 |
+
button.dark-mode-toggle {
|
| 612 |
background: var(--paper);
|
| 613 |
border: 2px solid var(--ink);
|
| 614 |
color: var(--ink);
|
|
|
|
| 618 |
font-weight: 600;
|
| 619 |
font-family: 'Space Grotesk', sans-serif;
|
| 620 |
font-size: 0.95rem;
|
| 621 |
+
width: auto !important;
|
| 622 |
+
min-width: 0 !important;
|
| 623 |
+
white-space: nowrap;
|
| 624 |
transition: all 0.3s;
|
| 625 |
}
|
| 626 |
|
| 627 |
+
#dark-mode-toggle:hover,
|
| 628 |
+
#dark-mode-toggle button:hover,
|
| 629 |
+
.dark-mode-toggle button:hover {
|
| 630 |
transform: scale(1.05);
|
| 631 |
opacity: 0.9;
|
| 632 |
}
|
| 633 |
|
| 634 |
+
.title,
|
| 635 |
+
.title h1,
|
| 636 |
+
.title p,
|
| 637 |
+
.gradio-container .title,
|
| 638 |
+
.gradio-container .title h1,
|
| 639 |
+
.gradio-container .title p {
|
| 640 |
+
color: var(--ink) !important;
|
| 641 |
+
}
|
| 642 |
+
|
| 643 |
.title h1 {
|
| 644 |
font-family: 'Cormorant Garamond', serif;
|
| 645 |
font-size: 3rem;
|
|
|
|
| 667 |
.panel .gr-markdown,
|
| 668 |
.panel .gradio-markdown,
|
| 669 |
.panel .gr-form label,
|
| 670 |
+
.panel .gr-form span,
|
| 671 |
+
.panel span,
|
| 672 |
+
.panel p,
|
| 673 |
+
.panel button,
|
| 674 |
+
.panel .prose,
|
| 675 |
+
.panel .prose * {
|
| 676 |
color: var(--ink) !important;
|
| 677 |
}
|
| 678 |
|
|
|
|
| 684 |
.panel .gr-radio,
|
| 685 |
.panel .gr-radio label,
|
| 686 |
.panel .gr-box,
|
| 687 |
+
.panel .gr-form,
|
| 688 |
+
.panel .wrap,
|
| 689 |
+
.panel .block,
|
| 690 |
+
.panel .block * {
|
| 691 |
color: var(--ink) !important;
|
| 692 |
}
|
| 693 |
|
|
|
|
| 705 |
|
| 706 |
.dark-mode .panel .gr-button,
|
| 707 |
.dark-mode .panel button {
|
| 708 |
+
color: var(--ink) !important;
|
| 709 |
border-color: rgba(232, 228, 220, 0.28) !important;
|
| 710 |
}
|
| 711 |
|
|
|
|
| 715 |
color: #f7f9ff !important;
|
| 716 |
}
|
| 717 |
|
| 718 |
+
#try-examples .example-text {
|
| 719 |
+
white-space: pre-wrap;
|
| 720 |
+
}
|
| 721 |
+
|
| 722 |
.legend {
|
| 723 |
display: flex;
|
| 724 |
align-items: center;
|
|
|
|
| 805 |
|
| 806 |
@media (max-width: 820px) {
|
| 807 |
.title h1 { font-size: 2.2rem; }
|
| 808 |
+
#dark-mode-toggle {
|
| 809 |
+
position: fixed !important;
|
| 810 |
+
top: 12px;
|
| 811 |
+
right: 12px;
|
|
|
|
| 812 |
}
|
| 813 |
}
|
| 814 |
"""
|
|
|
|
| 819 |
const isDark = mode === 'dark';
|
| 820 |
document.documentElement.classList.toggle('dark-mode', isDark);
|
| 821 |
document.documentElement.classList.toggle('light-mode', !isDark);
|
| 822 |
+
document.documentElement.dataset.theme = mode;
|
| 823 |
if (document.body) {
|
| 824 |
document.body.classList.toggle('dark-mode', isDark);
|
| 825 |
document.body.classList.toggle('light-mode', !isDark);
|
| 826 |
+
document.body.dataset.theme = mode;
|
| 827 |
}
|
| 828 |
return isDark ? 'Light Mode' : 'Dark Mode';
|
| 829 |
}
|
|
|
|
| 842 |
const isDark = mode === 'dark';
|
| 843 |
document.documentElement.classList.toggle('dark-mode', isDark);
|
| 844 |
document.documentElement.classList.toggle('light-mode', !isDark);
|
| 845 |
+
document.documentElement.dataset.theme = mode;
|
| 846 |
if (document.body) {
|
| 847 |
document.body.classList.toggle('dark-mode', isDark);
|
| 848 |
document.body.classList.toggle('light-mode', !isDark);
|
| 849 |
+
document.body.dataset.theme = mode;
|
| 850 |
}
|
| 851 |
localStorage.setItem('themeMode', mode);
|
| 852 |
return isDark ? 'Light Mode' : 'Dark Mode';
|
|
|
|
| 869 |
"""
|
| 870 |
<div class="title">
|
| 871 |
<h1>Ancient Greek Macronizer</h1>
|
| 872 |
+
<p>
|
| 873 |
+
Enter Ancient Greek to have the alphas, iotas and ypsilons marked as long or short. <br><br>
|
| 874 |
+
Made by Albin Thörn Cleland (Lund university) and Eric Cullhed (Uppsala university). Training the models was made possible by resources provided by the National Academic Infrastructure for Supercomputing in Sweden (NAISS), partially funded by the Swedish Research Council (grant agreement no. 2022-06725).
|
| 875 |
+
</p>
|
| 876 |
</div>
|
| 877 |
"""
|
| 878 |
)
|
|
|
|
| 892 |
with gr.Row():
|
| 893 |
classify_btn = gr.Button("Classify", variant="primary")
|
| 894 |
clear_btn = gr.Button("Clear")
|
| 895 |
+
gr.Examples(
|
| 896 |
+
examples=examples,
|
| 897 |
+
inputs=text_input,
|
| 898 |
+
label="Try examples",
|
| 899 |
+
elem_id="try-examples",
|
| 900 |
+
)
|
| 901 |
|
| 902 |
with gr.Column(elem_classes=["panel"]):
|
| 903 |
html_output = gr.HTML(label="Styled Results")
|
| 904 |
text_output = gr.Textbox(label="Plain Output", lines=12, buttons=["copy"])
|
| 905 |
|
| 906 |
+
api_text = gr.Textbox(label="text", visible=False)
|
| 907 |
+
api_output = gr.Textbox(label="plain_output", visible=False)
|
| 908 |
+
api_btn = gr.Button("API", visible=False)
|
| 909 |
+
|
| 910 |
+
classify_btn.click(
|
| 911 |
+
render_results,
|
| 912 |
+
inputs=[text_input, model_choice],
|
| 913 |
+
outputs=[html_output, text_output],
|
| 914 |
+
api_name=False,
|
| 915 |
+
)
|
| 916 |
+
clear_btn.click(
|
| 917 |
+
lambda: ("", "", ""),
|
| 918 |
+
outputs=[text_input, html_output, text_output],
|
| 919 |
+
api_name=False,
|
| 920 |
+
)
|
| 921 |
+
api_btn.click(
|
| 922 |
+
render_plain_output,
|
| 923 |
+
inputs=api_text,
|
| 924 |
+
outputs=api_output,
|
| 925 |
+
api_name="render_results",
|
| 926 |
+
)
|
| 927 |
theme_toggle.click(fn=None, inputs=None, outputs=theme_toggle, js=THEME_TOGGLE_JS)
|
| 928 |
demo.load(fn=None, inputs=None, outputs=theme_toggle, js=THEME_INIT_JS)
|
| 929 |
|
pytest.ini
CHANGED
|
@@ -10,3 +10,4 @@ addopts = -v --tb=short
|
|
| 10 |
# Markers
|
| 11 |
markers =
|
| 12 |
markup: Tests for markup output preservation
|
|
|
|
|
|
| 10 |
# Markers
|
| 11 |
markers =
|
| 12 |
markup: Tests for markup output preservation
|
| 13 |
+
online_api: Tests that call the hosted Gradio API
|
tests/test_markup.py
CHANGED
|
@@ -18,6 +18,7 @@ from app import (
|
|
| 18 |
_render_plain_line_per_word,
|
| 19 |
_render_styled_line_per_word,
|
| 20 |
preprocess_and_syllabify,
|
|
|
|
| 21 |
render_results,
|
| 22 |
)
|
| 23 |
|
|
@@ -158,5 +159,26 @@ def test_plain_output_box_contains_only_output_lines(monkeypatch):
|
|
| 158 |
assert '<div class="line-output">alpha</div>' in html_output
|
| 159 |
|
| 160 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 161 |
if __name__ == "__main__":
|
| 162 |
pytest.main([__file__, "-v", "-s"])
|
|
|
|
| 18 |
_render_plain_line_per_word,
|
| 19 |
_render_styled_line_per_word,
|
| 20 |
preprocess_and_syllabify,
|
| 21 |
+
render_plain_output,
|
| 22 |
render_results,
|
| 23 |
)
|
| 24 |
|
|
|
|
| 159 |
assert '<div class="line-output">alpha</div>' in html_output
|
| 160 |
|
| 161 |
|
| 162 |
+
def test_api_returns_only_plain_output(monkeypatch):
|
| 163 |
+
monkeypatch.setattr("app._render_plain_line_per_word", lambda line, model_id: f"marked {line}")
|
| 164 |
+
|
| 165 |
+
assert render_plain_output("alpha\nbeta") == "marked alpha\nmarked beta"
|
| 166 |
+
|
| 167 |
+
|
| 168 |
+
def test_public_api_endpoint_is_plain_output_only():
|
| 169 |
+
import app
|
| 170 |
+
|
| 171 |
+
public_deps = [
|
| 172 |
+
dep
|
| 173 |
+
for dep in app.demo.config.get("dependencies", [])
|
| 174 |
+
if dep.get("api_name") == "render_results"
|
| 175 |
+
and dep.get("api_visibility") == "public"
|
| 176 |
+
]
|
| 177 |
+
|
| 178 |
+
assert len(public_deps) == 1
|
| 179 |
+
assert len(public_deps[0].get("inputs", [])) == 1
|
| 180 |
+
assert len(public_deps[0].get("outputs", [])) == 1
|
| 181 |
+
|
| 182 |
+
|
| 183 |
if __name__ == "__main__":
|
| 184 |
pytest.main([__file__, "-v", "-s"])
|
tests/test_online_api.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from gradio_client import Client
|
| 2 |
+
import pytest
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
@pytest.mark.online_api
|
| 6 |
+
def test_online_api_returns_plain_output_only():
|
| 7 |
+
client = Client("al1808th/macronizer")
|
| 8 |
+
|
| 9 |
+
result = client.predict(
|
| 10 |
+
text="νεανίας ἀάατός ἐστιν καὶ καλός. τὰ παῖδες τὰ καλά",
|
| 11 |
+
api_name="/render_results",
|
| 12 |
+
)
|
| 13 |
+
|
| 14 |
+
assert result == "νεα_νί^ας ἀ^ά_α^τός ἐστι^ν καὶ κα^λός. τὰ^ παῖδες τὰ^ κα_λά_"
|