File size: 6,775 Bytes
3de68fd
 
 
 
 
 
 
 
721ccd8
3de68fd
 
 
 
 
 
 
721ccd8
 
 
 
 
 
 
3de68fd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
721ccd8
 
 
 
3de68fd
 
 
721ccd8
3de68fd
 
 
 
 
 
 
 
 
721ccd8
3de68fd
 
 
 
 
721ccd8
3de68fd
 
 
 
 
 
 
 
 
 
721ccd8
3de68fd
 
 
 
 
 
 
 
 
 
 
 
 
721ccd8
 
3de68fd
 
 
 
 
 
 
 
 
 
 
 
 
 
721ccd8
 
 
3de68fd
721ccd8
 
 
 
 
 
 
 
 
 
3de68fd
 
 
 
 
 
 
 
 
 
 
721ccd8
3de68fd
 
721ccd8
 
 
3de68fd
 
 
 
 
 
 
 
 
 
 
721ccd8
0d8bd51
 
 
 
 
721ccd8
 
0d8bd51
 
 
 
 
 
 
 
3de68fd
721ccd8
 
 
 
 
 
 
 
 
 
 
 
 
 
3de68fd
 
 
721ccd8
3de68fd
 
 
 
 
 
721ccd8
 
3de68fd
 
 
 
 
 
 
721ccd8
 
3de68fd
 
721ccd8
3de68fd
721ccd8
3de68fd
 
721ccd8
3de68fd
721ccd8
3de68fd
721ccd8
3de68fd
 
 
 
721ccd8
 
3de68fd
721ccd8
3de68fd
721ccd8
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
from concrete import fhe
from config import circuit_filepath, number_of_neighbors
from shapely.geometry import Point
import geopandas as gpd
import streamlit as st
import folium
from streamlit_folium import st_folium


def init_session():
    """Initialize the Streamlit session and layout configuration.

    Returns:
        Streamlit.columns: A tuple of Streamlit columns for layout customization.
    """
    st.set_page_config(layout="wide")

    if "markers" not in st.session_state:
        st.session_state["markers"] = []
    if "server_side" not in st.session_state:
        st.session_state["server_side"] = []
    if "client_side" not in st.session_state:
        st.session_state["client_side"] = []

    c1, c2, c3 = st.columns([1, 3, 1])

    return c1, c2, c3


def set_up_server():
    """Load a server instance from a specified circuit file

    Raises:
        OSError: If there is an issue loading the FHE server.

    Returns:
       concrete.fhe.compilation.server.Server: A server instance loaded from the circuit file.
    """
    try:
        server = fhe.Server.load(circuit_filepath)
    except OSError as e:
        raise OSError(
            f"Something went wrong with the circuit. Make sure that the circuit \
            exists in {circuit_filepath}.If not run python generate_circuit.py."
        ) from e

    return server


def set_up_client(serialized_client_specs):
    """Generate a client instance from a specified circuit file

    Args:
        serialized_client_specs (bytes): A serialized client specs

    Returns:
        concrete.fhe.compilation.client.Client: A client instance created from the client specs
    """

    client_specs = fhe.ClientSpecs.deserialize(serialized_client_specs)
    client = fhe.Client(client_specs)

    return client


def display_encrypted(encrypted_object):
    """Display a truncated representation of an encrypted object as a hexadecimal string

    Args:
        encrypted_object (bytes): A serialized encrypted object to display

    Returns:
        str: A truncated hexadecimal representation of the encrypted object
    """
    encoded_text = encrypted_object.hex()
    res = "..." + encoded_text[-10:]
    return res


def transform_point(longitude, latitude):
    """Transform coordinates into an integer to be processed by the FHE circuit

    Args:
        longitude (float): longitude of the point
        latitude (float): latitude of the point

    Returns:
        int, int: integers to be processed by the FHE circuit
    """
    gdf = gpd.GeoDataFrame({"geometry": [Point(longitude, latitude)]}, crs="EPSG:4326")
    gdf = gdf.to_crs("EPSG:2154")
    x, y = gdf.geometry.iloc[0].x, gdf.geometry.iloc[0].y
    x = int(x) % 10000
    y = int(y) % 10000

    return x, y


