Flask + GPT 实践

一、前言

本篇文章会介绍从零开始构建一个基于 Flask + GPT 的小项目的过程。总共有四个版本的迭代,包括:

1、调用 GPT 接口并渲染到前端页面;
2、使用 Flask 提供的 session 来实现登录和登出功能;
3、用 SQLAlchemy 管理数据库,实现用户注册和登录;
4、记录和分页查看用户与 GPT 的对话历史。

二、项目环境与依赖

Python 版本:建议 3.7+
Flask:最常用的 Python Web 框架之一
openai:官方 Python SDK,用于调用 GPT API
dotenv:用于在本地加载 .env 文件,存储一些敏感数据(如 OPENAI_API_KEY)
SQLAlchemy:Python ORM 框架,方便管理数据库
bcrypt:用于安全地加密与验证密码
前端:主要使用原生 HTML + JavaScript

安装依赖

pip install flask openai python-dotenv flask_sqlalchemy bcrypt

三、版本迭代与核心功能说明

版本一:简易版,直接调用 GPT

目标:能让用户在网页上输入一段文本,后端调用 GPT,直接返回结果给前端渲染即可。
关键点:
在 app.py 中直接引用 openai.ChatCompletion 接口;
前端用一个简单的 index.html 配合 AJAX (fetch) 请求。
代码如下:

app.py

import os
import openai
from flask import Flask, request, jsonify, render_template
from dotenv import load_dotenv

# 加载本地 .env 文件中的环境变量
load_dotenv()

app = Flask(__name__)

# 从环境变量中读取你的 GPT Key
openai.api_key = os.getenv("OPENAI_API_KEY")
@app.route("/")
def index():
    # 返回前端页面
    return render_template("index.html")

@app.route("/chat", methods=["POST"])
def chat():
    # 接收JSON数据
    data = request.get_json()
    user_message = data.get("message", "").strip()

    if not user_message:
        return jsonify({"error": "message cannot be empty"}), 400

    try:
        response = openai.ChatCompletion.create(
            model="gpt-4o-mini",
            messages=[{"role": "user", "content": user_message}]
        )
        reply = response.choices[0].message.content.strip()
        return jsonify({"reply": reply})
    except Exception as e:
        return jsonify({"error": str(e)}), 500

if __name__ == "__main__":
    app.run(debug=True, port=5001)

前端 index.html(放在 templates/index.html 下):

DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>GPT 聊天title>
head>
<body style="display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100vh; margin: 0;">
    <h1>GPT 聊天h1>
    <textarea id="userInput" rows="4" cols="50" placeholder="请输入您的问题..." style="width: 50%; resize: none;">textarea>
    <div style="width: 50%; display: flex; justify-content: flex-end; margin-top: 10px;">
        <button onclick="sendMessage()" style="padding: 10px 20px; font-size: 16px; cursor: pointer;">发送给 GPTbutton>
    div>
    <div style="width: 50%; margin-top: 20px;">
        <h2 style="margin: 0;">GPT 回复:h2>
        <div id="responseBox" style="white-space: pre-wrap; margin-top: 10px; padding: 10px; width: 100%; border: 1px solid #ccc; border-radius: 5px; background-color: #f9f9f9; min-height: 50px;">div>
    div>

    <script>
    async function sendMessage() {
      const userInput = document.getElementById("userInput").value.trim();
      if (!userInput) {
        alert("输入不能为空!");
        return;
      }
      try {
        const res = await fetch("/chat", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ message: userInput })
        });
        const data = await res.json();
        document.getElementById("responseBox").innerText = data.reply || data.error || "未知错误";
      } catch (error) {
        console.error(error);
        alert("请求出错了!");
      }
    }
    script>
body>
html>

此时我们已经完成了最基本的“把 GPT 接口包装成 Flask 服务”的功能。运行代码后,在浏览器访问 http://127.0.0.1:5001/,即可使用。
这是效果图:
Flask + GPT 实践_第1张图片

版本二:增加用户登录功能

