Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import requests | |
| import os | |
| from google import genai | |
| import json | |
| # --- 設定 API 金鑰 --- | |
| def setup_api_key(): | |
| """ | |
| 設定 Google API 金鑰。 | |
| """ | |
| api_key = os.environ.get('GOOGLE_API_KEY') | |
| if not api_key or api_key == "YOUR_API_KEY_HERE": | |
| print("警告:環境變數 'GOOGLE_API_KEY' 未設定或無效。AI 功能將無法使用。") | |
| return False | |
| else: | |
| print("成功從環境變數讀取 GOOGLE_API_KEY。") | |
| return True | |
| api_available = setup_api_key() | |
| client = None | |
| if api_available: | |
| try: | |
| client = genai.Client(api_key=os.environ["GOOGLE_API_KEY"]) | |
| except Exception as e: | |
| print(f"初始化 Google API Client 時發生錯誤: {e}") | |
| api_available = False | |
| # --- 元素資料定義 --- | |
| ELEMENTS_DATA = { | |
| "H": {"name": "氫", "symbol": "H", "number": 1, "period": 1, "group": 1, "category": "nonmetal"}, | |
| "He": {"name": "氦", "symbol": "He", "number": 2, "period": 1, "group": 18, "category": "noble_gas"}, | |
| "Li": {"name": "鋰", "symbol": "Li", "number": 3, "period": 2, "group": 1, "category": "alkali_metal"}, | |
| "Be": {"name": "鈹", "symbol": "Be", "number": 4, "period": 2, "group": 2, "category": "alkaline_earth"}, | |
| "B": {"name": "硼", "symbol": "B", "number": 5, "period": 2, "group": 13, "category": "metalloid"}, | |
| "C": {"name": "碳", "symbol": "C", "number": 6, "period": 2, "group": 14, "category": "nonmetal"}, | |
| "N": {"name": "氮", "symbol": "N", "number": 7, "period": 2, "group": 15, "category": "nonmetal"}, | |
| "O": {"name": "氧", "symbol": "O", "number": 8, "period": 2, "group": 16, "category": "nonmetal"}, | |
| "F": {"name": "氟", "symbol": "F", "number": 9, "period": 2, "group": 17, "category": "halogen"}, | |
| "Ne": {"name": "氖", "symbol": "Ne", "number": 10, "period": 2, "group": 18, "category": "noble_gas"}, | |
| "Na": {"name": "鈉", "symbol": "Na", "number": 11, "period": 3, "group": 1, "category": "alkali_metal"}, | |
| "Mg": {"name": "鎂", "symbol": "Mg", "number": 12, "period": 3, "group": 2, "category": "alkaline_earth"}, | |
| "Al": {"name": "鋁", "symbol": "Al", "number": 13, "period": 3, "group": 13, "category": "post_transition"}, | |
| "Si": {"name": "矽", "symbol": "Si", "number": 14, "period": 3, "group": 14, "category": "metalloid"}, | |
| "P": {"name": "磷", "symbol": "P", "number": 15, "period": 3, "group": 15, "category": "nonmetal"}, | |
| "S": {"name": "硫", "symbol": "S", "number": 16, "period": 3, "group": 16, "category": "nonmetal"}, | |
| "Cl": {"name": "氯", "symbol": "Cl", "number": 17, "period": 3, "group": 17, "category": "halogen"}, | |
| "Ar": {"name": "氬", "symbol": "Ar", "number": 18, "period": 3, "group": 18, "category": "noble_gas"}, | |
| "K": {"name": "鉀", "symbol": "K", "number": 19, "period": 4, "group": 1, "category": "alkali_metal"}, | |
| "Ca": {"name": "鈣", "symbol": "Ca", "number": 20, "period": 4, "group": 2, "category": "alkaline_earth"}, | |
| "Sc": {"name": "鈧", "symbol": "Sc", "number": 21, "period": 4, "group": 3, "category": "transition"}, | |
| "Ti": {"name": "鈦", "symbol": "Ti", "number": 22, "period": 4, "group": 4, "category": "transition"}, | |
| "V": {"name": "釩", "symbol": "V", "number": 23, "period": 4, "group": 5, "category": "transition"}, | |
| "Cr": {"name": "鉻", "symbol": "Cr", "number": 24, "period": 4, "group": 6, "category": "transition"}, | |
| "Mn": {"name": "錳", "symbol": "Mn", "number": 25, "period": 4, "group": 7, "category": "transition"}, | |
| "Fe": {"name": "鐵", "symbol": "Fe", "number": 26, "period": 4, "group": 8, "category": "transition"}, | |
| "Co": {"name": "鈷", "symbol": "Co", "number": 27, "period": 4, "group": 9, "category": "transition"}, | |
| "Ni": {"name": "鎳", "symbol": "Ni", "number": 28, "period": 4, "group": 10, "category": "transition"}, | |
| "Cu": {"name": "銅", "symbol": "Cu", "number": 29, "period": 4, "group": 11, "category": "transition"}, | |
| "Zn": {"name": "鋅", "symbol": "Zn", "number": 30, "period": 4, "group": 12, "category": "transition"}, | |
| "Ga": {"name": "鎵", "symbol": "Ga", "number": 31, "period": 4, "group": 13, "category": "post_transition"}, | |
| "Ge": {"name": "鍺", "symbol": "Ge", "number": 32, "period": 4, "group": 14, "category": "metalloid"}, | |
| "As": {"name": "砷", "symbol": "As", "number": 33, "period": 4, "group": 15, "category": "metalloid"}, | |
| "Se": {"name": "硒", "symbol": "Se", "number": 34, "period": 4, "group": 16, "category": "nonmetal"}, | |
| "Br": {"name": "溴", "symbol": "Br", "number": 35, "period": 4, "group": 17, "category": "halogen"}, | |
| "Kr": {"name": "氪", "symbol": "Kr", "number": 36, "period": 4, "group": 18, "category": "noble_gas"}, | |
| "Rb": {"name": "銣", "symbol": "Rb", "number": 37, "period": 5, "group": 1, "category": "alkali_metal"}, | |
| "Sr": {"name": "鍶", "symbol": "Sr", "number": 38, "period": 5, "group": 2, "category": "alkaline_earth"}, | |
| "Y": {"name": "釔", "symbol": "Y", "number": 39, "period": 5, "group": 3, "category": "transition"}, | |
| "Zr": {"name": "鋯", "symbol": "Zr", "number": 40, "period": 5, "group": 4, "category": "transition"}, | |
| "Nb": {"name": "鈮", "symbol": "Nb", "number": 41, "period": 5, "group": 5, "category": "transition"}, | |
| "Mo": {"name": "鉬", "symbol": "Mo", "number": 42, "period": 5, "group": 6, "category": "transition"}, | |
| "Tc": {"name": "鎝", "symbol": "Tc", "number": 43, "period": 5, "group": 7, "category": "transition"}, | |
| "Ru": {"name": "釕", "symbol": "Ru", "number": 44, "period": 5, "group": 8, "category": "transition"}, | |
| "Rh": {"name": "銠", "symbol": "Rh", "number": 45, "period": 5, "group": 9, "category": "transition"}, | |
| "Pd": {"name": "鈀", "symbol": "Pd", "number": 46, "period": 5, "group": 10, "category": "transition"}, | |
| "Ag": {"name": "銀", "symbol": "Ag", "number": 47, "period": 5, "group": 11, "category": "transition"}, | |
| "Cd": {"name": "鎘", "symbol": "Cd", "number": 48, "period": 5, "group": 12, "category": "transition"}, | |
| "In": {"name": "銦", "symbol": "In", "number": 49, "period": 5, "group": 13, "category": "post_transition"}, | |
| "Sn": {"name": "錫", "symbol": "Sn", "number": 50, "period": 5, "group": 14, "category": "post_transition"}, | |
| "Sb": {"name": "銻", "symbol": "Sb", "number": 51, "period": 5, "group": 15, "category": "metalloid"}, | |
| "Te": {"name": "碲", "symbol": "Te", "number": 52, "period": 5, "group": 16, "category": "metalloid"}, | |
| "I": {"name": "碘", "symbol": "I", "number": 53, "period": 5, "group": 17, "category": "halogen"}, | |
| "Xe": {"name": "氙", "symbol": "Xe", "number": 54, "period": 5, "group": 18, "category": "noble_gas"}, | |
| "Cs": {"name": "銫", "symbol": "Cs", "number": 55, "period": 6, "group": 1, "category": "alkali_metal"}, | |
| "Ba": {"name": "鋇", "symbol": "Ba", "number": 56, "period": 6, "group": 2, "category": "alkaline_earth"}, | |
| "La": {"name": "鑭", "symbol": "La", "number": 57, "period": 6, "group": 3, "category": "lanthanide"}, | |
| "Hf": {"name": "鉿", "symbol": "Hf", "number": 72, "period": 6, "group": 4, "category": "transition"}, | |
| "Ta": {"name": "鉭", "symbol": "Ta", "number": 73, "period": 6, "group": 5, "category": "transition"}, | |
| "W": {"name": "鎢", "symbol": "W", "number": 74, "period": 6, "group": 6, "category": "transition"}, | |
| "Re": {"name": "錸", "symbol": "Re", "number": 75, "period": 6, "group": 7, "category": "transition"}, | |
| "Os": {"name": "鋨", "symbol": "Os", "number": 76, "period": 6, "group": 8, "category": "transition"}, | |
| "Ir": {"name": "銥", "symbol": "Ir", "number": 77, "period": 6, "group": 9, "category": "transition"}, | |
| "Pt": {"name": "鉑", "symbol": "Pt", "number": 78, "period": 6, "group": 10, "category": "transition"}, | |
| "Au": {"name": "金", "symbol": "Au", "number": 79, "period": 6, "group": 11, "category": "transition"}, | |
| "Hg": {"name": "汞", "symbol": "Hg", "number": 80, "period": 6, "group": 12, "category": "transition"}, | |
| "Tl": {"name": "鉈", "symbol": "Tl", "number": 81, "period": 6, "group": 13, "category": "post_transition"}, | |
| "Pb": {"name": "鉛", "symbol": "Pb", "number": 82, "period": 6, "group": 14, "category": "post_transition"}, | |
| "Bi": {"name": "鉍", "symbol": "Bi", "number": 83, "period": 6, "group": 15, "category": "post_transition"}, | |
| "Po": {"name": "釙", "symbol": "Po", "number": 84, "period": 6, "group": 16, "category": "post_transition"}, | |
| "At": {"name": "砈", "symbol": "At", "number": 85, "period": 6, "group": 17, "category": "halogen"}, | |
| "Rn": {"name": "氡", "symbol": "Rn", "number": 86, "period": 6, "group": 18, "category": "noble_gas"}, | |
| "Fr": {"name": "鍅", "symbol": "Fr", "number": 87, "period": 7, "group": 1, "category": "alkali_metal"}, | |
| "Ra": {"name": "鐳", "symbol": "Ra", "number": 88, "period": 7, "group": 2, "category": "alkaline_earth"}, | |
| "Ac": {"name": "錒", "symbol": "Ac", "number": 89, "period": 7, "group": 3, "category": "actinide"}, | |
| "Rf": {"name": "鑪", "symbol": "Rf", "number": 104, "period": 7, "group": 4, "category": "transition"}, | |
| "Db": {"name": "𨧀", "symbol": "Db", "number": 105, "period": 7, "group": 5, "category": "transition"}, | |
| "Sg": {"name": "𨭎", "symbol": "Sg", "number": 106, "period": 7, "group": 6, "category": "transition"}, | |
| "Bh": {"name": "𨨏", "symbol": "Bh", "number": 107, "period": 7, "group": 7, "category": "transition"}, | |
| "Hs": {"name": "𨭆", "symbol": "Hs", "number": 108, "period": 7, "group": 8, "category": "transition"}, | |
| "Mt": {"name": "䥑", "symbol": "Mt", "number": 109, "period": 7, "group": 9, "category": "transition"}, | |
| "Ds": {"name": "𨭌", "symbol": "Ds", "number": 110, "period": 7, "group": 10, "category": "transition"}, | |
| "Rg": {"name": "錀", "symbol": "Rg", "number": 111, "period": 7, "group": 11, "category": "transition"}, | |
| "Cn": {"name": "鎶", "symbol": "Cn", "number": 112, "period": 7, "group": 12, "category": "transition"}, | |
| "Nh": {"name": "鉨", "symbol": "Nh", "number": 113, "period": 7, "group": 13, "category": "post_transition"}, | |
| "Fl": {"name": "鈇", "symbol": "Fl", "number": 114, "period": 7, "group": 14, "category": "post_transition"}, | |
| "Mc": {"name": "鏌", "symbol": "Mc", "number": 115, "period": 7, "group": 15, "category": "post_transition"}, | |
| "Lv": {"name": "鉝", "symbol": "Lv", "number": 116, "period": 7, "group": 16, "category": "post_transition"}, | |
| "Ts": {"name": "鿬", "symbol": "Ts", "number": 117, "period": 7, "group": 17, "category": "halogen"}, | |
| "Og": {"name": "鿫", "symbol": "Og", "number": 118, "period": 7, "group": 18, "category": "noble_gas"}, | |
| } | |
| # 顏色配置 | |
| CATEGORY_COLORS = { | |
| "alkali_metal": "#FF6B6B", "alkaline_earth": "#FFA726", "transition": "#42A5F5", | |
| "post_transition": "#66BB6A", "metalloid": "#AB47BC", "nonmetal": "#FFCA28", | |
| "halogen": "#26C6DA", "noble_gas": "#EC407A", "lanthanide": "#8D6E63", "actinide": "#78909C", | |
| } | |
| # --- 核心函式 --- | |
| def get_element_image(symbol): | |
| """獲取元素圖片""" | |
| image_url = f"https://www.webelements.com/_media/elements/element_pictures/{symbol}.jpg" | |
| try: | |
| response = requests.head(image_url, timeout=5) | |
| response.raise_for_status() | |
| return image_url | |
| except requests.exceptions.RequestException as e: | |
| print(f"獲取圖片時發生錯誤: {e}") | |
| return "https://dummyimage.com/400x400/2c3e50/ecf0f1.png&text=image+not+found" | |
| def get_element_trivia(element_name): | |
| """使用 Gemini API 生成元素冷知識""" | |
| if not client: | |
| return "錯誤:Google API 金鑰未設定或無效,無法生成 AI 資訊。" | |
| try: | |
| prompt = ( | |
| f"請你扮演一位化學知識淵博的科學家,用生動有趣的方式介紹化學元素「{element_name}」。" | |
| "請包含以下幾點,並用繁體中文回答:\n" | |
| "1. **一個最驚人的冷知識**:提供一個最讓人意想不到的有趣事實。\n" | |
| "2. **發現與命名**:簡述這個元素的發現歷史或命名由來。\n" | |
| "3. **生活中的應用**:舉出 2-3 個它在日常生活、科技或工業上的重要應用。\n" | |
| "4. **對人體的影響**:說明它對人體是必需、有毒、還是無關。\n" | |
| "請讓內容兼具知識性與趣味性,排版清晰易讀,適合一般大眾閱讀。" | |
| ) | |
| response = client.models.generate_content( | |
| model="gemini-2.0-flash-lite", | |
| contents=prompt | |
| ) | |
| return response.text | |
| except Exception as e: | |
| print(f"呼叫 Gemini API 時發生錯誤: {e}") | |
| return f"無法生成關於「{element_name}」的資訊,請檢查您的 API 金鑰設定或稍後再試。" | |
| def create_periodic_table_html(): | |
| """創建互動式元素週期表 HTML""" | |
| table_layout = [ | |
| [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], | |
| [3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 7, 8, 9, 10], | |
| [11, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 14, 15, 16, 17, 18], | |
| [19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36], | |
| [37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54], | |
| [55, 56, 57, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86], | |
| [87, 88, 89, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118], | |
| ] | |
| number_to_element = {data["number"]: symbol for symbol, data in ELEMENTS_DATA.items()} | |
| html = """ | |
| <style> | |
| .periodic-table { display: grid; grid-template-columns: repeat(18, 1fr); gap: 2px; padding: 10px; border-radius: 15px; } | |
| .element-cell { aspect-ratio: 1; border: 1px solid #FFFFFF44; border-radius: 8px; display: flex; flex-direction: column; justify-content: center; align-items: center; cursor: pointer; transition: all 0.3s ease; font-family: 'Arial', sans-serif; font-weight: bold; color: white; text-shadow: 1px 1px 2px rgba(0,0,0,0.5); position: relative; overflow: hidden; } | |
| .element-cell:hover { transform: scale(1.1); box-shadow: 0 5px 15px rgba(0,0,0,0.4); z-index: 10; } | |
| .element-cell.selected { border: 2px solid #FFD700; box-shadow: 0 0 20px rgba(255,215,0,0.8); } | |
| .element-symbol { font-size: 1.2vw; font-weight: bold; margin-bottom: 2px; } | |
| .element-number { font-size: 0.7vw; position: absolute; top: 4px; left: 4px; } | |
| .element-name { font-size: 0.7vw; margin-top: 2px; } | |
| .empty-cell { background: transparent; border: none; cursor: default; } | |
| .empty-cell:hover { transform: none; box-shadow: none; } | |
| .legend { margin-top: 20px; padding: 15px; background: rgba(0,0,0,0.2); border-radius: 10px; display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; } | |
| .legend-item { display: flex; align-items: center; gap: 5px; padding: 5px 10px; border-radius: 5px; color: white; } | |
| .legend-color { width: 20px; height: 20px; border-radius: 3px; border: 1px solid #FFF; } | |
| .title { text-align: center; color: white; font-size: 28px; font-weight: bold; margin-bottom: 10px; text-shadow: 2px 2px 4px rgba(0,0,0,0.5); } | |
| @media (max-width: 1200px) { .element-symbol { font-size: 1.5vw; } .element-number, .element-name { font-size: 1vw; } } | |
| @media (max-width: 768px) { .element-symbol { font-size: 2vw; } .element-number, .element-name { font-size: 1.5vw; } } | |
| </style> | |
| <!-- <div class="title">🧪 元素週期表 🧪</div> --> | |
| <div class="periodic-table" id="periodic-table-container"> | |
| """ | |
| for row in table_layout: | |
| for atomic_number in row: | |
| if atomic_number == 0: | |
| html += '<div class="element-cell empty-cell"></div>' | |
| else: | |
| element_symbol = number_to_element.get(atomic_number, "") | |
| if element_symbol and element_symbol in ELEMENTS_DATA: | |
| element_data = ELEMENTS_DATA[element_symbol] | |
| color = CATEGORY_COLORS.get(element_data["category"], "#888888") | |
| html += f''' | |
| <div class="element-cell" | |
| style="background-color: {color};" | |
| data-symbol="{element_symbol}"> | |
| <div class="element-number">{atomic_number}</div> | |
| <div class="element-symbol">{element_symbol}</div> | |
| <div class="element-name">{element_data['name']}</div> | |
| </div> | |
| ''' | |
| else: | |
| html += '<div class="element-cell empty-cell"></div>' | |
| html += "</div><div class='legend'>" | |
| for category, color in CATEGORY_COLORS.items(): | |
| html += f""" | |
| <div class="legend-item"> | |
| <div class="legend-color" style="background-color: {color};"></div> | |
| <span>{get_category_chinese(category)}</span> | |
| </div> | |
| """ | |
| html += "</div>" | |
| return html | |
| def get_category_chinese(category): | |
| """將英文類別轉換為中文""" | |
| category_map = { | |
| "alkali_metal": "鹼金屬", "alkaline_earth": "鹼土金屬", "transition": "過渡金屬", | |
| "post_transition": "後過渡金屬", "metalloid": "類金屬", "nonmetal": "非金屬", | |
| "halogen": "鹵素", "noble_gas": "惰性氣體", "lanthanide": "鑭系元素", "actinide": "錒系元素", | |
| } | |
| return category_map.get(category, "未知") | |
| # --- 建立 Gradio 介面 --- | |
| def create_interface(): | |
| """創建主要的 Gradio 介面""" | |
| DEVELOPER_NAME = "陳咨米、阮喆楷、黃聖紘、李依庭" | |
| app_description = f""" | |
| # 🧪 AI 元素週期表冷知識探索器 🧪 | |
| <p style="font-size: 1.2rem; font-weight: bold; margin-top: 20px;margin-bottom: 20px !important;">Designed by: {DEVELOPER_NAME}</p> | |
| 歡迎使用元素週期表冷知識探索器!點擊下方的互動式週期表中任何一個元素,即可查看其照片與 AI 生成的詳細介紹。 | |
| """ | |
| js_code = """ | |
| function gradio_init() { | |
| const url = new URL(window.location); | |
| // 檢查 URL 是否已經是 dark mode | |
| if (url.searchParams.get('__theme') !== 'dark') { | |
| // 如果不是,設定參數並重新載入 | |
| url.searchParams.set('__theme', 'dark'); | |
| window.location.href = url.href; | |
| } else { | |
| // 設定事件監聽 | |
| const observer = new MutationObserver((mutations, obs) => { | |
| const table = document.getElementById('periodic-table-container'); | |
| if (table) { | |
| console.log("Periodic table found, attaching event listener."); | |
| let selectedElementDiv = null; | |
| table.addEventListener('click', function(event) { | |
| const targetCell = event.target.closest('.element-cell'); | |
| if (targetCell && !targetCell.classList.contains('empty-cell')) { | |
| const symbol = targetCell.dataset.symbol; | |
| console.log(`Element clicked: ${symbol}`); | |
| if (selectedElementDiv) { | |
| selectedElementDiv.classList.remove('selected'); | |
| } | |
| targetCell.classList.add('selected'); | |
| selectedElementDiv = targetCell; | |
| const hidden_input_component = document.getElementById('hidden_trigger_for_js'); | |
| if (hidden_input_component) { | |
| const textarea = hidden_input_component.querySelector('textarea'); | |
| if (textarea) { | |
| textarea.value = symbol; | |
| textarea.dispatchEvent(new Event('input', { bubbles: true })); | |
| } | |
| } | |
| } | |
| }); | |
| obs.disconnect(); | |
| } | |
| }); | |
| observer.observe(document.body, { | |
| childList: true, | |
| subtree: true | |
| }); | |
| } | |
| } | |
| """ | |
| with gr.Blocks( | |
| theme=gr.themes.Soft(primary_hue="purple", secondary_hue="blue", neutral_hue="gray"), | |
| css=".gradio-container { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); font-family: 'Arial', sans-serif; }", | |
| js=js_code | |
| ) as app: | |
| gr.Markdown(app_description) | |
| with gr.Row(): | |
| periodic_table = gr.HTML(value=create_periodic_table_html()) | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| with gr.Group(): | |
| element_image = gr.Image( | |
| label="元素照片", height=400, show_label=True, | |
| value="https://dummyimage.com/400x400/2c3e50/ecf0f1.png&text=click+to+explore+!" | |
| ) | |
| element_info_html = gr.HTML( | |
| value="<div style='padding: 10px; text-align: center;'>請選擇一個元素</div>", | |
| label="📊 元素基本資訊" | |
| ) | |
| with gr.Column(scale=1): | |
| element_trivia = gr.Textbox( | |
| label="🧠 元素冷知識 (AI 生成)", lines=20, | |
| interactive=False, placeholder="選擇一個元素來查看詳細資訊..." | |
| ) | |
| # 建立一個隱藏的 Textbox,作為 JS 和 Python 之間的橋樑 | |
| hidden_trigger = gr.Textbox(visible=False, elem_id="hidden_trigger_for_js") | |
| # 定義處理元素選擇的核心函數 | |
| def process_element_selection(symbol): | |
| if not symbol or symbol not in ELEMENTS_DATA: | |
| return ( | |
| "https://dummyimage.com/400x400/2c3e50/ecf0f1.png&text=invalid+choice", | |
| "<div style='padding: 10px; text-align: center;'>請選擇一個有效的元素</div>", | |
| "請從左側週期表中選擇一個有效的元素。" | |
| ) | |
| element_data = ELEMENTS_DATA[symbol] | |
| name = element_data["name"] | |
| print(f"正在處理元素: {name} ({symbol})") | |
| # 生成基本資訊 HTML | |
| info_html = f""" | |
| <div style='padding:10px'> | |
| <h3 style='color: #007bff; margin-top: 0; margin-bottom: 15px; text-align:center;'> | |
| {name} ({symbol}) | |
| </h3> | |
| <div style='display: grid; grid-template-columns: 1fr 1fr; gap: 10px; font-size: 14px;'> | |
| <div><strong>原子序:</strong>{element_data['number']}</div> | |
| <div><strong>週期:</strong>{element_data['period']}</div> | |
| <div><strong>族:</strong>{element_data['group']}</div> | |
| <div><strong>類型:</strong>{get_category_chinese(element_data['category'])}</div> | |
| </div> | |
| </div> | |
| """ | |
| image_url = get_element_image(symbol) | |
| trivia_text = get_element_trivia(name) | |
| return image_url, info_html, trivia_text | |
| # 綁定事件:當隱藏的 Textbox 值改變時,觸發核心處理函數 | |
| hidden_trigger.change( | |
| fn=process_element_selection, | |
| inputs=hidden_trigger, | |
| outputs=[element_image, element_info_html, element_trivia] | |
| ) | |
| # 快速範例 | |
| gr.Examples( | |
| examples=["H", "C", "O", "Cs", "Ca"], | |
| inputs=hidden_trigger, | |
| outputs=[element_image, element_info_html, element_trivia], | |
| fn=process_element_selection, | |
| cache_examples=False, | |
| label="快速範例" | |
| ) | |
| # 透過 app.load 觸發 JS 初始化函式 | |
| app.load(fn=None, js="gradio_init") | |
| return app | |
| # 創建並啟動應用程式 | |
| app = create_interface() | |
| print("🚀 啟動元素週期表探索器...") | |
| app.launch(debug=False, share=True, show_error=True, show_api=False) |