HarmonyOS NEXT鸿蒙开发 ArkTS:openai 调用阿里云大模型

介绍

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

原文出处:/show_1GW2QL9E6nnf.html