将vue代码修改为按照模板进行生成
This commit is contained in:
parent
397b6fb1ef
commit
9040947491
0
.vscode/settings.json
vendored
Normal file
0
.vscode/settings.json
vendored
Normal file
0
.vscode/tasks.json
vendored
Normal file
0
.vscode/tasks.json
vendored
Normal file
0
ai_service.code-workspace
Normal file
0
ai_service.code-workspace
Normal file
@ -1,7 +1,428 @@
|
||||
# Vue模板配置文件
|
||||
# 为不同图片类型预定义Vue组件模板
|
||||
# 为不同海报类型预定义Vue组件模板
|
||||
|
||||
vue_templates:
|
||||
# 插画风模板
|
||||
illustration:
|
||||
name: "插画风海报"
|
||||
description: "4层结构:插画底图+文字图层"
|
||||
layers:
|
||||
- name: "插画底图"
|
||||
type: "background"
|
||||
description: "AI生成的通用建筑插图,彩色插画,色调和谐"
|
||||
- name: "主标题"
|
||||
type: "text"
|
||||
content: "见微知著记录南开"
|
||||
description: "最大号字体,放置在不遮挡主体的相对空白处"
|
||||
- name: "南开大学logo"
|
||||
type: "logo"
|
||||
description: "南开大学标识"
|
||||
- name: "机构名称"
|
||||
type: "text"
|
||||
content: "南开大学融媒体中心"
|
||||
description: "底部居中放置"
|
||||
template: |
|
||||
<template>
|
||||
<div class="poster-container illustration-theme" :style="containerStyle">
|
||||
<!-- 插画底图层 -->
|
||||
<div class="background-layer">
|
||||
<img :src="backgroundImage" alt="插画背景" class="background-image" />
|
||||
</div>
|
||||
|
||||
<!-- 内容层 -->
|
||||
<div class="content-layer">
|
||||
<!-- 主标题 -->
|
||||
<div class="main-title-section">
|
||||
<h1 class="primary-title">{{ mainTitle }}</h1>
|
||||
</div>
|
||||
|
||||
<!-- 南开logo -->
|
||||
<div class="logo-section">
|
||||
<img src="../outputs/nankai.png" alt="南开大学" class="nankai-logo" />
|
||||
</div>
|
||||
|
||||
<!-- 机构名称 -->
|
||||
<div class="organization-section">
|
||||
<h2 class="organization-name">{{ organizationName }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'IllustrationPoster',
|
||||
data() {
|
||||
return {
|
||||
mainTitle: '见微知著记录南开',
|
||||
organizationName: '南开大学融媒体中心',
|
||||
backgroundImage: '../outputs/background.png'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
containerStyle() {
|
||||
return {
|
||||
width: '1080px',
|
||||
height: '1920px',
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
background: 'linear-gradient(135deg, #f5f7fa, #c3cfe2)'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.poster-container {
|
||||
margin: 0 auto;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.background-layer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.background-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.content-layer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.main-title-section {
|
||||
position: absolute;
|
||||
top: 15%;
|
||||
left: 8%;
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.primary-title {
|
||||
font-size: 72px;
|
||||
font-weight: bold;
|
||||
color: #2c3e50;
|
||||
text-shadow: 2px 2px 4px rgba(255, 255, 255, 0.8);
|
||||
line-height: 1.2;
|
||||
font-family: 'SimHei', 'Microsoft YaHei', sans-serif;
|
||||
}
|
||||
|
||||
.logo-section {
|
||||
position: absolute;
|
||||
top: 45%;
|
||||
right: 10%;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.nankai-logo {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.2));
|
||||
}
|
||||
|
||||
.organization-section {
|
||||
position: absolute;
|
||||
bottom: 8%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.organization-name {
|
||||
font-size: 36px;
|
||||
color: #34495e;
|
||||
font-weight: 500;
|
||||
font-family: 'Microsoft YaHei', sans-serif;
|
||||
text-shadow: 1px 1px 2px rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
</style>
|
||||
|
||||
# 中秋节模板
|
||||
festival:
|
||||
name: "中秋节海报"
|
||||
description: "8层结构:背景+遮罩+装饰+logo+多文字层"
|
||||
layers:
|
||||
- name: "背景图层"
|
||||
type: "background"
|
||||
description: "AI生成节日插画"
|
||||
- name: "纯色遮罩"
|
||||
type: "overlay"
|
||||
description: "插画主色调遮罩"
|
||||
- name: "小插图背景"
|
||||
type: "decoration"
|
||||
description: "节日元素插图"
|
||||
- name: "南开logo"
|
||||
type: "logo"
|
||||
- name: "单位名称"
|
||||
type: "text"
|
||||
content: "南开大学"
|
||||
- name: "节日名称"
|
||||
type: "text"
|
||||
content: "中秋节"
|
||||
- name: "目的主题"
|
||||
type: "text"
|
||||
content: "月圆人团圆"
|
||||
- name: "日期元素"
|
||||
type: "text"
|
||||
content: "2025年10月6日"
|
||||
template: |
|
||||
<template>
|
||||
<div class="poster-container festival-theme" :style="containerStyle">
|
||||
<!-- 背景图层 -->
|
||||
<div class="background-layer">
|
||||
<img :src="backgroundImage" alt="节日背景" class="background-image" />
|
||||
</div>
|
||||
|
||||
<!-- 纯色遮罩层 -->
|
||||
<div class="color-overlay" :style="overlayStyle"></div>
|
||||
|
||||
<!-- 装饰元素层 -->
|
||||
<div class="decoration-layer">
|
||||
<img :src="decorationImage" alt="节日装饰" class="decoration-image" />
|
||||
</div>
|
||||
|
||||
<!-- 内容层 -->
|
||||
<div class="content-layer">
|
||||
<!-- 南开logo -->
|
||||
<div class="logo-section">
|
||||
<img src="../outputs/nankai.png" alt="南开大学" class="nankai-logo" />
|
||||
</div>
|
||||
|
||||
<!-- 单位名称 -->
|
||||
<div class="university-section">
|
||||
<h1 class="university-name">{{ universityName }}</h1>
|
||||
</div>
|
||||
|
||||
<!-- 节日名称 -->
|
||||
<div class="festival-section">
|
||||
<h2 class="festival-name">{{ festivalName }}</h2>
|
||||
</div>
|
||||
|
||||
<!-- 目的主题 -->
|
||||
<div class="theme-section">
|
||||
<div class="theme-background"></div>
|
||||
<h3 class="theme-text">{{ themeText }}</h3>
|
||||
</div>
|
||||
|
||||
<!-- 日期元素 -->
|
||||
<div class="date-section">
|
||||
<div class="date-background"></div>
|
||||
<p class="date-text">{{ dateText }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'FestivalPoster',
|
||||
data() {
|
||||
return {
|
||||
universityName: '南开大学',
|
||||
festivalName: '中秋节',
|
||||
themeText: '月圆人团圆',
|
||||
dateText: '2025年10月6日',
|
||||
backgroundImage: '../outputs/background.png',
|
||||
decorationImage: '../outputs/lotus.jpg',
|
||||
mainColor: '#d4a574' // 中秋主色调
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
containerStyle() {
|
||||
return {
|
||||
width: '1080px',
|
||||
height: '1920px',
|
||||
position: 'relative',
|
||||
overflow: 'hidden'
|
||||
}
|
||||
},
|
||||
overlayStyle() {
|
||||
return {
|
||||
backgroundColor: this.mainColor,
|
||||
opacity: 0.3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.poster-container {
|
||||
margin: 0 auto;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.background-layer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.background-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.color-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.decoration-layer {
|
||||
position: absolute;
|
||||
top: 60%;
|
||||
right: 5%;
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
z-index: 3;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.decoration-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 50%;
|
||||
filter: blur(1px);
|
||||
}
|
||||
|
||||
.content-layer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.logo-section {
|
||||
position: absolute;
|
||||
top: 8%;
|
||||
left: 8%;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
|
||||
.nankai-logo {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.3));
|
||||
}
|
||||
|
||||
.university-section {
|
||||
position: absolute;
|
||||
top: 25%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.university-name {
|
||||
font-size: 48px;
|
||||
color: #2c3e50;
|
||||
font-weight: bold;
|
||||
font-family: 'SimHei', 'Microsoft YaHei', sans-serif;
|
||||
text-shadow: 2px 2px 4px rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
.festival-section {
|
||||
position: absolute;
|
||||
top: 35%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.festival-name {
|
||||
font-size: 96px;
|
||||
color: #d4a574;
|
||||
font-weight: bold;
|
||||
font-family: 'SimSun', 'KaiTi', serif;
|
||||
text-shadow: 3px 3px 6px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.theme-section {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.theme-background {
|
||||
position: absolute;
|
||||
top: -20px;
|
||||
left: -40px;
|
||||
width: calc(100% + 80px);
|
||||
height: calc(100% + 40px);
|
||||
background: linear-gradient(135deg, rgba(212, 165, 116, 0.2), rgba(212, 165, 116, 0.1));
|
||||
border-radius: 20px;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.theme-text {
|
||||
font-size: 56px;
|
||||
color: #8b4513;
|
||||
font-weight: 500;
|
||||
font-family: 'KaiTi', serif;
|
||||
text-shadow: 1px 1px 3px rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.date-section {
|
||||
position: absolute;
|
||||
bottom: 12%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.date-background {
|
||||
position: absolute;
|
||||
top: -15px;
|
||||
left: -30px;
|
||||
width: calc(100% + 60px);
|
||||
height: calc(100% + 30px);
|
||||
background: linear-gradient(135deg, rgba(212, 165, 116, 0.3), rgba(212, 165, 116, 0.2));
|
||||
border-radius: 15px;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.date-text {
|
||||
font-size: 32px;
|
||||
color: #654321;
|
||||
font-weight: 400;
|
||||
font-family: 'Microsoft YaHei', sans-serif;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
# 通用模板(保留原有的lotus模板作为备用)
|
||||
lotus.jpg:
|
||||
theme: "荷花主题"
|
||||
style: "传统优雅"
|
||||
|
BIN
docs/南开大学融媒体中心.pdf
Normal file
BIN
docs/南开大学融媒体中心.pdf
Normal file
Binary file not shown.
0
docs/问题.md
Normal file
0
docs/问题.md
Normal file
BIN
outputs/30695088_20250710000325_0.png
Normal file
BIN
outputs/30695088_20250710000325_0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.4 MiB |
BIN
outputs/30695088_20250710000325_1.png
Normal file
BIN
outputs/30695088_20250710000325_1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.5 MiB |
BIN
outputs/7697019_20250712093109_0.png
Normal file
BIN
outputs/7697019_20250712093109_0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 MiB |
BIN
outputs/7697019_20250712093109_1.png
Normal file
BIN
outputs/7697019_20250712093109_1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 MiB |
BIN
outputs/background.zip
Normal file
BIN
outputs/background.zip
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 2.3 MiB After Width: | Height: | Size: 2.6 MiB |
240
outputs/generated_code.vue
Normal file
240
outputs/generated_code.vue
Normal file
@ -0,0 +1,240 @@
|
||||
<template>
|
||||
<div class="poster-container festival-theme" :style="containerStyle">
|
||||
<!-- 背景图层 -->
|
||||
<div class="background-layer">
|
||||
<img :src="backgroundImage" alt="节日背景" class="background-image" />
|
||||
</div>
|
||||
|
||||
<!-- 纯色遮罩层 -->
|
||||
<div class="color-overlay" :style="overlayStyle"></div>
|
||||
|
||||
<!-- 装饰元素层 -->
|
||||
<div class="decoration-layer">
|
||||
<img :src="decorationImage" alt="节日装饰" class="decoration-image" />
|
||||
</div>
|
||||
|
||||
<!-- 内容层 -->
|
||||
<div class="content-layer">
|
||||
<!-- 南开logo -->
|
||||
<div class="logo-section">
|
||||
<img src="../outputs/nankai.png" alt="南开大学" class="nankai-logo" />
|
||||
</div>
|
||||
|
||||
<!-- 单位名称 -->
|
||||
<div class="university-section">
|
||||
<h1 class="university-name">{{ universityName }}</h1>
|
||||
</div>
|
||||
|
||||
<!-- 节日名称 -->
|
||||
<div class="festival-section">
|
||||
<h2 class="festival-name">{{ festivalName }}</h2>
|
||||
</div>
|
||||
|
||||
<!-- 目的主题 -->
|
||||
<div class="theme-section">
|
||||
<div class="theme-background"></div>
|
||||
<h3 class="theme-text">{{ themeText }}</h3>
|
||||
</div>
|
||||
|
||||
<!-- 日期元素 -->
|
||||
<div class="date-section">
|
||||
<div class="date-background"></div>
|
||||
<p class="date-text">{{ dateText }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'FestivalPoster',
|
||||
data() {
|
||||
return {
|
||||
universityName: '南开大学',
|
||||
festivalName: '端午节',
|
||||
themeText: '粽叶飘香,龙舟竞渡',
|
||||
dateText: '2025年07月12日',
|
||||
backgroundImage: '../outputs/background.png',
|
||||
decorationImage: '../outputs/lotus.jpg',
|
||||
mainColor: '#d4a574' // 中秋主色调
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
containerStyle() {
|
||||
return {
|
||||
width: '1080px',
|
||||
height: '1920px',
|
||||
position: 'relative',
|
||||
overflow: 'hidden'
|
||||
}
|
||||
},
|
||||
overlayStyle() {
|
||||
return {
|
||||
backgroundColor: this.mainColor,
|
||||
opacity: 0.3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.poster-container {
|
||||
margin: 0 auto;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.background-layer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.background-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.color-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.decoration-layer {
|
||||
position: absolute;
|
||||
top: 60%;
|
||||
right: 5%;
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
z-index: 3;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.decoration-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 50%;
|
||||
filter: blur(1px);
|
||||
}
|
||||
|
||||
.content-layer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.logo-section {
|
||||
position: absolute;
|
||||
top: 8%;
|
||||
left: 8%;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
|
||||
.nankai-logo {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.3));
|
||||
}
|
||||
|
||||
.university-section {
|
||||
position: absolute;
|
||||
top: 25%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.university-name {
|
||||
font-size: 48px;
|
||||
color: #2c3e50;
|
||||
font-weight: bold;
|
||||
font-family: 'SimHei', 'Microsoft YaHei', sans-serif;
|
||||
text-shadow: 2px 2px 4px rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
.festival-section {
|
||||
position: absolute;
|
||||
top: 35%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.festival-name {
|
||||
font-size: 96px;
|
||||
color: #d4a574;
|
||||
font-weight: bold;
|
||||
font-family: 'SimSun', 'KaiTi', serif;
|
||||
text-shadow: 3px 3px 6px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.theme-section {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.theme-background {
|
||||
position: absolute;
|
||||
top: -20px;
|
||||
left: -40px;
|
||||
width: calc(100% + 80px);
|
||||
height: calc(100% + 40px);
|
||||
background: linear-gradient(135deg, rgba(212, 165, 116, 0.2), rgba(212, 165, 116, 0.1));
|
||||
border-radius: 20px;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.theme-text {
|
||||
font-size: 56px;
|
||||
color: #8b4513;
|
||||
font-weight: 500;
|
||||
font-family: 'KaiTi', serif;
|
||||
text-shadow: 1px 1px 3px rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.date-section {
|
||||
position: absolute;
|
||||
bottom: 12%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.date-background {
|
||||
position: absolute;
|
||||
top: -15px;
|
||||
left: -30px;
|
||||
width: calc(100% + 60px);
|
||||
height: calc(100% + 30px);
|
||||
background: linear-gradient(135deg, rgba(212, 165, 116, 0.3), rgba(212, 165, 116, 0.2));
|
||||
border-radius: 15px;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.date-text {
|
||||
font-size: 32px;
|
||||
color: #654321;
|
||||
font-weight: 400;
|
||||
font-family: 'Microsoft YaHei', sans-serif;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
@ -1,16 +1,16 @@
|
||||
{
|
||||
"layer5_logo_content": {
|
||||
"text": "",
|
||||
"color": "#7E0C6E"
|
||||
"color": "#000000"
|
||||
},
|
||||
"layer6_title_content": {
|
||||
"content": "南开风采",
|
||||
"font_name": "FZLanTingHei-ExtraBold-GB",
|
||||
"content": "端午节",
|
||||
"font_name": "SimHei",
|
||||
"color": "#000000"
|
||||
},
|
||||
"layer7_subtitle_content": {
|
||||
"content": "百年学府,智慧之光",
|
||||
"content": "粽叶飘香,龙舟竞渡",
|
||||
"font_name": "Microsoft YaHei",
|
||||
"color": "#333333"
|
||||
"color": "#7E0C6E"
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -5,7 +5,7 @@
|
||||
|
||||
@author 王秀强 (2310460@mail.nankai.edu.cn)
|
||||
@date 2025.5.19
|
||||
@version v2.0.0
|
||||
@version v0.5.2
|
||||
|
||||
@details
|
||||
本文件主要实现:
|
||||
@ -56,18 +56,12 @@ def call_deepseek(
|
||||
prompt=None,
|
||||
model='deepseek-chat',
|
||||
temperature=0.6,
|
||||
max_tokens=2000, # 增加token数量
|
||||
max_tokens=2000,
|
||||
stream=False,
|
||||
max_retries=3,
|
||||
):
|
||||
"""
|
||||
调用 DeepSeek API,支持多轮对话和流式/非流式响应
|
||||
"""
|
||||
# 初始化 OpenAI 客户端
|
||||
client = OpenAI(
|
||||
api_key=deepseek_api,
|
||||
base_url=deepseek_url,
|
||||
)
|
||||
"""调用 DeepSeek API,支持多轮对话和流式/非流式响应"""
|
||||
client = OpenAI(api_key=deepseek_api, base_url=deepseek_url)
|
||||
|
||||
# 参数验证
|
||||
if messages is None:
|
||||
@ -88,8 +82,6 @@ def call_deepseek(
|
||||
# 调用 API
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
print(f"{Fore.BLUE}📡 正在调用DeepSeek API (尝试 {attempt + 1}/{max_retries})...{Style.RESET_ALL}")
|
||||
|
||||
response = client.chat.completions.create(
|
||||
model=model,
|
||||
messages=messages,
|
||||
@ -98,25 +90,23 @@ def call_deepseek(
|
||||
stream=stream
|
||||
)
|
||||
|
||||
# 流式响应
|
||||
if stream:
|
||||
# 流式响应处理
|
||||
def stream_generator():
|
||||
usage = None
|
||||
for chunk in response:
|
||||
if chunk.choices[0].delta.content is not None:
|
||||
if hasattr(chunk, 'choices') and chunk.choices[0].delta.content is not None:
|
||||
yield chunk.choices[0].delta.content
|
||||
return usage
|
||||
return stream_generator(), None
|
||||
else:
|
||||
# 非流式响应
|
||||
content = response.choices[0].message.content
|
||||
print(f"{Fore.GREEN}✅ API调用成功,返回内容长度: {len(content)}{Style.RESET_ALL}")
|
||||
return content, response.usage
|
||||
if hasattr(response, 'choices') and response.choices:
|
||||
content = response.choices[0].message.content
|
||||
usage = getattr(response, 'usage', None)
|
||||
return content, usage
|
||||
return "", None
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}❌ API调用失败 (尝试 {attempt + 1}/{max_retries}): {str(e)}{Style.RESET_ALL}")
|
||||
if hasattr(e, 'status_code') and e.status_code == 429: # 限流
|
||||
print(f"{Fore.YELLOW}⏳ 请求过于频繁,等待重试...{Style.RESET_ALL}")
|
||||
if hasattr(e, 'status_code') and getattr(e, 'status_code') == 429:
|
||||
time.sleep(2 ** attempt) # 指数退避
|
||||
elif attempt == max_retries - 1:
|
||||
raise
|
||||
@ -128,202 +118,209 @@ def call_deepseek(
|
||||
|
||||
def load_vue_templates() -> Dict:
|
||||
"""加载预定义的Vue模板配置"""
|
||||
template_path = "../configs/vue_templates.yaml"
|
||||
|
||||
try:
|
||||
with open(template_path, 'r', encoding='utf-8') as f:
|
||||
templates = yaml.safe_load(f)
|
||||
print(f"{Fore.GREEN}✅ Vue模板配置加载成功{Style.RESET_ALL}")
|
||||
return templates.get('vue_templates', {})
|
||||
except Exception as e:
|
||||
print(f"{Fore.YELLOW}⚠️ Vue模板配置加载失败: {e},使用默认模板{Style.RESET_ALL}")
|
||||
return {}
|
||||
from utils import load_vue_templates as utils_load_templates
|
||||
return utils_load_templates()
|
||||
|
||||
|
||||
def get_template_by_images(parse_imglist: List[Dict]) -> Optional[str]:
|
||||
"""
|
||||
根据图片列表选择合适的预定义模板
|
||||
|
||||
参数:
|
||||
parse_imglist: 图片信息列表
|
||||
|
||||
返回:
|
||||
选中的模板代码,如果没有匹配的模板则返回None
|
||||
"""
|
||||
"""根据图片列表选择合适的预定义模板"""
|
||||
templates = load_vue_templates()
|
||||
|
||||
|
||||
if not templates or not parse_imglist:
|
||||
return None
|
||||
|
||||
# 检查固定的图片文件
|
||||
fixed_images = ["lotus.jpg", "nku.png", "stamp.jpg", "background.png"]
|
||||
|
||||
for img_name in fixed_images:
|
||||
img_path = f"../outputs/{img_name}"
|
||||
if os.path.exists(img_path) and img_name in templates:
|
||||
print(f"{Fore.CYAN}📋 找到匹配的预定义模板: {img_name}{Style.RESET_ALL}")
|
||||
|
||||
# 使用utils中的函数确定模板类型
|
||||
from utils import determine_template_type as utils_determine_type
|
||||
template_choice = utils_determine_type(parse_imglist)
|
||||
|
||||
if template_choice in templates:
|
||||
return templates[template_choice]['template']
|
||||
|
||||
# 备用:检查特定文件名
|
||||
for img_info in parse_imglist:
|
||||
img_name = img_info.get('picture_name', '')
|
||||
if img_name in templates:
|
||||
return templates[img_name]['template']
|
||||
|
||||
print(f"{Fore.YELLOW}⚠️ 未找到匹配的预定义模板,将使用AI生成{Style.RESET_ALL}")
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def generate_layout_prompt(user_input_analysis_result: Dict, parse_imglist: List[Dict], suggestions: Dict = None) -> str:
|
||||
"""
|
||||
生成增强的Vue布局提示,包含文案内容
|
||||
这个函数从run_pipeline.py移动到这里
|
||||
"""
|
||||
def determine_template_type(parse_imglist: List[Dict]) -> str:
|
||||
"""根据图片信息确定模板类型"""
|
||||
from utils import determine_template_type as utils_determine_type
|
||||
return utils_determine_type(parse_imglist)
|
||||
|
||||
|
||||
def generate_layout_prompt(user_input_analysis_result: Dict, parse_imglist: List[Dict], suggestions: Optional[Dict] = None) -> str:
|
||||
"""根据用户分析结果动态生成Vue布局提示"""
|
||||
width = user_input_analysis_result.get("width", 1080)
|
||||
height = user_input_analysis_result.get("height", 1920)
|
||||
theme = user_input_analysis_result.get("main_theme", "活动海报")
|
||||
|
||||
# 从用户分析中提取更多信息
|
||||
style = user_input_analysis_result.get("style", "现代简约")
|
||||
color_scheme = user_input_analysis_result.get("color_scheme", "默认配色")
|
||||
layout_type = user_input_analysis_result.get("layout_type", "标准布局")
|
||||
target_audience = user_input_analysis_result.get("target_audience", "一般用户")
|
||||
|
||||
# 构造图片信息字符串
|
||||
images_info = "\n".join(
|
||||
[f"- {img['picture_name']} ({img['picture_description']})" for img in parse_imglist]
|
||||
)
|
||||
# 构造图片信息
|
||||
images_info = []
|
||||
for i, img in enumerate(parse_imglist):
|
||||
img_desc = f"图片{i+1}: {img['picture_name']} - {img['picture_description']}"
|
||||
images_info.append(img_desc)
|
||||
|
||||
images_text = "\n".join(images_info) if images_info else "无特定图片资源"
|
||||
|
||||
# 构造文案信息
|
||||
content_info = ""
|
||||
content_parts = []
|
||||
if suggestions:
|
||||
try:
|
||||
if 'layer6_title_content' in suggestions:
|
||||
title = suggestions['layer6_title_content'].get('content', theme)
|
||||
content_info += f"- 主标题: {title}\n"
|
||||
content_parts.append(f"主标题: {title}")
|
||||
|
||||
if 'layer7_subtitle_content' in suggestions:
|
||||
subtitle = suggestions['layer7_subtitle_content'].get('content', '精彩活动,敬请参与')
|
||||
content_info += f"- 副标题: {subtitle}\n"
|
||||
content_parts.append(f"副标题: {subtitle}")
|
||||
|
||||
if 'layer5_logo_content' in suggestions:
|
||||
logo = suggestions['layer5_logo_content'].get('text', '主办方')
|
||||
content_info += f"- Logo文字: {logo}\n"
|
||||
except Exception as e:
|
||||
print(f"{Fore.YELLOW}⚠️ 文案信息解析错误: {e}{Style.RESET_ALL}")
|
||||
content_info = f"- 主标题: {theme}\n- 副标题: 精彩活动,敬请参与\n"
|
||||
logo = suggestions['layer5_logo_content'].get('text', '')
|
||||
if logo:
|
||||
content_parts.append(f"Logo文字: {logo}")
|
||||
except Exception:
|
||||
content_parts = [f"主标题: {theme}", "副标题: 精彩活动,敬请参与"]
|
||||
else:
|
||||
content_parts = [f"主标题: {theme}", "副标题: 精彩活动,敬请参与"]
|
||||
|
||||
# 调用DeepSeek生成动态排版Prompt
|
||||
system_prompt = "你是一个擅长前端开发的AI,专注于生成Vue.js代码。请根据提供的信息生成完整的Vue组件,包含所有必要的HTML结构和基础定位样式。"
|
||||
content_info = "\n".join([f"- {part}" for part in content_parts])
|
||||
|
||||
# 根据主题类型调整布局描述
|
||||
layout_requirements = []
|
||||
if "节日" in theme or "festival" in theme.lower():
|
||||
layout_requirements = [
|
||||
"背景图层: 使用节日主题背景,营造氛围",
|
||||
"标题区域: 突出节日名称,位于画布上方,使用醒目字体",
|
||||
"装饰元素: 添加节日相关装饰图案,分布在画面周围",
|
||||
"日期信息: 在适当位置显示日期",
|
||||
"Logo区域: 位于底部,展示主办方信息"
|
||||
]
|
||||
elif "校园" in theme or "大学" in theme or "学术" in theme:
|
||||
layout_requirements = [
|
||||
"背景图层: 使用校园或学术主题背景",
|
||||
"标题区域: 学术风格标题,位于画布上方1/3处",
|
||||
"内容区域: 展示学术内容或校园风光,居中布局",
|
||||
"信息栏: 显示相关学术信息或活动详情",
|
||||
"Logo区域: 展示学校标识,位于底部"
|
||||
]
|
||||
else:
|
||||
layout_requirements = [
|
||||
"背景图层: 使用主题相关背景图片,占据整个组件区域",
|
||||
"主标题: 位于画布上方1/3处,居中显示,突出主题",
|
||||
"副标题: 位于主标题下方,居中显示,补充说明",
|
||||
"内容区域: 合理布局图片和信息,保持视觉平衡",
|
||||
"Logo区域: 位于底部,居中显示主办方信息"
|
||||
]
|
||||
|
||||
layout_text = "\n".join([f"{i+1}. {req}" for i, req in enumerate(layout_requirements)])
|
||||
|
||||
system_prompt = f"你是一个专业的前端设计师,擅长根据用户需求生成{style}风格的Vue.js组件。请根据{target_audience}的审美偏好,生成完整的Vue组件代码。"
|
||||
|
||||
prompt = f"""
|
||||
请生成一个Vue.js组件代码,用于{theme}海报,要求如下:
|
||||
请为"{theme}"主题设计一个Vue 3组件,要求如下:
|
||||
|
||||
组件尺寸: {width}x{height}px
|
||||
【基本信息】
|
||||
- 组件尺寸: {width}x{height}px
|
||||
- 设计风格: {style}
|
||||
- 配色方案: {color_scheme}
|
||||
- 布局类型: {layout_type}
|
||||
|
||||
图片资源:
|
||||
{images_info}
|
||||
【图片资源】
|
||||
{images_text}
|
||||
|
||||
文案内容:
|
||||
{content_info}
|
||||
【文案内容】
|
||||
{content_info}
|
||||
|
||||
布局要求:
|
||||
1. 背景图层: 使用第一张图片作为背景,占据整个组件区域
|
||||
2. 主标题: 位于画布上方1/3处,居中显示
|
||||
3. 副标题: 位于主标题下方,居中显示
|
||||
4. 内容区域: 使用剩余图片,合理布局在中间区域
|
||||
5. Logo区域: 位于底部,居中显示
|
||||
【布局要求】
|
||||
{layout_text}
|
||||
|
||||
技术要求:
|
||||
- 使用Vue 3 Composition API
|
||||
- 使用absolute定位进行精确布局
|
||||
- 包含完整的template、script和style部分
|
||||
- 确保所有文本内容都正确显示
|
||||
- 图片使用相对路径引用
|
||||
【技术要求】
|
||||
- 使用Vue 3 Composition API
|
||||
- 使用absolute或flex定位进行精确布局
|
||||
- 包含完整的template、script setup和style部分
|
||||
- 确保响应式设计和良好的视觉效果
|
||||
- 图片使用相对路径引用
|
||||
- 样式要体现{style}的设计理念
|
||||
|
||||
请生成完整可用的Vue组件代码,不要包含任何说明文字。
|
||||
"""
|
||||
请生成完整可用的Vue组件代码,代码要简洁优雅,符合{style}风格特点。
|
||||
"""
|
||||
|
||||
try:
|
||||
result, _ = call_deepseek(prompt=prompt, system_prompt=system_prompt, temperature=0.4)
|
||||
return result
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}❌ 布局提示生成失败: {e}{Style.RESET_ALL}")
|
||||
return generate_fallback_vue_code(theme, width, height)
|
||||
return result if isinstance(result, str) else ""
|
||||
except Exception:
|
||||
return ""
|
||||
|
||||
|
||||
def fill_template_content(template: str, suggestions: Dict) -> str:
|
||||
"""
|
||||
填充模板中的动态内容
|
||||
|
||||
参数:
|
||||
template: Vue模板代码
|
||||
suggestions: 文案建议
|
||||
|
||||
返回:
|
||||
填充后的Vue代码
|
||||
"""
|
||||
filled_template = template
|
||||
|
||||
"""填充模板中的动态内容"""
|
||||
from utils import extract_content_from_suggestions
|
||||
|
||||
try:
|
||||
# 提取文案内容
|
||||
title_content = suggestions.get('layer6_title_content', {}).get('content', '默认标题')
|
||||
subtitle_content = suggestions.get('layer7_subtitle_content', {}).get('content', '默认副标题')
|
||||
logo_content = suggestions.get('layer5_logo_content', {}).get('text', '主办方')
|
||||
title_content, subtitle_content, logo_content = extract_content_from_suggestions(suggestions)
|
||||
|
||||
filled_template = template
|
||||
|
||||
# 根据模板类型进行替换
|
||||
if 'illustration-theme' in template:
|
||||
filled_template = filled_template.replace("'见微知著记录南开'", f"'{title_content}'")
|
||||
filled_template = filled_template.replace("'南开大学融媒体中心'", f"'{subtitle_content}'")
|
||||
if logo_content:
|
||||
filled_template = filled_template.replace("'主办方'", f"'{logo_content}'")
|
||||
|
||||
elif 'festival-theme' in template:
|
||||
filled_template = filled_template.replace("'南开大学'", "'南开大学'")
|
||||
filled_template = filled_template.replace("'中秋节'", f"'{title_content}'")
|
||||
filled_template = filled_template.replace("'月圆人团圆'", f"'{subtitle_content}'")
|
||||
from datetime import datetime
|
||||
current_date = datetime.now().strftime('%Y年%m月%d日')
|
||||
filled_template = filled_template.replace("'2025年10月6日'", f"'{current_date}'")
|
||||
|
||||
else:
|
||||
# 通用替换
|
||||
filled_template = filled_template.replace('{{ title_content }}', title_content)
|
||||
filled_template = filled_template.replace('{{ subtitle_content }}', subtitle_content)
|
||||
filled_template = filled_template.replace('{{ logo_content }}', logo_content)
|
||||
|
||||
# 替换模板占位符
|
||||
filled_template = filled_template.replace('{{ title_content }}', title_content)
|
||||
filled_template = filled_template.replace('{{ subtitle_content }}', subtitle_content)
|
||||
filled_template = filled_template.replace('{{ logo_content }}', logo_content)
|
||||
return filled_template
|
||||
|
||||
print(f"{Fore.GREEN}✅ 模板内容填充完成{Style.RESET_ALL}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.YELLOW}⚠️ 模板填充出错: {e},使用默认内容{Style.RESET_ALL}")
|
||||
|
||||
return filled_template
|
||||
except Exception:
|
||||
return template
|
||||
|
||||
|
||||
def generate_vue_code_enhanced(
|
||||
user_input_analysis_result: Dict,
|
||||
parse_imglist: List[Dict],
|
||||
suggestions: Dict = None,
|
||||
prompt: str = None
|
||||
suggestions: Optional[Dict] = None,
|
||||
prompt: Optional[str] = None
|
||||
) -> str:
|
||||
"""
|
||||
增强的Vue代码生成函数
|
||||
优先使用预定义模板,如果没有匹配的模板则使用AI生成
|
||||
|
||||
参数:
|
||||
user_input_analysis_result: 用户输入分析结果
|
||||
parse_imglist: 图片信息列表
|
||||
suggestions: 文案建议
|
||||
prompt: 自定义提示词(可选)
|
||||
|
||||
返回:
|
||||
Vue组件代码
|
||||
"""
|
||||
print(f"{Fore.CYAN}🎨 开始增强Vue代码生成...{Style.RESET_ALL}")
|
||||
|
||||
# 1. 尝试使用预定义模板
|
||||
"""增强的Vue代码生成函数,优先使用预定义模板"""
|
||||
|
||||
# 尝试使用预定义模板
|
||||
template_code = get_template_by_images(parse_imglist)
|
||||
|
||||
|
||||
if template_code and suggestions:
|
||||
print(f"{Fore.GREEN}✅ 使用预定义模板生成Vue代码{Style.RESET_ALL}")
|
||||
vue_code = fill_template_content(template_code, suggestions)
|
||||
return vue_code
|
||||
|
||||
# 2. 如果没有合适的模板,使用AI生成
|
||||
print(f"{Fore.BLUE}🤖 使用AI生成Vue代码{Style.RESET_ALL}")
|
||||
|
||||
# 使用AI生成
|
||||
if not prompt:
|
||||
prompt = generate_layout_prompt(user_input_analysis_result, parse_imglist, suggestions)
|
||||
|
||||
return generate_vue_code(prompt)
|
||||
|
||||
|
||||
def generate_vue_code(prompt=None):
|
||||
"""
|
||||
原有的Vue代码生成函数(保持兼容性)
|
||||
"""
|
||||
if not prompt:
|
||||
prompt = (
|
||||
"生成一个Vue组件代码,用于端午节活动海报,包含以下部分并指定排版位置:"
|
||||
"1. 背景图层:div,占据整个组件区域。"
|
||||
"2. 主体图层:div,位于顶部1/4处,居中,包含标题和副标题。"
|
||||
"3. 活动亮点:div,位于底部1/4处,居中,使用网格布局展示三项活动(每项包含图标、标题和描述)。"
|
||||
"4. 页脚:div,位于底部,居中,包含主办单位信息和logo图片。"
|
||||
"组件尺寸为1080x1920px,布局使用absolute定位,生成完整可用的Vue 3代码。"
|
||||
)
|
||||
|
||||
def generate_vue_code(prompt):
|
||||
"""Vue代码生成函数"""
|
||||
system_prompt = (
|
||||
"你是一个擅长前端开发的AI,专注于生成Vue.js代码。"
|
||||
"请生成完整的Vue 3组件,包含template、script setup和style部分。"
|
||||
@ -332,188 +329,40 @@ def generate_vue_code(prompt=None):
|
||||
)
|
||||
|
||||
try:
|
||||
print(f"{Fore.CYAN}🎨 正在生成Vue组件代码...{Style.RESET_ALL}")
|
||||
result, usage = call_deepseek(prompt=prompt, system_prompt=system_prompt, temperature=0.4)
|
||||
|
||||
# 清理代码,移除可能的markdown标记
|
||||
if result:
|
||||
# 移除markdown代码块标记
|
||||
if "```vue" in result:
|
||||
result = result.split("```vue")[1].split("```")[0].strip()
|
||||
elif "```html" in result:
|
||||
result = result.split("```html")[1].split("```")[0].strip()
|
||||
elif result.startswith("```") and result.endswith("```"):
|
||||
result = result[3:-3].strip()
|
||||
# 使用utils中的代码清理函数
|
||||
from utils import clean_vue_code
|
||||
if result and isinstance(result, str):
|
||||
cleaned_result = clean_vue_code(result)
|
||||
if cleaned_result:
|
||||
return cleaned_result
|
||||
|
||||
# 如果API失败,返回简单的错误提示
|
||||
return "<template><div>Vue代码生成失败</div></template>"
|
||||
|
||||
print(f"{Fore.GREEN}✅ Vue代码生成成功,长度: {len(result)} 字符{Style.RESET_ALL}")
|
||||
return result
|
||||
else:
|
||||
print(f"{Fore.RED}❌ Vue代码生成失败,返回空内容{Style.RESET_ALL}")
|
||||
return generate_fallback_vue_code()
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}❌ Vue代码生成异常: {str(e)}{Style.RESET_ALL}")
|
||||
return generate_fallback_vue_code()
|
||||
|
||||
def generate_fallback_vue_code(theme="默认主题", width=1080, height=1920):
|
||||
"""
|
||||
生成备用的Vue代码
|
||||
"""
|
||||
print(f"{Fore.YELLOW}⚠️ 使用备用Vue模板{Style.RESET_ALL}")
|
||||
return f"""<template>
|
||||
<div class="poster-container" :style="containerStyle">
|
||||
<div class="background-layer">
|
||||
<img src="../outputs/background.png" alt="背景" class="background-image" />
|
||||
</div>
|
||||
|
||||
<div class="content-layer">
|
||||
<div class="title-section">
|
||||
<h1 class="main-title">{theme}</h1>
|
||||
<h2 class="subtitle">精彩活动,敬请参与</h2>
|
||||
</div>
|
||||
|
||||
<div class="main-content">
|
||||
<div class="image-gallery">
|
||||
<img src="../outputs/image1.png" alt="活动图片" class="content-image" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer-section">
|
||||
<div class="logo-area">
|
||||
<span class="logo-text">主办方</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {{ computed }} from 'vue'
|
||||
|
||||
const containerStyle = computed(() => ({{
|
||||
width: '{width}px',
|
||||
height: '{height}px',
|
||||
position: 'relative',
|
||||
overflow: 'hidden'
|
||||
}}))
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.poster-container {{
|
||||
position: relative;
|
||||
background: #ffffff;
|
||||
}}
|
||||
|
||||
.background-layer {{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1;
|
||||
}}
|
||||
|
||||
.background-image {{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}}
|
||||
|
||||
.content-layer {{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 2;
|
||||
}}
|
||||
|
||||
.title-section {{
|
||||
position: absolute;
|
||||
top: 20%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
text-align: center;
|
||||
}}
|
||||
|
||||
.main-title {{
|
||||
font-size: 48px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 20px;
|
||||
color: #333;
|
||||
}}
|
||||
|
||||
.subtitle {{
|
||||
font-size: 24px;
|
||||
color: #666;
|
||||
margin-bottom: 40px;
|
||||
}}
|
||||
|
||||
.main-content {{
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}}
|
||||
|
||||
.content-image {{
|
||||
max-width: 400px;
|
||||
max-height: 300px;
|
||||
object-fit: cover;
|
||||
}}
|
||||
|
||||
.footer-section {{
|
||||
position: absolute;
|
||||
bottom: 10%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}}
|
||||
|
||||
.logo-text {{
|
||||
font-size: 18px;
|
||||
color: #666;
|
||||
}}
|
||||
</style>"""
|
||||
except Exception:
|
||||
return "<template><div>Vue代码生成失败</div></template>"
|
||||
|
||||
def save_code(code, file_path="../outputs/generated_code.vue"):
|
||||
"""
|
||||
保存代码到文件
|
||||
"""
|
||||
"""保存代码到文件"""
|
||||
try:
|
||||
# 确保目录存在
|
||||
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
||||
|
||||
# 写入文件
|
||||
with open(file_path, "w", encoding="utf-8") as f:
|
||||
f.write(code)
|
||||
|
||||
print(f"{Fore.GREEN}✅ Vue代码已保存到: {file_path}{Style.RESET_ALL}")
|
||||
|
||||
# 验证文件是否成功创建
|
||||
if os.path.exists(file_path):
|
||||
file_size = os.path.getsize(file_path)
|
||||
print(f"{Fore.CYAN}📁 文件大小: {file_size} 字节{Style.RESET_ALL}")
|
||||
else:
|
||||
print(f"{Fore.RED}❌ 文件保存失败{Style.RESET_ALL}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Fore.RED}❌ 保存代码时出错: {str(e)}{Style.RESET_ALL}")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(f"{Fore.MAGENTA}🚀 开始生成Vue组件...{Style.RESET_ALL}")
|
||||
|
||||
# 测试增强的Vue代码生成
|
||||
test_analysis = {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"main_theme": "端午节海报"
|
||||
}
|
||||
|
||||
# 简单测试
|
||||
test_analysis = {"width": 1080, "height": 1920, "main_theme": "端午节海报"}
|
||||
test_imglist = [
|
||||
{"picture_name": "background", "picture_description": "背景图片"},
|
||||
{"picture_name": "lotus", "picture_description": "荷花装饰"}
|
||||
]
|
||||
|
||||
test_suggestions = {
|
||||
"layer6_title_content": {"content": "端午安康"},
|
||||
"layer7_subtitle_content": {"content": "粽叶飘香,龙舟竞渡"},
|
||||
@ -522,4 +371,3 @@ if __name__ == "__main__":
|
||||
|
||||
vue_code = generate_vue_code_enhanced(test_analysis, test_imglist, test_suggestions)
|
||||
save_code(vue_code)
|
||||
print(f"{Fore.GREEN}✅ Vue组件代码生成完成{Style.RESET_ALL}")
|
||||
|
@ -412,3 +412,4 @@ if __name__ == "__main__":
|
||||
# 启动API服务器
|
||||
print(f"{Fore.GREEN}🚀 启动API服务器 v2.0...{Style.RESET_ALL}")
|
||||
uvicorn.run(app, host="0.0.0.0", port=8000)
|
||||
|
220
scripts/test.py
220
scripts/test.py
@ -1,220 +0,0 @@
|
||||
import json
|
||||
from websocket import create_connection, WebSocketTimeoutException, WebSocketConnectionClosedException
|
||||
import uuid
|
||||
import urllib.request
|
||||
import urllib.parse
|
||||
import random
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
# 定义一个函数来显示GIF图片
|
||||
def show_gif(fname):
|
||||
import base64
|
||||
from IPython import display
|
||||
with open(fname, 'rb') as fd:
|
||||
b64 = base64.b64encode(fd.read()).decode('ascii')
|
||||
return display.HTML(f'<img src="data:image/gif;base64,{b64}" />')
|
||||
|
||||
# 定义一个函数向服务器队列发送提示信息
|
||||
def queue_prompt(prompt):
|
||||
p = {"prompt": prompt, "client_id": client_id}
|
||||
data = json.dumps(p).encode('utf-8')
|
||||
req = urllib.request.Request("http://{}/prompt".format(server_address), data=data)
|
||||
return json.loads(urllib.request.urlopen(req).read())
|
||||
|
||||
# 定义一个函数来获取图片
|
||||
def get_image(filename, subfolder, folder_type):
|
||||
data = {"filename": filename, "subfolder": subfolder, "type": folder_type}
|
||||
url_values = urllib.parse.urlencode(data)
|
||||
with urllib.request.urlopen("http://{}/view?{}".format(server_address, url_values)) as response:
|
||||
return response.read()
|
||||
|
||||
# 定义一个函数来获取历史记录
|
||||
def get_history(prompt_id):
|
||||
with urllib.request.urlopen("http://{}/history/{}".format(server_address, prompt_id)) as response:
|
||||
return json.loads(response.read())
|
||||
|
||||
# 定义一个函数来获取图片,这涉及到监听WebSocket消息
|
||||
def get_images(ws, prompt):
|
||||
prompt_id = queue_prompt(prompt)['prompt_id']
|
||||
print('Prompt: ', prompt)
|
||||
print('Prompt ID: ', prompt_id)
|
||||
output_images = {}
|
||||
|
||||
# 等待执行完成
|
||||
start_time = time.time()
|
||||
while True:
|
||||
if time.time() - start_time > 1200: # 设置2分钟超时
|
||||
print("超时:等待执行完成超过120秒")
|
||||
break
|
||||
|
||||
out = ws.recv()
|
||||
if isinstance(out, str):
|
||||
message = json.loads(out)
|
||||
if message['type'] == 'executing':
|
||||
data = message['data']
|
||||
if data['node'] is None and data['prompt_id'] == prompt_id:
|
||||
print('Execution complete')
|
||||
break # 执行完成
|
||||
else:
|
||||
continue # 预览为二进制数据
|
||||
|
||||
# 获取完成的历史记录
|
||||
history = get_history(prompt_id).get(prompt_id, {})
|
||||
|
||||
if not history:
|
||||
print("未找到该提示的历史记录")
|
||||
return {}
|
||||
|
||||
for node_id in history['outputs']:
|
||||
node_output = history['outputs'][node_id]
|
||||
# 图片分支
|
||||
if 'images' in node_output:
|
||||
images_output = []
|
||||
for image in node_output['images']:
|
||||
try:
|
||||
image_data = get_image(image['filename'], image['subfolder'], image['type'])
|
||||
images_output.append(image_data)
|
||||
except Exception as e:
|
||||
print(f"获取图像错误: {str(e)}")
|
||||
output_images[node_id] = images_output
|
||||
# 视频分支
|
||||
elif 'videos' in node_output:
|
||||
videos_output = []
|
||||
for video in node_output['videos']:
|
||||
try:
|
||||
video_data = get_image(video['filename'], video['subfolder'], video['type'])
|
||||
videos_output.append(video_data)
|
||||
except Exception as e:
|
||||
print(f"获取视频错误: {str(e)}")
|
||||
output_images[node_id] = videos_output
|
||||
|
||||
print(f'Obtained {len(output_images)} image/video sets')
|
||||
return output_images
|
||||
|
||||
# 解析工作流并获取图片
|
||||
def parse_workflow(prompt, seed, workflowfile):
|
||||
print(f'Workflow file: {workflowfile}')
|
||||
try:
|
||||
with open(workflowfile, 'r', encoding="utf-8") as f:
|
||||
prompt_data = json.load(f)
|
||||
# 设置文本提示
|
||||
prompt_data["6"]["inputs"]["text"] = prompt
|
||||
# 设置随机种子(如果需要)
|
||||
if "Ksampler" in prompt_data:
|
||||
if "seed" in prompt_data["Ksampler"]["inputs"]:
|
||||
prompt_data["Ksampler"]["inputs"]["seed"] = seed
|
||||
elif "noise_seed" in prompt_data["Ksampler"]["inputs"]:
|
||||
prompt_data["Ksampler"]["inputs"]["noise_seed"] = seed
|
||||
return prompt_data
|
||||
except Exception as e:
|
||||
print(f"工作流解析错误: {str(e)}")
|
||||
return {}
|
||||
|
||||
# 生成图像并保存
|
||||
def generate_clip(prompt, seed, workflowfile, idx):
|
||||
print(f'Processing prompt #{idx}: "{prompt[:50]}{"..." if len(prompt) > 50 else ""}"')
|
||||
print(f'Using seed: {seed}')
|
||||
|
||||
try:
|
||||
# 使用正确的WebSocket连接方式
|
||||
ws_url = f"ws://{server_address}/ws?clientId={client_id}"
|
||||
|
||||
# 使用 create_connection
|
||||
ws = create_connection(ws_url, timeout=600)
|
||||
|
||||
# 解析工作流
|
||||
workflow_data = parse_workflow(prompt, seed, workflowfile)
|
||||
if not workflow_data:
|
||||
print("工作流数据为空")
|
||||
return
|
||||
|
||||
# 获取图像
|
||||
images = get_images(ws, workflow_data)
|
||||
|
||||
# 关闭连接
|
||||
ws.close()
|
||||
except WebSocketTimeoutException as e:
|
||||
print(f"WebSocket连接超时: {str(e)}")
|
||||
return
|
||||
except WebSocketConnectionClosedException as e:
|
||||
print(f"WebSocket连接已关闭: {str(e)}")
|
||||
return
|
||||
except Exception as e:
|
||||
print(f"WebSocket错误: {str(e)}")
|
||||
return
|
||||
|
||||
saved_files = []
|
||||
if images:
|
||||
for node_id, image_list in images.items():
|
||||
for i, image_data in enumerate(image_list):
|
||||
# 格式化时间戳
|
||||
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
|
||||
# 创建唯一文件名
|
||||
filename = f"{idx}_{seed}_{timestamp}_{i}.png"
|
||||
file_path = f"{WORKING_DIR}/{filename}"
|
||||
|
||||
print(f'Saving to: {file_path}')
|
||||
try:
|
||||
with open(file_path, "wb") as f:
|
||||
f.write(image_data)
|
||||
saved_files.append(file_path)
|
||||
except Exception as e:
|
||||
print(f"文件保存错误: {str(e)}")
|
||||
else:
|
||||
print("未获取到图像数据")
|
||||
|
||||
if saved_files:
|
||||
print(f"成功生成 {len(saved_files)} 张图片")
|
||||
else:
|
||||
print("未保存任何图片")
|
||||
|
||||
# 直接在代码中定义提示词列表
|
||||
PROMPTS = [
|
||||
"A beautiful sunset over the ocean, realistic, cinematic lighting",
|
||||
"A futuristic cityscape at night, cyberpunk style, neon lights",
|
||||
"An ancient forest with magical creatures, fantasy, photorealistic",
|
||||
"A steampunk laboratory with bubbling beakers and intricate machinery",
|
||||
"Abstract geometric patterns in vibrant colors, digital art",
|
||||
"A majestic lion in the African savannah, golden hour lighting",
|
||||
"A cozy cabin in the mountains during winter, warm lights inside",
|
||||
"A detailed close-up of a butterfly on a flower, macro photography",
|
||||
"Underwater scene with coral reef and tropical fish, crystal clear water"
|
||||
]
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 设置工作目录和项目相关的路径
|
||||
WORKING_DIR = 'output'
|
||||
workflowfile = './workflows/flux_redux.json'
|
||||
COMFYUI_ENDPOINT = '101.201.50.90:8188'
|
||||
|
||||
# 服务器配置
|
||||
global server_address, client_id
|
||||
server_address = COMFYUI_ENDPOINT
|
||||
client_id = str(uuid.uuid4()) # 生成一个唯一的客户端ID
|
||||
|
||||
# 种子设置 - 可以选择固定或随机
|
||||
USE_RANDOM_SEED = True # 设为False则使用固定种子
|
||||
base_seed = 15465856
|
||||
|
||||
print(f"Starting image generation with ComfyUI at {server_address}")
|
||||
print(f"Working directory: {WORKING_DIR}")
|
||||
print(f"Workflow file: {workflowfile}")
|
||||
print(f"Client ID: {client_id}")
|
||||
|
||||
start_time = time.time()
|
||||
|
||||
# 处理每个提示词
|
||||
for idx, prompt in enumerate(PROMPTS, start=1):
|
||||
# 设置种子
|
||||
current_seed = random.randint(1, 10**8) if USE_RANDOM_SEED else base_seed
|
||||
|
||||
print(f"\n===== Processing Prompt #{idx} of {len(PROMPTS)} =====")
|
||||
generate_clip(prompt, current_seed, workflowfile, idx)
|
||||
|
||||
# 添加延迟以避免服务器过载
|
||||
time.sleep(2) # 2秒延迟
|
||||
|
||||
elapsed = time.time() - start_time
|
||||
print(f"\nProcessing completed in {elapsed:.2f} seconds")
|
||||
print(f"Generated images for {len(PROMPTS)} prompts")
|
0
scripts/test_vue_templates.py
Normal file
0
scripts/test_vue_templates.py
Normal file
@ -258,6 +258,60 @@ def get_file_info(file_path: str) -> Dict:
|
||||
}
|
||||
|
||||
|
||||
# Vue模板工具函数
|
||||
def load_vue_templates() -> Dict:
|
||||
"""加载预定义的Vue模板配置"""
|
||||
template_path = "../configs/vue_templates.yaml"
|
||||
try:
|
||||
with open(template_path, 'r', encoding='utf-8') as f:
|
||||
templates = yaml.safe_load(f)
|
||||
return templates.get('vue_templates', {})
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
|
||||
def determine_template_type(parse_imglist: List[Dict]) -> str:
|
||||
"""根据图片信息确定模板类型"""
|
||||
for img_info in parse_imglist:
|
||||
description = img_info.get('picture_description', '').lower()
|
||||
name = img_info.get('picture_name', '').lower()
|
||||
|
||||
festival_keywords = ['中秋', '春节', '端午', '国庆', '元宵', '重阳', '节日', 'festival']
|
||||
if any(keyword in description or keyword in name for keyword in festival_keywords):
|
||||
return 'festival'
|
||||
|
||||
illustration_keywords = ['插画', '建筑', '校园', '大学', '教学楼', 'illustration', 'building']
|
||||
if any(keyword in description or keyword in name for keyword in illustration_keywords):
|
||||
return 'illustration'
|
||||
|
||||
return 'illustration'
|
||||
|
||||
|
||||
def clean_vue_code(result: str) -> str:
|
||||
"""清理Vue代码,移除markdown标记"""
|
||||
if not result:
|
||||
return result
|
||||
|
||||
if "```vue" in result:
|
||||
result = result.split("```vue")[1].split("```")[0].strip()
|
||||
elif "```html" in result:
|
||||
result = result.split("```html")[1].split("```")[0].strip()
|
||||
elif result.startswith("```") and result.endswith("```"):
|
||||
result = result[3:-3].strip()
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def extract_content_from_suggestions(suggestions: Dict) -> Tuple[str, str, str]:
|
||||
"""从建议中提取文案内容"""
|
||||
try:
|
||||
title_content = suggestions.get('layer6_title_content', {}).get('content', '南开风采')
|
||||
subtitle_content = suggestions.get('layer7_subtitle_content', {}).get('content', '百年学府,智慧之光')
|
||||
logo_content = suggestions.get('layer5_logo_content', {}).get('text', '')
|
||||
return title_content, subtitle_content, logo_content
|
||||
except Exception:
|
||||
return '南开风采', '百年学府,智慧之光', ''
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 测试工具函数
|
||||
print(f"{Fore.MAGENTA}🧪 测试工具函数{Style.RESET_ALL}")
|
||||
|
0
scripts/问题.md
Normal file
0
scripts/问题.md
Normal file
@ -0,0 +1,226 @@
|
||||
{
|
||||
"6": {
|
||||
"inputs": {
|
||||
"text": [
|
||||
"31",
|
||||
0
|
||||
],
|
||||
"clip": [
|
||||
"11",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode",
|
||||
"_meta": {
|
||||
"title": "CLIP Text Encode (Positive Prompt)"
|
||||
}
|
||||
},
|
||||
"8": {
|
||||
"inputs": {
|
||||
"samples": [
|
||||
"13",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"10",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "VAEDecode",
|
||||
"_meta": {
|
||||
"title": "VAE解码"
|
||||
}
|
||||
},
|
||||
"9": {
|
||||
"inputs": {
|
||||
"filename_prefix": "ComfyUI",
|
||||
"images": [
|
||||
"8",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "SaveImage",
|
||||
"_meta": {
|
||||
"title": "保存图像"
|
||||
}
|
||||
},
|
||||
"10": {
|
||||
"inputs": {
|
||||
"vae_name": "ae.safetensors"
|
||||
},
|
||||
"class_type": "VAELoader",
|
||||
"_meta": {
|
||||
"title": "加载VAE"
|
||||
}
|
||||
},
|
||||
"11": {
|
||||
"inputs": {
|
||||
"clip_name1": "t5xxl_fp16.safetensors",
|
||||
"clip_name2": "clip_l.safetensors",
|
||||
"type": "flux",
|
||||
"device": "default"
|
||||
},
|
||||
"class_type": "DualCLIPLoader",
|
||||
"_meta": {
|
||||
"title": "双CLIP加载器"
|
||||
}
|
||||
},
|
||||
"12": {
|
||||
"inputs": {
|
||||
"unet_name": "flux1-dev.safetensors",
|
||||
"weight_dtype": "default"
|
||||
},
|
||||
"class_type": "UNETLoader",
|
||||
"_meta": {
|
||||
"title": "UNet加载器"
|
||||
}
|
||||
},
|
||||
"13": {
|
||||
"inputs": {
|
||||
"noise": [
|
||||
"25",
|
||||
0
|
||||
],
|
||||
"guider": [
|
||||
"22",
|
||||
0
|
||||
],
|
||||
"sampler": [
|
||||
"16",
|
||||
0
|
||||
],
|
||||
"sigmas": [
|
||||
"17",
|
||||
0
|
||||
],
|
||||
"latent_image": [
|
||||
"27",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "SamplerCustomAdvanced",
|
||||
"_meta": {
|
||||
"title": "自定义采样器(高级)"
|
||||
}
|
||||
},
|
||||
"16": {
|
||||
"inputs": {
|
||||
"sampler_name": "euler"
|
||||
},
|
||||
"class_type": "KSamplerSelect",
|
||||
"_meta": {
|
||||
"title": "K采样器选择"
|
||||
}
|
||||
},
|
||||
"17": {
|
||||
"inputs": {
|
||||
"scheduler": "simple",
|
||||
"steps": 25,
|
||||
"denoise": 1,
|
||||
"model": [
|
||||
"30",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "BasicScheduler",
|
||||
"_meta": {
|
||||
"title": "基本调度器"
|
||||
}
|
||||
},
|
||||
"22": {
|
||||
"inputs": {
|
||||
"model": [
|
||||
"30",
|
||||
0
|
||||
],
|
||||
"conditioning": [
|
||||
"26",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "BasicGuider",
|
||||
"_meta": {
|
||||
"title": "基本引导器"
|
||||
}
|
||||
},
|
||||
"25": {
|
||||
"inputs": {
|
||||
"noise_seed": 142213168350829
|
||||
},
|
||||
"class_type": "RandomNoise",
|
||||
"_meta": {
|
||||
"title": "随机噪波"
|
||||
}
|
||||
},
|
||||
"26": {
|
||||
"inputs": {
|
||||
"guidance": 3.5,
|
||||
"conditioning": [
|
||||
"6",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "FluxGuidance",
|
||||
"_meta": {
|
||||
"title": "Flux引导"
|
||||
}
|
||||
},
|
||||
"27": {
|
||||
"inputs": {
|
||||
"width": "1080",
|
||||
"height": "1920",
|
||||
"batch_size": "2"
|
||||
},
|
||||
"class_type": "EmptySD3LatentImage",
|
||||
"_meta": {
|
||||
"title": "空Latent图像(SD3)"
|
||||
}
|
||||
},
|
||||
"30": {
|
||||
"inputs": {
|
||||
"max_shift": 1.1500000000000001,
|
||||
"base_shift": 0.5000000000000001,
|
||||
"width": 1024,
|
||||
"height": 1024,
|
||||
"model": [
|
||||
"12",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "ModelSamplingFlux",
|
||||
"_meta": {
|
||||
"title": "采样算法(Flux)"
|
||||
}
|
||||
},
|
||||
"31": {
|
||||
"inputs": {
|
||||
"user_prompt": "作为一个AI提示词专家,请你仿照范例,根据我给出的主题,生成一条符合下列要求的提示词,来让CLIP模型可以更好地理解画面主体。注意:你需要仿照下面的示例详细分析(仅仿照写法,而不仿照任何内容),将用户的需求转化为详细的提示词。\\n 要求共六条,请严格遵守:\\n 1: 用自然语言简单句来描述画面,请避免出现过于长的,或者格式过于复杂的句子,句子中不要出现*等特殊符号。\\n 2.用英语表达。 \\n 3.直接给出prompt内容即可,不需要任何解释和说明。\\n 4. 每条prompt至少50词,不超过200词。\\n 5.避免模棱两可的说法。\\n 6.描述的最开始加入:“no text, no AI style”\\n 例如:\nCartoon-Style Nankai University Main Building,\nvividly depicted with rounded edges and pastel gradients, the iconic Gothic-Revival structure stands majestically. Crimson brick façade contrasts with golden-glowing arched windows, while whimsical cloud-shaped eaves drip melted clock details. A giant smiling sun hangs low, casting honey-golden rays through simplified pine trees, creating striped shadows dancing on marble stairs.\n\nTranslucent ghostly scholars from 1919 float near pillars holding glowing books, their outlines shimmering like liquid mercury. Oversized autumn leaves (stylized as maple-red origami) spiral around twin bell towers chiming visible musical notes. Puddles on the ground mirror upside-down building reflections rippling with calculus formulas.\n\nEnvironment:\nSurreal candy-pink sunset gradients blend into starry indigo sky above. Playful squirrels wearing tiny graduation caps scamper across emerald lawns textured like green velvet.",
|
||||
"system_prompt": "腾讯的周年庆,qq,wx要素齐全",
|
||||
"enable_history": false,
|
||||
"max_history": 10,
|
||||
"history_json": "",
|
||||
"save_path": "./chat_history.json",
|
||||
"api_config": [
|
||||
"32",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "DeepSeekChat",
|
||||
"_meta": {
|
||||
"title": "LLM Model Input Box"
|
||||
}
|
||||
},
|
||||
"32": {
|
||||
"inputs": {
|
||||
"config_name": "DeepSeek官方Chat API",
|
||||
"temperature": 1,
|
||||
"max_tokens": 512,
|
||||
"stream": false,
|
||||
"api_key": ""
|
||||
},
|
||||
"class_type": "DeepSeekAPIConfig",
|
||||
"_meta": {
|
||||
"title": "LLM API Model Selector"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,226 @@
|
||||
{
|
||||
"6": {
|
||||
"inputs": {
|
||||
"text": [
|
||||
"31",
|
||||
0
|
||||
],
|
||||
"clip": [
|
||||
"11",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode",
|
||||
"_meta": {
|
||||
"title": "CLIP Text Encode (Positive Prompt)"
|
||||
}
|
||||
},
|
||||
"8": {
|
||||
"inputs": {
|
||||
"samples": [
|
||||
"13",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"10",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "VAEDecode",
|
||||
"_meta": {
|
||||
"title": "VAE解码"
|
||||
}
|
||||
},
|
||||
"9": {
|
||||
"inputs": {
|
||||
"filename_prefix": "ComfyUI",
|
||||
"images": [
|
||||
"8",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "SaveImage",
|
||||
"_meta": {
|
||||
"title": "保存图像"
|
||||
}
|
||||
},
|
||||
"10": {
|
||||
"inputs": {
|
||||
"vae_name": "ae.safetensors"
|
||||
},
|
||||
"class_type": "VAELoader",
|
||||
"_meta": {
|
||||
"title": "加载VAE"
|
||||
}
|
||||
},
|
||||
"11": {
|
||||
"inputs": {
|
||||
"clip_name1": "t5xxl_fp16.safetensors",
|
||||
"clip_name2": "clip_l.safetensors",
|
||||
"type": "flux",
|
||||
"device": "default"
|
||||
},
|
||||
"class_type": "DualCLIPLoader",
|
||||
"_meta": {
|
||||
"title": "双CLIP加载器"
|
||||
}
|
||||
},
|
||||
"12": {
|
||||
"inputs": {
|
||||
"unet_name": "flux1-dev.safetensors",
|
||||
"weight_dtype": "default"
|
||||
},
|
||||
"class_type": "UNETLoader",
|
||||
"_meta": {
|
||||
"title": "UNet加载器"
|
||||
}
|
||||
},
|
||||
"13": {
|
||||
"inputs": {
|
||||
"noise": [
|
||||
"25",
|
||||
0
|
||||
],
|
||||
"guider": [
|
||||
"22",
|
||||
0
|
||||
],
|
||||
"sampler": [
|
||||
"16",
|
||||
0
|
||||
],
|
||||
"sigmas": [
|
||||
"17",
|
||||
0
|
||||
],
|
||||
"latent_image": [
|
||||
"27",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "SamplerCustomAdvanced",
|
||||
"_meta": {
|
||||
"title": "自定义采样器(高级)"
|
||||
}
|
||||
},
|
||||
"16": {
|
||||
"inputs": {
|
||||
"sampler_name": "euler"
|
||||
},
|
||||
"class_type": "KSamplerSelect",
|
||||
"_meta": {
|
||||
"title": "K采样器选择"
|
||||
}
|
||||
},
|
||||
"17": {
|
||||
"inputs": {
|
||||
"scheduler": "simple",
|
||||
"steps": 25,
|
||||
"denoise": 1,
|
||||
"model": [
|
||||
"30",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "BasicScheduler",
|
||||
"_meta": {
|
||||
"title": "基本调度器"
|
||||
}
|
||||
},
|
||||
"22": {
|
||||
"inputs": {
|
||||
"model": [
|
||||
"30",
|
||||
0
|
||||
],
|
||||
"conditioning": [
|
||||
"26",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "BasicGuider",
|
||||
"_meta": {
|
||||
"title": "基本引导器"
|
||||
}
|
||||
},
|
||||
"25": {
|
||||
"inputs": {
|
||||
"noise_seed": 142213168350829
|
||||
},
|
||||
"class_type": "RandomNoise",
|
||||
"_meta": {
|
||||
"title": "随机噪波"
|
||||
}
|
||||
},
|
||||
"26": {
|
||||
"inputs": {
|
||||
"guidance": 3.5,
|
||||
"conditioning": [
|
||||
"6",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "FluxGuidance",
|
||||
"_meta": {
|
||||
"title": "Flux引导"
|
||||
}
|
||||
},
|
||||
"27": {
|
||||
"inputs": {
|
||||
"width": "1080",
|
||||
"height": "1920",
|
||||
"batch_size": "2"
|
||||
},
|
||||
"class_type": "EmptySD3LatentImage",
|
||||
"_meta": {
|
||||
"title": "空Latent图像(SD3)"
|
||||
}
|
||||
},
|
||||
"30": {
|
||||
"inputs": {
|
||||
"max_shift": 1.1500000000000001,
|
||||
"base_shift": 0.5000000000000001,
|
||||
"width": 1024,
|
||||
"height": 1024,
|
||||
"model": [
|
||||
"12",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "ModelSamplingFlux",
|
||||
"_meta": {
|
||||
"title": "采样算法(Flux)"
|
||||
}
|
||||
},
|
||||
"31": {
|
||||
"inputs": {
|
||||
"user_prompt": "作为一个AI提示词专家,请你仿照范例,根据我给出的主题,生成一条符合下列要求的提示词,来让CLIP模型可以更好地理解画面主体。注意:你需要仿照下面的示例详细分析(仅仿照写法,而不仿照任何内容),将用户的需求转化为详细的提示词。\\n 要求共六条,请严格遵守:\\n 1: 用自然语言简单句来描述画面,请避免出现过于长的,或者格式过于复杂的句子,句子中不要出现*等特殊符号。\\n 2.用英语表达。 \\n 3.直接给出prompt内容即可,不需要任何解释和说明。\\n 4. 每条prompt至少50词,不超过200词。\\n 5.避免模棱两可的说法。\\n 6.描述的最开始加入:“no text, no AI style”\\n 例如:\nCartoon-Style Nankai University Main Building,\nvividly depicted with rounded edges and pastel gradients, the iconic Gothic-Revival structure stands majestically. Crimson brick façade contrasts with golden-glowing arched windows, while whimsical cloud-shaped eaves drip melted clock details. A giant smiling sun hangs low, casting honey-golden rays through simplified pine trees, creating striped shadows dancing on marble stairs.\n\nTranslucent ghostly scholars from 1919 float near pillars holding glowing books, their outlines shimmering like liquid mercury. Oversized autumn leaves (stylized as maple-red origami) spiral around twin bell towers chiming visible musical notes. Puddles on the ground mirror upside-down building reflections rippling with calculus formulas.\n\nEnvironment:\nSurreal candy-pink sunset gradients blend into starry indigo sky above. Playful squirrels wearing tiny graduation caps scamper across emerald lawns textured like green velvet.",
|
||||
"system_prompt": "端午节海报,传统风格",
|
||||
"enable_history": false,
|
||||
"max_history": 10,
|
||||
"history_json": "",
|
||||
"save_path": "./chat_history.json",
|
||||
"api_config": [
|
||||
"32",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "DeepSeekChat",
|
||||
"_meta": {
|
||||
"title": "LLM Model Input Box"
|
||||
}
|
||||
},
|
||||
"32": {
|
||||
"inputs": {
|
||||
"config_name": "DeepSeek官方Chat API",
|
||||
"temperature": 1,
|
||||
"max_tokens": 512,
|
||||
"stream": false,
|
||||
"api_key": ""
|
||||
},
|
||||
"class_type": "DeepSeekAPIConfig",
|
||||
"_meta": {
|
||||
"title": "LLM API Model Selector"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,226 @@
|
||||
{
|
||||
"6": {
|
||||
"inputs": {
|
||||
"text": [
|
||||
"31",
|
||||
0
|
||||
],
|
||||
"clip": [
|
||||
"11",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode",
|
||||
"_meta": {
|
||||
"title": "CLIP Text Encode (Positive Prompt)"
|
||||
}
|
||||
},
|
||||
"8": {
|
||||
"inputs": {
|
||||
"samples": [
|
||||
"13",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"10",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "VAEDecode",
|
||||
"_meta": {
|
||||
"title": "VAE解码"
|
||||
}
|
||||
},
|
||||
"9": {
|
||||
"inputs": {
|
||||
"filename_prefix": "ComfyUI",
|
||||
"images": [
|
||||
"8",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "SaveImage",
|
||||
"_meta": {
|
||||
"title": "保存图像"
|
||||
}
|
||||
},
|
||||
"10": {
|
||||
"inputs": {
|
||||
"vae_name": "ae.safetensors"
|
||||
},
|
||||
"class_type": "VAELoader",
|
||||
"_meta": {
|
||||
"title": "加载VAE"
|
||||
}
|
||||
},
|
||||
"11": {
|
||||
"inputs": {
|
||||
"clip_name1": "t5xxl_fp16.safetensors",
|
||||
"clip_name2": "clip_l.safetensors",
|
||||
"type": "flux",
|
||||
"device": "default"
|
||||
},
|
||||
"class_type": "DualCLIPLoader",
|
||||
"_meta": {
|
||||
"title": "双CLIP加载器"
|
||||
}
|
||||
},
|
||||
"12": {
|
||||
"inputs": {
|
||||
"unet_name": "flux1-dev.safetensors",
|
||||
"weight_dtype": "default"
|
||||
},
|
||||
"class_type": "UNETLoader",
|
||||
"_meta": {
|
||||
"title": "UNet加载器"
|
||||
}
|
||||
},
|
||||
"13": {
|
||||
"inputs": {
|
||||
"noise": [
|
||||
"25",
|
||||
0
|
||||
],
|
||||
"guider": [
|
||||
"22",
|
||||
0
|
||||
],
|
||||
"sampler": [
|
||||
"16",
|
||||
0
|
||||
],
|
||||
"sigmas": [
|
||||
"17",
|
||||
0
|
||||
],
|
||||
"latent_image": [
|
||||
"27",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "SamplerCustomAdvanced",
|
||||
"_meta": {
|
||||
"title": "自定义采样器(高级)"
|
||||
}
|
||||
},
|
||||
"16": {
|
||||
"inputs": {
|
||||
"sampler_name": "euler"
|
||||
},
|
||||
"class_type": "KSamplerSelect",
|
||||
"_meta": {
|
||||
"title": "K采样器选择"
|
||||
}
|
||||
},
|
||||
"17": {
|
||||
"inputs": {
|
||||
"scheduler": "simple",
|
||||
"steps": 25,
|
||||
"denoise": 1,
|
||||
"model": [
|
||||
"30",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "BasicScheduler",
|
||||
"_meta": {
|
||||
"title": "基本调度器"
|
||||
}
|
||||
},
|
||||
"22": {
|
||||
"inputs": {
|
||||
"model": [
|
||||
"30",
|
||||
0
|
||||
],
|
||||
"conditioning": [
|
||||
"26",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "BasicGuider",
|
||||
"_meta": {
|
||||
"title": "基本引导器"
|
||||
}
|
||||
},
|
||||
"25": {
|
||||
"inputs": {
|
||||
"noise_seed": 142213168350829
|
||||
},
|
||||
"class_type": "RandomNoise",
|
||||
"_meta": {
|
||||
"title": "随机噪波"
|
||||
}
|
||||
},
|
||||
"26": {
|
||||
"inputs": {
|
||||
"guidance": 3.5,
|
||||
"conditioning": [
|
||||
"6",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "FluxGuidance",
|
||||
"_meta": {
|
||||
"title": "Flux引导"
|
||||
}
|
||||
},
|
||||
"27": {
|
||||
"inputs": {
|
||||
"width": "1080",
|
||||
"height": "1920",
|
||||
"batch_size": "2"
|
||||
},
|
||||
"class_type": "EmptySD3LatentImage",
|
||||
"_meta": {
|
||||
"title": "空Latent图像(SD3)"
|
||||
}
|
||||
},
|
||||
"30": {
|
||||
"inputs": {
|
||||
"max_shift": 1.1500000000000001,
|
||||
"base_shift": 0.5000000000000001,
|
||||
"width": 1024,
|
||||
"height": 1024,
|
||||
"model": [
|
||||
"12",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "ModelSamplingFlux",
|
||||
"_meta": {
|
||||
"title": "采样算法(Flux)"
|
||||
}
|
||||
},
|
||||
"31": {
|
||||
"inputs": {
|
||||
"user_prompt": "作为一个AI提示词专家,请你仿照范例,根据我给出的主题,生成一条符合下列要求的提示词,来让CLIP模型可以更好地理解画面主体。注意:你需要仿照下面的示例详细分析(仅仿照写法,而不仿照任何内容),将用户的需求转化为详细的提示词。\\n 要求共六条,请严格遵守:\\n 1: 用自然语言简单句来描述画面,请避免出现过于长的,或者格式过于复杂的句子,句子中不要出现*等特殊符号。\\n 2.用英语表达。 \\n 3.直接给出prompt内容即可,不需要任何解释和说明。\\n 4. 每条prompt至少50词,不超过200词。\\n 5.避免模棱两可的说法。\\n 6.描述的最开始加入:“no text, no AI style”\\n 例如:\nCartoon-Style Nankai University Main Building,\nvividly depicted with rounded edges and pastel gradients, the iconic Gothic-Revival structure stands majestically. Crimson brick façade contrasts with golden-glowing arched windows, while whimsical cloud-shaped eaves drip melted clock details. A giant smiling sun hangs low, casting honey-golden rays through simplified pine trees, creating striped shadows dancing on marble stairs.\n\nTranslucent ghostly scholars from 1919 float near pillars holding glowing books, their outlines shimmering like liquid mercury. Oversized autumn leaves (stylized as maple-red origami) spiral around twin bell towers chiming visible musical notes. Puddles on the ground mirror upside-down building reflections rippling with calculus formulas.\n\nEnvironment:\nSurreal candy-pink sunset gradients blend into starry indigo sky above. Playful squirrels wearing tiny graduation caps scamper across emerald lawns textured like green velvet.",
|
||||
"system_prompt": "端午节海报,传统风格",
|
||||
"enable_history": false,
|
||||
"max_history": 10,
|
||||
"history_json": "",
|
||||
"save_path": "./chat_history.json",
|
||||
"api_config": [
|
||||
"32",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "DeepSeekChat",
|
||||
"_meta": {
|
||||
"title": "LLM Model Input Box"
|
||||
}
|
||||
},
|
||||
"32": {
|
||||
"inputs": {
|
||||
"config_name": "DeepSeek官方Chat API",
|
||||
"temperature": 1,
|
||||
"max_tokens": 512,
|
||||
"stream": false,
|
||||
"api_key": ""
|
||||
},
|
||||
"class_type": "DeepSeekAPIConfig",
|
||||
"_meta": {
|
||||
"title": "LLM API Model Selector"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,226 @@
|
||||
{
|
||||
"6": {
|
||||
"inputs": {
|
||||
"text": [
|
||||
"31",
|
||||
0
|
||||
],
|
||||
"clip": [
|
||||
"11",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode",
|
||||
"_meta": {
|
||||
"title": "CLIP Text Encode (Positive Prompt)"
|
||||
}
|
||||
},
|
||||
"8": {
|
||||
"inputs": {
|
||||
"samples": [
|
||||
"13",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"10",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "VAEDecode",
|
||||
"_meta": {
|
||||
"title": "VAE解码"
|
||||
}
|
||||
},
|
||||
"9": {
|
||||
"inputs": {
|
||||
"filename_prefix": "ComfyUI",
|
||||
"images": [
|
||||
"8",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "SaveImage",
|
||||
"_meta": {
|
||||
"title": "保存图像"
|
||||
}
|
||||
},
|
||||
"10": {
|
||||
"inputs": {
|
||||
"vae_name": "ae.safetensors"
|
||||
},
|
||||
"class_type": "VAELoader",
|
||||
"_meta": {
|
||||
"title": "加载VAE"
|
||||
}
|
||||
},
|
||||
"11": {
|
||||
"inputs": {
|
||||
"clip_name1": "t5xxl_fp16.safetensors",
|
||||
"clip_name2": "clip_l.safetensors",
|
||||
"type": "flux",
|
||||
"device": "default"
|
||||
},
|
||||
"class_type": "DualCLIPLoader",
|
||||
"_meta": {
|
||||
"title": "双CLIP加载器"
|
||||
}
|
||||
},
|
||||
"12": {
|
||||
"inputs": {
|
||||
"unet_name": "flux1-dev.safetensors",
|
||||
"weight_dtype": "default"
|
||||
},
|
||||
"class_type": "UNETLoader",
|
||||
"_meta": {
|
||||
"title": "UNet加载器"
|
||||
}
|
||||
},
|
||||
"13": {
|
||||
"inputs": {
|
||||
"noise": [
|
||||
"25",
|
||||
0
|
||||
],
|
||||
"guider": [
|
||||
"22",
|
||||
0
|
||||
],
|
||||
"sampler": [
|
||||
"16",
|
||||
0
|
||||
],
|
||||
"sigmas": [
|
||||
"17",
|
||||
0
|
||||
],
|
||||
"latent_image": [
|
||||
"27",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "SamplerCustomAdvanced",
|
||||
"_meta": {
|
||||
"title": "自定义采样器(高级)"
|
||||
}
|
||||
},
|
||||
"16": {
|
||||
"inputs": {
|
||||
"sampler_name": "euler"
|
||||
},
|
||||
"class_type": "KSamplerSelect",
|
||||
"_meta": {
|
||||
"title": "K采样器选择"
|
||||
}
|
||||
},
|
||||
"17": {
|
||||
"inputs": {
|
||||
"scheduler": "simple",
|
||||
"steps": 25,
|
||||
"denoise": 1,
|
||||
"model": [
|
||||
"30",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "BasicScheduler",
|
||||
"_meta": {
|
||||
"title": "基本调度器"
|
||||
}
|
||||
},
|
||||
"22": {
|
||||
"inputs": {
|
||||
"model": [
|
||||
"30",
|
||||
0
|
||||
],
|
||||
"conditioning": [
|
||||
"26",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "BasicGuider",
|
||||
"_meta": {
|
||||
"title": "基本引导器"
|
||||
}
|
||||
},
|
||||
"25": {
|
||||
"inputs": {
|
||||
"noise_seed": 142213168350829
|
||||
},
|
||||
"class_type": "RandomNoise",
|
||||
"_meta": {
|
||||
"title": "随机噪波"
|
||||
}
|
||||
},
|
||||
"26": {
|
||||
"inputs": {
|
||||
"guidance": 3.5,
|
||||
"conditioning": [
|
||||
"6",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "FluxGuidance",
|
||||
"_meta": {
|
||||
"title": "Flux引导"
|
||||
}
|
||||
},
|
||||
"27": {
|
||||
"inputs": {
|
||||
"width": "1080",
|
||||
"height": "1920",
|
||||
"batch_size": "2"
|
||||
},
|
||||
"class_type": "EmptySD3LatentImage",
|
||||
"_meta": {
|
||||
"title": "空Latent图像(SD3)"
|
||||
}
|
||||
},
|
||||
"30": {
|
||||
"inputs": {
|
||||
"max_shift": 1.1500000000000001,
|
||||
"base_shift": 0.5000000000000001,
|
||||
"width": 1024,
|
||||
"height": 1024,
|
||||
"model": [
|
||||
"12",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "ModelSamplingFlux",
|
||||
"_meta": {
|
||||
"title": "采样算法(Flux)"
|
||||
}
|
||||
},
|
||||
"31": {
|
||||
"inputs": {
|
||||
"user_prompt": "作为一个AI提示词专家,请你仿照范例,根据我给出的主题,生成一条符合下列要求的提示词,来让CLIP模型可以更好地理解画面主体。注意:你需要仿照下面的示例详细分析(仅仿照写法,而不仿照任何内容),将用户的需求转化为详细的提示词。\\n 要求共六条,请严格遵守:\\n 1: 用自然语言简单句来描述画面,请避免出现过于长的,或者格式过于复杂的句子,句子中不要出现*等特殊符号。\\n 2.用英语表达。 \\n 3.直接给出prompt内容即可,不需要任何解释和说明。\\n 4. 每条prompt至少50词,不超过200词。\\n 5.避免模棱两可的说法。\\n 6.描述的最开始加入:“no text, no AI style”\\n 例如:\nCartoon-Style Nankai University Main Building,\nvividly depicted with rounded edges and pastel gradients, the iconic Gothic-Revival structure stands majestically. Crimson brick façade contrasts with golden-glowing arched windows, while whimsical cloud-shaped eaves drip melted clock details. A giant smiling sun hangs low, casting honey-golden rays through simplified pine trees, creating striped shadows dancing on marble stairs.\n\nTranslucent ghostly scholars from 1919 float near pillars holding glowing books, their outlines shimmering like liquid mercury. Oversized autumn leaves (stylized as maple-red origami) spiral around twin bell towers chiming visible musical notes. Puddles on the ground mirror upside-down building reflections rippling with calculus formulas.\n\nEnvironment:\nSurreal candy-pink sunset gradients blend into starry indigo sky above. Playful squirrels wearing tiny graduation caps scamper across emerald lawns textured like green velvet.",
|
||||
"system_prompt": "端午节海报,传统风格",
|
||||
"enable_history": false,
|
||||
"max_history": 10,
|
||||
"history_json": "",
|
||||
"save_path": "./chat_history.json",
|
||||
"api_config": [
|
||||
"32",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "DeepSeekChat",
|
||||
"_meta": {
|
||||
"title": "LLM Model Input Box"
|
||||
}
|
||||
},
|
||||
"32": {
|
||||
"inputs": {
|
||||
"config_name": "DeepSeek官方Chat API",
|
||||
"temperature": 1,
|
||||
"max_tokens": 512,
|
||||
"stream": false,
|
||||
"api_key": ""
|
||||
},
|
||||
"class_type": "DeepSeekAPIConfig",
|
||||
"_meta": {
|
||||
"title": "LLM API Model Selector"
|
||||
}
|
||||
}
|
||||
}
|
34
接口文档.md
Normal file
34
接口文档.md
Normal file
@ -0,0 +1,34 @@
|
||||
## Vue 模板系统
|
||||
|
||||
系统现在支持两种预定义的 Vue 模板:
|
||||
|
||||
### 1. 插画风模板 (illustration)
|
||||
|
||||
**适用场景**:通用建筑、校园、教学楼等主题
|
||||
**结构**:4 层布局
|
||||
|
||||
- 插画底图:AI 生成的通用建筑插图,彩色插画,色调和谐
|
||||
- 主标题:最大号字体,"见微知著记录南开",放置在不遮挡主体的相对空白处
|
||||
- 南开 logo:南开大学标识
|
||||
- 机构名称:底部居中,"南开大学融媒体中心"
|
||||
|
||||
### 2. 节日模板 (festival)
|
||||
|
||||
**适用场景**:中秋节、春节、端午节等节日主题
|
||||
**结构**:8 层布局
|
||||
|
||||
- 背景图层:AI 生成节日插画
|
||||
- 纯色遮罩:插画主色调遮罩
|
||||
- 小插图背景:节日元素插图
|
||||
- 南开 logo:大学标识
|
||||
- 单位名称:南开大学
|
||||
- 节日名称:具体节日
|
||||
- 目的主题:节日祝福语
|
||||
- 日期元素:当前日期
|
||||
|
||||
**模板自动选择逻辑**:
|
||||
|
||||
- 检测图片描述中的关键词
|
||||
- 节日关键词 → festival 模板
|
||||
- 建筑/插画关键词 → illustration 模板
|
||||
- 默认选择 illustration 模板
|
Loading…
Reference in New Issue
Block a user