目标:让用户只能在登录成功后,才能访问 GPT 聊天功能;
关键点:
在后端使用 Flask 的 session 来保存登录状态;
需要增加登录页 (login.html),以及登录、登出逻辑;
聊天接口 /chat 在没有 session 的情况下,禁止访问。

代码如下:

app.py

import os
import openai
import bcrypt
from flask import Flask, request, jsonify, render_template, session, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
from dotenv import load_dotenv

# =========================
# 1. 加载环境 & 基本配置
# =========================

load_dotenv()

app = Flask(__name__)

# 生成随机密钥并设置为 SECRET_KEY
app.config['SECRET_KEY'] = os.urandom(24)

# 从环境变量中读取你的 GPT Key
openai.api_key = os.getenv("OPENAI_API_KEY")

# 配置数据库,这里以 SQLite 为例
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///demo.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)

# =========================
# 2. 数据库模型
# =========================

class User(db.Model):
    """用户表"""
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    username = db.Column(db.String(50), unique=True, nullable=False)
    password_hash = db.Column(db.String(60), nullable=False)  # 存储哈希后的密码
    created_at = db.Column(db.DateTime, default=datetime.utcnow)

    # def __init__(self, username, password_hash):
    #     self.username = username
    #     self.password_hash = password_hash


# =========================
# 3. 路由逻辑
# =========================

@app.route('/')
def index():
    # 如果已登录,则在界面上显示聊天功能;否则提示登录或注册
    if session.get("logged_in"):
        return render_template("index.html", logged_in=True, username=session.get("username"))
    else:
        return render_template("index.html", logged_in=False)

@app.route('/register', methods=['GET', 'POST'])
def register():
    """
    用户注册:
    - GET 访问时返回注册页面
    - POST 提交时写数据库
    """
    if request.method == 'GET':
        return render_template("register.html")

    # POST 提交表单数据
    username = request.form.get('username')
    password = request.form.get('password')

    if not username or not password:
        return "用户名或密码不能为空", 400

    # 检查是否存在同名用户
    existing_user = User.query.filter_by(username=username).first()
    if existing_user:
        return "该用户名已被注册", 400

    # 加密密码(bcrypt)并存储到数据库
    hashed = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())
    new_user = User(username=username, password_hash=hashed.decode('utf-8'))
    db.session.add(new_user)
    db.session.commit()

    return redirect(url_for('login'))

@app.route('/login', methods=['GET', 'POST'])
def login():
    """
    用户登录:
    - GET 访问时返回登录页面
    - POST 提交时校验密码
    """
    if request.method == 'GET':
        # 如果已经登录,就直接跳到首页
        if session.get("logged_in"):
            return redirect(url_for("index"))
        return render_template("login.html")

    username = request.form.get('username')
    password = request.form.get('password')

    if not username or not password:
        return "用户名或密码不能为空", 400

    # 从数据库查询用户
    user = User.query.filter_by(username=username).first()
    if not user:
        return "用户名不存在", 400


    # 验证密码
    if bcrypt.checkpw(password.encode('utf-8'),  user.password_hash.encode('utf-8')):
        # 登录成功
        session["logged_in"] = True
        session["username"] = user.username
        return redirect(url_for('index'))
    else:
        return "密码错误", 401

@app.route('/logout')
def logout():
    """
    用户登出
    """
    session.clear()
    return redirect(url_for('index'))

@app.route("/chat", methods=["POST"])
def chat():
    """
    聊天接口 (GPT 调用)
    """
    if not session.get("logged_in"):
        return jsonify({"error": "未登录,无法访问此接口"}), 401

    data = request.get_json()
    user_message = data.get("message", "").strip()

    if not user_message:
        return jsonify({"error": "message cannot be empty"}), 400

    try:
        response = openai.ChatCompletion.create(
            model="gpt-4o-mini",
            messages=[{"role": "user", "content": user_message}]
        )
        reply = response.choices[0].message.content.strip()
        return jsonify({"reply": reply})
    except Exception as e:
        return jsonify({"error": str(e)}), 500


