摘要
在本教程中,我将建立一个聊天室网络应用,允许用户输入他们的信息并与ChatGPT进行对话。
开篇
最近,ChatGPT已经变得非常流行。人们要求ChatGPT帮助他们写论文、做作业,甚至要求他们如何赚钱。有了类似的想法,我认为通过向ChatGPT咨询,建立一个聊天室应用程序是很有趣的。
从简单的东西开始,我计划建立一个聊天室网络应用,允许用户输入他们的信息并与ChatGPT进行对话。由此产生的应用程序将看起来像这样。
我将首先弄清楚如何整合ChatGPT,因为这对我来说是新事物。然后,我将建立用户界面,实现逻辑和动作,完成整个应用程序。
不知道如何调用ChatGPT?
我是ChatGPT的新手,不知道如何调用ChatGPT,所以我的脑海中突然出现了一个想法。为什么不直接问ChatGPT呢?
所以我提出了我的第一个问题。
你能给我一个java的代码例子,向ChatGPT发送一个HTTP请求来发送一个消息吗?
然后ChatGPT给我回复了一个连接到
https://api.openai.com/v1/engines/davinci-codex/completions 的Java类例子,并提醒我用我自己的API密钥替换。
然后我问:
我在哪里可以得到API密钥?
ChatGPT给我提供了相关信息,我在这里总结一下:
- 去OpenAI的网站。
- 注册一个账户,或者如果你已经有一个账户,就登录。
- 一旦你登录了,在控制台中导航到API密钥部分。
- 点击 "创建密钥 "按钮。
- 给你的API密钥起个名字,并指定你想使用它的项目。
- 点击 "创建 "来生成API密钥。
- 把API密钥保存在安全的地方,因为它只会显示一次。
看起来很有希望。但当我实际运行Java代码的例子时,API返回代码429,这不是我所期望的。在检查了文档后,似乎URL是错误的。
所以我重新表述了我的问题。
如何在Java中调用OpenAI GPT-3模型?
它用另一个代码回答了我,这个代码连接到了这里。
点击给定的链接后,我发现这个URL已经失效了。所以我善意地告诉ChatGPT。
打开AI文档
https://beta.openai.com/docs/api-reference/engines,提到Engines端点已被废弃。
ChatGPT说:"你是正确的,"并给了我另一个带有正确URL的代码。经验之谈! 不要总是相信ChatGPT的回答。
这次运行代码,我终于得到了预期的JSON响应。
由于我懒得检查JSON字段以获得实际的文本回复,我又问了一个问题。
如何在Java中从OpenAI API响应中提取 "文本"?
而我又一次从ChatGPT中得到了一些有用的东西。
在ChatGPT的帮助下,通过将Java类重构为几个方法,我完成了ChatService,它调用OpenAI API来接收聊天完成建议。基本思路是创建一个HttpURLConnection实例,向OpenAI API端点(
https://api.openai.com/v1/completions)发送一个POST请求,请求体包括聊天提示和其他相关参数,并接收JSON格式的API响应。我在这里包括了技术细节。
Java 代码如下
prompt()向API发送一个聊天提示,并接收一个完成建议。
sendRequest()设置了HttpURLConnection,并将JSON请求体发送给API。
readResponse()从API读取JSON响应,并从JSON对象中检索完成建议。
关于OpenAI的API和完成端点的更多信息可以在OpenAI官方API文档中找到。
在我通过询问GPT,搞清楚了最大的未知数--ChatGPT的整合之后,我已经准备好将其引入我的网络应用。
用ZK设计一个聊天用户界面
在ChatService准备好后,我现在需要一个用户界面来让最终用户输入他们的信息。由于我已经和ZK框架合作了很长时间,我决定使用ZK和zul来构建用户界面。
用ZK组件构建用户界面
如果你没有听说过ZK--它是一个UI框架,允许你在Java中构建Web应用程序。ZK提供了一种ZUL语言,它为构建用户界面带来了大量的组件,从标签、按钮和文本框等基本元素,到网格、树和图表等高级组件。除了这些组件之外,ZUL还提供了一套属性,可以用来定制组件的行为和外观。
我将要建立的聊天室应用程序看起来是这样的。
这个用户界面可以用下面的zul来完成
hflex and vflex
在上面的ZUL代码中,我使用"<hlayout>"来定义我的聊天室的水平布局。<hlayout>有2个属性,hflex和vflex,它们决定了组件的相对大小。"hflex"的值决定了高度而"vflex"的值决定了宽度。在这个例子中,我用hflex="1 "来指定第一个"<div>"应该占用一个单位的水平空间,用hflex="7 "来指定第二个"<div>"应该占用七个单位的水平空间。"这可以使聊天室的布局对大多数屏幕宽度有响应,因为它没有固定的宽度。
textbox
textbox "用于创建聊天室中的文本输入区域。"我使用id属性给它一个唯一的标识符,它可以用来在我的composer类中引用文本框(在后面的段落中解释)。"焦点 "属性被设置为 "true",以强制文本框在页面加载时接受焦点。占位符属性用于向终端用户提供关于文本框用途的提示。
混合HTML标签
在一个ZUL文件中,HTML标签可以在ZUL命名空间内使用,指定为 "xmlns:h"="native"。然后,标签"<h:h1>表示一个HTML标题标签。有了这个命名空间,你可以在他们的ZUL页面中利用HTML标签,如标题、链接和图片,为他们的网络应用添加结构和风格。这为你提供了包括由网页设计师制作的HTML片段的能力,并在zul中建立你自己的自定义部分。
构建用户界面的各种方法
除了编写zul之外,你还可以通过另外2种方式在ZK中建立你的UI。
1.以Swing风格在Java中建立UI
2.用ZUL代码片段调用Java方法。我将在控制器部分做进一步解释。
用CSS打造一个独特的用户体验
在上一节中,我做了用户界面的布局。现在,为了使它更漂亮,我用对比强烈的颜色和不同的背景来区分我的信息和AI的回复。这不仅增强了应用程序的视觉效果,而且也增加了对话的整体可读性。我还为消息框添加了适当的边距和填充物,以创造一个视觉上有吸引力的、有条理的布局。这些都可以通过使用CSS来实现。
在这一节中,我将谈一谈用CSS为ZUL页面设计样式的基本知识,包括<style>标签的使用、sclass和style属性,以及iconSclass属性。
<style>"允许你为ZUL页面定义CSS样式。你可以用src属性在你的ZUL中直接包含一个CSS文件,如上面的代码片段。"这个文件中定义的样式可以使用sclass属性应用到你的ZUL中的组件上。
sclass 属性用于将CSS类应用于组件。在上面的zul中,容器类被应用到<div>组件上,并使用sclass="container "属性。通过使用CSS类,你可以在你的ZUL中为多个组件应用一致的样式。
style 属性允许你将内联样式直接应用于一个组件。在上面的ZUL中,messageBox类被应用到了带有sclass=messageBox属性的div组件中。此外,overflow-y: auto 样式被添加到样式属性中,以指定<div>的内容在溢出其高度时应可垂直滚动。
iconSclass 属性用于在一个按钮上显示图标。"在应用程序中,一个发送图标被显示在<button>上,图标Sclass="z-icon-send "属性。"这是用ZK捆绑的Font Awesome图标完成的,它提供了大量可扩展的矢量图标集合,可以用CSS定制。ZK已经默认包含了它,你不需要手动下载和包含它。
用ZK控制器实现你的应用逻辑
现在我已经准备好了我的用户界面,并以我喜欢的方式进行了风格设计。我的下一步是实现我的应用逻辑。这个用例中的应用逻辑非常简单。
当点击发送按钮(或按下回车键)时,在消息区显示用户输入的消息和ChatGPT的回复。
我目前使用的模式是ZK MVC。我应该在一个ZK控制器的事件监听器中实现我的应用逻辑。控制器是一个Java类,它通过操纵ZK组件来实现应用逻辑,它可以用来处理事件,访问数据,以及操纵用户界面。ZUL中的相关属性是apply属性,它被用来将ZK控制器类与ZUL组件联系起来。
在这个应用程序中,apply属性被设置为
org.zkoss.support.ChatRoomComposer,它将composer类与div联系起来。然后,这个控制器就可以操作这个div和它的子组件了。
连接组件
"ChatRoomComposer "扩展了ZK框架的SelectorComposer。SelectorComposer提供了一个注解,"@Wire",用于将ZUL中的组件与composer中的成员字段连接起来。它提供了类似CSS的选择器
- 第2-3行:ZUL中id="myMessage "的<textbox>被连接到myMessage字段,因为默认是 "ID选择器"
- 第6-7行:这是由 "sclass选择器 "连接的。
- 第8-9行:这是由 "组件名称选择器 "连接的。
关于完整的选择器语法,请参考Wire Components。
事件监听器
控制器还通过@Listen包含了事件监听器,它监听ZUL中组件上的事件,例如最终用户点击按钮或检查复选框。
点击发送按钮
在这个应用程序中,当 "发送 "按钮被点击时,我想调用send(),所以我写道。
onClick是事件名称。#send是 "发送 "按钮的ID选择器。
此外,为了方便,当终端用户在关注文本框时按下 "Enter "键,我也希望send()方法被调用。因此我写道。
onOK是终端用户在文本框中按下 "Enter "键时触发的事件名称。
所以现在我可以用一个监听器成功地监听到2个事件。关于完整的监听器语法,请参考《Wire Event Listeners》。
发送我的信息
在send()中,我可以调用组件API来实现应用逻辑:将我的消息发送到ChatGPT。
myMessage.getValue() 返回文本框中的用户输入。
fastCheckbox.isChecked() 返回 "快速响应 "的检查状态。
现在我可以发送和接收消息了,我只需要在用户界面上显示它们。
显示AI回复 - 在Java代码中构建UI
在文章的开头,我用zul来显示我的用户界面。你可以在这里使用同样的方式来显示AI回复,但我决定使用一种不同的技术--使用Java代码来创建和操作ZK组件。
- 它创建了一个Div组件来容纳整个AI信息。
- 创建一个新的Label组件,名为aiName,文本为 "ChatAI:",并将其样式类设置为ai。因为我想把这个文本变成绿色。
- 它将aiName追加到msgDiv中作为其子项。
- 它创建了另一个名为msg的Label,其文本来自chatService.prompt(),是ChatpGPT的回复。我将多行属性设置为true以显示多行消息
- 最后,它将msgDiv追加到msgBox中作为其子节点。
正如你所看到的,你可以在Java中创建UI组件,配置它们,并建立父-子关系。实际上,你可以用zul做的一切,都可以在Java代码中完成。
显示我的信息 - 用Zul在Java中建立UI
接下来,我将在用户界面中显示用户的信息。同样,你可以使用上面提到的同样的方法,但我决定使用另一种技术--用ZUL在Java中构建用户界面。
用zul和Java构建UI有它自己的好处。使用zul的好处是可读性。通过ZUL,你可以对一个页面有一个大致的了解。然而,使用Java可以让你在运行时根据状态动态地构建UI。如果我可以同时拥有这两个好处呢?这将是非常好的!
ZK确实提供了这样一种方式:通过向
Executions.createComponents()传递zul路径,你可以用zul动态创建组件
从一个ZUL代码段动态地创建UI组件。ZUL代码片段为用户名创建了一个Label。然后这个组件被附加到msgDiv .NET中。
使用这种方法,你可以建立一个动态的、功能性的用户界面,并根据你的应用程序的需要进行优化。
在这一点上,我已经把所有的东西都挂接起来了,我的由ChatGPT驱动的聊天室应用程序已经完全正常了
总结
通过询问ChatGPT,我能够收集到将ChatGPT纳入我的应用程序所需的所有信息。并非所有ChatGPT的答案都是准确的,但询问后续问题或重新表述我的问题都有帮助,并引导我找到我需要的一切。这个过程很有趣,节省了我50%以上的阅读文档和在线寻找资源的时间。