ASP.NET Core开发Chatbot API

news/2024/10/26 8:28:59/

在这里插入图片描述

本文介绍基于ASP.NET Core的Chatbot Restful API开发,通过调用大语言模型的SDK,完成一个简单的示例。并且通过容器化进行部署.

安装

首先需要安装.NET环境,笔者在Ubuntu 22.04通过二进制包进行安装,Windows和Mac下都有installer可以用. 选择的版本是.NET 8.

技术栈

我们分析一下要用到的技术栈,想要达到一个基本的demo需求,需要实现API,以及数据的查询存储,以及快速搭建运行环境.
因此我们选择postgresql存储数据,docker容器化实现快速部署. LLM服务选用了OpenAI.

Solution

首先创建一个solution,可以使用如下命令,或者使用IDE.

dotnet new sln

然后新建webapi工程并添加到solution中

mkdir WebApi
cd WebApi
dotnet new webapi
cd ..
dotnet sln add WebApi

完成创建后可以尝试restore并且简单build一下确认环境是否正常

dotnet restore
dotnet build

创建控制器

新建的webapi工程默认给了一个Program.cs

var builder = WebApplication.CreateBuilder(args);// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();var app = builder.Build();// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{app.UseSwagger();app.UseSwaggerUI();
}app.UseHttpsRedirection();var summaries = new[]
{"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};app.MapGet("/weatherforecast", () =>
{var forecast =  Enumerable.Range(1, 5).Select(index =>new WeatherForecast(DateOnly.FromDateTime(DateTime.Now.AddDays(index)),Random.Shared.Next(-20, 55),summaries[Random.Shared.Next(summaries.Length)])).ToArray();return forecast;
})
.WithName("GetWeatherForecast")
.WithOpenApi();app.Run();record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}

这个代码模板已经实现了一个简单的API,但不是我们需要的基于controller的模式,为了使用controller,我们还要安装一些依赖包.

dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
dotnet tool uninstall -g dotnet-aspnet-codegenerator
dotnet tool install -g dotnet-aspnet-codegenerator
dotnet tool update -g dotnet-aspnet-codegenerator

Microsoft官方tutorial中给出的是:

dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools
dotnet tool uninstall -g dotnet-aspnet-codegenerator
dotnet tool install -g dotnet-aspnet-codegenerator
dotnet tool update -g dotnet-aspnet-codegenerator

因为我们不使用EntityFrameworkCore,所以去掉了关于EntityFrameworkCore的引用.

然后是创建controller,例如我们命名为ChatController:

dotnet aspnet-codegenerator controller -name ChatController -api -outDir Controllers

创建后,我们可以得到ChatController.cs文件,稍作修改如下

using Microsoft.AspNetCore.Mvc;namespace WebApi.Controllers;[Route("api/[controller]")]
[ApiController]
public class ChatController(IChatService chatService) : ControllerBase
{[HttpPost][Route("[action]")]public ActionResult<ChatResponse> Completions([FromBody] ChatRequest request){var input = request.Text;var result = chatService.Complete(request);return Ok(result);}
}

这时,如果我们直接运行工程,会发现在swagger的页面中,找不到刚才添加的Chat endpoint,因为还需要一些配置
Program.cs中,我们需要让服务映射我们新增的controller.

builder.Services.AddControllers();
app.MapControllers();

上面是两行需要增加的代码,使整个Program.cs看起来这样

var builder = WebApplication.CreateBuilder(args);// Add services to the container.
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddControllers();var app = builder.Build();// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{app.UseSwagger();app.UseSwaggerUI();
}app.UseHttpsRedirection();
app.MapControllers();//entry point
app.Run();

这时,再运行就会发现swagger中已经有相关的endpoint。

OpenAI SDK

使用OpenAI SDK非常简单,直接安装依赖包

dotnet add package OpenAI-DotNet --version 8.3.0

