Jompatron commited on
Commit
ff7c80c
·
1 Parent(s): e63fa6f

Add dashboard app

Browse files
Files changed (3) hide show
  1. app.py +94 -119
  2. requirements.txt +6 -0
  3. requirements.txt.txt +0 -18
app.py CHANGED
@@ -1,134 +1,109 @@
1
  import gradio as gr
2
- from transformers import pipeline
3
- import numpy as np
4
  import hopsworks
 
 
 
5
  from xgboost import XGBRegressor
6
- import joblib
7
- from openai import OpenAI
8
- from functions.llm_chain import (
9
- load_model,
10
- get_llm_chain,
11
- generate_response,
12
- generate_response_openai,
13
- )
14
- # Initialize the ASR pipeline
15
- transcriber = pipeline("automatic-speech-recognition", model="openai/whisper-base.en")
16
-
17
- def connect_to_hopsworks():
18
- # Initialize Hopsworks feature store connection
19
- project = hopsworks.login()
20
- fs = project.get_feature_store()
21
 
22
- # Retrieve the model registry
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  mr = project.get_model_registry()
24
 
25
- # Retrieve the 'air_quality_fv' feature view
26
- feature_view = fs.get_feature_view(
27
- name="air_quality_fv",
28
- version=1,
29
- )
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
- # Initialize batch scoring
32
- feature_view.init_batch_scoring(1)
33
 
34
- # Retrieve the 'air_quality_xgboost_model' from the model registry
35
- retrieved_model = mr.get_model(name="air_quality_xgboost_model", version=1)
36
 
37
- # Download the saved model artifacts to a local directory
38
- saved_model_dir = retrieved_model.download()
 
 
 
 
 
 
 
 
39
 
40
- # Load the XGBoost regressor model and label encoder from the saved model directory
41
- # model_air_quality = joblib.load(saved_model_dir + "/xgboost_regressor.pkl")
42
- # Loading the XGBoost regressor model and label encoder from the saved model directory
43
- # retrieved_xgboost_model = joblib.load(saved_model_dir + "/xgboost_regressor.pkl")
44
- model_air_quality = XGBRegressor()
45
 
46
- model_air_quality.load_model(saved_model_dir + "/model.json")
 
 
 
 
47
 
48
- return feature_view, model_air_quality
 
 
49
 
 
 
 
 
 
 
 
 
 
 
50
 
51
- def retrieve_llm_chain():
52
- model_llm, tokenizer = load_model()
53
- llm_chain = get_llm_chain(
54
- model_llm,
55
- tokenizer,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  )
57
- return model_llm, tokenizer, llm_chain
58
-
59
- # Setup the models and feature view
60
- feature_view, model_air_quality = connect_to_hopsworks()
61
-
62
- def transcribe(audio):
63
- sr, y = audio
64
- y = y.astype(np.float32)
65
- if y.ndim > 1 and y.shape[1] > 1:
66
- y = np.mean(y, axis=1)
67
- y /= np.max(np.abs(y))
68
- return transcriber({"sampling_rate": sr, "raw": y})["text"]
69
-
70
-
71
- def generate_query_response(user_query, method, openai_api_key=None):
72
- if method == 'Hermes LLM':
73
- # Load the LLM and its corresponding tokenizer and configure a language model chain
74
- model_llm, tokenizer, llm_chain = retrieve_llm_chain()
75
-
76
- response = generate_response(
77
- user_query,
78
- feature_view,
79
- model_air_quality,
80
- model_llm,
81
- tokenizer,
82
- llm_chain,
83
- verbose=False,
84
- )
85
- return response
86
-
87
- elif method == 'OpenAI API' and openai_api_key:
88
- client = OpenAI(
89
- api_key=openai_api_key
90
- )
91
-
92
- response = generate_response_openai(
93
- user_query,
94
- feature_view,
95
- model_air_quality,
96
- client,
97
- verbose=False,
98
- )
99
- return response
100
-
101
- else:
102
- return "Invalid method or missing API key."
103
-
104
-
105
- def handle_input(text_input=None, audio_input=None, method='Hermes LLM', openai_api_key=""):
106
- if audio_input is not None:
107
- user_query = transcribe(audio_input)
108
- else:
109
- user_query = text_input
110
-
111
- # Check if OpenAI API key is required but not provided
112
- if method == 'OpenAI API' and not openai_api_key.strip():
113
- return "OpenAI API key is required for this method."
114
-
115
- if user_query:
116
- return generate_query_response(user_query, method, openai_api_key)
117
- else:
118
- return "Please provide input either via text or voice."
119
-
120
- # Setting up the Gradio Interface
121
- iface = gr.Interface(
122
- fn=handle_input,
123
- inputs=[
124
- gr.Textbox(placeholder="Type here or use voice input..."),
125
- gr.Audio(),
126
- gr.Radio(["Hermes LLM", "OpenAI API"], label="Choose the response generation method"),
127
- gr.Textbox(label="Enter your OpenAI API key (only if you selected OpenAI API):", type="password") # Removed `optional=True`
128
- ],
129
- outputs="text",
130
- title="🌤️ AirQuality AI Assistant 💬",
131
- description="Ask your questions about air quality or use your voice to interact. Select the response generation method and provide an OpenAI API key if necessary."
132
- )
133
-
134
- iface.launch(share=True)
 