# =========================
# 4. 启动应用入口
# =========================

if __name__ == "__main__":
    with app.app_context():
        db.create_all()  # 在应用上下文中创建表

    app.run(debug=True, port=5001)


index.html

DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>GPT 聊天title>
    <style>
        body {
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0; 
            font-family: Arial, sans-serif;
            background-color: #f9f9f9; 
        }

        h1 {
            margin-bottom: 20px;
        }

        .chat-container {
            width: 50%;
            display: flex;
            flex-direction: column;
            align-items: stretch;
            gap: 10px; 
        }

        textarea {
            width: 100%;
            resize: none;
            padding: 10px;
            font-size: 14px;
            border: 1px solid #ccc;
            border-radius: 5px;
        }

        .button-container {
            display: flex;
            justify-content: flex-end;
        }

        button {
            padding: 10px 20px;
            font-size: 16px;
            cursor: pointer;
            border: none;
            border-radius: 5px;
            background-color: #007BFF;
            color: white;
        }

        button:hover {
            background-color: #0056b3;
        }

        .response-container {
            padding: 10px;
            border: 1px solid #ccc;
            border-radius: 5px;
            background-color: #fff;
            min-height: 50px;
            white-space: pre-wrap;
        }

        .logout-link {
            margin-top: 20px;
            text-decoration: none;
            font-size: 16px;
            color: #007BFF;
        }

        .logout-link:hover {
            text-decoration: underline;
        }

        .centered {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 50vh;
        }

        .centered p {
            font-size: 18px;
        }
    style>
head>
<body>
    <h1>GPT 聊天h1>

    {% if logged_in %}
    <div class="chat-container">
        <p>您已登录!p>
        <textarea id="userInput" rows="4" placeholder="请输入您的问题...">textarea>
        <div class="button-container">
            <button onclick="sendMessage()">发送给 GPTbutton>
        div>
        <h2>GPT 回复:h2>
        <div class="response-container" id="responseBox">div>
    div>
    <a href="/logout" class="logout-link">退出登录a>

    <script>
    async function sendMessage() {
        const userInput = document.getElementById("userInput").value.trim();
        if (!userInput) {
            alert("输入不能为空!");
            return;
        }
        try {
            const res = await fetch("/chat", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ message: userInput })
            });
            const data = await res.json();
            document.getElementById("responseBox").innerText = data.reply || data.error || "未知错误";
        } catch (error) {
            console.error(error);
            alert("请求出错了!");
        }
    }
    script>
    {% else %}
    <div class="centered">
        <p>您尚未登录,请先 <a href="/login">登录a>p>
    div>
    {% endif %}
body>
html>

login.html

DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>登录title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            flex-direction: column; /* 垂直排列 */
        }

        h1 {
            margin-bottom: 20px;
        }

        .input-group {
            display: flex; 
            align-items: flex-end; 
            gap: 10px; 
        }

        input {
            flex: 1; 
            padding: 5px;
        }

        button {
            padding: 5px 10px;
            font-size: 14px;
        }

        form {
            width: 300px; /* 限制表单宽度 */
        }
    style>
head>
<body>
    <h1>登录页面h1> 
    <form action="/login" method="POST">
        <div>
            <label for="username">用户名:label>
            <input type="text" id="username" name="username" required>
        div>
        <div class="input-group">
            <label for="password">密码:label>
            <input type="password" id="password" name="password" required>
            <button type="submit">登录button>
        div>
    form>
body>
html>


这是效果图
Flask + GPT 实践_第2张图片

Flask + GPT 实践_第3张图片

Flask + GPT 实践_第4张图片

版本三:引入数据库,增加注册功能

目标:让用户可以在系统中“注册新账号”,并把密码以安全的方式存储到数据库,而不再写死用户名密码。
关键点:
使用 SQLAlchemy 管理数据库(这里示例用 SQLite);
新增 User 模型,包含 id, username, password_hash, created_at 等字段;
新增 register 路由,用户提交表单后,将数据写入数据库;
登录时从数据库读取用户信息,用 bcrypt 校验密码。
app.py:

