"""Module to launch the application.
run: `gradio main.py` to run the application
"""
import sys
import gradio as gr
from loguru import logger
from app.service import (
analyze_trends,
connect_database,
detect_anomalies,
generate_analysis_report,
list_available_metrics,
query_timeseries,
)
logger.add(
sys.stdout,
format="{time} {message}",
filter="my_module",
level="INFO",
colorize=True,
)
example_sensor = "temperature"
example_start = "2019-06-15T02:54:00"
example_end = "2019-06-17T02:54:00"
with gr.Blocks() as demo:
gr.Markdown("# TimescaleDB Time Series Analyzer API (Gradio)")
with gr.Tab("About"):
gr.Markdown("""
# mcp-tscontext
**mcp-tscontext** is a time series analysis tool designed for use with TimescaleDB.
Its goal is to provide a textual context about time series.
The idea is to provide a tool to an Agent to make it possible to better
understand the context when a user asks a question.
Built with Gradio, provides a mcp server.
My main use Case:
- provide an assistant to operators in charge of supervising industrial systems
(like a power plant). Combine this tool with RAG on technical documentation.
Other use case ideas:
- Build a personal assistant that could be aware of health metrics provided by a
smartwatch.
## Features
- **Database Connection**: Connect to a TimescaleDB instance or use a mock SQLite database for testing.
- **List Metrics**: View all available sensor ids in the database.
- **Query Time Series**: Retrieve time series for a specific sensor and time range.
- **Anomaly Detection**: Identify anomalies in sensor data using statistical methods.
- **Trend Analysis**: Analyze trends and changes in sensor data over time.
- **Report Generation**: Generate a report with trends, anomalies, and statistics.
- **User-Friendly UI**: Interact with all features through a modern Gradio web interface.
## Usage
By default, the app uses a mock SQLite database (`mock.db`).
To connect to a real TimescaleDB instance, set the following environment variables:
- USE_MOCK_DB (set to false)
- `DB_HOST`
- `DB_PORT`
- `DB_NAME`
- `DB_USER`
- `DB_PASS`
""")
with gr.Tab("Connect DB"):
connect_btn = gr.Button("Connect to TimescaleDB")
connect_out = gr.Textbox(label="Connection Result")
connect_btn.click(
fn=connect_database, inputs=[], outputs=connect_out, show_api=False
)
with gr.Tab("List Metrics"):
list_btn = gr.Button("List Available Metrics")
list_out = gr.Textbox(label="Metrics")
list_btn.click(
fn=list_available_metrics,
inputs=[],
outputs=list_out,
)
with gr.Tab("Query Timeseries"):
sensor_id = gr.Textbox(label="Sensor ID", value=example_sensor)
start_time = gr.Textbox(label="Start Time (ISO)", value=example_start)
end_time = gr.Textbox(label="End Time (ISO)", value=example_end)
query_btn = gr.Button("Query")
query_out = gr.Textbox(label="Query Result")
query_btn.click(
fn=query_timeseries,
inputs=[sensor_id, start_time, end_time],
outputs=query_out,
)
with gr.Tab("Detect Anomalies"):
sensor_id2 = gr.Textbox(label="Sensor ID", value=example_sensor)
start_time2 = gr.Textbox(label="Start Time (ISO)", value=example_start)
end_time2 = gr.Textbox(label="End Time (ISO)", value=example_end)
algorithm = gr.Radio(
label="Algorithm",
choices=["zscore", "isolation_forest"],
value="zscore",
)
threshold = gr.Number(label="Z-Score Threshold", value=2.0)
contamination = gr.Number(
label="Isolation Forest Contamination",
value=0.1,
minimum=0.01,
maximum=0.5,
step=0.01,
)
anomaly_btn = gr.Button("Detect")
anomaly_out = gr.Textbox(label="Anomaly Result")
anomaly_btn.click(
fn=detect_anomalies,
inputs=[
sensor_id2,
start_time2,
end_time2,
threshold,
algorithm,
contamination,
],
outputs=anomaly_out,
)
with gr.Tab("Analyze Trends"):
sensor_id3 = gr.Textbox(label="Sensor ID", value=example_sensor)
start_time3 = gr.Textbox(label="Start Time (ISO)", value=example_start)
end_time3 = gr.Textbox(label="End Time (ISO)", value=example_end)
trend_btn = gr.Button("Analyze")
trend_out = gr.Textbox(label="Trend Result")
trend_btn.click(
fn=analyze_trends,
inputs=[sensor_id3, start_time3, end_time3],
outputs=trend_out,
)
with gr.Tab("Generate Report"):
sensor_id4 = gr.Textbox(label="Sensor ID", value=example_sensor)
start_time4 = gr.Textbox(label="Start Time (ISO)", value=example_start)
end_time4 = gr.Textbox(label="End Time (ISO)", value=example_end)
include_anomalies = gr.Checkbox(label="Include Anomalies", value=True)
include_trends = gr.Checkbox(label="Include Trends", value=True)
user_question = gr.Textbox(label="User Question", value="")
anomaly_algorithm = gr.Radio(
label="Anomaly Detection Algorithm",
choices=["zscore", "isolation_forest"],
value="zscore",
)
anomaly_threshold = gr.Number(label="Z-Score Threshold", value=2.0)
anomaly_contamination = gr.Number(
label="Isolation Forest Contamination",
value=0.1,
minimum=0.01,
maximum=0.5,
step=0.01,
)
report_btn = gr.Button("Generate Report")
report_out = gr.Markdown(label="Report")
report_btn.click(
fn=generate_analysis_report,
inputs=[
sensor_id4,
start_time4,
end_time4,
include_anomalies,
include_trends,
user_question,
anomaly_algorithm,
anomaly_threshold,
anomaly_contamination,
],
outputs=report_out,
)
if __name__ == "__main__":
demo.launch(mcp_server=True)