|
import pandas as pd |
|
import numpy as np |
|
from momentfm import MOMENTPipeline |
|
from io import StringIO |
|
|
|
|
|
model = MOMENTPipeline.from_pretrained( |
|
"AutonLab/MOMENT-1-large", |
|
model_kwargs={"task_name": "reconstruction"}, |
|
) |
|
model.init() |
|
|
|
def generate_analysis_report(data_input, sensitivity=3.0): |
|
"""Generate a comprehensive textual analysis report""" |
|
try: |
|
|
|
df = pd.read_csv(StringIO(data_input)) |
|
|
|
|
|
if 'timestamp' not in df.columns or 'value' not in df.columns: |
|
return "Error: CSV must contain 'timestamp' and 'value' columns" |
|
|
|
|
|
df['timestamp'] = pd.to_datetime(df['timestamp'], errors='coerce') |
|
df['value'] = pd.to_numeric(df['value'], errors='coerce') |
|
|
|
|
|
if df.isnull().any().any(): |
|
return "Error: Invalid data format (check timestamp/value formats)" |
|
|
|
df = df.sort_values('timestamp') |
|
|
|
|
|
values = df['value'].values.astype(np.float32).reshape(1, -1, 1) |
|
|
|
|
|
reconstructed = model.reconstruct(values) |
|
errors = np.abs(df['value'].values - reconstructed[0,:,0]) |
|
|
|
|
|
median = np.median(errors) |
|
mad = np.median(np.abs(errors - median)) |
|
threshold = median + sensitivity * (1.4826 * mad) |
|
|
|
|
|
anomalies = df[errors > threshold].copy() |
|
anomalies['anomaly_score'] = errors[errors > threshold] |
|
anomalies = anomalies.sort_values('anomaly_score', ascending=False) |
|
|
|
normal_points = df[errors <= threshold] |
|
|
|
|
|
report = f""" |
|
EQUIPMENT ANALYSIS REPORT |
|
======================== |
|
Generated at: {pd.Timestamp.now()} |
|
Detection sensitivity: {sensitivity} (z-score) |
|
|
|
DATA OVERVIEW |
|
------------- |
|
Time period: {df['timestamp'].min()} to {df['timestamp'].max()} |
|
Total observations: {len(df)} |
|
Value range: {df['value'].min():.2f} to {df['value'].max():.2f} |
|
Median value: {df['value'].median():.2f} |
|
Mean value: {df['value'].mean():.2f} |
|
|
|
ANOMALY DETECTION RESULTS |
|
------------------------- |
|
Detection threshold: {threshold:.2f} |
|
Anomalies detected: {len(anomalies)} ({len(anomalies)/len(df):.1%} of data) |
|
Strongest anomaly: {errors.max():.2f} at {df.loc[errors.argmax(), 'timestamp']} |
|
|
|
TOP ANOMALIES |
|
------------- |
|
{anomalies[['timestamp', 'value', 'anomaly_score']].head(15).to_string(index=False, float_format='%.2f')} |
|
|
|
NORMAL OPERATION SUMMARY |
|
------------------------ |
|
Typical value range: {normal_points['value'].min():.2f} to {normal_points['value'].max():.2f} |
|
Stable period duration: {pd.Timedelta(normal_points['timestamp'].max() - normal_points['timestamp'].min())} |
|
|
|
RECOMMENDATIONS |
|
--------------- |
|
1. Investigate top {min(3, len(anomalies))} anomalous readings |
|
2. Check equipment around {anomalies['timestamp'].iloc[0]} for potential issues |
|
3. Consider recalibration if anomalies cluster in specific time periods |
|
4. Review maintenance logs around detected anomalies |
|
""" |
|
return report.strip() |
|
|
|
except Exception as e: |
|
return f"ANALYSIS ERROR: {str(e)}" |
|
|
|
|
|
import gradio as gr |
|
|
|
with gr.Blocks() as demo: |
|
gr.Markdown("## π Equipment Analysis Report Generator") |
|
|
|
with gr.Row(): |
|
with gr.Column(): |
|
data_input = gr.Textbox(label="Paste CSV Data", lines=10, value="""timestamp,value |
|
2025-04-01 00:00:00,100 |
|
2025-04-01 01:00:00,102 |
|
2025-04-01 02:00:00,98 |
|
2025-04-01 03:00:00,105 |
|
2025-04-01 04:00:00,103 |
|
2025-04-01 05:00:00,107 |
|
2025-04-01 06:00:00,200 |
|
2025-04-01 07:00:00,108 |
|
2025-04-01 08:00:00,110 |
|
2025-04-01 09:00:00,98 |
|
2025-04-01 10:00:00,99 |
|
2025-04-01 11:00:00,102 |
|
2025-04-01 12:00:00,101""") |
|
sensitivity = gr.Slider(1.0, 5.0, value=3.0, label="Detection Sensitivity") |
|
submit_btn = gr.Button("Generate Report", variant="primary") |
|
|
|
with gr.Column(): |
|
report_output = gr.Textbox(label="Analysis Report", lines=20, interactive=False) |
|
|
|
submit_btn.click( |
|
generate_analysis_report, |
|
inputs=[data_input, sensitivity], |
|
outputs=report_output |
|
) |
|
|
|
if __name__ == "__main__": |
|
demo.launch(server_name="0.0.0.0", server_port=7860) |
|
|