uni.request 配置流式接收+通义千问实现多轮对话

1. 配置基础的uni.request服务

ts 复制代码
// 基础URL
const baseUrl = 'localhost:3000';

// 扩展请求方法参数,新增 headers 配置
type Method = 'GET' | 'POST' | 'PUT' | 'DELETE';

// 通用请求函数(新增 headers 参数)
const request = (
  url: string,
  method: Method,
  data?: any,
  headers?: Record<string, string>
) => {
  return new Promise((resolve, reject) => {
    const fullUrl = url.startsWith('http') ? url : `${baseUrl}${url}`;

    // 合并默认 header 和自定义 header
    const mergedHeaders: Record<string, string> = {
      'Content-Type': 'application/json', // 默认保留
      ...headers, // 合并自定义 header(可覆盖默认值)
    };
    // 创建一个请求task
    const requestTask = uni.request({
      url: fullUrl,
      method: method,
      data: data,
      header: mergedHeaders, // 使用合并后的 header
      enableChunked: true,
      success: (res) => {
        resolve(res);
      },
      fail: (err) => {
        reject(err);
      },
    });

    // 返回一个包含流式处理方法的对象
    resolve({
      onHeadersReceived: (callback: (headers: any) => void) => {
        requestTask.onHeadersReceived((res) => {
          callback(res.header);
        });
      },
      onChunkReceived: (callback: (chunk: any) => void) => {
        (requestTask as any).onChunkReceived((res: any) => {
          callback(res.data);
        });
      },
      abort: () => {
        requestTask.abort();
      },
    });
  });
};


// GET请求方法(保持原有参数)
const get = (url: string, data?: any) => {
  return request(url, 'GET', data);
};

// POST请求方法(新增 headers 参数)
const post = (url: string, data: any, headers?: Record<string, string>) => {
  return request(url, 'POST', data, headers);
};

// 导出GET和POST方法
export { get, post };

2.编程专属的ai请求文件

ts 复制代码
// 引入基础请求方法
import { post } from './api.config';
import { SSEHandler } from "@/types/baseType";
const accessToken = 'sk-xxx';
export const callAliyunAI = async (userInput: string, history: Array<{ role: string, content: string }> = []): Promise<SSEHandler> => {
  const url = 'https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions';
  const headers = {
    'Authorization': `Bearer ${accessToken}`,
    // 'Content-Type': 'text/event-stream',
    // 'Cache-Control': 'no-cache',
    'X-DashScope-SSE': 'enable',
    // 'Coneection': 'keep-alive'
  };
  const messages = [
    ...history, // 添加历史对话记录
    {
      role: "user",
      content: userInput // 当前用户输入
    }
  ];
  const data = {
    model: 'qwen-plus',
    messages: messages,
    stream: true,
  };

  try {
    const response = await post(url, data, headers);
    return response as SSEHandler;
  } catch (error: any) {
    throw new Error(`调用AI模型失败: ${error.message}`);
  }
};
  1. 页面中多轮对话关键代码
ts 复制代码
// 发送消息
const sendMessage = async () => {
  if (input.value.trim() !== "") {
    messages.value.push({ role: "user", content: input.value });
    const userInput = input.value;
    input.value = "";
    try {
      // 调用 AI 接口,传入用户输入
      const sseHandler = await callAliyunAI(userInput, messages.value);
      sseHandler.onHeadersReceived((headers: Record<string, string>) => {
        console.log("响应头:", headers);
      });

      // // 处理流式数据
      sseHandler.onChunkReceived((chunk: ArrayBuffer) => {
        console.log("接收到数据:", chunk);
        parseData(chunk); // 数据解析 并填充到对话框
      });
    } catch (error) {
      console.error("调用AI模型失败:", error);
      messages.value.push({
        role: "system",
        content: "调用AI模型失败,请重试。",
      });
    }
  }
};

//  解析函数
const parseData = (data: ArrayBuffer) => {
  // 将 ArrayBuffer 转换为字符串
  const decoder = new TextDecoder("utf-8");
  const rawString = decoder.decode(data);

  // 按 "data: " 分割字符串,处理多条数据
  const jsonStrings = rawString
    .split("data: ")
    .filter((str) => str.trim() !== "");
  console.log("jsonStrings", jsonStrings);
  jsonStrings.forEach((jsonString) => {
    try {
      // 判断是否结束
      if (jsonString.indexOf("[DONE]") !== -1) {
        console.log("数据流结束");
        return;
      }

      // 解析 JSON 字符串
      const messageData = JSON.parse(jsonString);

      const message = messageData.choices[0].delta.content || "";
      const lastMessage = messages.value[messages.value.length - 1];
      if (lastMessage.role === "assistant") {
        lastMessage.content += message;
      } else {
        messages.value.push({ role: "assistant", content: message });
      }
      nextTick(() => {
        scrollIntoView.value = `msg-${messages.value.length - 1}`;
      });
    } catch (error) {
      console.error("解析数据失败:", error);
    }
  });
};
相关推荐
Irene199111 小时前
Vue 3 中,组合式 API 的 setup() 函数确实先于选项式 API 的生命周期钩子执行
vue.js·执行顺序·组合式 api·选项式 api
初学大模型11 小时前
我们从神经网络进化过程的角度从新审视神经网络
人工智能·机器人
小北方城市网11 小时前
第 4 课:微服务 API 网关设计与接口全生命周期管理|统一入口与接口治理实战
java·大数据·运维·人工智能·python·深度学习·数据库架构
Wu_Dylan11 小时前
液态神经网络系列(一) | 液态神经网络是什么?——从“脉冲”到“连续”的范式转移
人工智能
Blossom.11811 小时前
知识图谱增强大模型:构建可解释的行业智能搜索引擎
运维·人工智能·python·智能手机·自动化·prompt·知识图谱
派大鑫wink11 小时前
网络安全新挑战:AI 驱动的攻防对抗与防护策略(附实战操作)
人工智能·python·安全·web安全
CCPC不拿奖不改名11 小时前
Python基础:python语言中的文件操作+面试题目
开发语言·数据结构·人工智能·python·学习·面试·职场和发展
飞哥数智坊11 小时前
谈谈我对 Claude Code 之父13条技巧的理解
人工智能·ai编程·claude
ar012311 小时前
水务应用AR技术:推动智慧水务的创新实践
人工智能·ar