diff --git a/app/Dockerfile b/app/Dockerfile index 06be4dd..8e76d23 100644 --- a/app/Dockerfile +++ b/app/Dockerfile @@ -27,8 +27,8 @@ COPY pyproject.toml . COPY uv.lock* . RUN uv sync --frozen -RUN uv run playwright install chromium -RUN uv run playwright install-deps chromium +RUN uv run playwright install firefox +RUN uv run playwright install-deps firefox # 只複製 app/ 的內容進去 COPY . . diff --git a/app/invoice_fetcher.py b/app/invoice_fetcher.py index eca314d..e76ddbc 100644 --- a/app/invoice_fetcher.py +++ b/app/invoice_fetcher.py @@ -4,7 +4,7 @@ import os import time import asyncio import requests -import anthropic +from groq import Groq import urllib3 import threading import captcha_state @@ -28,7 +28,7 @@ load_dotenv("../.env") EINVOICE_USER = os.getenv("EINVOICE_USER") EINVOICE_PASS = os.getenv("EINVOICE_PASS") -ANTHROPIC_API_KEY = os.getenv("ANTHROPIC_API_KEY") +GROQ_API_KEY = os.getenv("GROQ_API_KEY") MY_USER_ID = os.getenv("LINE_USER_ID") cloudinary.config( @@ -53,19 +53,20 @@ Base = declarative_base() # created_at = Column(DateTime, default=datetime.now) def solve_captcha(img_b64: str) -> str: - client = anthropic.Anthropic(api_key=ANTHROPIC_API_KEY) - msg = client.messages.create( - model="claude-haiku-4-5-20251001", + + # client = anthropic.Anthropic(api_key=ANTHROPIC_API_KEY) + # 改用groq + client = Groq(api_key=GROQ_API_KEY) + msg = client.chat.completions.create( + model="llama-3.2-11b-vision-preview", max_tokens=10, messages=[{ "role": "user", "content": [ { - "type": "image", - "source": { - "type": "base64", - "media_type": "image/png", - "data": img_b64 + "type": "image_url", + "image_url": { + "url": f"data:image/png;base64,{img_b64}" } }, { @@ -75,7 +76,7 @@ def solve_captcha(img_b64: str) -> str: ] }] ) - return msg.content[0].text.strip() + return msg.choices[0].message.content.strip() async def solve_captcha_manual(img_b64: str): # 1. 解碼圖片並轉成白底 @@ -137,7 +138,7 @@ async def login_and_get_token() -> str | None: try: async with async_playwright() as p: # 載入登入頁拿 login_challenge - browser = await p.chromium.launch(headless=False) + browser = await p.firefox.launch(headless=True) page = await browser.new_page() await page.goto("https://www.einvoice.nat.gov.tw/accounts/login/mw") await page.wait_for_timeout(8000) @@ -160,7 +161,9 @@ async def login_and_get_token() -> str | None: # 將拿到的圖片存成檔案穰後轉給linebot處理 # ✅ 透過 LINE Bot 取得驗證碼 - captcha_text = await solve_captcha_manual(captcha_data["image"]) + # captcha_text = await solve_captcha_manual(captcha_data["image"]) + captcha_text = await solve_captcha(captcha_data["image"]) + print(f"驗證碼: {captcha_text}") # 登入 diff --git a/app/pyproject.toml b/app/pyproject.toml index b8fdeea..adb6093 100644 --- a/app/pyproject.toml +++ b/app/pyproject.toml @@ -8,6 +8,7 @@ dependencies = [ "anthropic>=0.84.0", "cloudinary>=1.44.1", "fastapi>=0.135.1", + "groq>=1.1.1", "line-bot-sdk>=3.22.0", "nest-asyncio>=1.6.0", "numpy>=2.4.2", diff --git a/app/uv.lock b/app/uv.lock index 47ee1fc..fe40915 100644 --- a/app/uv.lock +++ b/app/uv.lock @@ -157,6 +157,7 @@ dependencies = [ { name = "anthropic" }, { name = "cloudinary" }, { name = "fastapi" }, + { name = "groq" }, { name = "line-bot-sdk" }, { name = "nest-asyncio" }, { name = "numpy" }, @@ -173,6 +174,7 @@ requires-dist = [ { name = "anthropic", specifier = ">=0.84.0" }, { name = "cloudinary", specifier = ">=1.44.1" }, { name = "fastapi", specifier = ">=0.135.1" }, + { name = "groq", specifier = ">=1.1.1" }, { name = "line-bot-sdk", specifier = ">=3.22.0" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, { name = "numpy", specifier = ">=2.4.2" }, @@ -440,6 +442,23 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/29/4b/45d90626aef8e65336bed690106d1382f7a43665e2249017e9527df8823b/greenlet-3.3.2-cp314-cp314t-win_amd64.whl", hash = "sha256:c04c5e06ec3e022cbfe2cd4a846e1d4e50087444f875ff6d2c2ad8445495cf1a", size = 237086, upload-time = "2026-02-20T20:20:45.786Z" }, ] +[[package]] +name = "groq" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "distro" }, + { name = "httpx" }, + { name = "pydantic" }, + { name = "sniffio" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9f/bc/7ad1d9967c58b21cdec0c94f26f40fc37b07ba60715d6cbc7c7ef775d927/groq-1.1.1.tar.gz", hash = "sha256:ea971eca72d88e875a78567904bfb46a2f2e43907bfe400fc36a81150a4066d8", size = 150783, upload-time = "2026-03-11T09:11:32.027Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/1d/0749c5f0ed76693f6a3a40e2b0c40201fa23e1ccb00e69d5aa63e3f5b0ff/groq-1.1.1-py3-none-any.whl", hash = "sha256:6b7932c0fd3189ad1842fbc294f57fbf014713e01f72037451cb60a138c4b846", size = 139650, upload-time = "2026-03-11T09:11:29.87Z" }, +] + [[package]] name = "h11" version = "0.16.0"