[G1-Sync] Manual knowledge update

This commit is contained in:
Antigravity Agent
2026-05-09 21:08:02 +09:00
parent f0befc887a
commit 93ec7e9056
363 changed files with 68333 additions and 64 deletions
@@ -1,29 +1,62 @@
# 🌙 오토 플래너
# 🌙 오토 플래너 — 24시간 자율 모드
트렌드 스나이퍼를 정해진 간격으로 반복 실행해서 패턴 데이터를 쌓아주는 무인 작업자예요. 한 번 트렌드를 보면 지금 잘 되는 영상 한 장만 보이지만, 8시간 동안 2시간마다 4번 보면 "어떤 키워드의 후크가 시간이 지나도 계속 살아남는지"가 보이기 시작합니다 — 자는 동안에 그 작업을 대신해줍니다.
트렌드 스나이퍼를 정 간격으로 무한 반복 실행. 24시간 자율 사이클의 일부로, 자는 동안에도 데이터가 누적됨.
## 어떻게 도와주나요?
- ⏰ N시간마다 `trend_sniper.py`를 자동 실행 (스나이퍼 결과는 매번 sessions/에 누적)
- 🛌 잘 때 켜두면 아침에 4~5번분의 트렌드 스냅샷이 쌓여 있어요
- 📊 같은 키워드라도 시간대별로 어떤 영상이 새로 떠오르는지 비교 가능
- ⏰ N시간마다 `trend_sniper.py`를 자동 실행
- 🌙 디폴트는 **무한 반복** — 사용자가 중단할 때까지 매 6시간 실행 (하루 4번)
- 📊 매 회차마다 `trend_sniper_report.md`에 누적
- 🛌 잘 때 켜두면 아침에 트렌드 스냅샷 4~6개 쌓임
## 어떤 상황에 켜면 좋나요?
- 새 채널 컨셉을 결정하기 전, 며칠치 트렌드를 누적해서 보고 싶을 때
- 회사 일/외출 중 백그라운드에서 데이터만 모아두고 싶을 때
- 특정 키워드의 알고리즘 반응이 시간마다 다른지 확인하고 싶을 때
## 디폴트 설정 (v2.89.71부터)
| 필드 | 디폴트 | 의미 |
|---|---|---|
| `INTERVAL_HOURS` | **6** | 6시간마다 (하루 4번 = YouTube API quota 안전권) |
| `TOTAL_RUN_HOURS` | **0** | **0 = 무한** (사용자가 Ctrl+C 또는 창 닫을 때까지) |
원래 8시간 디폴트였는데 24시간 자율 모드와 모순돼서 0(무한) 으로 변경.
## 사용 모드 2가지
**📌 24시간 자율 모드 (디폴트)**
```json
{ "INTERVAL_HOURS": 6, "TOTAL_RUN_HOURS": 0 }
```
사용자가 멈출 때까지 6시간마다 무한 실행. 24시간 자율 사이클(설정의 `connectAiLab.autoCycleEnabled`) 과 호환.
**📌 제한 모드 (테스트용)**
```json
{ "INTERVAL_HOURS": 2, "TOTAL_RUN_HOURS": 8 }
```
8시간만 돌고 종료. 첫 사용·디버깅 시 유용.
## 시작하기 전 체크
- 트렌드 스나이퍼 도구가 먼저 설정돼 있어야 해요 (YouTube API 키, 키워드 목록 등)
- 첫 실행 전에 트렌드 스나이퍼를 한 번 수동으로 돌려서 정상 작동 확인을 권장합니다
## 설정값 (auto_planner.json)
- `INTERVAL_HOURS` — 몇 시간마다 실행할지 (기본 2)
- `TOTAL_RUN_HOURS` — 총 가동 시간 (기본 8 → 8시간 동안 4회 실행)
- 트렌드 스나이퍼 도구가 먼저 설정돼 있어야 해요 (YouTube API 키, TARGET_KEYWORDS)
- 첫 실행 시 자동으로 trend_sniper.py 한 번 검증 → 실패하면 본 루프 안 돌고 종료
- 검증 통과해야 본 루프 시작
## 실행 방법
패널의 [▶ 실행]을 누르면 시작됩니다. 또는 터미널에서:
**채팅 패널의 [▶ 실행]** — 24시간 자율 모드면 채팅창이 무한 점유됨. 제한 모드 권장.
**백그라운드 실행 (24시간 자율 권장)**:
```bash
python auto_planner.py
cd ~/Downloads/지식메모리/_company/_agents/youtube/tools/
nohup python3 auto_planner.py > planner.log 2>&1 &
```
⚠️ 이 스크립트는 끝날 때까지 터미널을 점유해요. 백그라운드로 돌리려면 별도 창에서 실행하세요. 중단하려면 Ctrl+C.
이러면 VS Code 닫아도 백그라운드에서 계속 돔. 중단하려면:
```bash
ps aux | grep auto_planner
kill <PID>
```
## YouTube API quota 주의
- 무료 티어: 일일 10,000 unit
- trend_sniper 1회 = 약 600 unit (search × 2 키워드)
- 6시간 간격 = 하루 4번 = 2,400 unit (안전)
- 1시간 간격은 사용 자제 (24번 = 14,400 unit → 한도 초과)
## 출력
- `trend_sniper_report.md` — 매 회차 분석 보고서 누적
- 콘솔: 회차 번호, 가동 시간, 다음 실행 시각
@@ -17,26 +17,52 @@ def load_config():
def main():
cfg = load_config()
interval_h = float(cfg.get("INTERVAL_HOURS", 2))
total_h = float(cfg.get("TOTAL_RUN_HOURS", 8))
print(f"\n🚀 [오토 플래너] {total_h}시간 동안 {interval_h}시간마다 트렌드 분석 실행")
interval_h = float(cfg.get("INTERVAL_HOURS", 6)) # v2.89.71: 디폴트 6시간 (하루 4번)
total_h = float(cfg.get("TOTAL_RUN_HOURS", 0)) # v2.89.71: 0 = 무한 (24시간 자율 모드)
# v2.89.71 — 24시간 자율 모드 본격 지원. TOTAL_RUN_HOURS=0이면 사용자가 멈출 때까지 무한.
if total_h <= 0:
print(f"\n🌙 [오토 플래너] 24시간 자율 모드 — {interval_h}시간마다 무한 반복")
print(f"⚠️ 사용자가 중단(Ctrl+C)할 때까지 계속 실행됩니다.")
print(f" 백그라운드로 돌리려면 터미널에서:")
print(f" nohup python3 {os.path.abspath(__file__)} > planner.log 2>&1 &")
else:
print(f"\n🚀 [오토 플래너] {total_h}시간 동안 {interval_h}시간마다 트렌드 분석 (제한 모드)")
print(f"⚠️ 종료까지 {total_h}시간 채팅창 점유. Ctrl+C로 중단 가능.")
print()
if not os.path.exists(SNIPER_PATH):
print(f"❌ trend_sniper.py를 찾을 수 없어요: {SNIPER_PATH}")
sys.exit(1)
# 첫 실행 전 trend_sniper.py가 정상 동작하는지 빠르게 검증
print("🔍 trend_sniper.py 첫 회차 검증 중 (~30초)...")
test_proc = subprocess.run([sys.executable, SNIPER_PATH], capture_output=True, text=True, timeout=300)
if test_proc.returncode != 0:
print(f"❌ trend_sniper.py 검증 실패 (exit {test_proc.returncode})")
print(" 먼저 trend_sniper.py 단독으로 ▶ 실행해서 설정·키워드·LLM 연결 확인 후 재시도.")
if test_proc.stderr.strip():
print(" 에러 일부:")
for line in test_proc.stderr.splitlines()[-5:]:
print(f" {line}")
sys.exit(1)
print("✅ 검증 완료. 본 루프 시작.\n")
start = time.time()
loop = 0
while True:
if time.time() - start > total_h * 3600:
# v2.89.71 — total_h = 0이면 무한 (24시간 자율 모드)
if total_h > 0 and (time.time() - start > total_h * 3600):
print("\n☀️ 목표 가동 시간을 채웠어요. 종료합니다.")
break
loop += 1
ts = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print(f"\n[{ts}] 🤖 {loop}회차 트렌드 스나이핑")
elapsed_h = (time.time() - start) / 3600
print(f"\n[{ts}] 🤖 {loop}회차 트렌드 스나이핑 (가동 {elapsed_h:.1f}시간)")
try:
subprocess.run([sys.executable, SNIPER_PATH], check=False)
except Exception as e:
print(f"❌ 실행 실패: {e}")
print(f"⏳ 다음 실행: {interval_h}시간 후")
next_at = datetime.datetime.now() + datetime.timedelta(hours=interval_h)
print(f"⏳ 다음 실행: {next_at.strftime('%Y-%m-%d %H:%M')} ({interval_h}시간 후)")
time.sleep(interval_h * 3600)
if __name__ == "__main__":
@@ -1,4 +1,5 @@
#!/usr/bin/env python3
# version: telegram_v3
"""Competitor Brief — for every channel in COMPETITOR_CHANNELS, pulls their
recent top-performing videos and asks the local LLM for a *prescriptive*
brief: what should YOU do next, given what's working for them.
@@ -108,29 +108,62 @@ def main():
3. 🎬 파괴적 영상 기획안 — 썸네일 카피, 제목 3개, 후킹 오프닝(첫 5초)
"""
print("🧠 [LLM 분석 중...]")
# v2.89.70 — LM Studio (OpenAI 호환 API) + Ollama 둘 다 지원. URL/포트로 자동 감지.
is_lm_studio = ('1234' in ollama_url) or ('/v1' in ollama_url)
print(f"🧠 [LLM 분석 중... 엔진: {'LM Studio' if is_lm_studio else 'Ollama'}]")
# 모델 자동 선택 — 엔진별로 다른 endpoint
if not model:
# Try first available model
try:
r = requests.get(f"{ollama_url}/api/tags", timeout=5)
r.raise_for_status()
models = [m["name"] for m in r.json().get("models", [])]
if is_lm_studio:
# LM Studio: GET /v1/models (OpenAI 호환)
base = ollama_url.rstrip('/')
if not base.endswith('/v1'):
base = base + '/v1'
r = requests.get(f"{base}/models", timeout=5)
r.raise_for_status()
models = [m["id"] for m in r.json().get("data", [])]
else:
# Ollama: GET /api/tags
r = requests.get(f"{ollama_url}/api/tags", timeout=5)
r.raise_for_status()
models = [m["name"] for m in r.json().get("models", [])]
if not models:
print("❌ 로컬 LLM에 설치된 모델이 없어요. Ollama/LM Studio에서 모델을 풀(pull)하세요.")
print(f"❌ 로컬 LLM에 설치된 모델이 없어요. {'LM Studio' if is_lm_studio else 'Ollama'} 에서 모델 로드/풀하세요.")
sys.exit(1)
model = models[0]
print(f" 자동 선택 모델: {model}")
except Exception as e:
print(f"❌ 로컬 LLM 연결 실패 ({ollama_url}): {e}")
print(f" 엔진 실행 확인: {'LM Studio (포트 1234)' if is_lm_studio else 'Ollama (포트 11434)'}")
sys.exit(1)
# 추론 호출 — 엔진별 다른 endpoint·payload 형식
try:
r = requests.post(
f"{ollama_url}/api/generate",
json={"model": model, "prompt": prompt, "stream": False},
timeout=180,
)
r.raise_for_status()
report = r.json().get("response", "").strip()
if is_lm_studio:
base = ollama_url.rstrip('/')
if not base.endswith('/v1'):
base = base + '/v1'
r = requests.post(
f"{base}/chat/completions",
json={
"model": model,
"messages": [{"role": "user", "content": prompt}],
"stream": False,
"max_tokens": 2048,
},
timeout=180,
)
r.raise_for_status()
report = r.json().get("choices", [{}])[0].get("message", {}).get("content", "").strip()
else:
r = requests.post(
f"{ollama_url}/api/generate",
json={"model": model, "prompt": prompt, "stream": False},
timeout=180,
)
r.raise_for_status()
report = r.json().get("response", "").strip()
except Exception as e:
print(f"❌ LLM 호출 실패: {e}")
sys.exit(1)