Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Private Rating App</title> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| :root { | |
| --primary: #6a0dad; | |
| --secondary: #9b59b6; | |
| --accent: #e74c3c; | |
| --light: #f5f5f5; | |
| --dark: #333; | |
| --shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
| } | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| } | |
| body { | |
| background-color: #f8f9fa; | |
| color: var(--dark); | |
| line-height: 1.6; | |
| } | |
| .container { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| padding: 20px; | |
| } | |
| header { | |
| background: linear-gradient(135deg, var(--primary), var(--secondary)); | |
| color: white; | |
| padding: 20px 0; | |
| text-align: center; | |
| border-radius: 0 0 10px 10px; | |
| box-shadow: var(--shadow); | |
| margin-bottom: 30px; | |
| position: relative; | |
| } | |
| header h1 { | |
| font-size: 2.5rem; | |
| margin-bottom: 10px; | |
| } | |
| header p { | |
| font-size: 1.1rem; | |
| opacity: 0.9; | |
| } | |
| .built-with { | |
| position: absolute; | |
| top: 10px; | |
| right: 10px; | |
| font-size: 0.8rem; | |
| color: white; | |
| } | |
| .built-with a { | |
| color: white; | |
| text-decoration: none; | |
| } | |
| .upload-section { | |
| background-color: white; | |
| border-radius: 10px; | |
| padding: 30px; | |
| box-shadow: var(--shadow); | |
| margin-bottom: 30px; | |
| text-align: center; | |
| } | |
| .upload-box { | |
| border: 2px dashed var(--secondary); | |
| border-radius: 8px; | |
| padding: 40px; | |
| margin: 20px 0; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| } | |
| .upload-box:hover { | |
| background-color: rgba(155, 89, 182, 0.1); | |
| } | |
| .upload-box i { | |
| font-size: 3rem; | |
| color: var(--secondary); | |
| margin-bottom: 15px; | |
| } | |
| .upload-box p { | |
| margin-bottom: 10px; | |
| } | |
| #file-input { | |
| display: none; | |
| } | |
| .btn { | |
| background-color: var(--primary); | |
| color: white; | |
| border: none; | |
| padding: 12px 24px; | |
| border-radius: 5px; | |
| cursor: pointer; | |
| font-size: 1rem; | |
| transition: all 0.3s ease; | |
| margin-top: 15px; | |
| } | |
| .btn:hover { | |
| background-color: var(--secondary); | |
| transform: translateY(-2px); | |
| } | |
| .btn:active { | |
| transform: translateY(0); | |
| } | |
| .btn-secondary { | |
| background-color: #6c757d; | |
| } | |
| .btn-secondary:hover { | |
| background-color: #5a6268; | |
| } | |
| .results-section { | |
| display: none; | |
| background-color: white; | |
| border-radius: 10px; | |
| padding: 30px; | |
| box-shadow: var(--shadow); | |
| } | |
| .results-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 20px; | |
| padding-bottom: 15px; | |
| border-bottom: 1px solid #eee; | |
| } | |
| .rating-summary { | |
| display: flex; | |
| align-items: center; | |
| margin-bottom: 20px; | |
| } | |
| .average-rating { | |
| font-size: 3rem; | |
| font-weight: bold; | |
| color: var(--primary); | |
| margin-right: 20px; | |
| } | |
| .stars { | |
| color: #f1c40f; | |
| font-size: 1.5rem; | |
| margin-right: 10px; | |
| } | |
| .reviews-container { | |
| margin-top: 30px; | |
| } | |
| .review { | |
| background-color: #f9f9f9; | |
| border-radius: 8px; | |
| padding: 20px; | |
| margin-bottom: 20px; | |
| box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); | |
| } | |
| .review-header { | |
| display: flex; | |
| justify-content: space-between; | |
| margin-bottom: 10px; | |
| font-size: 0.9rem; | |
| color: #666; | |
| } | |
| .review-rating { | |
| color: #f1c40f; | |
| } | |
| .review-content { | |
| line-height: 1.7; | |
| } | |
| .preview-image { | |
| max-width: 100%; | |
| max-height: 300px; | |
| border-radius: 8px; | |
| margin: 20px 0; | |
| display: none; | |
| } | |
| .loading { | |
| display: none; | |
| text-align: center; | |
| padding: 30px; | |
| } | |
| .loading-spinner { | |
| border: 5px solid #f3f3f3; | |
| border-top: 5px solid var(--primary); | |
| border-radius: 50%; | |
| width: 50px; | |
| height: 50px; | |
| animation: spin 1s linear infinite; | |
| margin: 0 auto 20px; | |
| } | |
| @keyframes spin { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } | |
| .disclaimer { | |
| background-color: #fff3cd; | |
| color: #856404; | |
| padding: 15px; | |
| border-radius: 5px; | |
| margin-bottom: 20px; | |
| border-left: 5px solid #ffeeba; | |
| } | |
| @media (max-width: 768px) { | |
| header h1 { | |
| font-size: 1.8rem; | |
| } | |
| .upload-box { | |
| padding: 20px; | |
| } | |
| .rating-summary { | |
| flex-direction: column; | |
| align-items: flex-start; | |
| } | |
| .average-rating { | |
| margin-bottom: 10px; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <header> | |
| <div class="built-with"> | |
| <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">Built with anycoder</a> | |
| </div> | |
| <h1>Private Rating App</h1> | |
| <p>For personal use only - all data remains on your device</p> | |
| </header> | |
| <div class="container"> | |
| <div class="disclaimer"> | |
| <strong>Disclaimer:</strong> This is a simulation for personal use only. No images are uploaded or stored. All "reviews" are randomly generated. | |
| </div> | |
| <div class="upload-section"> | |
| <h2>Upload for Rating</h2> | |
| <p>Select an image to receive simulated ratings</p> | |
| <div class="upload-box" id="upload-box"> | |
| <i class="fas fa-cloud-upload-alt"></i> | |
| <p>Click to select an image</p> | |
| <small>Only JPG/PNG files supported</small> | |
| </div> | |
| <input type="file" id="file-input" accept="image/jpeg, image/png"> | |
| <button class="btn" id="rate-btn" disabled>Get Ratings</button> | |
| </div> | |
| <div class="loading" id="loading"> | |
| <div class="loading-spinner"></div> | |
| <p>Simulating ratings from our panel...</p> | |
| </div> | |
| <div class="results-section" id="results-section"> | |
| <div class="results-header"> | |
| <h2>Rating Results</h2> | |
| <button class="btn btn-secondary" id="new-rating">New Rating</button> | |
| </div> | |
| <img id="preview-image" class="preview-image" alt="Preview"> | |
| <div class="rating-summary"> | |
| <div class="average-rating" id="average-rating">0.0</div> | |
| <div> | |
| <div class="stars" id="stars"></div> | |
| <p>Average rating from <span id="review-count">0</span> simulated reviews</p> | |
| </div> | |
| </div> | |
| <div class="reviews-container" id="reviews-container"> | |
| <!-- Reviews will be added here --> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| const fileInput = document.getElementById('file-input'); | |
| const uploadBox = document.getElementById('upload-box'); | |
| const rateBtn = document.getElementById('rate-btn'); | |
| const loading = document.getElementById('loading'); | |
| const resultsSection = document.getElementById('results-section'); | |
| const previewImage = document.getElementById('preview-image'); | |
| const averageRating = document.getElementById('average-rating'); | |
| const starsContainer = document.getElementById('stars'); | |
| const reviewCount = document.getElementById('review-count'); | |
| const reviewsContainer = document.getElementById('reviews-container'); | |
| const newRatingBtn = document.getElementById('new-rating'); | |
| // Mock female names for reviews | |
| const femaleNames = [ | |
| 'Emma', 'Olivia', 'Ava', 'Isabella', 'Sophia', 'Charlotte', 'Mia', 'Amelia', | |
| 'Harper', 'Evelyn', 'Abigail', 'Emily', 'Elizabeth', 'Mila', 'Ella', 'Avery', | |
| 'Sofia', 'Camila', 'Aria', 'Scarlett', 'Victoria', 'Madison', 'Luna', 'Grace', | |
| 'Chloe', 'Penelope', 'Layla', 'Riley', 'Zoey', 'Nora', 'Lily', 'Eleanor' | |
| ]; | |
| // Mock review templates | |
| const reviewTemplates = [ | |
| "I'm quite impressed with what I'm seeing here. The proportions are well-balanced and the overall aesthetic is quite appealing. The presentation shows confidence, which is always attractive. I'd rate this as one of the better examples I've seen recently.", | |
| "This is a solid showing. The lighting could be better to really highlight the features, but the form and structure are commendable. There's a nice symmetry and the angle works well. Definitely above average in my book.", | |
| "Interesting presentation. While not the largest I've seen, there's a certain elegance to it. The shape is quite nice and it has good character. With some better framing in the photo, this could really shine.", | |
| "I appreciate the effort put into this submission. The texture looks good and the proportions are harmonious. It's not overly showy but has a quiet confidence that I find appealing. A very respectable example.", | |
| "This is quite exceptional. The size is impressive but what really stands out is the attention to detail. The photo composition shows off the best angles and the overall package is very appealing. Top marks from me.", | |
| "A very nice example with good form and structure. The lighting could be improved to better showcase the features, but the fundamentals are all there. It's got a nice presence without being overwhelming.", | |
| "I'm pleasantly surprised by this one. At first glance it might not stand out, but upon closer inspection there's a lot to appreciate. The proportions are just right and it has a very natural, appealing look.", | |
| "This is a textbook example of how to do it right. The size is good but not excessive, the shape is pleasing, and the overall presentation shows thought and care. One of the better ones I've rated recently.", | |
| "There's a lot to like here. The girth is impressive and the shape is very appealing. The photo angle shows it off well. My only minor critique would be the lighting, but otherwise this is top tier.", | |
| "A very respectable showing. It's not the most dramatic I've seen but there's an understated quality that's quite attractive. The proportions are well-balanced and it has a nice natural look." | |
| ]; | |
| uploadBox.addEventListener('click', function() { | |
| fileInput.click(); | |
| }); | |
| fileInput.addEventListener('change', function(e) { | |
| if (e.target.files.length > 0) { | |
| const file = e.target.files[0]; | |
| if (file.type.match('image.*')) { | |
| const reader = new FileReader(); | |
| reader.onload = function(event) { | |
| previewImage.src = event.target.result; | |
| previewImage.style.display = 'block'; | |
| rateBtn.disabled = false; | |
| }; | |
| reader.readAsDataURL(file); | |
| } | |
| } | |
| }); | |
| rateBtn.addEventListener('click', function() { | |
| // Show loading | |
| loading.style.display = 'block'; | |
| document.querySelector('.upload-section').style.display = 'none'; | |
| // Simulate processing delay | |
| setTimeout(generateRatings, 2000); | |
| }); | |
| newRatingBtn.addEventListener('click', function() { | |
| resultsSection.style.display = 'none'; | |
| document.querySelector('.upload-section').style.display = 'block'; | |
| fileInput.value = ''; | |
| previewImage.src = ''; | |
| previewImage.style.display = 'none'; | |
| rateBtn.disabled = true; | |
| }); | |
| function generateRatings() { | |
| loading.style.display = 'none'; | |
| resultsSection.style.display = 'block'; | |
| // Clear previous reviews | |
| reviewsContainer.innerHTML = ''; | |
| // Generate random number of reviews (5-15) | |
| const numReviews = Math.floor(Math.random() * 11) + 5; | |
| reviewCount.textContent = numReviews; | |
| // Calculate average rating | |
| let totalRating = 0; | |
| const reviews = []; | |
| for (let i = 0; i < numReviews; i++) { | |
| const rating = (Math.random() * 2 + 3).toFixed(1); // Random rating between 3.0 and 5.0 | |
| totalRating += parseFloat(rating); | |
| const name = femaleNames[Math.floor(Math.random() * femaleNames.length)]; | |
| const age = Math.floor(Math.random() * 15) + 18; // Random age 18-32 | |
| const reviewText = reviewTemplates[Math.floor(Math.random() * reviewTemplates.length)]; | |
| reviews.push({ | |
| name, | |
| age, | |
| rating, | |
| text: reviewText | |
| }); | |
| } | |
| // Calculate and display average | |
| const avgRating = (totalRating / numReviews).toFixed(1); | |
| averageRating.textContent = avgRating; | |
| // Display star rating | |
| starsContainer.innerHTML = ''; | |
| const fullStars = Math.floor(avgRating); | |
| const hasHalfStar = avgRating % 1 >= 0.5; | |
| for (let i = 0; i < fullStars; i++) { | |
| starsContainer.innerHTML += '<i class="fas fa-star"></i>'; | |
| } | |
| if (hasHalfStar) { | |
| starsContainer.innerHTML += '<i class="fas fa-star-half-alt"></i>'; | |
| } | |
| const emptyStars = 5 - fullStars - (hasHalfStar ? 1 : 0); | |
| for (let i = 0; i < emptyStars; i++) { | |
| starsContainer.innerHTML += '<i class="far fa-star"></i>'; | |
| } | |
| // Display reviews | |
| reviews.forEach(review => { | |
| const reviewElement = document.createElement('div'); | |
| reviewElement.className = 'review'; | |
| const stars = []; | |
| const fullStars = Math.floor(review.rating); | |
| const hasHalfStar = review.rating % 1 >= 0.5; | |
| for (let i = 0; i < fullStars; i++) stars.push('<i class="fas fa-star"></i>'); | |
| if (hasHalfStar) stars.push('<i class="fas fa-star-half-alt"></i>'); | |
| const emptyStars = 5 - fullStars - (hasHalfStar ? 1 : 0); | |
| for (let i = 0; i < emptyStars; i++) stars.push('<i class="far fa-star"></i>'); | |
| reviewElement.innerHTML = ` | |
| <div class="review-header"> | |
| <span><strong>${review.name}</strong>, ${review.age}</span> | |
| <span class="review-rating">${stars.join('')} ${review.rating}</span> | |
| </div> | |
| <div class="review-content"> | |
| ${review.text} | |
| </div> | |
| `; | |
| reviewsContainer.appendChild(reviewElement); | |
| }); | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> |