YuShen1124 commited on
Commit
df08e13
·
verified ·
1 Parent(s): 6ca3010

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +209 -113
app.py CHANGED
@@ -1,127 +1,223 @@
1
- import os, csv, requests, gradio as gr
2
- from huggingface_hub import hf_hub_download, upload_file
3
- import logging
4
-
5
- # 設定日誌等級
6
- logging.basicConfig(level=logging.INFO)
7
-
8
- # -- 環境變數 & 路徑 --
9
- REPO_ID = os.getenv("REPO_ID", "YuShen1124/youtube-tags-tool")
10
- HF_TOKEN = os.getenv("HF_TOKEN")
11
- YOUTUBE_API_KEY = os.getenv("AIzaSyCvgpJMhcrDao6Li4qMUbFcifFSobbcIZw")
12
- DATA_DIR = "./data"
13
- CSV_FILE = os.path.join(DATA_DIR, "tags_data.csv")
14
- COUNTER_FILE = os.path.join(DATA_DIR, "counter.txt")
15
-
16
- os.makedirs(DATA_DIR, exist_ok=True)
17
-
18
- # 初始化遠端檔案,若不存在則本地建立
19
- def init_file(remote, local):
20
- try:
21
- hf_hub_download(repo_id=REPO_ID, filename=remote, local_dir=DATA_DIR, token=HF_TOKEN)
22
- logging.info(f"Downloaded {remote} from Hub")
23
- except Exception:
24
- open(local, "a", encoding="utf-8").close()
25
- logging.info(f"Initialized empty {local}")
26
-
27
- init_file("tags_data.csv", CSV_FILE)
28
- init_file("counter.txt", COUNTER_FILE)
29
-
30
- # 讀取 CSV
31
  def read_csv_data():
 
32
  data = {}
33
- try:
34
- with open(CSV_FILE, encoding='utf-8', newline='') as f:
35
- for tag, count in csv.reader(f):
36
- data[tag] = int(count)
37
- except Exception as e:
38
- logging.error(f"Error reading CSV: {e}")
 
 
 
 
 
 
 
 
 
39
  return data
40
 
41
- # 寫入並上傳 CSV
42
  def write_csv_data(data):
43
- try:
44
- with open(CSV_FILE, 'w', encoding='utf-8', newline='') as f:
45
- csv.writer(f).writerows(data.items())
46
- upload_file(path_or_fileobj=CSV_FILE, path_in_repo="tags_data.csv",
47
- repo_id=REPO_ID, token=HF_TOKEN)
48
- logging.info("CSV uploaded to Hub")
49
- except Exception as e:
50
- logging.error(f"Error writing/uploading CSV: {e}")
51
-
52
- # 呼叫 YouTube API 取得 tags,附加 timeout 與錯誤處理
53
  def get_video_tags(keyword):
54
- tags_count = {}
55
- try:
56
- resp = requests.get(
57
- "https://www.googleapis.com/youtube/v3/search",
58
- params={'part':'snippet','q':keyword,'type':'video','maxResults':10,'key':YOUTUBE_API_KEY},
59
- timeout=10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  )
61
- resp.raise_for_status()
62
- items = resp.json().get('items', [])
63
- except Exception as e:
64
- logging.error(f"Search API error: {e}")
65
- return tags_count
66
-
67
- for item in items:
68
- vid = item['id'].get('videoId')
69
- if not vid: continue
70
- try:
71
- info = requests.get(
72
- "https://www.googleapis.com/youtube/v3/videos",
73
- params={'part':'snippet','id':vid,'key':YOUTUBE_API_KEY},
74
- timeout=10
75
- )
76
- info.raise_for_status()
77
- for v in info.json().get('items', []):
78
- for tag in v['snippet'].get('tags', []):
79
- tags_count[tag] = tags_count.get(tag, 0) + 1
80
- except Exception as e:
81
- logging.warning(f"Video API error for {vid}: {e}")
82
- return tags_count
83
-
84
- # 更新並分析標籤
85
  def update_and_analyze_tags(keyword):
 
86
  if not keyword.strip():
87
- return "未輸入關鍵字", "", ""
 
 
 
 
88
  new_tags = get_video_tags(keyword)
 
89
  if not new_tags:
