File size: 3,592 Bytes
6494c95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
"""Generate one real image and print the latency and the estimated cost.

    uv run python -m scripts.try_image
    uv run python -m scripts.try_image --model detailed --aspect landscape --moderate
    uv run python -m scripts.try_image "a cat wearing a space helmet"

Needs the image backend's key (HF_TOKEN for `image_backend: hf`) in the environment or in the
.env file one folder above the repo. Costs real money (a few cents); run it locally, never in CI.
The image goes to a temporary PNG file, and the path is printed. The prompt is not moderated here:
use a harmless one. `--moderate` also sends the image to the OpenAI image moderation.
"""

from __future__ import annotations

import argparse
import asyncio
import os
import sys
import tempfile
from pathlib import Path

from src.config import load_env_file, load_settings
from src.errors import AppError
from src.logging_setup import configure_logging
from src.providers.base import ImageRequest
from src.providers.factory import build_image, build_moderator

DEFAULT_PROMPT = "a friendly robot painting a rainbow, colourful children's book illustration"


async def main() -> int:
    parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
    parser.add_argument("prompt", nargs="?", default=DEFAULT_PROMPT)
    parser.add_argument("--model", help="image model key from config/models.yaml")
    parser.add_argument("--aspect", choices=["square", "landscape", "portrait"], default="square")
    parser.add_argument("--moderate", action="store_true", help="also moderate the image")
    args = parser.parse_args()

    sys.stdout.reconfigure(encoding="utf-8")
    load_env_file()
    settings = load_settings()
    if settings.development_mode:
        print("Development mode uses fakes; unset DEVELOPMENT_MODE to try the real service.")
        return 2
    key_name = "FAL_KEY" if settings.config.image_backend == "fal" else "HF_TOKEN"
    needed = [key_name] + (["OPENAI_API_KEY"] if args.moderate else [])
    missing = [name for name in needed if not os.environ.get(name)]
    if missing:
        print(f"Missing: {', '.join(missing)} (set it in the shell or the .env file).")
        return 2
    model_key = args.model or settings.models.defaults.create_model
    active = settings.active_image_models()
    if model_key not in active:
        print(f"Unknown or inactive model '{model_key}'. Active: {list(active)}")
        return 2
    model = settings.models.image_models[model_key]
    print(f"Backend {settings.config.image_backend}, model {settings.model_id_for(model)}")

    try:
        result = await build_image(settings).generate(
            ImageRequest(prompt=args.prompt, model_key=model_key, aspect=args.aspect)
        )
    except AppError as error:
        print(f"Failed: {type(error).__name__} (see the log line above)")
        return 1
    with tempfile.NamedTemporaryFile(prefix="ai_image_lab_", suffix=".png", delete=False) as file:
        file.write(result.image)
    print(f"Latency {result.seconds:.1f} s, estimated cost ${result.est_cost:.3f}")
    print(f"Image: {len(result.image) / 1024:.0f} KiB -> {Path(file.name)}")

    if args.moderate:
        try:
            verdict = await build_moderator(settings).moderate_image(result.image)
        except AppError as error:
            print(f"Image moderation failed: {type(error).__name__}")
            return 1
        print(f"Image moderation: {'FLAGGED ' + str(verdict.code) if verdict.flagged else 'clean'}")
    return 0


if __name__ == "__main__":
    configure_logging()
    raise SystemExit(asyncio.run(main()))