asfag654 commited on
Commit
6253caf
·
verified ·
1 Parent(s): eafb28f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +90 -166
app.py CHANGED
@@ -1,174 +1,98 @@
1
- import logging
2
- import aiohttp
3
- import asyncio
4
  import gradio as gr
 
 
5
  from datetime import datetime
6
- import pytz
7
- import threading
8
- from typing import Dict, Tuple
9
-
10
- # 配置日志系统
11
- logging.basicConfig(
12
- level=logging.INFO,
13
- format='%(asctime)s - %(levelname)s - %(message)s',
14
- handlers=[
15
- logging.StreamHandler()
 
 
 
16
  ]
17
- )
18
- logger = logging.getLogger("URLMonitor")
19
 
20
- class URLMonitor:
21
- def __init__(self, urls: list, check_interval: int = 3600):
22
  self.urls = urls
23
- self.check_interval = check_interval
24
- self.timezone = pytz.timezone('Asia/Shanghai')
25
- self.status: Dict[str, Dict] = {url: {
26
- 'status_code': None,
27
- 'message': '等待首次检查',
28
- 'last_checked': None
29
- } for url in urls}
30
- self.lock = threading.Lock()
31
- self._running = False
32
-
33
- def get_current_time(self) -> str:
34
- """获取当前格式化时间"""
35
- return datetime.now(self.timezone).strftime('%m-%d %H:%M')
36
-
37
- async def check_single_url(self, session: aiohttp.ClientSession, url: str):
38
- """检查单个URL状态"""
 
 
 
 
 
 
 
 
39
  try:
40
- start_time = datetime.now()
41
- async with session.get(url, timeout=10) as response:
42
- status_code = response.status
43
- message = "服务正常" if status_code == 200 else f"服务异常 (HTTP {status_code})"
44
- latency = (datetime.now() - start_time).total_seconds()
45
- logger.info(f"{url} 状态: {status_code} 响应时间: {latency:.2f}s")
46
-
47
- except aiohttp.ClientError as e:
48
- status_code = None
49
- message = f"网络错误: {type(e).__name__}"
50
- logger.warning(f"{url} 网络错误: {str(e)}")
51
- except asyncio.TimeoutError:
52
- status_code = None
53
- message = "请求超时 (10秒)"
54
- logger.warning(f"{url} 请求超时")
55
- except Exception as e:
56
- status_code = None
57
- message = f"未知错误: {type(e).__name__}"
58
- logger.error(f"{url} 未知错误: {str(e)}", exc_info=True)
59
-
60
- timestamp = self.get_current_time()
61
- with self.lock:
62
- self.status[url] = {
63
- 'status_code': status_code,
64
- 'message': f"{message} - 最后检查: {timestamp}",
65
- 'last_checked': timestamp
66
- }
67
-
68
- async def run_checks(self):
69
- """执行所有URL检查"""
70
- async with aiohttp.ClientSession() as session:
71
- while self._running:
72
- tasks = [self.check_single_url(session, url) for url in self.urls]
73
- await asyncio.gather(*tasks)
74
- logger.info(f"本轮检查完成,{self.check_interval}秒后重新检查")
75
- await asyncio.sleep(self.check_interval)
76
 
77
  def start(self):
78
- """启动监控后台任务"""
79
- if not self._running:
80
- self._running = True
81
- threading.Thread(
82
- target=self._run_async_tasks,
83
- daemon=True,
84
- name="MonitorThread"
85
- ).start()
86
- logger.info("URL监控服务已启动")
87
-
88
- def stop(self):
89
- """停止监控服务"""
90
- self._running = False
91
- logger.info("URL监控服务已停止")
92
-
93
- def _run_async_tasks(self):
94
- """在新事件循环中运行异步任务"""
95
- loop = asyncio.new_event_loop()
96
- asyncio.set_event_loop(loop)
97
- loop.run_until_complete(self.run_checks())
98
-
99
- def get_status(self) -> Dict[str, str]:
100
- """获取当前状态信息"""
101
- with self.lock:
102
- return {url: info['message'] for url, info in self.status.items()}
103
-
104
-
105
- def create_gradio_interface(monitor: URLMonitor):
106
- """创建Gradio监控界面"""
107
- theme = gr.themes.Soft(
108
- primary_hue="blue",
109
- secondary_hue="gray"
110
- )
111
-
112
- with gr.Blocks(theme=theme, title="URL状态监控面板") as demo:
113
- gr.Markdown("# 🖥️ URL服务状态监控")
114
- gr.Markdown("> 实时监控多个服务的可用性状态")
115
-
116
- with gr.Row():
117
- refresh_btn = gr.Button("🔄 刷新状态", variant="primary")
118
- interval_slider = gr.Slider(
119
- minimum=60, maximum=86400, value=3600, step=300,
120
- label="检查频率 (秒)", interactive=True
121
- )
122
-
123
- status_table = gr.Dataframe(
124
- headers=["URL", "状态信息"],
125
- datatype=["str", "str"],
126
- interactive=False,
127
- label="服务状态"
128
- )
129
-
130
- # 组件交互
131
- refresh_btn.click(
132
- fn=lambda: [[url, info] for url, info in monitor.get_status().items()],
133
- outputs=status_table
134
- )
135
-
136
- interval_slider.change(
137
- fn=lambda x: setattr(monitor, "check_interval", x),
138
- inputs=interval_slider
139
- )
140
-
141
- # 初始加载数据
142
- demo.load(
143
- fn=lambda: [[url, info] for url, info in monitor.get_status().items()],
144
- outputs=status_table
145
- )
146
-
147
- return demo
148
-
149
-
150
- if __name__ == "__main__":
151
- # 配置监控URL列表
152
- monitored_urls = [
153
- 'https://asfag654-g.hf.space',
154
- 'https://asfag654-t.hf.space',
155
- 'https://imluochen-sleepy.hf.space'
156
- ]
157
-
158
- # 初始化监控器
159
- monitor = URLMonitor(monitored_urls, check_interval=3600)
160
- monitor.start()
161
-
162
- try:
163
- # 创建并启动Gradio界面
164
- interface = create_gradio_interface(monitor)
165
- interface.launch(
166
- server_name="0.0.0.0",
167
- server_port=7860,
168
- show_error=True,
169
- favicon_path="https://www.gstatic.com/devrel-devsite/prod/vc8928e4803ba00823d2deb39c327db4919db629f0ecb648b587b35b95297bc3f/tensorflow/images/favicon.png"
170
- )
171
- except KeyboardInterrupt:
172
- monitor.stop()
173
- finally:
174
- monitor.stop()
 
 
 
 
1
  import gradio as gr