准备好一个Open AI的key,配置到环境变量中,创建一个Factory获取ChatClient(这是和OpenAI交互的客户端). 笔者使用的模型是gpt-3.5-turbo,单纯是实惠,lol.

public abstract class OpenAiClientFactory
{public static ChatClient Create(){var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY")?? throw new InvalidOperationException("OpenAI API key not set");return new ChatClient("gpt-3.5-turbo", apiKey);}
}

有了ChatClient后,就可以进行交互了. 这里涉及到的知识有AI对话点角色问题,涉及到3个角色:

  1. system
  2. assistant
  3. user

相关的概念可以查看文档.
进行一次AI对话就很方便了,直接调用complete方法即可

var prompt = $"""You are an NLU expert help to do intent recognition, slot filling work. Now you are going to understand user input then give a proper result.""";
var systemChatMessage = new SystemChatMessage(prompt);
var userChatMessage = new UserChatMessage(input);
var response = chatClient.CompleteChat([systemChatMessage, userChatMessage]);

这是一个模板代码,可以按照自己的需求修改.

容器化

为了快速运行,可以在项目中增加一个Dockrfile

FROM mcr.microsoft.com/dotnet/sdk:8.0EXPOSE 5114COPY . /appWORKDIR /appRUN dotnet restore && dotnet buildCMD [ "dotnet","run","--project","./WebApi" ]

通过docker快速打包后就能在所有支持docker的平台上快速演示demo.
在容器化方面,我们还可以使用docker compose来把数据库也和主程序一起启动。

Docker Compose 是 Docker 官方编排工具,用于定义和运行多容器 Docker 应用程序。使用 Docker Compose,你可以通过一个 YAML 文件来配置你的应用服务,然后使用一个简单的命令来启动和停止所有服务。

Docker Compose 的主要特点包括:

  1. 多容器编排:可以定义多个容器服务,并管理它们之间的依赖关系。

  2. 服务隔离:每个服务运行在独立的容器中,可以单独配置环境变量、卷挂载、网络等。

  3. 一键部署:通过 docker-compose up 命令,可以一次性启动配置文件中定义的所有服务。

  4. 版本控制:Docker Compose 文件(通常是 docker-compose.yml)可以被版本控制系统跟踪,方便团队协作和持续集成。

  5. 环境一致性:在开发、测试和生产环境中使用相同的配置文件,确保环境一致性。

  6. 网络管理:可以定义服务之间的网络连接,使得服务之间可以通过服务名进行通信。

  7. 数据卷管理:可以定义数据卷,实现数据的持久化和共享。

  8. 扩展性:支持通过环境变量和扩展文件来扩展配置。

