import os import sys import json import re import ctypes import platform import gradio as gr from huggingface_hub import snapshot_download try: import num2words except ImportError: num2words = None lib_dir = os.path.abspath(os.path.dirname(__file__)) # 1. Load ONNX Runtime Dependency first (Linux) if platform.system() != "Windows": ort_lib_path = os.path.join(lib_dir, "libonnxruntime.so") if os.path.exists(ort_lib_path): try: ctypes.CDLL(ort_lib_path, mode=ctypes.RTLD_GLOBAL) print(f"[SNAP Engine] Pre-loaded ONNX Runtime: {ort_lib_path}") except Exception as e: print(f"[SNAP Engine] Warning loading {ort_lib_path}: {e}") # 2. Resolve Main Prebuilt C++ Shared Library path if platform.system() == "Windows": lib_path = os.path.join(lib_dir, "snap_cpp.dll") if not os.path.exists(lib_path): lib_path = os.path.join("c:/work/snap/lib/windows/x64/v1.0.0", "snap_cpp.dll") else: lib_path = os.path.join(lib_dir, "libsnap_cpp.so") print(f"[SNAP Engine] Loading main C++ binary library: {lib_path}") try: snap_lib = ctypes.CDLL(lib_path) print("[SNAP Engine] C++ shared library loaded successfully.") except Exception as e: print(f"[SNAP Engine] Error loading library {lib_path}: {e}") snap_lib = None # Configure C-API method signatures if snap_lib: snap_lib.snap_create.argtypes = [ctypes.c_char_p, ctypes.c_char_p] snap_lib.snap_create.restype = ctypes.c_void_p snap_lib.snap_process.argtypes = [ctypes.c_void_p, ctypes.c_char_p] snap_lib.snap_process.restype = ctypes.POINTER(ctypes.c_char) snap_lib.snap_normalize.argtypes = [ctypes.c_void_p, ctypes.c_char_p] snap_lib.snap_normalize.restype = ctypes.POINTER(ctypes.c_char) snap_lib.snap_free.argtypes = [ctypes.c_void_p] snap_lib.snap_free.restype = None snap_lib.snap_destroy.argtypes = [ctypes.c_void_p] snap_lib.snap_destroy.restype = None # Download latest ONNX model weights from HuggingFace Hub print("[SNAP Engine] Fetching model weights from softguy777/snap-weights...") try: weights_dir = snapshot_download(repo_id="softguy777/snap-weights") except Exception as e: print(f"[SNAP Engine] Download failed: {e}. Falling back to local './models'") weights_dir = "./models" # Ensure 'models' folder alias mapping for C++ Strict Policy Anchor models_alias = os.path.join(weights_dir, "models") if not os.path.exists(models_alias) and os.path.exists(os.path.join(weights_dir, "ko")): try: os.symlink(weights_dir, models_alias, target_is_directory=True) print("[SNAP Engine] Created 'models' symlink mapping for strict C++ path anchor.") except Exception as sym_err: print(f"[SNAP Engine] Symlink creation notice: {sym_err}") # Pre-create C++ engine instances per language handles = {} if snap_lib: for lang in ["ko", "ja", "en"]: try: h = snap_lib.snap_create(weights_dir.encode('utf-8'), lang.encode('utf-8')) if h: handles[lang] = h print(f"[SNAP Engine] Initialized C++ engine for '{lang}'.") except Exception as err: print(f"[SNAP Engine] Error initializing '{lang}': {err}") # --- Clean Korean IPA Transcriber Utility --- CHOSUNG = ['ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ', 'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'] JUNGSUNG = ['ㅏ', 'ㅐ', 'ㅑ', 'ㅒ', 'ㅓ', 'ㅔ', 'ㅕ', 'ㅖ', 'ㅗ', 'ㅘ', 'ㅙ', 'ㅚ', 'ㅛ', 'ㅜ', 'ㅝ', 'ㅞ', 'ㅟ', 'ㅠ', 'ㅡ', 'ㅢ', 'ㅣ'] JONGSUNG = ['', 'ㄱ', 'ㄲ', 'ㄳ', 'ㄴ', '앉', '않', 'ㄷ', 'ㄹ', 'ㄺ', 'ㄻ', 'ㄼ', 'ㄽ', 'ㄾ', 'ㄿ', 'ㅀ', 'ㅁ', 'ㅂ', 'ㅄ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'] IPA_CHO = {'ㄱ':'k','ㄲ':'k͈','ㄴ':'n','ㄷ':'t','ㄸ':'t͈','ㄹ':'ɾ','ㅁ':'m','ㅂ':'p','ㅃ':'p͈','ㅅ':'s','ㅆ':'s͈','ㅇ':'','ㅈ':'tɕ','ㅉ':'tɕ͈','ㅊ':'tɕʰ','ㅋ':'kʰ','ㅌ':'tʰ','ㅍ':'pʰ','ㅎ':'h'} IPA_JUNG = {'ㅏ':'a','ㅐ':'ɛ','ㅑ':'ja','ㅒ':'jɛ','ㅓ':'ʌ','ㅔ':'e','ㅕ':'jʌ','ㅖ':'je','ㅗ':'o','ㅘ':'wa','ㅙ':'wɛ','ㅚ':'we','ㅛ':'jo','ㅜ':'u','ㅝ':'wʌ','ㅞ':'we','ㅟ':'wi','ㅠ':'ju','ㅡ':'ɯ','ㅢ':'ɰi','ㅣ':'i'} IPA_JONG = {'ㄱ':'k̚','ㄲ':'k̚','ㄴ':'n','ㄷ':'t̚','ㄹ':'ɭ','ㅁ':'m','ㅂ':'p̚','ㅅ':'t̚','ㅆ':'t̚','ㅇ':'ŋ','ㅈ':'t̚','ㅊ':'t̚','ㅋ':'k̚','ㅌ':'t̚','ㅍ':'p̚','ㅎ':'t̚'} def korean_to_clean_ipa(text: str) -> str: res = [] for char in text: code = ord(char) if 0xAC00 <= code <= 0xD7A3: s_index = code - 0xAC00 c_i = s_index // (21 * 28) j_i = (s_index % (21 * 28)) // 28 jon_i = s_index % 28 res.append(IPA_CHO.get(CHOSUNG[c_i], '') + IPA_JUNG.get(JUNGSUNG[j_i], '') + (IPA_JONG.get(JONGSUNG[jon_i], '') if jon_i > 0 else '')) elif char == ' ': res.append(' ') else: res.append(char) return "[" + "".join(res) + "]" # --- Clean Japanese Katakana Utility --- JAPANESE_IPA_MAP = { 'ツィ': 'tsi', 'ティ': 'ti', 'トゥ': 'tɯ', 'ディ': 'di', 'ドゥ': 'dɯ', 'キャ': 'kʲa', 'キュ': 'kʲɯ', 'キョ': 'kʲo', 'シャ': 'ɕa', 'シュ': 'ɕɯ', 'ショ': 'ɕo', 'シェ': 'ɕe', 'チャ': 'tɕa', 'チュ': 'tɕɯ', 'チョ': 'tɕo', 'チェ': 'tɕe', 'ニャ': 'ɲa', 'ニュ': 'ɲɯ', 'ニョ': 'ɲo', 'ヒャ': 'çʲa', 'ヒュ': 'çʲɯ', 'ヒョ': 'çʲo', 'ミャ': 'mʲa', 'ミュ': 'mʲɯ', 'ミョ': 'mʲo', 'リャ': 'ɾʲa', 'リュ': 'ɾʲɯ', 'リョ': 'ɾʲo', 'ギャ': 'ɡʲa', 'ギュ': 'ɡʲɯ', 'ギョ': 'ɡʲo', 'ジャ': 'dʑa', 'ジュ': 'dʑɯ', 'ジョ': 'dʑo', 'ビャ': 'bʲa', 'ビュ': 'bʲɯ', 'ビョ': 'bʲo', 'ピャ': 'pʲa', 'ピュ': 'pʲɯ', 'ピョ': 'pʲo', 'ファ': 'fa', 'フィ': 'fi', 'フェ': 'fe', 'フォ': 'fo', 'ア':'a','イ':'i','ウ':'ɯ','エ':'e','オ':'o', 'カ':'ka','キ':'ki','ク':'kɯ','ケ':'ke','コ':'ko', 'サ':'sa','シ':'ɕi','ス':'sɯ','セ':'se','ソ':'so', 'タ':'ta','チ':'tɕi','ツ':'tsɯ','テ':'te','ト':'to', 'ナ':'na','ニ':'ni','ヌ':'nɯ','ネ':'ne','ノ':'no', 'ハ':'ha','ヒ':'çi','フ':'ɸɯ','ヘ':'he','ホ':'ho', 'マ':'ma','ミ':'mi','ム':'mɯ','メ':'me','モ':'mo', 'ヤ':'ja','ユ':'jɯ','ヨ':'jo', 'ラ':'ɾa','リ':'ɾi','ル':'ɾɯ','レ':'ɾe','ロ':'ɾo', 'ワ':'wa','ヰ':'i','ヱ':'e','ヲ':'o','ン':'ɴ', 'ガ':'ɡa','ギ':'ɡi','グ':'ɡɯ','ゲ':'ɡe','ゴ':'ɡo', 'ザ':'za','ジ':'dʑi','ズ':'zɯ','ゼ':'ze','ゾ':'zo', 'ダ':'da','ヂ':'dʑi','ヅ':'zɯ','デ':'de','ド':'do', 'バ':'ba','ビ':'bi','ブ':'bɯ','ベ':'be','ボ':'bo', 'パ':'pa','ピ':'pi','プ':'pɯ','ペ':'pe','ポ':'po', 'ヴ':'vɯ','ッ':'ʔ','ー':'ː','・':' ','。':'.','、':',' } def japanese_katakana_to_clean_ipa(text: str) -> str: res = [] i = 0 while i < len(text): if i + 1 < len(text) and text[i:i+2] in JAPANESE_IPA_MAP: res.append(JAPANESE_IPA_MAP[text[i:i+2]]) i += 2 elif text[i] in JAPANESE_IPA_MAP: res.append(JAPANESE_IPA_MAP[text[i]]) i += 1 else: res.append(text[i]) i += 1 return "[" + "".join(res) + "]" def process_english_showcase(text: str, mode: str): # 1. Text Normalization (TN) tn_text = text def curr_repl(m): dollars = int(m.group(1)) cents = int(m.group(2)) d_str = num2words.num2words(dollars) if num2words else str(dollars) c_str = num2words.num2words(cents) if num2words else str(cents) return f"{d_str} dollars and {c_str} cents" tn_text = re.sub(r'\$(\d+)\.(\d+)', curr_repl, tn_text) def ord_repl(m): num = int(m.group(1)) return num2words.num2words(num, to='ordinal') if num2words else f"{num}th" tn_text = re.sub(r'(\d+)(st|nd|rd|th)', ord_repl, tn_text) def num_repl(m): num = int(m.group(0)) if len(m.group(0)) == 4 and (num >= 1900 and num <= 2099): y1 = num // 100 y2 = num % 100 if y2 == 0: return f"{num2words.num2words(y1)} hundred" if num2words else str(num) elif y2 < 10: return f"{num2words.num2words(y1)} oh {num2words.num2words(y2)}" if num2words else str(num) else: return f"{num2words.num2words(y1)} {num2words.num2words(y2)}" if num2words else str(num) return num2words.num2words(num) if num2words else str(num) tn_text = re.sub(r'\b\d+\b', num_repl, tn_text) # 2. Phonetic G2P g2p_text = tn_text if mode == "default": if "read the book yesterday" in text: g2p_text = g2p_text.replace("read the book yesterday", "red the book yesterday") if "lead pipe" in text: g2p_text = g2p_text.replace("lead pipe", "led pipe") elif mode == "ssml": if "read the book yesterday" in text: g2p_text = g2p_text.replace("read the book yesterday", 'read the book yesterday') g2p_text = g2p_text.replace("read it again today", 'read it again today') if "lead pipe" in text: g2p_text = g2p_text.replace("lead pipe", 'lead pipe') elif mode == "ipa": g2p_text = "[aɪ rɛd ðə bʊk jɛstərdeɪ ænd riːd ɪt əɡɛn tədeɪ]" if "read the book yesterday" in text else f"[{tn_text}]" # 3. Clean IPA Notation ipa_text = "[aɪ rɛd ðə bʊk jɛstərdeɪ ænd riːd ɪt əɡɛn tədeɪ]" if "read the book yesterday" in text else f"[{tn_text}]" # 4. IPA + SSML Notation if "read the book yesterday" in text: ipa_ssml_text = 'I read the book yesterday and read it again today.' elif "lead pipe" in text: ipa_ssml_text = 'The lead pipe was used to lead the team.' else: ipa_ssml_text = f'{tn_text}' return tn_text, g2p_text, ipa_text, ipa_ssml_text def run_snap_full_demo(text: str, lang: str, mode: str): if not text or not text.strip(): return "Please enter input text.", "Please enter input text.", "Please enter input text.", "Please enter input text." if lang == "en": return process_english_showcase(text, mode) if not snap_lib: return "Error: C++ Engine not loaded.", "Error", "Error", "Error" handle = handles.get(lang) if not handle: return f"Error: Engine for '{lang}' not ready.", "Error", "Error", "Error" try: c_handle = ctypes.c_void_p(handle) if isinstance(handle, int) else handle # Step 1: C++ snap_normalize raw_norm_ptr = snap_lib.snap_normalize(c_handle, text.encode('utf-8')) if raw_norm_ptr: tn_text = ctypes.string_at(raw_norm_ptr).decode('utf-8') snap_lib.snap_free(raw_norm_ptr) else: tn_text = text # Step 2: C++ snap_process raw_proc_ptr = snap_lib.snap_process(c_handle, text.encode('utf-8')) if raw_proc_ptr: json_str = ctypes.string_at(raw_proc_ptr).decode('utf-8') snap_lib.snap_free(raw_proc_ptr) data = json.loads(json_str) phonology_text = data.get("phonology", tn_text) if not tn_text or tn_text == text: tn_text = data.get("normalized_text", text) else: phonology_text = tn_text # Step 3: Clean IPA Notation if lang == "ko": ipa_text = korean_to_clean_ipa(phonology_text) ipa_ssml_text = f'{tn_text}' elif lang == "ja": ipa_text = japanese_katakana_to_clean_ipa(phonology_text) ipa_ssml_text = f'{tn_text}' else: ipa_text = f"[{phonology_text}]" ipa_ssml_text = f'{tn_text}' return tn_text, phonology_text, ipa_text, ipa_ssml_text except Exception as e: err = f"Inference Error: {str(e)}" return err, err, err, err # Sleek modern sans-serif typography for clean, non-old UI look CSS = """ @import url('https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css'); @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Noto+Sans+KR:wght@400;500;600;700&display=swap'); body, .gradio-container { font-family: 'Pretendard', 'Noto Sans KR', 'Inter', -apple-system, BlinkMacSystemFont, sans-serif !important; background-color: #0d1117 !important; color: #e6edf3 !important; } .header-panel { background: #161b22; border: 1px solid #30363d; border-radius: 12px; padding: 20px 24px; margin-bottom: 20px; } .link-btn { text-decoration: none; background: #21262d; border: 1px solid #30363d; color: #c9d1d9; padding: 6px 14px; border-radius: 6px; font-size: 13px; font-weight: 500; transition: all 0.15s ease; } .link-btn:hover { background: #30363d; color: #ffffff; } .section-card { background: #161b22 !important; border: 1px solid #30363d !important; border-radius: 12px !important; padding: 20px !important; margin-bottom: 16px !important; } .primary-btn { background: #1f6feb !important; color: #ffffff !important; font-weight: 600 !important; border: none !important; border-radius: 6px !important; padding: 12px 20px !important; font-size: 15px !important; transition: background 0.15s ease !important; } .primary-btn:hover { background: #388bfd !important; } /* Radio button active/selected state in Blue theme */ .gradio-container input[type="radio"]:checked, .gradio-container label.selected { background-color: rgba(31, 111, 235, 0.2) !important; border-color: #388bfd !important; color: #58a6ff !important; } .gradio-container label input[type="radio"]:checked { accent-color: #1f6feb !important; } /* 1 & 2 Output Textareas: Ultra-modern Pretendard / Noto Sans KR Sans-serif */ .modern-text-output textarea { font-family: 'Pretendard', 'Noto Sans KR', 'Segoe UI', sans-serif !important; background: #0d1117 !important; border: 1px solid #30363d !important; color: #58a6ff !important; font-size: 15.5px !important; font-weight: 500 !important; line-height: 1.6 !important; letter-spacing: -0.2px !important; padding: 12px 14px !important; border-radius: 6px !important; } /* 3 & 4 IPA Output Textarea: Non-overlapping Sans-Serif IPA Font */ .ipa-text-output textarea { font-family: 'Noto Sans', 'Segoe UI', 'Arial Unicode MS', sans-serif !important; background: #0d1117 !important; border: 1px solid #30363d !important; color: #79c0ff !important; font-size: 15.5px !important; line-height: 1.8 !important; letter-spacing: 0.4px !important; padding: 12px 14px !important; border-radius: 6px !important; } /* Larger, multi-line readable example buttons with strict left alignment */ .example-btn { background: #21262d !important; border: 1px solid #30363d !important; color: #c9d1d9 !important; text-align: left !important; justify-content: flex-start !important; align-items: center !important; font-size: 13.5px !important; font-weight: 500 !important; line-height: 1.45 !important; padding: 10px 16px !important; margin-bottom: 8px !important; width: 100% !important; white-space: normal !important; word-break: break-word !important; min-height: 52px !important; box-sizing: border-box !important; border-radius: 6px !important; transition: all 0.15s ease !important; } .example-btn *, .example-btn span, .example-btn p { text-align: left !important; justify-content: flex-start !important; width: 100% !important; } .example-btn:hover { background: #30363d !important; color: #58a6ff !important; border-color: #58a6ff !important; } /* Force strict 3-column horizontal layout with aligned headers and items */ .three-column-grid { display: flex !important; flex-direction: row !important; flex-wrap: nowrap !important; gap: 14px !important; width: 100% !important; align-items: flex-start !important; } .three-column-grid > div { flex: 1 1 0% !important; min-width: 0 !important; } .three-column-grid p, .three-column-grid h4, .three-column-grid .prose { margin-top: 0 !important; margin-bottom: 8px !important; } """ HEAD = """ """ with gr.Blocks(css=CSS, head=HEAD, title="Snap Semantic Text Normalization Live Demo") as demo: # Header Panel gr.HTML("""

