'commit'
This commit is contained in:
319
dsLightRag/static/QwenImage/index.html
Normal file
319
dsLightRag/static/QwenImage/index.html
Normal file
@@ -0,0 +1,319 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>QWenImage - AI图像生成工具</title>
|
||||
<!-- 引入外部资源 -->
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link href="https://cdn.bootcdn.net/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.8/chart.min.js"></script>
|
||||
|
||||
<!-- Tailwind配置 -->
|
||||
<script>
|
||||
tailwind.config = {
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: '#4338ca',
|
||||
secondary: '#8b5cf6',
|
||||
accent: '#ec4899',
|
||||
dark: '#1e293b',
|
||||
light: '#f8fafc'
|
||||
},
|
||||
fontFamily: {
|
||||
inter: ['Inter', 'system-ui', 'sans-serif'],
|
||||
},
|
||||
animation: {
|
||||
'float': 'float 6s ease-in-out infinite',
|
||||
'pulse-slow': 'pulse 4s cubic-bezier(0.4, 0, 0.6, 1) infinite',
|
||||
},
|
||||
keyframes: {
|
||||
float: {
|
||||
'0%, 100%': { transform: 'translateY(0)' },
|
||||
'50%': { transform: 'translateY(-10px)' },
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- 自定义工具类 -->
|
||||
<style type="text/tailwindcss">
|
||||
@layer utilities {
|
||||
.content-auto {
|
||||
content-visibility: auto;
|
||||
}
|
||||
.text-gradient {
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
color: transparent;
|
||||
}
|
||||
.glass-effect {
|
||||
backdrop-filter: blur(10px);
|
||||
background-color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
.glass-effect-dark {
|
||||
backdrop-filter: blur(10px);
|
||||
background-color: rgba(15, 23, 42, 0.7);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="font-inter bg-gradient-to-br from-indigo-50 to-purple-50 dark:from-gray-900 dark:to-gray-800 min-h-screen text-gray-800 dark:text-gray-100 transition-colors duration-300">
|
||||
<!-- 导航栏 -->
|
||||
<header class="fixed top-0 left-0 right-0 z-50 transition-all duration-300">
|
||||
<nav class="glass-effect dark:glass-effect-dark border-b border-gray-200 dark:border-gray-700 py-4 px-6 md:px-12">
|
||||
<div class="container mx-auto flex justify-between items-center">
|
||||
<div class="flex items-center space-x-2">
|
||||
<div class="w-10 h-10 rounded-lg bg-gradient-to-br from-primary to-secondary flex items-center justify-center">
|
||||
<i class="fa fa-paint-brush text-white text-xl"></i>
|
||||
</div>
|
||||
<h1 class="text-xl font-bold bg-gradient-to-r from-primary to-secondary text-gradient">QWenImage</h1>
|
||||
</div>
|
||||
<div class="hidden md:flex items-center space-x-8">
|
||||
<a href="#generator" class="font-medium hover:text-primary dark:hover:text-primary transition-colors">图像生成</a>
|
||||
<a href="#history" class="font-medium hover:text-primary dark:hover:text-primary transition-colors">生成历史</a>
|
||||
<a href="#examples" class="font-medium hover:text-primary dark:hover:text-primary transition-colors">示例作品</a>
|
||||
</div>
|
||||
<div class="flex items-center space-x-4">
|
||||
<button id="themeToggle" class="p-2 rounded-full hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors">
|
||||
<i class="fa fa-sun-o dark:hidden"></i>
|
||||
<i class="fa fa-moon-o hidden dark:block"></i>
|
||||
</button>
|
||||
<button id="mobileMenuBtn" class="md:hidden p-2 rounded-full hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors">
|
||||
<i class="fa fa-bars"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<!-- 移动端菜单 -->
|
||||
<div id="mobileMenu" class="hidden md:hidden glass-effect dark:glass-effect-dark border-b border-gray-200 dark:border-gray-700 py-4 px-6">
|
||||
<div class="flex flex-col space-y-4">
|
||||
<a href="#generator" class="font-medium hover:text-primary dark:hover:text-primary transition-colors py-2">图像生成</a>
|
||||
<a href="#history" class="font-medium hover:text-primary dark:hover:text-primary transition-colors py-2">生成历史</a>
|
||||
<a href="#examples" class="font-medium hover:text-primary dark:hover:text-primary transition-colors py-2">示例作品</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container mx-auto pt-28 pb-16 px-6 md:px-12">
|
||||
<!-- 英雄区域 -->
|
||||
<section class="text-center mb-16 max-w-4xl mx-auto">
|
||||
<h1 class="text-[clamp(2.5rem,5vw,4rem)] font-bold mb-6 leading-tight">
|
||||
<span class="bg-gradient-to-r from-primary via-secondary to-accent text-gradient">AI驱动的图像创作</span>
|
||||
</h1>
|
||||
<p class="text-xl md:text-2xl text-gray-600 dark:text-gray-300 mb-8">
|
||||
只需输入文字描述,即可生成高质量图像,释放您的创造力
|
||||
</p>
|
||||
<div class="flex justify-center">
|
||||
<a href="#generator" class="px-8 py-4 bg-gradient-to-r from-primary to-secondary text-white font-medium rounded-full shadow-lg hover:shadow-xl transform hover:-translate-y-1 transition-all duration-300 flex items-center">
|
||||
<i class="fa fa-magic mr-2"></i>开始创作
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 生成器区域 -->
|
||||
<section id="generator" class="bg-white dark:bg-gray-800 rounded-2xl shadow-xl p-6 md:p-8 mb-16 transform transition-all duration-500 hover:shadow-2xl">
|
||||
<h2 class="text-2xl md:text-3xl font-bold mb-6">图像生成器</h2>
|
||||
|
||||
<div class="space-y-6">
|
||||
<!-- 提示词输入 -->
|
||||
<div class="space-y-3">
|
||||
<label for="prompt" class="block text-sm font-medium text-gray-700 dark:text-gray-300">描述词 <span class="text-red-500">*</span></label>
|
||||
<div class="flex flex-col md:flex-row space-y-3 md:space-y-0 md:space-x-3">
|
||||
<textarea id="prompt" rows="4" placeholder="请输入图像描述词,例如:一只可爱的橘猫在太空漂浮,科幻风格,高清细节,8K分辨率" class="flex-1 px-4 py-3 rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-900 focus:outline-none focus:ring-2 focus:ring-primary resize-none transition-all"> 一副典雅庄重的对联悬挂于厅堂之中,房间是个安静古典的中式布置,桌子上放着一些青花瓷,对联上左书“云端书声琅琅跨山海”,右书“智脉笔影翩翩启星辰”, 横批“东师理想”,字体飘逸,中间挂在一着一副中国风的画作,内容是岳阳楼。
|
||||
</textarea>
|
||||
<div class="flex flex-col space-y-3">
|
||||
<button id="randomPromptBtn" class="px-4 py-3 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 rounded-lg transition-colors flex items-center justify-center">
|
||||
<i class="fa fa-random mr-2"></i>随机提示词
|
||||
</button>
|
||||
<button id="clearPromptBtn" class="px-4 py-3 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 rounded-lg transition-colors flex items-center justify-center">
|
||||
<i class="fa fa-trash mr-2"></i>清空
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-xs text-gray-500 dark:text-gray-400">
|
||||
<i class="fa fa-lightbulb-o text-yellow-500 mr-1"></i>提示:使用更具体的描述词可以获得更符合预期的结果,如指定风格、构图、光线等
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 参数设置 -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div class="space-y-3">
|
||||
<label for="size" class="block text-sm font-medium text-gray-700 dark:text-gray-300">图像尺寸 <span class="text-red-500">*</span></label>
|
||||
<select id="size" class="w-full px-4 py-3 rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-900 focus:outline-none focus:ring-2 focus:ring-primary transition-all">
|
||||
<option value="1328*1328">1328×1328 (正方形)</option>
|
||||
<option value="1024*1536">1024×1536 (竖版)</option>
|
||||
<option value="1536*1024">1536×1024 (横版)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<label for="style" class="block text-sm font-medium text-gray-700 dark:text-gray-300">艺术风格</label>
|
||||
<select id="style" class="w-full px-4 py-3 rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-900 focus:outline-none focus:ring-2 focus:ring-primary transition-all">
|
||||
<option value="default">默认风格</option>
|
||||
<option value="realistic">写实风格</option>
|
||||
<option value="cartoon">卡通风格</option>
|
||||
<option value="anime">动漫风格</option>
|
||||
<option value="watercolor">水彩风格</option>
|
||||
<option value="oil">油画风格</option>
|
||||
<option value="pixel">像素风格</option>
|
||||
<option value="cyberpunk">赛博朋克</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 高级选项 (默认折叠) -->
|
||||
<div class="border-t border-gray-200 dark:border-gray-700 pt-6">
|
||||
<button id="advancedOptionsToggle" class="flex items-center text-gray-600 dark:text-gray-300 hover:text-primary dark:hover:text-primary transition-colors">
|
||||
<i class="fa fa-chevron-down mr-2 transition-transform duration-300"></i>
|
||||
<span>高级选项</span>
|
||||
</button>
|
||||
|
||||
<div id="advancedOptions" class="hidden mt-6 grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div class="space-y-3">
|
||||
<label for="negativePrompt" class="block text-sm font-medium text-gray-700 dark:text-gray-300">负面提示词</label>
|
||||
<input type="text" id="negativePrompt" placeholder="不需要的元素,例如:模糊,低质量,变形" class="w-full px-4 py-3 rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-900 focus:outline-none focus:ring-2 focus:ring-primary transition-all">
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<label for="guidanceScale" class="block text-sm font-medium text-gray-700 dark:text-gray-300">引导力度 (0-20)</label>
|
||||
<input type="range" id="guidanceScale" min="0" max="20" value="7" class="w-full h-2 bg-gray-200 dark:bg-gray-700 rounded-lg appearance-none cursor-pointer accent-primary">
|
||||
<div class="flex justify-between text-xs text-gray-500 dark:text-gray-400">
|
||||
<span>更具创意</span>
|
||||
<span id="guidanceScaleValue">7</span>
|
||||
<span>更贴合描述</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 生成按钮 -->
|
||||
<div class="pt-4 flex justify-end">
|
||||
<button id="generateBtn" class="px-8 py-4 bg-gradient-to-r from-primary to-secondary text-white font-medium rounded-lg shadow-lg hover:shadow-xl transform hover:-translate-y-1 transition-all duration-300 flex items-center">
|
||||
<i class="fa fa-magic mr-2"></i>生成图像
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<div id="loadingState" class="hidden py-8 flex flex-col items-center justify-center text-center">
|
||||
<div class="w-16 h-16 border-4 border-primary border-t-transparent rounded-full animate-spin mb-4"></div>
|
||||
<h3 class="text-xl font-medium mb-2">正在生成图像</h3>
|
||||
<p class="text-gray-600 dark:text-gray-300 mb-6">请稍候,这可能需要几秒钟时间...</p>
|
||||
<div class="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2.5 mb-2">
|
||||
<div id="progressBar" class="bg-primary h-2.5 rounded-full transition-all duration-300" style="width: 0%"></div>
|
||||
</div>
|
||||
<p id="progressText" class="text-sm text-gray-500 dark:text-gray-400">进度: 0%</p>
|
||||
</div>
|
||||
|
||||
<!-- 错误状态 -->
|
||||
<div id="errorState" class="hidden py-6 px-6 bg-red-50 dark:bg-red-900/30 border border-red-200 dark:border-red-800 rounded-lg">
|
||||
<div class="flex items-start">
|
||||
<i class="fa fa-exclamation-circle text-red-500 mt-1 mr-4 text-xl"></i>
|
||||
<div>
|
||||
<h3 class="text-lg font-medium text-red-800 dark:text-red-300 mb-1">生成失败</h3>
|
||||
<p id="errorMessage" class="text-red-700 dark:text-red-400">请检查您的描述词并重试</p>
|
||||
<button id="retryBtn" class="mt-3 text-sm text-primary hover:text-primary/80 dark:text-primary dark:hover:text-primary/80 transition-colors">
|
||||
<i class="fa fa-refresh mr-1"></i>重试
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 结果展示 -->
|
||||
<div id="resultState" class="hidden mt-8">
|
||||
<h3 class="text-xl font-medium mb-4">生成结果</h3>
|
||||
<div class="bg-gray-50 dark:bg-gray-900 rounded-xl p-4 md:p-6 border border-gray-200 dark:border-gray-700">
|
||||
<div id="resultImageContainer" class="flex justify-center mb-6">
|
||||
<img id="resultImage" src="" alt="生成的图像" class="max-w-full h-auto rounded-lg shadow-md transition-all duration-500 hover:shadow-xl">
|
||||
</div>
|
||||
<div class="flex flex-wrap justify-center gap-4">
|
||||
<button id="downloadBtn" class="px-4 py-2 bg-primary hover:bg-primary/90 text-white rounded-lg transition-all flex items-center">
|
||||
<i class="fa fa-download mr-2"></i>下载
|
||||
</button>
|
||||
<button id="regenerateBtn" class="px-4 py-2 border border-primary text-primary hover:bg-primary/10 rounded-lg transition-all flex items-center">
|
||||
<i class="fa fa-refresh mr-2"></i>重新生成
|
||||
</button>
|
||||
<button id="saveToHistoryBtn" class="px-4 py-2 border border-gray-300 dark:border-gray-600 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-all flex items-center">
|
||||
<i class="fa fa-bookmark-o mr-2"></i>保存到历史
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 示例作品 -->
|
||||
<section id="examples" class="mb-16">
|
||||
<h2 class="text-2xl md:text-3xl font-bold mb-6">示例作品</h2>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<!-- 示例1 -->
|
||||
<div class="bg-white dark:bg-gray-800 rounded-xl overflow-hidden shadow-lg transition-all duration-300 hover:shadow-xl group">
|
||||
<div class="relative overflow-hidden">
|
||||
<img src="https://picsum.photos/id/237/600/400" alt="示例图像" class="w-full h-60 object-cover transition-transform duration-500 group-hover:scale-110">
|
||||
<div class="absolute inset-0 bg-gradient-to-t from-black/70 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex items-end">
|
||||
<div class="p-4 text-white">
|
||||
<p class="font-medium text-sm truncate">可爱小狗,卡通风格</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 示例2 -->
|
||||
<div class="bg-white dark:bg-gray-800 rounded-xl overflow-hidden shadow-lg transition-all duration-300 hover:shadow-xl group">
|
||||
<div class="relative overflow-hidden">
|
||||
<img src="https://picsum.photos/id/1/600/400" alt="示例图像" class="w-full h-60 object-cover transition-transform duration-500 group-hover:scale-110">
|
||||
<div class="absolute inset-0 bg-gradient-to-t from-black/70 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex items-end">
|
||||
<div class="p-4 text-white">
|
||||
<p class="font-medium text-sm truncate">山间湖泊,写实风格</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 示例3 -->
|
||||
<div class="bg-white dark:bg-gray-800 rounded-xl overflow-hidden shadow-lg transition-all duration-300 hover:shadow-xl group">
|
||||
<div class="relative overflow-hidden">
|
||||
<img src="https://picsum.photos/id/20/600/400" alt="示例图像" class="w-full h-60 object-cover transition-transform duration-500 group-hover:scale-110">
|
||||
<div class="absolute inset-0 bg-gradient-to-t from-black/70 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex items-end">
|
||||
<div class="p-4 text-white">
|
||||
<p class="font-medium text-sm truncate">未来城市,赛博朋克风格</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 历史记录 -->
|
||||
<section id="history" class="mb-16">
|
||||
<h2 class="text-2xl md:text-3xl font-bold mb-6">生成历史</h2>
|
||||
<div id="historyContainer" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<!-- 历史记录会通过JS动态填充 -->
|
||||
<div class="text-center py-12 text-gray-500 dark:text-gray-400 col-span-full">
|
||||
<i class="fa fa-history text-4xl mb-4"></i>
|
||||
<p>暂无生成历史</p>
|
||||
<p class="text-sm mt-2">生成图像后,历史记录将显示在这里</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer class="bg-white dark:bg-gray-800 border-t border-gray-200 dark:border-gray-700 py-8">
|
||||
<div class="container mx-auto px-6 md:px-12">
|
||||
<div class="flex flex-col md:flex-row justify-between items-center">
|
||||
<div class="flex items-center space-x-2 mb-4 md:mb-0">
|
||||
<div class="w-8 h-8 rounded-lg bg-gradient-to-br from-primary to-secondary flex items-center justify-center">
|
||||
<i class="fa fa-paint-brush text-white text-sm"></i>
|
||||
</div>
|
||||
<h2 class="text-lg font-bold bg-gradient-to-r from-primary to-secondary text-gradient">QWenImage</h2>
|
||||
</div>
|
||||
<div class="text-gray-600 dark:text-gray-300 text-sm">
|
||||
© 2023 QWenImage AI. 保留所有权利
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- JavaScript -->
|
||||
<script src="qwen-image.js"></script>
|
||||
</body>
|
||||
</html>
|
306
dsLightRag/static/QwenImage/qwen-image.js
Normal file
306
dsLightRag/static/QwenImage/qwen-image.js
Normal file
@@ -0,0 +1,306 @@
|
||||
// DOM元素
|
||||
const elements = {
|
||||
// 主题切换
|
||||
themeToggle: document.getElementById('themeToggle'),
|
||||
// 移动端菜单
|
||||
mobileMenuBtn: document.getElementById('mobileMenuBtn'),
|
||||
mobileMenu: document.getElementById('mobileMenu'),
|
||||
// 高级选项切换
|
||||
advancedOptionsToggle: document.getElementById('advancedOptionsToggle'),
|
||||
advancedOptions: document.getElementById('advancedOptions'),
|
||||
// 生成器元素
|
||||
prompt: document.getElementById('prompt'),
|
||||
size: document.getElementById('size'),
|
||||
style: document.getElementById('style'),
|
||||
negativePrompt: document.getElementById('negativePrompt'),
|
||||
guidanceScale: document.getElementById('guidanceScale'),
|
||||
guidanceScaleValue: document.getElementById('guidanceScaleValue'),
|
||||
generateBtn: document.getElementById('generateBtn'),
|
||||
randomPromptBtn: document.getElementById('randomPromptBtn'),
|
||||
clearPromptBtn: document.getElementById('clearPromptBtn'),
|
||||
// 状态元素
|
||||
loadingState: document.getElementById('loadingState'),
|
||||
progressBar: document.getElementById('progressBar'),
|
||||
progressText: document.getElementById('progressText'),
|
||||
errorState: document.getElementById('errorState'),
|
||||
errorMessage: document.getElementById('errorMessage'),
|
||||
resultState: document.getElementById('resultState'),
|
||||
resultImage: document.getElementById('resultImage'),
|
||||
// 结果操作按钮
|
||||
retryBtn: document.getElementById('retryBtn'),
|
||||
downloadBtn: document.getElementById('downloadBtn'),
|
||||
regenerateBtn: document.getElementById('regenerateBtn'),
|
||||
saveToHistoryBtn: document.getElementById('saveToHistoryBtn'),
|
||||
// 历史记录
|
||||
historyContainer: document.getElementById('historyContainer')
|
||||
};
|
||||
|
||||
// 示例提示词库
|
||||
const examplePrompts = [
|
||||
"一副典雅庄重的对联悬挂于厅堂之中,房间是个安静古典的中式布置,桌子上放着一些青花瓷,对联上左书“云端书声琅琅跨山海”,右书“智脉笔影翩翩启星辰”, 横批“东师理想”,字体飘逸,中间挂在一着一副中国风的画作,内容是岳阳楼。",
|
||||
"未来城市的夜景,赛博朋克风格,霓虹灯,雨天,反射效果",
|
||||
"一片宁静美丽的松林,阳光透过树叶,雾气弥漫,油画风格",
|
||||
"一个穿着中世纪盔甲的骑士,站在山顶上,背景是龙和城堡",
|
||||
"海底世界,五彩斑斓的珊瑚和鱼群,梦幻光影效果",
|
||||
"一只戴着宇航员头盔的柴犬,站在火星表面,日落时分"
|
||||
];
|
||||
|
||||
// 初始化函数
|
||||
function init() {
|
||||
// 初始化主题
|
||||
initTheme();
|
||||
// 加载历史记录
|
||||
// loadHistory(); // 移除未定义函数调用
|
||||
// 绑定事件监听器
|
||||
bindEventListeners();
|
||||
}
|
||||
|
||||
// 获取随机提示词
|
||||
function getRandomPrompt() {
|
||||
return examplePrompts[Math.floor(Math.random() * examplePrompts.length)];
|
||||
}
|
||||
|
||||
// 初始化主题
|
||||
function initTheme() {
|
||||
// 检查本地存储
|
||||
const savedTheme = localStorage.getItem('theme');
|
||||
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
|
||||
// 设置初始主题
|
||||
if (savedTheme === 'dark' || (!savedTheme && prefersDark)) {
|
||||
document.documentElement.classList.add('dark');
|
||||
}
|
||||
}
|
||||
|
||||
// 切换主题
|
||||
function toggleTheme() {
|
||||
document.documentElement.classList.toggle('dark');
|
||||
const isDark = document.documentElement.classList.contains('dark');
|
||||
localStorage.setItem('theme', isDark ? 'dark' : 'light');
|
||||
}
|
||||
|
||||
// 切换移动端菜单
|
||||
function toggleMobileMenu() {
|
||||
elements.mobileMenu.classList.toggle('hidden');
|
||||
}
|
||||
|
||||
// 切换高级选项
|
||||
function toggleAdvancedOptions() {
|
||||
elements.advancedOptions.classList.toggle('hidden');
|
||||
const icon = elements.advancedOptionsToggle.querySelector('i');
|
||||
icon.classList.toggle('rotate-180');
|
||||
}
|
||||
|
||||
// 更新引导力度显示
|
||||
function updateGuidanceScale() {
|
||||
elements.guidanceScaleValue.textContent = elements.guidanceScale.value;
|
||||
}
|
||||
|
||||
// 显示加载状态
|
||||
function showLoadingState() {
|
||||
elements.generateBtn.disabled = true;
|
||||
elements.loadingState.classList.remove('hidden');
|
||||
elements.errorState.classList.add('hidden');
|
||||
elements.resultState.classList.add('hidden');
|
||||
}
|
||||
|
||||
// 更新进度
|
||||
function updateProgress(percent) {
|
||||
elements.progressBar.style.width = `${percent}%`;
|
||||
elements.progressText.textContent = `进度: ${percent}%`;
|
||||
}
|
||||
|
||||
// 显示错误状态
|
||||
function showErrorState(message) {
|
||||
elements.loadingState.classList.add('hidden');
|
||||
elements.errorState.classList.remove('hidden');
|
||||
elements.errorMessage.textContent = message;
|
||||
elements.generateBtn.disabled = false;
|
||||
}
|
||||
|
||||
// 显示结果状态
|
||||
function showResultState(imageUrl) {
|
||||
elements.loadingState.classList.add('hidden');
|
||||
elements.resultState.classList.remove('hidden');
|
||||
elements.resultImage.src = imageUrl;
|
||||
elements.generateBtn.disabled = false;
|
||||
}
|
||||
|
||||
// 生成图像
|
||||
async function generateImage() {
|
||||
const prompt = elements.prompt.value.trim();
|
||||
|
||||
// 验证输入
|
||||
if (!prompt) {
|
||||
showErrorState('请输入图像描述词');
|
||||
return;
|
||||
}
|
||||
|
||||
// 显示加载状态
|
||||
showLoadingState();
|
||||
updateProgress(10);
|
||||
|
||||
try {
|
||||
// 构建请求数据
|
||||
const requestData = {
|
||||
prompt: prompt,
|
||||
size: elements.size.value,
|
||||
};
|
||||
|
||||
// 模拟进度更新
|
||||
const progressInterval = setInterval(() => {
|
||||
const currentWidth = parseInt(elements.progressBar.style.width);
|
||||
if (currentWidth < 90) {
|
||||
updateProgress(currentWidth + Math.random() * 10);
|
||||
}
|
||||
}, 500);
|
||||
|
||||
// 调用API生成图像 (参考TestQWen3Image.py中的接口)
|
||||
console.log('请求URL:', '/api/qwenImage/generate');
|
||||
console.log('请求参数:', JSON.stringify(requestData, null, 2));
|
||||
const response = await fetch('/api/qwenImage/generate', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(requestData)
|
||||
});
|
||||
|
||||
clearInterval(progressInterval);
|
||||
updateProgress(100);
|
||||
|
||||
if (!response.ok) {
|
||||
// 尝试解析错误响应
|
||||
const errorDetails = await response.json().catch(() => ({}));
|
||||
const errorMsg = errorDetails.message || `API请求失败: ${response.status} ${response.statusText}`;
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
// 检查API返回状态 (参考TestQWen3Image.py中的响应处理)
|
||||
if (result.code !== 200 || !result.data || !result.data.images || result.data.images.length === 0) {
|
||||
throw new Error(result.message || '未获取到生成的图像');
|
||||
}
|
||||
|
||||
// 显示结果
|
||||
showResultState(result.data.images[0]);
|
||||
|
||||
} catch (error) {
|
||||
console.error('生成图像失败:', error);
|
||||
showErrorState(error.message || '生成图像时发生错误,请重试');
|
||||
}
|
||||
}
|
||||
|
||||
// 下载图像
|
||||
function downloadImage() {
|
||||
if (!elements.resultImage.src) return;
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.href = elements.resultImage.src;
|
||||
link.download = `qwen-image-${new Date().getTime()}.png`;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
}
|
||||
|
||||
// 保存到历史记录
|
||||
function saveToHistory() {
|
||||
if (!elements.resultImage.src || !elements.prompt.value.trim()) return;
|
||||
|
||||
const historyItem = {
|
||||
id: Date.now(),
|
||||
prompt: elements.prompt.value.trim(),
|
||||
size: elements.size.value,
|
||||
style: elements.style.value,
|
||||
imageUrl: elements.resultImage.src,
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
|
||||
// 获取现有历史记录
|
||||
const history = JSON.parse(localStorage.getItem('qwenImageHistory') || '[]');
|
||||
// 添加新记录
|
||||
history.unshift(historyItem);
|
||||
// 限制历史记录数量
|
||||
if (history.length > 20) history.pop();
|
||||
// 保存到本地存储
|
||||
localStorage.setItem('qwenImageHistory', JSON.stringify(history));
|
||||
// 更新历史记录显示
|
||||
renderHistory();
|
||||
|
||||
// 显示提示
|
||||
alert('已保存到历史记录');
|
||||
}
|
||||
|
||||
// 渲染历史记录
|
||||
function renderHistory() {
|
||||
const history = JSON.parse(localStorage.getItem('qwenImageHistory') || '[]');
|
||||
|
||||
if (history.length === 0) {
|
||||
elements.historyContainer.innerHTML = `
|
||||
<div class="text-center py-12 text-gray-500 dark:text-gray-400 col-span-full">
|
||||
<i class="fa fa-history text-4xl mb-4"></i>
|
||||
<p>暂无生成历史</p>
|
||||
<p class="text-sm mt-2">生成图像后,历史记录将显示在这里</p>
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
// 生成历史记录项
|
||||
elements.historyContainer.innerHTML = history.map(item => `
|
||||
<div class="bg-white dark:bg-gray-800 rounded-xl overflow-hidden shadow-md transition-all duration-300 hover:shadow-lg">
|
||||
<img src="${item.imageUrl}" alt="${item.prompt.substring(0, 30)}..." class="w-full h-48 object-cover">
|
||||
<div class="p-3">
|
||||
<p class="text-sm font-medium truncate" title="${item.prompt}">${item.prompt}</p>
|
||||
<div class="flex justify-between items-center mt-2 text-xs text-gray-500 dark:text-gray-400">
|
||||
<span>${item.size}</span>
|
||||
<span>${new Date(item.timestamp).toLocaleString()}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
// 绑定事件监听器
|
||||
function bindEventListeners() {
|
||||
// 主题切换
|
||||
elements.themeToggle.addEventListener('click', toggleTheme);
|
||||
|
||||
// 移动端菜单
|
||||
elements.mobileMenuBtn.addEventListener('click', toggleMobileMenu);
|
||||
|
||||
// 高级选项切换
|
||||
elements.advancedOptionsToggle.addEventListener('click', toggleAdvancedOptions);
|
||||
|
||||
// 引导力度滑块
|
||||
elements.guidanceScale.addEventListener('input', updateGuidanceScale);
|
||||
|
||||
// 随机提示词
|
||||
elements.randomPromptBtn.addEventListener('click', () => {
|
||||
elements.prompt.value = getRandomPrompt();
|
||||
});
|
||||
|
||||
// 清空提示词
|
||||
elements.clearPromptBtn.addEventListener('click', () => {
|
||||
elements.prompt.value = '';
|
||||
});
|
||||
|
||||
// 生成按钮
|
||||
elements.generateBtn.addEventListener('click', generateImage);
|
||||
|
||||
// 重试按钮
|
||||
elements.retryBtn.addEventListener('click', generateImage);
|
||||
|
||||
// 重新生成按钮
|
||||
elements.regenerateBtn.addEventListener('click', generateImage);
|
||||
|
||||
// 下载按钮
|
||||
elements.downloadBtn.addEventListener('click', downloadImage);
|
||||
|
||||
// 保存到历史
|
||||
elements.saveToHistoryBtn.addEventListener('click', saveToHistory);
|
||||
}
|
||||
|
||||
// 页面加载完成后初始化
|
||||
document.addEventListener('DOMContentLoaded', init);
|
Reference in New Issue
Block a user