Skill Tracer
Skills › Scientific Agent Skills › latex-posters › generate_schematic.py

generate_schematic.py

201 lines · skills/latex-posters/scripts/generate_schematic.py at 5f2bc03

1#!/usr/bin/env python3
2"""
3Scientific schematic generation using Nano Banana 2.
4
5Generate any scientific diagram by describing it in natural language.
6Nano Banana 2 handles everything automatically with smart iterative refinement.
7
8Smart iteration: Only regenerates if quality is below threshold for your document type.
9Quality review: Uses Gemini 3.7 Flash for professional scientific evaluation.
11Usage:
12 # Generate for journal paper (highest quality threshold)
13 python generate_schematic.py "CONSORT flowchart" -o flowchart.png --doc-type journal
15 # Generate for presentation (lower threshold, faster)
16 python generate_schematic.py "Transformer architecture" -o transformer.png --doc-type presentation
18 # Generate for poster
19 python generate_schematic.py "MAPK signaling pathway" -o pathway.png --doc-type poster
20"""
22import argparse
23import os
24import subprocess
25import sys
26from pathlib import Path
28# Variables forwarded to the generation subprocess. The child needs the
29# OpenRouter credential; the rest keep networking, TLS, and locale working.
30# Copying the whole parent environment instead would hand the child every
31# unrelated secret that happens to be exported in the calling shell.
32FORWARDED_ENV_VARS = (
33 "PATH", "HOME", "LANG", "LC_ALL", "TMPDIR", "PYTHONPATH",
34 "HTTP_PROXY", "HTTPS_PROXY", "NO_PROXY",
35 "http_proxy", "https_proxy", "no_proxy",
36 "SSL_CERT_FILE", "SSL_CERT_DIR", "REQUESTS_CA_BUNDLE", "CURL_CA_BUNDLE",
37 # Windows needs these for sockets, temp files, and interpreter startup.
38 "SYSTEMROOT", "WINDIR", "COMSPEC", "PATHEXT",
39 "APPDATA", "LOCALAPPDATA", "USERPROFILE", "TEMP", "TMP",
43def resolve_api_key(explicit=None):
44 """Resolve the OpenRouter key from --api-key, the environment, then any .env file.
46 The .env scan walks up from the working directory and finally checks the
47 script's own directory, so running from anywhere inside a project picks up
48 the key at its root. The child process is handed the resolved value through
49 build_subprocess_env, so it never has to repeat this search.
50 """
51 if explicit:
52 return explicit
54 from_env = os.environ.get("OPENROUTER_API_KEY", "").strip()
55 if from_env:
56 return from_env
58 cwd = Path.cwd()
59 for directory in [cwd, *cwd.parents, Path(__file__).resolve().parent]:
60 env_file = directory / ".env"
61 if not env_file.is_file():
62 continue
63 try:
64 content = env_file.read_text(encoding="utf-8", errors="replace")
65 except OSError:
66 continue
67 for raw in content.splitlines():
68 line = raw.strip()
69 if line.startswith("#") or "=" not in line:
70 continue
71 name, _, value = line.partition("=")
72 if name.strip() == "OPENROUTER_API_KEY":
73 value = value.strip().strip('"').strip("'")
74 if value:
75 return value
77 return None
80def build_subprocess_env(api_key):
81 """Return a minimal environment for the AI generation subprocess."""
82 env = {name: os.environ[name] for name in FORWARDED_ENV_VARS if name in os.environ}
83 if api_key:
84 env["OPENROUTER_API_KEY"] = api_key
85 return env
88def main():
89 """Command-line interface."""
90 parser = argparse.ArgumentParser(
91 description="Generate scientific schematics using AI with smart iterative refinement",
92 formatter_class=argparse.RawDescriptionHelpFormatter,
93 epilog="""
94How it works:
95 Simply describe your diagram in natural language
96 Nano Banana 2 generates it automatically with:
97 - Smart iteration (only regenerates if quality is below threshold)
98 - Quality review by Gemini 3.7 Flash
99 - Document-type aware quality thresholds
100 - PNG draft for visual and scientific verification
102Document Types (quality thresholds):
103 journal 8.5/10 - Nature, Science, peer-reviewed journals
104 conference 8.0/10 - Conference papers
105 thesis 8.0/10 - Dissertations, theses
106 grant 8.0/10 - Grant proposals
107 preprint 7.5/10 - arXiv, bioRxiv, etc.
108 report 7.5/10 - Technical reports
109 poster 7.0/10 - Academic posters
110 presentation 6.5/10 - Slides, talks
111 default 7.5/10 - General purpose
113Examples:
114 # Generate for journal paper (strict quality)
115 python generate_schematic.py "CONSORT participant flow" -o flowchart.png --doc-type journal
117 # Generate for poster (moderate quality)
118 python generate_schematic.py "Transformer architecture" -o arch.png --doc-type poster
120 # Generate for slides (faster, lower threshold)
121 python generate_schematic.py "System diagram" -o system.png --doc-type presentation
123 # Custom max iterations
124 python generate_schematic.py "Complex pathway" -o pathway.png --iterations 2
126 # Verbose output
127 python generate_schematic.py "Circuit diagram" -o circuit.png -v
129Environment Variables:
130 OPENROUTER_API_KEY Required for AI generation
131 """
132 )
134 parser.add_argument("prompt",
135 help="Description of the diagram to generate")
136 parser.add_argument("-o", "--output", required=True,
137 help="Output PNG file path (.png required)")
138 parser.add_argument("--doc-type", default="default",
139 choices=["journal", "conference", "poster", "presentation",
140 "report", "grant", "thesis", "preprint", "default"],
141 help="Document type for quality threshold (default: default)")
142 parser.add_argument("--iterations", type=int, default=2,
143 help="Maximum refinement iterations (default: 2, max: 2)")
144 parser.add_argument("--api-key",
145 help="OpenRouter API key (or use OPENROUTER_API_KEY env var)")
146 parser.add_argument("-v", "--verbose", action="store_true",
147 help="Verbose output")
149 args = parser.parse_args()
151 # Validated here rather than clamped silently, and before the credential
152 # lookup so an out-of-range value reports itself rather than an absent key.
153 if not 1 <= args.iterations <= 2:
154 parser.error("--iterations must be 1 or 2")
156 if Path(args.output).suffix.lower() != ".png":
157 parser.error("--output must end in .png; format conversion is not supported")
159 # Check for API key — resolves --api-key, the environment, then any .env file
160 api_key = resolve_api_key(args.api_key)
161 if not api_key:
162 print("Error: OPENROUTER_API_KEY not found")
163 print("\nFor AI generation, you need an OpenRouter API key.")
164 print("Get one at: https://openrouter.ai/keys")
165 print("\nSet it with:")
166 print(" export OPENROUTER_API_KEY='your_api_key'")
167 print("\nOr add OPENROUTER_API_KEY=your_api_key to a .env file")
168 print("Or use --api-key flag")
169 sys.exit(1)
171 # Find AI generation script
172 script_dir = Path(__file__).parent
173 ai_script = script_dir / "generate_schematic_ai.py"
175 if not ai_script.exists():
176 print(f"Error: AI generation script not found: {ai_script}")
177 sys.exit(1)
179 # Build command
180 cmd = [sys.executable, str(ai_script), args.prompt, "-o", args.output]
182 if args.doc_type != "default":
183 cmd.extend(["--doc-type", args.doc_type])
185 cmd.extend(["--iterations", str(args.iterations)])
187 if args.verbose:
188 cmd.append("-v")
190 # Execute — pass API key via environment to avoid exposure in process listings
191 try:
192 result = subprocess.run(cmd, check=False, env=build_subprocess_env(api_key))
193 sys.exit(result.returncode)
194 except Exception as e:
195 print(f"Error executing AI generation: {e}")
196 sys.exit(1)
199if __name__ == "__main__":
200 main()