Skip to content

yxplus1116/vue-ai-stream-helper

Repository files navigation

Vue AI Stream Helper

Vue License PRs Welcome

一个轻量级的 Vue.js 插件,用于处理 AI 大模型的流式响应(SSE - Server-Sent Events)。支持实时接收 AI 回复内容,提供简洁的 API 和完善的错误处理。

✨ 特性

  • 🚀 流式响应处理 - 完整支持 SSE (Server-Sent Events) 协议
  • 💬 实时内容更新 - 通过回调函数实时获取 AI 回复
  • 🔄 请求管理 - 支持取消正在进行的请求
  • 🔐 自动认证 - 自动添加 Token 到请求头
  • 轻量高效 - 零依赖,体积小巧
  • 🎯 TypeScript 友好 - 提供完整的类型定义
  • 🔧 高度可配置 - 灵活的配置选项
  • 🛡️ 错误处理 - 完善的异常捕获机制

📦 安装

NPM

npm install vue-ai-stream-helper

Yarn

yarn add vue-ai-stream-helper

CDN

<script src="https://unpkg.com/vue-ai-stream-helper"></script>

🚀 快速开始

1. 全局注册(推荐)

// main.js
import Vue from 'vue';
import AIStreamHelper from 'vue-ai-stream-helper';

Vue.use(AIStreamHelper, {
  baseURL: 'https://your-api.com',
  endpoint: '/api/chat',
  model: 'qwen-turbo',
  getToken: () => localStorage.getItem('token'), // 获取Token的函数
  headers: {
    // 自定义请求头(可选)
  }
});

2. 在组件中使用

<template>
  <div>
    <el-button @click="callAI" :loading="loading">
      {{ loading ? 'AI思考中...' : '开始对话' }}
    </el-button>
    <div class="response">{{ aiResponse }}</div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      loading: false,
      aiResponse: ''
    }
  },
  methods: {
    async callAI() {
      this.loading = true;
      this.aiResponse = '';

      await this.$aiChat.chat({
        content: '请介绍一下你自己',
        
        // 实时接收AI回复
        onMessage: ({ fullContent }) => {
          this.aiResponse = fullContent;
        },
        
        // 完成回调
        onComplete: (fullContent) => {
          this.$message.success('回复完成!');
          this.loading = false;
        },
        
        // 错误处理
        onError: (error) => {
          this.$message.error('调用失败');
          this.loading = false;
        }
      });
    }
  }
}
</script>

📖 API 文档

Vue.use(AIStreamHelper, options)

配置选项

参数 类型 必填 默认值 说明
baseURL String - API 基础 URL
endpoint String - 接口端点路径
model String 'qwen-turbo' 默认模型名称
getToken Function () => '' 获取认证 Token 的函数
headers Object {} 自定义请求头

this.$aiChat.chat(options)

发送流式聊天请求。

参数

参数 类型 必填 说明
content String 否* 用户消息内容(简化版)
messages Array 否* 完整消息列表(高级版)
model String 模型名称(覆盖默认配置)
onMessage Function 接收消息时的回调
onComplete Function 完成时的回调
onError Function 错误时的回调

*注:contentmessages 至少提供一个

onMessage 回调参数

{
  content: '当前片段内容',
  fullContent: '累积的完整内容',
  rawData: {} // 原始响应数据
}

this.$aiChat.abort()

取消当前正在进行的请求。

this.$aiChat.abort();

this.$streamChat(content, options)

快捷方法,用于简单的一次性调用。

await this.$streamChat('你好', {
  onMessage: ({ fullContent }) => console.log(fullContent)
});

💡 使用示例

基础用法

export default {
  methods: {
    async basicChat() {
      await this.$aiChat.chat({
        content: '什么是Vue.js?',
        onMessage: ({ fullContent }) => {
          console.log('当前内容:', fullContent);
        },
        onComplete: (fullContent) => {
          console.log('完整回复:', fullContent);
        }
      });
    }
  }
}

高级用法:自定义系统提示

export default {
  methods: {
    async professionalChat() {
      await this.$aiChat.chat({
        messages: [
          {
            role: 'system',
            content: '你是一个专业的前端开发工程师'
          },
          {
            role: 'user',
            content: '请解释Vue的响应式原理'
          }
        ],
        onMessage: ({ fullContent }) => {
          this.response = fullContent;
        }
      });
    }
  }
}

多轮对话

export default {
  data() {
    return {
      history: [
        {
          role: 'system',
          content: '你是一个helpful的助手'
        }
      ]
    }
  },
  methods: {
    async sendMessage(userInput) {
      // 添加用户消息
      this.history.push({
        role: 'user',
        content: userInput
      });

      let aiReply = '';

      await this.$aiChat.chat({
        messages: this.history,
        onMessage: ({ fullContent }) => {
          aiReply = fullContent;
        },
        onComplete: () => {
          // 添加AI回复到历史
          this.history.push({
            role: 'assistant',
            content: aiReply
          });
        }
      });
    }
  }
}

取消请求

<template>
  <div>
    <el-button @click="start">开始</el-button>
    <el-button @click="stop" v-if="generating">取消</el-button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      generating: false
    }
  },
  methods: {
    async start() {
      this.generating = true;
      await this.$aiChat.chat({
        content: '写一篇很长的文章...',
        onMessage: (data) => console.log(data),
        onComplete: () => {
          this.generating = false;
        }
      });
    },
    stop() {
      this.$aiChat.abort();
      this.generating = false;
    }
  },
  beforeDestroy() {
    // 组件销毁时取消请求
    this.$aiChat.abort();
  }
}
</script>