import os
import openai
import bcrypt
from flask import Flask, request, jsonify, render_template, session, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
from dotenv import load_dotenv

# =========================
# 1. 加载环境 & 基本配置
# =========================

load_dotenv()

app = Flask(__name__)

# 生成随机密钥并设置为 SECRET_KEY
app.config['SECRET_KEY'] = os.urandom(24)

# 从环境变量中读取你的 GPT Key
openai.api_key = os.getenv("OPENAI_API_KEY")

# 配置数据库,这里以 SQLite 为例
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///demo.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)

# =========================
# 2. 数据库模型
# =========================

class User(db.Model):
    """用户表"""
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    username = db.Column(db.String(50), unique=True, nullable=False)
    password_hash = db.Column(db.String(60), nullable=False)  # 存储哈希后的密码
    created_at = db.Column(db.DateTime, default=datetime.utcnow)

    def __init__(self, username, password_hash):
        self.username = username
        self.password_hash = password_hash


# =========================
# 3. 路由逻辑
# =========================

@app.route('/')
def index():
    # 如果已登录,则在界面上显示聊天功能;否则提示登录或注册
    if session.get("logged_in"):
        return render_template("index.html", logged_in=True, username=session.get("username"))
    else:
        return render_template("index.html", logged_in=False)

@app.route('/register', methods=['GET', 'POST'])
def register():
    """
    用户注册:
    - GET 访问时返回注册页面
    - POST 提交时写数据库
    """
    if request.method == 'GET':
        return render_template("register.html")

    # POST 提交表单数据
    username = request.form.get('username')
    password = request.form.get('password')

    if not username or not password:
        return "用户名或密码不能为空", 400

    # 检查是否存在同名用户
    existing_user = User.query.filter_by(username=username).first()
    if existing_user:
        return "该用户名已被注册", 400

    # 加密密码(bcrypt)并存储到数据库
    hashed = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())
    new_user = User(username=username, password_hash=hashed.decode('utf-8'))
    db.session.add(new_user)
    db.session.commit()

    return redirect(url_for('login'))

@app.route('/login', methods=['GET', 'POST'])
def login():
    """
    用户登录:
    - GET 访问时返回登录页面
    - POST 提交时校验密码
    """
    if request.method == 'GET':
        # 如果已经登录,就直接跳到首页
        if session.get("logged_in"):
            return redirect(url_for("index"))
        return render_template("login.html")

    username = request.form.get('username')
    password = request.form.get('password')

    if not username or not password:
        return "用户名或密码不能为空", 400

    # 从数据库查询用户
    user = User.query.filter_by(username=username).first()
    if not user:
        return "用户名不存在", 400


    # 验证密码
    if bcrypt.checkpw(password.encode('utf-8'),  user.password_hash.encode('utf-8')):
        # 登录成功
        session["logged_in"] = True
        session["username"] = user.username
        return redirect(url_for('index'))
    else:
        return "密码错误", 401

@app.route('/logout')
def logout():
    """
    用户登出
    """
    session.clear()
    return redirect(url_for('index'))

@app.route("/chat", methods=["POST"])
def chat():
    """
    聊天接口 (GPT 调用)
    """
    if not session.get("logged_in"):
        return jsonify({"error": "未登录,无法访问此接口"}), 401

    data = request.get_json()
    user_message = data.get("message", "").strip()

    if not user_message:
        return jsonify({"error": "message cannot be empty"}), 400

    try:
        response = openai.ChatCompletion.create(
            model="gpt-4o-mini",
            messages=[{"role": "user", "content": user_message}]
        )
        reply = response.choices[0].message.content.strip()
        return jsonify({"reply": reply})
    except Exception as e:
        return jsonify({"error": str(e)}), 500


# =========================
# 4. 启动应用入口
# =========================

if __name__ == "__main__":
    with app.app_context():
        db.create_all()  # 在应用上下文中创建表

    app.run(debug=True, port=5001)

register.html:

DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>注册title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            flex-direction: column; /* 垂直排列 */
        }
        h1 {
            margin-bottom: 20px; /* 与表单的间距 */
        }
        .input-group {
            display: flex; 
            align-items: flex-end; 
            gap: 10px; 
        }

        input {
            flex: 1; 
            padding: 5px;
        }

        button {
            padding: 5px 10px;
            font-size: 14px;
        }
    style>
head>
<body>
    <h1>用户注册h1>
    <form action="/register" method="POST">
        <div>
            <label for="username">用户名:label>
            <input type="text" id="username" name="username" required>
        div>
        <div class="input-group">
            <label for="password">密码:label>
            <input type="password" id="password" name="password" required>
            <button type="submit">注册button>
        div>
    form>
body>
html>

index.html文件需要将

<p>您尚未登录,请先 <a href="/login">登录a>p>

改为

<p>您尚未登录,请先 <a href="/login">登录a><a href="/register">注册a>.p>

然后这是效果图
Flask + GPT 实践_第5张图片
Flask + GPT 实践_第6张图片
在此版本中,你就可以在“注册”页面创建自己的账户,然后凭借这个账号登录并使用 GPT 聊天功能了。

版本四:新增聊天记录功能

目标:除了能聊天,还希望把每一次对话都保存到数据库,并在前端提供接口查看“历史聊天”。
关键点:
新增 ChatRecord 模型,包含 user_id, question, answer, created_at;
在 /chat 路由中,成功获取回复后,先存库再返回给前端;
新增 history 接口,支持分页查询,返回前端浏览。

然后app.py需要新增和修改的代码如下:

