摘要
理论学习的最终目的是为了创造。本文将作为一篇手把手的实战教程,带领您从零开始,一步步构建一个完整、可交互的生成式AI Web应用——“智能菜谱生成器”。我们将使用Python主流的Web框架Flask作为后端,结合OpenAI的API,并将结果呈现给一个简洁美观的前端界面。文章将覆盖从项目环境搭建、后端逻辑编写、API密钥安全管理,到核心Prompt设计、前端页面创建、应用整合部署的全过程。读完本文,您不仅能收获一个有趣的应用,更将掌握将生成式AI能力产品化的核心开发流程。
引言:“启智未来”的第一个练手项目
我们的“启智未来”初创团队在深入学习了提示
工程的理论与技巧后,决定启动一个练手项目(Mini-Project)来巩固所学,并将理论付诸实践。他们的想法是,与其直接开发复杂的教育功能,不如先从一个有趣、实用且能体现AI创造力的应用开始。
于是,“智能菜谱生成器”项目应运而生。这个应用的目标很简单:用户输入自己手头拥有的食材,AI就能为他们创造性地生成一份或多份菜谱。这个项目虽小,却“五脏俱全”,完美地涵盖了将一个LLM API封装成用户友好型产品的核心步骤。
让我们跟随“启智未来”的脚步,一起从0到1,完成这次开发之旅。
第一章:应用蓝图:系统架构与技术选型
在敲下第一行代码前,清晰的架构设计是成功的关键。我们的菜谱生成器遵循一个经典的Web应用架构。
数据流转时序图
下图清晰地展示了从用户请求到AI生成菜谱的完整流程:
图1: 智能菜谱生成器数据流转时序图
技术选型
- 后端: Python 3.x + Flask。Flask是一个轻量级的Python Web框架,非常适合快速开发和原型验证。
- AI核心: OpenAI API。我们将使用
openai
官方Python库来与其交互。 - 前端: HTML + CSS。我们不需要复杂的前端框架,只需基础的HTML表单和CSS样式。
第二章:项目搭建与后端初始化
1. 项目结构
首先,创建一个清晰的项目目录结构:
/recipe-generator
|-- /templates
| |-- index.html <-- 前端页面
|-- app.py <-- Flask应用主文件
|-- requirements.txt <-- Python依赖
|-- .env <-- (可选但推荐) 存储环境变量
2. 安装依赖
在 requirements.txt
文件中写入我们的项目依赖:
flask
openai
python-dotenv
flask
: Web框架。openai
: OpenAI官方库。python-dotenv
: (推荐) 用于从.env
文件加载环境变量,确保API密钥安全。
然后,在项目根目录下通过以下命令安装它们:
# 创建并激活一个虚拟环境(推荐)
python -m venv venv
source venv/bin/activate # 在Windows上使用 `venv\Scripts\activate`
# 安装依赖
pip install -r requirements.txt
3. API密钥的安全管理
切勿将您的API密钥硬编码在代码中! 这是最重要的安全实践。
在项目根目录创建一个名为 .env
的文件,并在其中存入您的密钥:
OPENAI_API_KEY="sk-YourSecretKeyHere"
同时,将.env
文件加入到你的.gitignore
中,防止其被提交到代码仓库。
4. 初始化Flask应用
现在,我们来编写 app.py
的初始框架。
# app.py
import os
from flask import Flask, render_template, request
from openai import OpenAI
from dotenv import load_dotenv
# 加载.env文件中的环境变量
load_dotenv()
# 初始化Flask应用
app = Flask(__name__)
# 初始化OpenAI客户端
# 该客户端会自动从环境变量 `OPENAI_API_KEY` 读取密钥
try:
client = OpenAI()
except Exception as e:
print(f"Error initializing OpenAI client: {e}")
# 在实际应用中,这里应该有更健壮的错误处理
client = None
# 主页路由,显示输入表单
@app.route('/')
def index():
return render_template('index.html')
# “神奇”发生的地方,处理表单提交和AI交互
@app.route('/generate', methods=['POST'])
def generate_recipe():
# (这部分逻辑我们将在下一章填充)
return "菜谱正在生成中..."
# 运行Flask应用
if __name__ == '__main__':
app.run(debug=True)
第三章:核心逻辑:精心设计菜谱生成Prompt
这是我们应用的大脑。一个好的Prompt,是生成高质量菜谱的关键。
我们将应用之前学到的提示工程技巧:
- 赋予角色 (Persona): 让AI成为一位“富有创造力的美食家”。
- 明确指令: 清晰地告诉它要做什么。
- 结构化输入: 将用户的输入(食材、菜系等)清晰地嵌入提示。
- 要求输出格式: 要求AI以Markdown格式返回,便于前端展示。
在 app.py
中,我们来完成 /generate
路由的逻辑:
# ... (app.py 上半部分代码) ...
@app.route('/generate', methods=['POST'])
def generate_recipe():
if not client:
return "OpenAI client not initialized. Please check your API key."
# 从表单获取用户输入
ingredients = request.form.get('ingredients')
cuisine = request.form.get('cuisine', '中式') # 默认为中式
if not ingredients:
return "请输入您拥有的食材!"
# --- 精心设计的Prompt ---
prompt = f"""
你是一位富有创造力、经验丰富的美食家和菜谱开发者。
请根据以下信息,为我创作一份详细的菜谱。
### 要求 ###
1. **主要食材**: {ingredients}
2. **期望菜系**: {cuisine}
3. **输出格式**: 请使用Markdown格式,包含以下部分:
- **菜名**: 给这道菜起一个吸引人的名字。
- **简介**: 简单描述这道菜的特色和风味。
- **所需食材**: 列出所有需要的食材和用量。
- **详细步骤**: 提供清晰、易于遵循的烹饪步骤。
- **小贴士**: (可选)提供一两个烹饪小建议。
请开始你的创作吧!
"""
try:
# 调用OpenAI API
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "你是一位富有创造力的美食家。"},
{"role": "user", "content": prompt}
],
temperature=0.8, # 增加一点创造力
max_tokens=1000
)
recipe_content = response.choices[0].message.content
# 将生成的内容传递给前端模板
return render_template('index.html', recipe=recipe_content, ingredients=ingredients, cuisine=cuisine)
except Exception as e:
print(f"Error calling OpenAI API: {e}")
error_message = f"调用AI服务时出错: {e}"
return render_template('index.html', error=error_message, ingredients=ingredients, cuisine=cuisine)
# ... (app.py 下半部分代码) ...
第四章:创建用户友好的前端界面
现在,我们来创建 templates/index.html
文件。我们将使用一个简单的HTML表单和一些内联CSS来保持项目的简洁性。
<!-- templates/index.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>智能菜谱生成器</title>
<style>
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; line-height: 1.6; color: #333; max-width: 800px; margin: 40px auto; padding: 20px; background-color: #f9f9f9; }
.container { background-color: #fff; padding: 30px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.05); }
h1 { text-align: center; color: #e84393; }
form { display: flex; flex-direction: column; gap: 15px; }
input, select, button { font-size: 16px; padding: 10px; border-radius: 5px; border: 1px solid #ddd; }
button { background-color: #e84393; color: white; border: none; cursor: pointer; transition: background-color 0.3s; }
button:hover { background-color: #d83383; }
.recipe-card { margin-top: 30px; padding: 20px; border: 1px solid #eee; border-radius: 8px; background-color: #fff8fb; }
.error { color: #d63031; }
/* 简单的Markdown样式 */
.recipe-card h2 { border-bottom: 2px solid #e84393; padding-bottom: 5px; }
.recipe-card h3 { color: #6c5ce7; }
.recipe-card ul, .recipe-card ol { padding-left: 20px; }
.recipe-card code { background-color: #eee; padding: 2px 4px; border-radius: 3px; }
</style>
</head>
<body>
<div class="container">
<h1>🍳 智能菜谱生成器 📝</h1>
<form action="/generate" method="post">
<label for="ingredients">告诉我你有什么食材(用逗号分隔):</label>
<input type="text" id="ingredients" name="ingredients" value="{{ ingredients or '' }}" placeholder="例如:鸡胸肉, 土豆, 胡萝卜" required>
<label for="cuisine">你偏爱什么菜系?</label>
<select id="cuisine" name="cuisine">
<option value="中式" {% if cuisine == '中式' %}selected{% endif %}>中式</option>
<option value="西式" {% if cuisine == '西式' %}selected{% endif %}>西式</option>
<option value="日式" {% if cuisine == '日式' %}selected{% endif %}>日式</option>
<option value="创意融合" {% if cuisine == '创意融合' %}selected{% endif %}>创意融合</option>
</select>
<button type="submit">✨ 生成神奇菜谱 ✨</button>
</form>
{% if error %}
<div class="recipe-card error">
<p><strong>出错了:</strong> {{ error }}</p>
</div>
{% endif %}
{% if recipe %}
<div class="recipe-card">
<!-- 我们需要一个方式将Markdown转换为HTML,但为了简单,我们先用pre标签展示 -->
<h2>为您生成的菜谱:</h2>
<pre style="white-space: pre-wrap; font-family: inherit;">{{ recipe }}</pre>
</div>
{% endif %}
</div>
</body>
</html>
注意: 为了让Markdown格式正确显示,最简单的方式是使用<pre>
标签。在生产应用中,您可能会使用一个Python库(如markdown2
)在后端将Markdown转换为HTML,或者在前端使用JavaScript库(如marked.js
)来渲染。
第五章:整合运行你的第一个AI应用
现在,所有部件都已就绪!确保你的 app.py
和 templates/index.html
文件内容完整。
运行应用:
在你的项目根目录下,打开终端(确保虚拟环境已激活),然后运行:
flask run
Flask会启动一个本地开发服务器。打开浏览器,访问 http://127.0.0.1:5000
,你将看到你的“智能菜谱生成器”!
输入你冰箱里的食材,选择一个菜系,然后点击按钮,见证AI为你创造美食的魔力吧!
总结:超越菜谱,你的GenAI构建之旅
恭喜你!你已经成功构建并运行了自己的第一个生成式AI应用。通过这个项目,你掌握了:
- Web应用基本架构: 如何组织一个包含前后端的项目。
- 后端与AI集成: 如何在Flask中安全地调用OpenAI API。
- 核心Prompt设计: 如何将业务逻辑转化为高效的AI指令。
- 前后端数据交互: 如何通过表单接收用户输入,并将结果展示在页面上。
这个“智能菜谱生成器”只是一个起点。现在,你可以尝试扩展它:
- 增加图片生成: 调用DALL-E 3 API,为生成的菜谱配上一张诱人的图片。
- 保存历史记录: 添加数据库功能,让用户可以保存、收藏他们喜欢的菜谱。
- 尝试不同模型: 替换为
gpt-4
或其他模型,看看输出有何不同。
你已经开启了作为一名生成式AI应用构建者的旅程。继续探索,继续创造吧!
参考资料
- 官方课程: Building Text Generation Applications - Microsoft/Github
- Flask官方文档: Flask Documentation
- OpenAI Python库: openai-python on GitHub