fix(anime): 파이프라인 5건 수정 — 에피소드 정규식(v2/S01E), 릴리스 그룹 필터, 자막 보호, 배치 다운로드, 타임아웃
This commit is contained in:
61
tests/cli_test_output.txt
Normal file
61
tests/cli_test_output.txt
Normal file
@@ -0,0 +1,61 @@
|
||||
=== Architecture Imports ===
|
||||
OK core.gemini_caller
|
||||
OK core.orchestrator
|
||||
OK core.task_pipeline
|
||||
OK tools.anime_pipeline
|
||||
OK tools.anissia_client
|
||||
OK tools.nyaa_client
|
||||
OK tools.qbit_client
|
||||
OK tools.nas_scanner
|
||||
OK tools.title_matcher
|
||||
OK tools.subtitle_downloader
|
||||
OK handlers.renderer
|
||||
|
||||
=== Deleted Files ===
|
||||
OK deleted tools/base.py
|
||||
OK deleted tools/registry.py
|
||||
OK deleted tools/anime_tool.py
|
||||
OK deleted prompts/planner.md
|
||||
OK deleted prompts/coder.md
|
||||
OK deleted prompts/summarizer.md
|
||||
|
||||
=== Required Files ===
|
||||
OK prompts/agent.md
|
||||
OK prompts/unified.md
|
||||
OK prompts/reviewer.md
|
||||
OK .gemini/skills/anime/SKILL.md
|
||||
|
||||
=== Title Matcher ===
|
||||
pykakasi('sousouno furiiren'): sousouno furiiren
|
||||
sim('sousouno furiiren', 'sousou no furiiren'): 0.971
|
||||
sim('Sousou no Frieren', 'sousou no furiiren'): 0.914
|
||||
|
||||
=== NAS Scanner ===
|
||||
accessible: True
|
||||
total folders: 322
|
||||
current quarter: 7 anime
|
||||
[26_1분기]29세 독신 중견 모험가의 일상 vid:6 sub:6
|
||||
[26_1분기]공주님고문의시간입니다2기 vid:8 sub:6
|
||||
[26_1분기]귀족전생-축복받은태생으로- vid:9 sub:0
|
||||
[26_1분기]너따위가마왕을이길수있다고생각하지마-용사파티추방 vid:9 sub:9
|
||||
[26_1분기]용사파티에서쫒겨난다재무능 vid:10 sub:8
|
||||
|
||||
=== Anissia Search ===
|
||||
'frieren': 2 results
|
||||
'sousou': 1 results
|
||||
|
||||
=== Nyaa Search ===
|
||||
'Sousou no Frieren ASW HEVC': 36 results
|
||||
top: [ASW] [ASW] Sousou no Frieren S2 - 08 [1080p HEVC x265 1 S:717
|
||||
|
||||
=== Pipeline Search ===
|
||||
success: True
|
||||
anime: 장송의 프리렌 2기
|
||||
captions: 2
|
||||
torrents: 20
|
||||
nas_folder: [26_1분기]장송의 프리렌 2기
|
||||
|
||||
=== qBittorrent ===
|
||||
connected: False
|
||||
|
||||
=== ALL TESTS DONE ===
|
||||
4
tests/run_test.bat
Normal file
4
tests/run_test.bat
Normal file
@@ -0,0 +1,4 @@
|
||||
@echo off
|
||||
cd /d c:\Users\Certes\Desktop\variet-agent
|
||||
python tests/test_cli_tools.py 2>&1
|
||||
type tests\cli_test_output.txt
|
||||
107
tests/test_architecture.py
Normal file
107
tests/test_architecture.py
Normal file
@@ -0,0 +1,107 @@
|
||||
"""아키텍처 v3 검증 스크립트.
|
||||
|
||||
사용법: 프로젝트 루트 또는 tests/ 디렉토리 어디서든 실행 가능.
|
||||
cd variet-agent && python tests/test_architecture.py
|
||||
cd variet-agent/tests && python test_architecture.py
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
|
||||
# 프로젝트 루트를 sys.path에 추가
|
||||
_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
if _root not in sys.path:
|
||||
sys.path.insert(0, _root)
|
||||
|
||||
errors = []
|
||||
|
||||
# 1. core 계층
|
||||
try:
|
||||
from core.gemini_caller import GeminiCaller, GeminiCallError
|
||||
print("✅ core.gemini_caller OK")
|
||||
except Exception as e:
|
||||
errors.append(f"❌ core.gemini_caller: {e}")
|
||||
|
||||
try:
|
||||
from core.orchestrator import Orchestrator
|
||||
print("✅ core.orchestrator OK")
|
||||
except Exception as e:
|
||||
errors.append(f"❌ core.orchestrator: {e}")
|
||||
|
||||
try:
|
||||
from core.task_pipeline import TaskPipeline
|
||||
print("✅ core.task_pipeline OK")
|
||||
except Exception as e:
|
||||
errors.append(f"❌ core.task_pipeline: {e}")
|
||||
|
||||
# 2. tools 계층 (CLI 스크립트)
|
||||
try:
|
||||
from tools.anime_pipeline import AnimePipeline
|
||||
print("✅ tools.anime_pipeline OK")
|
||||
except Exception as e:
|
||||
errors.append(f"❌ tools.anime_pipeline: {e}")
|
||||
|
||||
try:
|
||||
from tools.anissia_client import AnissiaClient, AnimeInfo
|
||||
print("✅ tools.anissia_client OK")
|
||||
except Exception as e:
|
||||
errors.append(f"❌ tools.anissia_client: {e}")
|
||||
|
||||
try:
|
||||
from tools.nyaa_client import NyaaClient, TorrentResult
|
||||
print("✅ tools.nyaa_client OK")
|
||||
except Exception as e:
|
||||
errors.append(f"❌ tools.nyaa_client: {e}")
|
||||
|
||||
try:
|
||||
from tools.qbit_client import QBitClient
|
||||
print("✅ tools.qbit_client OK")
|
||||
except Exception as e:
|
||||
errors.append(f"❌ tools.qbit_client: {e}")
|
||||
|
||||
try:
|
||||
from tools.nas_scanner import NasScanner
|
||||
print("✅ tools.nas_scanner OK")
|
||||
except Exception as e:
|
||||
errors.append(f"❌ tools.nas_scanner: {e}")
|
||||
|
||||
try:
|
||||
from tools.title_matcher import match_titles, japanese_to_romaji
|
||||
print("✅ tools.title_matcher OK")
|
||||
except Exception as e:
|
||||
errors.append(f"❌ tools.title_matcher: {e}")
|
||||
|
||||
# 3. handlers 계층
|
||||
try:
|
||||
from handlers.renderer import safe_send_embed
|
||||
print("✅ handlers.renderer OK")
|
||||
except Exception as e:
|
||||
errors.append(f"❌ handlers.renderer: {e}")
|
||||
|
||||
# 4. 삭제 확인
|
||||
for should_not_exist in ["tools/base.py", "tools/registry.py", "tools/anime_tool.py",
|
||||
"prompts/planner.md", "prompts/coder.md", "prompts/summarizer.md"]:
|
||||
path = os.path.join(_root, should_not_exist)
|
||||
if os.path.exists(path):
|
||||
errors.append(f"❌ 삭제해야 할 파일 존재: {should_not_exist}")
|
||||
else:
|
||||
print(f"✅ {should_not_exist} 삭제됨")
|
||||
|
||||
# 5. 필수 파일 확인
|
||||
for should_exist in ["prompts/agent.md", "prompts/unified.md", "prompts/reviewer.md",
|
||||
".gemini/skills/anime/SKILL.md"]:
|
||||
path = os.path.join(_root, should_exist)
|
||||
if os.path.exists(path):
|
||||
print(f"✅ {should_exist} 존재")
|
||||
else:
|
||||
errors.append(f"❌ 필수 파일 없음: {should_exist}")
|
||||
|
||||
# 결과
|
||||
print(f"\n{'='*40}")
|
||||
if errors:
|
||||
print(f"❌ {len(errors)}개 오류:")
|
||||
for e in errors:
|
||||
print(f" {e}")
|
||||
sys.exit(1)
|
||||
else:
|
||||
print("✅ v3 아키텍처 검증 통과!")
|
||||
sys.exit(0)
|
||||
119
tests/test_cli_tools.py
Normal file
119
tests/test_cli_tools.py
Normal file
@@ -0,0 +1,119 @@
|
||||
"""Full integration test — all tools + architecture + pipeline."""
|
||||
import sys, os, asyncio
|
||||
_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
sys.path.insert(0, _root)
|
||||
OUT = os.path.join(_root, "tests", "cli_test_output.txt")
|
||||
|
||||
lines = []
|
||||
|
||||
# ===== 1. Architecture: imports =====
|
||||
lines.append("=== Architecture Imports ===")
|
||||
tests = [
|
||||
("core.gemini_caller", "GeminiCaller, GeminiCallError"),
|
||||
("core.orchestrator", "Orchestrator"),
|
||||
("core.task_pipeline", "TaskPipeline"),
|
||||
("tools.anime_pipeline", "AnimePipeline"),
|
||||
("tools.anissia_client", "AnissiaClient"),
|
||||
("tools.nyaa_client", "NyaaClient"),
|
||||
("tools.qbit_client", "QBitClient"),
|
||||
("tools.nas_scanner", "NasScanner"),
|
||||
("tools.title_matcher", "match_titles, japanese_to_romaji"),
|
||||
("tools.subtitle_downloader", "SubtitleDownloader"),
|
||||
("handlers.renderer", "safe_send_embed"),
|
||||
]
|
||||
for mod, names in tests:
|
||||
try:
|
||||
exec(f"from {mod} import {names}")
|
||||
lines.append(f" OK {mod}")
|
||||
except Exception as e:
|
||||
lines.append(f" FAIL {mod}: {e}")
|
||||
|
||||
# ===== 2. Deleted files =====
|
||||
lines.append("\n=== Deleted Files ===")
|
||||
for f in ["tools/base.py", "tools/registry.py", "tools/anime_tool.py",
|
||||
"prompts/planner.md", "prompts/coder.md", "prompts/summarizer.md"]:
|
||||
exists = os.path.exists(os.path.join(_root, f))
|
||||
lines.append(f" {'FAIL exists' if exists else 'OK deleted'} {f}")
|
||||
|
||||
# ===== 3. Required files =====
|
||||
lines.append("\n=== Required Files ===")
|
||||
for f in ["prompts/agent.md", "prompts/unified.md", "prompts/reviewer.md",
|
||||
".gemini/skills/anime/SKILL.md"]:
|
||||
exists = os.path.exists(os.path.join(_root, f))
|
||||
lines.append(f" {'OK' if exists else 'FAIL missing'} {f}")
|
||||
|
||||
# ===== 4. Title Matcher (pykakasi) =====
|
||||
lines.append("\n=== Title Matcher ===")
|
||||
from tools.title_matcher import japanese_to_romaji, title_similarity
|
||||
cases = [
|
||||
("sousouno furiiren", "sousou no furiiren"),
|
||||
("Sousou no Frieren", "sousou no furiiren"),
|
||||
]
|
||||
romaji = japanese_to_romaji("sousouno furiiren")
|
||||
lines.append(f" pykakasi('sousouno furiiren'): {romaji}")
|
||||
for a, b in cases:
|
||||
sim = title_similarity(a, b)
|
||||
lines.append(f" sim('{a[:30]}', '{b[:30]}'): {sim:.3f}")
|
||||
|
||||
# ===== 5. NAS Scanner =====
|
||||
lines.append("\n=== NAS Scanner ===")
|
||||
from tools.nas_scanner import NasScanner
|
||||
scanner = NasScanner()
|
||||
lines.append(f" accessible: {scanner.is_accessible()}")
|
||||
if scanner.is_accessible():
|
||||
folders = scanner.list_anime_folders()
|
||||
lines.append(f" total folders: {len(folders)}")
|
||||
current = scanner.get_current_quarter_anime()
|
||||
lines.append(f" current quarter: {len(current)} anime")
|
||||
for f in current[:5]:
|
||||
lines.append(f" {f.folder_name} vid:{f.video_count} sub:{f.subtitle_count}")
|
||||
|
||||
# ===== 6. Async tests =====
|
||||
async def async_tests():
|
||||
# 6a. Anissia search
|
||||
lines.append("\n=== Anissia Search ===")
|
||||
from tools.anissia_client import AnissiaClient
|
||||
ac = AnissiaClient()
|
||||
for kw in ["frieren", "sousou"]:
|
||||
r = await ac.search_anime(kw)
|
||||
lines.append(f" '{kw}': {len(r)} results")
|
||||
|
||||
# 6b. Nyaa search
|
||||
lines.append("\n=== Nyaa Search ===")
|
||||
from tools.nyaa_client import NyaaClient
|
||||
nc = NyaaClient()
|
||||
r = await nc.search("Sousou no Frieren", use_default_suffix=True)
|
||||
lines.append(f" 'Sousou no Frieren ASW HEVC': {len(r)} results")
|
||||
if r:
|
||||
lines.append(f" top: [{r[0].group}] {r[0].title[:50]} S:{r[0].seeders}")
|
||||
|
||||
# 6c. Pipeline search
|
||||
lines.append("\n=== Pipeline Search ===")
|
||||
from tools.anime_pipeline import AnimePipeline
|
||||
pipe = AnimePipeline()
|
||||
try:
|
||||
result = await pipe.search("sousou")
|
||||
lines.append(f" success: {result.success}")
|
||||
lines.append(f" anime: {result.anime.subject if result.anime else 'None'}")
|
||||
lines.append(f" captions: {len(result.captions)}")
|
||||
lines.append(f" torrents: {len(result.torrents)}")
|
||||
lines.append(f" nas_folder: {result.nas_folder}")
|
||||
if result.errors:
|
||||
lines.append(f" errors: {'; '.join(result.errors[:3])}")
|
||||
except Exception as e:
|
||||
lines.append(f" ERROR: {e}")
|
||||
|
||||
# 6d. qBittorrent
|
||||
lines.append("\n=== qBittorrent ===")
|
||||
from tools.qbit_client import QBitClient
|
||||
qb = QBitClient()
|
||||
info = await qb.test_connection()
|
||||
lines.append(f" connected: {info.get('connected')}")
|
||||
if info.get('connected'):
|
||||
lines.append(f" version: {info.get('version')}")
|
||||
|
||||
asyncio.run(async_tests())
|
||||
|
||||
lines.append("\n=== ALL TESTS DONE ===")
|
||||
with open(OUT, "w", encoding="utf-8-sig") as f:
|
||||
f.write("\n".join(lines))
|
||||
Reference in New Issue
Block a user