# 1. 定义聊天记录表
class ChatRecord(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    user_id = db.Column(db.Integer, nullable=False)
    question = db.Column(db.Text, nullable=False)
    answer = db.Column(db.Text, nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)

# 2. 聊天时保存记录
@app.route("/chat", methods=["POST"])
def chat():
    if not session.get("logged_in"):
        return jsonify({"error": "未登录"}), 401

    data = request.get_json()
    user_message = data.get("message", "").strip()
    response = openai.ChatCompletion.create(...)
    reply = response.choices[0].message.content.strip()

    # 保存
    record = ChatRecord(
        user_id=session["user_id"],
        question=user_message,
        answer=reply
    )
    db.session.add(record)
    db.session.commit()

    return jsonify({"reply": reply})

# 3. 查询历史记录(带分页)
@app.route("/history", methods=["GET"])
def get_chat_history():
    if not session.get("logged_in"):
        return jsonify({"error": "未登录"}), 401

    page = request.args.get("page", 1, type=int)
    size = request.args.get("size", 10, type=int)
    user_id = session["user_id"]

    query = ChatRecord.query.filter_by(user_id=user_id).order_by(ChatRecord.created_at.desc())
    total = query.count()
    records = query.offset((page - 1) * size).limit(size).all()

    data = []
    for r in records:
        data.append({
            "id": r.id,
            "question": r.question,
            "answer": r.answer,
            "created_at": r.created_at.isoformat()
        })

    return jsonify({
        "records": data,
        "total": total,
        "total_pages": ceil(total / size),
        "current_page": page,
        "page_size": size
    })

然后是修改后的index.html代码

DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>GPT 聊天title>
    <style>
        body {
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            min-height: 100vh; 
            margin: 0; 
            font-family: Arial, sans-serif;
            background-color: #f9f9f9; 
        }

        .container {
            width: 70%;
            margin: 0 auto;
        }

        h1, h2 {
            text-align: center;
            margin-bottom: 20px;
        }

        .chat-box {
            margin-bottom: 20px;
            padding: 20px;
            border: 1px solid #ccc;
            border-radius: 5px;
            background-color: #f9f9f9;
            position: relative; /* 设置父容器为相对定位 */
        }

        textarea {
            width: calc(100% - 100px); /* 减去按钮的宽度及间距 */
            resize: none;
            padding: 10px;
            font-size: 14px;
            border: 1px solid #ccc;
            border-radius: 5px;
            box-sizing: border-box; /* 确保宽度计算正确 */
        }

        .send-button {
            position: absolute; /* 绝对定位按钮 */
            bottom: 25px; /* 距离父容器底部 10px */
            right: 10px; /* 距离父容器右侧 10px */
            padding: 10px 20px;
            font-size: 10px;
            cursor: pointer;
            border: none;
            border-radius: 5px;
            background-color: #007BFF;
            color: white;
        }

        .send-button:hover {
            background-color: #0056b3;
        }

        .response-box, .history-box {
            margin-bottom: 20px;
            padding: 20px;
            border: 1px solid #ccc;
            border-radius: 5px;
            background-color: #f9f9f9;
        }

        .response-container {
            min-height: 50px;
            border: 1px solid #ddd;
            padding: 10px;
            background-color: #f5f5f5;
        }

        .history-content {
            margin-top: 20px;
            border: 1px solid #ddd;
            padding: 10px;
            background-color: #fff;
        }

        .logout-link {
            display: block;
            margin-top: 20px;
            text-align: center;
            text-decoration: none;
            font-size: 16px;
            color: #007BFF;
        }

        .logout-link:hover {
            text-decoration: underline;
        }

        .pagination-buttons {
            display: flex;
            justify-content: center;
            gap: 10px;
            margin-top: 10px;
        }
    style>
head>
<body>
    {% if logged_in %}
      <div class="container">
          <p>用户{{ username }}已登录p>
          <div class="chat-box">
              <h2>GPT 聊天h2>
              <p style="font-weight: bold;">输入您的问题:p>
              <textarea id="userInput" rows="4" placeholder="请输入您的问题...">textarea>
              <button onclick="sendMessage()" class="send-button">发送给 GPTbutton>
          div>

          <div class="response-box">
              <h2>GPT 回复:h2>
              <div id="responseBox" class="response-container">div>
          div>

          <div class="history-box">
              <h2>聊天历史记录h2>
              <button onclick="loadHistory()">查看历史记录button>
              <div id="historyContent" class="history-content">div>
          div>
      div>

        <a href="/logout" class="logout-link">退出登录a>

        <script>
          // 发送消息给GPT
          async function sendMessage() {
            const userInput = document.getElementById("userInput").value.trim();
            if (!userInput) {
              alert("输入不能为空!");
              return;
            }
            try {
              const res = await fetch("/chat", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ message: userInput })
              });
              const data = await res.json();
              document.getElementById("responseBox").innerText = data.reply || data.error || "未知错误";
            } catch (error) {
              console.error(error);
              alert("请求出错了!");
            }
          }

          // 加载历史记录
          async function loadHistory(page=1, size=10) {
            try {
              const res = await fetch(`/history?page=${page}&size=${size}`);
              const data = await res.json();

              if (data.error) {
                document.getElementById("historyContent").innerText = data.error;
                return;
              }
              
              // 显示分页信息
              let historyHtml = `

${data.current_page} 页 / 共 ${data.total_pages} 页 (共 ${data.total} 条记录)

`
; // 遍历记录,生成HTML data.records.forEach(rec => { historyHtml += `
时间: ${rec.created_at}
问题:
${rec.question}
回答:
${rec.answer}

`
; }); // 如果有多页,可以加“上一页/下一页”按钮 historyHtml += '
'; if (data.current_page > 1) { historyHtml += ``; } if (data.current_page < data.total_pages) { historyHtml += ``; } historyHtml += '
'
; document.getElementById("historyContent").innerHTML = historyHtml; } catch (error) { console.error(error); alert("加载历史记录出错!"); } }
script> {% else %} <p>您尚未登录,请先 <a href="/login">登录a><a href="/register">注册a>.p> {% endif %} body> html>

最后是效果图
Flask + GPT 实践_第7张图片

至此,一套“登录 - 聊天 - 记录保存 - 历史查看”的基础应用就全部完成。

然后这是github 项目地址

你可能感兴趣的:(flask项目,flask,gpt,python)