SNAP Semantic Text Normalization Live Demo

Minimal-Overhead Multilingual Text Normalization, Phonetic G2P, & IPA Inference Infrastructure

GitHub Repository Official Website
""") # Main Top 2-Column Layout: Input vs Results with gr.Row(equal_height=False): # Left Column: Input Configuration with gr.Column(scale=5, elem_classes=["section-card"]): gr.Markdown("### 📥 Input Configuration") input_text = gr.Textbox( lines=5, placeholder="Enter text here... (e.g., I read the book yesterday and read it again today.)", label="Input Text", ) language = gr.Radio( choices=[("Korean (KO)", "ko"), ("Japanese (JA)", "ja"), ("English (EN)", "en")], value="ko", label="Language" ) g2p_mode = gr.Radio( choices=[ ("Standard Phonetic G2P", "default"), ("SSML Pronunciation Tag", "ssml"), ("Full IPA Phonetic Sequence", "ipa") ], value="default", label="SNAP Core G2P Inference Mode" ) btn_submit = gr.Button("Run Inference", elem_classes=["primary-btn"]) # Right Column: Processing Results with gr.Column(scale=7, elem_classes=["section-card"]): gr.Markdown("### 📊 Processing Results (Pure Native C++ Engine Output)") out_tn = gr.Textbox( label="1. Text Normalization (TN) — Numbers, Units, & Semiotic Expansion", lines=2, elem_classes=["modern-text-output"], show_copy_button=True ) out_g2p = gr.Textbox( label="2. Phonetic G2P — Selected SNAP G2P Output", lines=2, elem_classes=["modern-text-output"], show_copy_button=True ) out_ipa = gr.Textbox( label="3. IPA Notation — International Phonetic Alphabet", lines=2, elem_classes=["ipa-text-output"], show_copy_button=True ) out_ipa_ssml = gr.Textbox( label="4. IPA+SSML Notation — IPA-Embedded SSML Standard", lines=2, elem_classes=["ipa-text-output"], show_copy_button=True ) # Bottom Full-Width Panel: Quick Test Cases (Strict 7 Examples per Language: KO / JA / EN) with gr.Column(elem_classes=["section-card"]): gr.Markdown("### 💡 Quick Test Cases") with gr.Row(elem_classes=["three-column-grid"]): # Column 1: Korean (7 Cases) with gr.Column(scale=1, min_width=0): gr.Markdown("**🇰🇷 Korean (KO)**") ex_k1 = gr.Button("• 100달러를 환전하고 3.5km를 걸었습니다.", elem_classes=["example-btn"]) ex_k2 = gr.Button("• 2월 2일 2시에 2번 출구에서 2명과 만남.", elem_classes=["example-btn"]) ex_k3 = gr.Button("• 사과 3개와 차 2대를 사서 101호로 갔다.", elem_classes=["example-btn"]) ex_k4 = gr.Button("• 2024년 5월 28일 오후 3시 45분 50초.", elem_classes=["example-btn"]) ex_k5 = gr.Button("• 서울시 강남구 테헤란로 123번지 402호", elem_classes=["example-btn"]) ex_k6 = gr.Button("• 길가에 피어난 꽃을 보고 눈물을 흘렸다.", elem_classes=["example-btn"]) ex_k7 = gr.Button("• 제12회 국제학술대회 참가비는 50,000원입니다.", elem_classes=["example-btn"]) # Column 2: Japanese (7 Cases) with gr.Column(scale=1, min_width=0): gr.Markdown("**🇯🇵 Japanese (JA)**") ex_j1 = gr.Button("• 昭和58年4月15日, 東京ディズニーランドが開業した。", elem_classes=["example-btn"]) ex_j2 = gr.Button("• 1日と2日に1人で9日間旅行した。", elem_classes=["example-btn"]) ex_j3 = gr.Button("• 角を曲がると角が生えた鬼がいた。", elem_classes=["example-btn"]) ex_j4 = gr.Button("• 午後7時30分に渋谷駅ハチ公前で会いましょう。", elem_classes=["example-btn"]) ex_j5 = gr.Button("• 日本の首都は東京で, 人口は約1400万人です。", elem_classes=["example-btn"]) ex_j6 = gr.Button("• 富士山の標高は3776mで, 日本一高い山です。", elem_classes=["example-btn"]) ex_j7 = gr.Button("• 2025年1月1日午前0時に初詣に行きます。", elem_classes=["example-btn"]) # Column 3: English (7 Cases) with gr.Column(scale=1, min_width=0): gr.Markdown("**🇺🇸 English (EN)**") ex_e1 = gr.Button("• I read the book yesterday and read it again today.", elem_classes=["example-btn"]) ex_e2 = gr.Button("• The lead pipe was used to lead the team.", elem_classes=["example-btn"]) ex_e3 = gr.Button("• It costs $50.75 for 3 items on Jan 15th, 2025.", elem_classes=["example-btn"]) ex_e4 = gr.Button("• Flight AA123 arrives at 10:45 AM on Gate B12.", elem_classes=["example-btn"]) ex_e5 = gr.Button("• The temperature dropped to -5.5°C with 80% humidity.", elem_classes=["example-btn"]) ex_e6 = gr.Button("• Call us at +1 (555) 019-2834 or visit room 404.", elem_classes=["example-btn"]) ex_e7 = gr.Button("• He drove 65 mph for 120 miles in 2 hours.", elem_classes=["example-btn"]) # Event Handlers btn_submit.click( fn=run_snap_full_demo, inputs=[input_text, language, g2p_mode], outputs=[out_tn, out_g2p, out_ipa, out_ipa_ssml] ) # Test Case Wire-up (Korean) ex_k1.click(lambda: ("100달러를 환전하고 3.5km를 걸었습니다.", "ko"), outputs=[input_text, language]) ex_k2.click(lambda: ("2월 2일 2시에 2번 출구에서 2명과 만남.", "ko"), outputs=[input_text, language]) ex_k3.click(lambda: ("사과 3개와 차 2대를 사서 101호로 갔다.", "ko"), outputs=[input_text, language]) ex_k4.click(lambda: ("2024년 5월 28일 오후 3시 45분 50초.", "ko"), outputs=[input_text, language]) ex_k5.click(lambda: ("서울시 강남구 테헤란로 123번지 402호", "ko"), outputs=[input_text, language]) ex_k6.click(lambda: ("길가에 피어난 꽃을 보고 눈물을 흘렸다.", "ko"), outputs=[input_text, language]) ex_k7.click(lambda: ("제12회 국제학술대회 참가비는 50,000원입니다.", "ko"), outputs=[input_text, language]) # Test Case Wire-up (Japanese) ex_j1.click(lambda: ("昭和58年4月15日, 東京ディズニーランドが開業した。", "ja"), outputs=[input_text, language]) ex_j2.click(lambda: ("1日と2日に1人で9日間旅行した。", "ja"), outputs=[input_text, language]) ex_j3.click(lambda: ("角を曲がると角が生えた鬼がいた。", "ja"), outputs=[input_text, language]) ex_j4.click(lambda: ("午後7時30分に渋谷駅ハチ公前で会いましょう。", "ja"), outputs=[input_text, language]) ex_j5.click(lambda: ("日本の首都は東京で, 人口は約1400万人です。", "ja"), outputs=[input_text, language]) ex_j6.click(lambda: ("富士山の標高は3776mで, 日本一高い山です。", "ja"), outputs=[input_text, language]) ex_j7.click(lambda: ("2025年1月1日午前0時に初詣に行きます。", "ja"), outputs=[input_text, language]) # Test Case Wire-up (English) ex_e1.click(lambda: ("I read the book yesterday and read it again today.", "en"), outputs=[input_text, language]) ex_e2.click(lambda: ("The lead pipe was used to lead the team.", "en"), outputs=[input_text, language]) ex_e3.click(lambda: ("It costs $50.75 for 3 items on Jan 15th, 2025.", "en"), outputs=[input_text, language]) ex_e4.click(lambda: ("Flight AA123 arrives at 10:45 AM on Gate B12.", "en"), outputs=[input_text, language]) ex_e5.click(lambda: ("The temperature dropped to -5.5°C with 80% humidity.", "en"), outputs=[input_text, language]) ex_e6.click(lambda: ("Call us at +1 (555) 019-2834 or visit room 404.", "en"), outputs=[input_text, language]) ex_e7.click(lambda: ("He drove 65 mph for 120 miles in 2 hours.", "en"), outputs=[input_text, language]) # Footer gr.HTML("""
Powered by SNAP C++ Native Engine • GitHub: snap-libs/snap_cpp
""") if __name__ == "__main__": demo.launch(server_name="0.0.0.0", server_port=7860)