情感分析系统

发布于:2025-06-13 ⋅ 阅读:(19) ⋅ 点赞:(0)

前端代码:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>情感分析系统</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.8/dist/chart.umd.min.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">

    <!-- 自定义 Tailwind 配置 -->
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#3B82F6',
                        secondary: '#10B981',
                        neutral: '#64748B',
                        success: '#10B981',
                        warning: '#F59E0B',
                        danger: '#EF4444',
                        emotion: {
                            angry: '#FF4136',
                            contempt: '#7FDBFF',
                            disgust: '#2ECC40',
                            fear: '#B10DC9',
                            happy: '#FFDC00',
                            natural: '#AAAAAA',
                            sad: '#0074D9',
                            sleepy: '#39CCCC',
                            surprised: '#FF851B'
                        }
                    },
                    fontFamily: {
                        sans: ['Inter', 'system-ui', 'sans-serif'],
                    },
                }
            }
        }
    </script>

    <!-- 自定义工具类 -->
    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto {
                content-visibility: auto;
            }
            .card-hover {
                @apply transition-all duration-300 hover:shadow-lg hover:-translate-y-1;
            }
            .gradient-bg {
                @apply bg-gradient-to-r from-primary to-secondary;
            }
            .emotion-indicator {
                @apply inline-block w-3 h-3 rounded-full mr-2;
            }
            .drop-zone {
                @apply border-2 border-dashed border-gray-300 rounded-lg p-8 text-center hover:border-primary transition-colors;
            }
            .drop-zone-video {
                @apply border-2 border-dashed border-gray-300 rounded-lg p-8 text-center hover:border-secondary transition-colors;
            }
            .timeline-item {
                @apply bg-gray-50 p-4 rounded-lg border border-gray-200 flex items-start;
            }
            .timeline-time {
                @apply bg-primary text-white px-3 py-1 rounded-full text-sm font-medium mr-4;
            }
        }
    </style>
