Skip to content

ai_interpreter

Optional OpenAI-powered plain-language interpretation of any module's AnalysisOutput.

from climate_change import AIInterpreter, build_interpretation_prompt

interpreter

AI result interpretation using OpenAI GPT-4o. User supplies their own OPENAI_API_KEY — ARIN stores nothing.

AIInterpreter

AIInterpreter(api_key: str)

Stateless GPT-4o interpreter. Instantiated per request with user's API key. The key is never logged or stored beyond the request lifecycle.

Source code in ai_interpreter/interpreter.py
def __init__(self, api_key: str) -> None:
    self._client = OpenAI(api_key=api_key)

interpret

interpret(output: AnalysisOutput) -> str

Generate a one-shot interpretation of the analysis results.

Source code in ai_interpreter/interpreter.py
def interpret(self, output: AnalysisOutput) -> str:
    """Generate a one-shot interpretation of the analysis results."""
    try:
        response = self._client.chat.completions.create(
            model="gpt-4o",
            messages=[
                {
                    "role": "system",
                    "content": (
                        "You are a climate adaptation expert working for ARIN. "
                        "You interpret geospatial analysis results and provide "
                        "actionable, evidence-based recommendations."
                    ),
                },
                {"role": "user", "content": build_prompt(output)},
            ],
            temperature=0.3,
            max_tokens=900,
        )
    except OpenAIError as exc:
        raise RuntimeError(f"OpenAI interpretation failed: {exc}") from exc
    return response.choices[0].message.content or ""

chat

chat(output: AnalysisOutput, history: list[dict], user_message: str) -> str

Follow-up questions after initial interpretation.

Source code in ai_interpreter/interpreter.py
def chat(
    self,
    output: AnalysisOutput,
    history: list[dict],
    user_message: str,
) -> str:
    """Follow-up questions after initial interpretation."""
    messages = [
        {
            "role": "system",
            "content": (
                "You are a climate adaptation expert discussing analysis results "
                "from ARIN's Decision Support System. Answer questions about the "
                "results clearly and concisely. Refer back to the findings when relevant."
            ),
        },
        {"role": "user", "content": build_prompt(output)},
        {"role": "assistant", "content": "I have reviewed the analysis results."},
        *history,
        {"role": "user", "content": user_message},
    ]
    try:
        response = self._client.chat.completions.create(
            model="gpt-4o",
            messages=cast(list[ChatCompletionMessageParam], messages),
            temperature=0.4,
            max_tokens=600,
        )
    except OpenAIError as exc:
        raise RuntimeError(f"OpenAI chat failed: {exc}") from exc
    return response.choices[0].message.content or ""

build_interpretation_prompt

build_interpretation_prompt(output: AnalysisOutput) -> str

Build the module-agnostic base LLM prompt: registry description, country/ period/model context, and a raw dump of output.stats, followed by a fixed 4-section instruction (SUMMARY/KEY DRIVERS/RECOMMENDATIONS/CAVEATS). Module-specific builders (e.g. build_drought_prompt) call this first and append chart/stat detail particular to that module; build_prompt() dispatches to the right one automatically.

Source code in ai_interpreter/interpreter.py
def build_interpretation_prompt(output: AnalysisOutput) -> str:
    """
    Build the module-agnostic base LLM prompt: registry description, country/
    period/model context, and a raw dump of `output.stats`, followed by a
    fixed 4-section instruction (SUMMARY/KEY DRIVERS/RECOMMENDATIONS/CAVEATS).
    Module-specific builders (e.g. `build_drought_prompt`) call this first and
    append chart/stat detail particular to that module; `build_prompt()`
    dispatches to the right one automatically.
    """
    info = USE_CASE_REGISTRY[output.module]
    module_ctx = _MODULE_CONTEXT.get(output.module, "")
    stats_str = "\n".join(f"  {k}: {v}" for k, v in output.stats.items())

    return f"""
You are a senior climate scientist interpreting results from an AI-powered Decision
Support System developed by the Africa Research & Impact Network (ARIN).

MODULE: {info.name}
COUNTRY / REGION: {output.metadata.get("country", "unknown")}
ANALYSIS PERIOD: {output.metadata.get("start_date", "?")} to {output.metadata.get("end_date", "?")}
MODEL USED: {output.metadata.get("model", info.best_model)}

MODULE CONTEXT:
{module_ctx}

WHAT THIS TOOL DOES:
{info.description}

WHAT WAS PREDICTED: {info.dependent_variable}

KEY FINDINGS (statistical summary):
{stats_str}

Please provide ALL of the following, labelled exactly as shown:
1. SUMMARY (3-4 sentences for a non-technical policymaker)
2. KEY DRIVERS (3 bullet points on the dominant risk factors or patterns)
3. RECOMMENDATIONS (3 specific, actionable adaptation actions for the region)
4. CAVEATS (data quality issues or model limitations the user should know)

Respond in clear, professional English. Avoid jargon. Be concise.
""".strip()

build_prompt

build_prompt(output: AnalysisOutput) -> str

Return the richest prompt available for the given module.

Source code in ai_interpreter/interpreter.py
def build_prompt(output: AnalysisOutput) -> str:
    """Return the richest prompt available for the given module."""
    builder = _PROMPT_BUILDERS.get(output.module, build_interpretation_prompt)
    return builder(output)