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)
def create_video(animal_description):
try:
api_token = os.getenv('COZE_API_TOKEN')
workflow_id = os.getenv('WORKFLOW_ID')
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:
return None
@app.route("/generate-video", methods=['POST'])
def generate_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('/')
def index():
return send_file('index.html')
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>动物世界视频生成器</title>
<link rel="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>
<div class="container">
<div class="header">
<h1><i class="fas fa-paw"></i> 动物世界视频生成器</h1>
<p>描述你想象中的动物,AI 将为你生成独特的动物视频。从可爱的小猫到神奇的神兽,一切皆有可能!</p>
</div>
<div class="main-content">
<div class="input-section">
<div class="section-title"><i class="fas fa-edit"></i><h2>描述你的动物</h2></div>
<textarea class="animal-description" id="animalDescription" placeholder="描述你想要生成的动物视频...例如:一只蓝色的狐狸在雪地中奔跑,毛发如丝般顺滑,眼睛像蓝宝石一样闪耀。"></textarea>
<div class="examples">
<h3>试试这些例子:</h3>
<div class="example-tags">
<div class="example-tag" data-example="一只会说话的熊猫,戴着草帽,在竹林中跳舞">会说话的熊猫</div>
<div class="example-tag" data-example="一只彩虹色的独角兽,在星空中飞翔,身后留下七彩光芒">彩虹独角兽</div>
<div class="example-tag" data-example="一只机械狮子,在未来的城市中巡逻,眼睛发出红色光芒">机械狮子</div>
<div class="example-tag" data-example="一只透明的水母,在深海发光,触手轻轻摆动">发光水母</div>
<div class="example-tag" data-example="一只长着翅膀的小猫,在云朵间嬉戏">飞天小猫</div>
</div>
</div>
<div class="buttons">
<button class="btn generate-btn" id="generateBtn"><i class="fas fa-video"></i> 生成视频</button>
<button class="btn clear-btn" id="clearBtn"><i class="fas fa-eraser"></i> 清空内容</button>
</div>
</div>
<div class="output-section">
<div class="section-title"><i class="fas fa-film"></i><h2>生成的视频</h2></div>
<div class="video-container" id="videoContainer">
<div class="video-placeholder" id="videoPlaceholder">
<i class="fas fa-play-circle"></i>
<h3>视频将在这里显示</h3>
<p>描述一个动物,然后点击'生成视频'按钮</p>
</div>
<div class="loading" id="loadingIndicator" style="display: none;">
<div class="spinner"></div>
<h3>正在生成视频...</h3>
<p>这可能需要一些时间,请耐心等待</p>
</div>
<video class="video-player" id="videoPlayer" controls style="display: none;"></video>
</div>
<div class="video-info" id="videoInfo" style="display: none;">
<h3><i class="fas fa-info-circle"></i> 描述</h3>
<p class="description-text" id="descriptionText"></p>
<div class="action-buttons">
<button class="action-btn download-btn" id="downloadBtn"><i class="fas fa-download"></i> 下载视频</button>
<button class="action-btn share-btn" id="shareBtn"><i class="fas fa-share-alt"></i> 分享视频</button>
</div>
</div>
</div>
</div>
<div class="footer">
<p>Powered by Coze AI • 视频生成可能需要 30 秒到 1 分钟时间 • <a href="#" id="refreshLink">刷新页面</a></p>
</div>
</div>
<div class="notification" id="notification"></div>
<script>
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.();
refreshLink = .();
exampleTags.( {
tag.(, {
animalDescription. = tag.();
});
});
clearBtn.(, {
animalDescription. = ;
animalDescription.();
});
generateBtn.(, generateVideo);
animalDescription.(, {
((e. || e.) && e. === ) {
();
}
});
() {
description = animalDescription..();
(!description) {
(, );
animalDescription.();
;
}
loadingIndicator.. = ;
videoPlaceholder.. = ;
videoPlayer.. = ;
videoInfo.. = ;
generateBtn. = ;
generateBtn. = ;
{
response = (, {
: ,
: {
: ,
},
: .({ : description })
});
data = response.();
(data. && data.) {
videoPlayer. = data.;
videoPlayer.. = ;
descriptionText. = data.;
videoInfo.. = ;
(, );
videoPlayer. = {
loadingIndicator.. = ;
};
videoPlayer. = {
loadingIndicator.. = ;
(, );
};
} {
(data. || );
}
} (error) {
.(, error);
( + error., );
videoPlaceholder.. = ;
loadingIndicator.. = ;
} {
generateBtn. = ;
generateBtn. = ;
}
}
downloadBtn.(, {
(videoPlayer.) {
link = .();
link. = videoPlayer.;
link. = + .() + ;
..(link);
link.();
..(link);
(, );
} {
(, );
}
});
shareBtn.(, {
(videoPlayer.) {
(navigator.) {
navigator.({
: ,
: animalDescription.,
: ..,
}).( (, )).( ( + error., ));
} {
navigator..(videoPlayer.).( (, )).( (, ));
}
} {
(, );
}
});
refreshLink.(, {
e.();
..();
});
() {
notification. = message;
notification. = + type;
notification..();
( {
notification..();
}, );
}
.(, {
animalDescription.();
});
</script>
</body>
</html>