import os os.environ["GRADIO_SSR_MODE"] = "False" import html import urllib.parse from pathlib import Path import gradio as gr import pandas as pd DATASETS = { "Lancelot": { "Reviewed": Path("sample_data/reviewed_lancelot.csv"), "Raw": Path("sample_data/raw_lancelot.csv"), }, "De regimine principum": { "Reviewed": Path("sample_data/reviewed_de_regimine.csv"), "Raw": Path("sample_data/raw_de_regimine.csv"), }, } def get_data_file(corpus_name, alignment_type): return DATASETS[corpus_name][alignment_type] def load_alignments(corpus_name, alignment_type): data_file = get_data_file(corpus_name, alignment_type) if not data_file.exists(): return pd.DataFrame({"segment_id": []}) df = pd.read_csv(data_file, sep=None, engine="python", dtype=str).fillna("") df = df.rename(columns={df.columns[0]: "segment_id"}) return df def get_segment_choices(corpus_name, alignment_type): df = load_alignments(corpus_name, alignment_type) if df.empty: return [] return df["segment_id"].astype(str).tolist() def search_segments(corpus_name, alignment_type, query): df = load_alignments(corpus_name, alignment_type) if df.empty: return [] if query is None or not str(query).strip(): return df["segment_id"].astype(str).tolist() query = str(query).strip().lower() matching_segments = [] for _, row in df.iterrows(): row_text = " ".join(str(value).lower() for value in row.values) if query in row_text: matching_segments.append(str(row["segment_id"])) return matching_segments def get_witness_choices(corpus_name, alignment_type): df = load_alignments(corpus_name, alignment_type) if df.empty: return [] witness_columns = [col for col in df.columns if col != "segment_id"] if len(witness_columns) <= 1: return [] return witness_columns[1:] def clean_witness_name(name): return str(name).replace("-", " ").upper() def view_segment(corpus_name, alignment_type, segment_id, selected_witnesses=None): df = load_alignments(corpus_name, alignment_type) if df.empty: return "
No data found for this corpus and alignment type.
" row_match = df[df["segment_id"].astype(str) == str(segment_id)] if row_match.empty: return "No segment selected.
" row = row_match.iloc[0] witness_columns = [col for col in df.columns if col != "segment_id"] if not witness_columns: return "No witness columns found.
" main_witness = witness_columns[0] other_witnesses = witness_columns[1:] if selected_witnesses: other_witnesses = [w for w in other_witnesses if w in selected_witnesses] main_text = str(row[main_witness]).strip() warning = "" if alignment_type == "Raw": warning = """No data found.
", df, corpus_notice(corpus_name, alignment_type), get_download_file(corpus_name, alignment_type), "", "", ) first_segment = segments[0] return ( gr.update(choices=segments, value=first_segment), "", gr.update(choices=witnesses, value=witnesses), view_segment(corpus_name, alignment_type, first_segment, witnesses), df, corpus_notice(corpus_name, alignment_type), get_download_file(corpus_name, alignment_type), make_issue_report(corpus_name, alignment_type, first_segment), make_github_issue_link(corpus_name, alignment_type, first_segment), ) def update_search(corpus_name, alignment_type, query, selected_witnesses): segments = search_segments(corpus_name, alignment_type, query) if not segments: return ( gr.update(choices=[], value=None), "No matching segment found.
", 'No data found.
", "", "", "", ) first_segment = segments[0] return ( gr.update(value=""), gr.update(choices=segments, value=first_segment), view_segment(corpus_name, alignment_type, first_segment, selected_witnesses), "", make_issue_report(corpus_name, alignment_type, first_segment), make_github_issue_link(corpus_name, alignment_type, first_segment), ) def move_segment(corpus_name, alignment_type, current_segment, query, selected_witnesses, direction): segments = search_segments(corpus_name, alignment_type, query) if not segments: return ( gr.update(choices=[], value=None), "No segment available.
", "", "", ) current_segment = str(current_segment) if current_segment in segments: current_index = segments.index(current_segment) else: current_index = 0 if direction == "previous": new_index = max(0, current_index - 1) else: new_index = min(len(segments) - 1, current_index + 1) new_segment = segments[new_index] return ( gr.update(choices=segments, value=new_segment), view_segment(corpus_name, alignment_type, new_segment, selected_witnesses), make_issue_report(corpus_name, alignment_type, new_segment), make_github_issue_link(corpus_name, alignment_type, new_segment), ) custom_css = """ html, body, #root, .gradio-container, .app, .main, .wrap, .contain, footer { background-color: #f7f3ec !important; } .gradio-container { max-width: 1200px !important; margin: auto !important; background: #f7f3ec !important; color: #2b241f !important; } #main-banner { width: 100% !important; max-width: 100% !important; height: 370px !important; margin-top: -20px !important; margin-bottom: -20px !important; overflow: hidden !important; } #main-banner img { width: 100% !important; height: 400px !important; object-fit: cover !important; display: block !important; transform: translate(60px) !important; } .tabs { margin-top: -25px !important; } /* General sections */ .card, .about-section, .method-section, .explore-section, .team-card { background: #f7f3ec !important; color: #4a3a32 !important; padding: 25px; border-radius: 18px; box-shadow: none !important; margin-bottom: 20px; } .about-section, .method-section, .explore-section { max-width: 980px; margin: 0 auto; padding: 34px 28px 20px 28px; } .about-kicker { text-transform: uppercase; letter-spacing: 0.08em; font-size: 13px; color: #9a6a45; margin-bottom: 10px; font-weight: 600; } .about-section h2, .method-section h2, .explore-section h2, .card h2, .team-card h2 { color: #8a2a22 !important; font-weight: 700 !important; font-size: 30px; margin-top: 8px; margin-bottom: 18px; } .about-lead { font-size: 18px; line-height: 1.6; margin-bottom: 14px; } .about-section p, .method-section p, .explore-section p { line-height: 1.65; margin-bottom: 18px; } .about-question { font-family: Georgia, serif; font-size: 18px; line-height: 1.45; color: #5a2d27; margin: 38px 0 70px 0;; padding-left: 22px; border-left: 4px solid #8a2a22; } .about-note, .about-footer { text-align: center; color: #6a574e; font-size: 15px; max-width: 760px; margin: 30px auto 0 auto; background: #f7f3ec !important; border: none !important; box-shadow: none !important; } /* About feature blocks */ .feature-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 22px 36px; margin-top: 34px; margin-bottom: 34px; } .feature-card { background: transparent !important; border: none !important; box-shadow: none !important; padding: 0; } .feature-title { color: #8a2a22; font-weight: 700; margin-bottom: 8px; font-size: 17px; } .feature-text { color: #4a3a32; font-size: 15px; line-height: 1.55; } /* Method */ .method-steps { margin-top: 32px; display: flex; flex-direction: column; gap: 18px; } .method-step { display: grid; grid-template-columns: 48px 1fr; gap: 18px; align-items: start; } .step-number { width: 38px; height: 38px; border-radius: 50%; border: 2px solid rgba(138, 42, 34, 0.35); color: #8a2a22; display: flex; align-items: center; justify-content: center; font-weight: 700; font-family: Georgia, serif; } .step-title { color: #8a2a22; font-weight: 700; font-size: 17px; margin-bottom: 5px; } .step-text { color: #4a3a32; font-size: 15px; line-height: 1.55; } /* Explore alignments */ .reading-view { max-width: 1080px; margin: 18px auto 34px auto; } .segment-heading { font-family: Georgia, serif; font-size: 20px; color: #5a2d27; margin-bottom: 18px; } .segment-heading span { color: #8a2a22; font-weight: 700; } .main-witness-card { background: #fbf8f3; border-left: 5px solid #8a2a22; padding: 22px 24px; margin-bottom: 28px; border-radius: 0 16px 16px 0; } .witness-label { color: #8a2a22; font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 8px; } .witness-section-title { color: #8a2a22; font-weight: 700; font-size: 18px; margin: 24px 0 10px 0; } .parallel-view { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 18px; margin-top: 18px; margin-bottom: 28px; } .witness-card { background: #f7f3ec; border-left: 3px solid rgba(138, 42, 34, 0.28); padding: 16px 18px; min-height: 120px; } .witness-meta { color: #9a6a45; font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 12px; } .main-witness-text { color: #2f2824; font-family: Georgia, serif; font-size: 20px; line-height: 1.7; } .witness-text { color: #2f2824; font-family: Georgia, serif; font-size: 17px; line-height: 1.6; } .raw-warning { background: #fbf8f3; border-left: 4px solid #9a6a45; padding: 14px 18px; margin-bottom: 22px; color: #5a4a42; font-size: 15px; line-height: 1.5; } .corpus-notice { max-width: 980px; margin: 0 auto 20px auto; padding: 16px 20px; background: #fbf8f3; border-left: 4px solid rgba(138, 42, 34, 0.45); color: #4a3a32; font-size: 15px; line-height: 1.5; } .search-status { max-width: 980px; margin: 8px auto 20px auto; padding: 12px 16px; background: #fbf8f3; border-left: 4px solid #9a6a45; color: #5a4a42; font-size: 14px; line-height: 1.5; } .report-box { margin-top: 12px; padding: 12px 16px; background: #fbf8f3; border-left: 4px solid rgba(138, 42, 34, 0.35); } .report-box a { color: #8a2a22 !important; font-weight: 700; text-decoration: none; } .report-box a:hover { text-decoration: underline; } /* Gradio form controls */ .gradio-container label, .gradio-container .wrap label, .gradio-container span { color: #8a2a22 !important; } .gradio-container input, .gradio-container textarea, .gradio-container select { background: #f7f3ec !important; color: #2b241f !important; border-color: rgba(138, 42, 34, 0.18) !important; } .gradio-container .block, .gradio-container .form, .gradio-container .form > *, .gradio-container [data-testid="block-info"], .gradio-container [data-testid="dropdown"] { background: #f7f3ec !important; border-color: rgba(138, 42, 34, 0.12) !important; } .gradio-container button { background: #f7f3ec !important; color: #8a2a22 !important; border-color: rgba(138, 42, 34, 0.18) !important; } /* Witness checkbox chips */ .gradio-container input[type="checkbox"] { accent-color: #8a2a22 !important; } .gradio-container label:has(input[type="checkbox"]) { background: #f7f3ec !important; color: #4a3a32 !important; border: 1px solid rgba(138, 42, 34, 0.18) !important; border-radius: 10px !important; } .gradio-container label:has(input[type="checkbox"]:checked) { background: #fbf8f3 !important; color: #8a2a22 !important; border: 1px solid rgba(138, 42, 34, 0.35) !important; } /* Team */ .person-avatar { width: 110px !important; height: 110px !important; min-height: 110px !important; margin: auto !important; display: block !important; } .person-avatar img { width: 110px !important; height: 110px !important; min-height: 110px !important; object-fit: cover !important; border-radius: 50% !important; border: 3px solid rgba(138, 42, 34, 0.25); display: block !important; } .person-avatar .icon-button-wrapper, .person-avatar .image-controls, .person-avatar [aria-label="Download"], .person-avatar [aria-label="Fullscreen"], .person-avatar [title="Download"], .person-avatar [title="Fullscreen"] { display: none !important; } .person-name { color: #8a2a22; font-weight: 700; font-size: 17px; margin-top: 12px; margin-bottom: 8px; text-align: center; } .person-links { font-size: 14px; text-align: center; } .person-links a { color: #8a2a22 !important; text-decoration: none; font-weight: 600; } .person-links a:hover { text-decoration: underline; } /* Contact */ .contact-section { max-width: 980px; margin: 0 auto; padding: 34px 28px 20px 28px; color: #4a3a32; } .contact-section h2 { color: #8a2a22 !important; font-weight: 700 !important; font-size: 30px; margin-top: 8px; margin-bottom: 18px; } .contact-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 22px; margin-top: 30px; margin-bottom: 28px; } .contact-card { background: #f7f3ec; border-left: 3px solid rgba(138, 42, 34, 0.35); padding: 18px; } .contact-title { color: #8a2a22; font-weight: 700; font-size: 17px; margin-bottom: 8px; } .contact-text { color: #4a3a32; font-size: 15px; line-height: 1.55; margin-bottom: 12px; } .contact-link a { color: #8a2a22 !important; font-weight: 700; text-decoration: none; } .contact-link a:hover { text-decoration: underline; } /* Publications — sober style */ .publications-section { max-width: 980px; margin: 0 auto; padding: 34px 28px 20px 28px; color: #4a3a32; } .publications-section h2 { color: #8a2a22 !important; font-weight: 700 !important; font-size: 30px; margin-top: 8px; margin-bottom: 18px; } .publication-list { display: flex; flex-direction: column; gap: 22px; margin-top: 32px; } .publication-item { background: transparent !important; border-left: 2px solid rgba(138, 42, 34, 0.22); padding: 4px 0 4px 18px; } .publication-title { color: #5a2d27; font-weight: 650; font-size: 17px; line-height: 1.45; margin-bottom: 6px; } .publication-meta { color: #5a4a42; font-size: 14px; font-weight: 400; line-height: 1.55; margin-bottom: 8px; } .publication-text { color: #6a574e; font-size: 14px; line-height: 1.5; margin-bottom: 8px; } .publication-link { margin-top: 6px; } .publication-link a { color: #8a2a22 !important; font-size: 14px; font-weight: 600; text-decoration: none; } .publication-link a:hover { text-decoration: underline; } .bibtex-box { margin-top: 8px; background: transparent !important; border-left: none !important; padding: 0; } .bibtex-box summary { cursor: pointer; color: #9a6a45; font-size: 13px; font-weight: 600; margin-top: 6px; } .bibtex-box pre { white-space: pre-wrap; color: #4a3a32; font-size: 12px; line-height: 1.45; background: #fbf8f3; border: 1px solid rgba(138, 42, 34, 0.10); border-radius: 10px; padding: 12px; margin: 10px 0 0 0; } /* Repositories */ .repository-list { margin-top: 42px; padding-top: 26px; } .repository-title { color: #8a2a22; font-weight: 700; font-size: 22px; margin-bottom: 18px; } .repository-group-title { color: #9a6a45; font-weight: 700; font-size: 13px; text-transform: uppercase; letter-spacing: 0.08em; margin-top: 26px; margin-bottom: 10px; } .repository-item { border-left: 2px solid rgba(138, 42, 34, 0.20); padding: 4px 0 4px 18px; margin-bottom: 18px; color: #5a4a42; font-size: 14px; line-height: 1.55; } .repository-item strong { color: #5a2d27; font-size: 15px; } .repository-links { margin-top: 6px; } .repository-item a, .repository-links a { color: #8a2a22 !important; font-size: 14px; font-weight: 600; text-decoration: none; } .repository-item a:hover, .repository-links a:hover { text-decoration: underline; } /* Strong mobile fixes */ @media screen and (max-width: 768px) { html, body, #root, .gradio-container { width: 100% !important; max-width: 100% !important; overflow-x: hidden !important; } .gradio-container { margin: 0 !important; padding: 0 12px !important; } .contain, .wrap, .main, .app, main { width: 100% !important; max-width: 100% !important; overflow-x: hidden !important; } #main-banner { width: 100% !important; height: auto !important; margin: 0 0 12px 0 !important; overflow: hidden !important; } #main-banner img { width: 100% !important; height: auto !important; max-height: 220px !important; object-fit: contain !important; transform: none !important; } .tabs { width: 100% !important; max-width: 100% !important; overflow-x: auto !important; white-space: nowrap !important; margin-top: 0 !important; } .about-section, .method-section, .explore-section, .publications-section, .contact-section, .card, .team-card, .reading-view { width: 100% !important; max-width: 100% !important; margin: 0 !important; padding: 22px 8px !important; overflow-x: hidden !important; } .about-section h2, .method-section h2, .explore-section h2, .publications-section h2, .contact-section h2 { font-size: 25px !important; line-height: 1.2 !important; } .about-kicker { font-size: 11px !important; letter-spacing: 0.06em !important; white-space: normal !important; overflow-wrap: anywhere !important; } .about-lead, .about-section p, .method-section p, .explore-section p, .step-text, .feature-text, .publication-meta, .publication-text, .repository-item { font-size: 15px !important; line-height: 1.55 !important; max-width: 100% !important; overflow-wrap: anywhere !important; word-break: normal !important; } .about-question { font-size: 18px !important; line-height: 1.45 !important; margin: 26px 0 36px 0 !important; padding-left: 14px !important; max-width: 100% !important; overflow-wrap: anywhere !important; } .feature-grid, .parallel-view, .contact-grid, .team-grid { display: grid !important; grid-template-columns: 1fr !important; gap: 16px !important; width: 100% !important; max-width: 100% !important; } .method-step { display: grid !important; grid-template-columns: 44px minmax(0, 1fr) !important; gap: 12px !important; width: 100% !important; max-width: 100% !important; } .step-title { font-size: 16px !important; line-height: 1.35 !important; overflow-wrap: anywhere !important; } .step-number { width: 36px !important; height: 36px !important; min-width: 36px !important; } .main-witness-card, .witness-card, .publication-item, .repository-item, .corpus-notice, .search-status { width: 100% !important; max-width: 100% !important; overflow-x: hidden !important; overflow-wrap: anywhere !important; } .main-witness-text { font-size: 17px !important; line-height: 1.55 !important; overflow-wrap: anywhere !important; } .witness-text { font-size: 16px !important; line-height: 1.5 !important; overflow-wrap: anywhere !important; } .bibtex-box pre { max-width: 100% !important; overflow-x: auto !important; white-space: pre-wrap !important; word-break: break-word !important; font-size: 11px !important; } .gradio-container table, .gradio-container .dataframe, .gradio-container [data-testid="dataframe"] { max-width: 100% !important; overflow-x: auto !important; } } /* Ultra-strong mobile width fix */ @media screen and (max-width: 768px) { * { box-sizing: border-box !important; } html, body, #root, .gradio-container, .app, .main, .wrap, .contain, main { width: 100vw !important; max-width: 100vw !important; min-width: 0 !important; margin-left: 0 !important; margin-right: 0 !important; overflow-x: hidden !important; } .gradio-container > *, .app > *, .main > *, .wrap > *, .contain > *, main > * { max-width: 100% !important; min-width: 0 !important; } .tabs, [role="tablist"] { width: 100% !important; max-width: 100% !important; overflow-x: auto !important; white-space: nowrap !important; } .about-section, .method-section, .explore-section, .publications-section, .contact-section, .team-card, .card { width: 100% !important; max-width: 100% !important; min-width: 0 !important; margin-left: 0 !important; margin-right: 0 !important; padding-left: 14px !important; padding-right: 14px !important; } .about-section *, .method-section *, .explore-section *, .publications-section *, .contact-section *, .team-card *, .card * { max-width: 100% !important; min-width: 0 !important; overflow-wrap: anywhere !important; word-break: normal !important; } .method-step { display: grid !important; grid-template-columns: 38px minmax(0, 1fr) !important; width: 100% !important; max-width: 100% !important; } .step-title, .step-text, .about-lead, .about-question { white-space: normal !important; overflow-wrap: anywhere !important; } .feature-grid, .parallel-view, .team-grid, .contact-grid { grid-template-columns: 1fr !important; width: 100% !important; max-width: 100% !important; } #main-banner, #main-banner img { width: 100% !important; max-width: 100% !important; transform: none !important; } } /* Emergency mobile width reset */ @media screen and (max-width: 768px) { html, body { width: 100% !important; max-width: 100% !important; overflow-x: hidden !important; margin: 0 !important; padding: 0 !important; } #root, .gradio-container, .gradio-container > div, .gradio-container .main, .gradio-container .wrap, .gradio-container .contain, .gradio-container .block, .gradio-container .form, .gradio-container .gap, .gradio-container .panel, .gradio-container .tabs, .gradio-container .tabitem, .gradio-container .tab-nav, .gradio-container [class*="container"], .gradio-container [class*="wrap"], .gradio-container [class*="block"], .gradio-container [class*="column"], .gradio-container [class*="row"] { width: 100% !important; max-width: 100% !important; min-width: 0 !important; overflow-x: hidden !important; box-sizing: border-box !important; } .gradio-container [role="tablist"] { width: 100% !important; max-width: 100% !important; min-width: 0 !important; overflow-x: auto !important; overflow-y: hidden !important; white-space: nowrap !important; display: flex !important; flex-wrap: nowrap !important; } .gradio-container [role="tab"] { flex: 0 0 auto !important; max-width: none !important; white-space: nowrap !important; } .about-section, .method-section, .explore-section, .publications-section, .contact-section, .team-card, .card { width: 100% !important; max-width: 100% !important; min-width: 0 !important; margin: 0 !important; padding: 18px 8px !important; box-sizing: border-box !important; overflow-x: hidden !important; } .about-section *, .method-section *, .explore-section *, .publications-section *, .contact-section *, .team-card *, .card * { max-width: 100% !important; min-width: 0 !important; box-sizing: border-box !important; white-space: normal !important; overflow-wrap: anywhere !important; word-break: normal !important; } .method-step { display: grid !important; grid-template-columns: 32px minmax(0, 1fr) !important; gap: 10px !important; width: 100% !important; max-width: 100% !important; min-width: 0 !important; } .step-number { width: 30px !important; height: 30px !important; min-width: 30px !important; font-size: 13px !important; } .about-lead, .step-text, .step-title, .feature-text, .main-witness-text, .witness-text, .publication-title, .publication-meta, .publication-text, .repository-item { width: 100% !important; max-width: 100% !important; min-width: 0 !important; white-space: normal !important; overflow-wrap: anywhere !important; } .about-lead { font-size: 15px !important; line-height: 1.5 !important; } .step-title { font-size: 15px !important; line-height: 1.3 !important; } .step-text { font-size: 14px !important; line-height: 1.45 !important; } .about-section h2, .method-section h2, .explore-section h2, .publications-section h2, .contact-section h2 { font-size: 24px !important; line-height: 1.15 !important; } .about-kicker { font-size: 10px !important; line-height: 1.4 !important; letter-spacing: 0.04em !important; white-space: normal !important; } .feature-grid, .parallel-view, .team-grid, .contact-grid { display: grid !important; grid-template-columns: minmax(0, 1fr) !important; width: 100% !important; max-width: 100% !important; min-width: 0 !important; } #main-banner { width: 100% !important; max-width: 100% !important; height: auto !important; margin: 0 0 10px 0 !important; overflow: hidden !important; } #main-banner img { width: 100% !important; max-width: 100% !important; height: auto !important; max-height: 200px !important; object-fit: contain !important; transform: none !important; } iframe, table, pre, code, .dataframe, [data-testid="dataframe"] { max-width: 100% !important; overflow-x: auto !important; white-space: pre-wrap !important; } } /* Professional mobile tabs: scroll tabs, not the whole page */ @media screen and (max-width: 768px) { .gradio-container [role="tablist"] { display: flex !important; flex-wrap: nowrap !important; overflow-x: auto !important; overflow-y: hidden !important; max-width: 100vw !important; width: 100% !important; white-space: nowrap !important; scrollbar-width: thin !important; } .gradio-container [role="tab"] { flex: 0 0 auto !important; white-space: nowrap !important; max-width: none !important; } .gradio-container [role="tabpanel"] { width: 100% !important; max-width: 100vw !important; overflow-x: hidden !important; } .gradio-container { overflow-x: hidden !important; } } /* Final responsive fix */ @media screen and (max-width: 768px) { html, body, gradio-app, #root, .gradio-container { width: 100% !important; max-width: 100% !important; min-width: 0 !important; overflow-x: hidden !important; } .gradio-container * { max-width: 100% !important; min-width: 0 !important; box-sizing: border-box !important; } .gradio-container .row, .gradio-container .column, .gradio-container [class*="row"], .gradio-container [class*="column"] { flex-wrap: wrap !important; width: 100% !important; max-width: 100% !important; min-width: 0 !important; } .gradio-container [data-testid="block-label"], .gradio-container label, .gradio-container input, .gradio-container textarea, .gradio-container select, .gradio-container button { max-width: 100% !important; min-width: 0 !important; white-space: normal !important; } .about-section, .method-section, .explore-section, .publications-section, .contact-section, .team-card, .card, .reading-view, .main-witness-card, .witness-card, .publication-item, .repository-item { width: 100% !important; max-width: 100% !important; min-width: 0 !important; margin-left: 0 !important; margin-right: 0 !important; padding-left: 10px !important; padding-right: 10px !important; overflow-x: hidden !important; } .feature-grid, .parallel-view, .team-grid, .contact-grid { display: grid !important; grid-template-columns: minmax(0, 1fr) !important; width: 100% !important; max-width: 100% !important; } .method-step { grid-template-columns: 32px minmax(0, 1fr) !important; } .about-section *, .method-section *, .explore-section *, .publications-section *, .contact-section *, .team-card *, .card *, .reading-view * { white-space: normal !important; overflow-wrap: anywhere !important; word-break: normal !important; } [role="tablist"] { max-width: 100% !important; overflow-x: auto !important; display: flex !important; flex-wrap: nowrap !important; } [role="tab"] { flex: 0 0 auto !important; white-space: nowrap !important; } #main-banner img { transform: none !important; width: 100% !important; height: auto !important; object-fit: contain !important; } }/* Android / tablet responsive fix */ @media screen and (max-width: 1200px) { html, body, #root, .gradio-container { width: 100% !important; max-width: 100% !important; min-width: 0 !important; margin: 0 !important; padding: 0 !important; overflow-x: hidden !important; } .gradio-container { padding-left: 12px !important; padding-right: 12px !important; } .gradio-container *, .gradio-container *::before, .gradio-container *::after { box-sizing: border-box !important; min-width: 0 !important; } #main-banner { width: 100% !important; max-width: 100% !important; height: auto !important; margin: 0 0 14px 0 !important; overflow: hidden !important; } #main-banner img { width: 100% !important; max-width: 100% !important; height: auto !important; max-height: 220px !important; object-fit: contain !important; transform: none !important; display: block !important; } .tabs, [role="tablist"] { width: 100% !important; max-width: 100% !important; overflow-x: auto !important; overflow-y: hidden !important; display: flex !important; flex-wrap: nowrap !important; white-space: nowrap !important; } [role="tab"] { flex: 0 0 auto !important; white-space: nowrap !important; } .about-section, .method-section, .explore-section, .publications-section, .contact-section, .team-card, .card, .reading-view, .main-witness-card, .witness-card, .publication-item, .repository-item, .corpus-notice, .search-status { width: 100% !important; max-width: 100% !important; min-width: 0 !important; margin-left: 0 !important; margin-right: 0 !important; padding-left: 12px !important; padding-right: 12px !important; overflow-x: hidden !important; } .about-section *, .method-section *, .explore-section *, .publications-section *, .contact-section *, .team-card *, .card *, .reading-view * { max-width: 100% !important; min-width: 0 !important; white-space: normal !important; overflow-wrap: anywhere !important; word-break: normal !important; } .feature-grid, .parallel-view, .team-grid, .contact-grid { display: grid !important; grid-template-columns: minmax(0, 1fr) !important; gap: 16px !important; width: 100% !important; max-width: 100% !important; } .method-step { display: grid !important; grid-template-columns: 36px minmax(0, 1fr) !important; gap: 12px !important; width: 100% !important; max-width: 100% !important; } .step-number { width: 32px !important; height: 32px !important; min-width: 32px !important; font-size: 14px !important; } .about-section h2, .method-section h2, .explore-section h2, .publications-section h2, .contact-section h2 { font-size: 26px !important; line-height: 1.2 !important; } .about-kicker { font-size: 11px !important; letter-spacing: 0.05em !important; white-space: normal !important; } .about-lead, .about-question, .step-title, .step-text, .feature-text, .main-witness-text, .witness-text, .publication-title, .publication-meta, .publication-text, .repository-item { max-width: 100% !important; white-space: normal !important; overflow-wrap: anywhere !important; word-break: normal !important; } .about-lead { font-size: 16px !important; line-height: 1.5 !important; } .step-title { font-size: 16px !important; line-height: 1.3 !important; } .step-text { font-size: 15px !important; line-height: 1.5 !important; } .main-witness-text { font-size: 17px !important; line-height: 1.55 !important; } .witness-text { font-size: 16px !important; line-height: 1.5 !important; } .bibtex-box pre, table, .dataframe, [data-testid="dataframe"] { max-width: 100% !important; overflow-x: auto !important; white-space: pre-wrap !important; } } .mobile-warning { display: none; } @media screen and (max-width: 1200px) { .mobile-warning { display: block !important; background: #fbf8f3; border-left: 3px solid rgba(138, 42, 34, 0.35); color: #5a2d27; padding: 14px 16px; margin: 14px 12px 20px 12px; font-size: 14px; line-height: 1.5; } } """ mobile_head = """ """ #with gr.Blocks( # title="Aquilign Demo", # theme=gr.themes.Soft(), # css=custom_css, #) as demo: with gr.Blocks( title="Aquilign Demo", theme=gr.themes.Soft(), css=custom_css, head=mobile_head, ) as demo: gr.Image( value="quilign.png", show_label=False, container=False, elem_id="main-banner", ) gr.HTML( """Browse curated alignment samples produced with Aquilign and manually reviewed for demonstration purposes. You can search across witnesses, choose which witnesses to display, and inspect raw Aquilign output for transparency.
No data found.
" ) with gr.Row(): download_button = gr.DownloadButton( label="Download current dataset", value=str(get_data_file(default_corpus, default_type)), ) with gr.Accordion("Report an alignment issue", open=False): issue_text = gr.Textbox( label="Issue report template", value=make_issue_report(default_corpus, default_type, first_segment) if first_segment else "", lines=7, interactive=True, ) issue_link = gr.HTML( value=make_github_issue_link(default_corpus, default_type, first_segment) if first_segment else "" ) with gr.Accordion("Full alignment table", open=False): table = gr.Dataframe( value=load_alignments(default_corpus, default_type), interactive=False, ) corpus_selector.change( fn=update_explore, inputs=[corpus_selector, type_selector], outputs=[ segment_selector, search_box, witness_selector, parallel_output, table, notice_output, download_button, issue_text, issue_link, ], ) type_selector.change( fn=update_explore, inputs=[corpus_selector, type_selector], outputs=[ segment_selector, search_box, witness_selector, parallel_output, table, notice_output, download_button, issue_text, issue_link, ], ) search_box.submit( fn=update_search, inputs=[corpus_selector, type_selector, search_box, witness_selector], outputs=[ segment_selector, parallel_output, search_status, issue_text, issue_link, ], ) clear_button.click( fn=clear_search, inputs=[corpus_selector, type_selector, witness_selector], outputs=[ search_box, segment_selector, parallel_output, search_status, issue_text, issue_link, ], ) previous_button.click( fn=lambda corpus, atype, segment, query, witnesses: move_segment( corpus, atype, segment, query, witnesses, "previous" ), inputs=[ corpus_selector, type_selector, segment_selector, search_box, witness_selector, ], outputs=[ segment_selector, parallel_output, issue_text, issue_link, ], ) next_button.click( fn=lambda corpus, atype, segment, query, witnesses: move_segment( corpus, atype, segment, query, witnesses, "next" ), inputs=[ corpus_selector, type_selector, segment_selector, search_box, witness_selector, ], outputs=[ segment_selector, parallel_output, issue_text, issue_link, ], ) segment_selector.change( fn=view_segment, inputs=[ corpus_selector, type_selector, segment_selector, witness_selector, ], outputs=parallel_output, ) segment_selector.change( fn=make_issue_report, inputs=[corpus_selector, type_selector, segment_selector], outputs=issue_text, ) segment_selector.change( fn=make_github_issue_link, inputs=[corpus_selector, type_selector, segment_selector], outputs=issue_link, ) witness_selector.change( fn=view_segment, inputs=[ corpus_selector, type_selector, segment_selector, witness_selector, ], outputs=parallel_output, ) with gr.Tab("About"): gr.Markdown( """Aquilign is a multilingual alignment and collation engine for historical and philological corpora. It is designed to help researchers compare medieval textual traditions across languages, witnesses, translations, and corpora.
Aquilign is developed within the ProMeText ecosystem and released as an open-source research tool for computational humanities, historical linguistics, and historical NLP.
Aquilign is designed as a modular workflow for preparing, segmenting, aligning, and exploring multilingual medieval textual traditions.
The current demo presents reviewed alignment samples alongside raw Aquilign output for transparency.
Please cite the relevant publications and datasets when using Aquilign, the demo alignments, or the associated segmentation resources.
@inproceedings{gillelevenson_TextualTransmissionBorders_2024a,
title = {Textual Transmission without Borders: Multiple Multilingual Alignment and Stemmatology of the ``Lancelot En Prose'' (Medieval French, Castilian, Italian)},
shorttitle = {Textual Transmission without Borders},
booktitle = {Proceedings of the Computational Humanities Research Conference 2024},
author = {Gille Levenson, Matthias and Ing, Lucence and Camps, Jean-Baptiste},
editor = {Haverals, Wouter and Koolen, Marijn and Thompson, Laure},
date = {2024},
series = {CEUR Workshop Proceedings},
volume = {3834},
pages = {65--92},
publisher = {CEUR},
location = {Aarhus, Denmark},
issn = {1613-0073},
url = {https://ceur-ws.org/Vol-3834/#paper104},
urldate = {2024-12-09},
eventtitle = {Computational Humanities Research 2024},
langid = {english}
}
@inproceedings{ing2026phrase,
title = {Phrase-Level Segmentation on Medieval Corpora for Aligning Multilingual Texts},
author = {Ing, Lucence and Gille Levenson, Matthias and Macedo, Carolina},
booktitle = {Proceedings of the Fifteenth Language Resources and Evaluation Conference (LREC 2026)},
year = {2026},
doi = {10.63317/32HUZUUOKPFR}
}
These references document the alignment approach, segmentation workflow, datasets, and corpus resources associated with Aquilign.
For questions, feedback, or collaboration requests related to Aquilign, you can contact the project team or open an issue on GitHub.
Aquilign is developed as an open-source research tool for digital philology, historical linguistics, and computational humanities.