File size: 2,507 Bytes
214f910
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
from __future__ import annotations

import os
from typing import List

from langchain_core.messages import HumanMessage, SystemMessage
from langchain_groq import ChatGroq

from .models import ItineraryPlan, UserRequest


def get_groq_chat() -> ChatGroq | None:
    """Return a Groq-backed chat model if GROQ_API_KEY is set, else None."""
    api_key = os.getenv("GROQ_API_KEY")
    if not api_key:
        return None
    # Deterministic, low-temperature model choice
    return ChatGroq(
        model="llama-3.1-70b-versatile",
        temperature=0.2,
        groq_api_key=api_key,
    )


def generate_narrative_logs(plan: ItineraryPlan, request: UserRequest) -> List[str]:
    """

    Use Groq (if available) to generate a concise, human-readable itinerary guide.

    Falls back to deterministic heuristic logs when GROQ_API_KEY is not set.

    """
    llm = get_groq_chat()
    if llm is None:
        logs: List[str] = []
        for stop in plan.stops:
            logs.append(
                f"Between {stop.start_time} and {stop.end_time}, enjoy {stop.attraction_name}. "
                f"Expect around {stop.estimated_wait_minutes} minutes of queuing and "
                f"approximately {stop.walking_distance_m} meters of walking from the previous stop."
            )
        return logs

    system = SystemMessage(
        content=(
            "You are Qiddiya Smart Guide, an expert theme-park planner. "
            "Given a structured itinerary, write a clear, concise, step-by-step guide. "
            "Each step should be on its own line starting with a number and a period "
            "(for example: '1. 10:00–10:30 — ...'). Focus on clarity; do not add new rides."
        )
    )
    human = HumanMessage(
        content=(
            f"Visitor date: {request.visit_date}\n"
            f"Start/end: {request.start_time}{request.end_time}\n"
            f"Must-do attractions: {', '.join(request.must_do_attractions) or 'none'}\n"
            f"Intensity: {request.intensity_preference}, walking tolerance: {request.walking_tolerance}\n\n"
            f"Itinerary stops (JSON): {plan.model_dump()['stops']}\n\n"
            "Now produce the numbered guide as described."
        )
    )
    result = llm.invoke([system, human])
    text = result.content if isinstance(result.content, str) else str(result.content)
    lines = [line.strip() for line in text.splitlines() if line.strip()]
    return lines