赞
踩
目录
该项目演示了如何使用Angular、ASP.NET API和Azure创建OpenAI聊天应用程序,强调Azure设置、OpenAI交互的API配置ASP.NET,以及为聊天界面构建响应式Angular前端,该界面具有消息顺序和区分用户和OpenAI响应等功能。
在这个项目中,我将向你展示如何使用Angular、ASP.NET API和Azure构建OpenAI聊天应用程序。
有关此项目的最新更新,请转到 DotNetLead的源文章。
我们将介绍:
第一件事是创建如下所示的Azure OpenAI资源。默认情况下,它是Azure中不可用的资源,必须申请访问权限。Microsoft审核你的请求(需要几天时间)后,你将能够创建Azure OpenAI资源。您可以申请访问这里。
创建Azure OpenAI资源后,转到“模型部署”部分,选择要使用的OpenAI模型,如下所示,Azure将转到Azure AI Studio,还可以在其网站上测试聊天功能。
通过选择您喜欢的ChatGpt版本来创建部署,如下所示。在发布时,我选择了gpt-35-turbo。
创建模型后,记下部署的名称,如下所示。您将需要用于构建API的部署名称。
返回到Azure OpenAI资源,记下生成API所需的EndPoint和Key,如下所示。在API中只需要1个密钥。
用于从Azure OpenAI获取聊天响应的代码如下所示。首先,创建OpenAIClient,然后创建ChatCompletionsOptions用于准备查询(即用户聊天输入),然后调用该GetChatCompletionsAsync方法以从Azure OpenAI获取响应。在控制器方法中,我们只返回来自OpenAI的响应内容。
- [HttpGet]
- public async Task<ChatMsg> GetResponse(string query)
- {
- OpenAIClient client = new OpenAIClient(
- new Uri(config["AzureEndPoint"]),
- new AzureKeyCredential(config["AzureKey"])
- );
-
- ChatCompletionsOptions option = new ChatCompletionsOptions { };
- option.Messages.Add(new ChatMessage(ChatRole.User, query));
-
- Response<ChatCompletions> response = await client.GetChatCompletionsAsync(
- config["DeploymentName"],
- option
- );
- return new ChatMsg { Message = response.Value.Choices[0].Message.Content };
- }

如ReadMe.txt文件中所述,使用.NET机密管理器需要以下三个配置,以便配置不会存储在纯文本文件中。
- AzureEndPoint
- AzureKey
- DeploymentName
有关如何使用.NET Secret Manager的说明,请查看使用Secret Manager和Azure Key Vault保护ASP.NET Core配置。
构建聊天前端需要几个属性:
要使聊天窗口保持静态并允许在内容展开时滚动,请声明一个固定位置的flexbox容器(在下面的代码中显示为chat-container类),第一个flexbox项将只是另一个flexbox(在下面的代码中显示为messages类),它具有从下到上显示项的flex-direction作为column-reverse,overflow-y作为scroll用于垂直滚动,overflow-x作为hidden用于隐藏水平滚动。
用户输入和OpenAI响应需要以不同的方式显示,这可以通过声明两个不同的类来完成,即用于显示OpenAI响应的bot-message类和用于显示用户输入的user-message类。请注意,user-message类具有align-self作为flex-end,因此它与右侧对齐。
下面是HTML:
- <div class="chat-container">
- <div class="messages">
- <div *ngFor="let msg of chatHistory"
- [ngClass]="{'user-message': msg.type == 1,
- 'bot-message': msg.type == 2}" >
- <p>{{msg.message}}</p>
- </div>
- </div>
- ...
下面是scss:
- .chat-container {
- position: fixed;
- top: 4rem;
- bottom: 4rem;
- display: flex;
- flex-direction: column;
- width: 42rem;
- box-shadow: $shadow;
- .messages {
- flex: 1;
- display: flex;
- flex-direction: column-reverse; //default scroll to the bottom
- overflow-y: scroll;
- overflow-x: hidden; //hide bottom scroll bar
- padding: 1rem 1.5rem;
- .bot-message {
- display: flex;
- align-items: center;
- p {
- @include message-item($bot-color);
- }
- }
- .user-message {
- display: flex;
- align-items: center;
- align-self: flex-end; //move to the right
- p {
- @include message-item($user-color);
- }
- }
- }
- ...

每条消息的消息类型为1表示用户输入,2表示OpenAI响应,如上面的html所示。消息的定义如下所示:
- export enum MessageType {
- Send = 1,
- Receive = 2
- }
-
- export interface IChatMsg {
- type: MessageType,
- message: string
- }
以下是组件的代码:
- export class ChatComponent implements OnInit {
-
- frmQuery: FormGroup;
- chatHistory: IChatMsg[];
-
- constructor(private chatSvc: ChatService,
- private fb: FormBuilder) { }
-
- ngOnInit(): void {
- this.frmQuery = this.fb.group({
- txtQuery: [null]
- });
-
- this.chatSvc.chat(null)
- .subscribe(aa => this.chatHistory = aa);
- }
-
- submitQuery() {
- //ignore if no query given
- if (!this.frmQuery.get("txtQuery").value)
- return;
- let queryMessage: IChatMsg = {
- type: MessageType.Send,
- message: this.frmQuery.get("txtQuery").value
- };
- this.chatSvc.chat(queryMessage);
- //blank out textbox for next user input
- this.frmQuery.get("txtQuery").setValue(null);
- }
- }

接下来,我们需要在最底部显示最新消息,并将之前的消息向上推送。虽然CSS定义会从下到上显示消息,但消息的顺序是从上到下,需要颠倒过来。此外,对API的每次调用只是一个请求和一个响应,需要保留聊天的历史记录。这些问题可以通过声明一个数组来存储聊天历史记录来解决,并使用该reverse方法将聊天历史记录作为Observable。聊天服务的代码如下所示:
- export class ChatService {
- readonly url = this.appConfig.get('apiChat');
-
- private chatHistory = new BehaviorSubject<IChatMsg[] | null>(null);
- chatHistory$ = this.chatHistory.asObservable();
-
- //stores the chat history
- chatHistoryRecord : IChatMsg[] = [];
-
- constructor(private http:HttpClient,
- private appConfig:AppConfigService){}
-
- chat(queryMessage: IChatMsg): Observable<IChatMsg[]>{
- if (!queryMessage)
- return this.chatHistory$;
- this.chatHistoryRecord.push(queryMessage);
- this.chatHistory.next(this.chatHistoryRecord.slice().reverse());
- //get response
- let queryUrl = this.url + "?query=" + queryMessage.message;
- this.http.get<IChatMsg>(queryUrl).pipe()
- .subscribe(result=>{
- if (result){
- const receiveMsg : IChatMsg =
- { type: MessageType.Receive, message : result.message };
- this.chatHistoryRecord.push(receiveMsg);
- this.chatHistory.next(this.chatHistoryRecord.slice().reverse());
- }
- }
- )
- return this.chatHistory$;
- }
- }

仅此而已,希望您会发现这个项目有用。
本文最初发表于 Building OpenAI chat application with Angular, ASP .Net API, and Azure – .NET Lead
https://www.codeproject.com/Articles/5369946/Building-OpenAI-Chat-Application-with-Angular-ASP
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。