最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue通過(guò)ollama接口調(diào)用開源模型實(shí)現(xiàn)人機(jī)對(duì)話功能

 更新時(shí)間:2024年11月11日 09:41:17   作者:小G同學(xué)  
文章介紹了如何在本地安裝ollama并配置開源大模型,以及如何通過(guò)JavaScript和Vue.js實(shí)現(xiàn)人機(jī)對(duì)話功能,感興趣的朋友一起看看吧

先展示下最終效果:

第一步:先安裝ollama,并配置對(duì)應(yīng)的開源大模型。

安裝步驟可以查看上一篇博客:

ollama搭建本地ai大模型并應(yīng)用調(diào)用

第二步:需要注意兩個(gè)配置,頁(yè)面才可以調(diào)用

1)OLLAMA_HOST= "0.0.0.0:11434"

2)若應(yīng)用部署服務(wù)器后想調(diào)用,需要配置:OLLAMA_ORIGINS=*

第三步:js流式調(diào)用大模型接口方法

async startStreaming(e) {
      if(e.ctrkey&&e.keyCode==13){
        this.form.desc+='\n';
      }
      document.getElementById("txt_suiwen").disabled="true";
      // 如果已經(jīng)有一個(gè)正在進(jìn)行的流式請(qǐng)求,則中止它
      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:''
               });
             // 創(chuàng)建一個(gè)新的 AbortController 實(shí)例
             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 });
                 // 處理流中的每一塊數(shù)據(jù),這里假設(shè)每塊數(shù)據(jù)都是完整的 JSON 對(duì)象
                 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 解析錯(cuò)誤
                     //console.error('Failed to parse JSON:', e);
                   }
                 }
                 // 清空 result 以便處理下一塊數(shù)據(jù)
                 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="說(shuō)說(shuō)你想問(wèn)點(diǎn)啥....按Enter鍵可直接發(fā)送" @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";
      // 如果已經(jīng)有一個(gè)正在進(jìn)行的流式請(qǐng)求,則中止它
      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:''
               });
             // 創(chuàng)建一個(gè)新的 AbortController 實(shí)例
             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 });
                 // 處理流中的每一塊數(shù)據(jù),這里假設(shè)每塊數(shù)據(jù)都是完整的 JSON 對(duì)象
                 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 解析錯(cuò)誤
                     //console.error('Failed to parse JSON:', e);
                   }
                 }
                 // 清空 result 以便處理下一塊數(shù)據(jù)
                 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() {
    // 組件銷毀時(shí)中止流式請(qǐng)求
    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>

到此這篇關(guān)于vue通過(guò)ollama接口調(diào)用開源模型實(shí)現(xiàn)人機(jī)對(duì)話的文章就介紹到這了,更多相關(guān)vue ollama接口人機(jī)對(duì)話內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Vue-Router如何動(dòng)態(tài)更改當(dāng)前頁(yè)url query

    Vue-Router如何動(dòng)態(tài)更改當(dāng)前頁(yè)url query

    這篇文章主要介紹了Vue-Router如何動(dòng)態(tài)更改當(dāng)前頁(yè)url query問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • 解決vant的Cascader級(jí)聯(lián)選擇組建css樣式錯(cuò)亂問(wèn)題

    解決vant的Cascader級(jí)聯(lián)選擇組建css樣式錯(cuò)亂問(wèn)題

    這篇文章主要介紹了解決vant的Cascader級(jí)聯(lián)選擇組建css樣式錯(cuò)亂問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • Vue 3 響應(yīng)式系統(tǒng)中ref 在 reactive 中的自動(dòng)解包行為解析

    Vue 3 響應(yīng)式系統(tǒng)中ref 在 reactive 中的自動(dòng)解包行為

    Vue3中,ref與reactive配合使用時(shí)會(huì)自動(dòng)解包,使代碼更簡(jiǎn)潔,響應(yīng)式系統(tǒng)更智能,替換ref會(huì)斷開舊連接,淺層reactive/shallowRef不觸發(fā)解包,但是需注意區(qū)分,下面通過(guò)示例給大家介紹Vue3響應(yīng)式探秘:ref 在reactive中的自動(dòng)解包行為解析,感興趣的朋友一起看看吧
    2025-07-07
  • Vue3手機(jī)外觀組件庫(kù)超詳細(xì)代碼示例

    Vue3手機(jī)外觀組件庫(kù)超詳細(xì)代碼示例

    vue作為一款深受廣大群眾喜歡的前端框架,擁有眾多優(yōu)秀的開源UI組件庫(kù),這篇文章主要介紹了Vue3手機(jī)外觀組件庫(kù)的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2026-05-05
  • Vue+Element實(shí)現(xiàn)表格編輯、刪除、以及新增行的最優(yōu)方法

    Vue+Element實(shí)現(xiàn)表格編輯、刪除、以及新增行的最優(yōu)方法

    這篇文章主要為大家詳細(xì)介紹了Vue+Element實(shí)現(xiàn)表格的編輯、刪除、以及新增行的最優(yōu)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • vue el-table實(shí)現(xiàn)遞歸嵌套的示例代碼

    vue el-table實(shí)現(xiàn)遞歸嵌套的示例代碼

    本文主要介紹了vue el-table實(shí)現(xiàn)遞歸嵌套的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • Vue結(jié)合Element-Plus封裝遞歸組件實(shí)現(xiàn)目錄示例

    Vue結(jié)合Element-Plus封裝遞歸組件實(shí)現(xiàn)目錄示例

    本文主要介紹了Vue結(jié)合Element-Plus封裝遞歸組件實(shí)現(xiàn)目錄示例,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • vue 1.0 結(jié)合animate.css定義動(dòng)畫效果

    vue 1.0 結(jié)合animate.css定義動(dòng)畫效果

    本文分步驟給大家介紹了Vue 1.0自定義動(dòng)畫效果,vue1.0代碼結(jié)合animate.css定義動(dòng)畫,頁(yè)面一定要引入animate.cdd,具體實(shí)例代碼大家參考下本文
    2018-07-07
  • Vue3中Composition?API和Options?API的區(qū)別

    Vue3中Composition?API和Options?API的區(qū)別

    Vue3的Composition API和Options API是Vue.js框架中的兩種不同的API,本文主要介紹了Vue3中Composition?API和Options?API的區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • vue中v-bind與v-model的區(qū)別舉例詳解

    vue中v-bind與v-model的區(qū)別舉例詳解

    這篇文章主要給大家介紹了關(guān)于vue中v-bind與v-model區(qū)別的相關(guān)資料,v-model和v-bind是Vue.js框架中的兩個(gè)常用指令,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-09-09

最新評(píng)論

武清区| 济阳县| 双辽市| 万宁市| 壶关县| 道真| 津南区| 涞源县| 鹿泉市| 门源| 云龙县| 娄底市| 许昌县| 黄冈市| 通山县| 迁安市| 屏山县| 柘荣县| 稷山县| 肇庆市| 吕梁市| 察哈| 玉林市| 义乌市| 普安县| 天长市| 达孜县| 蒙城县| 萨嘎县| 涞水县| 宿州市| 临朐县| 西林县| 易门县| 汽车| 咸宁市| 巧家县| 莎车县| 秦皇岛市| 城口县| 香格里拉县|