File size: 7,230 Bytes
3692b0f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
import os
import gradio as gr
from dotenv import load_dotenv

from crewai import Agent, Task, Crew

# Firecrawl tool (from crewai tools package)
from crewai_tools import FirecrawlSearchTool


# -----------------------------
# Load environment variables
# -----------------------------
load_dotenv()  # reads local .env (HF Spaces uses Secrets as env vars)

OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "").strip()
FIRECRAWL_API_KEY = os.getenv("FIRECRAWL_API_KEY", "").strip()


def _validate_env():
    missing = []
    if not OPENAI_API_KEY:
        missing.append("OPENAI_API_KEY")
    if not FIRECRAWL_API_KEY:
        missing.append("FIRECRAWL_API_KEY")
    if missing:
        return (
            "❌ Missing environment variables: "
            + ", ".join(missing)
            + "\n\n"
            "On Hugging Face Spaces:\n"
            "Space → Settings → Secrets → add them as:\n"
            "- OPENAI_API_KEY\n"
            "- FIRECRAWL_API_KEY\n"
        )
    return None


# -----------------------------
# Build CrewAI setup
# -----------------------------
def build_crew():
    """

    Builds tools, agents, tasks, and the crew.

    """
    # Tool
    travel_search_tool = FirecrawlSearchTool(api_key=FIRECRAWL_API_KEY)

    # Agents
    flights_agent = Agent(
        role="Flight Search Specialist",
        goal="Find round-trip flight options that balance price, duration, and convenience.",
        backstory="Expert in comparing flights across airlines, booking sites, and schedules.",
        tools=[travel_search_tool],
        allow_delegation=False,
    )

    hotels_agent = Agent(
        role="Hotel Research Specialist",
        goal="Find good hotel options near destination city center, balancing price, reviews, and amenities.",
        backstory="Knows how to compare hotels on different sites and summarize top picks.",
        tools=[travel_search_tool],
        allow_delegation=False,
    )

    info_agent = Agent(
        role="Destination Info Specialist",
        goal="Collect useful information about attractions, safety tips, and transport options in the destination.",
        backstory="Experienced in giving local insights to travelers, focusing on practical tips.",
        tools=[travel_search_tool],
        allow_delegation=False,
    )

    consultant_agent = Agent(
        role="Travel Consultant",
        goal="Summarize all findings (flights, hotels, destination info) into a final travel plan.",
        backstory="Expert travel planner who creates easy-to-follow itineraries.",
        allow_delegation=False,
    )

    # Tasks
    search_flights = Task(
        description=(
            "Search for round-trip flights from {origin} to {destination}, departing around {departure_date} "
            "and returning around {return_date}, within budget {budget}."
        ),
        expected_output="""

Top 3 round-trip flight options:

1) Airline/Provider: ..., Route: ..., Depart/Arrive: ..., Return: ..., Total duration: ..., Stops: ..., Price: ...

2) ...

3) ...

""",
        agent=flights_agent,
    )

    search_hotels = Task(
        description=(
            "Find 3-4 hotel options in {destination}, near city center, within nightly budget {hotel_budget}. "
            "Include hotel name, location, rating, and price per night."
        ),
        expected_output="""

Top hotel options:

1) Name: ..., Area: ..., Rating: ..., Price/night: ..., Why it’s good: ...

2) ...

3) ...

4) ...

""",
        agent=hotels_agent,
    )

    get_destination_info = Task(
        description=(
            "Gather key travel info for {destination}: top attractions, safety advice, and transport options "
            "from airport to city center."
        ),
        expected_output="""

Destination info:

- Attractions: ...

- Safety: ...

- Transport (airport -> city): ...

- Local tips: ...

""",
        agent=info_agent,
    )

    create_summary = Task(
        description="Summarize the results from flights, hotels, and destination info into a structured final travel plan.",
        expected_output="""

Final Travel Plan:



✈️ Flights:

- ...



🏨 Hotels:

- ...



📍 Destination Tips:

- ...

""",
        agent=consultant_agent,
    )

    crew = Crew(
        agents=[flights_agent, hotels_agent, info_agent, consultant_agent],
        tasks=[search_flights, search_hotels, get_destination_info, create_summary],
        verbose=True,
    )

    return crew


def run_travel_planner(origin, destination, departure_date, return_date, trip_budget, hotel_budget):
    env_error = _validate_env()
    if env_error:
        return env_error

    # Some light cleanup
    origin = (origin or "").strip()
    destination = (destination or "").strip()
    departure_date = (departure_date or "").strip()
    return_date = (return_date or "").strip()
    trip_budget = (trip_budget or "").strip()
    hotel_budget = (hotel_budget or "").strip()

    if not all([origin, destination, departure_date, return_date, trip_budget, hotel_budget]):
        return "❗ Please fill in all fields before running."

    try:
        crew = build_crew()
        result = crew.kickoff(
            inputs={
                "origin": origin,
                "destination": destination,
                "departure_date": departure_date,
                "return_date": return_date,
                "budget": trip_budget,
                "hotel_budget": hotel_budget,
            }
        )
        # CrewAI may return a string or richer object; stringify safely
        return str(result)

    except Exception as e:
        return f"❌ Error while running the crew:\n{type(e).__name__}: {e}"


# -----------------------------
# Gradio UI
# -----------------------------
with gr.Blocks(title="CrewAI Multi-Agent Travel Planner") as demo:
    gr.Markdown(
        "# ✈️🏨 CrewAI Multi-Agent Travel Planner\n"
        "Enter your trip details and run the multi-agent workflow (Flights + Hotels + Destination Info → Final Plan)."
    )

    with gr.Row():
        origin = gr.Textbox(label="Origin", value="Singapore")
        destination = gr.Textbox(label="Destination", value="Tokyo")

    with gr.Row():
        departure_date = gr.Textbox(label="Departure Date", value="Mar 15th, 2026")
        return_date = gr.Textbox(label="Return Date", value="Mar 30th, 2026")

    with gr.Row():
        trip_budget = gr.Textbox(label="Trip Budget (total flights budget)", value="$2000")
        hotel_budget = gr.Textbox(label="Hotel Budget (per night)", value="$150")

    run_btn = gr.Button("Run Multi-Agent Planner", variant="primary")
    output = gr.Textbox(label="Result", lines=22)

    run_btn.click(
        fn=run_travel_planner,
        inputs=[origin, destination, departure_date, return_date, trip_budget, hotel_budget],
        outputs=[output],
    )

    gr.Markdown(
        "### 🔐 Secrets needed on Hugging Face\n"
        "- `OPENAI_API_KEY`\n"
        "- `FIRECRAWL_API_KEY`\n"
    )

if __name__ == "__main__":
    demo.launch()