当前位置: 首页 > news >正文

基于FastAPI与Kimi AI的智能聊天应用开发实践

一、项目概述

本文介绍一个基于现代Web技术栈的智能对话系统,前端采用响应式设计实现聊天界面,后端通过FastAPI框架构建高性能API服务,集成Moonshot AI大语言模型实现智能对话功能。系统具备完整的消息交互流程,支持参数定制化配置,适用于智能客服、在线咨询等多种场景。

二、项目准备

1、首先要去Kimi开放者平台的用户中心去注册一个自己的API key。

Moonshot AI 开放平台https://platform.moonshot.cn/docs/intro#%E6%96%87%E6%9C%AC%E7%94%9F%E6%88%90%E6%A8%A1%E5%9E%8B

这里一点要复制保存好自己的密钥,因为密钥只会出现一次,后去就不能查到了。

三、技术栈全景

跨栈技术选型:

  • 前端三件套:HTML5/CSS3/JavaScript
  • 服务端框架:FastAPI(Python 3.8+)
  • HTTP客户端:httpx(异步支持)
  • AI服务:Moonshot API(月之暗面大模型)
  • 部署工具:Uvicorn ASGI服务器

四、前后端代码展示

4.1、后端代码

from fastapi import FastAPI, HTTPException, Query  # 从fastapi库导入FastAPI类、HTTPException类和Query类
import httpx  # 导入httpx库,用于异步HTTP请求
from pydantic import BaseModel, Field  # 从pydantic库导入BaseModel和Field类,用于数据模型定义
import logging  # 导入logging库,用于日志记录
import uvicorn
from fastapi.middleware.cors import CORSMiddleware  # 导入CORS中间件

app = FastAPI()  # 创建一个FastAPI应用实例

# 启用CORS
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 允许所有来源,生产环境中请指定具体域名
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

APIKEY = "sk-SQ5lF3g2OajgNRSi71DXanPbOajSdsx6WJHtWBu52QlDR4XP"  # 定义API密钥,用于授权访问外部API
MOONSHOT_URL = "https://api.moonshot.cn/v1/chat/completions"  # 定义外部API的URL

# 配置模型参数
class ChatRequest(BaseModel):  # 定义一个名为ChatRequest的Pydantic模型类,继承自BaseModel
    msg: str = Field(..., min_length=1, example="你好")  # 定义msg字段,类型为str,最小长度为1,示例值为"你好"
    temperature: float = Field(0.7, ge=0, le=1)  # 定义temperature字段,类型为float,默认值为0.7,范围在0到1之间
    max_tokens: int = Field(2000, ge=100, le=8000)  # 定义max_tokens字段,类型为int,默认值为2000,范围在100到8000之间

@app.get("/chat", response_model=str)  # 定义一个路由,处理GET请求,路径为/chat
async def chat(
    msg: str = Query(..., min_length=1, example="你好"),  # 定义msg查询参数
    temperature: float = Query(0.7, ge=0, le=1),  # 定义temperature查询参数
    max_tokens: int = Query(2000, ge=100, le=8000)  # 定义max_tokens查询参数
):
    """
    与Moonshot AI交互的聊天接口
    - 支持流式响应(需前端配合)
    - 参数验证与错误处理
    """
    async with httpx.AsyncClient(timeout=30) as client:  # 创建一个异步HTTP客户端实例,设置超时时间为30秒
        try:
            response = await client.post(  # 发送POST请求到外部API
                MOONSHOT_URL,  # 目标URL
                headers={"Authorization": f"Bearer {APIKEY}"},  # 设置请求头,包含授权信息
                json={  # 设置请求体,包含模型参数
                    "model": "moonshot-v1-8k",  # 指定使用的模型
                    "messages": [{"role": "user", "content": msg}],  # 设置请求消息内容
                    "temperature": temperature,  # 设置temperature参数
                    "max_tokens": max_tokens  # 设置max_tokens参数
                }
            )
            response.raise_for_status()  # 如果响应状态码不是200,抛出异常
            return response.json()["choices"][0]["message"]["content"]  # 解析响应JSON数据,提取回复消息内容并返回

        except httpx.HTTPStatusError as e:  # 捕获HTTP状态错误
            logging.error(f"API错误: {e.response.text}")  # 记录错误日志
            raise HTTPException(status_code=e.response.status_code, detail="模型服务异常")  # 抛出HTTP异常,状态码和错误信息
        except Exception as e:  # 捕获其他异常
            logging.error(f"系统错误: {str(e)}")  # 记录错误日志
            raise HTTPException(status_code=500, detail="内部服务器错误")  # 抛出HTTP异常,状态码500和错误信息

