ToolSignal Pro 무료 코드 모음 — sess136 자동화 스크립트 8편 + 학습 노트

ToolSignal Pro 운영 중에 작성한 자동화 스크립트 일부를 정리해 공유합니다. API 키·접근 토큰·개인 경로·계정 식별자 등 민감 정보는 모두 제거했습니다. 자유롭게 참고하시되, 그대로 옮겨 쓰실 때는 환경 맞춰 경로·키를 채워 주세요.

라이선스: 자유 사용. 출처 표시 권장 (toolsignalpro.com).

1. sess136_chrome_to_hybrid.py

사장님 Gemini Web 구독으로 chart chrome 이미지 생성, 클립보드로 받아서 PIL composer 통과 후 Drive 등록까지 자동.


"""sess136 - Take pre-generated chrome PNG (from Gemini Web UI), do Drive
upload + slot_coords update + manifest upsert + compose hybrid sample +
Desktop copy + sample Drive upload. Same end-state as
sess134_batch_8kinds_final.py minus the Gemini API call.

Usage:
 python _scratch/sess136_chrome_to_hybrid.py radar
"""
import json, os, shutil, sys, time
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))

from webapp.seo.drive_assets import upload_file
from webapp.seo.asset_manifest import upsert_entry
from webapp.seo.image_composer import compose

