首页 > 其他分享 >vue通过ollama接口调用开源模型

vue通过ollama接口调用开源模型

时间:2024-11-09 15:20:01浏览次数:3  
标签:vue const 开源 length result error msg message ollama

先展示下最终效果:

 第一步:先安装ollama,并配置对应的开源大模型。

安装步骤可以查看上一篇博客:

ollama搭建本地ai大模型并应用调用

 第二步:需要注意两个配置,页面才可以调用 1)OLLAMA_HOST= "0.0.0.0:11434" 2)若应用部署服务器后想调用,需要配置:OLLAMA_ORIGINS=*   第三步:js流式调用大模型接口方法
async startStreaming(e) {
      if(e.ctrkey&&e.keyCode==13){
        this.form.desc+='\n';
      }
      document.getElementById("txt_suiwen").disabled="true";
      // 如果已经有一个正在进行的流式请求,则中止它
      if (this.controller) {
        this.controller.abort();
      }

      setTimeout(()=>{
        this.scrollToBottom();
       },50);
        var mymsg=this.form.desc.trim(); 
        if(mymsg.length>0){
               this.form.desc='';
               this.message.push({
                   user:this.username,
                   msg:mymsg
               })           
               this.message.push({
                       user:'GPT', 
                       msg:'',
                       dot:''
               });
        
             // 创建一个新的 AbortController 实例
             this.controller = new AbortController();
             const signal = this.controller.signal;
             this.arequestData.messages.push({role:"user",content:mymsg});

             try {
               const response = await fetch('http://127.0.0.1:11434/api/chat', {
                 method: 'POST',
                 headers: {
                   'Content-Type': 'application/json'
                 },
                 body:JSON.stringify(this.arequestData),
                 signal
               });
       
               if (!response.body) {
                 this.message[this.message.length-1].msg='ReadableStream not yet supported in this browser.';
                 throw new Error('ReadableStream not yet supported in this browser.');
               }
       
               const reader = response.body.getReader();
               const decoder = new TextDecoder();
               let result = '';
               this.message[this.message.length-1].dot='⚪';
               while (true) {
                 const { done, value } = await reader.read();
                 if (done) {
                   break;
                 }
                 result += decoder.decode(value, { stream: true });
        
                 // 处理流中的每一块数据,这里假设每块数据都是完整的 JSON 对象
                 const jsonChunks = result.split('\n').filter(line => line.trim());
                 //console.log(result)
                 for (const chunk of jsonChunks) {
                   try {
                     const data = JSON.parse(chunk);
                     //console.log(data.message.content) 
                     this.message[this.message.length-1].msg+=data.message.content;
                     setTimeout(()=>{
                       this.scrollToBottom();
                      },50); 
                   } catch (e) {
                     //this.message[this.message.length-1].msg=e;
                     // 处理 JSON 解析错误
                     //console.error('Failed to parse JSON:', e);
                   }
                 }
       
                 // 清空 result 以便处理下一块数据
                 result = '';
               }
             } catch (error) {
               if (error.name === 'AbortError') {
                 console.log('Stream aborted');
                 this.message[this.message.length-1].msg='Stream aborted';
               } else {
                 console.error('Streaming error:', error);
                 this.message[this.message.length-1].msg='Stream error'+error;
               }
             }
             this.message[this.message.length-1].dot='';
             this.arequestData.messages.push({
                     role: 'assistant',//this.message[this.message.length-1].user,//"GPT",
                     content: this.message[this.message.length-1].msg
                   })
             setTimeout(()=>{
                this.scrollToBottom();
               },50); 
               
    }else{
          this.form.desc='';
        }
        document.getElementById("txt_suiwen").disabled="";
        document.getElementById("txt_suiwen").focus();
    }  
  }

 

