""" 大宗商品即期價格 v3 配色:米白暖灰(護眼) 字體:全面放大 """ import yfinance as yf import pandas as pd import numpy as np import matplotlib matplotlib.use("Agg") import matplotlib.pyplot as plt import gradio as gr from datetime import datetime, timedelta import pytz, io, warnings warnings.filterwarnings("ignore") # 中文字型 import subprocess try: subprocess.run(["apt-get","install","-y","-q","fonts-noto-cjk"], capture_output=True) import matplotlib.font_manager as fm fm._load_fontmanager(try_read_cache=False) plt.rcParams["font.family"] = ["Noto Sans CJK TC","DejaVu Sans"] except Exception: pass # ── 配色 ── BG_PAGE = "#F8F5F0" BG_HEADER = "#4A3728" BG_CARD = "#FFFFFF" BG_INNER = "#F8F5F0" C_BORDER = "#D4C5A9" C_TITLE = "#F5DEB3" C_SUB = "#C4A882" C_TEXT = "#2C1810" C_MUTED = "#8B7355" C_UP = "#1A7A1A" C_DOWN = "#CC3300" COMMODITIES = { "黃金": {"ticker":"GC=F", "unit":"USD / 盎司", "color":"#DAA520"}, "白銀": {"ticker":"SI=F", "unit":"USD / 盎司", "color":"#888888"}, "石油(WTI)": {"ticker":"CL=F", "unit":"USD / 桶", "color":"#8B4513"}, "比特幣": {"ticker":"BTC-USD", "unit":"USD", "color":"#F7931A"}, "以太幣": {"ticker":"ETH-USD", "unit":"USD", "color":"#627EEA"}, } def get_usdtwd(): try: h = yf.Ticker("USDTWD=X").history(period="5d") if not h.empty: return float(h["Close"].iloc[-1]) except Exception: pass return 31.5 def get_data(ticker, days=10): try: end = datetime.now() start = end - timedelta(days=days+7) df = yf.download(ticker, start=start, end=end, auto_adjust=True, progress=False) if df.empty: return None if isinstance(df.columns, pd.MultiIndex): df.columns = df.columns.get_level_values(0) return df[["Close"]].dropna().tail(days) except Exception: return None def make_spark(df, color, name): fig, ax = plt.subplots(figsize=(5, 2.2)) fig.patch.set_facecolor(BG_CARD) ax.set_facecolor(BG_INNER) if df is not None and len(df) >= 2: prices = df["Close"].squeeze().values xs = list(range(len(prices))) ax.plot(xs, prices, color=color, linewidth=2.8, zorder=3) ax.fill_between(xs, prices, prices.min()*0.998, alpha=0.15, color=color, zorder=2) ax.annotate(f"{prices[-1]:,.2f}", xy=(xs[-1], prices[-1]), xytext=(-55, 8), textcoords="offset points", color=color, fontsize=12, fontweight="bold") ax.set_xlim(xs[0], xs[-1]) ax.set_ylim(prices.min()*0.994, prices.max()*1.006) else: ax.text(0.5, 0.5, "資料載入中", ha="center", va="center", color=C_MUTED, transform=ax.transAxes, fontsize=13) ax.set_title(name, color=color, fontsize=14, fontweight="bold", pad=5, loc="left") ax.tick_params(colors=C_MUTED, labelsize=9) for sp in ax.spines.values(): sp.set_edgecolor(C_BORDER) ax.grid(axis="y", color=C_BORDER, linewidth=0.6, alpha=0.7) ax.set_xlabel("近 7 交易日", color=C_MUTED, fontsize=9) plt.tight_layout(pad=0.6) buf = io.BytesIO() fig.savefig(buf, format="png", dpi=140, facecolor=BG_CARD) buf.seek(0) plt.close(fig) from PIL import Image return Image.open(buf) def build_card(name, price, chg_abs, chg_pct, unit, color, usdtwd, now): if price is None: return f"""
大宗商品即期價格
黃金 · 白銀 · 石油 · 比特幣 · 以太幣 | USD + TWD 雙幣顯示 | 7日走勢圖
📊 即期價格
') cards_out = gr.HTML() gr.HTML(f'📈 7日走勢圖
') with gr.Row(): gold_img = gr.Image(label="🥇 黃金", show_label=True, height=200) silver_img = gr.Image(label="🥈 白銀", show_label=True, height=200) oil_img = gr.Image(label="🛢️ 石油(WTI)", show_label=True, height=200) with gr.Row(): btc_img = gr.Image(label="₿ 比特幣", show_label=True, height=200) eth_img = gr.Image(label="◈ 以太幣", show_label=True, height=200) gr.HTML(f"""