90
- logging.info("No tags found for keyword")
91
- agg = read_csv_data()
92
- for t, c in new_tags.items(): agg[t] = agg.get(t, 0) + c
93
- write_csv_data(agg)
94
-
95
- # 計數器讀取、更新與上傳
96
- try:
97
- cnt = int(open(COUNTER_FILE, encoding='utf-8').read().strip() or 0) + 1
98
- except:
99
- cnt = 1
100
- with open(COUNTER_FILE, 'w', encoding='utf-8') as f:
101
- f.write(str(cnt))
102
- try:
103
- upload_file(path_or_fileobj=COUNTER_FILE, path_in_repo="counter.txt",
104
- repo_id=REPO_ID, token=HF_TOKEN)
105
- logging.info("Counter uploaded")
106
- except Exception as e:
107
- logging.error(f"Error uploading counter: {e}")
108
-
109
- sorted_tags = sorted(agg.items(), key=lambda x: x[1], reverse=True)
110
- full = "\n".join(f"{t}: {c}" for t, c in sorted_tags)
111
- copy = ",".join(t for t, _ in sorted_tags)
112
- return full or "未找到標籤。", copy or "", f"執行次數:{cnt}"
113
-
114
- # Gradio 介面
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  with gr.Blocks() as demo:
 
116
  gr.Markdown("## YouTube 關鍵字工具")
 
 
 
 
 
 
 
 
 
 
 
117
  with gr.Row():
118
- inp = gr.Textbox(lines=1, placeholder="輸入關鍵字,例如:遊戲", label="關鍵字")
119
- btn = gr.Button("確認")
120
- out1 = gr.Textbox(label="累計結果 (標籤: 次數)", interactive=False)
121
- out2 = gr.Textbox(label="標籤清單", interactive=False, show_copy_button=True)
122
- out3 = gr.Textbox(label="執行次數", interactive=False)
123
- btn.click(update_and_analyze_tags, inputs=inp, outputs=[out1, out2, out3])
124
- inp.submit(update_and_analyze_tags, inputs=inp, outputs=[out1, out2, out3])
125
-
126
- if __name__ == "__main__":
127
- demo.launch(server_name="0.0.0.0", server_port=int(os.getenv("PORT", 7860)))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ import csv
4
+
5
+ import requests
6
+
7
+ import gradio as gr
8
+
9
+ # 請替換為你的 YouTube API Key
10
+
11
+ YOUTUBE_API_KEY = "AIzaSyCvgpJMhcrDao6Li4qMUbFcifFSobbcIZw"
12
+
13
+ # CSV 檔案名稱,用來儲存累計標籤與使用次數
14
+
15
+ CSV_FILE = "tags_data.csv"
16
+
17
+ # 執行次數計數檔案名稱
18
+
19
+ COUNTER_FILE = "counter.txt"
20
+
 
 
 
 
 
 
 
 
 
 
21
  def read_csv_data():
22
+
23
  data = {}
24
+
25
+ if os.path.exists(CSV_FILE):
26
+
27
+ with open(CSV_FILE, mode="r", newline="", encoding="utf-8") as f:
28
+
29
+ reader = csv.reader(f)
30
+
31
+ for row in reader:
32
+
33
+ if len(row) == 2:
34
+
35
+ tag, count = row
36
+
37
+ data[tag] = int(count)
38
+
39
  return data
40
 
 
41
  def write_csv_data(data):
42
+
43
+ with open(CSV_FILE, mode="w", newline="", encoding="utf-8") as f:
44
+
45
+ writer = csv.writer(f)
46
+
47
+ for tag, count in data.items():
48
+
49
+ writer.writerow([tag, count])
50
+
 
51
  def get_video_tags(keyword):
52
+
53
+ search_url = (
54
+
55
+ f"https://www.googleapis.com/youtube/v3/search?part=snippet&q={keyword}"
56
+
57
+ f"&type=video&maxResults=10&key={YOUTUBE_API_KEY}"
58
+
59
+ )
60
+
61
+ search_response = requests.get(search_url).json()
62
+
63
+ video_tags = {}
64
+
65
+ # 如果沒有取得影片結果,印出回應內容作除錯
66
+
67
+ if "items" not in search_response or not search_response["items"]:
68
+
69
+ print("搜尋回應無影片結果:", search_response)
70
+
71
+ for item in search_response.get("items", []):
72
+
73
+ video_id = item["id"]["videoId"]
74
+
75
+ video_url = (
76
+
77
+ f"https://www.googleapis.com/youtube/v3/videos?part=snippet&id={video_id}"
78
+
79
+ f"&key={YOUTUBE_API_KEY}"
80
+
81
  )
