From a755e12ea3521ac6295901c2f9ba0761c4ea802f Mon Sep 17 00:00:00 2001 From: David Rice Date: Thu, 16 Apr 2026 15:46:56 +0100 Subject: [PATCH] Changes --- display.py | 14 +++++++------- gen_face_ai.py | 41 +++++++++++++---------------------------- 2 files changed, 20 insertions(+), 35 deletions(-) diff --git a/display.py b/display.py index 3a97fd3..32aafa4 100644 --- a/display.py +++ b/display.py @@ -20,7 +20,6 @@ Framebuffer prerequisites on Debian (device): """ import os -import sys import math import argparse from datetime import datetime @@ -215,15 +214,15 @@ def main() -> None: pygame.display.set_caption('JARVIS') fonts = { - 'large': _load_font(76), - 'small': _load_font(24), + 'large': _load_font(56), + 'small': _load_font(18), } # Layout anchors — all relative to screen size so they adapt to resolution + face_rx = int(min(W, H) * 0.115) # half-width at cheek level + face_ry = int(min(W, H) * 0.135) # half-height crown→chin face_cx = W // 2 - face_cy = int(H * 0.31) - face_rx = int(min(W, H) * 0.150) # half-width at cheek level - face_ry = int(min(W, H) * 0.175) # half-height crown→chin + face_cy = int(face_ry * 1.2) + 8 # nearly touches the top edge status_y = int(H * 0.82) dot_y = int(H * 0.895) @@ -269,7 +268,8 @@ def main() -> None: special_flags=pygame.BLEND_ADD) else: draw_wireframe_face(screen, face_cx, face_cy, face_rx, face_ry) - draw_clock(screen, fonts, 20, 14) + clock_block_h = fonts['small'].get_height() + 4 + fonts['large'].get_height() + draw_clock(screen, fonts, 20, face_cy - clock_block_h // 2) draw_status(screen, fonts, status_text, W // 2, status_y) draw_dot(screen, W // 2, dot_y) diff --git a/gen_face_ai.py b/gen_face_ai.py index 000a4fb..7bb8dce 100644 --- a/gen_face_ai.py +++ b/gen_face_ai.py @@ -1,17 +1,13 @@ #!/usr/bin/env python3 """ -gen_face_ai.py – Generate assets/face_wire.png using Gemini image generation -──────────────────────────────────────────────────────────────────────────────── -Uses the Gemini / Google Gen AI SDK with a native image-generation model -(gemini-2.5-flash-image or similar) to produce a wireframe face PNG ready for -display.py to load. +gen_face_ai.py – Generate assets/face_wire.png via Gemini image generation +────────────────────────────────────────────────────────────────────────────── +Run once to produce the face PNG that display.py loads at startup. pip install google-genai pillow python3 gen_face_ai.py -Or set the key in the environment: - export GEMINI_API_KEY=YOUR_KEY - python3 gen_face_ai.py +Pass --list-models to see what image-capable models your key can reach. """ import os @@ -19,16 +15,15 @@ import sys import io import argparse -# ── Paste your Gemini API key here ──────────────────────────────────────────── +# ── API key ─────────────────────────────────────────────────────────────────── API_KEY = 'AQ.Ab8RN6LuGwkGiKPa61jsLAEYEpJp1Yl2EkZuBWTbN9AMKxgTSw' # ───────────────────────────────────────────────────────────────────────────── -# ── CLI ─────────────────────────────────────────────────────────────────────── ap = argparse.ArgumentParser() -ap.add_argument('--key', default='', help='Override the hardcoded API key') -ap.add_argument('--out', default='assets/face_wire.png') +ap.add_argument('--key', default='', help='Override the hardcoded API key') +ap.add_argument('--out', default='assets/face_wire.png') ap.add_argument('--model', default='gemini-2.5-flash-image', - help='Gemini image model to use (default: gemini-2.5-flash-image)') + help='Gemini image model to use') ap.add_argument('--list-models', action='store_true', help='Print models that support generateContent then exit') args = ap.parse_args() @@ -37,7 +32,6 @@ api_key = args.key or API_KEY or os.environ.get('GEMINI_API_KEY', '') if not api_key: sys.exit('ERROR: paste your key into API_KEY at the top of this file') -# ── Install check ───────────────────────────────────────────────────────────── try: from google import genai from google.genai import types @@ -49,7 +43,6 @@ try: except ImportError: sys.exit('Run: pip install pillow then try again.') -# ── Connect ─────────────────────────────────────────────────────────────────── print('Connecting to Google GenAI …') client = genai.Client(api_key=api_key) @@ -61,7 +54,6 @@ if args.list_models: print(f' {m.name}') sys.exit(0) -# ── Prompt ──────────────────────────────────────────────────────────────────── PROMPT = ( "3D wireframe polygon mesh of a human head and face, viewed from slightly " "below, front-facing, neutral expression, pure black background, thin " @@ -70,17 +62,15 @@ PROMPT = ( "style, high contrast monochrome" ) -# ── Generate ────────────────────────────────────────────────────────────────── print(f'Generating with {args.model} …') response = client.models.generate_content( - model = args.model, - contents= PROMPT, - config = types.GenerateContentConfig( + model = args.model, + contents = PROMPT, + config = types.GenerateContentConfig( response_modalities = ['IMAGE', 'TEXT'], ), ) -# ── Extract image bytes ─────────────────────────────────────────────────────── img_bytes = None for part in response.candidates[0].content.parts: if part.inline_data and part.inline_data.mime_type.startswith('image/'): @@ -88,17 +78,12 @@ for part in response.candidates[0].content.parts: break if img_bytes is None: - # Print any text the model returned to help debug for part in response.candidates[0].content.parts: if hasattr(part, 'text') and part.text: - print('Model text response:', part.text[:400]) + print('Model said:', part.text[:400]) sys.exit('No image in response – try a different --model') -# ── Save as PNG ─────────────────────────────────────────────────────────────── -os.makedirs(os.path.dirname(args.out) if os.path.dirname(args.out) else '.', - exist_ok=True) - -# Convert whatever format came back to a proper PNG +os.makedirs(os.path.dirname(args.out) if os.path.dirname(args.out) else '.', exist_ok=True) img = Image.open(io.BytesIO(img_bytes)) img.save(args.out, 'PNG')