</head>
<body class="bg-gray-50 min-h-screen">
    <!-- 导航栏 -->
    <nav class="gradient-bg text-white shadow-md fixed w-full z-10">
        <div class="container mx-auto px-4 py-4 flex justify-between items-center">
            <div class="flex items-center space-x-3">
                <i class="fa fa-smile-o text-2xl"></i>
                <h1 class="text-xl md:text-2xl font-bold">情感分析系统</h1>
            </div>
            <div class="hidden md:flex items-center space-x-6">
                <a href="#" class="hover:text-gray-200 transition-colors">首页</a>
                <a href="#" class="hover:text-gray-200 transition-colors">使用说明</a>
                <a href="#" class="hover:text-gray-200 transition-colors">关于我们</a>
            </div>
            <button class="md:hidden text-xl">
                <i class="fa fa-bars"></i>
            </button>
        </div>
    </nav>

    <!-- 主内容区 -->
    <main class="container mx-auto px-4 py-8 pt-24">
        <!-- 介绍卡片 -->
        <div class="bg-white rounded-xl shadow-md p-6 mb-8 card-hover">
            <h2 class="text-2xl font-bold text-gray-800 mb-4">面部表情智能分析</h2>
            <p class="text-gray-600 mb-4">
                本系统基于先进的深度学习模型,能够快速准确地识别图片和视频中的面部表情。
                支持分析多种常见表情:愤怒、轻蔑、厌恶、恐惧、快乐、中性、悲伤、困倦和惊讶。
            </p>
            <div class="grid grid-cols-2 md:grid-cols-4 gap-4 mt-6">
                <div class="bg-gray-50 rounded-lg p-4 text-center">
                    <i class="fa fa-image text-primary text-3xl mb-2"></i>
                    <h3 class="font-medium text-gray-800">图片分析</h3>
                    <p class="text-sm text-gray-600">上传图片进行表情识别</p>
                </div>
                <div class="bg-gray-50 rounded-lg p-4 text-center">
                    <i class="fa fa-film text-secondary text-3xl mb-2"></i>
                    <h3 class="font-medium text-gray-800">视频分析</h3>
                    <p class="text-sm text-gray-600">分析视频中的表情变化</p>
                </div>
                <div class="bg-gray-50 rounded-lg p-4 text-center">
                    <i class="fa fa-bar-chart text-warning text-3xl mb-2"></i>
                    <h3 class="font-medium text-gray-800">数据可视化</h3>
                    <p class="text-sm text-gray-600">表情分布与趋势图表</p>
                </div>
                <div class="bg-gray-50 rounded-lg p-4 text-center">
                    <i class="fa fa-lightbulb-o text-success text-3xl mb-2"></i>
                    <h3 class="font-medium text-gray-800">智能推荐</h3>
                    <p class="text-sm text-gray-600">基于表情的内容推荐</p>
                </div>
            </div>
        </div>

        <!-- 图片上传区 -->
        <div class="bg-white rounded-xl shadow-md p-6 mb-8 card-hover">
            <h2 class="text-xl font-bold text-gray-800 mb-4 flex items-center">
                <i class="fa fa-image text-primary mr-2"></i>图片表情分析
            </h2>

            <div class="drop-zone" id="imageDropZone">
                <form id="imageForm" class="space-y-4">
                    <input type="file" id="imageInput" name="image" accept="image/*" class="hidden">

                    <label for="imageInput" class="cursor-pointer block">
                        <div class="flex flex-col items-center">
                            <i class="fa fa-cloud-upload text-4xl text-gray-400 mb-4"></i>
                            <p class="text-gray-600 mb-2">点击或拖拽图片到此处</p>
                            <p class="text-sm text-gray-500">支持 JPG, PNG, GIF 格式</p>
                            <button type="button" id="selectImageBtn" class="mt-4 bg-primary hover:bg-primary/90 text-white font-medium py-2 px-6 rounded-lg transition-all">
                                <i class="fa fa-upload mr-2"></i>选择图片
                            </button>
                        </div>
                    </label>

                    <div id="imagePreview" class="hidden mt-4">
                        <img id="previewImg" src="" alt="预览图片" class="max-w-full h-auto rounded-lg border-2 border-gray-200">
                    </div>

                    <button type="submit" id="analyzeImageBtn" class="mt-4 bg-secondary hover:bg-secondary/90 text-white font-medium py-2 px-6 rounded-lg transition-all hidden">
                        <i class="fa fa-eye mr-2"></i>分析表情
                    </button>
                </form>
            </div>
        </div>

        <!-- 图片分析结果 -->
        <div id="imageResultSection" class="hidden bg-white rounded-xl shadow-md p-6 mb-8 card-hover">
            <h2 class="text-xl font-bold text-gray-800 mb-4 flex items-center">
                <i class="fa fa-check-circle text-success mr-2"></i>分析结果
                <span id="imageAnalysisTime" class="ml-3 text-sm text-gray-500"></span>
            </h2>

            <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
                <!-- 原图 -->
                <div class="md:col-span-1">
                    <h3 class="text-lg font-medium text-gray-700 mb-2">原始图片</h3>
                    <div class="bg-gray-100 rounded-lg overflow-hidden relative">
                        <img id="resultImage" src="" alt="分析结果图片" class="w-full h-auto">
                    </div>
                </div>

                <!-- 检测结果 -->
                <div class="md:col-span-2">
                    <h3 class="text-lg font-medium text-gray-700 mb-2">表情检测结果</h3>
                    <div id="imageDetectionResults" class="space-y-4">
                        <!-- 结果将通过 JavaScript 动态填充 -->
                    </div>
                </div>
            </div>
        </div>

        <!-- 视频上传区 -->
        <div class="bg-white rounded-xl shadow-md p-6 mb-8 card-hover">
            <h2 class="text-xl font-bold text-gray-800 mb-4 flex items-center">
                <i class="fa fa-film text-secondary mr-2"></i>视频表情分析
            </h2>

            <div class="drop-zone-video" id="videoDropZone">
                <form id="videoForm" class="space-y-4">
                    <input type="file" id="videoInput" name="video" accept="video/*" class="hidden">

                    <label for="videoInput" class="cursor-pointer block">
                        <div class="flex flex-col items-center">
                            <i class="fa fa-video-camera text-4xl text-gray-400 mb-4"></i>
                            <p class="text-gray-600 mb-2">点击或拖拽视频到此处</p>
                            <p class="text-sm text-gray-500">支持 MP4, AVI, MOV 格式</p>
                            <button type="button" id="selectVideoBtn" class="mt-4 bg-secondary hover:bg-secondary/90 text-white font-medium py-2 px-6 rounded-lg transition-all">
                                <i class="fa fa-upload mr-2"></i>选择视频
                            </button>
                        </div>
                    </label>

                    <div id="videoPreview" class="hidden mt-4">
                        <video id="previewVideo" controls class="max-w-full h-auto rounded-lg border-2 border-gray-200"></video>
                    </div>

                    <button type="submit" id="analyzeVideoBtn" class="mt-4 bg-secondary hover:bg-secondary/90 text-white font-medium py-2 px-6 rounded-lg transition-all hidden">
                        <i class="fa fa-play-circle mr-2"></i>分析视频
                    </button>
                </form>
            </div>
        </div>

        <!-- 视频分析结果 -->
        <div id="videoResultSection" class="hidden bg-white rounded-xl shadow-md p-6 mb-8 card-hover">
            <h2 class="text-xl font-bold text-gray-800 mb-4 flex items-center">
                <i class="fa fa-film text-secondary mr-2"></i>视频分析结果
                <span id="videoAnalysisTime" class="ml-3 text-sm text-gray-500"></span>
            </h2>

            <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6">
                <!-- 视频预览 -->
                <div class="md:col-span-1">
                    <h3 class="text-lg font-medium text-gray-700 mb-2">原始视频</h3>
                    <div class="bg-gray-100 rounded-lg overflow-hidden">
                        <video id="resultVideo" controls class="w-full h-auto"></video>
                    </div>
                </div>

                <!-- 统计信息 -->
                <div class="md:col-span-2">
                    <h3 class="text-lg font-medium text-gray-700 mb-2">表情统计</h3>

                    <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
                        <div class="bg-gray-50 rounded-lg p-4">
                            <h4 class="font-medium text-gray-800 mb-2">主导表情</h4>
                            <div class="flex items-center justify-center">
                                <div id="dominantEmotion" class="text-3xl font-bold"></div>
                            </div>
                            <div class="mt-3 text-center">
                                <p id="videoRecommendation" class="text-gray-600"></p>
                            </div>
                        </div>

                        <div class="bg-gray-50 rounded-lg p-4">
                            <h4 class="font-medium text-gray-800 mb-2">表情分布</h4>
                            <div class="h-48">
                                <canvas id="emotionDistributionChart"></canvas>
                            </div>
                        </div>
                    </div>
                </div>
            </div>

            <!-- 表情趋势图表 -->
            <div class="mb-6">
                <h3 class="text-lg font-medium text-gray-700 mb-2">表情随时间变化趋势</h3>
                <div class="bg-gray-50 rounded-lg p-4">
                    <div class="h-64">
                        <canvas id="emotionTrendChart"></canvas>
                    </div>
                </div>
            </div>

            <!-- 时间线分析 -->
            <div>
                <h3 class="text-lg font-medium text-gray-700 mb-2">关键表情时间点</h3>
                <div id="emotionTimeline" class="space-y-3">
                    <!-- 时间线将通过 JavaScript 动态填充 -->
                </div>
            </div>
        </div>
    </main>

    <!-- 页脚 -->
    <footer class="bg-gray-800 text-white py-8">
        <div class="container mx-auto px-4">
            <div class="grid grid-cols-1 md:grid-cols-3 gap-8">
                <div>
                    <h3 class="text-xl font-bold mb-4">情感分析系统</h3>
                    <p class="text-gray-400">
                        基于先进深度学习模型的面部表情智能分析系统,
                        能够准确识别图片和视频中的多种表情,为您提供情感分析和内容推荐服务。
                    </p>
                </div>
                <div>
                    <h3 class="text-lg font-bold mb-4">功能导航</h3>
                    <ul class="space-y-2">
                        <li><a href="#" class="text-gray-400 hover:text-white transition-colors">图片分析</a></li>
                        <li><a href="#" class="text-gray-400 hover:text-white transition-colors">视频分析</a></li>
                        <li><a href="#" class="text-gray-400 hover:text-white transition-colors">使用说明</a></li>
                        <li><a href="#" class="text-gray-400 hover:text-white transition-colors">关于我们</a></li>
                    </ul>
                </div>
                <div>
                    <h3 class="text-lg font-bold mb-4">联系我们</h3>
                    <ul class="space-y-2">
                        <li class="flex items-center">
                            <i class="fa fa-envelope-o mr-2 text-gray-400"></i>
                            <a href="mailto:contact@example.com" class="text-gray-400 hover:text-white transition-colors">contact@example.com</a>
                        </li>
                        <li class="flex items-center">
                            <i class="fa fa-phone mr-2 text-gray-400"></i>
                            <span class="text-gray-400">+86 123 4567 8901</span>
                        </li>
                        <li class="flex items-center">
                            <i class="fa fa-map-marker mr-2 text-gray-400"></i>
                            <span class="text-gray-400">北京市海淀区科技园区</span>
                        </li>
                    </ul>
                </div>
            </div>
            <div class="border-t border-gray-700 mt-8 pt-6 text-center text-gray-500">
                <p>© 2023 情感分析系统. 保留所有权利.</p>
            </div>
        </div>
    </footer>

    <!-- JavaScript -->
    <script>
        document.addEventListener('DOMContentLoaded', function() {
            // 图片上传处理
            const imageInput = document.getElementById('imageInput');
            const imageForm = document.getElementById('imageForm');
            const imagePreview = document.getElementById('imagePreview');
            const previewImg = document.getElementById('previewImg');
            const analyzeImageBtn = document.getElementById('analyzeImageBtn');
            const imageResultSection = document.getElementById('imageResultSection');
            const resultImage = document.getElementById('resultImage');
            const imageDetectionResults = document.getElementById('imageDetectionResults');
            const imageAnalysisTime = document.getElementById('imageAnalysisTime');
            const selectImageBtn = document.getElementById('selectImageBtn');
            const imageDropZone = document.getElementById('imageDropZone');

            // 视频上传处理
            const videoInput = document.getElementById('videoInput');
            const videoForm = document.getElementById('videoForm');
            const videoPreview = document.getElementById('videoPreview');
            const previewVideo = document.getElementById('previewVideo');
            const analyzeVideoBtn = document.getElementById('analyzeVideoBtn');
            const videoResultSection = document.getElementById('videoResultSection');
            const resultVideo = document.getElementById('resultVideo');
            const videoAnalysisTime = document.getElementById('videoAnalysisTime');
            const dominantEmotion = document.getElementById('dominantEmotion');
            const videoRecommendation = document.getElementById('videoRecommendation');
            const selectVideoBtn = document.getElementById('selectVideoBtn');
            const videoDropZone = document.getElementById('videoDropZone');

            // 图片上传预览
            imageInput.addEventListener('change', function() {
                handleImageFile(this.files[0]);
            });

            // 视频上传预览
            videoInput.addEventListener('change', function() {
                handleVideoFile(this.files[0]);
            });

            // 选择图片按钮
            selectImageBtn.addEventListener('click', function() {
                imageInput.click();
            });

            // 选择视频按钮
            selectVideoBtn.addEventListener('click', function() {
                videoInput.click();
            });

            // 拖放功能 - 图片
            imageDropZone.addEventListener('dragover', function(e) {
                e.preventDefault();
                this.classList.add('border-primary', 'bg-blue-50');
            });

            imageDropZone.addEventListener('dragleave', function() {
                this.classList.remove('border-primary', 'bg-blue-50');
            });

            imageDropZone.addEventListener('drop', function(e) {
                e.preventDefault();
                this.classList.remove('border-primary', 'bg-blue-50');

                if (e.dataTransfer.files.length) {
                    handleImageFile(e.dataTransfer.files[0]);
                }
            });

            // 拖放功能 - 视频
            videoDropZone.addEventListener('dragover', function(e) {
                e.preventDefault();
                this.classList.add('border-secondary', 'bg-green-50');
            });

            videoDropZone.addEventListener('dragleave', function() {
                this.classList.remove('border-secondary', 'bg-green-50');
            });

            videoDropZone.addEventListener('drop', function(e) {
                e.preventDefault();
                this.classList.remove('border-secondary', 'bg-green-50');

                if (e.dataTransfer.files.length) {
                    handleVideoFile(e.dataTransfer.files[0]);
                }
            });

            // 处理图片文件
            function handleImageFile(file) {
                if (!file) return;

                const validTypes = ['image/jpeg', 'image/png', 'image/gif'];
                if (!validTypes.includes(file.type)) {
                    alert('请上传 JPG, PNG 或 GIF 格式的图片');
                    return;
                }

                const reader = new FileReader();

                reader.onload = function(e) {
                    previewImg.src = e.target.result;
                    imagePreview.classList.remove('hidden');
                    analyzeImageBtn.classList.remove('hidden');
                }

                reader.readAsDataURL(file);
            }

            // 处理视频文件
            function handleVideoFile(file) {
                if (!file) return;

                const validTypes = ['video/mp4', 'video/avi', 'video/quicktime'];
                if (!validTypes.includes(file.type)) {
                    alert('请上传 MP4, AVI 或 MOV 格式的视频');
                    return;
                }

                const videoUrl = URL.createObjectURL(file);
                previewVideo.src = videoUrl;
                videoPreview.classList.remove('hidden');
                analyzeVideoBtn.classList.remove('hidden');
            }

            // 图片分析
            imageForm.addEventListener('submit', function(e) {
                e.preventDefault();

                if (!imageInput.files.length && !previewImg.src) {
                    alert('请选择一张图片');
                    return;
                }

                // 显示加载状态
                imageResultSection.classList.remove('hidden');
                imageDetectionResults.innerHTML = `
                    <div class="flex items-center justify-center py-12">
                        <div class="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-primary"></div>
                        <span class="ml-3 text-gray-600">正在分析表情...</span>
                    </div>
                `;

                // 创建FormData
                const formData = new FormData();
                if (imageInput.files.length) {
                    formData.append('image', imageInput.files[0]);
                } else {
                    // 处理拖放的文件
                    const blob = dataURItoBlob(previewImg.src);
                    formData.append('image', blob, 'uploaded_image.png');
                }

                // 发送请求
                fetch('/analyze-image', {
                    method: 'POST',
                    body: formData
                })
                .then(response => {
                    if (!response.ok) {
                        throw new Error('网络响应异常');
                    }
                    return response.json();
                })
                .then(data => {
                    if (data.success) {
                        // 更新结果图片
                        resultImage.src = data.image_url;

                        // 更新分析时间
                        imageAnalysisTime.textContent = `分析耗时: ${data.inference_time.toFixed(2)}秒`;

                        // 清空结果区域
                        imageDetectionResults.innerHTML = '';

                        // 渲染检测结果
                        if (data.detections.length > 0) {
                            data.detections.forEach((detection, index) => {
                                const confidencePercent = (detection.confidence * 100).toFixed(1);

                                imageDetectionResults.innerHTML += `
                                    <div class="bg-gray-50 p-4 rounded-lg border border-gray-200 card-hover">
                                        <div class="flex justify-between items-center">
                                            <h4 class="font-medium text-lg" style="color: ${detection.color}">
                                                <i class="fa fa-user-circle-o mr-2"></i>人物 #${index + 1}
                                            </h4>
                                            <span class="px-3 py-1 rounded-full bg-gray-100 text-sm">
                                                置信度: ${confidencePercent}%
                                            </span>
                                        </div>

                                        <div class="mt-3 grid grid-cols-2 gap-2">
                                            <div class="bg-white p-3 rounded-lg">
                                                <p class="text-sm text-gray-500">识别表情</p>
                                                <p class="text-xl font-semibold" style="color: ${detection.color}">
                                                    <i class="fa fa-smile-o mr-2"></i>${detection.emotion}
                                                </p>
                                            </div>
                                            <div class="bg-white p-3 rounded-lg">
                                                <p class="text-sm text-gray-500">推荐内容</p>
                                                <p class="text-gray-700">${detection.recommendation}</p>
                                            </div>
                                        </div>

                                        <div class="mt-4">
                                            <p class="text-sm text-gray-500 mb-2">边界框坐标</p>
                                            <div class="grid grid-cols-2 gap-2 text-sm">
                                                <div class="bg-gray-100 p-2 rounded">
                                                    <span class="font-medium">左上: </span>(${Math.round(detection.bbox[0])}, ${Math.round(detection.bbox[1])})
                                                </div>
                                                <div class="bg-gray-100 p-2 rounded">
                                                    <span class="font-medium">右下: </span>(${Math.round(detection.bbox[2])}, ${Math.round(detection.bbox[3])})
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                `;
                            });
                        } else {
                            imageDetectionResults.innerHTML = `
                                <div class="text-center py-12 text-gray-500">
                                    <i class="fa fa-meh-o text-3xl mb-2"></i>
                                    <p>未检测到人脸表情</p>
                                </div>
                            `;
                        }
                    } else {
                        imageDetectionResults.innerHTML = `
                            <div class="text-center py-12 text-red-500">
                                <i class="fa fa-exclamation-triangle text-3xl mb-2"></i>
                                <p>分析失败: ${data.error || '未知错误'}</p>
                            </div>
                        `;
                    }
                })
                .catch(error => {
                    console.error('Error:', error);
                    imageDetectionResults.innerHTML = `
                        <div class="text-center py-12 text-red-500">
                            <i class="fa fa-exclamation-triangle text-3xl mb-2"></i>
                            <p>发生错误: ${error.message || '网络或服务器错误'}</p>
                        </div>
                    `;
                });
            });

            // 视频分析
            videoForm.addEventListener('submit', function(e) {
                e.preventDefault();

                if (!videoInput.files.length && !previewVideo.src) {
                    alert('请选择一个视频');
                    return;
                }

                // 显示加载状态
                videoResultSection.classList.remove('hidden');

                // 清空图表容器
                document.getElementById('emotionDistributionChart').remove();
                document.getElementById('emotionTrendChart').remove();
                document.getElementById('emotionTimeline').innerHTML = '';

                // 创建新的图表容器
                const distributionContainer = document.createElement('canvas');
                distributionContainer.id = 'emotionDistributionChart';
                document.querySelector('#emotionDistributionChart').parentNode.appendChild(distributionContainer);

                const trendContainer = document.createElement('canvas');
                trendContainer.id = 'emotionTrendChart';
                document.querySelector('#emotionTrendChart').parentNode.appendChild(trendContainer);

                // 显示加载状态
                document.getElementById('emotionDistributionChart').parentNode.innerHTML = `
                    <div class="flex items-center justify-center h-full">
                        <div class="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-secondary"></div>
                        <span class="ml-3 text-gray-600">正在分析视频...</span>
                    </div>
                `;

                document.getElementById('emotionTrendChart').parentNode.innerHTML = `
                    <div class="flex items-center justify-center h-full">
                        <div class="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-secondary"></div>
                        <span class="ml-3 text-gray-600">正在分析视频...</span>
                    </div>
                `;

                document.getElementById('emotionTimeline').innerHTML = `
                    <div class="flex items-center justify-center py-6">
                        <div class="animate-spin rounded-full h-8 w-8 border-t-2 border-b-2 border-secondary"></div>
                        <span class="ml-3 text-gray-600">正在生成时间线...</span>
                    </div>
                `;

                // 创建FormData
                const formData = new FormData();
                if (videoInput.files.length) {
                    formData.append('video', videoInput.files[0]);
                } else {
                    // 处理拖放的文件
                    const blob = dataURItoBlob(previewVideo.src);
                    formData.append('video', blob, 'uploaded_video.mp4');
                }

                // 发送请求
                fetch('/analyze-video', {
                    method: 'POST',
                    body: formData
                })
                .then(response => {
                    if (!response.ok) {
                        throw new Error('网络响应异常');
                    }
                    return response.json();
                })
                .then(data => {
                    if (data.success) {
                        // 更新结果视频
                        resultVideo.src = data.video_url;

                        // 更新分析时间
                        videoAnalysisTime.textContent = `分析耗时: ${data.inference_time.toFixed(2)}秒`;

                        // 更新主导表情和推荐
                        dominantEmotion.innerHTML = `
                            <span class="inline-block w-8 h-8 rounded-full mr-2" style="background-color: ${EMOTION_COLORS[data.dominant_emotion] || '#AAAAAA'}"></span>
                            ${data.dominant_emotion}
                        `;
                        videoRecommendation.textContent = data.recommendation;

                        // 渲染表情分布饼图
                        renderDistributionChart(data.emotion_counts);

                        // 渲染表情趋势图
                        renderTrendChart(data.emotion_timeline, data.duration);

                        // 渲染时间线
                        renderTimeline(data.emotion_timeline);
                    } else {
                        // 错误处理
                        document.getElementById('emotionDistributionChart').parentNode.innerHTML = `
                            <div class="text-center py-12 text-red-500">
                                <i class="fa fa-exclamation-triangle text-3xl mb-2"></i>
                                <p>分析失败: ${data.error || '未知错误'}</p>
                            </div>
                        `;
                    }
                })
                .catch(error => {
                    console.error('Error:', error);
                    document.getElementById('emotionDistributionChart').parentNode.innerHTML = `
                        <div class="text-center py-12 text-red-500">
                            <i class="fa fa-exclamation-triangle text-3xl mb-2"></i>
                            <p>发生错误: ${error.message || '网络或服务器错误'}</p>
                        </div>
                    `;
                });
            });

            // 渲染表情分布饼图
            function renderDistributionChart(emotionCounts) {
                const ctx = document.getElementById('emotionDistributionChart').getContext('2d');

                const labels = Object.keys(emotionCounts);
                const data = Object.values(emotionCounts);
                const backgroundColors = labels.map(emotion => EMOTION_COLORS[emotion] || '#CCCCCC');

                new Chart(ctx, {
                    type: 'doughnut',
                    data: {
                        labels: labels,
                        datasets: [{
                            data: data,
                            backgroundColor: backgroundColors,
                            borderWidth: 0
                        }]
                    },
                    options: {
                        responsive: true,
                        maintainAspectRatio: false,
                        plugins: {
                            legend: {
                                position: 'right',
                                labels: {
                                    boxWidth: 12,
                                    padding: 15,
                                    font: {
                                        size: 12
                                    }
                                }
                            }
                        }
                    }
                });
            }

            // 渲染表情趋势图
            function renderTrendChart(emotionTimeline, duration) {
                const ctx = document.getElementById('emotionTrendChart').getContext('2d');

                // 准备数据
                const emotions = Object.keys(EMOTION_CLASSES).map(key => EMOTION_CLASSES[key]);
                const datasets = [];

                emotions.forEach(emotion => {
                    const dataPoints = emotionTimeline.map(point => {
                        return point.emotions.includes(emotion) ? 1 : 0;
                    });

                    datasets.push({
                        label: emotion,
                        data: dataPoints,
                        backgroundColor: EMOTION_COLORS[emotion] + '33',
                        borderColor: EMOTION_COLORS[emotion],
                        borderWidth: 2,
                        pointRadius: 0,
                        tension: 0.3,
                        fill: false
                    });
                });

                // 生成时间标签
                const labels = emotionTimeline.map(point => point.time.toFixed(1) + 's');

                new Chart(ctx, {
                    type: 'line',
                    data: {
                        labels: labels,
                        datasets: datasets
                    },
                    options: {
                        responsive: true,
                        maintainAspectRatio: false,
                        scales: {
                            y: {
                                beginAtZero: true,
                                ticks: {
                                    callback: function(value) {
                                        return value === 1 ? emotion : '';
                                    }
                                }
                            },
                            x: {
                                title: {
                                    display: true,
                                    text: '时间 (秒)'
                                }
                            }
                        },
                        plugins: {
                            legend: {
                                position: 'top',
                            },
                            tooltip: {
                                callbacks: {
                                    label: function(context) {
                                        return context.dataset.label;
                                    }
                                }
                            }
                        }
                    }
                });
            }

            // 渲染时间线
            function renderTimeline(emotionTimeline) {
                const timelineContainer = document.getElementById('emotionTimeline');
                timelineContainer.innerHTML = '';

                emotionTimeline.forEach(point => {
                    const emotionsHtml = point.emotions.map(emotion => {
                        return `<span class="inline-flex items-center mr-3">
                            <span class="emotion-indicator" style="background-color: ${EMOTION_COLORS[emotion]}"></span>
                            ${emotion}
                        </span>`;
                    }).join('');

                    timelineContainer.innerHTML += `
                        <div class="timeline-item">
                            <span class="timeline-time">${point.time.toFixed(1)}秒</span>
                            <div class="flex flex-wrap">
                                ${emotionsHtml}
                            </div>
                        </div>
                    `;
                });
            }

            // 辅助函数:将DataURI转换为Blob
            function dataURItoBlob(dataURI) {
                const byteString = atob(dataURI.split(',')[1]);
                const mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
                const ab = new ArrayBuffer(byteString.length);
                const ia = new Uint8Array(ab);

                for (let i = 0; i < byteString.length; i++) {
                    ia[i] = byteString.charCodeAt(i);
                }

                return new Blob([ab], { type: mimeString });
            }
        });
    </script>
</body>
</html>

网站公告

今日签到

点亮在社区的每一天
去签到