Spaces:
Sleeping
Sleeping
File size: 6,184 Bytes
25c28fc 087e783 25c28fc 6c9375d 25c28fc 087e783 25c28fc 087e783 25c28fc 087e783 25c28fc a577b50 25c28fc 480e488 25c28fc |
1 2 3 4 5 6 7 8 9 10 11 12 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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
import gradio as gr
import pandas as pd
from pytrends.request import TrendReq
import plotly.express as px
import plotly.graph_objects as go
DEVELOPER_NAME = "黃千宥、陳奕瑄、汪于捷、李哲弘、洪寓澤"
# 初始化 pytrends
# hl='zh-TW' -> 繁體中文, tz=480 -> 台灣時區 (GMT+8)
pytrends = TrendReq(hl='zh-TW', tz=480)
PLOTLY_TEMPLATE = "plotly_dark"
def analyze_google_trends(keywords_str: str, timeframe: str):
"""
根據輸入的關鍵字和時間範圍,從 Google Trends 獲取並分析資料。
Args:
keywords_str: 以逗號分隔的關鍵字字串。
timeframe: Gradio 選項對應的時間範圍字串。
Returns:
一個包含兩個 Plotly 圖表的元組 (時間趨勢圖, 區域熱度圖)。
"""
if not keywords_str:
gr.Warning("請至少輸入一個關鍵字!")
# 回傳空的圖表
return go.Figure(), go.Figure()
# 解析關鍵字
kw_list = [kw.strip() for kw in keywords_str.split(',')]
if len(kw_list) > 5:
gr.Warning("為了圖表清晰,最多支援比較 5 個關鍵字。")
kw_list = kw_list[:5]
# 對應 Gradio 選項到 pytrends 的時間格式
timeframe_map = {
"過去 7 天": 'now 7-d',
"過去一個月": 'today 1-m',
"過去三個月": 'today 3-m',
"過去一年": 'today 12-m',
}
selected_timeframe = timeframe_map.get(timeframe, 'now 7-d')
try:
# 1. 獲取時間序列資料
pytrends.build_payload(kw_list, cat=0, timeframe=selected_timeframe, geo='', gprop='')
interest_over_time_df = pytrends.interest_over_time()
if interest_over_time_df.empty:
gr.Warning(f"找不到關於 '{keywords_str}' 的時間趨勢資料。")
time_fig = go.Figure()
else:
interest_over_time_df = interest_over_time_df.drop(columns=['isPartial'], errors='ignore')
time_fig = plot_interest_over_time(interest_over_time_df, f"'{', '.join(kw_list)}' 在 {timeframe} 的搜尋熱度趨勢")
# 2. 獲取區域熱度資料
# 注意:區域熱度分析不支援多個關鍵字同時比較,因此我們只分析第一個關鍵字
first_keyword = kw_list[0]
pytrends.build_payload([first_keyword], cat=0, timeframe=selected_timeframe, geo='', gprop='')
interest_by_region_df = pytrends.interest_by_region(resolution='COUNTRY', inc_low_vol=True, inc_geo_code=False)
if interest_by_region_df.empty:
gr.Warning(f"找不到關於 '{first_keyword}' 的區域熱度資料。")
region_fig = go.Figure()
else:
# 只取前 20 名
interest_by_region_df = interest_by_region_df.sort_values(by=first_keyword, ascending=False).head(20)
region_fig = plot_interest_by_region(interest_by_region_df, f"'{first_keyword}' 在全球的區域熱度 Top 20")
return time_fig, region_fig
except Exception as e:
gr.Error(f"查詢時發生錯誤: {e}")
return go.Figure(), go.Figure()
def plot_interest_over_time(df: pd.DataFrame, title: str):
"""使用 Plotly 繪製時間趨勢圖。"""
fig = px.line(df, x=df.index, y=df.columns, title=title, labels={'value': '相對熱度', 'date': '日期', 'variable': '關鍵字'})
fig.update_layout(
template=PLOTLY_TEMPLATE,
paper_bgcolor='rgba(0,0,0,0)',
plot_bgcolor='rgba(0,0,0,0.2)',
legend_title_text=''
)
return fig
def plot_interest_by_region(df: pd.DataFrame, title: str):
"""使用 Plotly 繪製區域熱度長條圖。"""
fig = px.bar(df, x=df.index, y=df.columns[0], title=title, labels={'y': '相對熱度', 'index': '國家/地區'})
fig.update_layout(
template=PLOTLY_TEMPLATE,
paper_bgcolor='rgba(0,0,0,0)',
plot_bgcolor='rgba(0,0,0,0.2)'
)
fig.update_xaxes(categoryorder='total descending')
return fig
with gr.Blocks(
theme=gr.themes.Soft(
primary_hue="blue",
secondary_hue="cyan",
font=["Arial", "sans-serif"]
),
js="""
function refresh() {
const url = new URL(window.location);
if (url.searchParams.get('__theme') !== 'dark') {
url.searchParams.set('__theme', 'dark');
window.location.href = url.href;
}
}
"""
) as app:
gr.Markdown(f"""
<div style='text-align: center; padding: 20px; color: white;'>
<h1 style='font-size: 3em; color: #2563eb;'>📊 關鍵字趨勢分析儀表板</h1>
<p style='font-size: 1.2em; color: #A9A9A9;'>輸入關鍵字,洞察全球搜尋趨勢與市場脈動</p>
<p style='font-size: 0.9em; color: #888;'>Designed by: {DEVELOPER_NAME}</p>
</div>
""")
with gr.Group():
with gr.Row():
keywords_input = gr.Textbox(
label="🔍 輸入關鍵字",
placeholder="例如:Bitcoin, Ethereum, Dogecoin (以逗號分隔)",
scale=3
)
timeframe_input = gr.Radio(
["過去 7 天", "過去一個月", "過去三個月", "過去一年"],
label="🗓️ 選擇時間範圍",
value="過去 7 天",
scale=2
)
analyze_button = gr.Button("🚀 開始分析", variant="primary")
with gr.Tabs():
with gr.TabItem("📈 時間趨勢比較"):
time_series_plot = gr.Plot()
with gr.TabItem("🌍 全球區域熱度"):
region_plot = gr.Plot()
gr.Markdown("<p style='text-align: center; color: #888;'>註:區域熱度分析僅針對您輸入的第一個關鍵字。</p>")
analyze_button.click(
fn=analyze_google_trends,
inputs=[keywords_input, timeframe_input],
outputs=[time_series_plot, region_plot]
)
gr.Examples(
examples=[
["Bitcoin, Ethereum", "過去三個月"],
["穩定幣, Coinbase", "過去一年"],
["NVIDIA, AMD, TSMC", "過去一個月"],
],
inputs=[keywords_input, timeframe_input]
)
app.launch(share=True, debug=False, show_error=True, show_api=False) |