介绍
OpenAI 请求工具库,基本保留原 npm 库 TypeScript 定义。
官方API
https://ohpm.openharmony.cn/#/cn/detail/@iuroc%2Fopenai/v/1.0.0
安装使用
ohpm install @iuroc/openai
使用方法一
import { OpenAI } from '@iuroc/openai'
const openai = new OpenAI({
apiKey: 'sk-xxxx',
baseURL: 'https://api.openai.com/v1'
})
const result = openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [
{ role: 'user', content: 'hello' }
]
})
const response = result.response
const session = result.session
等待请求完成
Promise 方式
const resp = await completion.response
Callback 方式
response.then( resp => {
})
resp结果
上面 resp 结果:
{
"choices": [
{
"message": {
"role": "assistant",
"content": "我是通义千问,阿里巴巴集团旗下的超大规模语言模型。我能够回答问题、创作文字,比如写故事、写公文、写邮件、写剧本等等,还能进行逻辑推理、编程等任务。如果你有任何问题或需要帮助,欢迎随时告诉我!"
},
"finish_reason": "stop",
"index": 0,
"logprobs": null
}
],
"object": "chat.completion",
"usage": {
"prompt_tokens": 22,
"completion_tokens": 57,
"total_tokens": 79,
"prompt_tokens_details": {
"cached_tokens": 0
}
},
"created": 1765956702,
"system_fingerprint": null,
"model": "qwen-plus",
"id": "chatcmpl-fdb9e303-863a-4a20-a7b4-533dc71b4024"
}
取出正文内容:
const json = resp.toJSON()
if(json!=null) {
// console.log(TAG, "json---------",json['choices'][0].message.content)
this.message = json['choices'][0].message.content
// console.log(TAG,"message--",this.message)
}
终止请求
session.cancel()
使用方法二-流式输出
提示:官网的流式输出有bug
const onDataCallback: OnDataCallback = (chunks:ChatCompletionChunk[]) => {
// const newContent = chunks.map(chunk => chunk.choices[0].delta.content).join('')
// console.log(TAG,newContent)
// this.answer += newContent
for(let chunk of chunks){
// 过滤空内容(避免无效数据)
if (!chunk.choices || chunk.choices.length === 0) continue;
const choice = chunk.choices[0];
const content = choice.delta?.content || ''; // 增量内容
// 1. 核心判断:finish_reason 存在 → 输出结束
if (choice.finish_reason) {
// isFinished = true;
console.log(TAG,`流式输出结束,结束原因:${choice.finish_reason}`);
this.resetSendBtn()
break; // 终止遍历
}
// 拼接并打印增量内容
if (content) {
this.answer += content
}
}
}
const onErrorCallback = (error: Error) => {
console.error(TAG,JSON.stringify(error))
}
const options : ChatCompletionsCreateOptions = {
onData:onDataCallback,
onError:onErrorCallback,
}
const result = openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [
{ role: 'user', content: 'hello' }
],
stream: true
}, options)
案例
安装 markdown
本例子使用第三方 markdown 组件,可以正常显示大模型返回的 markdown内容
安装:
ohpm install @luvi/lv-markdown-in
阿里百炼
api网址如下:
https://bailian.console.aliyun.com/?tab=api#/api/?type=model&url=2712576
需要注册、申请api key
代码
提示:将阿里百炼API Key填到下面 apiKey 中
import { OpenAI } from '@iuroc/openai'
import { Markdown } from '@luvi/lv-markdown-in'
import { rcp } from '@kit.RemoteCommunicationKit';
import { OnDataCallback,ChatCompletionsCreateOptions } from '@iuroc/openai/src/main/ets/ChatCompletions';
import { ChatCompletionChunk } from '@iuroc/openai/src/main/ets/openai@4.73.1/resources';
const openai = new OpenAI(
{
// 若没有配置环境变量,请用百炼API Key将下行替换为:apiKey: "sk-xxx",
apiKey: "",
baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1"
}
);
const TAG = "HealthPage-------"
/**
* 发送按钮-未发送
*/
const SENDBTN_NOT_SEND = 0
/**
* 发送按钮-正在发送
*/
const SENDBTN_SEND = 1
const SENDBTN_TEXT_SEND = "发送"
const SENDBTN_TEXT_STOP = "停止"
@Entry
@Component
struct HealthPage {
@State answer: string = ''
@State question: string = '冬季如何补气血'
// 发送按钮是否可用
@State btnEnabled:boolean = true
// 发送按钮显示内容
@State btnText:string = SENDBTN_TEXT_SEND
@State sendBtnStatus:number = SENDBTN_NOT_SEND
session!:rcp.Session|null
build() {
Column(){
Text("我是您的健康小助手,有什么问题:")
.width("100%")
.margin({
top:20
})
TextArea({
text:$$this.question,
placeholder:"您有什么问题尽管问我哈"
})
.height(100)
.margin({
top:5
})
Row() {
Blank()
Button(this.btnText)
.onClick(async () => {
this.send()
})
.enabled(this.btnEnabled)
}
.width("100%")
.margin({
top:10
})
Scroll() {
Markdown({ text: this.answer })
}
.margin({
top: 10
})
}
.height("70%")
.padding({
left:10,
right:10,
})
}
async send(){
if(this.sendBtnStatus == SENDBTN_NOT_SEND) {
this.answer = ""
console.log(TAG,"send 开始----------")
// this.btnEnabled = false
this.btnText = SENDBTN_TEXT_STOP
this.sendBtnStatus = SENDBTN_SEND
// 普通输出
// const completion = openai.chat.completions.create({
// model: "qwen-plus", //此处以qwen-plus为例,可按需更换模型名称。模型列表:https://help.aliyun.com/zh/model-studio/getting-started/models
// messages: [
// { role: "system", content: "你是养生专家" },
// { role: "user", content: this.question }
// ],
// });
// const resp = await completion.response
// this.session = completion.session
// console.log(TAG, "send 结束----------")
// // console.log(TAG,JSON.stringify(resp))
// const json = resp.toJSON()
//
// if (json != null ) {
// // console.log(TAG, "json---------",json['choices'][0].message.content)
// this.answer = json['choices'][0].message.content
// // console.log(TAG,"message--",this.message)
// }
// 下面是流式输出---------------------
const onDataCallback: OnDataCallback = (chunks:ChatCompletionChunk[]) => {
// const newContent = chunks.map(chunk => chunk.choices[0].delta.content).join('')
// console.log(TAG,newContent)
// this.answer += newContent
for(let chunk of chunks){
// 过滤空内容(避免无效数据)
if (!chunk.choices || chunk.choices.length === 0) continue;
const choice = chunk.choices[0];
const content = choice.delta?.content || ''; // 增量内容
// 1. 核心判断:finish_reason 存在 → 输出结束
if (choice.finish_reason) {
// isFinished = true;
console.log(TAG,`流式输出结束,结束原因:${choice.finish_reason}`);
this.resetSendBtn()
break; // 终止遍历
}
// 拼接并打印增量内容
if (content) {
this.answer += content
}
}
}
const onErrorCallback = (error: Error) => {
console.error(TAG,JSON.stringify(error))
}
const options : ChatCompletionsCreateOptions = {
onData:onDataCallback,
onError:onErrorCallback,
}
const completion = openai.chat.completions.create({
model: "qwen-plus", //此处以qwen-plus为例,可按需更换模型名称。模型列表:https://help.aliyun.com/zh/model-studio/getting-started/models
messages: [
{ role: "system", content: "你是养生专家" },
{ role: "user", content: this.question }
],
stream: true
},options);
this.session = completion.session
}else {
console.log(TAG,"send 手动停止----------")
if(this.session) {
this.session.cancel()
}
this.resetSendBtn()
}
}
/**
* 重置发送按钮
*/
resetSendBtn(){
this.btnText = SENDBTN_TEXT_SEND
this.sendBtnStatus = SENDBTN_NOT_SEND
this.session = null
}
}
export default HealthPage