import os import json from dotenv import load_dotenv from cozepy import Coze, TokenAuth, COZE_CN_BASE_URL from flask import Flask, request, jsonify, send_file from flask_cors import CORS # 加载环境变量 load_dotenv() app = Flask(__name__) CORS(app)# 允许跨域请求# 调用工作流生成视频defcreate_video(animal_description):try: api_token = os.getenv('COZE_API_TOKEN') workflow_id = os.getenv('WORKFLOW_ID')# 初始化coze客户端 coze = Coze( auth=TokenAuth(token=api_token), base_url=COZE_CN_BASE_URL )# 执行工作流 workflow = coze.workflows.runs.create( workflow_id=workflow_id, parameters={"input": animal_description })# 接收返回的内容 video_url = json.loads(workflow.data)['output']return video_url except Exception as e:returnNone# 声明接口路由@app.route("/generate-video", methods=['POST'])defgenerate_video():# 获取请求参数 data = request.get_json() animal_description = data.get('input','').strip() video_url = create_video(animal_description)return jsonify({'success':True,'video_url': video_url,'description': animal_description })# 访问首页@app.route('/')defindex():return send_file('index.html')if __name__ =='__main__': app.run(debug=True, host='0.0.0.0', port=5000)
<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>动物世界视频生成器</title><linkrel="stylesheet"href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"><style>*{margin: 0;padding: 0;box-sizing: border-box;font-family:'Segoe UI','Microsoft YaHei', sans-serif;}body{background:linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);background-size: 400% 400%;animation: gradientBG 15s ease infinite;min-height: 100vh;color: #333;padding: 20px;}@keyframes gradientBG{0%{background-position: 0% 50%;}50%{background-position: 100% 50%;}100%{background-position: 0% 50%;}}.container{max-width: 1200px;margin: 0 auto;padding: 20px;}.header{text-align: center;margin-bottom: 30px;color: white;text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);}.header h1{font-size: 3rem;margin-bottom: 10px;background:linear-gradient(45deg, #FFD700, #FF8C00);-webkit-background-clip: text;background-clip: text;color: transparent;}.header p{font-size: 1.2rem;max-width: 800px;margin: 0 auto;line-height: 1.6;color:rgba(255, 255, 255, 0.9);}.main-content{display: flex;flex-direction: column;gap: 30px;}@media(min-width: 992px){.main-content{flex-direction: row;}}.input-section, .output-section{background:rgba(255, 255, 255, 0.95);border-radius: 20px;padding: 30px;box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);backdrop-filter:blur(10px);flex: 1;}.input-section{display: flex;flex-direction: column;}.section-title{display: flex;align-items: center;gap: 10px;font-size: 1.8rem;margin-bottom: 20px;color: #2c3e50;padding-bottom: 10px;border-bottom: 2px solid #3498db;}.section-title i{color: #3498db;}.animal-description{flex: 1;min-height: 200px;padding: 20px;font-size: 1.1rem;border: 2px solid #e0e0e0;border-radius: 15px;resize: vertical;margin-bottom: 20px;transition: border 0.3s;}.animal-description:focus{outline: none;border-color: #3498db;box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.2);}.examples{margin-top: 15px;margin-bottom: 25px;}.examples h3{color: #2c3e50;margin-bottom: 10px;font-size: 1.2rem;}.example-tags{display: flex;flex-wrap: wrap;gap: 10px;}.example-tag{background: #e3f2fd;padding: 8px 16px;border-radius: 20px;cursor: pointer;transition: all 0.3s;border: 1px solid #bbdefb;font-size: 0.95rem;}.example-tag:hover{background: #bbdefb;transform:translateY(-3px);box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);}.buttons{display: flex;gap: 15px;margin-top: 20px;}.btn{padding: 15px 30px;border: none;border-radius: 12px;font-size: 1.1rem;font-weight: 600;cursor: pointer;display: flex;align-items: center;justify-content: center;gap: 10px;transition: all 0.3s;flex: 1;}.generate-btn{background:linear-gradient(45deg, #3498db, #2ecc71);color: white;}.generate-btn:hover{transform:translateY(-3px);box-shadow: 0 7px 15px rgba(52, 152, 219, 0.4);}.generate-btn:active{transform:translateY(0);}.clear-btn{background: #f5f5f5;color: #555;border: 1px solid #ddd;}.clear-btn:hover{background: #e0e0e0;transform:translateY(-3px);}.output-section{display: flex;flex-direction: column;}.video-container{flex: 1;display: flex;align-items: center;justify-content: center;background: #f8f9fa;border-radius: 15px;overflow: hidden;margin-bottom: 20px;min-height: 300px;position: relative;}.video-placeholder{text-align: center;color: #7f8c8d;padding: 40px;}.video-placeholder i{font-size: 4rem;margin-bottom: 20px;color: #bdc3c7;}.video-placeholder h3{font-size: 1.5rem;margin-bottom: 10px;}.video-player{width: 100%;height: 100%;border-radius: 15px;}.loading{position: absolute;top: 0;left: 0;width: 100%;height: 100%;background:rgba(255, 255, 255, 0.9);display: flex;flex-direction: column;align-items: center;justify-content: center;z-index: 10;border-radius: 15px;}.spinner{width: 70px;height: 70px;border: 8px solid #f3f3f3;border-top: 8px solid #3498db;border-radius: 50%;animation: spin 1.5s linear infinite;margin-bottom: 20px;}@keyframes spin{0%{transform:rotate(0deg);}100%{transform:rotate(360deg);}}.video-info{background: #f8f9fa;padding: 20px;border-radius: 15px;margin-top: 20px;}.video-info h3{color: #2c3e50;margin-bottom: 10px;display: flex;align-items: center;gap: 10px;}.description-text{line-height: 1.6;color: #555;}.action-buttons{display: flex;gap: 15px;margin-top: 20px;}.action-btn{padding: 12px 25px;border-radius: 10px;border: none;font-size: 1rem;font-weight: 600;cursor: pointer;display: flex;align-items: center;justify-content: center;gap: 10px;transition: all 0.3s;flex: 1;}.download-btn{background:linear-gradient(45deg, #2ecc71, #27ae60);color: white;}.download-btn:hover{transform:translateY(-3px);box-shadow: 0 5px 15px rgba(46, 204, 113, 0.4);}.share-btn{background:linear-gradient(45deg, #9b59b6, #8e44ad);color: white;}.share-btn:hover{transform:translateY(-3px);box-shadow: 0 5px 15px rgba(155, 89, 182, 0.4);}.footer{text-align: center;margin-top: 40px;color:rgba(255, 255, 255, 0.8);font-size: 0.9rem;padding: 20px;}.footer a{color: #FFD700;text-decoration: none;}.footer a:hover{text-decoration: underline;}.notification{position: fixed;top: 30px;right: 30px;padding: 15px 25px;border-radius: 10px;color: white;font-weight: 600;box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);z-index: 1000;display: flex;align-items: center;gap: 10px;transform:translateX(150%);transition: transform 0.5s ease;}.notification.show{transform:translateX(0);}.success{background:linear-gradient(45deg, #2ecc71, #27ae60);}.error{background:linear-gradient(45deg, #e74c3c, #c0392b);}@media(max-width: 768px){.header h1{font-size: 2.2rem;}.input-section, .output-section{padding: 20px;}.buttons, .action-buttons{flex-direction: column;}.btn, .action-btn{width: 100%;}}</style></head><body><divclass="container"><divclass="header"><h1><iclass="fas fa-paw"></i> 动物世界视频生成器</h1><p>描述你想象中的动物,AI将为你生成独特的动物视频。从可爱的小猫到神奇的神兽,一切皆有可能!</p></div><divclass="main-content"><divclass="input-section"><divclass="section-title"><iclass="fas fa-edit"></i><h2>描述你的动物</h2></div><textareaclass="animal-description"id="animalDescription"placeholder="描述你想要生成的动物视频...例如:一只蓝色的狐狸在雪地中奔跑,毛发如丝般顺滑,眼睛像蓝宝石一样闪耀。"></textarea><divclass="examples"><h3>试试这些例子:</h3><divclass="example-tags"><divclass="example-tag"data-example="一只会说话的熊猫,戴着草帽,在竹林中跳舞">会说话的熊猫</div><divclass="example-tag"data-example="一只彩虹色的独角兽,在星空中飞翔,身后留下七彩光芒">彩虹独角兽</div><divclass="example-tag"data-example="一只机械狮子,在未来的城市中巡逻,眼睛发出红色光芒">机械狮子</div><divclass="example-tag"data-example="一只透明的水母,在深海发光,触手轻轻摆动">发光水母</div><divclass="example-tag"data-example="一只长着翅膀的小猫,在云朵间嬉戏">飞天小猫</div></div></div><divclass="buttons"><buttonclass="btn generate-btn"id="generateBtn"><iclass="fas fa-video"></i> 生成视频 </button><buttonclass="btn clear-btn"id="clearBtn"><iclass="fas fa-eraser"></i> 清空内容 </button></div></div><divclass="output-section"><divclass="section-title"><iclass="fas fa-film"></i><h2>生成的视频</h2></div><divclass="video-container"id="videoContainer"><divclass="video-placeholder"id="videoPlaceholder"><iclass="fas fa-play-circle"></i><h3>视频将在这里显示</h3><p>描述一个动物,然后点击"生成视频"按钮</p></div><divclass="loading"id="loadingIndicator"style="display: none;"><divclass="spinner"></div><h3>正在生成视频...</h3><p>这可能需要一些时间,请耐心等待</p></div><videoclass="video-player"id="videoPlayer"controlsstyle="display: none;"></video></div><divclass="video-info"id="videoInfo"style="display: none;"><h3><iclass="fas fa-info-circle"></i> 描述</h3><pclass="description-text"id="descriptionText"></p><divclass="action-buttons"><buttonclass="action-btn download-btn"id="downloadBtn"><iclass="fas fa-download"></i> 下载视频 </button><buttonclass="action-btn share-btn"id="shareBtn"><iclass="fas fa-share-alt"></i> 分享视频 </button></div></div></div></div><divclass="footer"><p>Powered by Coze AI • 视频生成可能需要30秒到1分钟时间 • <ahref="#"id="refreshLink">刷新页面</a></p></div></div><divclass="notification"id="notification"></div><script>// DOM元素const animalDescription = document.getElementById('animalDescription');const generateBtn = document.getElementById('generateBtn');const clearBtn = document.getElementById('clearBtn');const videoContainer = document.getElementById('videoContainer');const videoPlaceholder = document.getElementById('videoPlaceholder');const videoPlayer = document.getElementById('videoPlayer');const videoInfo = document.getElementById('videoInfo');const descriptionText = document.getElementById('descriptionText');const loadingIndicator = document.getElementById('loadingIndicator');const downloadBtn = document.getElementById('downloadBtn');const shareBtn = document.getElementById('shareBtn');const exampleTags = document.querySelectorAll('.example-tag');const notification = document.getElementById('notification');const refreshLink = document.getElementById('refreshLink');// 示例标签点击事件 exampleTags.forEach(tag=>{ tag.addEventListener('click',()=>{ animalDescription.value = tag.getAttribute('data-example');});});// 清空按钮事件 clearBtn.addEventListener('click',()=>{ animalDescription.value =''; animalDescription.focus();});// 生成视频按钮事件 generateBtn.addEventListener('click', generateVideo);// 按Enter键生成视频(Ctrl+Enter或Cmd+Enter) animalDescription.addEventListener('keydown',(e)=>{if((e.ctrlKey || e.metaKey)&& e.key ==='Enter'){generateVideo();}});// 生成视频函数asyncfunctiongenerateVideo(){const description = animalDescription.value.trim();if(!description){showNotification('请输入动物描述','error'); animalDescription.focus();return;}// 显示加载指示器 loadingIndicator.style.display ='flex'; videoPlaceholder.style.display ='none'; videoPlayer.style.display ='none'; videoInfo.style.display ='none';// 禁用生成按钮 generateBtn.disabled =true; generateBtn.innerHTML ='<i></i> 生成中...';try{// 调用后端APIconst response =awaitfetch('/generate-video',{method:'POST',headers:{'Content-Type':'application/json',},body:JSON.stringify({input: description })});const data =await response.json();if(data.success && data.video_url){// 显示视频 videoPlayer.src = data.video_url; videoPlayer.style.display ='block';// 显示描述信息 descriptionText.textContent = data.description; videoInfo.style.display ='block';// 显示成功通知showNotification('视频生成成功!','success');// 视频加载后隐藏加载指示器 videoPlayer.onloadeddata=()=>{ loadingIndicator.style.display ='none';};// 如果视频加载失败,也隐藏加载指示器 videoPlayer.onerror=()=>{ loadingIndicator.style.display ='none';showNotification('视频加载失败,请检查链接','error');};}else{thrownewError(data.error ||'视频生成失败');}}catch(error){ console.error('生成视频时出错:', error);showNotification('视频生成失败: '+ error.message,'error'); videoPlaceholder.style.display ='block'; loadingIndicator.style.display ='none';}finally{// 恢复生成按钮状态 generateBtn.disabled =false; generateBtn.innerHTML ='<i></i> 生成视频';}}// 下载视频按钮事件 downloadBtn.addEventListener('click',()=>{if(videoPlayer.src){const link = document.createElement('a'); link.href = videoPlayer.src; link.download ='动物视频_'+ Date.now()+'.mp4'; document.body.appendChild(link); link.click(); document.body.removeChild(link);showNotification('视频下载已开始','success');}else{showNotification('没有可下载的视频','error');}});// 分享视频按钮事件 shareBtn.addEventListener('click',()=>{if(videoPlayer.src){if(navigator.share){ navigator.share({title:'我生成的动物视频',text: animalDescription.value,url: window.location.href,}).then(()=>showNotification('分享成功','success')).catch((error)=>showNotification('分享失败: '+ error.message,'error'));}else{// 如果不支持Web Share API,则复制链接到剪贴板 navigator.clipboard.writeText(videoPlayer.src).then(()=>showNotification('视频链接已复制到剪贴板','success')).catch(()=>showNotification('复制失败,请手动复制链接','error'));}}else{showNotification('没有可分享的视频','error');}});// 刷新链接事件 refreshLink.addEventListener('click',(e)=>{ e.preventDefault(); window.location.reload();});// 显示通知函数functionshowNotification(message, type){ notification.textContent = message; notification.className ='notification '+ type; notification.classList.add('show');setTimeout(()=>{ notification.classList.remove('show');},3000);}// 页面加载时聚焦到描述框 window.addEventListener('load',()=>{ animalDescription.focus();});</script></body></html>