File size: 5,916 Bytes
f51e2d4
 
 
 
 
 
f8fce5b
f51e2d4
f2ab51b
f51e2d4
95eac8e
 
 
8cccf60
f51e2d4
 
f2ab51b
 
 
f51e2d4
 
b70216b
f51e2d4
 
 
 
 
 
 
8ef2488
 
1365a32
b70216b
1365a32
 
 
f51e2d4
 
 
8ef2488
f51e2d4
 
 
 
 
 
 
 
 
1365a32
 
 
 
 
f51e2d4
 
f2ab51b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f51e2d4
f2ab51b
 
 
 
 
 
 
 
 
 
 
 
 
f51e2d4
 
 
d53ded5
f51e2d4
6d70bb2
f51e2d4
 
 
f2ab51b
 
f51e2d4
 
 
 
 
6d70bb2
 
 
4444725
f51e2d4
4444725
 
f51e2d4
 
4444725
 
f51e2d4
 
4444725
 
 
f51e2d4
 
4444725
 
 
f51e2d4
4444725
6208e81
f51e2d4
b584653
f2ab51b
f51e2d4
f2ab51b
00bf345
f2ab51b
4444725
f51e2d4
 
 
b0734c4
f51e2d4
 
 
 
 
 
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
from huggingface_hub import InferenceClient
import json
import folium
from gradio_folium import Folium
import gradio as gr
from geopy.geocoders import Nominatim
from geopy.adapters import AioHTTPAdapter
import os
from urllib.parse import quote

from dotenv import load_dotenv
load_dotenv()

repo_id = "mistralai/Mistral-7B-Instruct-v0.2"
llm_client = InferenceClient(model=repo_id, timeout=180, token=os.getenv("HF_TOKEN"))

repo_id = "dslim/bert-base-NER"
NER_client = InferenceClient(model=repo_id, timeout=180, token=os.getenv("HF_TOKEN"))

def show_map(places_list):
    
    geolocator = Nominatim(user_agent="HF_smart-travel-planner") #, adapter_factory=AioHTTPAdapter)

    i = 0
    for place in places_list:
        city = place['city']
        attraction = place['attraction']
        desc = place['description']

        google_link = f"<a href='https://www.google.com/search?q={attraction}, {city}' target='_blank'><b>Learn more</b></a>"
        
        try:
            locate = geolocator.geocode(f"{attraction}, {city}", timeout=10)
        except:
            locate = None
            
        if locate is not None:
            if i == 0:
                mymap = folium.Map(location=[locate.latitude, locate.longitude], zoom_start=10)
            folium.Marker(location=[locate.latitude, locate.longitude], popup=folium.Popup(f"{attraction}: {desc} \n {google_link}", max_width=200)).add_to(mymap)
            i += 1

    return mymap


def parse_output(output):
    
    itinerary = "Itinerary" + output.split("Key points:")[0].split('Itinerary:')[1]
    key_points = output.split("Key points:")[1].strip()
    try:
        itinerary_list = json.loads(key_points)
    except:
        itinerary_list = []
        
    return itinerary, itinerary_list

def process_itinerary(itinerary, places_list):
    places = NER_client.token_classification(itinerary)
    locs = [place for place in places if place.get('entity_group') == 'LOC']
    unique_words = set()
    locs = [d for d in locs if d.get('word') not in unique_words and (unique_words.add(d.get('word')) or True)]

    words = [loc['word'] for loc in locs]
    cities = find_cities_by_attraction(places_list, words)
    
    links = [f"[{loc['word']}](https://www.google.com/search?q={quote(loc['word'])},{quote(cities[i])})" for i,loc in enumerate(locs)]

    itin_copy = itinerary

    for word, link in zip(words, links):
        itin_copy = itin_copy.replace(word, link, 1)  # Replace only the first occurrence

    return itin_copy

def find_cities_by_attraction(places, words):
    matched_cities = []
    for word in words:
        Found = False
        for place in places:
            if word.lower() in place['attraction'].lower() and not Found:  # Case insensitive match
                matched_cities.append(place['city'])
                Found = True
                
        if not Found:
            matched_cities.append(places[0]['city'].split(',')[1])
    return matched_cities
    
def run_program(place, duration, start, end):
    
    prompt = f"""Please generate a list of key cities and attractions in each cities for the following place: {place} suitable for {duration}, starting from {start} and ending at {end}, as a json list of less than 10 dictionaries with the following keys: 'city', 'attraction' and 'description'.
ALWAYS write the city and country in the 'city'. For instance do not only "city": "Paris" as the city but "city": "Paris, France". Don't combine multiplpe locations in one element. In the 'description', write the main attractions in that city as well.
Try to minimize the distance between locations. Always think of the transportation means that you want to use, and the timing: morning, afternoon, where to sleep.
Strictly generate two sections: 'Itinerary:' provides a descriptive day-wise explanation of the itinerary formatted with bullet points, then you list the locations in 'Key points:'"""

    response = llm_client.text_generation(prompt, max_new_tokens=3000) #, max_new_tokens=2000, stream=True)
    itinerary, places_list = parse_output(response)
    itinerary = process_itinerary(itinerary, places_list)
    
    mymap = show_map(places_list)

    return itinerary, mymap


with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.green,secondary_hue=gr.themes.colors.blue)) as demo:
    
    gr.Markdown("# ✈️ Smart Travel Planner 🗺️\nThis personal travel planner is based on Mistral-7B-Instruct-v0.2, called through the Hugging Face API. Describe your destination, duration, starting and ending points of your trip. The AI assistant will suggest you an itinerary for the trip! \n Beware that the model does not have access to train or plane schedules, it is relying on general world knowledge!")
                
    dest = gr.Textbox(
        label="Destination",
        placeholder="Destination, Eg. Bavaria, Germany"
    )
    dur = gr.Textbox(
        label="Duration",
        placeholder="Duration of your trip. Eg. 3 days"
    )
    start = gr.Textbox(
        label="Starting location",
        value="anywhere",
        placeholder="Starting location of your trip. Type 'anywhere' if you don't have a place in mind"
    )
    end = gr.Textbox(
        label="Ending location",
        value="anywhere",
        placeholder="Ending location of your trip. Type 'anywhere' if you don't have a place in mind"
    )
    
    button = gr.Button("Generate itinerary!")

    gr.Markdown("### Itinerary")
    
    itinery, starting_map = run_program(dest, dur, start, end)
    
    itinerary = gr.Markdown(itinery)
    
    gr.Markdown("_Click the markers on the map to display information about the places._")
    # Get initial map
    map = Folium(value=starting_map, height=600, label="Chosen locations")

 
    # Dynamics
    button.click(run_program, inputs=[dest, dur, start, end], outputs=[itinerary, map])


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