Spaces:
Runtime error
Runtime error
File size: 6,016 Bytes
6790676 | 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 162 163 164 165 166 167 168 169 170 171 172 173 174 | # app.py
# pip install gradio==4.43.0 pandas requests unidecode
import requests
import re
import random
import gradio as gr
import pandas as pd
from difflib import SequenceMatcher
from unidecode import unidecode
import os
# -----------------------------
# 工具函数
# -----------------------------
def normalize(s: str) -> str:
s = s.strip().lower()
s = unidecode(s)
s = re.sub(r"\s+", " ", s)
return s
def dedup_words(words):
out, seen = [], set()
for w in words:
k = normalize(w)
if k not in seen:
seen.add(k)
out.append(w)
return out
def similarity(a: str, b: str) -> float:
return SequenceMatcher(None, normalize(a), normalize(b)).ratio()
# -----------------------------
# TikTok Cookie 支持
# -----------------------------
TIKTOK_COOKIE = ""
def set_cookie(cookie_text):
global TIKTOK_COOKIE
TIKTOK_COOKIE = cookie_text
return "✅ Cookie 已更新"
# -----------------------------
# 1. TikTok 实时热搜抓取
# -----------------------------
def get_tiktok_trending_keywords(region="VN", query=None, topk=12):
if query:
url = f"https://www.tiktok.com/api/discover/search/?keyword={query}®ion={region}"
else:
url = f"https://www.tiktok.com/api/discover/trending/?region={region}"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
"Referer": "https://www.tiktok.com/",
}
if TIKTOK_COOKIE:
headers["Cookie"] = TIKTOK_COOKIE
try:
r = requests.get(url, headers=headers, timeout=8)
r.raise_for_status()
data = r.json()
except Exception as e:
print("请求失败:", e)
return []
keywords = []
for item in data.get("data", []):
title = item.get("title") or item.get("challenge_info", {}).get("title")
views = item.get("viewCount") or 0
if title:
keywords.append((title.strip(), views))
keywords.sort(key=lambda x: x[1], reverse=True)
return [kw for kw, _ in keywords[:topk]]
# -----------------------------
# 2. 热词建议
# -----------------------------
def suggest_hotwords(product_name: str, category: str, lang: str, topk: int = 12):
region_map = {"zh": "CN", "fr": "FR", "en": "US", "vi": "VN"}
region = region_map.get(lang, "US")
return get_tiktok_trending_keywords(region=region, query=product_name, topk=topk)
# -----------------------------
# 3. 标题生成
# -----------------------------
def rank_keywords(core_words, hotwords):
items = []
for w in core_words:
items.append((w, 1.0))
for i, w in enumerate(hotwords):
items.append((w, 0.9 - i * 0.02))
uniq = {}
for w, sc in items:
k = normalize(w)
if k not in uniq or sc > uniq[k]:
uniq[k] = sc
ranked = sorted([(w, sc) for w, sc in uniq.items()], key=lambda x: x[1], reverse=True)
return [w for w, _ in ranked]
def build_title(core, ranked, max_len):
segments = dedup_words(core + ranked)
title = " ".join(segments)
if len(title) > max_len:
title = title[:max_len]
return title
def generate_titles(product_name, category, lang, n_titles, hotwords_text, max_len):
core_words = dedup_words(re.split(r"[,\|/;,、 ]+", product_name))
hotwords = dedup_words(re.split(r"[,\|/;,、\n]+", hotwords_text))
ranked = rank_keywords(core_words, hotwords)
out = []
for i in range(n_titles):
random.shuffle(ranked)
title = build_title(core_words, ranked, max_len)
out.append(title)
df = pd.DataFrame({"序号": list(range(1, len(out) + 1)), "标题": out})
csv_bytes = df.to_csv(index=False).encode("utf-8-sig")
return "\n".join(out), csv_bytes
# -----------------------------
# 4. Gradio UI
# -----------------------------
LANGS = [("中文", "zh"), ("Français", "fr"), ("English", "en"), ("Tiếng Việt", "vi")]
def ui_hotwords(product_name, category, lang, topk):
if not product_name:
return ""
kws = suggest_hotwords(product_name, category, lang, int(topk))
return ", ".join(kws)
with gr.Blocks(theme=gr.themes.Soft()) as demo:
gr.Markdown("## TikTok 商品标题优化工具(实时热搜 + Cookie 支持)")
with gr.Row():
product_name = gr.Textbox(label="商品名称与关键词", placeholder="输入商品名,例如:阻力带", lines=2)
category = gr.Textbox(label="类目", value="健身用品/健身器材")
with gr.Row():
lang = gr.Dropdown(LANGS, value="fr", label="语言")
n_titles = gr.Slider(1, 10, value=3, step=1, label="生成数量")
max_len = gr.Slider(30, 120, value=80, step=1, label="最大标题长度")
topk = gr.Slider(6, 30, value=12, step=1, label="热门关键词数量")
hotwords_box = gr.Textbox(label="热门关键词(实时获取)", lines=2, placeholder="将自动填充")
btn_refresh = gr.Button("⟳ 获取实时热门关键词")
btn_generate = gr.Button("⚡ 生成标题")
cookie_input = gr.Textbox(label="TikTok Cookie(可选)", placeholder="可手动粘贴 Cookie", lines=2)
btn_set_cookie = gr.Button("✅ 更新 Cookie")
titles_out = gr.Textbox(label="生成结果", lines=10)
csv_file = gr.File(label="下载 CSV", file_count="single")
product_name.change(ui_hotwords, [product_name, category, lang, topk], [hotwords_box])
lang.change(ui_hotwords, [product_name, category, lang, topk], [hotwords_box])
topk.change(ui_hotwords, [product_name, category, lang, topk], [hotwords_box])
btn_refresh.click(ui_hotwords, [product_name, category, lang, topk], [hotwords_box])
btn_generate.click(
generate_titles,
[product_name, category, lang, n_titles, hotwords_box, max_len],
[titles_out, csv_file]
)
btn_set_cookie.click(set_cookie, [cookie_input], [cookie_input])
if __name__ == "__main__":
demo.launch()
|