  9. 命令行工具:提供了丰富的命令行工具,用于管理服务的生命周期,如启动、停止、重建、日志查看等。

一个基本的 docker-compose.yml 文件示例如下:

version: '3'
services:web:image: "nginx:latest"ports:- "80:80"volumes:- "/var/www:/usr/share/nginx/html"depends_on:- dbdb:image: "postgres:latest"environment:POSTGRES_DB: "mydb"POSTGRES_USER: "user"POSTGRES_PASSWORD: "password"

在我们的例子中,还需要一个功能,就是在docker启动的时候,需要执行一段sql脚本初始化数据库,这个需求postgresql的image已经考虑到,只需要把要执行的脚本映射到一个特殊的路径即可。映射后,在container启动的时候,会执行sql.

- ./db.sql:/docker-entrypoint-initdb.d/init.sql

那么最终我们的docker-compose文件可能是这样:

version: '3'
services:web:build:context: .dockerfile: Dockerfileenvironment:- ConnectionStrings__DefaultConnection=Host=db;Port=5432;Database=db;Username=postgres;- ASPNETCORE_ENVIRONMENT=Development- OPENAI_API_KEY=sk-1234567890abcdef1234567890abcdef # REPLACE WITH YOUR OPENAI KEYports:- "5000:5000"depends_on:- dbdb:image: bitnami/postgresql:latestcontainer_name: pg-containerrestart: alwaysenvironment:POSTGRES_USER: postgresALLOW_EMPTY_PASSWORD: yesPOSTGRES_DB: dbvolumes:- ./db.sql:/docker-entrypoint-initdb.d/init.sqlports:- "5432:5432"

总结

使用ASP.NET Core开发restful api相当方便,而借助容器的强大功能,部署到云环境进行快速验证也得以实现.


http://www.ppmy.cn/news/1542057.html

相关文章

TortoiseSVN 添加日志模板

1、找到项目文件夹&#xff0c;“右键-TortoiseSVN-属性” 2、“新建-其他” 3、增加属性 属性选择&#xff1a;“tsvn:logtemplate” 在“取值”中填写格式&#xff1a; 添加完成&#xff1a;

云原生后端开发之道

云原生后端开发之道 在现代软件开发中&#xff0c;云原生后端正如一道光芒&#xff0c;照亮了我们通往高效与灵活的道路。那么&#xff0c;究竟什么是云原生后端&#xff1f;它的魅力何在&#xff1f;今天&#xff0c;我们就带你深入这个充满可能性的领域。 1. 云原生后端概述…

MySql中使用findInSet和collection实践

FIND_IN_SET 需求如下&#xff1a;有张用户表&#xff0c;表里有个字段叫school&#xff0c;意为这个用户上过哪些学校&#xff0c;数据库里存的就是字符串类型&#xff0c;存的值类似"2,5,12"&#xff0c;要求就是查询出上过id为2的学校有哪些用户 解决方法&#x…

【C++修炼】初识C++:命名空间、缺省参数、函数重载、引用、内联函数、指针空值

目录 一、命名空间 1.1 命名空间的定义 1.2 命名空间的使用 二、缺省参数 2.1 缺省参数的概念 2.2 缺省参数的分类 三、重载函数 四、引用 4.1 引用的概念 4.2 引用特性 4.3 常引用/const引用 4.4 使用场景 4.5 传值与传引用的效率对比 4.6 引用和指针的区别 五…

【安全解决方案】深入解析:如何通过CDN获取用户真实IP地址

一、业务场景 某大型互联网以及电商公司为了防止客户端获取到真实的ip地址&#xff0c;以及达到保护后端业务服务器不被网站攻击&#xff0c;同时又可以让公安要求留存网站日志和排查违法行为&#xff0c;以及打击犯罪的时候&#xff0c;获取不到真实的ip地址&#xff0c;发现…

前端零基础入门到上班:【Day5】HTML 和 CSS

HTML 和 CSS 的完美结合&#xff1a;从基础到进阶 引言 1. HTML 与 CSS 的基础知识1.1 HTML 概述常用标签 1.2 CSS 概述选择器与属性 1.3 HTML 与 CSS 的基本结合 2. HTML 与 CSS 的基本结合2.1 选择器的使用2.1.1 元素选择器2.1.2 类选择器2.1.3 ID 选择器2.1.4 组合选择器 2.…

WebView渲染异常导致闪退解决方案

背景&#xff1a; App主页面使用了大量WebView容器(10个以上)显示图表信息&#xff0c;最新发现bugly上面出现一些关于浏览器Native Crash&#xff0c;如下&#xff1a; 经排查&#xff0c;是WebView渲染失败导致Crash&#xff0c;可以通过webView.loadUrl("chrome://cra…

【赵渝强老师】Hive的内部表与外部表

Hive是基于HDFS之上的数据仓库&#xff0c;它把所有的数据存储在HDFS中&#xff0c;Hive并没有专门的数据存储格式。当在Hive中创建了表&#xff0c;可以使用load语句将本地或者HDFS上的数据加载到表中&#xff0c;从而使用SQL语句进行分析和处理。 Hive的数据模型主要是指Hiv…