Spaces:
Running
Running
chore: clean
Browse files- index.html +3 -3
- style.css +0 -28
- wasm-demo.js +42 -16
index.html
CHANGED
@@ -361,9 +361,9 @@
|
|
361 |
<!-- Hero -->
|
362 |
<header class="hero" role="banner">
|
363 |
<div class="hero-copy">
|
364 |
-
<h1>Private Watermark Detection - Check if your text
|
365 |
<div class="explanation-text">
|
366 |
-
Private SynthID uses Google's SynthID technology to detect AI-generated text while preserving privacy through Fully Homomorphic Encryption (FHE). This means you can check if text
|
367 |
</div>
|
368 |
</div>
|
369 |
|
@@ -393,7 +393,7 @@ sequenceDiagram
|
|
393 |
|
394 |
<!-- Wizard Steps -->
|
395 |
<main>
|
396 |
-
<h2 class="section-title">How
|
397 |
<div class="cards-wrapper">
|
398 |
<!-- 1 Keys -->
|
399 |
<section class="card" aria-labelledby="step1">
|
|
|
361 |
<!-- Hero -->
|
362 |
<header class="hero" role="banner">
|
363 |
<div class="hero-copy">
|
364 |
+
<h1>Private Watermark Detection - Check if your text contains watermarks</h1>
|
365 |
<div class="explanation-text">
|
366 |
+
Private SynthID uses Google's SynthID technology to detect watermarks in AI-generated text while preserving privacy through Fully Homomorphic Encryption (FHE). This means you can check if text contains AI watermarks without revealing the content to anyone. Note that this only detects watermarked text - not all AI-generated text will be detected. Learn more about <a href="https://deepmind.google/science/synthid/" target="_blank">SynthID</a> and <a href="https://www.zama.ai/" target="_blank">FHE applications</a>.
|
367 |
</div>
|
368 |
</div>
|
369 |
|
|
|
393 |
|
394 |
<!-- Wizard Steps -->
|
395 |
<main>
|
396 |
+
<h2 class="section-title">How watermark detection works</h2>
|
397 |
<div class="cards-wrapper">
|
398 |
<!-- 1 Keys -->
|
399 |
<section class="card" aria-labelledby="step1">
|
style.css
DELETED
@@ -1,28 +0,0 @@
|
|
1 |
-
body {
|
2 |
-
padding: 2rem;
|
3 |
-
font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
|
4 |
-
}
|
5 |
-
|
6 |
-
h1 {
|
7 |
-
font-size: 16px;
|
8 |
-
margin-top: 0;
|
9 |
-
}
|
10 |
-
|
11 |
-
p {
|
12 |
-
color: rgb(107, 114, 128);
|
13 |
-
font-size: 15px;
|
14 |
-
margin-bottom: 10px;
|
15 |
-
margin-top: 5px;
|
16 |
-
}
|
17 |
-
|
18 |
-
.card {
|
19 |
-
max-width: 620px;
|
20 |
-
margin: 0 auto;
|
21 |
-
padding: 16px;
|
22 |
-
border: 1px solid lightgray;
|
23 |
-
border-radius: 16px;
|
24 |
-
}
|
25 |
-
|
26 |
-
.card p:last-child {
|
27 |
-
margin-bottom: 0;
|
28 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
wasm-demo.js
CHANGED
@@ -177,20 +177,46 @@ async function pollTaskStatus(currentTaskId, currentUid) {
|
|
177 |
if (!statusResponse.ok) {
|
178 |
const errorText = await statusResponse.text();
|
179 |
console.error(`[Poll] Error fetching status: ${statusResponse.status} ${errorText}`);
|
180 |
-
$('srvStatus').textContent = `
|
181 |
show('spin', false);
|
182 |
return null;
|
183 |
}
|
184 |
|
185 |
const statusData = await statusResponse.json();
|
186 |
console.log('[Poll] Task status:', statusData);
|
187 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
188 |
|
189 |
if (statusData.status === 'success' || statusData.status === 'completed') {
|
190 |
return statusData;
|
191 |
} else if (['failure', 'revoked', 'unknown', 'error'].includes(statusData.status.toLowerCase())) {
|
192 |
console.error('[Poll] Task failed or unrecoverable:', statusData);
|
193 |
-
$('srvStatus').textContent = `Task failed: ${statusData.status}`;
|
194 |
show('spin', false);
|
195 |
return null;
|
196 |
} else {
|
@@ -203,34 +229,35 @@ async function pollTaskStatus(currentTaskId, currentUid) {
|
|
203 |
}
|
204 |
} catch (e) {
|
205 |
console.error('[Poll] Polling exception:', e);
|
206 |
-
$('srvStatus').textContent =
|
207 |
show('spin', false);
|
208 |
return null;
|
209 |
}
|
210 |
}
|
211 |
|
212 |
async function getTaskResult(currentTaskId, currentUid, taskName) {
|
213 |
-
$('srvStatus').textContent = '
|
214 |
try {
|
215 |
const resultResponse = await fetch(`${SERVER}/get_task_result?task_name=${taskName}&task_id=${currentTaskId}&uid=${currentUid}`);
|
216 |
|
217 |
if (!resultResponse.ok) {
|
218 |
const errorText = await resultResponse.text();
|
219 |
-
throw new Error(`
|
220 |
}
|
221 |
|
222 |
const resultArrayBuffer = await resultResponse.arrayBuffer();
|
223 |
encServerResult = new Uint8Array(resultArrayBuffer);
|
224 |
|
225 |
console.log(`[Main] Received encrypted result: ${encServerResult.length} bytes`);
|
226 |
-
$('encResult').value = `(${encServerResult.length}
|
227 |
-
|
|
|
228 |
enable('btnDecrypt');
|
229 |
|
230 |
} catch (e) {
|
231 |
-
const duration = window.taskStartTime ? ((performance.now() - window.taskStartTime) / 1000).toFixed(
|
232 |
console.error(`[Main] /get_task_result failed after ${duration}s:`, e);
|
233 |
-
$('srvStatus').textContent =
|
234 |
} finally {
|
235 |
show('spin', false);
|
236 |
$('srvComputing').hidden = true;
|
@@ -249,8 +276,8 @@ $('btnSend').onclick = async () => {
|
|
249 |
|
250 |
show('encIcon', false);
|
251 |
show('spin', true);
|
252 |
-
$('srvStatus').textContent = '
|
253 |
-
$('srvComputing').hidden = true;
|
254 |
window.taskStartTime = performance.now();
|
255 |
|
256 |
try {
|
@@ -269,14 +296,13 @@ $('btnSend').onclick = async () => {
|
|
269 |
|
270 |
if (!startTaskResponse.ok) {
|
271 |
const errorText = await startTaskResponse.text();
|
272 |
-
throw new Error(`Server
|
273 |
}
|
274 |
|
275 |
const { task_id: newTaskId } = await startTaskResponse.json();
|
276 |
taskId = newTaskId;
|
277 |
console.log('[Main] Task submitted to server. Task ID:', taskId);
|
278 |
-
$('srvStatus').textContent =
|
279 |
-
$('srvComputing').hidden = false;
|
280 |
|
281 |
pollTaskStatus(taskId, sessionUid).then(finalStatus => {
|
282 |
if (finalStatus && (finalStatus.status === 'success' || finalStatus.status === 'completed')) {
|
@@ -287,7 +313,7 @@ $('btnSend').onclick = async () => {
|
|
287 |
} catch (e) {
|
288 |
const duration = ((performance.now() - window.taskStartTime) / 1000).toFixed(2);
|
289 |
console.error(`[Main] Task submission failed after ${duration}s:`, e);
|
290 |
-
$('srvStatus').textContent =
|
291 |
show('spin', false);
|
292 |
$('srvComputing').hidden = true;
|
293 |
}
|
|
|
177 |
if (!statusResponse.ok) {
|
178 |
const errorText = await statusResponse.text();
|
179 |
console.error(`[Poll] Error fetching status: ${statusResponse.status} ${errorText}`);
|
180 |
+
$('srvStatus').textContent = `Error checking status`;
|
181 |
show('spin', false);
|
182 |
return null;
|
183 |
}
|
184 |
|
185 |
const statusData = await statusResponse.json();
|
186 |
console.log('[Poll] Task status:', statusData);
|
187 |
+
|
188 |
+
// Parse and display user-friendly status messages
|
189 |
+
let userMessage = '';
|
190 |
+
let showComputing = false;
|
191 |
+
|
192 |
+
if (statusData.status === 'queued') {
|
193 |
+
// Extract position from details if available
|
194 |
+
const positionMatch = statusData.details?.match(/Position:\s*(\d+)\/(\d+)/);
|
195 |
+
if (positionMatch) {
|
196 |
+
const [, position, total] = positionMatch;
|
197 |
+
userMessage = `Waiting in queue (${position} of ${total})`;
|
198 |
+
} else {
|
199 |
+
userMessage = 'Waiting in queue...';
|
200 |
+
}
|
201 |
+
} else if (statusData.status === 'processing' || statusData.status === 'running') {
|
202 |
+
userMessage = 'Processing your request...';
|
203 |
+
showComputing = true;
|
204 |
+
} else if (statusData.status === 'success' || statusData.status === 'completed') {
|
205 |
+
userMessage = 'Processing complete!';
|
206 |
+
} else if (['failure', 'revoked', 'unknown', 'error'].includes(statusData.status.toLowerCase())) {
|
207 |
+
userMessage = 'Task failed. Please try again.';
|
208 |
+
} else {
|
209 |
+
// Fallback for any other status
|
210 |
+
userMessage = `Status: ${statusData.status}`;
|
211 |
+
}
|
212 |
+
|
213 |
+
$('srvStatus').textContent = userMessage;
|
214 |
+
$('srvComputing').hidden = !showComputing;
|
215 |
|
216 |
if (statusData.status === 'success' || statusData.status === 'completed') {
|
217 |
return statusData;
|
218 |
} else if (['failure', 'revoked', 'unknown', 'error'].includes(statusData.status.toLowerCase())) {
|
219 |
console.error('[Poll] Task failed or unrecoverable:', statusData);
|
|
|
220 |
show('spin', false);
|
221 |
return null;
|
222 |
} else {
|
|
|
229 |
}
|
230 |
} catch (e) {
|
231 |
console.error('[Poll] Polling exception:', e);
|
232 |
+
$('srvStatus').textContent = 'Connection error. Please check your network.';
|
233 |
show('spin', false);
|
234 |
return null;
|
235 |
}
|
236 |
}
|
237 |
|
238 |
async function getTaskResult(currentTaskId, currentUid, taskName) {
|
239 |
+
$('srvStatus').textContent = 'Retrieving results...';
|
240 |
try {
|
241 |
const resultResponse = await fetch(`${SERVER}/get_task_result?task_name=${taskName}&task_id=${currentTaskId}&uid=${currentUid}`);
|
242 |
|
243 |
if (!resultResponse.ok) {
|
244 |
const errorText = await resultResponse.text();
|
245 |
+
throw new Error(`Failed to get results`);
|
246 |
}
|
247 |
|
248 |
const resultArrayBuffer = await resultResponse.arrayBuffer();
|
249 |
encServerResult = new Uint8Array(resultArrayBuffer);
|
250 |
|
251 |
console.log(`[Main] Received encrypted result: ${encServerResult.length} bytes`);
|
252 |
+
$('encResult').value = `Encrypted result (${encServerResult.length} bytes)`;
|
253 |
+
const duration = ((performance.now() - window.taskStartTime) / 1000).toFixed(1);
|
254 |
+
$('srvStatus').textContent = `✓ Complete! (${duration}s)`;
|
255 |
enable('btnDecrypt');
|
256 |
|
257 |
} catch (e) {
|
258 |
+
const duration = window.taskStartTime ? ((performance.now() - window.taskStartTime) / 1000).toFixed(1) : 'N/A';
|
259 |
console.error(`[Main] /get_task_result failed after ${duration}s:`, e);
|
260 |
+
$('srvStatus').textContent = 'Failed to retrieve results. Please try again.';
|
261 |
} finally {
|
262 |
show('spin', false);
|
263 |
$('srvComputing').hidden = true;
|
|
|
276 |
|
277 |
show('encIcon', false);
|
278 |
show('spin', true);
|
279 |
+
$('srvStatus').textContent = 'Sending encrypted data...';
|
280 |
+
$('srvComputing').hidden = true; // Ensure it's hidden initially
|
281 |
window.taskStartTime = performance.now();
|
282 |
|
283 |
try {
|
|
|
296 |
|
297 |
if (!startTaskResponse.ok) {
|
298 |
const errorText = await startTaskResponse.text();
|
299 |
+
throw new Error(`Server error: ${startTaskResponse.status}`);
|
300 |
}
|
301 |
|
302 |
const { task_id: newTaskId } = await startTaskResponse.json();
|
303 |
taskId = newTaskId;
|
304 |
console.log('[Main] Task submitted to server. Task ID:', taskId);
|
305 |
+
$('srvStatus').textContent = 'Request submitted. Checking status...';
|
|
|
306 |
|
307 |
pollTaskStatus(taskId, sessionUid).then(finalStatus => {
|
308 |
if (finalStatus && (finalStatus.status === 'success' || finalStatus.status === 'completed')) {
|
|
|
313 |
} catch (e) {
|
314 |
const duration = ((performance.now() - window.taskStartTime) / 1000).toFixed(2);
|
315 |
console.error(`[Main] Task submission failed after ${duration}s:`, e);
|
316 |
+
$('srvStatus').textContent = 'Failed to submit request. Please try again.';
|
317 |
show('spin', false);
|
318 |
$('srvComputing').hidden = true;
|
319 |
}
|