Spaces:
Running
Running
| /** | |
| * 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 | |
| }; | |
| } |