82
+
83
+ video_response = requests.get(video_url).json()
84
+
85
+ print("影片回傳資料:", video_response) # 除錯:印出影片資料回應
86
+
87
+ for video_item in video_response.get("items", []):
88
+
89
+ # 嘗試取得 tags 欄位
90
+
91
+ tags = video_item["snippet"].get("tags", [])
92
+
93
+ print("取得的 tags:", tags) # 除錯:印出取得的 tags
94
+
95
+ for tag in tags:
96
+
97
+ video_tags[tag] = video_tags.get(tag, 0) + 1
98
+
99
+ return video_tags
100
+
 
 
 
 
 
101
  def update_and_analyze_tags(keyword):
102
+
103
  if not keyword.strip():
104
+
105
+ return "您未輸入關鍵字", "您未輸入關鍵字", "目前執行次數:不增加"
106
+
107
+
108
+
109
  new_tags = get_video_tags(keyword)
110
+
111
  if not new_tags:
112
+
113
+ print("查無標籤資料,請確認搜尋關鍵字是否正確或影片是否有公開標籤")
114
+
115
+ aggregated = read_csv_data()
116
+
117
+ for tag, count in new_tags.items():
118
+
119
+ aggregated[tag] = aggregated.get(tag, 0) + count
120
+
121
+ write_csv_data(aggregated)
122
+
123
+
124
+
125
+ sorted_tags = sorted(aggregated.items(), key=lambda x: x[1], reverse=True)
126
+
127
+ full_output = "\n".join(f"{tag}: {count}" for tag, count in sorted_tags)
128
+
129
+ copy_output = ",".join(tag for tag, count in sorted_tags)
130
+
131
+
132
+
133
+ if os.path.exists(COUNTER_FILE):
134
+
135
+ with open(COUNTER_FILE, "r", encoding="utf-8") as f:
136
+
137
+ try:
138
+
139
+ usage_count = int(f.read())
140
+
141
+ except Exception as e:
142
+
143
+ print("讀取 counter.txt 時發生例外:", e)
144
+
145
+ usage_count = 0
146
+
147
+ else:
148
+
149
+ usage_count = 0
150
+
151
+ usage_count += 1
152
+
153
+ with open(COUNTER_FILE, "w", encoding="utf-8") as f:
154
+
155
+ f.write(str(usage_count))
156
+
157
+ usage_output = f"執行次數:{usage_count}"
158
+
159
+
160
+
161
+ # 如果 full_output 或 copy_output 為空,則回傳「未找到相關標籤。」
162
+
163
+ return (
164
+
165
+ full_output if full_output else "未找到相關標籤。",
166
+
167
+ copy_output if copy_output else "未找到相關標籤。",
168
+
169
+ usage_output
170
+
171
+ )
172
+
173
  with gr.Blocks() as demo:
174
+
175
  gr.Markdown("## YouTube 關鍵字工具")
176
+
177
+ with gr.Row():
178
+
179
+ keyword_input = gr.Textbox(lines=1, placeholder="輸入關鍵字,例如:遊戲", label="關鍵字")
180
+
181
+ confirm_button = gr.Button("確認")
182
+
183
+ with gr.Row():
184
+
185
+ full_output_box = gr.Textbox(label="累計結果 (標籤: 次數)", interactive=False)
186
+
187
  with gr.Row():
188
+
189
+ copy_output_box = gr.Textbox(label="僅標籤 (以逗號分隔,一鍵複製)", interactive=False, show_copy_button=True)
190
+
191
+ with gr.Row():
192
+
193
+ usage_box = gr.Textbox(label="執行次數", interactive=False)
194
+
195
+
196
+
197
+ gr.Markdown(
198
+
199
+ "使用說明:\n"
200
+
201
+ "- 請先輸入關鍵字,再點選【確認】按鈕或按 Enter 鍵觸發查詢。\n"
202
+
203
+ "- 若未輸入內容,則不會更新資料與執行次數。\n"
204
+
205
+ "- 上方輸出框顯示累計結果(每行格式:標籤: 次數)。\n"
206
+
207
+ "- 中間輸出框顯示所有標籤,以半形逗號隔開,點擊複製按鈕即可複製全部標籤。\n"
208
+
209
+ "- 下方輸出框顯示該工具累計的執行次數。"
210
+
211
+ )
212
+
213
+
214
+
215
+ confirm_button.click(update_and_analyze_tags, inputs=keyword_input,
216
+
217
+ outputs=[full_output_box, copy_output_box, usage_box])
218
+
219
+ keyword_input.submit(update_and_analyze_tags, inputs=keyword_input,
220
+
221
+ outputs=[full_output_box, copy_output_box, usage_box])
222
+
223
+ demo.launch()