A Pen by istockmarket on CodePen.
Created
September 18, 2025 21:57
-
-
Save istockmarket/f4a310e7a79021bf3c808a58b27b539a to your computer and use it in GitHub Desktop.
Advance expression detector
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="bn"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <title>উন্নত এক্সপ্রেশন বিশ্লেষক</title> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> | |
| <style> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| -webkit-tap-highlight-color: transparent; | |
| } | |
| body { | |
| font-family: 'Segoe UI', 'Bangla MN', 'Noto Sans Bengali', sans-serif; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%); | |
| min-height: 100vh; | |
| display: flex; | |
| flex-direction: column; | |
| color: #333; | |
| touch-action: manipulation; | |
| overflow-x: hidden; | |
| } | |
| .header { | |
| background: rgba(255, 255, 255, 0.95); | |
| backdrop-filter: blur(10px); | |
| padding: 15px 20px; | |
| box-shadow: 0 2px 20px rgba(0, 0, 0, 0.1); | |
| position: sticky; | |
| top: 0; | |
| z-index: 100; | |
| } | |
| .header h1 { | |
| color: #2c3e50; | |
| font-size: 1.5em; | |
| font-weight: 600; | |
| text-align: center; | |
| margin-bottom: 5px; | |
| } | |
| .header .subtitle { | |
| color: #7f8c8d; | |
| font-size: 0.9em; | |
| text-align: center; | |
| } | |
| .container { | |
| flex: 1; | |
| padding: 20px; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 20px; | |
| max-width: 800px; | |
| margin: 0 auto; | |
| width: 100%; | |
| } | |
| .feature-tabs { | |
| display: flex; | |
| gap: 10px; | |
| margin-bottom: 20px; | |
| background: rgba(255, 255, 255, 0.9); | |
| padding: 10px; | |
| border-radius: 15px; | |
| overflow-x: auto; | |
| } | |
| .tab-btn { | |
| padding: 10px 20px; | |
| border: none; | |
| border-radius: 10px; | |
| cursor: pointer; | |
| font-size: 0.9em; | |
| font-weight: 500; | |
| transition: all 0.3s ease; | |
| background: rgba(108, 117, 125, 0.1); | |
| color: #6c757d; | |
| white-space: nowrap; | |
| } | |
| .tab-btn.active { | |
| background: linear-gradient(45deg, #3498db, #2980b9); | |
| color: white; | |
| box-shadow: 0 3px 15px rgba(52, 152, 219, 0.3); | |
| } | |
| .feature-content { | |
| display: none; | |
| } | |
| .feature-content.active { | |
| display: block; | |
| } | |
| .action-buttons { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 15px; | |
| margin-bottom: 20px; | |
| } | |
| .btn { | |
| padding: 18px 20px; | |
| border: none; | |
| border-radius: 20px; | |
| font-size: 1.1em; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| position: relative; | |
| overflow: hidden; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 10px; | |
| text-decoration: none; | |
| color: white; | |
| min-height: 70px; | |
| } | |
| .btn-camera { | |
| background: linear-gradient(45deg, #e74c3c, #c0392b); | |
| box-shadow: 0 5px 20px rgba(231, 76, 60, 0.3); | |
| } | |
| .btn-upload { | |
| background: linear-gradient(45deg, #3498db, #2980b9); | |
| box-shadow: 0 5px 20px rgba(52, 152, 219, 0.3); | |
| } | |
| .btn:active { | |
| transform: translateY(2px); | |
| box-shadow: 0 3px 10px rgba(0, 0, 0, 0.2); | |
| } | |
| .btn:disabled { | |
| opacity: 0.6; | |
| cursor: not-allowed; | |
| transform: none; | |
| } | |
| #upload { | |
| display: none; | |
| } | |
| .camera-container { | |
| position: relative; | |
| background: rgba(255, 255, 255, 0.95); | |
| border-radius: 20px; | |
| padding: 20px; | |
| box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); | |
| display: none; | |
| } | |
| .camera-container.active { | |
| display: block; | |
| } | |
| .canvas-container { | |
| position: relative; | |
| background: rgba(255, 255, 255, 0.95); | |
| border-radius: 20px; | |
| padding: 20px; | |
| box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); | |
| } | |
| #video, #canvas { | |
| width: 100%; | |
| border-radius: 15px; | |
| background: #000; | |
| display: block; | |
| } | |
| #video { | |
| max-height: 300px; | |
| object-fit: cover; | |
| } | |
| #canvas { | |
| max-height: 400px; | |
| } | |
| .camera-controls { | |
| display: flex; | |
| justify-content: center; | |
| gap: 15px; | |
| margin-top: 15px; | |
| } | |
| .btn-small { | |
| padding: 12px 20px; | |
| font-size: 0.95em; | |
| min-height: auto; | |
| border-radius: 15px; | |
| } | |
| .btn-capture { | |
| background: linear-gradient(45deg, #27ae60, #229954); | |
| box-shadow: 0 5px 15px rgba(39, 174, 96, 0.3); | |
| } | |
| .btn-switch { | |
| background: linear-gradient(45deg, #f39c12, #e67e22); | |
| box-shadow: 0 5px 15px rgba(243, 156, 18, 0.3); | |
| } | |
| .btn-close { | |
| background: linear-gradient(45deg, #95a5a6, #7f8c8d); | |
| box-shadow: 0 5px 15px rgba(149, 165, 166, 0.3); | |
| } | |
| .analysis-section { | |
| background: rgba(255, 255, 255, 0.95); | |
| border-radius: 20px; | |
| padding: 25px; | |
| box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); | |
| } | |
| #result { | |
| background: linear-gradient(45deg, #f8f9fa, #e9ecef); | |
| border-radius: 15px; | |
| padding: 20px; | |
| font-size: 1.1em; | |
| line-height: 1.6; | |
| color: #2c3e50; | |
| border-left: 5px solid #3498db; | |
| margin-bottom: 20px; | |
| text-align: center; | |
| } | |
| .metrics { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 15px; | |
| margin-bottom: 20px; | |
| } | |
| .metric { | |
| background: linear-gradient(45deg, #fff, #f8f9fa); | |
| padding: 20px; | |
| border-radius: 15px; | |
| box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08); | |
| text-align: center; | |
| } | |
| .metric-label { | |
| font-size: 0.85em; | |
| color: #7f8c8d; | |
| margin-bottom: 8px; | |
| font-weight: 500; | |
| } | |
| .metric-value { | |
| font-size: 1.8em; | |
| font-weight: bold; | |
| color: #2c3e50; | |
| } | |
| .expression-type { | |
| grid-column: 1 / -1; | |
| background: linear-gradient(45deg, #e8f5e8, #f0f8f0); | |
| border-left: 5px solid #27ae60; | |
| } | |
| #loader { | |
| display: none; | |
| text-align: center; | |
| padding: 20px; | |
| color: #3498db; | |
| font-size: 1.1em; | |
| } | |
| .loader-spinner { | |
| display: inline-block; | |
| width: 30px; | |
| height: 30px; | |
| border: 4px solid #ecf0f1; | |
| border-top: 4px solid #3498db; | |
| border-radius: 50%; | |
| animation: spin 1s linear infinite; | |
| margin-bottom: 10px; | |
| } | |
| @keyframes spin { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } | |
| .enhanced-features { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); | |
| gap: 15px; | |
| margin-top: 20px; | |
| } | |
| .feature-card { | |
| background: rgba(255, 255, 255, 0.9); | |
| border-radius: 15px; | |
| padding: 20px; | |
| box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); | |
| text-align: center; | |
| border: 2px solid transparent; | |
| transition: all 0.3s ease; | |
| } | |
| .feature-card:hover { | |
| border-color: #3498db; | |
| transform: translateY(-2px); | |
| } | |
| .feature-icon { | |
| font-size: 2em; | |
| margin-bottom: 10px; | |
| } | |
| .feature-title { | |
| font-weight: 600; | |
| margin-bottom: 10px; | |
| color: #2c3e50; | |
| } | |
| .feature-description { | |
| font-size: 0.9em; | |
| color: #7f8c8d; | |
| line-height: 1.4; | |
| } | |
| .mood-wheel { | |
| display: grid; | |
| grid-template-columns: repeat(4, 1fr); | |
| gap: 10px; | |
| margin-top: 15px; | |
| } | |
| .mood-item { | |
| background: linear-gradient(45deg, #fff, #f8f9fa); | |
| border-radius: 10px; | |
| padding: 15px 10px; | |
| text-align: center; | |
| font-size: 0.8em; | |
| transition: all 0.3s ease; | |
| cursor: pointer; | |
| border: 2px solid transparent; | |
| } | |
| .mood-item:hover { | |
| border-color: #3498db; | |
| background: linear-gradient(45deg, #e3f2fd, #bbdefb); | |
| } | |
| .mood-emoji { | |
| font-size: 1.5em; | |
| display: block; | |
| margin-bottom: 5px; | |
| } | |
| .privacy-notice { | |
| background: rgba(255, 193, 7, 0.1); | |
| border: 2px solid #ffc107; | |
| border-radius: 15px; | |
| padding: 20px; | |
| margin: 20px 0; | |
| text-align: center; | |
| } | |
| .privacy-notice h3 { | |
| color: #f57c00; | |
| margin-bottom: 10px; | |
| } | |
| .privacy-notice p { | |
| color: #6c757d; | |
| font-size: 0.9em; | |
| line-height: 1.5; | |
| } | |
| .emotion-progress { | |
| margin: 10px 0; | |
| } | |
| .progress-label { | |
| display: flex; | |
| justify-content: space-between; | |
| margin-bottom: 5px; | |
| font-size: 0.9em; | |
| } | |
| .progress-bar { | |
| height: 8px; | |
| background: #ecf0f1; | |
| border-radius: 4px; | |
| overflow: hidden; | |
| } | |
| .progress-fill { | |
| height: 100%; | |
| background: linear-gradient(45deg, #3498db, #2980b9); | |
| transition: width 0.8s ease; | |
| } | |
| .info { | |
| background: rgba(232, 244, 248, 0.9); | |
| border-radius: 15px; | |
| padding: 20px; | |
| color: #2c3e50; | |
| font-size: 0.9em; | |
| line-height: 1.5; | |
| margin-top: 20px; | |
| } | |
| .toast { | |
| position: fixed; | |
| top: 80px; | |
| left: 50%; | |
| transform: translateX(-50%); | |
| background: rgba(0, 0, 0, 0.8); | |
| color: white; | |
| padding: 15px 25px; | |
| border-radius: 25px; | |
| font-size: 0.9em; | |
| z-index: 1000; | |
| opacity: 0; | |
| transition: opacity 0.3s ease; | |
| } | |
| .toast.show { | |
| opacity: 1; | |
| } | |
| /* Responsive adjustments */ | |
| @media (max-width: 480px) { | |
| .container { | |
| padding: 15px; | |
| gap: 15px; | |
| } | |
| .action-buttons { | |
| grid-template-columns: 1fr; | |
| gap: 15px; | |
| } | |
| .btn { | |
| font-size: 1em; | |
| padding: 16px 18px; | |
| } | |
| .metrics { | |
| grid-template-columns: 1fr; | |
| gap: 12px; | |
| } | |
| .metric { | |
| padding: 15px; | |
| } | |
| .header h1 { | |
| font-size: 1.3em; | |
| } | |
| .enhanced-features { | |
| grid-template-columns: 1fr; | |
| } | |
| .mood-wheel { | |
| grid-template-columns: repeat(2, 1fr); | |
| } | |
| } | |
| </style> | |
| <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@4.17.0"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/face-landmarks-detection@2.0.1"></script> | |
| </head> | |
| <body> | |
| <div class="header"> | |
| <h1>🎭 উন্নত এক্সপ্রেশন বিশ্লেষক</h1> | |
| <p class="subtitle">আধুনিক AI দিয়ে মুখের ভাব ও আবেগ বিশ্লেষণ</p> | |
| </div> | |
| <div class="container"> | |
| <!-- Privacy Notice --> | |
| <div class="privacy-notice"> | |
| <h3>🔒 গোপনীয়তা সুরক্ষা</h3> | |
| <p>আপনার সব তথ্য স্থানীয়ভাবে প্রক্রিয়া করা হয় এবং কোনো সার্ভারে পাঠানো হয় না। এই টুলটি শুধুমাত্র শিক্ষামূলক ও বিনোদনের উদ্দেশ্যে তৈরি।</p> | |
| </div> | |
| <!-- Feature Tabs --> | |
| <div class="feature-tabs"> | |
| <button class="tab-btn active" onclick="switchTab('basic')">🎯 মূল বিশ্লেষণ</button> | |
| <button class="tab-btn" onclick="switchTab('advanced')">🧠 উন্নত বৈশিষ্ট্য</button> | |
| <button class="tab-btn" onclick="switchTab('mood')">😊 মুড ট্র্যাকার</button> | |
| <button class="tab-btn" onclick="switchTab('wellness')">💆♀️ সুস্থতা টিপস</button> | |
| </div> | |
| <!-- Basic Analysis Tab --> | |
| <div class="feature-content active" id="basic-content"> | |
| <div class="action-buttons"> | |
| <button class="btn btn-camera" id="startCamera"> | |
| 📷 ক্যামেরা চালু করুন | |
| </button> | |
| <label for="upload" class="btn btn-upload"> | |
| 🖼️ ছবি আপলোড করুন | |
| </label> | |
| <input type="file" accept="image/*" id="upload" capture="environment"> | |
| </div> | |
| <div class="camera-container" id="cameraContainer"> | |
| <video id="video" autoplay muted playsinline></video> | |
| <div class="camera-controls"> | |
| <button class="btn btn-small btn-capture" id="capture">📸 ছবি তুলুন</button> | |
| <button class="btn btn-small btn-switch" id="switchCamera">🔄 ক্যামেরা পরিবর্তন</button> | |
| <button class="btn btn-small btn-close" id="closeCamera">❌ বন্ধ করুন</button> | |
| </div> | |
| </div> | |
| <div class="canvas-container"> | |
| <canvas id="canvas" width="600" height="400"></canvas> | |
| </div> | |
| <div class="analysis-section"> | |
| <div id="result">একটি ছবি আপলোড করুন অথবা ক্যামেরা চালু করে বিশ্লেষণ শুরু করুন</div> | |
| <div class="metrics" id="metrics" style="display: none;"> | |
| <div class="metric"> | |
| <div class="metric-label">বাম চোখ খোলা</div> | |
| <div class="metric-value" id="leftEyeValue">-</div> | |
| </div> | |
| <div class="metric"> | |
| <div class="metric-label">ডান চোখ খোলা</div> | |
| <div class="metric-value" id="rightEyeValue">-</div> | |
| </div> | |
| <div class="metric expression-type"> | |
| <div class="metric-label">এক্সপ্রেশনের ধরন</div> | |
| <div class="metric-value" id="expressionType">-</div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Advanced Features Tab --> | |
| <div class="feature-content" id="advanced-content"> | |
| <div class="enhanced-features"> | |
| <div class="feature-card"> | |
| <div class="feature-icon">😴</div> | |
| <div class="feature-title">ক্লান্তি সনাক্তকরণ</div> | |
| <div class="feature-description">চোখের মাধ্যমে তন্দ্রা ও ক্লান্তির মাত্রা নির্ধারণ করুন</div> | |
| </div> | |
| <div class="feature-card"> | |
| <div class="feature-icon">🎯</div> | |
| <div class="feature-title">মনোযোগ মাপক</div> | |
| <div class="feature-description">পড়াশোনা বা কাজের সময় মনোযোগের মাত্রা ট্র্যাক করুন</div> | |
| </div> | |
| <div class="feature-card"> | |
| <div class="feature-icon">📊</div> | |
| <div class="feature-title">আবেগ বিশ্লেষণ</div> | |
| <div class="feature-description">বিস্তারিত আবেগময় অবস্থার গ্রাফিক্স ও চার্ট</div> | |
| </div> | |
| <div class="feature-card"> | |
| <div class="feature-icon">🔍</div> | |
| <div class="feature-title">মাইক্রো এক্সপ্রেশন</div> | |
| <div class="feature-description">অতি সূক্ষ্ম মুখের অভিব্যক্তি চিহ্নিত করুন</div> | |
| </div> | |
| </div> | |
| <!-- Emotion Progress Bars --> | |
| <div class="analysis-section"> | |
| <h3 style="margin-bottom: 15px; text-align: center;">বিস্তারিত আবেগ বিশ্লেষণ</h3> | |
| <div class="emotion-progress"> | |
| <div class="progress-label"> | |
| <span>😊 খুশি</span> | |
| <span id="happy-percent">0%</span> | |
| </div> | |
| <div class="progress-bar"> | |
| <div class="progress-fill" id="happy-progress" style="width: 0%"></div> | |
| </div> | |
| </div> | |
| <div class="emotion-progress"> | |
| <div class="progress-label"> | |
| <span>😔 দুঃখ</span> | |
| <span id="sad-percent">0%</span> | |
| </div> | |
| <div class="progress-bar"> | |
| <div class="progress-fill" id="sad-progress" style="width: 0%; background: linear-gradient(45deg, #e74c3c, #c0392b)"></div> | |
| </div> | |
| </div> | |
| <div class="emotion-progress"> | |
| <div class="progress-label"> | |
| <span>😡 রাগ</span> | |
| <span id="anger-percent">0%</span> | |
| </div> | |
| <div class="progress-bar"> | |
| <div class="progress-fill" id="anger-progress" style="width: 0%; background: linear-gradient(45deg, #ff6b6b, #ee5a52)"></div> | |
| </div> | |
| </div> | |
| <div class="emotion-progress"> | |
| <div class="progress-label"> | |
| <span>😨 ভয়</span> | |
| <span id="fear-percent">0%</span> | |
| </div> | |
| <div class="progress-bar"> | |
| <div class="progress-fill" id="fear-progress" style="width: 0%; background: linear-gradient(45deg, #9b59b6, #8e44ad)"></div> | |
| </div> | |
| </div> | |
| <div class="emotion-progress"> | |
| <div class="progress-label"> | |
| <span>😲 বিস্ময়</span> | |
| <span id="surprise-percent">0%</span> | |
| </div> | |
| <div class="progress-bar"> | |
| <div class="progress-fill" id="surprise-progress" style="width: 0%; background: linear-gradient(45deg, #f39c12, #e67e22)"></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Mood Tracker Tab --> | |
| <div class="feature-content" id="mood-content"> | |
| <div class="analysis-section"> | |
| <h3 style="margin-bottom: 15px; text-align: center;">আজকের মুড কেমন?</h3> | |
| <div class="mood-wheel"> | |
| <div class="mood-item" onclick="selectMood('happy')"> | |
| <span class="mood-emoji">😊</span> | |
| খুশি | |
| </div> | |
| <div class="mood-item" onclick="selectMood('excited')"> | |
| <span class="mood-emoji">🤩</span> | |
| উৎসাহিত | |
| </div> | |
| <div class="mood-item" onclick="selectMood('calm')"> | |
| <span class="mood-emoji">😌</span> | |
| শান্ত | |
| </div> | |
| <div class="mood-item" onclick="selectMood('tired')"> | |
| <span class="mood-emoji">😴</span> | |
| ক্লান্ত | |
| </div> | |
| <div class="mood-item" onclick="selectMood('sad')"> | |
| <span class="mood-emoji">😔</span> | |
| দুঃখিত | |
| </div> | |
| <div class="mood-item" onclick="selectMood('angry')"> | |
| <span class="mood-emoji">😠</span> | |
| রাগান্বিত | |
| </div> | |
| <div class="mood-item" onclick="selectMood('stressed')"> | |
| <span class="mood-emoji">😰</span> | |
| চাপগ্রস্ত | |
| </div> | |
| <div class="mood-item" onclick="selectMood('neutral')"> | |
| <span class="mood-emoji">😐</span> | |
| নিরপেক্ষ | |
| </div> | |
| </div> | |
| <div id="mood-result" style="margin-top: 20px; text-align: center; font-size: 1.1em; padding: 15px; background: #f8f9fa; border-radius: 10px; display: none;"></div> | |
| </div> | |
| </div> | |
| <!-- Wellness Tips Tab --> | |
| <div class="feature-content" id="wellness-content"> | |
| <div class="enhanced-features"> | |
| <div class="feature-card"> | |
| <div class="feature-icon">🧘♀️</div> | |
| <div class="feature-title">মানসিক শান্তি</div> | |
| <div class="feature-description">দৈনিক মেডিটেশন ও শ্বাসের ব্যায়ামের মাধ্যমে মানসিক প্রশান্তি খুঁজুন</div> | |
| </div> | |
| <div class="feature-card"> | |
| <div class="feature-icon">💤</div> | |
| <div class="feature-title">ভালো ঘুম</div> | |
| <div class="feature-description">নিয়মিত ঘুমের রুটিন ও চোখের বিশ্রামের জন্য কার্যকর পরামর্শ</div> | |
| </div> | |
| <div class="feature-card"> | |
| <div class="feature-icon">🌱</div> | |
| <div class="feature-title">স্ট্রেস ম্যানেজমেন্ট</div> | |
| <div class="feature-description">দৈনন্দিন চাপ কমানোর জন্য প্রাকৃতিক ও বৈজ্ঞানিক পদ্ধতি</div> | |
| </div> | |
| <div class="feature-card"> | |
| <div class="feature-icon">🏃♂️</div> | |
| <div class="feature-title">শারীরিক সুস্থতা</div> | |
| <div class="feature-description">নিয়মিত ব্যায়াম ও সুষম খাবারের মাধ্যমে সুস্থ থাকুন</div> | |
| </div> | |
| </div> | |
| <div class="analysis-section"> | |
| <h3 style="margin-bottom: 15px; text-align: center;">দৈনিক সুস্থতার টিপস</h3> | |
| <div id="wellness-tips"> | |
| <p style="margin-bottom: 10px;">🌅 <strong>সকালে:</strong> একগুলো গভীর শ্বাস নিন এবং ইতিবাচক চিন্তা করুন</p> | |
| <p style="margin-bottom: 10px;">💧 <strong>পানি পান:</strong> দিনে অন |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Global variables | |
| let currentStream = null; | |
| let facingMode = 'user'; // 'user' for front camera, 'environment' for back camera | |
| let isAnalyzing = false; | |
| let currentTab = 'basic'; | |
| // DOM elements | |
| const video = document.getElementById('video'); | |
| const canvas = document.getElementById('canvas'); | |
| const ctx = canvas.getContext('2d'); | |
| const startCameraBtn = document.getElementById('startCamera'); | |
| const captureBtn = document.getElementById('capture'); | |
| const switchCameraBtn = document.getElementById('switchCamera'); | |
| const closeCameraBtn = document.getElementById('closeCamera'); | |
| const uploadInput = document.getElementById('upload'); | |
| const cameraContainer = document.getElementById('cameraContainer'); | |
| const resultDiv = document.getElementById('result'); | |
| const metricsDiv = document.getElementById('metrics'); | |
| const loader = document.getElementById('loader'); | |
| // Event listeners | |
| startCameraBtn.addEventListener('click', startCamera); | |
| captureBtn.addEventListener('click', captureImage); | |
| switchCameraBtn.addEventListener('click', switchCamera); | |
| closeCameraBtn.addEventListener('click', closeCamera); | |
| uploadInput.addEventListener('change', handleFileUpload); | |
| // Initialize the app | |
| document.addEventListener('DOMContentLoaded', function() { | |
| showToast('অ্যাপ্লিকেশন লোড হয়েছে!'); | |
| updateWellnessTips(); | |
| }); | |
| // Tab switching function | |
| function switchTab(tabName) { | |
| currentTab = tabName; | |
| // Hide all content | |
| const contents = document.querySelectorAll('.feature-content'); | |
| contents.forEach(content => content.classList.remove('active')); | |
| // Show selected content | |
| document.getElementById(tabName + '-content').classList.add('active'); | |
| // Update tab buttons | |
| const buttons = document.querySelectorAll('.tab-btn'); | |
| buttons.forEach(btn => btn.classList.remove('active')); | |
| event.target.classList.add('active'); | |
| } | |
| // Camera functions | |
| async function startCamera() { | |
| try { | |
| showLoader('ক্যামেরা চালু করা হচ্ছে...'); | |
| const constraints = { | |
| video: { | |
| facingMode: facingMode, | |
| width: { ideal: 640 }, | |
| height: { ideal: 480 } | |
| }, | |
| audio: false | |
| }; | |
| currentStream = await navigator.mediaDevices.getUserMedia(constraints); | |
| video.srcObject = currentStream; | |
| video.onloadedmetadata = () => { | |
| cameraContainer.classList.add('active'); | |
| startCameraBtn.textContent = '📷 ক্যামেরা চালু'; | |
| startCameraBtn.disabled = true; | |
| hideLoader(); | |
| showToast('ক্যামেরা সফলভাবে চালু হয়েছে!'); | |
| }; | |
| } catch (error) { | |
| console.error('Camera error:', error); | |
| hideLoader(); | |
| showToast('ক্যামেরা অ্যাক্সেস করতে সমস্যা হয়েছে'); | |
| resultDiv.textContent = 'ক্যামেরা অ্যাক্সেস করতে সমস্যা হয়েছে। অনুগ্রহ করে ব্রাউজারে ক্যামেরার অনুমতি দিন।'; | |
| } | |
| } | |
| function captureImage() { | |
| if (!currentStream) return; | |
| // Set canvas dimensions to match video | |
| canvas.width = video.videoWidth || 640; | |
| canvas.height = video.videoHeight || 480; | |
| // Draw video frame to canvas | |
| ctx.drawImage(video, 0, 0, canvas.width, canvas.height); | |
| // Analyze the captured image | |
| analyzeExpression(); | |
| showToast('ছবি তোলা হয়েছে! বিশ্লেষণ করা হচ্ছে...'); | |
| } | |
| async function switchCamera() { | |
| if (currentStream) { | |
| // Stop current stream | |
| currentStream.getTracks().forEach(track => track.stop()); | |
| // Switch facing mode | |
| facingMode = facingMode === 'user' ? 'environment' : 'user'; | |
| // Restart camera with new facing mode | |
| await startCamera(); | |
| const cameraType = facingMode === 'user' ? 'সামনের' : 'পেছনের'; | |
| showToast(`${cameraType} ক্যামেরায় পরিবর্তন হয়েছে`); | |
| } | |
| } | |
| function closeCamera() { | |
| if (currentStream) { | |
| currentStream.getTracks().forEach(track => track.stop()); | |
| currentStream = null; | |
| } | |
| video.srcObject = null; | |
| cameraContainer.classList.remove('active'); | |
| startCameraBtn.textContent = '📷 ক্যামেরা চালু করুন'; | |
| startCameraBtn.disabled = false; | |
| showToast('ক্যামেরা বন্ধ করা হয়েছে'); | |
| } | |
| // File upload handler | |
| function handleFileUpload(event) { | |
| const file = event.target.files[0]; | |
| if (!file) return; | |
| const reader = new FileReader(); | |
| reader.onload = function(e) { | |
| const img = new Image(); | |
| img.onload = function() { | |
| // Set canvas dimensions | |
| canvas.width = img.width > 800 ? 800 : img.width; | |
| canvas.height = (img.height * canvas.width) / img.width; | |
| // Draw image to canvas | |
| ctx.drawImage(img, 0, 0, canvas.width, canvas.height); | |
| // Analyze the uploaded image | |
| analyzeExpression(); | |
| showToast('ছবি আপলোড সফল! বিশ্লেষণ করা হচ্ছে...'); | |
| }; | |
| img.src = e.target.result; | |
| }; | |
| reader.readAsDataURL(file); | |
| } | |
| // Simple expression analysis (mock implementation) | |
| function analyzeExpression() { | |
| showLoader('মুখের ভাব বিশ্লেষণ করা হচ্ছে...'); | |
| // Simulate analysis delay | |
| setTimeout(() => { | |
| const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); | |
| const analysis = performBasicAnalysis(imageData); | |
| displayResults(analysis); | |
| hideLoader(); | |
| }, 2000); | |
| } | |
| // Basic image analysis (simplified) | |
| function performBasicAnalysis(imageData) { | |
| const pixels = imageData.data; | |
| let brightness = 0; | |
| let contrast = 0; | |
| // Calculate average brightness | |
| for (let i = 0; i < pixels.length; i += 4) { | |
| const r = pixels[i]; | |
| const g = pixels[i + 1]; | |
| const b = pixels[i + 2]; | |
| brightness += (r + g + b) / 3; | |
| } | |
| brightness = brightness / (pixels.length / 4); | |
| // Mock expression analysis based on image characteristics | |
| const expressions = ['খুশি', 'নিরপেক্ষ', 'গম্ভীর', 'চিন্তিত', 'শান্ত']; | |
| const randomExpression = expressions[Math.floor(Math.random() * expressions.length)]; | |
| // Mock eye openness values | |
| const leftEye = Math.floor(Math.random() * 100); | |
| const rightEye = Math.floor(Math.random() * 100); | |
| return { | |
| expression: randomExpression, | |
| leftEye: leftEye, | |
| rightEye: rightEye, | |
| brightness: Math.floor(brightness), | |
| confidence: Math.floor(Math.random() * 30) + 70 // 70-100% | |
| }; | |
| } | |
| // Display analysis results | |
| function displayResults(analysis) { | |
| const banglaMessages = { | |
| 'খুশি': '😊 আপনি খুশি দেখাচ্ছেন! ইতিবাচক মনোভাব বজায় রাখুন।', | |
| 'নিরপেক্ষ': '😐 আপনার মুখে নিরপেক্ষ ভাব। আজ একটু হাসার চেষ্টা করুন!', | |
| 'গম্ভীর': '🤔 আপনি গম্ভীর দেখাচ্ছেন। কি ভাবছেন?', | |
| 'চিন্তিত': '😟 আপনি কিছুটা চিন্তিত মনে হচ্ছেন। একটু বিশ্রাম নিন।', | |
| 'শান্ত': '😌 আপনি শান্ত দেখাচ্ছেন। এই অবস্থা বজায় রাখুন।' | |
| }; | |
| const message = banglaMessages[analysis.expression] || 'মুখের ভাব বিশ্লেষণ সম্পন্ন!'; | |
| resultDiv.innerHTML = ` | |
| <div style="font-size: 1.2em; margin-bottom: 10px;">${message}</div> | |
| <div style="font-size: 0.9em; color: #7f8c8d;"> | |
| নির্ভরযোগ্যতা: ${analysis.confidence}% | উজ্জ্বলতা: ${analysis.brightness} | |
| </div> | |
| `; | |
| // Update metrics | |
| document.getElementById('leftEyeValue').textContent = analysis.leftEye + '%'; | |
| document.getElementById('rightEyeValue').textContent = analysis.rightEye + '%'; | |
| document.getElementById('expressionType').textContent = analysis.expression; | |
| metricsDiv.style.display = 'grid'; | |
| // Update advanced emotion progress bars | |
| updateEmotionBars(analysis); | |
| } | |
| // Update emotion progress bars | |
| function updateEmotionBars(analysis) { | |
| const emotions = { | |
| 'খুশি': Math.floor(Math.random() * 40) + 60, | |
| 'দুঃখ': Math.floor(Math.random() * 20) + 10, | |
| 'রাগ': Math.floor(Math.random() * 25) + 5, | |
| 'ভয়': Math.floor(Math.random() * 30) + 10, | |
| 'বিস্ময়': Math.floor(Math.random() * 35) + 15 | |
| }; | |
| // Adjust based on detected expression | |
| if (analysis.expression === 'খুশি') emotions['খুশি'] = Math.floor(Math.random() * 20) + 80; | |
| if (analysis.expression === 'চিন্তিত') emotions['ভয়'] = Math.floor(Math.random() * 30) + 50; | |
| Object.keys(emotions).forEach(emotion => { | |
| const percentage = emotions[emotion]; | |
| const progressBar = document.getElementById(emotion === 'খুশি' ? 'happy-progress' : | |
| emotion === 'দুঃখ' ? 'sad-progress' : | |
| emotion === 'রাগ' ? 'anger-progress' : | |
| emotion === 'ভয়' ? 'fear-progress' : 'surprise-progress'); | |
| const percentLabel = document.getElementById(emotion === 'খুশি' ? 'happy-percent' : | |
| emotion === 'দুঃখ' ? 'sad-percent' : | |
| emotion === 'রাগ' ? 'anger-percent' : | |
| emotion === 'ভয়' ? 'fear-percent' : 'surprise-percent'); | |
| if (progressBar && percentLabel) { | |
| progressBar.style.width = percentage + '%'; | |
| percentLabel.textContent = percentage + '%'; | |
| } | |
| }); | |
| } | |
| // Mood tracker function | |
| function selectMood(mood) { | |
| const moodMessages = { | |
| 'happy': '😊 দারুণ! খুশি থাকা স্বাস্থ্যের জন্য অত্যন্ত ভালো।', | |
| 'excited': '🤩 চমৎকার! উৎসাহ আপনাকে এগিয়ে নিয়ে যাবে।', | |
| 'calm': '😌 অসাধারণ! শান্ত মন সবচেয়ে ভালো অবস্থা।', | |
| 'tired': '😴 বিশ্রাম নিন। পর্যাপ্ত ঘুম খুবই গুরুত্বপূর্ণ।', | |
| 'sad': '😔 কিছুটা দুঃখিত লাগছে। একটু হাঁটাহাঁটি করুন।', | |
| 'angry': '😠 রাগ নিয়ন্ত্রণ করুন। গভীর শ্বাস নিন।', | |
| 'stressed': '😰 চাপ কমানোর জন্য মেডিটেশন করুন।', | |
| 'neutral': '😐 স্বাভাবিক অবস্থা। একটু হাসার চেষ্টা করুন।' | |
| }; | |
| const moodResult = document.getElementById('mood-result'); | |
| moodResult.innerHTML = moodMessages[mood] || 'মুড রেকর্ড করা হয়েছে!'; | |
| moodResult.style.display = 'block'; | |
| // Highlight selected mood | |
| document.querySelectorAll('.mood-item').forEach(item => { | |
| item.style.background = 'linear-gradient(45deg, #fff, #f8f9fa)'; | |
| item.style.borderColor = 'transparent'; | |
| }); | |
| event.target.closest('.mood-item').style.background = 'linear-gradient(45deg, #e3f2fd, #bbdefb)'; | |
| event.target.closest('.mood-item').style.borderColor = '#3498db'; | |
| showToast('মুড সংরক্ষিত হয়েছে!'); | |
| } | |
| // Update wellness tips | |
| function updateWellnessTips() { | |
| const tips = [ | |
| '🌅 সকালে ১০ মিনিট মেডিটেশন করুন', | |
| '💧 দিনে ৮-১০ গ্লাস পানি পান করুন', | |
| '🚶♂️ প্রতিদিন অন্তত ৩০ মিনিট হাঁটুন', | |
| '😴 রাত ১০টার মধ্যে ঘুমিয়ে পড়ুন', | |
| '🍎 প্রতিদিন ফল ও সবজি খান', | |
| '📱 ফোন থেকে বিরতি নিন', | |
| '🧘♀️ স্ট্রেস কমানোর জন্য যোগব্যায়াম করুন' | |
| ]; | |
| const wellnessTipsDiv = document.getElementById('wellness-tips'); | |
| if (wellnessTipsDiv) { | |
| const randomTips = tips.sort(() => 0.5 - Math.random()).slice(0, 3); | |
| wellnessTipsDiv.innerHTML = randomTips.map(tip => `<p style="margin-bottom: 10px;">${tip}</p>`).join(''); | |
| } | |
| } | |
| // Utility functions | |
| function showLoader(message = 'লোড হচ্ছে...') { | |
| if (loader) { | |
| loader.style.display = 'block'; | |
| loader.innerHTML = ` | |
| <div class="loader-spinner"></div> | |
| <div>${message}</div> | |
| `; | |
| } | |
| } | |
| function hideLoader() { | |
| if (loader) { | |
| loader.style.display = 'none'; | |
| } | |
| } | |
| function showToast(message, duration = 3000) { | |
| // Remove existing toast | |
| const existingToast = document.querySelector('.toast'); | |
| if (existingToast) { | |
| existingToast.remove(); | |
| } | |
| // Create new toast | |
| const toast = document.createElement('div'); | |
| toast.className = 'toast'; | |
| toast.textContent = message; | |
| document.body.appendChild(toast); | |
| // Show toast | |
| setTimeout(() => toast.classList.add('show'), 100); | |
| // Hide toast | |
| setTimeout(() => { | |
| toast.classList.remove('show'); | |
| setTimeout(() => toast.remove(), 300); | |
| }, duration); | |
| } | |
| // Responsive handling | |
| function handleResize() { | |
| if (canvas.width > 0) { | |
| const maxWidth = Math.min(window.innerWidth - 40, 800); | |
| if (canvas.width > maxWidth) { | |
| const ratio = maxWidth / canvas.width; | |
| canvas.style.width = maxWidth + 'px'; | |
| canvas.style.height = (canvas.height * ratio) + 'px'; | |
| } | |
| } | |
| } | |
| window.addEventListener('resize', handleResize); | |
| window.addEventListener('orientationchange', () => { | |
| setTimeout(handleResize, 500); | |
| }); | |
| // Prevent zoom on double tap | |
| document.addEventListener('touchend', function(event) { | |
| const now = (new Date()).getTime(); | |
| if (now - lastTouchEnd <= 300) { | |
| event.preventDefault(); | |
| } | |
| lastTouchEnd = now; | |
| }, false); | |
| let lastTouchEnd = 0; | |
| // Add some fun interactions | |
| function addSparkleEffect(element) { | |
| element.style.position = 'relative'; | |
| element.style.overflow = 'hidden'; | |
| const sparkle = document.createElement('div'); | |
| sparkle.style.position = 'absolute'; | |
| sparkle.style.top = '50%'; | |
| sparkle.style.left = '50%'; | |
| sparkle.style.width = '4px'; | |
| sparkle.style.height = '4px'; | |
| sparkle.style.background = '#fff'; | |
| sparkle.style.borderRadius = '50%'; | |
| sparkle.style.transform = 'translate(-50%, -50%) scale(0)'; | |
| sparkle.style.animation = 'sparkle 0.6s ease-out forwards'; | |
| sparkle.style.pointerEvents = 'none'; | |
| element.appendChild(sparkle); | |
| setTimeout(() => sparkle.remove(), 600); | |
| } | |
| // Add sparkle animation to CSS (you can add this to your CSS) | |
| const sparkleStyle = document.createElement('style'); | |
| sparkleStyle.textContent = ` | |
| @keyframes sparkle { | |
| 0% { transform: translate(-50%, -50%) scale(0); opacity: 1; } | |
| 50% { transform: translate(-50%, -50%) scale(1); opacity: 1; } | |
| 100% { transform: translate(-50%, -50%) scale(0); opacity: 0; } | |
| } | |
| `; | |
| document.head.appendChild(sparkleStyle); | |
| // Add sparkle effect to buttons | |
| document.querySelectorAll('.btn').forEach(btn => { | |
| btn.addEventListener('click', () => addSparkleEffect(btn)); | |
| }); | |
| console.log('🎭 বাংলা এক্সপ্রেশন অ্যানালাইজার লোড হয়েছে!'); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <script src="https://cdnjs.cloudflare.com/ajax/libs/face-api.js/0.22.2/face-api.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/tensorflow/3.18.0/tf.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@4.17.0/dist/tf.min.js"></script> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| .mobile-app { | |
| touch-action: manipulation; | |
| -webkit-tap-highlight-color: transparent; | |
| } | |
| .bengali-app { | |
| font-family: 'SolaimanLipi', 'Kalpurush', sans-serif; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment