最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

鸿蒙 Next 对接 AI API 实现文字对话功能指南

网站源码admin7浏览0评论

鸿蒙 Next 对接 AI API 实现文字对话功能指南

鸿蒙 Next 对接 AI API 实现文字对话功能指南

在智能化浪潮下,为用户提供便捷的 AI 文字对话功能,成为众多鸿蒙 Next 应用提升用户体验的关键。接下来,我们将深入剖析如何在鸿蒙 Next 系统中对接 AI API,打造流畅的文字对话交互。

前期搭建

环境部署

首先,安装 DevEco Studio 这一鸿蒙原生应用开发的核心工具。它能提供智能代码补全等功能,极大提高开发效率。安装过程需严格遵循官方文档,确保每个环节正确无误。

项目初始化

在 DevEco Studio 内创建新的鸿蒙 Next 应用项目。创建时,依据应用定位,精准选择合适的模板与配置选项。例如,若应用定位为知识问答类,可选择简洁的表单式页面模板,方便用户输入问题与查看答案。

网络权限申请

在应用的\entry\src\main\module.json5配置文件中,明确声明网络访问权限,这是应用与 AI API 进行数据交互的基础。添加如下代码:

代码语言:json复制
{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      }
    ]
  }
}

对接流程

选定 AI API 服务

目前,市场上有多种 AI API 服务可供选择。像华为云自然语言处理服务,凭借其与鸿蒙系统的良好兼容性,能提供稳定高效的自然语言处理能力;还有百度文心一言 API,具备强大的语义理解与文本生成功能。开发者需综合考量服务的功能特性、价格、性能以及与鸿蒙 Next 系统的适配度等因素,做出合适的选择。

集成 AI API 可使用 nodejs 转发

  • \entry\src\main\resources\base\profile\main_pages.json文件中配置页面:
代码语言:json复制
{
  "src": ["pages/Index"]
}
  • \entry\src\main\ets\pages目录中添加Index.ets
代码语言:ts复制
import { router } from '@kit.ArkUI';
import { sendChat } from '../apis/chat';

const enterKeyCode = 2054;
const primaryColor = '#0ea5e9';

enum AiModel {
  // 文生图
  Text2Img = "ti",
  // 文字对话
  Text2Text = "tt",
}

interface IListItem<T> {
  id: T;
  name: string;
}


interface IMessage {
  itemAlign: ItemAlign;
  charts: string;
}

interface RoomParams {
  model: AiModel;
}

interface IAiModelItem extends IListItem<AiModel> {
  hello: string;
}

const aiModels: IAiModelItem[] = [
  {
    id: AiModel.Text2Text,
    name: "聊天",
    hello: '你好,我是文本生成图片的AI工具',
  },
  {
    id: AiModel.Text2Img,
    name: "文生图",
    hello: '请输入绘画的内容',
  }
];

@Entry
@Component
struct Room {
  @State buttonScale: number = 1;
  @State avatarUrl: string = '';
  @State model: IAiModelItem | undefined = undefined;
  @State title: string = '';
  @State bone: number = 0;
  @State messages: IMessage[] = [];
  @State charts: string = '';
  @State loading: boolean = false;
  handleMessage: () => void = () => {
    if (!this.charts) {
      return;
    }
    this.messages.unshift({
      itemAlign: ItemAlign.End,
      charts: this.charts,
    })
    this.loading = true;

    if (!this.model) {
      return;
    }
    const chat = this.charts;
    if (!chat) {
      AlertDialog.show({ message: '内容输入异常,请联系管理员' });
      return;
    }
    sendChat({
      model: this.model.id,
      chat: chat
    }).then((res) => {
      this.charts = '';
      this.loading = false
      this.messages.unshift({ itemAlign: ItemAlign.Start, charts: res })
    }).catch((e: string) => {
      console.log('发送失败' + e);
    })
  }

  onPageShow(): void {
    this.avatarUrl = '/images/logo.png';
    const params = router.getParams() as RoomParams;
    this.model = aiModels.find(item => item.id === params.model);
    const storage = preferences.getPreferencesSync(getContext(), { name: 'storage' });
    const user = storage.getSync('user', null) as IUser;
    if (user) {
      this.bone = user.bone;
    }
  }

  @Builder
  renderTextChat(text: string) {
    Text(text)
      .alignSelf(ItemAlign.Start)
      .backgroundColor('white')
      .padding(8)
      .borderRadius(8)
      .fontColor('black')
  }

  scroller: Scroller = new Scroller();

  build() {
    Column() {
      Row({ space: 12 }) {
        Image('images/back.png').onClick(() => {
          router.back()
        }).width(24).height(24)
        if (this.avatarUrl) {
          Image(this.avatarUrl).width(32).height(32).borderRadius(50)
        }
        if (this.model) {
          Column({ space: 4 }) {
            Text(this.model.name).fontWeight(FontWeight.Medium).fontSize(16);
          }.alignItems(HorizontalAlign.Start).flexGrow(1)
        }
        Text('举报').onClick(() => {
          router.replaceUrl({
            url: 'pages/Report'
          })
        })
      }
      .width('100%')
      .backgroundColor('#ffffff')
      .padding(8)
      .alignItems(VerticalAlign.Center)
      .position({ left: 0, top: 0 })
      .zIndex(1)

      Scroll() {
        Column({ space: 12 }) {
          if (this.loading) {
            this.renderTextChat('...')
          }
          ForEach(this.messages, (item: IMessage) => {
            if (item.itemAlign === ItemAlign.End) {
              Text(item.charts)
                .alignSelf(item.itemAlign)
                .backgroundColor(primaryColor)
                .padding(8)
                .borderRadius(8)
                .fontColor('white')
            }
            if (item.itemAlign === ItemAlign.Start) {
              if (this.model?.id === AiModel.Text2Text) {
                this.renderTextChat(item.charts);
              }
              if (this.model?.id === AiModel.Text2Img) {
                Column() {
                  Image(item.charts).width(200).height(200).borderRadius(4)
                }.alignSelf(ItemAlign.Start).borderRadius(8).backgroundColor('white').padding(8)
              }
            }
          })
          if (this.model) {
            this.renderTextChat(this.model.hello)
          }
        }.width('100%')
      }
      .width('100%')
      .padding({
        top: 128,
        bottom: 0,
        left: 12,
        right: 12
      })

      Column() {
        Row() {
          TextInput({ text: this.charts, placeholder: this.bone + ' (签到领取)' })
            .onChange(v => {
              this.charts = v;
            })
            .backgroundColor('transparent')
            .defaultFocus(true)
            .onKeyEvent(e => {
              if (e.keyCode === enterKeyCode) {
                this.handleMessage();
              }
            })
            .flexGrow(1)
            .height(60)
          Image('/images/bone.svg')
            .onClick(this.handleMessage)
            .width(36)
            .animation({ duration: 200, curve: Curve.Ease })
            .clickEffect({ level: ClickEffectLevel.LIGHT, scale: 0.5 })
            .position({ right: 0, top: 12 })
        }
        .width('100%')
        .borderRadius(20)
        .padding({ right: 20 })
        .alignItems(VerticalAlign.Center)
        .backgroundColor('#ffffff')
        .justifyContent(FlexAlign.SpaceBetween)
        .shadow(ShadowStyle.OUTER_DEFAULT_XS)
      }
      .padding({
        left: 12,
        right: 12,
        top: 12,
        bottom: 12
      })
      .position({ top: 48, left: 0 })
    }.width('100%').height('100%')
  }
}
  • \entry\src\main\ets\apis\chat目录下添加如下代码
代码语言:ts复制
// 引入包名
import { http } from "@kit.NetworkKit";
import { BusinessError } from "@kit.BasicServicesKit";
import { router } from "@kit.ArkUI";

const URL_BASE = "https://******/api";

// const URL_BASE = 'http://localhost:8081/api';

function sendHttp<R, T>(path: string, method: http.RequestMethod, data?: T): Promise<R> {
  // 每一个httpRequest对应一个HTTP请求任务,不可复用
  const httpRequest = http.createHttp();

  return new Promise((res, rej) => {
    httpRequest.request(
      // 填写HTTP请求的URL地址,可以带参数也可以不带参数。URL地址需要开发者自定义。请求的参数可以在extraData中指定
      URL_BASE + path,
      {
        method: method, // 可选,默认为http.RequestMethod.GET
        // 当使用POST请求时此字段用于传递请求体内容,具体格式与服务端协商确定
        extraData: data || null,
        expectDataType: http.HttpDataType.STRING, // 可选,指定返回数据的类型
        usingCache: true, // 可选,默认为true
        priority: 1, // 可选,默认为1
        // 开发者根据自身业务需要添加header字段
        header: { "content-type": "application/json", auth: "huawei" },
        readTimeout: 60000, // 可选,默认为60000ms
        connectTimeout: 60000, // 可选,默认为60000ms
        usingProtocol: http.HttpProtocol.HTTP1_1, // 可选,协议类型默认值由系统自动指定
        usingProxy: false, //可选,默认不使用网络代理,自API 10开始支持该属性
      },
      (err: BusinessError, resp: http.HttpResponse) => {
        httpRequest.destroy();
        if (err) {
          console.log(err.message);
          rej(500);
          return;
        }
        if (resp.responseCode === 401) {
          router.replaceUrl({ url: "pages/Index" });
          rej(401);
          return;
        }
        if (resp.responseCode !== 200) {
          console.log(resp.result + "");
          rej(resp.responseCode);
          httpRequest.destroy();
          return;
        }
        try {
          res(JSON.parse(resp.result as string));
        } catch (e) {
          res(resp.result as R);
        }
      }
    );
  });
}

interface IChatOption {
  model: AiModel;
  chat: string;
}

export function sendChat(data: IChatOption) {
  return sendHttp<string, IChatOption>("/ai", http.RequestMethod.POST, data);
}

服务器代码 以 nextjs + api 为例

代码语言:ts复制
import { NextApiRequest, NextApiResponse } from "next";

// *********************************************鸿蒙next********************************************

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method !== "POST") return res.status(405);

  const { chat = "" } = req.body;
  if (!chat.trim()) {
    return res.status(400).send("no chat");
  }

  const resp = await axios.post(
    ".5-72B-Instruct/chat/completions",
    {
      stream: false,
      max_tokens: 512,
      temperature: 0.7,
      frequency_penalty: 1,
      messages: [
        {
          role: "user",
          content: chat,
        },
      ],
    },
    {
      headers: {
        Authorization: `Bearer 【此处是密钥】`,
        "Content-Type": "application/json",
      },
    }
  );
  const content = resp.data.choices[0]?.message.content;
  res.status(200).send(content);

  res.status(405).send(405);
}

至此就从服务端、客户端实现了调用AI api的功能

功能测试与优化

完成功能开发后,要在不同设备与网络环境下对应用进行全面测试。检查用户输入的文字能否准确传递给 AI API,AI 回复是否符合预期,多轮对话时上下文信息的传递是否正确,以及应用在长时间对话中的性能表现等。针对测试中发现的问题,如响应延迟、回复不准确等,及时优化代码与调整配置,确保为用户提供流畅、高效的文字对话服务。

通过以上步骤,开发者能够在鸿蒙 Next 系统中成功对接 AI API,实现强大的文字对话功能,为用户带来智能化的交互体验。在开发过程中,需充分利用鸿蒙系统资源,严格遵循开发规范,持续打磨细节,才能打造出优质的应用。

发布评论

评论列表(0)

  1. 暂无评论