Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
first import
Browse files- .gitignore +23 -0
- .npmrc +1 -0
- .prettierignore +6 -0
- .prettierrc +15 -0
- README.md +0 -38
- eslint.config.js +36 -0
- package-lock.json +0 -0
- package.json +42 -0
- src/app.css +2 -0
- src/app.d.ts +13 -0
- src/app.html +12 -0
- src/lib/index.ts +100 -0
- src/routes/+layout.svelte +19 -0
- src/routes/+page.svelte +186 -0
- src/routes/+page.ts +6 -0
- static/favicon.png +0 -0
- svelte.config.js +18 -0
- tsconfig.json +19 -0
- vite.config.ts +7 -0
.gitignore
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
node_modules
|
2 |
+
|
3 |
+
# Output
|
4 |
+
.output
|
5 |
+
.vercel
|
6 |
+
.netlify
|
7 |
+
.wrangler
|
8 |
+
/.svelte-kit
|
9 |
+
/build
|
10 |
+
|
11 |
+
# OS
|
12 |
+
.DS_Store
|
13 |
+
Thumbs.db
|
14 |
+
|
15 |
+
# Env
|
16 |
+
.env
|
17 |
+
.env.*
|
18 |
+
!.env.example
|
19 |
+
!.env.test
|
20 |
+
|
21 |
+
# Vite
|
22 |
+
vite.config.js.timestamp-*
|
23 |
+
vite.config.ts.timestamp-*
|
.npmrc
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
engine-strict=true
|
.prettierignore
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Package Managers
|
2 |
+
package-lock.json
|
3 |
+
pnpm-lock.yaml
|
4 |
+
yarn.lock
|
5 |
+
bun.lock
|
6 |
+
bun.lockb
|
.prettierrc
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"useTabs": true,
|
3 |
+
"singleQuote": true,
|
4 |
+
"trailingComma": "none",
|
5 |
+
"printWidth": 100,
|
6 |
+
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
|
7 |
+
"overrides": [
|
8 |
+
{
|
9 |
+
"files": "*.svelte",
|
10 |
+
"options": {
|
11 |
+
"parser": "svelte"
|
12 |
+
}
|
13 |
+
}
|
14 |
+
]
|
15 |
+
}
|
README.md
CHANGED
@@ -1,39 +1 @@
|
|
1 |
-
# sv
|
2 |
-
|
3 |
-
Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli).
|
4 |
-
|
5 |
-
## Creating a project
|
6 |
-
|
7 |
-
If you're seeing this, you've probably already done this step. Congrats!
|
8 |
-
|
9 |
-
```bash
|
10 |
-
# create a new project in the current directory
|
11 |
-
npx sv create
|
12 |
-
|
13 |
-
# create a new project in my-app
|
14 |
-
npx sv create my-app
|
15 |
-
```
|
16 |
-
|
17 |
-
## Developing
|
18 |
-
|
19 |
-
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
20 |
-
|
21 |
-
```bash
|
22 |
-
npm run dev
|
23 |
-
|
24 |
-
# or start the server and open the app in a new browser tab
|
25 |
-
npm run dev -- --open
|
26 |
-
```
|
27 |
-
|
28 |
-
## Building
|
29 |
-
|
30 |
-
To create a production version of your app:
|
31 |
-
|
32 |
-
```bash
|
33 |
-
npm run build
|
34 |
-
```
|
35 |
-
|
36 |
-
You can preview the production build with `npm run preview`.
|
37 |
-
|
38 |
-
> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
|
39 |
# huggingface-fast
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
# huggingface-fast
|
eslint.config.js
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import prettier from 'eslint-config-prettier';
|
2 |
+
import js from '@eslint/js';
|
3 |
+
import { includeIgnoreFile } from '@eslint/compat';
|
4 |
+
import svelte from 'eslint-plugin-svelte';
|
5 |
+
import globals from 'globals';
|
6 |
+
import { fileURLToPath } from 'node:url';
|
7 |
+
import ts from 'typescript-eslint';
|
8 |
+
import svelteConfig from './svelte.config.js';
|
9 |
+
|
10 |
+
const gitignorePath = fileURLToPath(new URL('./.gitignore', import.meta.url));
|
11 |
+
|
12 |
+
export default ts.config(
|
13 |
+
includeIgnoreFile(gitignorePath),
|
14 |
+
js.configs.recommended,
|
15 |
+
...ts.configs.recommended,
|
16 |
+
...svelte.configs.recommended,
|
17 |
+
prettier,
|
18 |
+
...svelte.configs.prettier,
|
19 |
+
{
|
20 |
+
languageOptions: {
|
21 |
+
globals: { ...globals.browser, ...globals.node }
|
22 |
+
},
|
23 |
+
rules: { 'no-undef': 'off' }
|
24 |
+
},
|
25 |
+
{
|
26 |
+
files: ['**/*.svelte', '**/*.svelte.ts', '**/*.svelte.js'],
|
27 |
+
languageOptions: {
|
28 |
+
parserOptions: {
|
29 |
+
projectService: true,
|
30 |
+
extraFileExtensions: ['.svelte'],
|
31 |
+
parser: ts.parser,
|
32 |
+
svelteConfig
|
33 |
+
}
|
34 |
+
}
|
35 |
+
}
|
36 |
+
);
|
package-lock.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
package.json
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "huggingface-fast",
|
3 |
+
"private": true,
|
4 |
+
"version": "0.0.1",
|
5 |
+
"type": "module",
|
6 |
+
"scripts": {
|
7 |
+
"dev": "vite dev",
|
8 |
+
"build": "vite build",
|
9 |
+
"preview": "vite preview",
|
10 |
+
"prepare": "svelte-kit sync || echo ''",
|
11 |
+
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
12 |
+
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
13 |
+
"format": "prettier --write .",
|
14 |
+
"lint": "prettier --check . && eslint ."
|
15 |
+
},
|
16 |
+
"devDependencies": {
|
17 |
+
"@eslint/compat": "^1.2.5",
|
18 |
+
"@eslint/js": "^9.18.0",
|
19 |
+
"@sveltejs/adapter-auto": "^6.0.0",
|
20 |
+
"@sveltejs/kit": "^2.16.0",
|
21 |
+
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
22 |
+
"@tailwindcss/typography": "^0.5.15",
|
23 |
+
"@tailwindcss/vite": "^4.0.0",
|
24 |
+
"eslint": "^9.18.0",
|
25 |
+
"eslint-config-prettier": "^10.0.1",
|
26 |
+
"eslint-plugin-svelte": "^3.0.0",
|
27 |
+
"globals": "^16.0.0",
|
28 |
+
"prettier": "^3.4.2",
|
29 |
+
"prettier-plugin-svelte": "^3.3.3",
|
30 |
+
"prettier-plugin-tailwindcss": "^0.6.11",
|
31 |
+
"svelte": "^5.0.0",
|
32 |
+
"svelte-check": "^4.0.0",
|
33 |
+
"tailwindcss": "^4.0.0",
|
34 |
+
"typescript": "^5.0.0",
|
35 |
+
"typescript-eslint": "^8.20.0",
|
36 |
+
"vite": "^6.2.6"
|
37 |
+
},
|
38 |
+
"dependencies": {
|
39 |
+
"@fortawesome/fontawesome-free": "^6.7.2",
|
40 |
+
"chart.js": "^4.4.9"
|
41 |
+
}
|
42 |
+
}
|
src/app.css
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
@import 'tailwindcss';
|
2 |
+
@plugin '@tailwindcss/typography';
|
src/app.d.ts
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// See https://svelte.dev/docs/kit/types#app.d.ts
|
2 |
+
// for information about these interfaces
|
3 |
+
declare global {
|
4 |
+
namespace App {
|
5 |
+
// interface Error {}
|
6 |
+
// interface Locals {}
|
7 |
+
// interface PageData {}
|
8 |
+
// interface PageState {}
|
9 |
+
// interface Platform {}
|
10 |
+
}
|
11 |
+
}
|
12 |
+
|
13 |
+
export {};
|
src/app.html
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!doctype html>
|
2 |
+
<html lang="en">
|
3 |
+
<head>
|
4 |
+
<meta charset="utf-8" />
|
5 |
+
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
6 |
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
7 |
+
%sveltekit.head%
|
8 |
+
</head>
|
9 |
+
<body data-sveltekit-preload-data="hover" class="bg-gray-50 min-h-screen">
|
10 |
+
<div class="container mx-auto px-4 py-8">%sveltekit.body%</div>
|
11 |
+
</body>
|
12 |
+
</html>
|
src/lib/index.ts
ADDED
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// place files you want to import through the `$lib` alias in this folder.
|
2 |
+
|
3 |
+
interface BandwidthCallback {
|
4 |
+
(
|
5 |
+
elapsedMs: number,
|
6 |
+
loadedBytes: number,
|
7 |
+
totalBytes: number,
|
8 |
+
bytesPerSecond: number,
|
9 |
+
done: boolean
|
10 |
+
): void;
|
11 |
+
}
|
12 |
+
|
13 |
+
export async function bandwidthTest(
|
14 |
+
onProgress: BandwidthCallback,
|
15 |
+
onLatency: (latency: number) => void
|
16 |
+
) {
|
17 |
+
performance.setResourceTimingBufferSize(100);
|
18 |
+
performance.clearResourceTimings();
|
19 |
+
// start timer
|
20 |
+
const startTime = performance.now();
|
21 |
+
// const url = 'https://cdn-test-cloudfront.hf.co/140gb.safetensors';
|
22 |
+
const url = 'https://cdn-test-cloudfront.hf.co/15mb.json';
|
23 |
+
const response = await fetch(url);
|
24 |
+
if (!response.ok) {
|
25 |
+
throw new Error(`Network response was not ok: ${response.status}`);
|
26 |
+
}
|
27 |
+
// setTimeout(() => {
|
28 |
+
// const entries = performance.getEntriesByType('resource');
|
29 |
+
// const resourceEntry = entries.find((e) => e.name === url);
|
30 |
+
// if (!resourceEntry) {
|
31 |
+
// return
|
32 |
+
// }
|
33 |
+
// console.log(resourceEntry);
|
34 |
+
// const { requestStart, responseStart } = resourceEntry;
|
35 |
+
// const latency = responseStart - requestStart;
|
36 |
+
// onLatency(latency);
|
37 |
+
// }, 2000);
|
38 |
+
const latency = performance.now() - startTime;
|
39 |
+
onLatency(latency);
|
40 |
+
const contentLengthHeader = response.headers.get('Content-Length');
|
41 |
+
const totalBytes = contentLengthHeader ? parseInt(contentLengthHeader, 10) : 0;
|
42 |
+
const reader = response.body.getReader();
|
43 |
+
let loadedBytes = 0;
|
44 |
+
let lastTimestamp = performance.now();
|
45 |
+
let lastLoaded = 0;
|
46 |
+
const REPORT_INTERVAL_MS = 500;
|
47 |
+
onProgress(latency, loadedBytes, totalBytes, 0, false);
|
48 |
+
let bytesPerSecond= 0;
|
49 |
+
while (true) {
|
50 |
+
const { done, value } = await reader.read();
|
51 |
+
if (done) {
|
52 |
+
// stream is finished
|
53 |
+
const elapsedMs = performance.now() - startTime;
|
54 |
+
onProgress(elapsedMs, loadedBytes, totalBytes, bytesPerSecond, true);
|
55 |
+
break;
|
56 |
+
}
|
57 |
+
|
58 |
+
// `value` is a Uint8Array for this chunk
|
59 |
+
loadedBytes += value.byteLength;
|
60 |
+
|
61 |
+
// Current time
|
62 |
+
const now = performance.now();
|
63 |
+
const deltaMs = now - lastTimestamp;
|
64 |
+
|
65 |
+
if (deltaMs >= REPORT_INTERVAL_MS) {
|
66 |
+
// compute bytes downloaded since last report
|
67 |
+
const deltaBytes = loadedBytes - lastLoaded;
|
68 |
+
// convert ms to seconds
|
69 |
+
const deltaSeconds = deltaMs / 1000;
|
70 |
+
bytesPerSecond = deltaBytes / deltaSeconds;
|
71 |
+
|
72 |
+
// Invoke callback
|
73 |
+
const elapsedMs = performance.now() - startTime;
|
74 |
+
onProgress(elapsedMs, loadedBytes, totalBytes, bytesPerSecond, false);
|
75 |
+
|
76 |
+
// Reset our “last” markers
|
77 |
+
lastLoaded = loadedBytes;
|
78 |
+
lastTimestamp = now;
|
79 |
+
}
|
80 |
+
}
|
81 |
+
}
|
82 |
+
|
83 |
+
export async function counter(callback: BandwidthCallback) {
|
84 |
+
// start timer
|
85 |
+
const startTime = performance.now();
|
86 |
+
let counter = 0;
|
87 |
+
// set a random value between 50 and 150
|
88 |
+
const interval = setInterval(() => {
|
89 |
+
counter = Math.floor(Math.random() * 100) + 50;
|
90 |
+
// Calculate elapsed time in milliseconds
|
91 |
+
const elapsedMs = performance.now() - startTime;
|
92 |
+
callback(elapsedMs, 100, 100, counter, false);
|
93 |
+
}, 1000);
|
94 |
+
// Stop the counter after 3600 seconds
|
95 |
+
setTimeout(() => {
|
96 |
+
clearInterval(interval);
|
97 |
+
const elapsedMs = performance.now() - startTime;
|
98 |
+
callback(elapsedMs, 100, 100, counter, true);
|
99 |
+
}, 3600 * 1000);
|
100 |
+
}
|
src/routes/+layout.svelte
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import '../app.css';
|
3 |
+
import '@fortawesome/fontawesome-free/css/all.min.css'
|
4 |
+
|
5 |
+
let { children } = $props();
|
6 |
+
</script>
|
7 |
+
|
8 |
+
<div class="max-w-4xl mx-auto">
|
9 |
+
<header class="text-center mb-10">
|
10 |
+
<div class="flex justify-center items-center mb-4">
|
11 |
+
<img src="https://huggingface.co/front/assets/huggingface_logo-noborder.svg" alt="Hugging Face Logo" class="h-12 mr-3">
|
12 |
+
<h1 class="text-3xl md:text-4xl font-bold text-gray-800">Bandwidth Monitor</h1>
|
13 |
+
</div>
|
14 |
+
<p class="text-gray-600 max-w-2xl mx-auto">
|
15 |
+
Measure your connection speed to Hugging Face's servers in real-time
|
16 |
+
</p>
|
17 |
+
</header>
|
18 |
+
{@render children()}
|
19 |
+
</div>
|
src/routes/+page.svelte
ADDED
@@ -0,0 +1,186 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import { bandwidthTest, counter } from '$lib';
|
3 |
+
import { Chart, registerables } from 'chart.js';
|
4 |
+
import type { Action } from 'svelte/action';
|
5 |
+
|
6 |
+
Chart.register(...registerables);
|
7 |
+
|
8 |
+
let currentBandwidth = $state("0");
|
9 |
+
let currentLatency = $state(0);
|
10 |
+
let bandwidthMeasurements: number[] = $state([]);
|
11 |
+
let timeMeasurements: string[] = $state([]);
|
12 |
+
let bandwidthCallback = (elapsedMs: number, totalBytes: number, loadedBytes: number, bw: number) => {
|
13 |
+
let mbps = (bw / 1000000 * 8); // convert Bps to Mbps
|
14 |
+
// update the bandwidth state
|
15 |
+
currentBandwidth = mbps.toFixed(2);
|
16 |
+
// update the bandwidth measurements array
|
17 |
+
bandwidthMeasurements.push(mbps); // convert Bps to Mbps
|
18 |
+
timeMeasurements.push((elapsedMs / 1000).toFixed(1)); // convert ms to seconds
|
19 |
+
// only keep the last 20 measurements
|
20 |
+
if (bandwidthMeasurements.length > 20) {
|
21 |
+
bandwidthMeasurements.shift();
|
22 |
+
timeMeasurements.shift();
|
23 |
+
}
|
24 |
+
};
|
25 |
+
let latencyCallback = (latency: number) => {
|
26 |
+
// update the latency state
|
27 |
+
currentLatency = latency;
|
28 |
+
console.log('Latency:', latency);
|
29 |
+
};
|
30 |
+
//counter(callback);
|
31 |
+
bandwidthTest(bandwidthCallback, latencyCallback);
|
32 |
+
|
33 |
+
let canvas: HTMLCanvasElement;
|
34 |
+
|
35 |
+
const chart: Action<
|
36 |
+
HTMLCanvasElement
|
37 |
+
> = (node) => {
|
38 |
+
let speedChart: Chart;
|
39 |
+
|
40 |
+
function dispatch<T>(name: string, detail: T) {
|
41 |
+
node.dispatchEvent(new CustomEvent(name, { detail }));
|
42 |
+
}
|
43 |
+
|
44 |
+
$effect(() => {
|
45 |
+
const ctx = canvas.getContext('2d');
|
46 |
+
if (speedChart) {
|
47 |
+
speedChart.destroy();
|
48 |
+
}
|
49 |
+
speedChart = new Chart(ctx, {
|
50 |
+
type: 'line',
|
51 |
+
data: {
|
52 |
+
labels: $state.snapshot(timeMeasurements),
|
53 |
+
datasets: [
|
54 |
+
{
|
55 |
+
label: 'Download Speed (Mbps)',
|
56 |
+
data: $state.snapshot(bandwidthMeasurements),
|
57 |
+
borderColor: '#4f46e5',
|
58 |
+
backgroundColor: 'rgba(79, 70, 229, 0.1)',
|
59 |
+
tension: 0.4,
|
60 |
+
fill: true
|
61 |
+
}
|
62 |
+
]
|
63 |
+
},
|
64 |
+
options: {
|
65 |
+
animation: false,
|
66 |
+
responsive: true,
|
67 |
+
maintainAspectRatio: false,
|
68 |
+
scales: {
|
69 |
+
y: {
|
70 |
+
beginAtZero: true,
|
71 |
+
title: {
|
72 |
+
display: true,
|
73 |
+
text: 'Speed (Mbps)'
|
74 |
+
}
|
75 |
+
},
|
76 |
+
x: {
|
77 |
+
title: {
|
78 |
+
display: true,
|
79 |
+
text: 'Time (seconds)'
|
80 |
+
}
|
81 |
+
}
|
82 |
+
},
|
83 |
+
plugins: {
|
84 |
+
legend: {
|
85 |
+
position: 'top'
|
86 |
+
},
|
87 |
+
tooltip: {
|
88 |
+
mode: 'index',
|
89 |
+
intersect: false
|
90 |
+
}
|
91 |
+
}
|
92 |
+
}
|
93 |
+
});
|
94 |
+
});
|
95 |
+
dispatch('updated', bandwidthMeasurements);
|
96 |
+
return () => {
|
97 |
+
speedChart.destroy();
|
98 |
+
};
|
99 |
+
};
|
100 |
+
</script>
|
101 |
+
<!-- Main Card -->
|
102 |
+
<div class="bg-white rounded-xl shadow-lg overflow-hidden mb-8 transition-all duration-300 hover:shadow-xl">
|
103 |
+
<div class="p-6 md:p-8">
|
104 |
+
<div class="flex items-center justify-between mb-6">
|
105 |
+
<h2 class="text-xl font-semibold text-gray-800">Connection Statistics</h2>
|
106 |
+
<div id="connection-status" class="flex items-center">
|
107 |
+
<span class="h-3 w-3 rounded-full bg-gray-300 mr-2"></span>
|
108 |
+
<span class="text-sm text-gray-500">Idle</span>
|
109 |
+
</div>
|
110 |
+
</div>
|
111 |
+
|
112 |
+
<!-- Speed Display -->
|
113 |
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
|
114 |
+
<div class="bg-gray-50 p-4 rounded-lg text-center">
|
115 |
+
<div class="text-gray-500 mb-1 flex justify-center items-center">
|
116 |
+
<i class="fas fa-download mr-2"></i>
|
117 |
+
<span>Download Speed</span>
|
118 |
+
</div>
|
119 |
+
<div id="download-speed" class="text-2xl font-bold text-indigo-600">{currentBandwidth}</div>
|
120 |
+
<div class="text-sm text-gray-400">Mbps</div>
|
121 |
+
</div>
|
122 |
+
<div class="bg-gray-50 p-4 rounded-lg text-center">
|
123 |
+
<div class="text-gray-500 mb-1 flex justify-center items-center">
|
124 |
+
<i class="fas fa-clock mr-2"></i>
|
125 |
+
<span>Latency</span>
|
126 |
+
</div>
|
127 |
+
<div id="latency" class="text-2xl font-bold text-amber-500">{currentLatency}</div>
|
128 |
+
<div class="text-sm text-gray-400">ms</div>
|
129 |
+
</div>
|
130 |
+
</div>
|
131 |
+
<!-- Progress Bar -->
|
132 |
+
<div class="mb-6">
|
133 |
+
<div class="flex justify-between mb-2">
|
134 |
+
<span class="text-sm font-medium text-gray-700">Test Progress</span>
|
135 |
+
<span id="progress-percent" class="text-sm font-medium text-gray-700">0%</span>
|
136 |
+
</div>
|
137 |
+
<div class="w-full bg-gray-200 rounded-full h-2.5">
|
138 |
+
<div id="progress-bar" class="progress-bar h-2.5 rounded-full" style="width: 0%"></div>
|
139 |
+
</div>
|
140 |
+
</div>
|
141 |
+
<!-- Test Controls -->
|
142 |
+
<div class="flex flex-col sm:flex-row justify-center gap-4">
|
143 |
+
<button id="start-test"
|
144 |
+
class="bg-indigo-600 hover:bg-indigo-700 text-white font-medium py-3 px-6 rounded-lg transition-all flex items-center justify-center glow">
|
145 |
+
<i class="fas fa-play mr-2"></i>
|
146 |
+
Start Test
|
147 |
+
</button>
|
148 |
+
<button id="stop-test"
|
149 |
+
class="bg-gray-200 hover:bg-gray-300 text-gray-800 font-medium py-3 px-6 rounded-lg transition-all flex items-center justify-center"
|
150 |
+
disabled>
|
151 |
+
<i class="fas fa-stop mr-2"></i>
|
152 |
+
Stop Test
|
153 |
+
</button>
|
154 |
+
</div>
|
155 |
+
</div>
|
156 |
+
</div>
|
157 |
+
<!-- Results Graph -->
|
158 |
+
<div class="bg-white rounded-xl shadow-lg overflow-hidden mb-8">
|
159 |
+
<div class="p-6 md:p-8">
|
160 |
+
<h2 class="text-xl font-semibold text-gray-800 mb-6">Speed Over Time</h2>
|
161 |
+
<div class="h-64 relative">
|
162 |
+
<canvas id="speed-chart" bind:this={canvas} use:chart></canvas>
|
163 |
+
</div>
|
164 |
+
</div>
|
165 |
+
</div>
|
166 |
+
<!-- Information Section -->
|
167 |
+
<div class="bg-white rounded-xl shadow-lg overflow-hidden">
|
168 |
+
<div class="p-6 md:p-8">
|
169 |
+
<h2 class="text-xl font-semibold text-gray-800 mb-4">About This Test</h2>
|
170 |
+
<div class="prose prose-indigo max-w-none text-gray-600">
|
171 |
+
<p>
|
172 |
+
This bandwidth test measures your connection speed to Hugging Face's servers by downloading and uploading sample
|
173 |
+
files.
|
174 |
+
The test calculates:
|
175 |
+
</p>
|
176 |
+
<ul class="list-disc pl-5 mt-2 space-y-1">
|
177 |
+
<li><strong>Download speed:</strong> How fast data can be transferred from Hugging Face to your device</li>
|
178 |
+
<li><strong>Latency:</strong> The time it takes to establish connection to Hugging Face server</li>
|
179 |
+
</ul>
|
180 |
+
<p class="mt-4">
|
181 |
+
For accurate results, close other bandwidth-intensive applications and ensure you're not on a VPN unless testing
|
182 |
+
through it.
|
183 |
+
</p>
|
184 |
+
</div>
|
185 |
+
</div>
|
186 |
+
</div>
|
src/routes/+page.ts
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import type { PageLoad } from './$types';
|
2 |
+
export const ssr = false;
|
3 |
+
|
4 |
+
export const load: PageLoad = ({ params }) => {
|
5 |
+
return {};
|
6 |
+
};
|
static/favicon.png
ADDED
![]() |
svelte.config.js
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import adapter from '@sveltejs/adapter-auto';
|
2 |
+
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
3 |
+
|
4 |
+
/** @type {import('@sveltejs/kit').Config} */
|
5 |
+
const config = {
|
6 |
+
// Consult https://svelte.dev/docs/kit/integrations
|
7 |
+
// for more information about preprocessors
|
8 |
+
preprocess: vitePreprocess(),
|
9 |
+
|
10 |
+
kit: {
|
11 |
+
// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
|
12 |
+
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
|
13 |
+
// See https://svelte.dev/docs/kit/adapters for more information about adapters.
|
14 |
+
adapter: adapter()
|
15 |
+
}
|
16 |
+
};
|
17 |
+
|
18 |
+
export default config;
|
tsconfig.json
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"extends": "./.svelte-kit/tsconfig.json",
|
3 |
+
"compilerOptions": {
|
4 |
+
"allowJs": true,
|
5 |
+
"checkJs": true,
|
6 |
+
"esModuleInterop": true,
|
7 |
+
"forceConsistentCasingInFileNames": true,
|
8 |
+
"resolveJsonModule": true,
|
9 |
+
"skipLibCheck": true,
|
10 |
+
"sourceMap": true,
|
11 |
+
"strict": true,
|
12 |
+
"moduleResolution": "bundler"
|
13 |
+
}
|
14 |
+
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
|
15 |
+
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
|
16 |
+
//
|
17 |
+
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
|
18 |
+
// from the referenced tsconfig.json - TypeScript does not merge them in
|
19 |
+
}
|
vite.config.ts
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import tailwindcss from '@tailwindcss/vite';
|
2 |
+
import { sveltekit } from '@sveltejs/kit/vite';
|
3 |
+
import { defineConfig } from 'vite';
|
4 |
+
|
5 |
+
export default defineConfig({
|
6 |
+
plugins: [tailwindcss(), sveltekit()]
|
7 |
+
});
|