euler314 commited on
Commit
fb4f63a
Β·
verified Β·
1 Parent(s): 9446526

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +123 -141
app.py CHANGED
@@ -1,167 +1,149 @@
1
  # app.py
2
 
3
- from flask import Flask, send_file, request, jsonify, Response
4
- import io, os, random
5
- import threading
6
- import time
7
- import gradio as gr
8
 
9
- # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
10
- # Minimal Flask backend for LibreSpeed-style tests
11
- # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
12
 
13
  app = Flask(__name__)
14
 
 
15
  # Pre-generate a 10 MiB random blob for download tests
16
- DOWNLOAD_SIZE_BYTES = 10 * 1024 * 1024 # 10 MiB
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
- # We generate once at startup to avoid repeated overhead
19
- _random_blob = os.urandom(DOWNLOAD_SIZE_BYTES)
20
 
 
 
 
21
  @app.route("/download_test")
22
  def download_test():
23
- """
24
- Serve a fixed-size blob (10 MiB) to the client for download‐speed measurement.
25
- """
26
  return Response(
27
- _random_blob,
28
  mimetype="application/octet-stream",
29
  headers={
30
  "Content-Disposition": f"attachment; filename=\"test_{DOWNLOAD_SIZE_BYTES}.bin\""
31
  }
32
  )
33
 
 
 
 
 
34
  @app.route("/upload_test", methods=["POST"])
35
  def upload_test():
36
- """
37
- Accept arbitrary data from client. Return immediately with length for timing.
38
- """
39
- data = request.get_data()
40
- size = len(data) # bytes received
41
- # We don’t store it; this endpoint exists purely to let the JS measure upload speed.
42
  return jsonify({"received_bytes": size})
43
 
 
44
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
45
- # HTML/JS frontend (embedded LibreSpeed logic)
46
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
47
-
48
- LIBRESPEED_HTML = """
49
- <!DOCTYPE html>
50
- <html lang="en">
51
- <head>
52
- <meta charset="UTF-8" />
53
- <title>Client-Side Speed Test</title>
54
- <style>
55
- body { font-family: sans-serif; max-width: 600px; margin: 2em auto; }
56
- button { padding: 0.5em 1em; font-size: 1rem; }
57
- .result { margin-top: 1.5em; }
58
- .label { font-weight: bold; }
59
- </style>
60
- </head>
61
- <body>
62
- <h2>Wi-Fi / Ethernet Speed Test (Client-Side)</h2>
63
- <p>This test will measure your real Internet speed by downloading a 10 MiB file and uploading random data.</p>
64
- <button id="startBtn">Start Speed Test</button>
65
-
66
- <div class="result" id="results" style="display: none;">
67
- <p><span class="label">Download Speed:</span> <span id="dlSpeed">–</span></p>
68
- <p><span class="label">Upload Speed:</span> <span id="ulSpeed">–</span></p>
69
- <p><span class="label">Ping:</span> <span id="ping">–</span></p>
70
- </div>
71
-
72
- <script>
73
- const startBtn = document.getElementById("startBtn");
74
- const resultsDiv = document.getElementById("results");
75
- const dlSpan = document.getElementById("dlSpeed");
76
- const ulSpan = document.getElementById("ulSpeed");
77
- const pingSpan = document.getElementById("ping");
78
-
79
- // Utility to format bits/sec β†’ Mbps
80
- function toMbps(bits) {
81
- return (bits / 1e6).toFixed(2) + " Mbps";
82
- }
83
-
84
- startBtn.addEventListener("click", async () => {
85
- startBtn.disabled = true;
86
- resultsDiv.style.display = "block";
87
- dlSpan.textContent = "Testing...";
88
- ulSpan.textContent = "Testing...";
89
- pingSpan.textContent = "Testing...";
90
-
91
- // 1) Measure ping by sending a tiny GET
92
- let pingTimes = [];
93
- for (let i = 0; i < 5; i++) {
94
- const t0 = performance.now();
95
- await fetch("/ping_test?t=" + i, { cache: "no-store" });
96
- const t1 = performance.now();
97
- pingTimes.push(t1 - t0);
98
- }
99
- const avgPing = pingTimes.reduce((a, b) => a + b, 0) / pingTimes.length;
100
- pingSpan.textContent = avgPing.toFixed(2) + " ms";
101
-
102
- // 2) Download test: fetch the 10 MiB blob, measure duration
103
- const dlUrl = "/download_test";
104
- const dlStart = performance.now();
105
- const response = await fetch(dlUrl, { cache: "no-store" });
106
- const blob = await response.blob();
107
- const dlEnd = performance.now();
108
- const dlBytes = blob.size;
109
- const dlBits = dlBytes * 8;
110
- const dlDurationSec = (dlEnd - dlStart) / 1000;
111
- const dlSpeedBps = dlBits / dlDurationSec; // bits/sec
112
- dlSpan.textContent = toMbps(dlSpeedBps);
113
-
114
- // 3) Upload test: send a random ArrayBuffer of same size (10 MiB) to /upload_test
115
- // We reuse the DownloadSize for symmetry. In real tests, you might want a smaller upload blob.
116
- const uploadSizeBytes = dlBytes;
117
- // Generate random bytes
118
- const randomBuffer = new Uint8Array(uploadSizeBytes);
119
- window.crypto.getRandomValues(randomBuffer);
120
-
121
- const ulStart = performance.now();
122
- await fetch("/upload_test", {
123
- method: "POST",
124
- headers: { "Content-Type": "application/octet-stream" },
125
- body: randomBuffer
126
- });
127
- const ulEnd = performance.now();
128
- const ulDurationSec = (ulEnd - ulStart) / 1000;
129
- const ulBits = uploadSizeBytes * 8;
130
- const ulSpeedBps = ulBits / ulDurationSec;
131
- ulSpan.textContent = toMbps(ulSpeedBps);
132
-
133
- startBtn.disabled = false;
134
- });
135
- </script>
136
- </body>
137
- </html>
138
- """
139
-
140
- # Expose the HTML through Gradio’s Interface
141
- def serve_html():
142
- return LIBRESPEED_HTML
143
-
144
- iface = gr.Interface(
145
- fn=serve_html,
146
- inputs=[],
147
- outputs=gr.HTML(label="Speed Test"),
148
- title="Client-Side Speed Test",
149
- description="Measures your actual Internet link (download/upload/ping) via JavaScript."
150
- )
151
-
152
- def gradio_thread():
153
- """
154
- Run Gradio in a thread so that Flask and Gradio both serve on the same port.
155
- """
156
- iface.launch(server_name="0.0.0.0", server_port=7860, share=False)
157
-
158
  if __name__ == "__main__":
