Course ES
← back to chapter

Prompt template

Paste a raw, half-formed change description. Get a release note back in the

Showcase — Prompt template

Paste a raw, half-formed change description. Get a release note back in the same three sections every time: Summary, Impact, Action. The template is baked into the prompt, so the structure is something you can count on instead of something you hope the model remembers.

Run

bash bootstrap-secrets.sh              # reads ../../../../.env, writes secrets/
docker compose up --build              # default: PROVIDER=openai

Open http://localhost:3000.

To run against Gemini instead:

PROVIDER=gemini docker compose up --build

What's where

  • backend/ai_openai.py — the TEMPLATE string (the lesson) + the OpenAI call
  • backend/ai_gemini.py — same template, Gemini call
  • backend/main.py — identical FastAPI loader; reads PROVIDER and dispatches
  • frontend/app/page.tsx — textarea + result
  • docker-compose.yml — two services, secrets mounted from ./secrets/

The input is the raw change description, passed straight through as the single string the def run(input: str) -> str contract expects.

Stop

docker compose down

Run locally

Download the project as a ZIP and run it with Docker. Brings up a FastAPI backend + Next.js frontend on localhost:3000.

Download prompt-template.zip

unzip prompt-template.zip
cd prompt-template
bash bootstrap-secrets.sh   # one-time: pulls API keys into ./secrets
docker compose up --build   # default provider: openai
# or:  PROVIDER=gemini docker compose up --build

Type some input, pick a provider, and run the same code shown in Source against the live API. Sign-in required.


  

The same modules the Run button hits. The whole project (frontend, Dockerfile, compose) is in the ZIP under README.

backend/ai_openai.py

"""Week 2 - Showcase 3 (OpenAI): a fixed template pins the output shape.

Drop a raw, messy change description in; get a release note back in the
same three sections every time. The template lives in the prompt, so the
structure is a property of the prompt, not something you hope the model
remembers. Plain def run(input: str) -> str — the input is the raw text.
"""
from openai import OpenAI

_client = OpenAI()

# The template is the lesson. The model fills the slots; it does not get to
# redesign the document. Same input shape in, same three headings out.
TEMPLATE = """\
Rewrite the change description below as a release note. Use exactly this
template, keep the three headings verbatim, and fill each with one line:

Summary: <what changed, in plain language>
Impact: <who is affected and how>
Action: <what the reader should do, or "None" if nothing>

Return only the filled template. Do not add sections or commentary.

Change description:
{text}"""


def run(text: str) -> str:
    prompt = TEMPLATE.format(text=text.strip())
    response = _client.responses.create(
        model="gpt-5.4-nano", input=prompt, max_output_tokens=300,
    )
    return response.output_text

backend/ai_gemini.py

"""Week 2 - Showcase 3 (Gemini): a fixed template pins the output shape."""
import os

from google import genai
from google.genai import types

_client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])

TEMPLATE = """\
Rewrite the change description below as a release note. Use exactly this
template, keep the three headings verbatim, and fill each with one line:

Summary: <what changed, in plain language>
Impact: <who is affected and how>
Action: <what the reader should do, or "None" if nothing>

Return only the filled template. Do not add sections or commentary.

Change description:
{text}"""


def run(text: str) -> str:
    prompt = TEMPLATE.format(text=text.strip())
    response = _client.models.generate_content(
        model="gemini-3.1-flash-lite",
        contents=prompt,
        config=types.GenerateContentConfig(max_output_tokens=300),
    )
    return response.text

Project files

  • .gitignore
  • README.md
  • backend/Dockerfile
  • backend/ai_gemini.py
  • backend/ai_openai.py
  • backend/main.py
  • backend/requirements.txt
  • bootstrap-secrets.sh
  • docker-compose.yml
  • frontend/Dockerfile
  • frontend/app/layout.tsx
  • frontend/app/page.tsx
  • frontend/next.config.ts
  • frontend/package.json
  • frontend/tsconfig.json