独立实例(不使用全局注册)

import { createAIChat } from 'vue-ai-stream-helper';

export default {
  data() {
    return {
      aiChat: null
    }
  },
  created() {
    this.aiChat = createAIChat({
      baseURL: 'https://your-api.com',
      endpoint: '/api/chat',
      getToken: () => this.$store.state.token
    });
  },
  methods: {
    async chat() {
      await this.aiChat.chat({
        content: 'Hello',
        onMessage: (data) => console.log(data)
      });
    }
  }
}

🎯 完整示例:AI简历优化

<template>
  <div class="ai-resume-optimizer">
    <el-input
      v-model="resumeContent"
      type="textarea"
      :rows="8"
      placeholder="请输入简历内容"
    />
    
    <div class="actions">
      <el-button
        type="primary"
        :loading="optimizing"
        @click="optimize"
        icon="el-icon-magic-stick"
      >
        {{ optimizing ? '优化中...' : 'AI优化' }}
      </el-button>
      
      <el-button
        v-if="optimizing"
        @click="cancel"
        icon="el-icon-close"
      >
        取消
      </el-button>
    </div>

    <div v-if="optimizedContent" class="result">
      <h3>优化结果:</h3>
      <div class="content">{{ optimizedContent }}</div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      resumeContent: '',
      optimizedContent: '',
      optimizing: false
    }
  },
  
  methods: {
    async optimize() {
      if (!this.resumeContent.trim()) {
        this.$message.warning('请输入简历内容');
        return;
      }

      this.optimizing = true;
      this.optimizedContent = '';

      try {
        await this.$aiChat.chat({
          messages: [
            {
              role: 'system',
              content: '你是一个专业的简历优化专家。请帮助用户优化简历,使其更专业、简洁、有吸引力。'
            },
            {
              role: 'user',
              content: `请优化以下简历:\n\n${this.resumeContent}`
            }
          ],
          
          onMessage: ({ fullContent }) => {
            this.optimizedContent = fullContent;
          },
          
          onComplete: () => {
            this.$message.success('优化完成!');
            this.optimizing = false;
          },
          
          onError: (error) => {
            this.$message.error('优化失败:' + error.message);
            this.optimizing = false;
          }
        });
      } catch (error) {
        if (error.name !== 'AbortError') {
          this.$message.error('请求异常');
        }
        this.optimizing = false;
      }
    },

    cancel() {
      this.$aiChat.abort();
      this.optimizing = false;
      this.$message.info('已取消优化');
    }
  },
  
  beforeDestroy() {
    this.$aiChat.abort();
  }
}
</script>

<style scoped>
.ai-resume-optimizer {
  padding: 20px;
}

.actions {
  margin: 16px 0;
}

.result {
  margin-top: 20px;
  padding: 16px;
  background: #f5f7fa;
  border-radius: 4px;
}

.content {
  white-space: pre-wrap;
  line-height: 1.8;
}
</style>

🔧 配置示例

使用不同的AI服务

OpenAI

Vue.use(AIStreamHelper, {
  baseURL: 'https://api.openai.com',
  endpoint: '/v1/chat/completions',
  model: 'gpt-3.5-turbo',
  getToken: () => localStorage.getItem('openai_token')
});

通义千问

Vue.use(AIStreamHelper, {
  baseURL: 'https://dashscope.aliyuncs.com',
  endpoint: '/api/v1/services/aigc/text-generation/generation',
  model: 'qwen-turbo',
  getToken: () => localStorage.getItem('qwen_token')
});

自定义服务

Vue.use(AIStreamHelper, {
  baseURL: 'https://your-api.com',
  endpoint: '/api/chat',
  model: 'your-model',
  getToken: () => store.state.token,
  headers: {
    'X-Custom-Header': 'value'
  }
});

📝 SSE 响应格式

插件期望的 SSE 响应格式:

data:{"choices":[{"delta":{"role":"assistant","content":"Hello"}}],"model":"qwen-turbo"}

data:{"choices":[{"delta":{"content":" World"}}]}

data:{"choices":[{"finishReason":"stop"}]}

data:[DONE]

⚠️ 注意事项

  1. Token 管理:确保 getToken 函数能正确返回有效的认证 Token
  2. 请求取消:建议在组件销毁时调用 abort() 避免内存泄漏
  3. 错误处理:始终提供 onError 回调处理异常情况
  4. CORS 配置:确保后端服务器正确配置 CORS 头

🤝 贡献

欢迎提交 Issue 和 Pull Request!

  1. Fork 本仓库
  2. 创建特性分支 (git checkout -b feature/AmazingFeature)
  3. 提交更改 (git commit -m 'Add some AmazingFeature')
  4. 推送到分支 (git push origin feature/AmazingFeature)
  5. 开启 Pull Request

📄 许可证

MIT License © 2025

🙏 致谢

感谢所有贡献者!


如果这个项目对您有帮助,请给一个 ⭐️ Star!

About

一个用于纯 Javascript的AI流式响应处理工具,支持SSE (Server-Sent Events) 流式调用,可支持 Vue、React。

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors