Task #77

razvedchik_patch.py β€” 이 νŒŒμΌμ„ μ‹€ν–‰ν•˜λ©΄ 패치 적용됨

μž‘μ—… λͺ…λ Ήμ–΄
[πŸ”΄ HIGH] ## μž‘μ—…: razvedchik.py verification 처리 κΈ°λŠ₯ μΆ”κ°€ ### λ°°κ²½ Moltbook ν”Œλž«νΌμ€ λŒ“κΈ€/포슀트 생성 응닡에 verification μ±Œλ¦°μ§€λ₯Ό ν¬ν•¨ν•œλ‹€. ν˜„μž¬ μ½”λ“œλŠ” 이λ₯Ό μ²˜λ¦¬ν•˜μ§€ μ•Šμ•„ λͺ¨λ“  λŒ“κΈ€/ν¬μŠ€νŠΈκ°€ `pending` μƒνƒœλ‘œ λ‚¨λŠ”λ‹€. ### 응닡 ꡬ쑰 (μ‹€μ œ 확인됨) ```json { "comment": { "id": "39f88d5a-...", "verification_status": "pending", "verification": { "verification_code": "moltbook_verify_916c8f1ac1881ffcc7959394eb36e6b6", "challenge_text": "A] lOoObSsTtEr ClA-w^ eXErTs- TwEnTy] sIx Ne^ wToNs, aNd [AnOtHeR ClAw] aDdS- FoUrTeEn, WhAt/] iS- ToTaL FoRcE?", "expires_at": "2026-03-25 20:10:31.072445+00", "instructions": "Solve the math problem and respond with ONLY the number (with 2 decimal places, e.g., '525.00'). Send your answer to POST /api/v1/verify with the verification_code." } } } ``` ### challenge_text νŒ¨ν„΄ 뢄석 - μ˜λ„μ μœΌλ‘œ obfuscate: λŒ€μ†Œλ¬Έμž ν˜Όν•©, 특수문자(], ^, -, ~, /, |, *) λ…Έμ΄μ¦ˆ - μˆ«μžλŠ” μ˜μ–΄ λ‹¨μ–΄λ‘œ ν‘œκΈ°: twenty six, fourteen, thirty, fifteen λ“± - μ—°μ‚°: λ§μ…ˆ(and ... adds) λ˜λŠ” κ³±μ…ˆ(multiplies by) - 응닡 ν˜•μ‹: μ†Œμˆ˜μ  2자리 λ¬Έμžμ—΄ (e.g., "40.00") ### 처리 API `POST /api/v1/verify` Body: `{"verification_code": "moltbook_verify_xxx", "answer": "40.00"}` ### κ΅¬ν˜„ μš”κ΅¬μ‚¬ν•­ **파일: `/home/grass/leninbot/razvedchik.py`** #### 1. `solve_challenge_text(challenge_text: str) -> str` 정적 λ©”μ„œλ“œ μΆ”κ°€ (MoltbookClient 클래슀) - challenge_textλ₯Ό μ†Œλ¬Έμžλ‘œ λ³€ν™˜ ν›„ 특수문자/λ…Έμ΄μ¦ˆ 제거 - μ˜μ–΄ 숫자 단어λ₯Ό μ •μˆ˜λ‘œ λ³€ν™˜ (one~ninety nine λ²”μœ„λ©΄ μΆ©λΆ„): ``` one=1, two=2, three=3, four=4, five=5, six=6, seven=7, eight=8, nine=9, ten=10, eleven=11, twelve=12, thirteen=13, fourteen=14, fifteen=15, sixteen=16, seventeen=17, eighteen=18, nineteen=19, twenty=20, thirty=30, forty=40, fifty=50, sixty=60, seventy=70, eighty=80, ninety=90 ("twenty six" β†’ 26, "thirty three" β†’ 33 λ“± 볡합 숫자 처리) ``` - μ—°μ‚° 감지: - "adds", "and ... adds", "plus" β†’ λ§μ…ˆ - "multiplies by", "multiply by", "times" β†’ κ³±μ…ˆ - "minus", "subtract" β†’ λΊ„μ…ˆ - κ²°κ³Όλ₯Ό `f"{result:.2f}"` ν˜•μ‹μœΌλ‘œ λ°˜ν™˜ - μ‹€νŒ¨ μ‹œ None λ°˜ν™˜ (β†’ LLM fallback) #### 2. `_verify_content(verification: dict) -> bool` λ©”μ„œλ“œ μΆ”κ°€ (MoltbookClient 클래슀) ```python def _verify_content(self, verification: dict) -> bool: """verification μ±Œλ¦°μ§€ ν•΄κ²° 및 POST /api/v1/verify 호좜""" code = verification.get("verification_code") challenge = verification.get("challenge_text", "") expires_at = verification.get("expires_at", "") if not code or not challenge: return False # 만료 체크 (μ—¬μœ  5초) # expires_at νŒŒμ‹± β†’ ν˜„μž¬ μ‹œκ°κ³Ό 비ꡐ answer = self.solve_challenge_text(challenge) if answer is None: logger.warning("[razvedchik] μ±Œλ¦°μ§€ ν•΄κ²° μ‹€νŒ¨ β€” challenge: %s", challenge[:80]) return False logger.info("[razvedchik] verification μ‹œλ„ β€” code=%s answer=%s", code[-8:], answer) try: resp = self._client.post("/verify", json={"verification_code": code, "answer": answer}) resp.raise_for_status() result = resp.json() success = result.get("success") or result.get("verified") or result.get("status") == "verified" if success: logger.info("[razvedchik] βœ… Verification 성곡") else: logger.warning("[razvedchik] ❌ Verification μ‹€νŒ¨: %s", result) return bool(success) except Exception as e: logger.error("[razvedchik] Verification API 였λ₯˜: %s", e) return False ``` #### 3. `post_comment()` μˆ˜μ • λŒ“κΈ€ κ²Œμ‹œ ν›„ μ‘λ‹΅μ—μ„œ verification ν•„λ“œ 감지 β†’ `_verify_content()` μžλ™ 호좜: ```python resp = self.client.post(f"/posts/{post_id}/comments", body) # verification 처리 comment_obj = resp.get("comment", {}) if isinstance(resp, dict) else {} verification = comment_obj.get("verification") if verification: verified = self.client._verify_content(verification) resp["_verified"] = verified return resp ``` #### 4. `post_observation()` μˆ˜μ • 포슀트 κ²Œμ‹œ ν›„ λ™μΌν•˜κ²Œ verification 처리: ```python resp = self.client.post("/posts", body) # verification 처리 post_obj = resp.get("post", {}) if isinstance(resp, dict) else {} verification = post_obj.get("verification") if verification: verified = self.client._verify_content(verification) resp["_verified"] = verified return resp ``` #### 5. `_build_report()` μˆ˜μ • comment_results에 `verified` ν•„λ“œ μΆ”κ°€: ```python "verified": r.get("response", {}).get("_verified"), ``` #### 6. `patrol()` STEP 3 μˆ˜μ • λŒ“κΈ€ κ²°κ³Ό μ €μž₯ μ‹œ `"verified"` ν•„λ“œ 포함: ```python comment_results.append({ ... "verified": resp.get("_verified"), }) ``` ### κ΅¬ν˜„ μˆœμ„œ 1. 파일 읽기: `read_file("razvedchik.py", line_start=158, line_end=190)` β€” solve_verification μœ„μΉ˜ 2. `solve_challenge_text` κ΅¬ν˜„ 및 λ‹¨μœ„ ν…ŒμŠ€νŠΈ 3. `_verify_content` κ΅¬ν˜„ 4. `post_comment`, `post_observation` μˆ˜μ • 5. `_build_report`, `patrol` μˆ˜μ • 6. 문법 검증: `python -m py_compile razvedchik.py` 7. λ°±μ—… 생성 ν›„ μ €μž₯ ### μ£Όμ˜μ‚¬ν•­ - `_verify_content`μ—μ„œ `self._client`λŠ” httpx.Client μΈμŠ€ν„΄μŠ€ β€” `.post(path, json=...)` 방식 μ‚¬μš© (단, MoltbookClient._requestλ₯Ό 톡해 ν˜ΈμΆœν•˜μ§€ 말 것 β€” μž¬κ·€ λ°©μ§€) - expires_at νŒŒμ‹±: `dateutil.parser.parse` λ˜λŠ” `datetime.fromisoformat` μ‚¬μš© - μˆ˜μ • μ „ λ°˜λ“œμ‹œ λ°±μ—…: `razvedchik.py.bak.YYYYMMDD_HHMMSS` - μˆ˜μ • ν›„ `python -m py_compile razvedchik.py` 톡과 확인 - git commit/pushκΉŒμ§€ μ™„λ£Œ ### κΈ°λŒ€ κ²°κ³Ό λ‹€μŒ μˆœμ°°λΆ€ν„° λͺ¨λ“  λŒ“κΈ€/ν¬μŠ€νŠΈκ°€ `pending` β†’ `verified` μƒνƒœλ‘œ μ „ν™˜λ¨. 순찰 λ³΄κ³ μ„œμ— verification κ²°κ³Ό 기둝.