vue完整代码如下:
<template> 
  <el-row :gutter="12" class="demo-radius">
    <div
        class="radius"
        :style="{
          borderRadius: 'base'
        }">
        <div class="messge" id="messgebox"  ref="scrollDiv"> 
            <ul>
  <li v-for="(item, index) in message" :key="index" style="list-style-type:none;">
    <div v-if="item.user == username" class="mymsginfo" style="float:right">
        <div>
          <el-avatar style="float: right;margin-right: 30px;background: #01bd7e;">  
            <!-- {{ item.user.substring(0, 2) }}   -->
            <img :alt="item.user.substring(0, 2)" :src=userphoto /> 
          </el-avatar>  
    </div><div style="float: right;margin-right: 10px;margin-top:10px;width:80%;text-align: right;"> {{ item.msg }} </div> 
     </div>
     <div v-else class="chatmsginfo" >
        <div>
        <el-avatar style="float: left;margin-right: 10px;">  {{ item.user }}  </el-avatar> 
    </div>
      <div style="float: left;margin-top:10px;width:80%;">
        <img alt="loading" v-if="item.msg == ''" class="loading" src="../../assets/loading.gif"/>
        <MdPreview style="margin-top:-20px;"  :autoFoldThreshold="9999" :editorId="id" :modelValue=" item.msg + item.dot  " />
        <!-- {{ item.msg }} -->
        </div> 
      </div>
  </li>
</ul>
        </div>
        <div class="inputmsg">
            <el-form :model="form" >
                <el-form-item > 
                   <el-avatar style="float: left;background: #01bd7e;margin-bottom: -44px;margin-left: 4px;z-index: 999;width: 30px;height: 30px;">  
                     <img alt="jin" :src=userphoto /> 
                    </el-avatar>  
                    <el-input id="txt_suiwen" :prefix-icon="userphoto" resize="none"  autofocus="true"  :autosize="{ minRows: 1, maxRows: 2 }" v-model="form.desc"  placeholder="说说你想问点啥....按Enter键可直接发送" @keydown.enter.native.prevent="startStreaming($event)" type="textarea" />
                </el-form-item>
            </el-form>
        </div>
      </div>    
  </el-row>

</template>
<script setup>
import { MdPreview, MdCatalog } from 'md-editor-v3';
import 'md-editor-v3/lib/preview.css';