1
  import gradio as gr
 
 
2
  import hopsworks
3
+ import pandas as pd
4
+ import matplotlib.pyplot as plt
5
+ import os
6
  from xgboost import XGBRegressor
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
+ # IMPORTANT: HuggingFace builds need non-interactive backend
9
+ import matplotlib
10
+ matplotlib.use("Agg")
11
+
12
+ FEATURE_COLUMNS = [
13
+ "temperature_2m_mean",
14
+ "precipitation_sum",
15
+ "wind_speed_10m_max",
16
+ "wind_direction_10m_dominant"
17
+ ]
18
+
19
+ def load_resources():
20
+ """Connect to Hopsworks, load model + feature view."""
21
+ project = hopsworks.login(
22
+ api_key=os.environ["HOPSWORKS_API_KEY"],
23
+ host=os.environ["HOPSWORKS_HOST"],
24
+ )
25
+
26
+ fs = project.get_feature_store()
27
  mr = project.get_model_registry()
28
 
29
+ # Load model
30
+ model_meta = mr.get_model("air_quality_xgboost_model", version=1)
31
+ model_dir = model_meta.download()
32
+ model = XGBRegressor()
33
+ model.load_model(model_dir + "/model.json")
34
+
35
+ # Load feature view
36
+ fv = fs.get_feature_view("air_quality_fv", version=1)
37
+
38
+ return model, fv
39
+
40
+ # Load on startup
41
+ model, feature_view = load_resources()
42
+
43
+ def generate_forecast():
44
+ """Fetch latest feature data, generate PM25 forecast plot."""
45
+ df = feature_view.get_batch_data()
46
 
47
+ # Convert timestamp to datetime
48
+ df["date"] = pd.to_datetime(df["date"], unit="us")
49
 
50
+ # Predict PM2.5
51
+ df["predicted_pm25"] = model.predict(df[FEATURE_COLUMNS])
52
 
53
+ # Plot forecast
54
+ plt.figure(figsize=(10, 4))
55
+ plt.plot(df["date"], df["predicted_pm25"], marker="o")
56
+ plt.title("PM2.5 Forecast (Next Days)")
57
+ plt.xlabel("Date")
58
+ plt.ylabel("Predicted PM2.5")
59
+ plt.grid(True)
60
+ plt.tight_layout()
61
+ plt.savefig("forecast.png")
62
+ plt.close()
63
 
64
+ return "forecast.png"
 
 
 
 
65
 
66
+ def generate_hindcast():
67
+ """Generate hindcast accuracy plot (past days)."""
68
+ df = feature_view.get_batch_data()
69
+ df["date"] = pd.to_datetime(df["date"], unit="us")
70
+ df["predicted_pm25"] = model.predict(df[FEATURE_COLUMNS])
71
 
72
+ # For hindcast: show difference between predicted & actual (most recent available data)
73
+ # NOTE: Your data may not include true pm25 for recent dates;
74
+ # we'll plot model signal only.
75
 
76
+ plt.figure(figsize=(10, 4))
77
+ plt.plot(df["date"], df["predicted_pm25"], label="Predicted", marker="o")
78
+ plt.title("PM2.5 Hindcast (Recent Days)")
79
+ plt.xlabel("Date")
80
+ plt.ylabel("PM2.5")
81
+ plt.grid(True)
82
+ plt.legend()
83
+ plt.tight_layout()
84
+ plt.savefig("hindcast.png")
85
+ plt.close()
86
 
87
+ return "hindcast.png"
88
+
89
+
90
+ def run_dashboard():
91
+ forecast_img = generate_forecast()
92
+ hindcast_img = generate_hindcast()
93
+ return forecast_img, hindcast_img
94
+
95
+
96
+ with gr.Blocks() as demo:
97
+ gr.Markdown("# 🌤️ PM2.5 Air Quality Dashboard")
98
+ gr.Markdown("Powered by Hopsworks Feature Store + XGBoost Model")
99
+
100
+ btn = gr.Button("Generate Forecast")
101
+ output_forecast = gr.Image(label="Forecast (Next Days)")
102
+ output_hindcast = gr.Image(label="Hindcast (Past Days)")
103
+
104
+ btn.click(
105
+ run_dashboard,
106
+ outputs=[output_forecast, output_hindcast]
107
  )
108
+
109
+ demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ gradio
2
+ hopsworks
3
+ pandas
4
+ xgboost
5
+ matplotlib
6
+ numpy
requirements.txt.txt DELETED
@@ -1,18 +0,0 @@
1
- hopsworks[python,great-expectations]
2
- streamlit==1.28.2
3
- email-validator==2.2.0
4
- pydantic-settings>=2.6.1
5
- geopy==2.4.1
6
- openmeteo-requests
7
- requests-cache==1.2.0
8
- retry-requests==2.0.0
9
- xgboost==2.0.3
10
- scikit-learn==1.2.2
11
- matplotlib==3.8.3
12
- plotly
13
- seaborn
14
- nbformat
15
- Faker
16
- invoke
17
- python-dotenv
18
- #feldera==0.41