Spaces:
Runtime error
Runtime error
second commit
Browse files- APIs/__pycache__/geolocation.cpython-311.pyc +0 -0
- APIs/__pycache__/meteo.cpython-311.pyc +0 -0
- APIs/geolocation.py +62 -0
- APIs/meteo.py +94 -0
- app.py +32 -4
- chatbot.py +126 -0
- requirements.txt +8 -0
- utils.py +45 -0
APIs/__pycache__/geolocation.cpython-311.pyc
ADDED
Binary file (2.93 kB). View file
|
|
APIs/__pycache__/meteo.cpython-311.pyc
ADDED
Binary file (5.02 kB). View file
|
|
APIs/geolocation.py
ADDED
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import requests
|
2 |
+
import re
|
3 |
+
|
4 |
+
|
5 |
+
def get_geolocation(adresse, latitude, longitude):
|
6 |
+
"""Return latitude, longitude & code INSEE from an adress. Latitude & longitude only if they are not specified in the function.
|
7 |
+
|
8 |
+
Args:
|
9 |
+
adresse (str): Adress or city for example
|
10 |
+
|
11 |
+
Returns:
|
12 |
+
Tuple(float, float, str): latitude, longitude & code INSEE
|
13 |
+
"""
|
14 |
+
if latitude is not None and longitude is not None:
|
15 |
+
url = f"https://data.geopf.fr/geocodage/reverse?lon={longitude}&lat={latitude}&index=parcel"
|
16 |
+
else:
|
17 |
+
url = f"https://data.geopf.fr/geocodage/search?q={adresse}"
|
18 |
+
|
19 |
+
response = requests.get(url)
|
20 |
+
if response.status_code == 200:
|
21 |
+
data = response.json()["features"][0]
|
22 |
+
if 'parcel' in url:
|
23 |
+
properties = data["properties"]
|
24 |
+
code_insee = properties["departmentcode"] + \
|
25 |
+
properties["municipalitycode"]
|
26 |
+
else:
|
27 |
+
coordinates = data["geometry"]["coordinates"]
|
28 |
+
latitude, longitude = coordinates[1], coordinates[0]
|
29 |
+
code_insee = data["properties"]["citycode"]
|
30 |
+
return latitude, longitude, code_insee
|
31 |
+
return None, None, None
|
32 |
+
|
33 |
+
|
34 |
+
def get_risques(code_insee):
|
35 |
+
"""Get list of risks from a 'code INSEE'
|
36 |
+
|
37 |
+
Args:
|
38 |
+
code_insee (str): Code INSEE
|
39 |
+
|
40 |
+
Returns:
|
41 |
+
List[str]: List of risks
|
42 |
+
"""
|
43 |
+
requete = f"https://georisques.gouv.fr/api/v1/gaspar/risques?code_insee={code_insee}"
|
44 |
+
response = requests.get(requete)
|
45 |
+
if response.status_code == 200:
|
46 |
+
risques = eval(response.content.decode().replace("null", "-1"))
|
47 |
+
if risques["results"] > 0:
|
48 |
+
risques = risques["data"]
|
49 |
+
risques = [r["libelle_risque_long"]
|
50 |
+
for r in risques[0]["risques_detail"]]
|
51 |
+
else:
|
52 |
+
risques = []
|
53 |
+
else:
|
54 |
+
risques = None
|
55 |
+
return risques
|
56 |
+
|
57 |
+
|
58 |
+
if __name__ == "__main__":
|
59 |
+
lon, lat, code_insee = get_geolocation(
|
60 |
+
"6 allée de chartres 91370 Verrieres le Buisson", None, None)
|
61 |
+
|
62 |
+
print(get_risques(code_insee))
|
APIs/meteo.py
ADDED
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import openmeteo_requests
|
2 |
+
import requests_cache
|
3 |
+
import pandas as pd
|
4 |
+
from retry_requests import retry
|
5 |
+
|
6 |
+
|
7 |
+
# Setup the Open-Meteo API client with cache and retry on error
|
8 |
+
cache_session = requests_cache.CachedSession('.cache', expire_after=3600)
|
9 |
+
retry_session = retry(cache_session, retries=5, backoff_factor=0.2)
|
10 |
+
openmeteo = openmeteo_requests.Client(session=retry_session)
|
11 |
+
|
12 |
+
|
13 |
+
def get_info_meteo(latitude, longitude):
|
14 |
+
"""Function that creates a Json file containing the weather data of the location
|
15 |
+
ARGS:
|
16 |
+
latitude (Float) : latitude coordinate
|
17 |
+
longitude (Float): longitude coordinate
|
18 |
+
|
19 |
+
"""
|
20 |
+
|
21 |
+
url = "https://api.open-meteo.com/v1/forecast"
|
22 |
+
params = {
|
23 |
+
"latitude": latitude,
|
24 |
+
"longitude": longitude,
|
25 |
+
"hourly": {"relative_humidity_2m", "soil_temperature_0cm", "soil_moisture_0_to_1cm"},
|
26 |
+
"daily": {"temperature_2m_max", "precipitation_sum", "wind_speed_10m_max", "sunshine_duration"},
|
27 |
+
"past_days": 30,
|
28 |
+
"forecast_days": 7
|
29 |
+
|
30 |
+
}
|
31 |
+
|
32 |
+
responses = openmeteo.weather_api(url, params=params)
|
33 |
+
response = responses[0]
|
34 |
+
|
35 |
+
# Hourly dataframe
|
36 |
+
hourly = response.Hourly()
|
37 |
+
hourly_relative_humidity_2m = hourly.Variables(0).ValuesAsNumpy()
|
38 |
+
hourly_soil_temperature_0cm = hourly.Variables(1).ValuesAsNumpy()
|
39 |
+
hourly_soil_moisture_0_to_1cm = hourly.Variables(2).ValuesAsNumpy()
|
40 |
+
|
41 |
+
hourly_data = {"date": pd.date_range(
|
42 |
+
start=pd.to_datetime(hourly.Time(), unit="s", utc=True),
|
43 |
+
end=pd.to_datetime(hourly.TimeEnd(), unit="s", utc=True),
|
44 |
+
freq=pd.Timedelta(seconds=hourly.Interval()),
|
45 |
+
inclusive="left"
|
46 |
+
)}
|
47 |
+
|
48 |
+
hourly_data["relative_humidity_2m_%"] = hourly_relative_humidity_2m
|
49 |
+
hourly_data["soil_temperature_0cm_C"] = hourly_soil_temperature_0cm
|
50 |
+
hourly_data["soil_moisture_0_to_1cm_m³"] = hourly_soil_moisture_0_to_1cm
|
51 |
+
|
52 |
+
hourly_dataframe = pd.DataFrame(data=hourly_data)
|
53 |
+
|
54 |
+
# Average hourly data per day
|
55 |
+
hourly_dataframe['day_date'] = hourly_dataframe['date'].dt.strftime(
|
56 |
+
'%Y-%m-%d')
|
57 |
+
|
58 |
+
tmp = hourly_dataframe.groupby('day_date')[
|
59 |
+
['relative_humidity_2m_%', 'soil_temperature_0cm_C', 'soil_moisture_0_to_1cm_m³']].mean()
|
60 |
+
|
61 |
+
avg_hourly_dataframe = tmp.rename(columns={'relative_humidity_2m_%': 'avg_hourly_relative_humidity_2m_%',
|
62 |
+
'soil_temperature_0cm_C': 'avg_hourly_soil_temperature_0cm_C', 'soil_moisture_0_to_1cm_m³': 'avg_hourly_soil_moisture_0_to_1cm_m³'})
|
63 |
+
|
64 |
+
# Daily dataframe
|
65 |
+
daily = response.Daily()
|
66 |
+
daily_temperature_2m_max = daily.Variables(0).ValuesAsNumpy()
|
67 |
+
daily_precipitation_sum = daily.Variables(1).ValuesAsNumpy()
|
68 |
+
daily_wind_speed_10m_max = daily.Variables(2).ValuesAsNumpy()
|
69 |
+
daily_sunshine_duration = daily.Variables(3).ValuesAsNumpy()
|
70 |
+
|
71 |
+
daily_data = {"date": pd.date_range(
|
72 |
+
start=pd.to_datetime(daily.Time(), unit="s", utc=True),
|
73 |
+
end=pd.to_datetime(daily.TimeEnd(), unit="s", utc=True),
|
74 |
+
freq='D',
|
75 |
+
inclusive="left"
|
76 |
+
)}
|
77 |
+
|
78 |
+
daily_data["daily_temperature_2m_max_C"] = daily_temperature_2m_max
|
79 |
+
daily_data["daily_precipitation_sum_mm"] = daily_precipitation_sum
|
80 |
+
daily_data["daily_wind_speed_10m_max_km/h"] = daily_wind_speed_10m_max
|
81 |
+
daily_data["daily_sunshine_duration_sec"] = daily_sunshine_duration
|
82 |
+
|
83 |
+
daily_dataframe = pd.DataFrame(data=daily_data)
|
84 |
+
|
85 |
+
daily_dataframe['day_date'] = daily_dataframe['date'].dt.strftime(
|
86 |
+
'%Y-%m-%d')
|
87 |
+
total_df = pd.merge(daily_dataframe, avg_hourly_dataframe,
|
88 |
+
on="day_date", how="left")
|
89 |
+
|
90 |
+
total_df['date'] = total_df['day_date']
|
91 |
+
total_df = total_df.drop('day_date', axis=1)
|
92 |
+
|
93 |
+
return total_df
|
94 |
+
#total_df.to_json("app/data/weather_data.json", orient='columns')
|
app.py
CHANGED
@@ -1,7 +1,35 @@
|
|
1 |
import gradio as gr
|
|
|
2 |
|
3 |
-
|
4 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
|
6 |
-
|
7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
import gradio as gr
|
2 |
+
from utils import *
|
3 |
|
4 |
+
with gr.Blocks() as demo:
|
5 |
+
with gr.Row():
|
6 |
+
with gr.Column():
|
7 |
+
lat = gr.Number(value=48.832408, label="Latitude",
|
8 |
+
info="La latitude de votre élevage")
|
9 |
+
lon = gr.Number(value=2.28619, label="Longitude",
|
10 |
+
info="La longitude de votre élevage")
|
11 |
+
address = gr.Textbox(
|
12 |
+
label="Address",
|
13 |
+
info="Dans le cas ou vous ne connaissez pas vos coordonnées GPS, rentrez votre adresse !")
|
14 |
+
with gr.Column():
|
15 |
+
type_elevage = gr.CheckboxGroup(choices=[
|
16 |
+
"Bovin",
|
17 |
+
"Ovin",
|
18 |
+
"Caprin",
|
19 |
+
"Porcin",
|
20 |
+
"Volailles",
|
21 |
+
"Equin"
|
22 |
+
], label="Type d'élevage", info="Quel est votre type d'élevage?")
|
23 |
+
with gr.Column():
|
24 |
+
btn = gr.Button(value="Submit", size="sm")
|
25 |
|
26 |
+
with gr.Tab("Map"):
|
27 |
+
map = gr.HTML()
|
28 |
+
|
29 |
+
with gr.Tab("Weather data"):
|
30 |
+
fig = gr.Plot(label="Météo")
|
31 |
+
|
32 |
+
demo.load(show_map, [lat, lon, address], [map, fig])
|
33 |
+
btn.click(show_map, [lat, lon, address], [map, fig])
|
34 |
+
|
35 |
+
demo.launch()
|
chatbot.py
ADDED
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import gradio as gr
|
3 |
+
|
4 |
+
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
|
5 |
+
|
6 |
+
from llama_index.readers.web import SimpleWebPageReader
|
7 |
+
|
8 |
+
from llama_index.llms.mistralai import MistralAI
|
9 |
+
from llama_index.embeddings.mistralai import MistralAIEmbedding
|
10 |
+
|
11 |
+
from llama_index.core import Settings
|
12 |
+
from llama_index.core.query_engine import RetrieverQueryEngine
|
13 |
+
|
14 |
+
from dotenv import load_dotenv
|
15 |
+
|
16 |
+
def print_conversation(chat_history):
|
17 |
+
"""
|
18 |
+
Fonction de vérification.
|
19 |
+
|
20 |
+
Args:
|
21 |
+
chat_history (List[List[str]]): historique d'échanges avec le chatbot
|
22 |
+
"""
|
23 |
+
for question, response in chat_history:
|
24 |
+
print('Question :', end = '\n')
|
25 |
+
print(question, end = '\n')
|
26 |
+
print('Response :', end = '\n')
|
27 |
+
print(response, end = '\n\n')
|
28 |
+
|
29 |
+
def main(
|
30 |
+
query_engine,
|
31 |
+
elevage,
|
32 |
+
temperature,
|
33 |
+
humidite,
|
34 |
+
meteo
|
35 |
+
):
|
36 |
+
"""
|
37 |
+
Fonction qui crée le bloc du chatbot avec gradio.
|
38 |
+
Couplage entre le
|
39 |
+
|
40 |
+
Args:
|
41 |
+
query_engine (_type_): index de recherche vectorielle.
|
42 |
+
elevage (str):
|
43 |
+
temperature (str):
|
44 |
+
humidite (str):
|
45 |
+
meteo (str):
|
46 |
+
|
47 |
+
Returns:
|
48 |
+
None
|
49 |
+
"""
|
50 |
+
|
51 |
+
title = "Gaia Mistral Chat RAG URL Demo"
|
52 |
+
description = "Example of an assistant with Gradio, RAG from url and Mistral AI via its API"
|
53 |
+
placeholder = "Vous pouvez me posez une question sur ce contexte, appuyer sur Entrée pour valider"
|
54 |
+
|
55 |
+
with gr.Blocks() as demo:
|
56 |
+
|
57 |
+
chatbot = gr.Chatbot()
|
58 |
+
msg = gr.Textbox(placeholder = placeholder)
|
59 |
+
clear = gr.ClearButton([msg, chatbot])
|
60 |
+
|
61 |
+
def respond(message, chat_history):
|
62 |
+
|
63 |
+
global_message = f"""
|
64 |
+
Tu es un chatbot qui réponds en français, commence et qui dois aider à déterminer les risques parasitaires d'élevage en fonction des conditions météo, voici les conditions météo :
|
65 |
+
|
66 |
+
- élevage : {elevage}
|
67 |
+
- température moyenne : {temperature}
|
68 |
+
- humidité moyenne : {humidite}
|
69 |
+
- météo : {meteo}
|
70 |
+
|
71 |
+
{message}
|
72 |
+
|
73 |
+
Donne-moi ensuite les solutions de prévention et de traitement pour chacun d'eux indépendamment du tableau.
|
74 |
+
Tu dois impérativement répondre en français.
|
75 |
+
"""
|
76 |
+
|
77 |
+
response = query_engine.query(global_message)
|
78 |
+
chat_history.append((message, str(response)))
|
79 |
+
|
80 |
+
print_conversation(chat_history)
|
81 |
+
return '', chat_history
|
82 |
+
|
83 |
+
msg.submit(respond, [msg, chatbot], [msg, chatbot])
|
84 |
+
|
85 |
+
demo.title = title
|
86 |
+
demo.launch()
|
87 |
+
|
88 |
+
if __name__ == "__main__":
|
89 |
+
|
90 |
+
#### Loading de la clef Mistral
|
91 |
+
load_dotenv()
|
92 |
+
env_api_key = os.getenv('MISTRAL_API_KEY')
|
93 |
+
|
94 |
+
### Type du modèle
|
95 |
+
llm_model = 'mistral-small-2312'
|
96 |
+
|
97 |
+
### Config modèle
|
98 |
+
Settings.llm = MistralAI(
|
99 |
+
max_tokens = 1024,
|
100 |
+
api_key = env_api_key
|
101 |
+
)
|
102 |
+
|
103 |
+
Settings.embed_model = MistralAIEmbedding(
|
104 |
+
model_name="mistral-embed",
|
105 |
+
api_key=env_api_key
|
106 |
+
)
|
107 |
+
|
108 |
+
### Mise en place de l'index
|
109 |
+
documents = SimpleDirectoryReader("documents").load_data()
|
110 |
+
index = VectorStoreIndex.from_documents(documents)
|
111 |
+
query_engine = index.as_query_engine(similarity_top_k=15)
|
112 |
+
|
113 |
+
### Précision du type d'élevage et des conditions météo
|
114 |
+
elevage = 'bovin'
|
115 |
+
temperature = '15°C'
|
116 |
+
humidite = '40%'
|
117 |
+
meteo = 'pluvieux'
|
118 |
+
|
119 |
+
### Lancement du Gradio
|
120 |
+
main(
|
121 |
+
query_engine,
|
122 |
+
elevage,
|
123 |
+
temperature,
|
124 |
+
humidite,
|
125 |
+
meteo
|
126 |
+
)
|
requirements.txt
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
mistralai
|
2 |
+
faiss-cpu
|
3 |
+
numpy
|
4 |
+
html2text
|
5 |
+
llama-index==0.10.10
|
6 |
+
llama-index-llms-mistralai
|
7 |
+
llama-index-embeddings-mistralai
|
8 |
+
llama-index-llms-huggingface
|
utils.py
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pandas as pd
|
2 |
+
import folium
|
3 |
+
from folium import IFrame
|
4 |
+
import plotly.graph_objects as go
|
5 |
+
from APIs.geolocation import get_geolocation, get_risques
|
6 |
+
from APIs.meteo import get_info_meteo
|
7 |
+
|
8 |
+
|
9 |
+
def get_and_plot_meteo(lat, lon):
|
10 |
+
df = get_info_meteo(lat, lon)
|
11 |
+
fig = go.Figure()
|
12 |
+
fig.add_trace(go.Scatter(x=df['date'], y=df['daily_temperature_2m_max_C'],
|
13 |
+
name="Température °C", mode="lines+markers"))
|
14 |
+
fig.add_trace(go.Scatter(x=df['date'], y=df['avg_hourly_relative_humidity_2m_%'],
|
15 |
+
name="Humidité moyenne en %", mode="lines+markers", yaxis="y2"))
|
16 |
+
fig.update_layout(
|
17 |
+
title="Température maximale et humidité moyenne journalière",
|
18 |
+
xaxis_title="Date",
|
19 |
+
yaxis_title="Température (°C)",
|
20 |
+
yaxis2=dict(
|
21 |
+
title="Humidity (%)",
|
22 |
+
overlaying="y",
|
23 |
+
side="right"
|
24 |
+
)
|
25 |
+
)
|
26 |
+
return fig
|
27 |
+
|
28 |
+
|
29 |
+
def show_map(lat, lon, address):
|
30 |
+
if address:
|
31 |
+
lat_tmp, lon_tmp, code_insee = get_geolocation(address, None, None)
|
32 |
+
risques = get_risques(code_insee=code_insee)
|
33 |
+
if lat_tmp or lon_tmp:
|
34 |
+
lat, lon = lat_tmp, lon_tmp
|
35 |
+
else:
|
36 |
+
return "Adress not found. Please enter a valid address", ""
|
37 |
+
if lat and lon:
|
38 |
+
lat_tmp, lon_tmp, code_insee = get_geolocation(None, lat, lon)
|
39 |
+
risques = get_risques(code_insee=code_insee)
|
40 |
+
# Create a map centered at the input coordinates
|
41 |
+
location_map = folium.Map(location=[lat, lon], zoom_start=14)
|
42 |
+
folium.Marker([lat, lon], popup=risques).add_to(location_map)
|
43 |
+
map_html = location_map._repr_html_()
|
44 |
+
fig = get_and_plot_meteo(lat, lon)
|
45 |
+
return map_html, fig
|