Spaces:
Runtime error
Runtime error
/** | |
* Piclet Verification Helper for Frontend | |
* Use this in your Svelte game to generate verified Piclets | |
*/ | |
// This should match the server's secret key | |
const PICLET_SECRET_KEY = "piclets-dev-key-change-in-production"; | |
/** | |
* Create HMAC-SHA256 signature (requires crypto-js or similar) | |
* For browser compatibility, you'll need to include crypto-js: | |
* npm install crypto-js | |
* or include via CDN: https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js | |
*/ | |
async function createHMAC(message, key) { | |
// Browser-native crypto API version (modern browsers) | |
if (window.crypto && window.crypto.subtle) { | |
const encoder = new TextEncoder(); | |
const keyData = encoder.encode(key); | |
const messageData = encoder.encode(message); | |
const cryptoKey = await window.crypto.subtle.importKey( | |
'raw', | |
keyData, | |
{ name: 'HMAC', hash: 'SHA-256' }, | |
false, | |
['sign'] | |
); | |
const signature = await window.crypto.subtle.sign('HMAC', cryptoKey, messageData); | |
const hashArray = Array.from(new Uint8Array(signature)); | |
return hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); | |
} | |
// Fallback: Use crypto-js if available | |
if (window.CryptoJS) { | |
return CryptoJS.HmacSHA256(message, key).toString(); | |
} | |
throw new Error("No crypto implementation available. Include crypto-js or use modern browser."); | |
} | |
/** | |
* Create verification data for a Piclet | |
* Call this when generating a Piclet in your game | |
*/ | |
async function createPicletVerification(picletData, imageCaption = "", conceptString = "") { | |
const timestamp = Math.floor(Date.now() / 1000); | |
// Core data used for signature | |
const coreData = { | |
name: picletData.name || "", | |
primaryType: picletData.primaryType || "", | |
baseStats: picletData.baseStats || {}, | |
movepool: picletData.movepool || [], | |
timestamp: timestamp | |
}; | |
// Generation metadata | |
const generationData = { | |
image_caption: imageCaption, | |
concept_string: conceptString, | |
generation_method: "official_app" | |
}; | |
// Add generation data to core data | |
coreData.generation_data = generationData; | |
// Create deterministic JSON string | |
const dataString = JSON.stringify(coreData, null, 0); | |
// Create signature | |
const signature = await createHMAC(dataString, PICLET_SECRET_KEY); | |
return { | |
signature: signature, | |
timestamp: timestamp, | |
generation_data: generationData, | |
verification_version: "1.0" | |
}; | |
} | |
/** | |
* Add verification to a Piclet before saving | |
* Use this in your PicletGenerator component | |
*/ | |
async function verifyAndPreparePiclet(picletData, imageCaption = "", conceptString = "") { | |
try { | |
// Create verification data | |
const verification = await createPicletVerification(picletData, imageCaption, conceptString); | |
// Add verification to Piclet data | |
const verifiedPiclet = { | |
...picletData, | |
verification: verification | |
}; | |
return { | |
success: true, | |
piclet: verifiedPiclet, | |
signature: verification.signature | |
}; | |
} catch (error) { | |
return { | |
success: false, | |
error: error.message | |
}; | |
} | |
} | |
/** | |
* Save a verified Piclet to the server | |
* Use this instead of direct API calls | |
*/ | |
async function saveVerifiedPiclet(gradioClient, picletData, imageFile = null, imageCaption = "", conceptString = "") { | |
try { | |
// Create verified Piclet | |
const verificationResult = await verifyAndPreparePiclet(picletData, imageCaption, conceptString); | |
if (!verificationResult.success) { | |
return { | |
success: false, | |
error: `Verification failed: ${verificationResult.error}` | |
}; | |
} | |
// Save to server | |
const result = await gradioClient.predict("/save_piclet_api", [ | |
JSON.stringify(verificationResult.piclet), | |
verificationResult.signature, | |
imageFile | |
]); | |
return JSON.parse(result.data[0]); | |
} catch (error) { | |
return { | |
success: false, | |
error: `Save failed: ${error.message}` | |
}; | |
} | |
} | |
/** | |
* Example usage in your Svelte component: | |
* | |
* // In PicletGenerator.svelte or similar component | |
* import { saveVerifiedPiclet } from './verification_helper.js'; | |
* | |
* async function savePiclet() { | |
* const picletData = { | |
* name: generatedName, | |
* primaryType: detectedType, | |
* baseStats: calculatedStats, | |
* movepool: generatedMoves, | |
* // ... other data | |
* }; | |
* | |
* const result = await saveVerifiedPiclet( | |
* gradioClient, | |
* picletData, | |
* uploadedImageFile, | |
* imageCaption, | |
* conceptString | |
* ); | |
* | |
* if (result.success) { | |
* console.log(`Piclet saved with ID: ${result.piclet_id}`); | |
* } else { | |
* console.error(`Save failed: ${result.error}`); | |
* } | |
* } | |
*/ | |
// Export for ES modules | |
if (typeof module !== 'undefined' && module.exports) { | |
module.exports = { | |
createPicletVerification, | |
verifyAndPreparePiclet, | |
saveVerifiedPiclet | |
}; | |
} | |
// Global functions for script tag usage | |
if (typeof window !== 'undefined') { | |
window.PicletVerification = { | |
createPicletVerification, | |
verifyAndPreparePiclet, | |
saveVerifiedPiclet | |
}; | |
} |