Add AI documentary photo gallery — 13 Gemini-generated images
Gallery page with: - 13 photorealistic documentary photos matching Lolo field photo DNA - Pillar-based filtering (Water/Food/Livelihoods/Education) - Lightbox with keyboard navigation - Masonry-style grid layout - All images optimized to JPG (~130KB each, 1.7MB total) Images: fish ponds aerial, borehole water, fish harvest, solar panels, classroom, market, sunset water tank, pond construction, woman carrying water, community meeting, hands with seedling, catfish basin, camp overview
This commit is contained in:
@@ -0,0 +1,298 @@
|
||||
"""
|
||||
Taawunu Gallery — AI Documentary Photography Generator
|
||||
Uses Gemini 2.0 Flash to generate photorealistic documentary images
|
||||
matching the exact visual DNA of Lolo Camp field photography.
|
||||
|
||||
Visual DNA (from 20+ analyzed field photos):
|
||||
- SOIL: Deep red-orange laterite (#8B4513 to #6B3A2A), freshly turned earth, mounds
|
||||
- VEGETATION: Lush saturated tropical green, cassava plants, savanna grass,
|
||||
scattered deciduous trees (some bare trunks), banana/plantain, dense forest backdrop
|
||||
- SKY: Often overcast/hazy milky white-blue, sometimes dramatic cumulus, warm light
|
||||
- PEOPLE: Hi-vis safety vests (yellow-green UDES, green HFA), traditional West African
|
||||
boubous (brown/purple/cream), taqiyah/embroidered caps, straw hats, women in colorful
|
||||
wraps, children in bright everyday clothes
|
||||
- STRUCTURES: Open-sided shelters, corrugated metal roofs, yellow-painted concrete pillars
|
||||
- CAMERA: Smartphone quality, natural light, candid/documentary, slight noise/compression
|
||||
- ATMOSPHERE: Humid, tropical, warm tones, no harsh flash, overcast soft light
|
||||
"""
|
||||
|
||||
import os, sys, json, base64, time, urllib.request, urllib.error
|
||||
|
||||
API_KEY = os.environ.get("GEMINI_API_KEY", "")
|
||||
if not API_KEY:
|
||||
try:
|
||||
API_KEY = open("../.env").read().split("GEMINI_API_KEY=")[1].split("\n")[0].strip()
|
||||
except:
|
||||
print("ERROR: Set GEMINI_API_KEY"); sys.exit(1)
|
||||
OUTPUT_DIR = "taawunu-site/html/images/gallery"
|
||||
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||
|
||||
# The visual DNA preamble that goes into every prompt
|
||||
VISUAL_DNA = """Photorealistic documentary photograph shot on a smartphone camera in rural
|
||||
Cameroon, Adamawa Region. The setting is a refugee camp community development project.
|
||||
The earth is deep red-orange laterite soil. Vegetation is lush tropical green — cassava
|
||||
plants, savanna grass, scattered deciduous trees with some bare trunks, banana plants,
|
||||
dense forest in the background. Sky is overcast and hazy with milky white-blue tones,
|
||||
creating soft diffused natural light with no harsh shadows. The atmosphere is warm and
|
||||
humid. The image has the quality of a smartphone photo — slight noise, natural compression,
|
||||
no professional lighting or staging. Candid documentary style, not posed. No text, logos,
|
||||
watermarks, or overlays in the image."""
|
||||
|
||||
# Each image: (filename, specific_prompt, aspect)
|
||||
GALLERY = [
|
||||
(
|
||||
"fish-ponds-aerial",
|
||||
f"""{VISUAL_DNA} Wide overhead view looking down at a series of large rectangular
|
||||
earthen fish ponds carved into the red laterite soil, arranged in two rows of five.
|
||||
The ponds are filled with murky brown-green water. Between the ponds are narrow earthen
|
||||
walkways of red soil. Surrounding the pond complex is cleared farmland transitioning to
|
||||
dense tropical bush and forest. A few people in yellow hi-vis safety vests walk along the
|
||||
embankments inspecting the ponds. The scale is impressive — each pond is roughly 10 meters
|
||||
by 15 meters. Shot from a slight elevation, perhaps from a nearby hill, looking down at
|
||||
the entire fish farm layout. Late afternoon warm light.""",
|
||||
"landscape"
|
||||
),
|
||||
(
|
||||
"borehole-water-flowing",
|
||||
f"""{VISUAL_DNA} Close-up to medium shot of a solar-powered borehole water system
|
||||
in action. A thick black polyethylene pipe emerges from a concrete wellhead, with clear
|
||||
water gushing forcefully from the pipe into a blue plastic collection tank. In the
|
||||
background, an elevated metal water storage tank (dark green, cylindrical, ~5000 liters)
|
||||
sits on a simple metal frame tower about 4 meters high. Two small solar panels on a metal
|
||||
frame are visible nearby, tilted toward the sky. The ground is red laterite earth. A woman
|
||||
in a colorful blue patterned wrap skirt and headscarf stands nearby watching the water flow,
|
||||
holding a yellow jerry can. The scene conveys abundance — clean water flowing freely in a
|
||||
place that previously had none.""",
|
||||
"landscape"
|
||||
),
|
||||
(
|
||||
"fish-harvest-community",
|
||||
f"""{VISUAL_DNA} A vibrant community fish harvest scene at an earthen pond. Several
|
||||
men stand knee-deep in the murky brown water of a drained fish pond, using large fishing
|
||||
nets to scoop out catfish. The catfish are large, dark grey, glistening. On the
|
||||
embankment above the pond, women and children watch and help sort fish into large plastic
|
||||
basins and metal bowls. People wear a mix of traditional clothing — men in rolled-up
|
||||
boubous and some in hi-vis vests, women in colorful wraps. The mood is joyful and
|
||||
energetic — this is the first harvest, a celebration. The red earth of the embankment
|
||||
contrasts with the brown water. Green vegetation and trees in the background. Overcast
|
||||
sky with warm light filtering through. Multiple people, candid action, authentic movement
|
||||
and expressions of accomplishment.""",
|
||||
"landscape"
|
||||
),
|
||||
(
|
||||
"solar-panels-installation",
|
||||
f"""{VISUAL_DNA} Two men installing solar panels on a simple metal frame structure
|
||||
in the middle of cleared red laterite farmland. One man stands on a small wooden ladder
|
||||
holding a solar panel while another supports it from below. They wear yellow-green hi-vis
|
||||
safety vests over traditional clothing. The solar panel array is modest — three panels on
|
||||
an angled metal frame. Thick cables run down from the panels toward a battery box on the
|
||||
ground. Behind them, the landscape shows cleared farmland transitioning to tropical bush
|
||||
with cassava plants and scattered trees. Overcast sky. The image captures the moment of
|
||||
construction — real work being done, not polished corporate solar installation.""",
|
||||
"landscape"
|
||||
),
|
||||
(
|
||||
"children-classroom-light",
|
||||
f"""{VISUAL_DNA} Interior of a simple community classroom. Children aged 6-12 sit
|
||||
on rough wooden benches at basic wooden desks. The room has a corrugated metal roof,
|
||||
unpainted concrete block walls, and a dirt floor. Natural light streams through open
|
||||
window spaces (no glass — just rectangular openings in the wall). A single solar-powered
|
||||
LED light hangs from the ceiling beam, casting white light. A teacher — a woman in a long
|
||||
dress and headscarf — stands at the front near a small blackboard. Some children have
|
||||
exercise books, others have traditional wooden writing boards (alluha). The children wear
|
||||
bright colored everyday clothes. The feeling is hopeful — basic but functional. Through
|
||||
the windows you can see red earth and green vegetation outside.""",
|
||||
"landscape"
|
||||
),
|
||||
(
|
||||
"market-fish-sales",
|
||||
f"""{VISUAL_DNA} A local market scene in rural Cameroon. A woman sits behind a
|
||||
large metal basin filled with fresh catfish on a wooden table. The fish are large, silvery-dark,
|
||||
stacked in the basin. Behind her, other market vendors sell vegetables and goods under
|
||||
simple wooden structures with tarpaulin shade. Customers — men in traditional robes and
|
||||
women with colorful headscarves — browse and negotiate. The ground is packed red-brown
|
||||
earth. The market has an authentic, bustling feel — not staged. Some plastic bags, a
|
||||
weighing scale, stacks of local currency. The warm overcast light creates even illumination
|
||||
across the scene. The fish are the centerpiece — this is the economic engine of the project,
|
||||
the transformation from aid dependency to self-sufficiency made visible.""",
|
||||
"landscape"
|
||||
),
|
||||
(
|
||||
"water-tank-sunset",
|
||||
f"""{VISUAL_DNA} Golden hour photograph of a cylindrical elevated water storage tank
|
||||
silhouetted against a dramatic warm sunset sky. The tank sits on a metal frame tower about
|
||||
5 meters high. Below it, a black water pipe descends to ground level where it connects to
|
||||
a distribution point — a simple concrete tap stand. The sun is low on the horizon, casting
|
||||
long shadows across the red laterite ground. The sky transitions from deep orange near the
|
||||
horizon through golden amber to blue-grey above. Silhouettes of tropical trees (scattered
|
||||
deciduous with bare branches) frame the scene. A few small figures walk in the distance
|
||||
on a dirt path, carrying jerry cans. The image conveys permanence — this infrastructure
|
||||
will be here long after the project team has gone home. Beautiful, contemplative, editorial.""",
|
||||
"landscape"
|
||||
),
|
||||
(
|
||||
"pond-construction-workers",
|
||||
f"""{VISUAL_DNA} Wide documentary shot of community members constructing a fish pond.
|
||||
Six or seven people dig with hand hoes and shovels, carving a large rectangular hole in the
|
||||
red laterite earth. The pond is half-dug — about 1.5 meters deep — with steep red earth
|
||||
walls visible. Mounds of excavated red soil line the edges. Workers include men in
|
||||
traditional boubous with rolled-up sleeves, wearing yellow-green hi-vis safety vests, and
|
||||
women in colorful wrap skirts and headscarves also digging. Everyone is working — no one
|
||||
is watching. The scale of manual labor is evident. In the background, other completed ponds
|
||||
are visible as rectangular depressions. Green tropical vegetation borders the work site.
|
||||
Overcast humid sky. Sweat-stained clothes, real effort, authentic construction in progress.""",
|
||||
"landscape"
|
||||
),
|
||||
(
|
||||
"woman-carrying-water",
|
||||
f"""{VISUAL_DNA} A young African woman walks along a narrow red laterite path between
|
||||
lush green vegetation, carrying a yellow jerry can of water on her head with one hand
|
||||
steadying it. She wears a bright purple patterned wrap and a matching headscarf. Her
|
||||
expression is calm and purposeful. Behind her on the path, a child in a blue shirt follows
|
||||
carrying a smaller container. The path leads toward a cluster of simple structures —
|
||||
corrugated roofs visible through the trees. The vegetation on either side is thick — tall
|
||||
grass, cassava plants, small trees. The morning light is soft and warm, filtering through
|
||||
thin overcast clouds. The image captures everyday life and resilience — the dignity of
|
||||
routine. Documentary style, not posed, shot from slightly ahead on the path as they walk
|
||||
toward the camera.""",
|
||||
"portrait"
|
||||
),
|
||||
(
|
||||
"community-meeting-shelter",
|
||||
f"""{VISUAL_DNA} A community meeting under a large open-sided shelter with a
|
||||
corrugated metal roof supported by yellow-painted concrete pillars. About 30 people sit
|
||||
on mats and plastic chairs in a circle on the packed red earth floor. Community elders
|
||||
in traditional robes sit at the front. Some people wear hi-vis safety vests. Women sit
|
||||
together on one side in colorful clothing. A man stands addressing the group, gesturing
|
||||
with his hands toward a simple whiteboard or paper chart. The mood is serious and engaged —
|
||||
this is decision-making, not ceremony. Through the open sides of the shelter you can see
|
||||
the camp — simple structures, red paths, green trees, overcast sky. Notebooks, water
|
||||
bottles, and a few mobile phones visible. The image captures community governance and
|
||||
collective agency — people making decisions about their own future.""",
|
||||
"landscape"
|
||||
),
|
||||
(
|
||||
"hands-soil-seedling",
|
||||
f"""{VISUAL_DNA} Extreme close-up of two dark-skinned weathered hands cupping a
|
||||
small amount of rich red-brown laterite soil with a tiny green seedling emerging from it.
|
||||
The hands are strong, calloused, the hands of someone who works the earth. The soil is
|
||||
moist and red, with fine roots visible. The background is softly blurred — a suggestion
|
||||
of red earth field and green vegetation. Warm natural light from the side creates gentle
|
||||
shadows in the creases of the palms. A few drops of water glisten on the soil. The image
|
||||
is symbolic without being sentimental — these are working hands holding real earth with a
|
||||
real plant. Shot in macro/close-up mode on a smartphone. The depth of field is shallow,
|
||||
focusing entirely on the hands and seedling. This is the core metaphor: from the ground up.""",
|
||||
"square"
|
||||
),
|
||||
(
|
||||
"catfish-closeup-basin",
|
||||
f"""{VISUAL_DNA} Close-up overhead photograph of freshly harvested catfish packed in
|
||||
a large round metal basin. The catfish are large (30-40cm), dark grey-brown with whiskers,
|
||||
glistening wet. There are perhaps 20-30 fish packed tightly. Water pools at the bottom of
|
||||
the basin. Around the edges of the frame, the red laterite ground is visible. A hand —
|
||||
dark-skinned, wearing a rubber glove — reaches in to sort the fish. The image is detailed
|
||||
and visceral — you can see the texture of the fish skin, the whiskers, the sheen. Shot
|
||||
from directly above looking down into the basin. Natural daylight. This image proves the
|
||||
model works — these fish are real, they grew in the ponds, and they're about to be sold.""",
|
||||
"square"
|
||||
),
|
||||
(
|
||||
"drone-camp-overview",
|
||||
f"""{VISUAL_DNA} Wide landscape photograph from elevated vantage point showing the
|
||||
layout of a refugee camp community in rural Cameroon. In the foreground, a series of
|
||||
rectangular fish ponds filled with water are carved into the red earth. Beyond the ponds,
|
||||
simple rectangular structures with corrugated metal roofs — homes and community buildings —
|
||||
are scattered along red dirt paths. Tropical trees and vegetation surround everything. In
|
||||
the distance, rolling green hills meet an overcast hazy sky. A few figures are visible —
|
||||
tiny, going about daily life. The solar panel array is visible as a small reflective
|
||||
rectangle near the ponds. The elevated water tank is visible as a small structure on stilts.
|
||||
The image captures the full ecosystem: water infrastructure, fish ponds, community,
|
||||
all interconnected. Beautiful, expansive, showing scale and context.""",
|
||||
"landscape"
|
||||
),
|
||||
]
|
||||
|
||||
def generate_image(prompt, filename, aspect="landscape"):
|
||||
"""Generate an image using Gemini 2.0 Flash with image generation."""
|
||||
|
||||
url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp-image-generation:generateContent?key={API_KEY}"
|
||||
|
||||
# Gemini image generation payload
|
||||
payload = {
|
||||
"contents": [{
|
||||
"parts": [{
|
||||
"text": f"Generate a photorealistic image: {prompt}"
|
||||
}]
|
||||
}],
|
||||
"generationConfig": {
|
||||
"responseModalities": ["TEXT", "IMAGE"]
|
||||
}
|
||||
}
|
||||
|
||||
data = json.dumps(payload).encode('utf-8')
|
||||
req = urllib.request.Request(url, data=data, headers={
|
||||
"Content-Type": "application/json"
|
||||
})
|
||||
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=120) as resp:
|
||||
result = json.loads(resp.read().decode('utf-8'))
|
||||
|
||||
# Extract image from response
|
||||
candidates = result.get("candidates", [])
|
||||
for candidate in candidates:
|
||||
parts = candidate.get("content", {}).get("parts", [])
|
||||
for part in parts:
|
||||
if "inlineData" in part:
|
||||
img_data = part["inlineData"]["data"]
|
||||
mime = part["inlineData"].get("mimeType", "image/png")
|
||||
ext = "png" if "png" in mime else "jpg"
|
||||
|
||||
filepath = os.path.join(OUTPUT_DIR, f"{filename}.{ext}")
|
||||
with open(filepath, "wb") as f:
|
||||
f.write(base64.b64decode(img_data))
|
||||
|
||||
size_kb = os.path.getsize(filepath) // 1024
|
||||
print(f" OK {filename}.{ext} ({size_kb}KB)")
|
||||
return filepath
|
||||
|
||||
# If no image in response, check for text response
|
||||
for candidate in candidates:
|
||||
parts = candidate.get("content", {}).get("parts", [])
|
||||
for part in parts:
|
||||
if "text" in part:
|
||||
print(f" TEXT response for {filename}: {part['text'][:200]}")
|
||||
|
||||
print(f" FAIL {filename} — no image in response")
|
||||
return None
|
||||
|
||||
except urllib.error.HTTPError as e:
|
||||
body = e.read().decode('utf-8')
|
||||
print(f" ERR {filename} — HTTP {e.code}: {body[:300]}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f" ERR {filename} — {str(e)[:200]}")
|
||||
return None
|
||||
|
||||
# Generate all images
|
||||
print(f"Generating {len(GALLERY)} documentary photographs...")
|
||||
print(f"Output: {OUTPUT_DIR}/")
|
||||
print()
|
||||
|
||||
results = []
|
||||
for i, (filename, prompt, aspect) in enumerate(GALLERY):
|
||||
print(f"[{i+1}/{len(GALLERY)}] {filename}...")
|
||||
result = generate_image(prompt, filename, aspect)
|
||||
results.append((filename, result))
|
||||
|
||||
# Rate limiting
|
||||
if i < len(GALLERY) - 1:
|
||||
time.sleep(3)
|
||||
|
||||
print()
|
||||
print(f"=== Results ===")
|
||||
success = sum(1 for _, r in results if r)
|
||||
print(f" Generated: {success}/{len(GALLERY)}")
|
||||
for filename, result in results:
|
||||
status = "OK" if result else "FAILED"
|
||||
print(f" {status} {filename}")
|
||||
Reference in New Issue
Block a user