phase 9
This commit is contained in:
107
tests/detect/manual/test_cloud_provider.py
Normal file
107
tests/detect/manual/test_cloud_provider.py
Normal file
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test cloud LLM provider with a real API call.
|
||||
|
||||
Sends a test image to the configured cloud provider and verifies
|
||||
the response. Set your provider env vars before running.
|
||||
|
||||
Usage:
|
||||
# Groq (default)
|
||||
CLOUD_LLM_PROVIDER=groq GROQ_API_KEY=gsk_... python tests/detect/manual/test_cloud_provider.py
|
||||
|
||||
# Gemini
|
||||
CLOUD_LLM_PROVIDER=gemini GEMINI_API_KEY=AIza... python tests/detect/manual/test_cloud_provider.py
|
||||
|
||||
# Claude
|
||||
CLOUD_LLM_PROVIDER=claude ANTHROPIC_API_KEY=sk-ant-... python tests/detect/manual/test_cloud_provider.py
|
||||
|
||||
# OpenAI-compatible
|
||||
CLOUD_LLM_PROVIDER=openai OPENAI_API_KEY=sk-... python tests/detect/manual/test_cloud_provider.py
|
||||
"""
|
||||
|
||||
import base64
|
||||
import io
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Load .env from ctrl/ (same as docker-compose uses)
|
||||
env_file = Path(__file__).resolve().parents[3] / "ctrl" / ".env"
|
||||
if env_file.exists():
|
||||
for line in env_file.read_text().splitlines():
|
||||
line = line.strip()
|
||||
if line and not line.startswith("#") and "=" in line:
|
||||
key, _, value = line.partition("=")
|
||||
os.environ.setdefault(key.strip(), value.strip())
|
||||
|
||||
import numpy as np
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
sys.path.insert(0, ".")
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format="%(levelname)-7s %(name)s — %(message)s")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def make_brand_image(text: str, width: int = 300, height: int = 100) -> str:
|
||||
img = Image.new("RGB", (width, height), "white")
|
||||
draw = ImageDraw.Draw(img)
|
||||
try:
|
||||
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 42)
|
||||
except (OSError, IOError):
|
||||
font = ImageFont.load_default()
|
||||
draw.text((10, 20), text, fill="black", font=font)
|
||||
buf = io.BytesIO()
|
||||
img.save(buf, "JPEG")
|
||||
return base64.b64encode(buf.getvalue()).decode()
|
||||
|
||||
|
||||
def main():
|
||||
from detect.providers import get_provider, has_api_key, PROVIDERS
|
||||
|
||||
provider_name = os.environ.get("CLOUD_LLM_PROVIDER", "groq")
|
||||
logger.info("Provider: %s", provider_name)
|
||||
logger.info("Available providers: %s", list(PROVIDERS.keys()))
|
||||
|
||||
if not has_api_key():
|
||||
logger.error("No API key set for provider '%s'", provider_name)
|
||||
logger.error("Set the appropriate env var (see usage in docstring)")
|
||||
sys.exit(1)
|
||||
|
||||
provider = get_provider()
|
||||
logger.info("Model: %s", provider.model)
|
||||
logger.info("Available models: %s", list(provider.models.keys()))
|
||||
input("\nPress Enter to start...")
|
||||
|
||||
prompt = (
|
||||
"Identify the brand or sponsor visible in this image from a soccer broadcast. "
|
||||
"Respond with: brand, confidence (0-1), reasoning."
|
||||
)
|
||||
|
||||
test_cases = ["NIKE", "EMIRATES", "Coca-Cola", "adidas"]
|
||||
|
||||
for text in test_cases:
|
||||
logger.info("--- Testing: '%s' ---", text)
|
||||
image_b64 = make_brand_image(text)
|
||||
|
||||
try:
|
||||
result = provider.call(image_b64, prompt)
|
||||
logger.info(" answer: %s", result.answer)
|
||||
logger.info(" tokens: %d", result.total_tokens)
|
||||
|
||||
if text.lower() in result.answer.lower():
|
||||
logger.info(" PASS — found '%s' in response", text)
|
||||
else:
|
||||
logger.warning(" MISS — '%s' not in response (may be correct, check answer)", text)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(" FAIL — %s: %s", type(e).__name__, e)
|
||||
if hasattr(e, 'response') and e.response is not None:
|
||||
logger.error(" Response: %s", e.response.text[:500])
|
||||
|
||||
logger.info("All provider tests complete.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user