Copied to Clipboard
text'])
for chunk_idx, chunk in enumerate(chunks):
if len(chunk.strip()) < 10:
continue
chunk_id = hashlib.md5(
f"{filename}_{page['page_num']}_{chunk_idx}".encode()
).hexdigest()
self.collection.add(
ids=[chunk_id],
documents=[chunk],
metadatas=[{
"source": filename,
"page_num": page['page_num'],
"chunk_idx": chunk_idx,
"full_path": page['path'],
"ingested_at": datetime.now().isoformat()
}]
)
added_count += 1
return {
"status": "success",
"filename": filename,
"pages": len(pages),
"chunks_added": added_count
}
This snippet shows part of the Climate Library viewer logic, including the local PDF worker and the in-memory PDF cache used to keep the viewer responsive.
pdfjs.GlobalWorkerOptions.workerSrc = `${process.env.PUBLIC_URL || ""}/pdf.worker.min.js`;
type CachedPdf = {
blob: Blob;
objectUrl: string;
totalPages: number;
pageTextByPage: Record<number, string>;
pdfDocument: any;
};
const pdfCacheRef = useRef<Map<string, CachedPdf>>(new Map());
const getPdfCacheKey = useCallback((file: File) => {
return normalizePdfName(file.name);
}, []);
This snippet shows the default Teach-In Facilitator brief and how the experience starts with a strong session setup instead of a blank form.
export const DEFAULT_TEACH_IN_BRIEF: TeachInBrief = {
sessionTitle: "Neighborhood Clean Energy Teach-In",
audience:
"High-school students, parents, and community volunteers curious about practical local climate action",
venueContext:
"Public library community room with projector and open discussion seating",
duration: "45 minutes",
goals:
"Help attendees understand clean energy in everyday life, connect it to climate justice, and leave with two realistic actions they can take this month.",
focusAreas:
"Renewable energy basics, energy bills, climate justice, neighborhood resilience, community action",
materials:
"Projector, whiteboard, local utility bill example, sticky notes, Earth Day handout, signup sheet",
};
How I Built It
I built the product around a three step model: study, structure, and facilitate.
For the study layer, the main focus was grounding. Climate material is often long, technical, and dense, so I did not want a system that simply accepted a PDF and then answered in a vague way. When a user uploads a document into Climate Library, the backend stores the file, extracts the text, splits it into chunks, creates embeddings, and stores them in ChromaDB. When the user asks a question, the backend retrieves the most relevant chunks and passes them into the model as context. That creates a proper retrieval augmented generation flow instead of a general chat flow. It also allows the app to support citations, page navigation, and highlighted source jumps back into the document.
That source connection was important to me because climate literacy is not only about getting an answer. It is about trusting where the answer came from. If someone is preparing an Earth Day session, a school lesson, or a community discussion, they need to be able to go back to the original material and verify what they are using.
For the structure layer, I wanted to go beyond a single generated course outline. That is why Teach-In Builder creates both a pathway and a mind map. Those two views do slightly different jobs. The pathway helps the user think in sequence, while the mind map helps the user think in connections. Once a module is opened, the system expands it into Guide, Practice Lab, and Field Media so the topic becomes something a person can actually work through and teach from. This part of the build was about making generated content feel usable, not just impressive.
For the facilitate layer, I adapted the live assistant flow into a planning companion for real Earth Day events. The user starts with a structured brief, then moves into a live Gemini session where the focus is on audience fit, session flow, materials, and next steps. Function calling is used to turn that planning flow into a structured output with learning objectives, agenda, materials, and community actions. I wanted this to feel like an event planning tool, not a generic live chat demo.
Gemini is the key technology across the whole project. I used it for live voice interaction, multimodal context, structured teach-in planning, and document assistance when paired with retrieval. In Climate Library, Gemini helps turn indexed PDFs into an interactive learning experience. In Teach-In Builder, it supports turning broad topics into structured educational pathways. In Teach-In Facilitator, it helps shape a real Earth Day session that can actually be delivered to an audience.
The shared live control tray also became a meaningful part of the product. The microphone supports a more natural planning and exploration flow. Screen share makes the assistant useful for real materials, not just typed prompts. Webcam adds live visual context to the session. Together, those controls make the app feel more like a working multimodal study and facilitation environment.
I also spent time on the interface direction because I did not want the project to feel like a generic AI dashboard. I moved away from a loud or overly synthetic look and shaped it into something more like an editorial field guide for climate learning. The goal was to make the experience feel grounded, readable, and specific to Earth Day rather than looking like a general purpose AI tool with green branding.
The biggest thing I learned while building this was that climate education is a strong and practical Earth Day direction. Many projects in this space focus only on tracking or visualization. Those are useful, but I wanted to build around the human part of environmental action: understanding the material, organizing it, and helping other people learn from it. That is where I think this project is strongest.
Prize Categories
I am submitting this project for Best Use of Google Gemini.
Gemini is central to the project, not an extra layer added on top. It powers the live voice interaction, the multimodal reasoning over shared visual context, the structured teach-in planning flow, and the grounded assistance in the document workflow when combined with retrieval.
This is a solo submission.