if __name__ == "__main__":
    uvicorn.run("msg:app", host="127.0.0.1", port=8000, reload=True)  # 启动FastAPI应用,监听127.0.0.1的8000端口,并启用自动重载

4.2、前端代码

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">  <!-- 设置字符编码为UTF-8 -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0">  <!-- 设置视口,使页面适应不同设备 -->
    <title>聊天界面</title>  <!-- 设置页面标题 -->
    <style>
        html, body {
            height: 100%;
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
        }
        #chat-container {
            width: 100%;  /* 设置宽度为100% */
            height: 100%;  /* 设置高度为100% */
            background-color: #fff;  /* 设置背景颜色 */
            border-radius: 10px;  /* 设置圆角 */
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);  /* 设置阴影 */
            overflow: hidden;  /* 隐藏溢出内容 */
            display: flex;  /* 使用Flexbox布局 */
            flex-direction: column;  /* 设置垂直方向 */
        }
        #chat-title {
            background-color: #007bff;  /* 设置标题背景颜色 */
            color: #fff;  /* 设置标题文字颜色 */
            padding: 20px;  /* 设置内边距 */
            text-align: center;  /* 文字居中 */
            border-top-left-radius: 10px;  /* 设置左上角圆角 */
            border-top-right-radius: 10px;  /* 设置右上角圆角 */
        }
        #messages {
            flex: 1;  /* 占据剩余空间 */
            padding: 20px;  /* 设置内边距 */
            overflow-y: auto;  /* 设置垂直滚动条 */
            border-bottom: 1px solid #ddd;  /* 设置底部边框 */
        }
        .message {
            margin: 10px 0;  /* 设置消息间距 */
            padding: 10px;  /* 设置内边距 */
            border-radius: 10px;  /* 设置圆角 */
            max-width: 70%;  /* 设置最大宽度 */
        }
        .user {
            background-color: #dcf8c6;  /* 设置用户消息背景颜色 */
            align-self: flex-end;  /* 消息靠右对齐 */
        }
        .bot {
            background-color: #e0e0e0;  /* 设置机器人消息背景颜色 */
            align-self: flex-start;  /* 消息靠左对齐 */
        }
        #input-container {
            display: flex;  /* 使用Flexbox布局 */
            padding: 20px;  /* 设置内边距 */
        }
        #user-input {
            flex: 1;  /* 占据剩余空间 */
            padding: 10px;  /* 设置内边距 */
            border: 1px solid #ddd;  /* 设置边框 */
            border-radius: 20px;  /* 设置圆角 */
            margin-right: 10px;  /* 设置右边距 */
            outline: none;  /* 移除聚焦时的默认轮廓 */
        }
        #user-input:focus {
            border-color: #007bff;  /* 聚焦时改变边框颜色 */
        }
        #send-button {
            padding: 10px 20px;  /* 设置内边距 */
            background-color: #007bff;  /* 设置背景颜色 */
            color: #fff;  /* 设置文字颜色 */
            border: none;  /* 移除边框 */
            border-radius: 20px;  /* 设置圆角 */
            cursor: pointer;  /* 设置鼠标悬停时的光标样式 */
        }
        #send-button:hover {
            background-color: #0056b3;  /* 悬停时改变背景颜色 */
        }
    </style>
