Files
scientific-agent-skills/skills/latex-posters/scripts/generate_schematic.py

197 lines
7.3 KiB
Python

#!/usr/bin/env python3
"""
Scientific schematic generation using Nano Banana 2.
Generate any scientific diagram by describing it in natural language.
Nano Banana 2 handles everything automatically with smart iterative refinement.
Smart iteration: Only regenerates if quality is below threshold for your document type.
Quality review: Uses Gemini 3.6 Flash for professional scientific evaluation.
Usage:
# Generate for journal paper (highest quality threshold)
python generate_schematic.py "CONSORT flowchart" -o flowchart.png --doc-type journal
# Generate for presentation (lower threshold, faster)
python generate_schematic.py "Transformer architecture" -o transformer.png --doc-type presentation
# Generate for poster
python generate_schematic.py "MAPK signaling pathway" -o pathway.png --doc-type poster
"""
import argparse
import os
import subprocess
import sys
from pathlib import Path
# Variables forwarded to the generation subprocess. The child needs the
# OpenRouter credential; the rest keep networking, TLS, and locale working.
# Copying the whole parent environment instead would hand the child every
# unrelated secret that happens to be exported in the calling shell.
FORWARDED_ENV_VARS = (
"PATH", "HOME", "LANG", "LC_ALL", "TMPDIR", "PYTHONPATH",
"HTTP_PROXY", "HTTPS_PROXY", "NO_PROXY",
"http_proxy", "https_proxy", "no_proxy",
"SSL_CERT_FILE", "SSL_CERT_DIR", "REQUESTS_CA_BUNDLE", "CURL_CA_BUNDLE",
# Windows needs these for sockets, temp files, and interpreter startup.
"SYSTEMROOT", "WINDIR", "COMSPEC", "PATHEXT",
"APPDATA", "LOCALAPPDATA", "USERPROFILE", "TEMP", "TMP",
)
def resolve_api_key(explicit=None):
"""Resolve the OpenRouter key from --api-key, the environment, then any .env file.
The .env scan walks up from the working directory and finally checks the
script's own directory, so running from anywhere inside a project picks up
the key at its root. The child process is handed the resolved value through
build_subprocess_env, so it never has to repeat this search.
"""
if explicit:
return explicit
from_env = os.environ.get("OPENROUTER_API_KEY", "").strip()
if from_env:
return from_env
cwd = Path.cwd()
for directory in [cwd, *cwd.parents, Path(__file__).resolve().parent]:
env_file = directory / ".env"
if not env_file.is_file():
continue
try:
content = env_file.read_text(encoding="utf-8", errors="replace")
except OSError:
continue
for raw in content.splitlines():
line = raw.strip()
if line.startswith("#") or "=" not in line:
continue
name, _, value = line.partition("=")
if name.strip() == "OPENROUTER_API_KEY":
value = value.strip().strip('"').strip("'")
if value:
return value
return None
def build_subprocess_env(api_key):
"""Return a minimal environment for the AI generation subprocess."""
env = {name: os.environ[name] for name in FORWARDED_ENV_VARS if name in os.environ}
if api_key:
env["OPENROUTER_API_KEY"] = api_key
return env
def main():
"""Command-line interface."""
parser = argparse.ArgumentParser(
description="Generate scientific schematics using AI with smart iterative refinement",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
How it works:
Simply describe your diagram in natural language
Nano Banana 2 generates it automatically with:
- Smart iteration (only regenerates if quality is below threshold)
- Quality review by Gemini 3.6 Flash
- Document-type aware quality thresholds
- Publication-ready output
Document Types (quality thresholds):
journal 8.5/10 - Nature, Science, peer-reviewed journals
conference 8.0/10 - Conference papers
thesis 8.0/10 - Dissertations, theses
grant 8.0/10 - Grant proposals
preprint 7.5/10 - arXiv, bioRxiv, etc.
report 7.5/10 - Technical reports
poster 7.0/10 - Academic posters
presentation 6.5/10 - Slides, talks
default 7.5/10 - General purpose
Examples:
# Generate for journal paper (strict quality)
python generate_schematic.py "CONSORT participant flow" -o flowchart.png --doc-type journal
# Generate for poster (moderate quality)
python generate_schematic.py "Transformer architecture" -o arch.png --doc-type poster
# Generate for slides (faster, lower threshold)
python generate_schematic.py "System diagram" -o system.png --doc-type presentation
# Custom max iterations
python generate_schematic.py "Complex pathway" -o pathway.png --iterations 2
# Verbose output
python generate_schematic.py "Circuit diagram" -o circuit.png -v
Environment Variables:
OPENROUTER_API_KEY Required for AI generation
"""
)
parser.add_argument("prompt",
help="Description of the diagram to generate")
parser.add_argument("-o", "--output", required=True,
help="Output file path")
parser.add_argument("--doc-type", default="default",
choices=["journal", "conference", "poster", "presentation",
"report", "grant", "thesis", "preprint", "default"],
help="Document type for quality threshold (default: default)")
parser.add_argument("--iterations", type=int, default=2,
help="Maximum refinement iterations (default: 2, max: 2)")
parser.add_argument("--api-key",
help="OpenRouter API key (or use OPENROUTER_API_KEY env var)")
parser.add_argument("-v", "--verbose", action="store_true",
help="Verbose output")
args = parser.parse_args()
# Check for API key — resolves --api-key, the environment, then any .env file
api_key = resolve_api_key(args.api_key)
if not api_key:
print("Error: OPENROUTER_API_KEY not found")
print("\nFor AI generation, you need an OpenRouter API key.")
print("Get one at: https://openrouter.ai/keys")
print("\nSet it with:")
print(" export OPENROUTER_API_KEY='your_api_key'")
print("\nOr add OPENROUTER_API_KEY=your_api_key to a .env file")
print("Or use --api-key flag")
sys.exit(1)
# Find AI generation script
script_dir = Path(__file__).parent
ai_script = script_dir / "generate_schematic_ai.py"
if not ai_script.exists():
print(f"Error: AI generation script not found: {ai_script}")
sys.exit(1)
# Build command
cmd = [sys.executable, str(ai_script), args.prompt, "-o", args.output]
if args.doc_type != "default":
cmd.extend(["--doc-type", args.doc_type])
# Enforce max 2 iterations
iterations = min(args.iterations, 2)
if iterations != 2:
cmd.extend(["--iterations", str(iterations)])
if args.verbose:
cmd.append("-v")
# Execute — pass API key via environment to avoid exposure in process listings
try:
result = subprocess.run(cmd, check=False, env=build_subprocess_env(api_key))
sys.exit(result.returncode)
except Exception as e:
print(f"Error executing AI generation: {e}")
sys.exit(1)
if __name__ == "__main__":
main()