| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683 |
- <!DOCTYPE html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>多模态内容分析平台 | AI智能分析</title>
- <script src="https://cdn.tailwindcss.com"></script>
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
- <style>
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
-
- body {
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
- }
-
- .gradient-bg {
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- }
-
- .card-hover {
- transition: all 0.3s ease;
- }
-
- .card-hover:hover {
- transform: translateY(-4px);
- box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
- }
-
- .loading-spinner {
- border: 3px solid #f3f3f3;
- border-top: 3px solid #667eea;
- border-radius: 50%;
- width: 40px;
- height: 40px;
- animation: spin 1s linear infinite;
- }
-
- @keyframes spin {
- 0% { transform: rotate(0deg); }
- 100% { transform: rotate(360deg); }
- }
-
- .fade-in {
- animation: fadeIn 0.5s ease-in;
- }
-
- @keyframes fadeIn {
- from { opacity: 0; transform: translateY(10px); }
- to { opacity: 1; transform: translateY(0); }
- }
-
- .scene-card {
- background: linear-gradient(to bottom right, #f8fafc, #f1f5f9);
- }
-
- .result-container {
- background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%);
- }
-
- .tab-active {
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- color: white;
- }
-
- .upload-zone {
- border: 2px dashed #cbd5e1;
- transition: all 0.3s ease;
- }
-
- .upload-zone:hover {
- border-color: #667eea;
- background-color: #f8fafc;
- }
-
- .upload-zone.dragover {
- border-color: #667eea;
- background-color: #eef2ff;
- }
-
- /* 三栏布局样式 */
- .sidebar {
- width: 280px;
- height: calc(100vh - 120px);
- overflow-y: auto;
- }
-
- .main-content {
- flex: 1;
- height: calc(100vh - 120px);
- overflow-y: auto;
- }
-
- .config-panel {
- width: 320px;
- height: calc(100vh - 120px);
- overflow-y: auto;
- }
-
- .tree-item {
- cursor: pointer;
- transition: all 0.2s ease;
- }
-
- .tree-item:hover {
- background-color: #f3f4f6;
- }
-
- .tree-item.active {
- background-color: #eef2ff;
- border-left: 3px solid #667eea;
- }
-
- .bucket-header {
- cursor: pointer;
- transition: all 0.2s ease;
- }
-
- .bucket-header:hover {
- background-color: #f9fafb;
- }
- </style>
- </head>
- <body class="bg-gray-50 min-h-screen">
- <!-- Header -->
- <header class="gradient-bg text-white shadow-lg">
- <div class="container mx-auto px-6 py-6">
- <div class="flex items-center justify-between">
- <div class="flex items-center space-x-4">
- <div class="bg-white bg-opacity-20 backdrop-blur-sm rounded-xl p-3">
- <i class="fas fa-brain text-2xl"></i>
- </div>
- <div>
- <h1 class="text-3xl font-bold">多模态智能分析平台</h1>
- <p class="text-sm text-purple-100 mt-1">AI-Powered Multi-Modal Content Analysis</p>
- </div>
- </div>
- <div class="hidden md:flex items-center space-x-6 text-sm">
- <div class="bg-white bg-opacity-20 backdrop-blur-sm rounded-lg px-4 py-2">
- <i class="fas fa-text-width mr-2"></i>文本分析
- </div>
- <div class="bg-white bg-opacity-20 backdrop-blur-sm rounded-lg px-4 py-2">
- <i class="fas fa-image mr-2"></i>图像识别
- </div>
- <div class="bg-white bg-opacity-20 backdrop-blur-sm rounded-lg px-4 py-2">
- <i class="fas fa-video mr-2"></i>视频解析
- </div>
- </div>
- </div>
- </div>
- </header>
- <!-- Main Content - Three Column Layout -->
- <main class="flex h-screen">
- <!-- Left Sidebar - File Navigator -->
- <aside class="sidebar bg-white border-r border-gray-200 p-4">
- <div class="mb-4">
- <h2 class="text-lg font-bold text-gray-800 flex items-center">
- <i class="fas fa-folder-tree mr-2 text-purple-600"></i>
- 文件浏览器
- </h2>
- <button onclick="loadAllBuckets()" class="mt-2 w-full px-3 py-2 bg-purple-600 text-white text-sm rounded-lg hover:bg-purple-700 transition-all">
- <i class="fas fa-sync-alt mr-2"></i>刷新
- </button>
- </div>
-
- <!-- Loading State -->
- <div id="sidebar-loading" class="hidden text-center py-8">
- <div class="loading-spinner mx-auto mb-2" style="width: 30px; height: 30px;"></div>
- <p class="text-sm text-gray-600">加载中...</p>
- </div>
-
- <!-- Bucket Tree -->
- <div id="bucket-tree" class="space-y-2">
- <!-- 动态生成桶和文件 -->
- </div>
-
- <!-- Empty State -->
- <div id="sidebar-empty" class="hidden text-center py-8">
- <i class="fas fa-folder-open text-4xl text-gray-300 mb-2"></i>
- <p class="text-sm text-gray-500">暂无文件</p>
- </div>
- </aside>
- <!-- Center - Preview & Results -->
- <div class="main-content bg-gray-50 p-6">
- <!-- File Preview -->
- <div id="preview-section" class="hidden bg-white rounded-xl shadow-lg p-6 mb-6 fade-in">
- <div class="flex items-center justify-between mb-4">
- <h3 class="text-xl font-bold text-gray-800">
- <i class="fas fa-image mr-2 text-purple-600"></i>文件预览
- </h3>
- <button onclick="clearPreview()" class="text-gray-500 hover:text-red-500">
- <i class="fas fa-times-circle text-xl"></i>
- </button>
- </div>
- <div class="bg-gray-100 rounded-lg p-4 flex items-center justify-center" style="min-height: 300px;">
- <img id="preview-img" class="max-w-full h-auto rounded-lg" style="max-height: 500px;">
- <div id="preview-video-placeholder" class="hidden text-center">
- <i class="fas fa-video text-6xl text-gray-400 mb-4"></i>
- <p class="text-gray-600">视频文件</p>
- <p id="preview-filename" class="text-sm text-gray-500 mt-2"></p>
- </div>
- </div>
- </div>
-
- <!-- Loading State -->
- <div id="loading" class="hidden bg-white rounded-xl shadow-lg p-12 text-center mb-6">
- <div class="loading-spinner mx-auto mb-4"></div>
- <p class="text-lg font-semibold text-gray-700">AI正在分析中...</p>
- <p class="text-sm text-gray-500 mt-2">这可能需要几秒到几分钟,请耐心等待</p>
- </div>
- <!-- Results Section -->
- <div id="results" class="hidden bg-white rounded-xl shadow-lg p-6 fade-in">
- <!-- Content Type Badge -->
- <div class="mb-6">
- <span id="content-type-badge" class="inline-flex items-center px-4 py-2 rounded-full text-sm font-semibold bg-gradient-to-r from-purple-500 to-indigo-600 text-white shadow-lg">
- <i class="fas fa-check-circle mr-2"></i>分析完成
- </span>
- </div>
- <!-- Main Result -->
- <div class="result-container rounded-2xl shadow-xl p-8 mb-8">
- <div class="flex items-center mb-4">
- <div class="bg-purple-100 rounded-full p-3 mr-4">
- <i class="fas fa-sparkles text-purple-600 text-xl"></i>
- </div>
- <h2 class="text-2xl font-bold text-gray-800">分析结果</h2>
- </div>
- <div id="main-result" class="text-gray-700 leading-relaxed text-lg whitespace-pre-wrap"></div>
- </div>
- <!-- Scene Descriptions (for videos) -->
- <div id="scenes-container" class="hidden">
- <div class="flex items-center mb-6">
- <div class="bg-indigo-100 rounded-full p-3 mr-4">
- <i class="fas fa-film text-indigo-600 text-xl"></i>
- </div>
- <h2 class="text-2xl font-bold text-gray-800">镜头分析</h2>
- </div>
- <div id="scenes-list" class="grid grid-cols-1 md:grid-cols-2 gap-6"></div>
- </div>
- <!-- Actions -->
- <div class="mt-8 flex space-x-4">
- <button
- onclick="copyResult()"
- class="flex-1 bg-white border-2 border-purple-600 text-purple-600 font-semibold py-3 rounded-lg hover:bg-purple-50 transition-all"
- >
- <i class="fas fa-copy mr-2"></i>复制结果
- </button>
- <button
- onclick="resetForm()"
- class="flex-1 gradient-bg text-white font-semibold py-3 rounded-lg hover:opacity-90 transition-all"
- >
- <i class="fas fa-redo mr-2"></i>新建分析
- </button>
- </div>
- </div>
- </div>
- <!-- Right Sidebar - Configuration Panel -->
- <aside class="config-panel bg-white border-l border-gray-200 p-4">
- <div class="mb-4">
- <h2 class="text-lg font-bold text-gray-800 flex items-center">
- <i class="fas fa-sliders-h mr-2 text-purple-600"></i>
- 配置面板
- </h2>
- </div>
-
- <!-- 视频处理参数 -->
- <div class="mb-6 bg-purple-50 rounded-lg p-4">
- <h3 class="font-semibold text-gray-700 mb-3 flex items-center">
- <i class="fas fa-video mr-2 text-purple-600"></i>视频参数
- </h3>
- <div class="space-y-3">
- <div>
- <label class="block text-xs text-gray-600 mb-1">每镜头抽帧数</label>
- <input type="number" id="keyframes-per-scene" value="3" min="1" max="10"
- class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 text-sm">
- </div>
- <div>
- <label class="block text-xs text-gray-600 mb-1">抽帧间隔(秒)</label>
- <input type="number" id="extract-interval" value="3" min="1" max="10"
- class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 text-sm">
- </div>
- </div>
- </div>
-
- <!-- 提示词配置 -->
- <div class="bg-indigo-50 rounded-lg p-4">
- <h3 class="font-semibold text-gray-700 mb-3 flex items-center">
- <i class="fas fa-comments mr-2 text-indigo-600"></i>提示词
- </h3>
- <div class="space-y-3">
- <div>
- <label class="block text-xs text-gray-600 mb-1">文本提示词</label>
- <input type="text" id="prompt-text" placeholder="请回答用户的问题。"
- class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 text-xs">
- </div>
- <div>
- <label class="block text-xs text-gray-600 mb-1">图片提示词</label>
- <input type="text" id="prompt-image" placeholder="请描述图像中的主要内容..."
- class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 text-xs">
- </div>
- <div>
- <label class="block text-xs text-gray-600 mb-1">视频提示词</label>
- <input type="text" id="prompt-video" placeholder="请描述镜头中的主要内容..."
- class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 text-xs">
- </div>
- </div>
- </div>
-
- <!-- 分析按钮 -->
- <button
- id="analyze-btn"
- onclick="analyzeSelectedFile()"
- class="w-full mt-6 gradient-bg text-white font-semibold py-3 rounded-lg hover:opacity-90 transition-all shadow-lg disabled:opacity-50 disabled:cursor-not-allowed"
- disabled
- >
- <i class="fas fa-robot mr-2"></i>开始分析
- </button>
- </aside>
- </main>
- <script>
- let selectedFile = null;
- let selectedFileUrl = null;
- let allFiles = [];
- const API_BASE_URL = 'http://127.0.0.1:8000';
- // 页面加载时自动加载文件
- window.onload = function() {
- loadAllBuckets();
- };
- // 切换URL输入区域
- function toggleUrlInput() {
- const content = document.getElementById('url-input-content');
- const icon = document.getElementById('url-input-icon');
- content.classList.toggle('hidden');
- if (content.classList.contains('hidden')) {
- icon.classList.remove('fa-chevron-up');
- icon.classList.add('fa-chevron-down');
- } else {
- icon.classList.remove('fa-chevron-down');
- icon.classList.add('fa-chevron-up');
- }
- }
- // 加载所有桶和文件
- async function loadAllBuckets() {
- const loading = document.getElementById('sidebar-loading');
- const tree = document.getElementById('bucket-tree');
- const empty = document.getElementById('sidebar-empty');
-
- loading.classList.remove('hidden');
- tree.innerHTML = '';
- empty.classList.add('hidden');
-
- try {
- const response = await fetch(`${API_BASE_URL}/minio/files`);
- if (!response.ok) throw new Error('加载失败');
-
- const data = await response.json();
- loading.classList.add('hidden');
-
- if (data.files && data.files.length > 0) {
- allFiles = data.files;
- // 按桶分组(这里目前只有一个桶,但结构支持多桶)
- const buckets = groupFilesByBucket(data.files);
-
- Object.keys(buckets).forEach(bucketName => {
- const bucketElement = createBucketTree(bucketName, buckets[bucketName]);
- tree.appendChild(bucketElement);
- });
- } else {
- empty.classList.remove('hidden');
- }
- } catch (error) {
- loading.classList.add('hidden');
- alert('加载文件失败: ' + error.message);
- }
- }
-
- // 按桶分组文件
- function groupFilesByBucket(files) {
- const buckets = {};
- files.forEach(file => {
- // 从 URL 中提取 bucket 名称
- const match = file.url.match(/\/\/[^\/]+\/([^\/]+)\//);
- const bucketName = match ? match[1] : 'default';
- if (!buckets[bucketName]) {
- buckets[bucketName] = [];
- }
- buckets[bucketName].push(file);
- });
- return buckets;
- }
-
- // 创建桶的树形结构
- function createBucketTree(bucketName, files) {
- const bucketDiv = document.createElement('div');
- bucketDiv.className = 'mb-2';
-
- // 桶头部
- const header = document.createElement('div');
- header.className = 'bucket-header flex items-center justify-between p-2 rounded-lg';
- header.onclick = () => toggleBucket(bucketName);
- header.innerHTML = `
- <div class="flex items-center">
- <i id="bucket-icon-${bucketName}" class="fas fa-chevron-down mr-2 text-gray-500 text-sm transition-transform"></i>
- <i class="fas fa-folder text-yellow-500 mr-2"></i>
- <span class="font-semibold text-sm text-gray-700">${bucketName}</span>
- </div>
- <span class="text-xs text-gray-500">${files.length}</span>
- `;
-
- // 文件列表
- const fileList = document.createElement('div');
- fileList.id = `bucket-files-${bucketName}`;
- fileList.className = 'ml-4 mt-1 space-y-1';
-
- files.forEach(file => {
- const fileItem = createFileTreeItem(file);
- fileList.appendChild(fileItem);
- });
-
- bucketDiv.appendChild(header);
- bucketDiv.appendChild(fileList);
- return bucketDiv;
- }
-
- // 创建文件树项
- function createFileTreeItem(file) {
- const item = document.createElement('div');
- item.className = 'tree-item flex items-center p-2 rounded text-sm';
- item.onclick = () => selectFileFromTree(file, item);
-
- const icon = file.type === 'image' ? 'fa-image' : 'fa-video';
- const iconColor = file.type === 'image' ? 'text-blue-500' : 'text-green-500';
-
- item.innerHTML = `
- <i class="fas ${icon} ${iconColor} mr-2 text-xs"></i>
- <span class="truncate text-gray-700" title="${file.name}">${file.name}</span>
- `;
-
- return item;
- }
-
- // 切换桶的展开/折叠
- function toggleBucket(bucketName) {
- const fileList = document.getElementById(`bucket-files-${bucketName}`);
- const icon = document.getElementById(`bucket-icon-${bucketName}`);
-
- fileList.classList.toggle('hidden');
- if (fileList.classList.contains('hidden')) {
- icon.classList.remove('fa-chevron-down');
- icon.classList.add('fa-chevron-right');
- } else {
- icon.classList.remove('fa-chevron-right');
- icon.classList.add('fa-chevron-down');
- }
- }
-
- // 从树形列表选择文件
- function selectFileFromTree(file, itemElement) {
- // 清除所有active状态
- document.querySelectorAll('.tree-item').forEach(item => {
- item.classList.remove('active');
- });
-
- // 添加active状态
- itemElement.classList.add('active');
-
- selectedFile = file;
- selectedFileUrl = file.url;
-
- // 显示预览
- const previewSection = document.getElementById('preview-section');
- const previewImg = document.getElementById('preview-img');
- const videoPlaceholder = document.getElementById('preview-video-placeholder');
- const previewFilename = document.getElementById('preview-filename');
-
- previewSection.classList.remove('hidden');
-
- if (file.type === 'image') {
- previewImg.src = file.url;
- previewImg.classList.remove('hidden');
- videoPlaceholder.classList.add('hidden');
- } else {
- previewImg.classList.add('hidden');
- videoPlaceholder.classList.remove('hidden');
- previewFilename.textContent = file.name;
- }
-
- // 启用分析按钮
- document.getElementById('analyze-btn').disabled = false;
- }
-
- // 清除预览
- function clearPreview() {
- selectedFile = null;
- selectedFileUrl = null;
- document.getElementById('preview-section').classList.add('hidden');
- document.getElementById('analyze-btn').disabled = true;
-
- // 清除active状态
- document.querySelectorAll('.tree-item').forEach(item => {
- item.classList.remove('active');
- });
- }
-
- function formatFileSize(bytes) {
- if (bytes < 1024) return bytes + ' B';
- if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + ' KB';
- return (bytes / (1024 * 1024)).toFixed(2) + ' MB';
- }
- // API calls
- async function analyzeContent() {
- const content = document.getElementById('content-input').value.trim();
- if (!content) {
- alert('请输入内容');
- return;
- }
-
- // 获取配置参数
- const keyframesPerScene = parseInt(document.getElementById('keyframes-per-scene').value) || 3;
- const extractInterval = parseInt(document.getElementById('extract-interval').value) || 3;
- const promptText = document.getElementById('prompt-text').value.trim() || null;
- const promptImage = document.getElementById('prompt-image').value.trim() || null;
- const promptVideo = document.getElementById('prompt-video').value.trim() || null;
-
- showLoading();
- try {
- const response = await fetch(`${API_BASE_URL}/analyze`, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({
- content: content,
- // 不发送 content_type,强制后端自动检测
- keyframes_per_scene: keyframesPerScene,
- extract_interval: extractInterval,
- prompt_text: promptText,
- prompt_image: promptImage,
- prompt_video: promptVideo
- })
- });
- if (!response.ok) {
- throw new Error('分析失败');
- }
- const data = await response.json();
- displayResults(data);
- } catch (error) {
- alert('分析出错: ' + error.message);
- hideLoading();
- }
- }
- // 分析选中文件
- async function analyzeSelectedFile() {
- if (!selectedFileUrl) {
- alert('请选择文件');
- return;
- }
- // 从右侧配置面板获取参数
- const keyframesPerScene = parseInt(document.getElementById('keyframes-per-scene').value) || 3;
- const extractInterval = parseInt(document.getElementById('extract-interval').value) || 3;
- const promptText = document.getElementById('prompt-text').value.trim() || null;
- const promptImage = document.getElementById('prompt-image').value.trim() || null;
- const promptVideo = document.getElementById('prompt-video').value.trim() || null;
- showLoading();
- try {
- const response = await fetch(`${API_BASE_URL}/analyze`, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({
- content: selectedFileUrl,
- // 不发送 content_type,强制后端自动检测
- keyframes_per_scene: keyframesPerScene,
- extract_interval: extractInterval,
- prompt_text: promptText,
- prompt_image: promptImage,
- prompt_video: promptVideo
- })
- });
- if (!response.ok) {
- throw new Error('分析失败');
- }
- const data = await response.json();
- displayResults(data);
- } catch (error) {
- alert('分析出错: ' + error.message);
- hideLoading();
- }
- }
- // UI updates
- function showLoading() {
- document.getElementById('results').classList.add('hidden');
- document.getElementById('loading').classList.remove('hidden');
- }
- function hideLoading() {
- document.getElementById('loading').classList.add('hidden');
- }
- function displayResults(data) {
- hideLoading();
- // Update badge
- const badge = document.getElementById('content-type-badge');
- const typeIcons = {
- 'text': 'fa-text-width',
- 'image': 'fa-image',
- 'video': 'fa-video'
- };
- badge.innerHTML = `<i class="fas ${typeIcons[data.content_type]} mr-2"></i>${data.content_type.toUpperCase()} 分析完成`;
- // Display main result
- document.getElementById('main-result').textContent = data.result;
- // Display scenes if video
- const scenesContainer = document.getElementById('scenes-container');
- if (data.content_type === 'video' && data.scenes && data.scenes.length > 0) {
- scenesContainer.classList.remove('hidden');
- const scenesList = document.getElementById('scenes-list');
- scenesList.innerHTML = '';
-
- data.scenes.forEach((scene, index) => {
- const sceneCard = document.createElement('div');
- sceneCard.className = 'scene-card rounded-xl p-6 shadow-lg';
- sceneCard.innerHTML = `
- <div class="flex items-center mb-3">
- <div class="bg-indigo-500 text-white rounded-full w-8 h-8 flex items-center justify-center font-bold mr-3">
- ${index + 1}
- </div>
- <h3 class="font-bold text-gray-800">镜头 ${index + 1}</h3>
- </div>
- <p class="text-gray-700 leading-relaxed">${scene}</p>
- `;
- scenesList.appendChild(sceneCard);
- });
- } else {
- scenesContainer.classList.add('hidden');
- }
- document.getElementById('results').classList.remove('hidden');
- }
- function copyResult() {
- const mainResult = document.getElementById('main-result').textContent;
- const scenes = document.getElementById('scenes-container').classList.contains('hidden')
- ? ''
- : '\n\n镜头分析:\n' + Array.from(document.querySelectorAll('#scenes-list .scene-card p'))
- .map((p, i) => `镜头${i+1}: ${p.textContent}`).join('\n');
-
- navigator.clipboard.writeText(mainResult + scenes).then(() => {
- alert('结果已复制到剪贴板');
- });
- }
- function resetForm() {
- document.getElementById('content-input').value = '';
- clearPreview();
- document.getElementById('results').classList.add('hidden');
- }
- </script>
- </body>
- </html>
|