SAMPLES = {
 "radar": {
 "title": "AI 도구 4축 평가 - 종합",
 "subtitle": "속도 / 정확도 / 비용 / 통합성 4축으로 평가.",
 "axis_1": "속도",
 "axis_2": "정확도",
 "axis_3": "비용 효율",
 "axis_4": "통합성",
 "series_label": "Claude Code 종합 점수 (vs 평균)",
 "sources": "Anthropic eval suite · Cursor benchmarks · 자체 측정",

📥 전체 파일 다운로드 (.txt)

2. webapp/seo/asset_manifest.py

비주얼 자산 단일 source-of-truth. upsert + reuse-aware pick(). 동일 글에 같은 자산 반복 사용 방지.


"""sess134 — Visual asset manifest (single source of truth).

Boss directive 2026-05-22 (累計):
 "글이 벌써 50개가 넘는데... 이미지 자료들 최적화 잘해서 모아두고, 썸네일,
 차트, 등등으로 활용할 수 있게... 잘 준비해두고 구글 드라이브에 업로드."

Schema per asset entry — see `docs/sess134_visual_pipeline_prompts.md`
PROMPT D. Source of truth lives at `logs/visual_assets_manifest.json`
(write-through JSON cache). Drive holds the actual binary; this file holds
the index so the webapp doesn't hit Drive on every page view.

Public surface:
 - `add_entry(entry)` register a new asset
 - `list_entries(**filters)` filter by category/kind/theme/version/tag
 - `get_entry(asset_id)` fetch one
 - `mark_used(asset_id, post_id)` use_count++, last_used_post_id update
 - `pick(tags, *, kind, theme, limit)` reuse-aware ranking
 - `soft_delete(asset_id)` sets deleted_at, keeps record
 - `sync_from_drive()` recover from Drive if manifest is lost
"""
from __future__ import annotations

import json
import logging
import threading
import time
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Optional

📥 전체 파일 다운로드 (.txt)

3. webapp/seo/image_composer.py (excerpt)

PIL + Pretendard 6-weight composer. chrome PNG 위에 slot_coords JSON 따라 텍스트·레전드 오버레이.


"""sess134 - Hybrid layer image composer (PIL + Pretendard + slot_coords).

Per PROMPT E in docs/sess134_visual_pipeline_prompts.md:
 Layer 1 = Gemini chrome PNG (text-free background, motif art).
 Layer 2 = Python PIL data composition (deterministic slot coordinates).
 Output = WebP merged image.

The chrome lives in Drive (download on demand + small local cache).
The slot_coords JSON lives in `slot_coords/{kind}.json` in this repo and is
the single source of truth for where each editable field renders.

Public surface:
 - `compose(template_id, data, *, output_path=None) -> dict`
 - `load_slot_coords(kind) -> dict`
 - `validate_data(data, slot_coords) -> list[str]` list of missing slots
 - `fetch_chrome(drive_file_id, cache_dir) -> Path`
"""
from __future__ import annotations

import json
import logging
import shutil
import time
import urllib.request
from pathlib import Path
from typing import Any, Optional

logger = logging.getLogger(__name__)

📥 전체 파일 다운로드 (.txt)

4. webapp/seo/inline_charts_neural.py (excerpt)

16종 inline neural-light SVG 차트 템플릿. faint dot-grid + violet glow nodes. 외부 이미지 의존 0.


"""sess134 — Neural-light inline chart components.

Boss directive 2026-05-22:
 "사이트 hero의 AI 신경망 파티클 느낌을 얹고, 깔끔하면서 기존 이미지 안 깨고,
 그러면서도 임팩트는 있어야."

Design rules (read this before adding a new chart kind):
 - NO card border, NO box-shadow, NO chrome background (no-boundaries doctrine).
 - Light canvas (#ffffff / #fdfcff). White on white site doctrine.
 - Subtle dot-grid backdrop layer behind every chart — VERY faint
 (opacity 0.06) so it whispers, never shouts.
 - Every data point is a node: small circle + soft violet glow.
 - Connections are synapse-like thin lines, sometimes gradient.
 - Typography: Pretendard 800 ink (#1a1a2e) titles, 13px subtitle.
 - KPI accent uses sess125 particle violet (#7c5bff).
 - Brand footer: one right-aligned line in #94a3b8, very light.

Palette pulled directly from sess125 SESS114-hero particle network so the
charts and the homepage hero feel like one continuous system:
 - node ink: #2d2850 (deep navy purple, sess125 NODE_DOT base)
 - glow: #7c5bff (violet, sess125 NODE_GLOW base + sess113 accent)
 - link line: #46366e (sess125 LINK_BASE base, used at 0.18-0.32 alpha)
 - cyan: #38bdf8 (secondary accent — kept from inline_charts_dark)
 - mint: #34d399 (good / positive)
 - rose: #f87171 (bad / negative)

Caller (compatible with inline_charts_dark dispatcher signature):
 from webapp.seo.inline_charts_neural import render_inline_chart
 html = render_inline_chart("treemap", data={...})

📥 전체 파일 다운로드 (.txt)

5. webapp/seo/chart_recommender.py

순수 Python intent classifier. 제목·라벨·키워드 → comparison/review/news intent 매핑 + 적합 차트 종류 추천 (LLM 호출 없음).


"""sess133 — Article-aware chart recommendation engine.

Inputs: article title, topic, keywords, label, content type, optional outline.
Output: list of 1-3 chart recommendations, each with reason + best section +
 primary flag. The frontend / writer pipeline can then surface these as
 "Best Fit / Optional" badges and let the user accept or override.

Intent vocabulary (matches editorial content types we publish):
 - comparison : "A vs B vs C", "Best of X", "Top N", side-by-side picks
 - review : single-product deep dive, verdict
 - howto : step-by-step guide
 - news : weekly news roundup, market move, breaking
 - market : market share, growth, size, trend
 - pricing : pricing tier / cost / API token cost
 - technical : architecture, stack, flow diagram
 - tutorial : code-along, setup walkthrough
 - listicle : bullet list, "5 ways to ..."

Chart catalog (16 — see webapp/seo/inline_charts_dark.py).

Pure-Python keyword classifier; no LLM call. Cheap and predictable. The writer
UI can override the suggestion any time.
"""
from __future__ import annotations

import re
from typing import Any

📥 전체 파일 다운로드 (.txt)

6. webapp/seo/realtime_facts.py

USD-KRW 실시간 환율 3-tier fallback. open.er-api → Yahoo → 캐시. 글에 환율 인용 시 LLM 추정값 대신 실제 값.


"""sess134 — Real-time fact resolver (환율 / 현재 시점 데이터 수집 루트).

Boss directive 2026-05-22:
 "환율이나 현재 시점에 정확해야 하는 정보들 수집 루트 명확하게."

The blog publishes articles whose body text quotes USD-KRW rate, weekly
financial figures, GDP/inflation snapshots, etc. The LLM (Gemini) does NOT
know today's exact rate or this week's index value — its answers are
training-cutoff plausible guesses. To honour `feedback_reality_check_in_
comparison.md` ("가격 비교 글에 반드시 실제 한도 + 장기 누적 비용 동반") and
`feedback_research_before_writing.md` ("글쓰기전에 다양하게 검색해보고
크롤링했으면 현실반영. 빈약한 글의 이유는 검색 부족"), we resolve those
facts at write-time / publish-time from authoritative APIs, with a small
cache so we are not hammering free tiers.

Sources (priority order):
 - **USD-KRW exchange rate**:
 1. exchangerate-api.com /v6/{key}/latest/USD (free tier, 1500/mo) —
 if key configured.
 2. open.er-api.com /v6/latest/USD (free, no-key, daily).
 3. Yahoo Finance unofficial JSON (last resort).
 4. Cached previous value with `stale=true` (graceful fallback).
 - **한국은행 ECOS** (BOK statistics — base rate, CPI, etc.):
 ECOS OpenAPI /api/StatisticSearch/{key}/json/kr/1/100/722Y001 —
 if `ecos_api_key` configured. Returns time-series.
 - **Generic "what is today's X" lookups**:
 Pluggable. We expose a `resolve_fact(slug, *, fallback=None)` interface
 so callers can ask `resolve_fact("usd_krw")`, `resolve_fact("kr_base_
 rate")`, etc. without knowing the upstream source.

📥 전체 파일 다운로드 (.txt)

7. 매크로켬.bat (바탕화면)

Windows Task Scheduler 'ToolSignal Autonomous Loop' 활성. ASCII + CRLF + 한국어 cmd 안전.


@echo off
REM ============================================================
REM Macro START - enable Auto-Paste Loop Task Scheduler
REM
REM ASCII-pure file. Display strings English to dodge cp949/utf8.
REM ============================================================
setlocal
set TASKNAME=ToolSignal Autonomous Loop

echo.
echo ============================================================
echo MACRO START ( auto-paste 1 ON )
echo ============================================================
echo Target task: %TASKNAME%
echo ------------------------------------------------------------
schtasks /Change /TN "%TASKNAME%" /ENABLE
echo ------------------------------------------------------------
echo Status:
schtasks /Query /TN "%TASKNAME%" /FO LIST | findstr "Status"
echo ============================================================
echo.
endlocal
ping 127.0.0.1 -n 4 1>NUL
exit /b 0

📥 전체 파일 다운로드 (.txt)

8. 매크로멈춤.bat (바탕화면)

동일 task 비활성. 자율주행 잠시 멈출 때 사용.


@echo off
REM ============================================================
REM Macro STOP - disable Auto-Paste Loop Task Scheduler
REM
REM ASCII-pure file. Display strings English to dodge cp949/utf8.
REM ============================================================
setlocal
set TASKNAME=ToolSignal Autonomous Loop

echo.
echo ============================================================
echo MACRO STOP ( auto-paste 1 OFF )
echo ============================================================
echo Target task: %TASKNAME%
echo ------------------------------------------------------------
schtasks /Change /TN "%TASKNAME%" /DISABLE
echo ------------------------------------------------------------
echo Status:
schtasks /Query /TN "%TASKNAME%" /FO LIST | findstr "Status"
echo ============================================================
echo.
endlocal
ping 127.0.0.1 -n 4 1>NUL
exit /b 0

📥 전체 파일 다운로드 (.txt)


── 학습 노트 (실패 실험) ──

부록 sess136_blob_receiver.py — 실패 실험 / 학습 노트

본 코드는 작동하지 않은 우회 시도입니다. HTTPS 페이지에서 localhost로 POST 보내려고 했지만 Content-Security-Policy connect-src 정책에 차단됐습니다. 결국 클립보드 + PIL ImageGrab 경로로 우회. 같은 함정 피하실 분들 참고용.


"""sess136 - tiny HTTP server to receive blob bytes from Gemini Chrome MCP."""
import os, sys, time
from http.server import BaseHTTPRequestHandler, HTTPServer
from pathlib import Path

OUTDIR = Path(__file__).resolve().parents[1] / "_scratch"
OUTDIR.mkdir(parents=True, exist_ok=True)

class H(BaseHTTPRequestHandler):
 def _cors(self):
 self.send_header("Access-Control-Allow-Origin", "*")
 self.send_header("Access-Control-Allow-Methods", "POST, OPTIONS")
 self.send_header("Access-Control-Allow-Headers", "*")

 def do_OPTIONS(self):
 self.send_response(204)
 self._cors()
 self.end_headers()

 def do_POST(self):
 try:
 name = self.headers.get("X-Filename") or self.path.lstrip("/") or "blob.bin"
 name = name.replace("..", "").replace("/", "_").replace("\\", "_")
 length = int(self.headers.get("Content-Length", "0"))
 data = self.rfile.read(length) if length > 0 else b""
 outpath = OUTDIR / name
 outpath.write_bytes(data)
 print(f"[recv] {name} {len(data):,} bytes -> {outpath}", flush=True)
 self.send_response(200)

📥 전체 파일 다운로드 (.txt)


본 코드는 sess136 시점 정리본입니다. 이후 보강된 버전이 webapp 안에 살아 있을 수 있습니다. 의견·개선 제안은 사이트 푸터 연락처로 부탁드립니다.

ToolSignal Pro Editorial

ToolSignal Pro editor. We compare AI tools, CRM, automation, and SaaS for small business buyers — no fluff, just the decision drivers that matter.

이전 글 다음 글