const id = 'preview-only';
</script>
<script>   
export default {
  data() {
    return {
      form: {
        desc: ''
      },
      message:[],
      username:sessionStorage.name,
      userphoto:sessionStorage.photo,
      loadingtype:false, 
      controller: null, 
      arequestData : {
          model: "qwen2",//"llama3.1",
          messages: []
      }
    }
  },
  mounted() { 
  },
  methods: {
    scrollToBottom() {
        let elscroll=this.$refs["scrollDiv"];
        elscroll.scrollTop = elscroll.scrollHeight+30
       
    }, 
    clearForm(formName){
      this.form.desc='';
    }, 
    async startStreaming(e) {
      if(e.ctrkey&&e.keyCode==13){
        this.form.desc+='\n';
      }
      document.getElementById("txt_suiwen").disabled="true";
      // 如果已经有一个正在进行的流式请求,则中止它
      if (this.controller) {
        this.controller.abort();
      }

      setTimeout(()=>{
        this.scrollToBottom();
       },50);
        var mymsg=this.form.desc.trim(); 
        if(mymsg.length>0){
               this.form.desc='';
               this.message.push({
                   user:this.username,
                   msg:mymsg
               })           
               this.message.push({
                       user:'GPT', 
                       msg:'',
                       dot:''
               });
        
             // 创建一个新的 AbortController 实例
             this.controller = new AbortController();
             const signal = this.controller.signal;
             this.arequestData.messages.push({role:"user",content:mymsg});

             try {
               const response = await fetch('http://127.0.0.1:11434/api/chat', {
                 method: 'POST',
                 headers: {
                   'Content-Type': 'application/json'
                 },
                 body:JSON.stringify(this.arequestData),
                 signal
               });
       
               if (!response.body) {
                 this.message[this.message.length-1].msg='ReadableStream not yet supported in this browser.';
                 throw new Error('ReadableStream not yet supported in this browser.');
               }
       
               const reader = response.body.getReader();
               const decoder = new TextDecoder();
               let result = '';
               this.message[this.message.length-1].dot='⚪';
               while (true) {
                 const { done, value } = await reader.read();
                 if (done) {
                   break;
                 }
                 result += decoder.decode(value, { stream: true });
                 // 处理流中的每一块数据,这里假设每块数据都是完整的 JSON 对象
                 const jsonChunks = result.split('\n').filter(line => line.trim());
                 //console.log(result)
                 for (const chunk of jsonChunks) {
                   try {
                     const data = JSON.parse(chunk);
                     //console.log(data.message.content) 
                     this.message[this.message.length-1].msg+=data.message.content;
                     setTimeout(()=>{
                       this.scrollToBottom();
                      },50); 
                   } catch (e) {
                     //this.message[this.message.length-1].msg=e;
                     // 处理 JSON 解析错误
                     //console.error('Failed to parse JSON:', e);
                   }
                 }
                 // 清空 result 以便处理下一块数据
                 result = '';
               }
             } catch (error) {
               if (error.name === 'AbortError') {
                 console.log('Stream aborted');
                 this.message[this.message.length-1].msg='Stream aborted';
               } else {
                 console.error('Streaming error:', error);
                 this.message[this.message.length-1].msg='Stream error'+error;
               }
             }
             this.message[this.message.length-1].dot='';
             this.arequestData.messages.push({
                     role: 'assistant',//this.message[this.message.length-1].user,//"GPT",
                     content: this.message[this.message.length-1].msg
                   })
             setTimeout(()=>{
                this.scrollToBottom();
               },50); 
               
    }else{
          this.form.desc='';
        }
        document.getElementById("txt_suiwen").disabled="";
        document.getElementById("txt_suiwen").focus();
    }  
  },
  beforeDestroy() {
    // 组件销毁时中止流式请求
    if (this.controller) {
      this.controller.abort();
    }
  }
}
</script>
<style scoped>
.radius{
  margin:0 auto;
}
.demo-radius .title {
  color: var(--el-text-color-regular);
  font-size: 18px;
  margin: 10px 0;
}
.demo-radius .value {
  color: var(--el-text-color-primary);
  font-size: 16px;
  margin: 10px 0;
}
.demo-radius .radius {
  min-height: 580px;
  height: 85vh;
  width: 70%;
  border: 1px solid var(--el-border-color);
  border-radius: 14px;
  margin-top: 10px;
}
.messge{
    width:96%;
    height:84%;
    /* border:1px solid red; */
    margin: 6px auto;
    overflow: hidden;
    overflow-y: auto;
}
.inputmsg{
    width:96%;
    height:12%;
    /* border:1px solid blue; */
    border-top:2px solid #ccc;
    margin: 4px auto;
    padding-top: 10px;
}
.mymsginfo{
    width:100%;
    height:auto;
    min-height:50px;
}


::-webkit-scrollbar {width: 6px;height: 5px;
}
::-webkit-scrollbar-track {background-color: rgba(0, 0, 0, 0.2);border-radius: 10px;
}
::-webkit-scrollbar-thumb {background-color: rgba(0, 0, 0, 0.5);border-radius: 10px;
}
::-webkit-scrollbar-button {background-color: #7c2929;height: 0;width: 0px;
}
::-webkit-scrollbar-corner {background-color: black;
} 

</style>
<style>
.el-textarea__inner{
  padding-left: 45px;
  padding-top: .75rem;
  padding-bottom: .75rem;
}
</style>

 

   

 

标签:vue,const,开源,length,result,error,msg,message,ollama
From: https://www.cnblogs.com/ggtop/p/18536834

