Invicto69 commited on
Commit
b8f45a1
·
verified ·
1 Parent(s): fa995d8

chore: Initial commit

Browse files
Files changed (5) hide show
  1. .python-version +1 -0
  2. Dockerfile +13 -0
  3. app.py +157 -0
  4. pyproject.toml +9 -0
  5. uv.lock +0 -0
.python-version ADDED
@@ -0,0 +1 @@
 
 
1
+ 3.12
Dockerfile ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.12-slim
2
+
3
+ WORKDIR /app
4
+ RUN pip install --no-cache-dir uv
5
+
6
+ COPY pyproject.toml .
7
+ RUN uv sync
8
+
9
+ COPY . .
10
+
11
+ EXPOSE 8505
12
+
13
+ CMD ["uv", "run", "streamlit", "run", "app.py", "--server.port", "8505"]
app.py ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import urllib.request
3
+ import urllib.error
4
+ import xml.etree.ElementTree as ET
5
+ from datetime import datetime, timedelta
6
+ import re
7
+ import time
8
+ import hashlib
9
+
10
+ # Page config
11
+ st.set_page_config(page_title="OpenAI Status Tracker", layout="wide")
12
+
13
+ # Persistent state management
14
+ if 'etag' not in st.session_state:
15
+ st.session_state.etag = None
16
+ if 'last_modified' not in st.session_state:
17
+ st.session_state.last_modified = None
18
+ if 'last_hash' not in st.session_state:
19
+ st.session_state.last_hash = None
20
+ if 'events' not in st.session_state:
21
+ st.session_state.events = []
22
+
23
+ def parse_rss_to_events(xml_data):
24
+ events = []
25
+ try:
26
+ root = ET.fromstring(xml_data)
27
+ items = list(root.findall('./channel/item'))
28
+ items.reverse()
29
+
30
+ for item in items:
31
+ title = item.find('title').text or "No Title"
32
+ pub_date_str = item.find('pubDate').text or ""
33
+ description = item.find('description').text or ""
34
+
35
+ try:
36
+ dt = datetime.strptime(pub_date_str, "%a, %d %b %Y %H:%M:%S %Z")
37
+ timestamp_str = dt.strftime("%Y-%m-%d %H:%M:%S")
38
+ except ValueError:
39
+ dt = datetime.now()
40
+ timestamp_str = pub_date_str
41
+
42
+ components = re.findall(r"<li>(.*?)</li>", description)
43
+ if components:
44
+ clean_components = [c.replace(" (Operational)", "").strip() for c in components]
45
+ product = "OpenAI - " + ", ".join(clean_components)
46
+ else:
47
+ product = "OpenAI API (General)"
48
+
49
+ status_match = re.search(r"<b>Status:\s*(.*?)</b>", description)
50
+ status_val = status_match.group(1) if status_match else "Update"
51
+
52
+ events.append({
53
+ "dt": dt,
54
+ "timestamp_str": timestamp_str,
55
+ "product": product,
56
+ "status_message": f"[{status_val}] {title}"
57
+ })
58
+ except ET.ParseError:
59
+ pass
60
+ return events
61
+
62
+ def fetch_feed_with_etag(url):
63
+ """Fetches feed using ETag/Last-Modified and falls back to SHA-256 hashing."""
64
+ req = urllib.request.Request(url, headers={'User-Agent': 'StatusTracker/1.0'})
65
+
66
+ if st.session_state.etag:
67
+ req.add_header('If-None-Match', st.session_state.etag)
68
+ if st.session_state.last_modified:
69
+ req.add_header('If-Modified-Since', st.session_state.last_modified)
70
+
71
+ try:
72
+ with urllib.request.urlopen(req) as response:
73
+ st.session_state.etag = response.headers.get('ETag')
74
+ st.session_state.last_modified = response.headers.get('Last-Modified')
75
+
76
+ xml_data = response.read()
77
+
78
+ # Client-Side Hash Check
79
+ current_hash = hashlib.sha256(xml_data).hexdigest()
80
+ if current_hash == st.session_state.last_hash:
81
+ return False, "304 Proxy (Hash Match)"
82
+
83
+ st.session_state.last_hash = current_hash
84
+ st.session_state.events = parse_rss_to_events(xml_data)
85
+ return True, "200 OK (New Data)"
86
+
87
+ except urllib.error.HTTPError as e:
88
+ if e.code == 304:
89
+ return False, "304 Not Modified (Server)"
90
+ except Exception:
91
+ pass
92
+ return False, "Checking..."
93
+
94
+ def main():
95
+ st.title("OpenAI Status Tracker")
96
+
97
+ feed_url = "https://status.openai.com/feed.rss"
98
+ is_new_data, status_reason = fetch_feed_with_etag(feed_url)
99
+
100
+ # Use a fixed reference time for the slider so it doesn't shift while you're sliding
101
+ if 'reference_time' not in st.session_state:
102
+ st.session_state.reference_time = datetime.now()
103
+
104
+ events = st.session_state.events
105
+
106
+ col1, col2 = st.columns([1, 2])
107
+ with col1:
108
+ mode = st.radio("Select Mode:", ["Live Tracking", "Time Simulator"], horizontal=True)
109
+
110
+ with col2:
111
+ if mode == "Live Tracking":
112
+ # Update reference time to 'now' constantly in live mode
113
+ st.session_state.reference_time = datetime.now()
114
+ active_time = st.session_state.reference_time
115
+ auto_refresh = st.checkbox("Enable Auto-Refresh (30s)", value=False)
116
+
117
+ if "200 OK" in status_reason:
118
+ st.success(f"{status_reason} at {active_time.strftime('%H:%M:%S')}")
119
+ else:
120
+ st.info(f"{status_reason} at {active_time.strftime('%H:%M:%S')}")
121
+ else:
122
+ auto_refresh = False
123
+ # Determine slider range based on the frozen reference time
124
+ min_time = events[0]["dt"] - timedelta(minutes=30) if events else st.session_state.reference_time - timedelta(days=1)
125
+
126
+ # Key='sim_slider' ensures the value is kept in session state between re-runs
127
+ active_time = st.slider(
128
+ "Simulate Time",
129
+ min_value=min_time,
130
+ max_value=st.session_state.reference_time,
131
+ value=st.session_state.reference_time,
132
+ format="YYYY-MM-DD HH:mm:ss",
133
+ key="sim_slider"
134
+ )
135
+ st.button("Reset to Latest", on_click=lambda: st.session_state.pop('sim_slider', None))
136
+
137
+ st.divider()
138
+ st.subheader(f"System Logs (As of {active_time.strftime('%Y-%m-%d %H:%M:%S')})")
139
+
140
+ # Filter and display
141
+ visible_events = [e for e in events if e["dt"] <= active_time]
142
+
143
+ if not visible_events:
144
+ st.info("No incidents reported prior to this time.")
145
+ else:
146
+ log_output = ""
147
+ for event in visible_events:
148
+ log_output += f"[{event['timestamp_str']}] Product: {event['product']}\n"
149
+ log_output += f"Status: {event['status_message']}\n\n"
150
+ st.code(log_output, language="text")
151
+
152
+ if mode == "Live Tracking" and auto_refresh:
153
+ time.sleep(30)
154
+ st.rerun()
155
+
156
+ if __name__ == "__main__":
157
+ main()
pyproject.toml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ [project]
2
+ name = "openai-updates"
3
+ version = "0.1.0"
4
+ description = "Add your description here"
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ dependencies = [
8
+ "streamlit>=1.54.0",
9
+ ]
uv.lock ADDED
The diff for this file is too large to render. See raw diff