Spaces:
Runtime error
Runtime error
| import streamlit as st | |
| import os | |
| import hashlib | |
| from transformers import AutoTokenizer, AutoModelForSeq2SeqLM | |
| import torch | |
| from upload_to_s3 import upload_file_to_s3 | |
| from notify_slack import send_slack_alert | |
| # Load model | |
| model_path = "Tuathe/codementor-flan-watchtower" | |
| tokenizer = AutoTokenizer.from_pretrained(model_path) | |
| model = AutoModelForSeq2SeqLM.from_pretrained(model_path) | |
| # Secrets from Hugging Face Spaces | |
| aws_key = st.secrets["AWS_ACCESS_KEY_ID"] | |
| aws_secret = st.secrets["AWS_SECRET_ACCESS_KEY"] | |
| aws_region = st.secrets["AWS_REGION"] | |
| bucket_name = st.secrets["S3_BUCKET_NAME"] | |
| slack_url = st.secrets["SLACK_WEBHOOK_URL"] | |
| # Fallback classifier | |
| def fallback_label(log): | |
| log_lower = log.lower() | |
| if "login" in log_lower and "failed" in log_lower: | |
| return "SECURITY" | |
| elif "error" in log_lower or "failed" in log_lower: | |
| return "ERROR" | |
| elif "timeout" in log_lower or "not responding" in log_lower: | |
| return "CRITICAL" | |
| elif "cpu" in log_lower or "memory" in log_lower: | |
| return "WARNING" | |
| else: | |
| return "INFO" | |
| # Classifier | |
| def classify_log(log): | |
| prompt = f"""Classify this log message as one of: INFO, WARNING, ERROR, CRITICAL, SECURITY. | |
| Log: {log} | |
| Label:""" | |
| inputs = tokenizer(prompt, return_tensors="pt", truncation=True) | |
| with torch.no_grad(): | |
| outputs = model.generate(**inputs, max_new_tokens=3) | |
| prediction = tokenizer.decode(outputs[0], skip_special_tokens=True).strip().upper() | |
| valid_labels = {"INFO", "WARNING", "ERROR", "CRITICAL", "SECURITY"} | |
| return prediction if prediction in valid_labels else fallback_label(log), ("Model" if prediction in valid_labels else "Fallback") | |
| # Runbook generator | |
| def generate_runbook(log_text, label): | |
| prompt = f""" | |
| You are an expert SRE. Create a step-by-step runbook in markdown format for the following {label} log. | |
| Log message: "{log_text}" | |
| Include: | |
| 1. Summary | |
| 2. Possible causes | |
| 3. Troubleshooting steps | |
| 4. Mitigation actions | |
| 5. Responsible team or escalation | |
| Only output valid markdown text. | |
| """ | |
| inputs = tokenizer(prompt, return_tensors="pt", truncation=True) | |
| with torch.no_grad(): | |
| outputs = model.generate(**inputs, max_new_tokens=300) | |
| runbook_text = tokenizer.decode(outputs[0], skip_special_tokens=True).strip() | |
| hash_id = hashlib.md5(log_text.encode()).hexdigest()[:8] | |
| runbook_path = f"runbooks/runbook_{hash_id}.md" | |
| os.makedirs("runbooks", exist_ok=True) | |
| with open(runbook_path, "w", encoding="utf-8") as f: | |
| f.write(runbook_text) | |
| return runbook_path, runbook_text | |
| # Streamlit UI | |
| st.set_page_config(page_title="WatchTowerAI", layout="centered") | |
| st.title(" WatchTowerAI - Log Classification + Runbook Generator") | |
| log_input = st.text_input(" Enter a log message") | |
| uploaded_file = st.file_uploader(" Or upload a .log file", type=["txt", "log"]) | |
| if st.button(" Classify + Generate Runbook"): | |
| logs = [] | |
| if log_input: | |
| logs.append(log_input.strip()) | |
| if uploaded_file: | |
| content = uploaded_file.read().decode("utf-8") | |
| logs.extend([line.strip() for line in content.splitlines() if line.strip()]) | |
| if not logs: | |
| st.warning("Please enter a log or upload a file.") | |
| else: | |
| for log in logs: | |
| with st.spinner(f"Processing: {log}"): | |
| label, source = classify_log(log) | |
| st.markdown(f"**Classification:** `{label}` via `{source}`") | |
| st.markdown(f"**Log:** {log}") | |
| if label in {"CRITICAL", "SECURITY"}: | |
| runbook_path, runbook_md = generate_runbook(log, label) | |
| s3_path = runbook_path.replace("\\", "/") | |
| success = upload_file_to_s3(runbook_path, bucket_name, s3_path, aws_key, aws_secret, aws_region) | |
| if success: | |
| s3_url = f"https://{bucket_name}.s3.{aws_region}.amazonaws.com/{s3_path}" | |
| send_slack_alert(log, s3_url) | |
| st.success(" Slack alert sent.") | |
| st.markdown(f"[ View Runbook on S3]({s3_url})") | |
| st.download_button(" Download Runbook", runbook_md, file_name=os.path.basename(runbook_path)) | |
| else: | |
| st.error(" Failed to upload runbook to S3.") | |
| else: | |
| st.info(" No runbook generated for this log.") | |