2
+ import asyncio, aiohttp
3
+ import threading, logging
4
  from datetime import datetime
5
+
6
+ logging.basicConfig(level=logging.INFO)
7
+ logger = logging.getLogger(__name__)
8
+
9
+ URLS = [
10
+ 'https://asfag654-g.hf.space',
11
+ 'https://asfag654-libretranslate.hf.space',
12
+ 'https://asfag654-kk.hf.space',
13
+ 'https://asfag654-t.hf.space',
14
+ 'https://asfag654-b.hf.space',
15
+ 'https://imluochen-sleepy.hf.space',
16
+ 'https://7d820-ss.hf.space',
17
+ 'https://7d820-kk.hf.space'
18
  ]
 
 
19
 
20
+ class Monitor:
21
+ def __init__(self, urls):
22
  self.urls = urls
23
+ self.status = {url: [] for url in urls}
24
+ self.check_interval = 3600
25
+ self._stop_event = threading.Event()
26
+
27
+ def record(self, url, success):
28
+ now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
29
+ self.status[url].append((now, success))
30
+ if len(self.status[url]) > 100:
31
+ self.status[url] = self.status[url][-100:]
32
+
33
+ def get_current(self):
34
+ return [[url, *([f"{t} ✅" if s else f"{t} ❌"][-1:])] for url, logs in self.status.items() for t, s in logs[-1:]]
35
+
36
+ def get_stats(self, selected=None):
37
+ table = []
38
+ for url, logs in self.status.items():
39
+ if selected and selected not in url: continue
40
+ total = len(logs)
41
+ ok = sum(1 for _, s in logs if s)
42
+ pct = f"{ok / total:.1%}" if total else "N/A"
43
+ table.append([url, total, ok, pct])
44
+ return sorted(table, key=lambda x: -x[2])
45
+
46
+ async def check_url(self, url):
47
  try:
48
+ async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(10)) as session:
49
+ async with session.get(url):
50
+ self.record(url, True)
51
+ except:
52
+ self.record(url, False)
53
+
54
+ async def run_check(self):
55
+ await asyncio.gather(*(self.check_url(url) for url in self.urls))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
 
57
  def start(self):
58
+ def loop():
59
+ while not self._stop_event.is_set():
60
+ asyncio.run(self.run_check())
61
+ self._stop_event.wait(self.check_interval)
62
+ threading.Thread(target=loop, daemon=True).start()
63
+
64
+ monitor = Monitor(URLS)
65
+ monitor.start()
66
+
67
+ def refresh_all():
68
+ logger.info("刷新状态")
69
+ return monitor.get_current(), monitor.get_stats()
70
+
71
+ def get_filtered_stats(sel):
72
+ return monitor.get_stats(sel)
73
+
74
+ with gr.Blocks(title="服务状态监控") as demo:
75
+ gr.Markdown("## 状态监控\n每小时自动检测服务状态。")
76
+
77
+ status_table = gr.Dataframe(headers=["URL", "最近状态"], interactive=False)
78
+ stats_table = gr.Dataframe(headers=["URL", "检测数", "成功", "成功率"], interactive=False)
79
+
80
+ with gr.Row():
81
+ sel = gr.Dropdown(choices=[u.split('//')[1].split('.')[0] for u in URLS], label="筛选")
82
+ btn = gr.Button("🔄 刷新状态")
83
+
84
+ sel.change(get_filtered_stats, inputs=sel, outputs=stats_table)
85
+ btn.click(refresh_all, outputs=[status_table, stats_table])
86
+
87
+ demo.load(refresh_all, outputs=[status_table, stats_table])
88
+
89
+ gr.HTML("""
90
+ <script>
91
+ setInterval(() => {
92
+ const btn = [...document.querySelectorAll('button')].find(b => b.innerText.includes('刷新'));
93
+ if (btn) btn.click();
94
+ }, 30000);
95
+ </script>
96
+ """)
97
+
98
+ demo.launch()