1. 项目概述与核心思路
本文将介绍如何搭建一个能够用大模型自动生成代码的微信小程序 。其核心思路是:用户通过自然语言描述需求,小程序调用大模型API,将描述转换为可执行的微信小程序代码,并实时渲染预览 。**你将学到:**1. 如何创建并配置一个基础的微信小程序项目。
-
如何集成大模型API。
-
如何设计一个简单的UI,让用户输入需求并展示生成的代码和预览。
-
如何安全地将大模型返回的代码字符串动态渲染到小程序页面上。技术栈预览:
技术栈预览:
技术栈预览:
- 前端/界面: 微信小程序原生框架
- AI能力: 大模型API
- 后端(可选): 云开发/自有服务器(用于中转API请求,保护密钥)## 2. 环境与工具准备
- 访问微信公众平台,注册并登录。
2.2 安装开发者工具下载并安装微信开发者工具。这是官方开发、调试和预览的必备工具。
2.3 获取大模型API密钥
以大模型API为例:
- 访问你选择的大模型API平台并注册登录。
- 进入API密钥管理页面,创建一个新的密钥并妥善保存。注意:此密钥不可直接暴露在小程序前端代码中!
2.4 创建小程序项目
- 打开微信开发者工具,选择"小程序"项目。2. 点击"+",填写项目信息:
- 项目名称: AI代码生成助手
- 目录: 选择你的项目存放路径
- AppID: 填入你刚才获取的AppID
- 开发模式: 小程序
- 模板: 选择"JavaScript-基础模板"
- 点击"新建",一个基础的小程序项目就创建完成了。
3. 项目结构设计
创建完成后,你的项目目录结构大致如下,我们需要在此基础上进行修改和新增:
ai-code-miniprogram/
├── pages/
│ ├── index/ # 主页:用户输入与结果展示
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ └── logs/ # (可删除或保留)示例日志页
├── utils/
│ └── util.js # 工具函数
├── app.js # 小程序全局逻辑
├── app.json # 小程序全局配置
├── app.wxss # 小程序全局样式
└── project.config.json # 项目配置
核心页面规划:
pages/index/index:主页面,包含:- 一个文本输入框,用于接收用户的需求描述(如:"生成一个红色的按钮,点击弹出提示")。
- 一个"生成"按钮。
- 一个Tab栏,用于切换查看"代码"和"预览"。
- "代码"面板:显示大模型生成的WXML、WXSS、JS代码。
- "预览"面板:动态渲染生成的代码,实时看到UI效果。
4. 前端界面开发 (pages/index)
4.1 页面布局 (index.wxml)
我们将构建一个简单的双面板布局。
xml
<!-- pages/index/index.wxml -->
<view class="container">
<!-- 头部标题 -->
<view class="header">
<text class="title">🤖 AI 小程序代码生成器</text>
<text class="subtitle">用自然语言描述,自动生成可运行的小程序代码</text>
</view>
<!-- 需求输入区 -->
<view class="input-section">
<textarea
class="input-area"
placeholder="请输入你的需求,例如:生成一个居中的蓝色按钮,文字是'点击我',点击后控制台输出'Hello AI'"
maxlength="500"
value="{{userInput}}"
bindinput="onInputChange"
/>
<text class="char-count">{{userInput.length}}/500</text>
<button class="generate-btn" type="primary" bindtap="onGenerateCode" loading="{{loading}}">
{{loading ? '生成中...' : '开始生成'}}
</button>
</view>
<!-- 结果展示区 -->
<view class="result-section" wx:if="{{hasResult}}">
<!-- Tab切换 -->
<view class="tabs">
<view
class="tab {{activeTab === 'code' ? 'active' : ''}}"
data-tab="code"
bindtap="switchTab"
>
查看代码
</view>
<view
class="tab {{activeTab === 'preview' ? 'active' : ''}}"
data-tab="preview"
bindtap="switchTab"
>
预览效果
</view>
</view>
<!-- 代码面板 -->
<view class="tab-content" wx:if="{{activeTab === 'code'}}">
<view class="code-block">
<view class="code-header">WXML (结构)</view>
<textarea class="code-area" value="{{generatedWxml}}" disabled />
</view>
<view class="code-block">
<view class="code-header">WXSS (样式)</view>
<textarea class="code-area" value="{{generatedWxss}}" disabled />
</view>
<view class="code-block">
<view class="code-header">JS (逻辑)</view>
<textarea class="code-area" value="{{generatedJs}}" disabled />
</view>
</view>
<!-- 预览面板 -->
<view class="tab-content preview-panel" wx:if="{{activeTab === 'preview'}}">
<text class="preview-hint">以下是根据生成的代码动态渲染的预览:</text>
<!-- 动态渲染的核心区域 -->
<view class="preview-container">
<!-- 使用 wx:if 和 template 来动态渲染,这里简化处理 -->
<view wx:if="{{previewData.wxml}}">
<!-- 注意:实际项目中,动态渲染WXML需要更复杂的方案,如使用WXS或第三方库,此处为概念展示 -->
<text>动态渲染预览功能需结合自定义组件或`wx.createSelectorQuery`实现,本文后续会介绍安全方案。</text>
</view>
</view>
</view>
</view>
<!-- 无结果时的提示 -->
<view class="empty-tip" wx:else>
<text>👆 在上方输入你的想法,然后点击"开始生成"</text>
</view>
</view>
4.2 页面样式 (index.wxss)
css
/* pages/index/index.wxss */
.container {
padding: 20rpx;
min-height: 100vh;
background-color: #f5f5f5;
}
.header {
text-align: center;
margin-bottom: 40rpx;
}
.title {
font-size: 40rpx;
font-weight: bold;
display: block;
color: #333;
}
.subtitle {
font-size: 26rpx;
color: #666;
display: block;
margin-top: 10rpx;
}
.input-section {
background: white;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 30rpx;
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.05);
}
.input-area {
width: 100%;
height: 200rpx;
border: 2rpx solid #e0e0e0;
border-radius: 12rpx;
padding: 20rpx;
font-size: 28rpx;
box-sizing: border-box;
margin-bottom: 10rpx;
}
.char-count {
font-size: 24rpx;
color: #999;
text-align: right;
display: block;
}
.generate-btn {
margin-top: 30rpx;
width: 100%;
border-radius: 12rpx;
}
.result-section {
background: white;
border-radius: 16rpx;
overflow: hidden;
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.05);
}
.tabs {
display: flex;
border-bottom: 2rpx solid #f0f0f0;
}
.tab {
flex: 1;
text-align: center;
padding: 24rpx 0;
font-size: 30rpx;
color: #666;
}
.tab.active {
color: #07c160;
font-weight: bold;
border-bottom: 4rpx solid #07c160;
}
.tab-content {
padding: 30rpx;
}
.code-block {
margin-bottom: 30rpx;
}
.code-header {
font-size: 28rpx;
font-weight: bold;
margin-bottom: 15rpx;
color: #333;
}
.code-area {
width: 100%;
height: 200rpx;
background-color: #f8f9fa;
border: 1rpx solid #ddd;
border-radius: 8rpx;
padding: 15rpx;
font-family: 'Courier New', monospace;
font-size: 24rpx;
color: #333;
box-sizing: border-box;
}
.preview-panel {
min-height: 400rpx;
}
.preview-hint {
font-size: 26rpx;
color: #666;
display: block;
margin-bottom: 30rpx;
}
.preview-container {
border: 2rpx dashed #07c160;
border-radius: 12rpx;
padding: 40rpx;
text-align: center;
}
.empty-tip {
text-align: center;
padding: 100rpx 20rpx;
color: #999;
font-size: 28rpx;
}
4.3 页面逻辑 (index.js) - 第一部分:数据与交互
这里先实现基础的数据绑定和界面交互,AI调用部分后续添加。
javascript
// pages/index/index.js
Page({
/**
* 页面的初始数据
*/
data: {
userInput: '', // 用户输入的需求描述
loading: false, // 生成按钮的加载状态
hasResult: false, // 是否有生成结果
activeTab: 'code', // 当前激活的Tab:'code' 或 'preview'
// 生成的结果
generatedWxml: '',
generatedWxss: '',
generatedJs: '',
// 预览数据(简化版)
previewData: {
wxml: '',
wxss: '',
js: ''
}
},
/**
* 监听输入框变化
*/
onInputChange(e) {
this.setData({
userInput: e.detail.value
});
},
/**
* 切换Tab
*/
switchTab(e) {
const tab = e.currentTarget.dataset.tab;
this.setData({
activeTab: tab
});
},
/**
* 点击生成按钮
* 目前是模拟,下一步将接入真实AI
*/
onGenerateCode() {
const input = this.data.userInput.trim();
if (!input) {
wx.showToast({
title: '请输入需求描述',
icon: 'none'
});
return;
}
this.setData({ loading: true });
// 模拟AI生成延迟
setTimeout(() => {
// 这里是模拟数据,后续替换为真实的AI API调用
const mockWxml = `<view class="container">\n <button class="custom-btn" bindtap="onTap">点击我</button>\n</view>`;
const mockWxss = `.custom-btn {\n background-color: #007aff;\n color: white;\n padding: 20rpx 40rpx;\n border-radius: 10rpx;\n}`;
const mockJs = `Page({\n onTap() {\n wx.showToast({\n title: 'Hello AI!',\n })\n }\n})`;
this.setData({
loading: false,
hasResult: true,
generatedWxml: mockWxml,
generatedWxss: mockWxss,
generatedJs: mockJs,
previewData: {
wxml: mockWxml,
wxss: mockWxss,
js: mockJs
}
});
wx.showToast({
title: '生成成功!',
icon: 'success'
});
}, 1500); // 模拟1.5秒网络请求
}
})
5. 后端服务与AI集成(关键步骤)重要: 由于小程序前端无法安全存储API密钥,且微信对网络请求域名有严格限制,我们必须通过一个后端服务来中转请求。
5.1 方案选择择
- 微信云开发: 使用云函数调用大模型API,无需配置服务器和域名。
- 自建后端服务器: 使用Node.js (Express/Koa)、Python (Flask/FastAPI) 等搭建API服务。本文以微信云开发为例进行讲解,因其与小程序集成较为方便。。
5.2 开通云开发并创建云函数
- 在微信开发者工具中,点击顶部菜单"云开发",开通环境(会有一个免费额度)。
- 在云开发控制台,创建一个新的云函数,例如
callAI。 - 在该云函数的
index.js中编写逻辑,调用OpenAI API。### 5.3 云函数代码示例 (callAI)t
// 云函数入口文件 index.js
const cloud = require('wx-server-sdk');
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV });
const axios = require('axios'); // 需要手动上传node_modules中的axios,或使用云开发提供的HTTP API
// 云函数入口函数
exports.main = async (event, context) => {
const { userPrompt } = event; // 接收从小程序传来的用户输入
// 1. 构造给AI的指令(Prompt Engineering)
// 这是最关键的一步,指令越清晰,生成的代码质量越高
const systemPrompt = `你是一个微信小程序代码专家。请根据用户的需求,生成完整、可直接运行的微信小程序代码。
要求:
- 只返回一个JSON对象,包含三个字段:wxml, wxss, js。不要有任何其他解释。
- WXML: 生成页面的结构代码,使用标准的微信小程序标签。
- WXSS: 生成页面的样式代码,使用rpx单位,样式类名要合理。
- JS: 生成页面的JavaScript逻辑代码,包含Page函数和必要的事件处理函数。
- 代码要简洁、规范,确保没有语法错误。`;
const fullPrompt = ${systemPrompt}\n\n用户需求:${userPrompt};
// 2. 调用大模型API (示例,请替换为你的真实密钥和端点)
// 注意:实际部署时,应将API KEY存储在云开发的环境变量中,而非硬编码。
const API_KEY = '你的-API-KEY'; // TODO: 从环境变量读取
const API_URL = 'https://api.example.com/v1/chat/completions'; // 替换为实际API地址
try {
const response = await axios.post(
API_URL,
{
model: 'gpt-3.5-turbo', // 根据实际使用的模型调整
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userPrompt }
],
temperature: 0.7,
max_tokens: 1500
},
{
headers: {
'Authorization': Bearer ${API_KEY},
'Content-Type': 'application/json'
}
}
);
const aiResponse = response.data.choices[0].message.content;
// 解析AI返回的JSON字符串
let result;
try {
result = JSON.parse(aiResponse);
} catch (e) {
// 如果AI没有返回标准JSON,尝试提取或返回错误
console.error('AI返回非JSON格式:', aiResponse);
result = {
wxml: '<!-- AI返回格式有误 -->',
wxss: '/* AI返回格式有误 */',
js: '// AI返回格式有误'
};
}
return {
success: true,
code: 200,
data: result
};
} catch (error) {
console.error('调用AI API失败:', error);
return {
success: false,
code: error.response?.status || 500,
message: error.message
};
}
};
### 5.4 修改小程序前端,调用云函数
更新 `pages/index/index.js` 中的 `onGenerateCode` 方法,替换掉模拟数据部分。
```javascript
// pages/index/index.js - 更新 onGenerateCode 方法
onGenerateCode() {
const input = this.data.userInput.trim();
if (!input) {
wx.showToast({ title: '请输入需求描述', icon: 'none' });
return;
}
this.setData({ loading: true });
// 调用云函数
wx.cloud.callFunction({
name: 'callAI', //