</head>
<body>
    <div id="chat-container">
        <div id="chat-title">My Kimi</div>  <!-- 添加聊天标题 -->
        <div id="messages"></div>  <!-- 用于显示聊天消息 -->
        <div id="input-container">
            <input type="text" id="user-input" placeholder="输入消息...">  <!-- 用户输入框 -->
            <button id="send-button">发送</button>  <!-- 发送按钮 -->
        </div>
    </div>

    <script>
        document.getElementById('send-button').addEventListener('click', sendMessage);  // 绑定发送按钮点击事件
        document.getElementById('user-input').addEventListener('keypress', function(event) {
            if (event.key === 'Enter') {
                sendMessage();  // 如果按下Enter键,调用sendMessage函数
            }
        });

        async function sendMessage() {
            const userInput = document.getElementById('user-input').value;  // 获取用户输入的内容
            if (!userInput) return;  // 如果输入为空,直接返回

            // 显示用户消息
            displayMessage('user', userInput);

            const params = new URLSearchParams({
                msg: userInput,
                temperature: 0.7,
                max_tokens: 2000
            });

            try {
                const response = await fetch(`http://127.0.0.1:8000/chat?${params}`, {
                    method: 'GET',
                    headers: {
                        'Content-Type': 'application/json'
                    }
                });

                if (!response.ok) {
                    throw new Error('网络响应异常');
                }

                const data = await response.json();
                displayMessage('bot', data);
            } catch (error) {
                console.error('发送消息时出错:', error);
                displayMessage('bot', '发生错误,请重试。');
            }

            // 清空输入框
            document.getElementById('user-input').value = '';
        }

        function displayMessage(sender, message) {
            const messagesContainer = document.getElementById('messages');
            const messageElement = document.createElement('div');
            messageElement.className = `message ${sender}`;
            if (sender === 'user') {
                messageElement.textContent = `你: ${message}`;  // 显示用户消息时添加“你:”前缀
            } else {
                messageElement.textContent = message;  // 显示机器人消息时不添加前缀
            }
            messagesContainer.appendChild(messageElement);
            messagesContainer.scrollTop = messagesContainer.scrollHeight;  // 滚动到底部
        }
    </script>
</body>
</html>
<!--前端的启动: python -m http.server 8080-->

 六、本地部署

# 前端服务
python -m http.server 8080

# 后端服务
uvicorn main:app --reload --port 8000

七、项目运行截图

代码的温度,源于对用户体验的极致追求;智能的未来,始于每一次勇敢的技术探索。

如果觉得对你有帮助的话,留下一个点赞和关注把。

相关文章:

  • 6. 使用VUE实现前端页面的分级嵌套
  • Spring Boot集成阿里云OSS:对象存储实战指南
  • 【学习】数字经济下数据价值化的内在逻辑与关键挑战
  • Vue的实例
  • SpringBoot整合Log4j2进行日志记录异步写入日志文件
  • 《深度剖析Android 12 SystemUI锁屏通知布局亮屏流程:从源码到实现》
  • 0323-B树、B+树
  • Mybatis-plus配置动态多数据源
  • Linux系统之yum本地仓库创建
  • EMC知识学习一
  • 【android】补充
  • Jenkins 配置python项目和allure
  • 【HTML 基础教程】HTML 元素
  • 逼用户升级Win11,微软开始给Win10限速
  • 使用 langchain_deepseek 实现自然语言转数据库查询SQL
  • LXC 容器技术简介
  • rbpf虚拟机-验证器(verifier)
  • iOS:GCD信号量、同步、异步的使用方法
  • Browserlist 使用指南:应对浏览器兼容性问题的解决方案
  • golang-互斥锁-mutex-源码阅读笔记
  • 货代一般都去哪个网站找客户/长沙seo结算
  • 如何做中英文网站设计/百度网站排名怎么提高
  • 电器网站建设策划书/国家免费培训机构
  • 前端做网站要会什么/什么样的人适合做策划
  • 网站如何让百度收录/商品关键词优化的方法
  • 佛山网站哪家最专业/上海网络推广招聘