Eric Dai
commited on
Commit
·
e51b1cb
1
Parent(s):
dbef77f
Add travel mcp server and client
Browse files- README.md +96 -2
- mcp_config.json +11 -0
- requirements.txt +5 -0
- setup.sh +22 -0
- travel_mcp_client.py +50 -0
- travel_mcp_server.py +208 -0
README.md
CHANGED
|
@@ -1,2 +1,96 @@
|
|
| 1 |
-
#
|
| 2 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Travel Documentation MCP Server
|
| 2 |
+
|
| 3 |
+
> An AI-powered travel documentation assistant built with Gradio's MCP server capabilities and smolagents for the Hugging Face MCP Hackathon 2025.
|
| 4 |
+
|
| 5 |
+
## What This Project Does
|
| 6 |
+
|
| 7 |
+
This project creates an intelligent travel documentation agent that helps travelers understand what documents they need for international trips. It consists of:
|
| 8 |
+
|
| 9 |
+
1. **MCP Server** (`travel_mcp_server.py`) - A Gradio interface that exposes travel documentation analysis as an MCP tool, mocking data is used for demonstration
|
| 10 |
+
2. **MCP Client** (`travel_mcp_client.py`) - An AI agent that uses smolagents to interact with the MCP server and provide conversational assistance
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
## Technical Implementation
|
| 14 |
+
- **Gradio MCP Server**: Uses Gradio's built-in MCP server functionality
|
| 15 |
+
- **smolagents Integration**: AI agent framework for tool execution and conversation
|
| 16 |
+
- **Local LLM Support**: Uses Ollama for local AI inference
|
| 17 |
+
|
| 18 |
+
## Installation & Setup
|
| 19 |
+
|
| 20 |
+
### Prerequisites
|
| 21 |
+
- Python 3.8+
|
| 22 |
+
- Ollama (for local LLM)
|
| 23 |
+
|
| 24 |
+
### 1. Install Dependencies
|
| 25 |
+
```bash
|
| 26 |
+
pip install -r requirements.txt
|
| 27 |
+
```
|
| 28 |
+
|
| 29 |
+
### 2. Set up Ollama (for the AI agent)
|
| 30 |
+
```bash
|
| 31 |
+
# Install Ollama from https://ollama.ai
|
| 32 |
+
# Pull the required model
|
| 33 |
+
ollama pull gemma3:4b
|
| 34 |
+
```
|
| 35 |
+
|
| 36 |
+
### 3. Start the MCP Server
|
| 37 |
+
```bash
|
| 38 |
+
python travel_mcp_server.py
|
| 39 |
+
```
|
| 40 |
+
The server will start at `http://127.0.0.1:7861` with MCP endpoint at `http://127.0.0.1:7861/gradio_api/mcp/sse`
|
| 41 |
+
|
| 42 |
+
### 4. Start the AI Agent Client
|
| 43 |
+
```bash
|
| 44 |
+
python travel_mcp_client.py
|
| 45 |
+
```
|
| 46 |
+
|
| 47 |
+
## Usage
|
| 48 |
+
|
| 49 |
+
### Direct Web Interface
|
| 50 |
+
Visit `http://127.0.0.1:7861` to use the travel documentation tool directly:
|
| 51 |
+
|
| 52 |
+
**Input Parameters:**
|
| 53 |
+
- **Your Citizenship Country**: e.g., "Canada", "China", "India"
|
| 54 |
+
- **Destination Country**: e.g., "Japan", "USA", "Germany"
|
| 55 |
+
- **Trip Duration**: Number of days (1-365)
|
| 56 |
+
- **Trip Purpose**: tourism, business, study, transit, work, family visit
|
| 57 |
+
|
| 58 |
+
**Example Output:**
|
| 59 |
+
```json
|
| 60 |
+
{
|
| 61 |
+
"trip_info": {
|
| 62 |
+
"from_country": "Canada",
|
| 63 |
+
"to_country": "Japan",
|
| 64 |
+
"duration_days": 30,
|
| 65 |
+
"purpose": "Tourism"
|
| 66 |
+
},
|
| 67 |
+
"visa_requirements": {
|
| 68 |
+
"visa_required": false,
|
| 69 |
+
"max_stay": "90 days"
|
| 70 |
+
},
|
| 71 |
+
"required_documents": [
|
| 72 |
+
{
|
| 73 |
+
"document_type": "Passport",
|
| 74 |
+
"required": true,
|
| 75 |
+
"description": "Valid passport with at least 6 months validity remaining"
|
| 76 |
+
}
|
| 77 |
+
],
|
| 78 |
+
"summary": {
|
| 79 |
+
"required_count": 5,
|
| 80 |
+
"optional_count": 1,
|
| 81 |
+
"visa_needed": false
|
| 82 |
+
}
|
| 83 |
+
}
|
| 84 |
+
```
|
| 85 |
+
|
| 86 |
+
### AI Agent Chat Interface
|
| 87 |
+
Use the conversational agent for natural language queries:
|
| 88 |
+
|
| 89 |
+
**Example Conversations:**
|
| 90 |
+
```
|
| 91 |
+
User: "I'm a Canadian citizen planning to visit Japan for 2 weeks for tourism"
|
| 92 |
+
Agent: "..."
|
| 93 |
+
|
| 94 |
+
User: "What documents do I need for business travel from China to USA?"
|
| 95 |
+
Agent: "..."
|
| 96 |
+
```
|
mcp_config.json
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"servers": {
|
| 3 |
+
"travel-docs": {
|
| 4 |
+
"command": "python",
|
| 5 |
+
"args": ["travel_docs_server.py"],
|
| 6 |
+
"env": {
|
| 7 |
+
"PYTHONPATH": "."
|
| 8 |
+
}
|
| 9 |
+
}
|
| 10 |
+
}
|
| 11 |
+
}
|
requirements.txt
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
mcp
|
| 2 |
+
gradio[mcp]
|
| 3 |
+
smolagents
|
| 4 |
+
smolagents[mcp]
|
| 5 |
+
fastmcp
|
setup.sh
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
# Setup script for Travel Documentation MCP Server
|
| 3 |
+
|
| 4 |
+
echo "Setting up Travel Documentation MCP Server"
|
| 5 |
+
echo "=============================================="
|
| 6 |
+
|
| 7 |
+
# Check Python version
|
| 8 |
+
python_version=$(python3 --version 2>&1)
|
| 9 |
+
echo "Python version: $python_version"
|
| 10 |
+
|
| 11 |
+
# Install dependencies
|
| 12 |
+
echo "Installing dependencies..."
|
| 13 |
+
pip3 install -r requirements.txt
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
echo "Setup complete!"
|
| 17 |
+
echo ""
|
| 18 |
+
echo "To run the applications:"
|
| 19 |
+
echo " MCP Server: python travel_mcp_server.py"
|
| 20 |
+
echo " MCP Client with Agent: python travel_mcp_client.py"
|
| 21 |
+
echo ""
|
| 22 |
+
echo "Access the web interface at: http://127.0.0.1:7860"
|
travel_mcp_client.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
|
| 3 |
+
from smolagents import CodeAgent, tool, LiteLLMModel
|
| 4 |
+
from smolagents.mcp_client import MCPClient
|
| 5 |
+
|
| 6 |
+
@tool
|
| 7 |
+
def self_introduction() -> str:
|
| 8 |
+
"""
|
| 9 |
+
Provides information about the agent's identity and capabilities.
|
| 10 |
+
|
| 11 |
+
This tool should be triggered when the user asks questions like:
|
| 12 |
+
- "What's your name?"
|
| 13 |
+
- "Who are you?"
|
| 14 |
+
- "What can you do?"
|
| 15 |
+
- "Tell me about yourself"
|
| 16 |
+
- "What are your capabilities?"
|
| 17 |
+
- Any other introductory or identity-related queries
|
| 18 |
+
|
| 19 |
+
Returns:
|
| 20 |
+
str: A friendly introduction explaining the agent's purpose and capabilities. You are free to rewrite the introduction but need to keep the same meaning.
|
| 21 |
+
"""
|
| 22 |
+
return "Hello! I am your travel documentation Agent. I can help you find out what documetations are required for your trip, get me your original coutry, destionation country, trip duration and purpose and I can help you."
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
mcp_client = MCPClient(
|
| 26 |
+
{"url": "http://127.0.0.1:7861/gradio_api/mcp/sse"}
|
| 27 |
+
)
|
| 28 |
+
|
| 29 |
+
try:
|
| 30 |
+
tools = mcp_client.get_tools()
|
| 31 |
+
|
| 32 |
+
# for local testing
|
| 33 |
+
model = LiteLLMModel(
|
| 34 |
+
model_id="ollama_chat/gemma3:4b",
|
| 35 |
+
api_base="http://127.0.0.1:11434",
|
| 36 |
+
num_ctx=8192,
|
| 37 |
+
)
|
| 38 |
+
agent = CodeAgent(tools=[*tools], model=model)
|
| 39 |
+
|
| 40 |
+
demo = gr.ChatInterface(
|
| 41 |
+
fn=lambda message, history: str(agent.run(message)),
|
| 42 |
+
type="messages",
|
| 43 |
+
examples=["Your trip plan..."],
|
| 44 |
+
title="Travel documentation agent",
|
| 45 |
+
description="This is a simple agent that uses MCP tools to help you find out required documentations for your international trip.",
|
| 46 |
+
)
|
| 47 |
+
|
| 48 |
+
demo.launch()
|
| 49 |
+
finally:
|
| 50 |
+
mcp_client.disconnect()
|
travel_mcp_server.py
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
from typing import Dict, List, Any
|
| 3 |
+
|
| 4 |
+
class TravelDocumentationService:
|
| 5 |
+
"""Service for fetching travel documentation requirements"""
|
| 6 |
+
|
| 7 |
+
def get_visa_requirements(
|
| 8 |
+
self,
|
| 9 |
+
from_country: str,
|
| 10 |
+
to_country: str,
|
| 11 |
+
trip_duration: int = 30
|
| 12 |
+
) -> Dict[str, Any]:
|
| 13 |
+
"""Get visa requirements for travel between countries"""
|
| 14 |
+
|
| 15 |
+
# Mock data
|
| 16 |
+
visa_free_combinations = {
|
| 17 |
+
("canada", "japan"): {"visa_required": False, "max_stay": "90 days"},
|
| 18 |
+
("canada", "uk"): {"visa_required": False, "max_stay": "6 months"},
|
| 19 |
+
("canada", "usa"): {"visa_required": False, "max_stay": "6 months"},
|
| 20 |
+
("canada", "germany"): {"visa_required": False, "max_stay": "90 days"},
|
| 21 |
+
("usa", "japan"): {"visa_required": False, "max_stay": "90 days"},
|
| 22 |
+
("usa", "uk"): {"visa_required": False, "max_stay": "6 months"},
|
| 23 |
+
("usa", "germany"): {"visa_required": False, "max_stay": "90 days"},
|
| 24 |
+
("china", "japan"): {"visa_required": True, "visa_type": "Tourist Visa", "max_stay": "30 days", "processing_time": "5-7 business days", "fee": "$30 USD"},
|
| 25 |
+
("india", "japan"): {"visa_required": True, "visa_type": "Tourist Visa", "max_stay": "90 days", "processing_time": "5-10 business days", "fee": "$50 USD"},
|
| 26 |
+
("china", "usa"): {"visa_required": True, "visa_type": "B-2 Tourist Visa", "max_stay": "6 months", "processing_time": "3-5 weeks", "fee": "$160 USD"},
|
| 27 |
+
("india", "usa"): {"visa_required": True, "visa_type": "B-2 Tourist Visa", "max_stay": "6 months", "processing_time": "3-5 weeks", "fee": "$160 USD"},
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
key = (from_country.lower(), to_country.lower())
|
| 31 |
+
|
| 32 |
+
if key in visa_free_combinations:
|
| 33 |
+
return visa_free_combinations[key]
|
| 34 |
+
else:
|
| 35 |
+
return {
|
| 36 |
+
"visa_required": True,
|
| 37 |
+
"visa_type": "Tourist Visa",
|
| 38 |
+
"max_stay": "30 days",
|
| 39 |
+
"processing_time": "5-10 business days",
|
| 40 |
+
"fee": "$50-150 USD"
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
def get_document_requirements(
|
| 44 |
+
self,
|
| 45 |
+
from_country: str,
|
| 46 |
+
to_country: str,
|
| 47 |
+
trip_duration: int = 30,
|
| 48 |
+
trip_purpose: str = "tourism"
|
| 49 |
+
) -> List[Dict[str, Any]]:
|
| 50 |
+
"""Get comprehensive document requirements for travel"""
|
| 51 |
+
|
| 52 |
+
requirements = []
|
| 53 |
+
|
| 54 |
+
requirements.append({
|
| 55 |
+
"document_type": "Passport",
|
| 56 |
+
"required": True,
|
| 57 |
+
"description": "Valid passport with at least 6 months validity remaining",
|
| 58 |
+
"validity_period": "At least 6 months from travel date",
|
| 59 |
+
"additional_notes": "Must have at least 2 blank pages for stamps"
|
| 60 |
+
})
|
| 61 |
+
|
| 62 |
+
visa_info = self.get_visa_requirements(from_country, to_country, trip_duration)
|
| 63 |
+
|
| 64 |
+
if visa_info.get("visa_required", False):
|
| 65 |
+
requirements.append({
|
| 66 |
+
"document_type": "Visa",
|
| 67 |
+
"required": True,
|
| 68 |
+
"description": f"Required {visa_info.get('visa_type', 'Tourist Visa')}",
|
| 69 |
+
"processing_time": visa_info.get("processing_time", "5-10 business days"),
|
| 70 |
+
"additional_notes": f"Fee: {visa_info.get('fee', 'Varies by embassy')}"
|
| 71 |
+
})
|
| 72 |
+
|
| 73 |
+
insurance_required_countries = ["schengen", "germany", "france", "italy", "spain", "netherlands", "austria", "belgium"]
|
| 74 |
+
if to_country.lower() in insurance_required_countries:
|
| 75 |
+
requirements.append({
|
| 76 |
+
"document_type": "Travel Insurance",
|
| 77 |
+
"required": True,
|
| 78 |
+
"description": "Travel insurance with minimum €30,000 coverage",
|
| 79 |
+
"additional_notes": "Required for Schengen area countries"
|
| 80 |
+
})
|
| 81 |
+
else:
|
| 82 |
+
requirements.append({
|
| 83 |
+
"document_type": "Travel Insurance",
|
| 84 |
+
"required": False,
|
| 85 |
+
"description": "Travel insurance (highly recommended)",
|
| 86 |
+
"additional_notes": "Covers medical emergencies, trip cancellation, etc."
|
| 87 |
+
})
|
| 88 |
+
|
| 89 |
+
requirements.append({
|
| 90 |
+
"document_type": "Return/Onward Ticket",
|
| 91 |
+
"required": True,
|
| 92 |
+
"description": "Proof of return or onward travel",
|
| 93 |
+
"additional_notes": "Flight confirmation or travel itinerary"
|
| 94 |
+
})
|
| 95 |
+
|
| 96 |
+
financial_amount = "$100-150 per day" if to_country.lower() in ["japan", "switzerland", "norway"] else "$50-100 per day"
|
| 97 |
+
requirements.append({
|
| 98 |
+
"document_type": "Financial Proof",
|
| 99 |
+
"required": True,
|
| 100 |
+
"description": f"Proof of sufficient funds ({financial_amount})",
|
| 101 |
+
"additional_notes": "Bank statements, credit cards, or traveler's checks"
|
| 102 |
+
})
|
| 103 |
+
|
| 104 |
+
requirements.append({
|
| 105 |
+
"document_type": "Accommodation Proof",
|
| 106 |
+
"required": True,
|
| 107 |
+
"description": "Hotel booking or invitation letter",
|
| 108 |
+
"additional_notes": "Confirmation of where you'll be staying"
|
| 109 |
+
})
|
| 110 |
+
|
| 111 |
+
if trip_purpose.lower() == "business":
|
| 112 |
+
requirements.append({
|
| 113 |
+
"document_type": "Business Invitation Letter",
|
| 114 |
+
"required": True,
|
| 115 |
+
"description": "Letter from host company",
|
| 116 |
+
"additional_notes": "Must include company details and purpose of visit"
|
| 117 |
+
})
|
| 118 |
+
elif trip_purpose.lower() == "study":
|
| 119 |
+
requirements.append({
|
| 120 |
+
"document_type": "Student Visa/Permit",
|
| 121 |
+
"required": True,
|
| 122 |
+
"description": "Student visa or study permit",
|
| 123 |
+
"additional_notes": "Issued by educational institution"
|
| 124 |
+
})
|
| 125 |
+
requirements.append({
|
| 126 |
+
"document_type": "Acceptance Letter",
|
| 127 |
+
"required": True,
|
| 128 |
+
"description": "Letter of acceptance from educational institution",
|
| 129 |
+
"additional_notes": "Must be from recognized institution"
|
| 130 |
+
})
|
| 131 |
+
|
| 132 |
+
return requirements
|
| 133 |
+
|
| 134 |
+
travel_service = TravelDocumentationService()
|
| 135 |
+
|
| 136 |
+
def get_requirements(from_country, to_country, trip_duration, trip_purpose):
|
| 137 |
+
"""
|
| 138 |
+
Analyze the documentation requirment for user's travel plan
|
| 139 |
+
|
| 140 |
+
Args:
|
| 141 |
+
from_country (str): User's original country
|
| 142 |
+
to_country (str): The destination country that the user plans to travel to
|
| 143 |
+
trip_duration (number): The days length that the user plans to stay in the destination country
|
| 144 |
+
trip_purpose (str): The purpose of the travel, the user is go for business, tourism, study or other purposes
|
| 145 |
+
|
| 146 |
+
Returns:
|
| 147 |
+
json: Contains the comprehensive documentation requires and suggestions based on the user input
|
| 148 |
+
"""
|
| 149 |
+
try:
|
| 150 |
+
requirements = travel_service.get_document_requirements(
|
| 151 |
+
from_country, to_country, int(trip_duration), trip_purpose
|
| 152 |
+
)
|
| 153 |
+
|
| 154 |
+
visa_info = travel_service.get_visa_requirements(from_country, to_country, int(trip_duration))
|
| 155 |
+
|
| 156 |
+
required_docs = [req for req in requirements if req['required']]
|
| 157 |
+
optional_docs = [req for req in requirements if not req['required']]
|
| 158 |
+
|
| 159 |
+
result = {
|
| 160 |
+
"trip_info": {
|
| 161 |
+
"from_country": from_country.title(),
|
| 162 |
+
"to_country": to_country.title(),
|
| 163 |
+
"duration_days": int(trip_duration),
|
| 164 |
+
"purpose": trip_purpose.title()
|
| 165 |
+
},
|
| 166 |
+
"visa_requirements": {
|
| 167 |
+
"visa_required": visa_info.get("visa_required", False),
|
| 168 |
+
"visa_type": visa_info.get("visa_type"),
|
| 169 |
+
"max_stay": visa_info.get("max_stay"),
|
| 170 |
+
"processing_time": visa_info.get("processing_time"),
|
| 171 |
+
"fee": visa_info.get("fee")
|
| 172 |
+
},
|
| 173 |
+
"required_documents": required_docs,
|
| 174 |
+
"optional_documents": optional_docs,
|
| 175 |
+
"total_documents": len(requirements),
|
| 176 |
+
"summary": {
|
| 177 |
+
"required_count": len(required_docs),
|
| 178 |
+
"optional_count": len(optional_docs),
|
| 179 |
+
"visa_needed": visa_info.get("visa_required", False)
|
| 180 |
+
}
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
return result
|
| 184 |
+
|
| 185 |
+
except Exception as e:
|
| 186 |
+
return {"error": str(e)}
|
| 187 |
+
|
| 188 |
+
|
| 189 |
+
travel_demo = gr.Interface(
|
| 190 |
+
fn=get_requirements,
|
| 191 |
+
inputs=[
|
| 192 |
+
gr.Textbox(label="Your Citizenship Country", placeholder="e.g., Canada", value="Canada"),
|
| 193 |
+
gr.Textbox(label="Destination Country", placeholder="e.g., Japan", value="Japan"),
|
| 194 |
+
gr.Number(label="Trip Duration (days)", value=30, minimum=1, maximum=365),
|
| 195 |
+
gr.Dropdown(label="Trip Purpose", choices=["tourism", "business", "transit", "study", "work", "family visit"], value="tourism")
|
| 196 |
+
],
|
| 197 |
+
outputs=gr.JSON(),
|
| 198 |
+
title="Travel Documentation Requirements",
|
| 199 |
+
description="Get the comprehensive travel documentation requirements for international travel"
|
| 200 |
+
)
|
| 201 |
+
|
| 202 |
+
if __name__ == "__main__":
|
| 203 |
+
travel_demo.launch(
|
| 204 |
+
# share=True,
|
| 205 |
+
show_error=True,
|
| 206 |
+
mcp_server=True,
|
| 207 |
+
server_port=7861
|
| 208 |
+
)
|