新增 Pinterest 参考模式:独立于 Google Trends 的完整链路(12国种子词池 / LLM搜索词json_schema+防重复+已用词限100 / 并发爬图 / 多模态分析→原创简报 / 生图带爬取图参考图生图 / UI流程选择)
This commit is contained in:
@@ -190,8 +190,12 @@ def _apply_provider_mode(config: dict, provider: str) -> None:
|
||||
cp["backend"] = "openai" if on else "mock"
|
||||
pp = config.setdefault("product", {})
|
||||
pp["backend"] = "openai" if on else "mock"
|
||||
# Pinterest 参考模式:LLM(搜索词/图片分析)提供商跟随模式开关
|
||||
pin = config.setdefault("pinterest", {})
|
||||
pin["provider"] = "openai" if on else "mock"
|
||||
print(f"[UI] 模式开关: {'OpenAI(真 LLM + 真生图)' if on else 'Mock(演示)'} | "
|
||||
f"llm_screen={ls['provider']} compose={cp['backend']} product={pp['backend']}")
|
||||
f"llm_screen={ls['provider']} compose={cp['backend']} product={pp['backend']} "
|
||||
f"pinterest={pin['provider']}")
|
||||
|
||||
|
||||
def fetch_keywords(country, provider, max_seeds, log_q, oai=None):
|
||||
@@ -374,6 +378,75 @@ def run_pipeline(countries, provider, max_seeds, log_q,
|
||||
log_q.put(("log", f"[UI] 缓存打包失败: {e}\n"))
|
||||
|
||||
|
||||
def run_pinterest_pipeline(countries, provider, log_q, spu_tasks=None, spu_count=0,
|
||||
oai=None, markup_percent=0.0, code_prefix="DG", template_path=""):
|
||||
"""Pinterest 参考模式后台线程:独立于 Google Trends 采集链路。
|
||||
|
||||
各国独立种子词池 → LLM 搜索词(json_schema + 动态注入防重复)→ 爬图
|
||||
→ LLM 分析图片 → 设计简报 → 产品生成(设计稿/主图/种草图/模板导出)。
|
||||
"""
|
||||
config = load_config()
|
||||
config["seed_provider"] = provider
|
||||
apply_openai_cfg(config, oai)
|
||||
_apply_provider_mode(config, provider) # 联动 pinterest.provider / compose / product backend
|
||||
p = config.setdefault("product", {})
|
||||
if template_path:
|
||||
p["template_path"] = template_path
|
||||
if spu_tasks:
|
||||
p["spu_tasks"] = spu_tasks
|
||||
p.pop("spu_code", None)
|
||||
if spu_count:
|
||||
p["spu_count"] = spu_count
|
||||
if markup_percent:
|
||||
p["markup_percent"] = markup_percent
|
||||
if code_prefix:
|
||||
p["code_prefix"] = code_prefix
|
||||
# 任务扩展(与 run_pipeline 一致):每个集合按自己数量复制 N 份
|
||||
if spu_tasks:
|
||||
tasks_list = []
|
||||
for t in spu_tasks:
|
||||
n = int(t.get("count") or 0) or spu_count or 1
|
||||
for _ in range(n):
|
||||
tt = dict(t)
|
||||
tt.pop("count", None)
|
||||
tasks_list.append(tt)
|
||||
p["spu_tasks"] = tasks_list
|
||||
if spu_count:
|
||||
p["spu_count"] = spu_count
|
||||
# 简报数上限联动:设计数 ≥ 任务数(否则任务会复用简报)
|
||||
pcfg = config.setdefault("pinterest", {})
|
||||
pcfg["max_designs"] = max(int(pcfg.get("max_designs", 10) or 10), int(spu_count or 1))
|
||||
|
||||
old_stdout = sys.stdout
|
||||
sys.stdout = StdoutRedirector(log_q)
|
||||
results = {}
|
||||
task_ts = time.strftime("%Y%m%d%H%M%S")
|
||||
try:
|
||||
from graph.agent import run_pinterest_ref
|
||||
for c in countries:
|
||||
log_q.put(("log", f"\n===== Pinterest 参考模式 {c}(SPU 数量 {spu_count})=====\n"))
|
||||
state = run_pinterest_ref(c, config, config_root(), runtime_root(), task_timestamp=task_ts)
|
||||
items = state.get("product") or []
|
||||
errs = state.get("errors") or []
|
||||
log_q.put(("log", f"[{c}] Pinterest 参考完成:{len(items)} 个产品,兜底错误 {len(errs)}\n"))
|
||||
results[c] = items
|
||||
ts_dir = runtime_root() / "output" / countries[0] / task_ts
|
||||
log_q.put(("log", f"\n✅ Pinterest 参考任务完成,产物文件夹:{ts_dir}\n"
|
||||
f" (缓存/去重记录在 {runtime_root() / 'output' / countries[0]} 根目录,不进任务文件夹)\n"))
|
||||
log_q.put(("done", results))
|
||||
except Exception as e: # noqa: BLE001
|
||||
import traceback
|
||||
log_q.put(("log", f"运行失败: {e}\n{traceback.format_exc()}\n"))
|
||||
log_q.put(("error", None))
|
||||
finally:
|
||||
sys.stdout = old_stdout
|
||||
try:
|
||||
for c in countries:
|
||||
_pack_cache(c, log_q) # 运行完成 → 自动打包缓存/去重数据
|
||||
except Exception as e: # noqa: BLE001
|
||||
log_q.put(("log", f"[UI] 缓存打包失败: {e}\n"))
|
||||
|
||||
|
||||
def _pack_cache(country: str, log_q=None) -> str:
|
||||
"""运行/采集完成后,把该国缓存+去重数据打包成 zip(output/cache_packs/<国>_<时间戳>.zip),
|
||||
内含 design_briefs / used_designs / collected_keywords / products.json + .cache 关键缓存,
|
||||
@@ -459,6 +532,12 @@ class App(tk.Tk):
|
||||
variable=self.provider_var).pack(side="left", padx=2)
|
||||
ttk.Radiobutton(top, text="Mock 演示", value="mock",
|
||||
variable=self.provider_var).pack(side="left", padx=2)
|
||||
ttk.Label(top, text=" 流程:").pack(side="left", padx=(14, 0))
|
||||
self.flow_var = tk.StringVar(value="trends")
|
||||
ttk.Radiobutton(top, text="热点采集", value="trends",
|
||||
variable=self.flow_var).pack(side="left", padx=2)
|
||||
ttk.Radiobutton(top, text="Pinterest 参考", value="pinterest",
|
||||
variable=self.flow_var).pack(side="left", padx=2)
|
||||
ttk.Label(top, text=" 种子数量:").pack(side="left", padx=(14, 0))
|
||||
self.seed_var = tk.StringVar(value="24")
|
||||
ttk.Entry(top, textvariable=self.seed_var, width=4).pack(side="left")
|
||||
@@ -934,14 +1013,25 @@ class App(tk.Tk):
|
||||
self._busy = True
|
||||
self.run_btn.config(state="disabled", text="运行中…")
|
||||
self.fetch_btn.config(state="disabled")
|
||||
threading.Thread(
|
||||
target=run_pipeline,
|
||||
args=(countries, self.provider_var.get(), ms, self._q,
|
||||
"", "", spu_count, tasks, self._oai_cfg(), markup,
|
||||
self.code_prefix_var.get().strip() or "DG",
|
||||
self.template_path_var.get().strip()),
|
||||
daemon=True,
|
||||
).start()
|
||||
if self.flow_var.get() == "pinterest":
|
||||
# Pinterest 参考模式:独立于 Google Trends 采集链路
|
||||
threading.Thread(
|
||||
target=run_pinterest_pipeline,
|
||||
args=(countries, self.provider_var.get(), self._q,
|
||||
tasks, spu_count, self._oai_cfg(), markup,
|
||||
self.code_prefix_var.get().strip() or "DG",
|
||||
self.template_path_var.get().strip()),
|
||||
daemon=True,
|
||||
).start()
|
||||
else:
|
||||
threading.Thread(
|
||||
target=run_pipeline,
|
||||
args=(countries, self.provider_var.get(), ms, self._q,
|
||||
"", "", spu_count, tasks, self._oai_cfg(), markup,
|
||||
self.code_prefix_var.get().strip() or "DG",
|
||||
self.template_path_var.get().strip()),
|
||||
daemon=True,
|
||||
).start()
|
||||
|
||||
def _poll(self):
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user