"""
@file generate_layout.py
@brief Vue组件代码生成模块
基于DeepSeek API生成响应式Vue 3组件布局代码
@author 王秀强 (2310460@mail.nankai.edu.cn)
@date 2025.5.19
@version v1.0.0
@details
本文件主要实现:
- DeepSeek API调用封装和错误处理
- Vue 3 Composition API组件代码生成
- 海报布局的动态排版和样式生成
- 代码清理和格式化处理
- 备用Vue模板生成机制
@note
- 需要配置DEEPSEEK_API_KEY环境变量
- 支持流式和非流式响应模式
- 生成的Vue代码包含完整的template、script和style部分
- 具备指数退避重试机制处理API限流
@usage
# 生成Vue组件代码
vue_code = generate_vue_code("生成端午节海报Vue组件")
save_code(vue_code, "../outputs/poster.vue")
# 调用DeepSeek API
result, usage = call_deepseek(prompt="请生成代码", temperature=0.6)
@copyright
(c) 2025 砚生项目组
"""
import os
from openai import OpenAI
from dotenv import load_dotenv
import time
from colorama import init, Fore, Back, Style
# 初始化colorama
init(autoreset=True)
# === Config LLM call ===
load_dotenv()
deepseek_url = 'https://api.deepseek.com/v1' # set to be compatible with the OpenAI API
deepseek_api = os.getenv("DEEPSEEK_API_KEY")
if not deepseek_api:
raise ValueError("DEEPSEEK_API_KEY not set!")
def call_deepseek(
messages=None,
system_prompt="你是一个擅长前端开发的AI,专注于生成Vue.js代码。",
prompt=None,
model='deepseek-chat',
temperature=0.6,
max_tokens=2000, # 增加token数量
stream=False,
max_retries=3,
):
"""
调用 DeepSeek API,支持多轮对话和流式/非流式响应
"""
# 初始化 OpenAI 客户端
client = OpenAI(
api_key=deepseek_api,
base_url=deepseek_url,
)
# 参数验证
if messages is None:
if not prompt:
raise ValueError("必须提供 message 或 prompt 参数")
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": prompt}
]
elif not isinstance(messages, list) or not messages:
raise ValueError("message 参数必须是非空列表")
# 模型验证
models = ["deepseek-chat", "deepseek-reasoner"]
if model not in models:
raise ValueError(f"无效的模型名称: {model},可用模型: {models}")
# 调用 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,
temperature=temperature,
max_tokens=max_tokens,
stream=stream
)
# 流式响应
if stream:
def stream_generator():
usage = None
for chunk in response:
if 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
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}")
time.sleep(2 ** attempt) # 指数退避
elif attempt == max_retries - 1:
raise
else:
time.sleep(1)
raise Exception("达到最大重试次数,API 调用失败")
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代码。"
)
system_prompt = (
"你是一个擅长前端开发的AI,专注于生成Vue.js代码。"
"请生成完整的Vue 3组件,包含template、script setup和style部分。"
"确保代码结构清晰,语法正确,可以直接使用。"
"不要包含任何解释文字,只返回纯代码。"
)
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()
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():
"""
生成备用的Vue代码
"""
print(f"{Fore.YELLOW}⚠️ 使用备用Vue模板{Style.RESET_ALL}")
return """
端午节活动
传统文化,现代体验
包粽子体验
亲手制作传统粽子
龙舟竞赛
激情龙舟比赛
文化表演
精彩传统表演
"""
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}")
if __name__ == "__main__":
print(f"{Fore.MAGENTA}🚀 开始生成Vue组件...{Style.RESET_ALL}")
vue_code = generate_vue_code()
save_code(vue_code)
print(f"{Fore.GREEN}✅ Vue组件代码生成完成{Style.RESET_ALL}")