159
- # 1) Start Gradio in a background thread
160
- t = threading.Thread(target=gradio_thread, daemon=True)
161
- t.start()
162
-
163
- # 2) Start Flask to serve endpoints (on port 7860 as well)
164
- # Since Gradio’s Flask is already bound, we just add our routes to the same server.
165
- # Gradio uses Flask under the hood, so these routes will be served automatically.
166
- # (In recent Gradio versions, custom @app routes work if we set `allow_flagging="never"`, etc.)
167
  app.run(host="0.0.0.0", port=7860, debug=False)
 
1
  # app.py
2
 
3
+ from flask import Flask, Response, request, jsonify
 
 
 
 
4
 
5
+ import os
 
 
6
 
7
  app = Flask(__name__)
8
 
9
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
10
  # Pre-generate a 10 MiB random blob for download tests
11
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
12
+ DOWNLOAD_SIZE_BYTES = 10 * 1024 * 1024
13
+ _blob = os.urandom(DOWNLOAD_SIZE_BYTES)
14
+
15
+
16
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
17
+ # Route: Root – serve the HTML + JS speed‐test page
18
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
19
+ @app.route("/")
20
+ def index():
21
+ html = """
22
+ <!DOCTYPE html>
23
+ <html lang="en">
24
+ <head>
25
+ <meta charset="UTF-8" />
26
+ <title>Client-Side Speed Test</title>
27
+ <style>
28
+ body { font-family: sans-serif; max-width: 600px; margin: 2em auto; }
29
+ button { padding: 0.5em 1em; font-size: 1rem; }
30
+ .result { margin-top: 1.5em; }
31
+ .label { font-weight: bold; }
32
+ </style>
33
+ </head>
34
+ <body>
35
+ <h2>Wi-Fi / Ethernet Speed Test</h2>
36
+ <p>This runs entirely in your browserβ€”download a 10 MiB file and upload random data to measure your real Internet link.</p>
37
+ <button id="startBtn">Start Speed Test</button>
38
+
39
+ <div class="result" id="results" style="display: none;">
40
+ <p><span class="label">Download Speed:</span> <span id="dlSpeed">–</span></p>
41
+ <p><span class="label">Upload Speed:</span> <span id="ulSpeed">–</span></p>
42
+ <p><span class="label">Ping:</span> <span id="ping">–</span></p>
43
+ </div>
44
+
45
+ <script>
46
+ const startBtn = document.getElementById("startBtn");
47
+ const resultsDiv = document.getElementById("results");
48
+ const dlSpan = document.getElementById("dlSpeed");
49
+ const ulSpan = document.getElementById("ulSpeed");
50
+ const pingSpan = document.getElementById("ping");
51
+
52
+ // Convert bits/sec to Mbps string
53
+ function toMbps(bits) {
54
+ return (bits / 1e6).toFixed(2) + " Mbps";
55
+ }
56
+
57
+ startBtn.addEventListener("click", async () => {
58
+ startBtn.disabled = true;
59
+ resultsDiv.style.display = "block";
60
+ dlSpan.textContent = "Testing…";
61
+ ulSpan.textContent = "Testing…";
62
+ pingSpan.textContent = "Testing…";
63
+
64
+ // 1) Ping: 5 small GETs to /ping_test
65
+ let pingTimes = [];
66
+ for (let i = 0; i < 5; i++) {
67
+ const t0 = performance.now();
68
+ await fetch("/ping_test?t=" + i, { cache: "no-store" });
69
+ const t1 = performance.now();
70
+ pingTimes.push(t1 - t0);
71
+ }
72
+ const avgPing = pingTimes.reduce((a, b) => a + b, 0) / pingTimes.length;
73
+ pingSpan.textContent = avgPing.toFixed(2) + " ms";
74
+
75
+ // 2) Download test: fetch 10 MiB blob
76
+ const dlStart = performance.now();
77
+ const response = await fetch("/download_test", { cache: "no-store" });
78
+ const blob = await response.blob();
79
+ const dlEnd = performance.now();
80
+ const dlBytes = blob.size;
81
+ const dlBits = dlBytes * 8;
82
+ const dlDurationSec = (dlEnd - dlStart) / 1000;
83
+ const dlSpeedBps = dlBits / dlDurationSec;
84
+ dlSpan.textContent = toMbps(dlSpeedBps);
85
+
86
+ // 3) Upload test: send 10 MiB random data
87
+ const uploadSizeBytes = dlBytes;
88
+ const randomBuffer = new Uint8Array(uploadSizeBytes);
89
+ window.crypto.getRandomValues(randomBuffer);
90
+
91
+ const ulStart = performance.now();
92
+ await fetch("/upload_test", {
93
+ method: "POST",
94
+ headers: { "Content-Type": "application/octet-stream" },
95
+ body: randomBuffer
96
+ });
97
+ const ulEnd = performance.now();
98
+ const ulDurationSec = (ulEnd - ulStart) / 1000;
99
+ const ulBits = uploadSizeBytes * 8;
100
+ const ulSpeedBps = ulBits / ulDurationSec;
101
+ ulSpan.textContent = toMbps(ulSpeedBps);
102
+
103
+ startBtn.disabled = false;
104
+ });
105
+ </script>
106
+ </body>
107
+ </html>
108
+ """
109
+ return Response(html, mimetype="text/html")
110
+
111
+
112
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
113
+ # Route: /ping_test – empty 200 response (used for ping measurement)
114
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
115
+ @app.route("/ping_test")
116
+ def ping_test():
117
+ return Response(status=200)
118
 
 
 
119
 
120
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
121
+ # Route: /download_test – serve the 10 MiB random blob
122
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
123
  @app.route("/download_test")
124
  def download_test():
 
 
 
125
  return Response(
126
+ _blob,
127
  mimetype="application/octet-stream",
128
  headers={
129
  "Content-Disposition": f"attachment; filename=\"test_{DOWNLOAD_SIZE_BYTES}.bin\""
130
  }
131
  )
132
 
133
+
134
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
135
+ # Route: /upload_test – accept upload, return JSON with received size
136
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
137
  @app.route("/upload_test", methods=["POST"])
138
  def upload_test():
139
+ data = request.get_data() # read all bytes
140
+ size = len(data)
 
 
 
 
141
  return jsonify({"received_bytes": size})
142
 
143
+
144
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
145
+ # Run the Flask app
146
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  if __name__ == "__main__":
148
+ # Bind to 0.0.0.0 so HF’s runtime can route traffic correctly
 
 
 
 
 
 
 
149
  app.run(host="0.0.0.0", port=7860, debug=False)