def process_result(rest, result):
    """Add the nearest restaurants in the map and in the client view

    Args:
        rest (geopandas.DataFrame): list of restaurants
        result (list[(int, int)]): list of the nearest neighbors returned by the algorithm
    """
    add_to_client_side(
        f"The {number_of_neighbors} closest restaurant to your location are:"
    )
    for index, res in enumerate(result):
        mask1 = (
            rest["geometry"]
            .to_crs("epsg:2154")
            .apply(lambda geom: int(geom.x) % 10000 == res[0])
        )
        mask2 = (
            rest["geometry"]
            .to_crs("epsg:2154")
            .apply(lambda geom: int(geom.y) % 10000 == res[1])
        )
        final_mask = mask1 & mask2
        result_df = rest[final_mask]
        restaurant_info = f"{result_df.name.iloc[0]}, {result_df.cuisine.iloc[0]}"
        add_marker(result_df.geometry, restaurant_info)
        add_to_client_side(f"{index+1}. {restaurant_info}.")


def add_marker(coordinates, name):
    """Add a marker with coordinates and a name to the Streamlit session.

    Args:
        coordinates (Point): The coordinates of the marker
        name (str): The name or label for the marker
    """
    data = {"coordinates": coordinates, "name": name}
    st.session_state["markers"].append(data)


def display_map(restaurants, returned_objects=None):
    """Display the map with nodes and optional markers and paths.

    Args:
        nodes (geopandas.DataFrame): A dataframe containing the nodes to display
        returned_objects (List[str], optional): Objects to be returned when interacting with the map. Defaults to None.

    Returns:
        Streamlit.FoliumMap: An interactive map displaying nodes and markers
    """
    if "decrypted_result" in st.session_state:
        m = restaurants.explore(
            scheme="naturalbreaks",
            tooltip="name",
            popup=["name"],
            name="Quadratic-Paris",
            color="red",
            marker_kwds=dict(radius=5, fill=True, name="node_id"),
        )
    else:
        m = restaurants.explore(
            scheme="naturalbreaks",
            tooltip="name",
            popup=["name"],
            name="Quadratic-Paris",
        )

    if "position" in st.session_state:
        position = st.session_state["position"]
        folium.Marker(
            [position.y, position.x], popup="Starting point", tooltip="Starting point"
        ).add_to(m)

    if "markers" in st.session_state:
        for mrk in st.session_state["markers"]:
            folium.Marker(
                [mrk["coordinates"].y, mrk["coordinates"].x],
                popup=mrk["name"],
                tooltip=mrk["name"],
                icon=folium.Icon(color="black", icon_color="#FFFF00"),
            ).add_to(m)

    return st_folium(m, width=725, key="origin", returned_objects=returned_objects)


def add_to_server_side(message):
    """Add a message to the server side of the view

    Args:
        message (str): The message to be added to the server side
    """
    st.session_state["server_side"].append(message)


def add_to_client_side(message):
    """Add a message to the client side of the view

    Args:
        message (str): The message to be added to the client side
    """
    st.session_state["client_side"].append(message)


def display_server_side():
    """Display the messages stored in the server-side view."""
    st.write("**Server-side**")
    for message in st.session_state["server_side"]:
        st.write(message)


def display_client_side():
    """Display the messages stored in the client-side view."""
    st.write("**Client-side**")
    for message in st.session_state["client_side"]:
        st.write(message)


def restart_session():
    """Clear the session state to restart"""
    if st.button("Restart"):
        for key in st.session_state.items():
            if key[0] != "evaluation_key":
                del st.session_state[key[0]]
        st.rerun()