相关文章

  • 基于nodejs+vue只租不卖汽车租赁平台[开题+源码+程序+论文]计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景关于汽车租赁平台的研究,现有研究主要以传统的汽车租赁业务模式为主,包括租赁流程、市场规模、竞争格局等方面的分析。专门针对只租不卖这种特殊运营模式......
  • 基于nodejs+vue职业信息交流平台[开题+源码+程序+论文]计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景随着信息技术的飞速发展,职业信息的交流与传播变得日益重要。关于职业信息交流平台的研究,现有研究主要以信息传播的一般性理论为主,专门针对职业信息交流......
  • 基于SpringBoot+Vue的巨会玩剧本杀服务平台管理系统(源码+LW+调试文档+讲解)
    项目简介基于SpringBoot+Vue的巨会玩剧本杀服务平台管理系统是专为剧本杀行业打造的高效管理系统。对于玩家而言,可在平台浏览丰富的剧本信息,包括剧本类型(如悬疑、古风、情感等)、难度级别、人数要求、时长等。玩家能在线预订场次、选择喜欢的DM(主持人),还可查看评价。......
  • 基于SpringBoot+Vue的就医信息管理系统(源码+LW+调试文档+讲解)
    项目简介基于SpringBoot+Vue的就医信息管理系统为就医流程和医院管理带来便利。患者可预约挂号,查看科室与医生信息、排班情况并在线支付挂号费,就医时能查询检查检验结果,病历也能存储和查询。医院工作人员通过该系统管理患者信息、医生排班和科室资源,实现诊疗流程电子......
  • 基于SpringBoot+Vue的旧时光咖啡厅管理系统(源码+LW+调试文档+讲解)
    项目简介基于SpringBoot+Vue的旧时光咖啡厅管理系统是专为咖啡厅运营打造的高效管理工具。对于咖啡厅员工,系统可用于管理桌位信息,实时查看空闲与已占用桌位,方便为顾客安排就座。能处理点餐流程,记录顾客所点饮品、食物信息并传至厨房和吧台。同时,支持收银功能,计算订......
  • 基于SpringBoot+Vue的酒店预定系统(源码+LW+调试文档+讲解)
    项目简介基于SpringBoot+Vue的酒店预订系统是一个功能全面的应用。用户可通过系统搜索酒店,查看酒店的详细信息,包括不同房型(如单人房、双人房、家庭房等)的介绍、价格范围、配备的设施(像电视、空调、独立卫浴等)以及酒店周边的餐饮、娱乐、交通情况。用户能自由选择入......
  • Vue功能菜单的异步加载、动态渲染
            实际的Vue应用中,常常需要提供功能菜单,例如:文件下载、用户注册、数据采集、信息查询等等。每个功能菜单项,对应某个.vue组件。下面的代码,提供了一种独特的异步加载、动态渲染功能菜单的构建方法:<scriptsetup>import{defineComponent,getCurrentInstance,h}......
  • 【让中国再次伟大】腾讯开源大语言模型Hunyuan-large,支持高达256K文本序列
    腾讯今日发布开源MOE大语言模型Hunyuan-large,总参数量达398B,激活参数量52B。公开测评结果显示,腾讯混元Large在CMMLU、MMLU、CEva1、MATH等多学科综合评测集以及中英文NLP任务、代码和数学等9大维度全面领先,超过Llama3.1、Mixtral等一流的开源大模型。随着人工智能技术的飞......
  • Vue3.5新增的baseWatch让watch函数和Vue组件彻底分手
    Vue3.5版本中新增的`baseWatch`函数确实让`watch`函数与Vue组件彻底分手。这一变化的主要目的是使`watch`函数的实现与Vue组件及其生命周期解耦,从而使得`watch`函数更加灵活和独立。具体来说,`baseWatch`函数的引入使得开发者可以在不依赖Vue组件的情况下使用`watch`功能,这为......
  • Vue3 - 详细实现将多个文件批量导出为ZIP压缩包格式并下载功能,vue3将文件批量下载打包
    前言Vue2版本,请访问这篇文章。在vue3|nuxt3项目开发中,详解实现把多个文件组合成一个ZIP压缩包格式下载到用户本地,将文件批量下载打包成zip格式并自定义压缩包命名名称,vue3批量下载文件并导出为压缩包的功能,如何将后端返回的二进制文件流打包成zip格式,支持任意文件......