ollama+springboot ai+vue+elementUI整合

1. 下载安装ollama

(1) 官网下载地址:https://github.com/ollama/ollama

这里以window版本为主,下载链接为:https://ollama.com/download/OllamaSetup.exe。

安装完毕后,桌面小图标有一个小图标,表示已安装成功,安装完毕后,首先改变环境变量,打开系统环境变量,设置如下:

OLLAMA_HOST: 0.0.0.0
OLLAMA_MODELS: D:\ai-models (这个目录需要提前创建好,目录名任意)

在这里,OLLAMA_HOST参数是为了跨域访问,方便第三方应用通过http请求访问。OLLAMA_MODELS参数为了改变模型下载地址,默认目录为C:\Users\<用户名>\.ollama\models。

接着,我们拉一个大模型,这里以阿里qwen2.5为例,更多模型可以从Ollama网站查询。打开命令行执行下面的命令:

ollama run qwen2.5

如果没有模型,首先自动尝试拉镜像,如果需要手动拉取镜像,执行ollama pull qwen2.5命令。上述命令执行完毕后,我们就可以直接使用大模型。

2. curl命令请求数据

Api详细文档: https://github.com/ollama/ollama/blob/main/docs/api.md

gitbash对curl命令支持并不好,下面的命令用win11的bash窗口或者用linux窗口执行这些命令。

(1)

curl http://localhost:11434/api/chat -d '{"model": "qwen2.5","messages": [{"role": "user","content": "天空为什么是蓝色的?"}]
}'

(2)

curl http://localhost:11434/api/chat -d '{"model": "qwen2.5","stream":false,"messages": [{"role": "user","content": "天空为什么是蓝色的?"}]
}'

(3)

curl http://localhost:11434/api/generate -d '{"model": "qwen2.5","prompt": "你是谁?"
}'

(4)

curl http://localhost:11434/api/generate -d '{"model": "qwen2.5","prompt": "你是谁?","stream": false
}'

3. Springboot集成

(1) 首先打开https://start.spring.io/网站,填写如下必要信息。这里要注意,不要使用springboot2.x。我们需要使用springboot3.x.

(2) 用Eclipse或者idea导入项目,首先配置application.yml,内容如下:

server:port: 9999
spring:ai:ollama:base-url: http://localhost:11434chat:options:model: qwen2.5

(3) 接下来我们需要配置跨域设置,新建一个类CorsConfig,写入如下内容:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class CorsConfig implements WebMvcConfigurer {@Beanpublic WebMvcConfigurer corsConfigurer() {return new WebMvcConfigurer() {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOriginPatterns("*").allowedMethods("*").allowedHeaders("*").allowCredentials(true).exposedHeaders(HttpHeaders.SET_COOKIE).maxAge(3600L);}};}
}

(4) 编写controller类,定义OllamaClientController类,写入如下内容:

import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;@RestController
@RequestMapping("/ollama")
public class OllamaClientController {@Autowiredprivate OllamaChatModel ollamaChatModel;// http://localhost:9999/ollama/chat/v1?msg=天空为什么是蓝色的?@GetMapping("/chat/v1")public String ollamaChat(@RequestParam String msg) {return ollamaChatModel.call(msg);}// http://localhost:9999/ollama/chat/v2?msg=天空为什么是蓝色的?@GetMapping("/chat/v2")public Flux<String> ollamaChat2(@RequestParam String msg) {Flux<String> stream = ollamaChatModel.stream(msg);return stream;}
}

(5) 接着启动项目,打开浏览器输入: http://localhost:9999/ollama/chat/v2?msg=天空为什么是蓝色的?, 会看到如下图信息,这里中文虽然乱码,但是不影响后续前端开发。

4. 前端页面开发

(1)这里采用Vue+ElementUI开发,首先需要创建一个vue项目。Vue项目整合ElementUI参考Element - The world's most popular Vue UI framework。将实现如下图所示的效果图:

(2) 优先采用流式数据返回,因为它响应速度较快,并且由于restful返回的结果是md格式的数据,所以,首先集成对md的支持。

首先,项目需要增加如下依赖:

npm i vue-markdown-loader
npm i vue-loader
npm i vue-template-compiler
npm i github-markdown-css
npm i highlight.js
npm i markdown-loader
npm i html-loader
npm i marked

安装完成后,还需要做一些配置,首先配置vue.config文件,增加如下内容:

const { defineConfig } = require('@vue/cli-service')
const path = require("path");
module.exports = defineConfig({transpileDependencies: true,devServer: {port: 8932, // 端口client: {overlay: false,},},configureWebpack: {module: {rules: [// 配置读取 *.md 文件的规则{test: /\.md$/,use: [{ loader: "html-loader" },{ loader: "markdown-loader", options: {} }]}]}}
})

之后,我们需要在main.js中配置参数,增加如下内容:

import 'element-ui/lib/theme-chalk/index.css';
// markdown样式
import "github-markdown-css";
// 代码高亮
import "highlight.js/styles/github.css"; //默认样式

接着启动项目,如果项目启动失败,删除package-lock.json文件和node_modules目录,执行npm install,然后启动项目。

接着增加QuestionItem.vue组件,内容如下:

<template><div class="question-warp"><div><el-avatar size="small" src="images/user-icon.jpg"></el-avatar></div><div class="question-content">{{ value }}</div></div>
</template>
<script>
export default {name: 'QuestionItem',props: {value: String,},data() {return {}},methods: {}
}
</script>
<style scoped>.question-warp {display: flex;
}.question-content {margin: 5px;line-height: 25px;text-align: justify;width: 100%;background-color: rgb(249, 246, 243);border-radius: 10px;padding: 10px;
}
</style>

接着增加一个AnswerItem.vue组件,内容如下:

<template><div class="answer-warp"><div class="answer-content"><div  v-html="value" class="markdown-body"></div></div><div><el-avatar size="small" src="images/ai-icon.jpg"></el-avatar></div></div>
</template>
<script>
export default {name: 'AnswerItem',props: {value: String,},data() {return {}},methods: {}
}
</script>
<style scoped>
.answer-warp {display: flex;
}
.markdown-body{background-color: rgb(223, 241, 249);
}
.answer-content {margin: 5px;line-height: 25px;width: 100%;text-align: justify;background-color: rgb(223, 241, 249);border-radius: 10px;padding: 10px;
}
</style>

以上两个组件分别是问题和答案的组件,所以接下来增加CustomerService.vue组件,内容如下:

<template><div><div class="title"><span style="color: red;">AI</span>智能客服为您服务</div><div class="content"><template v-for="item in data"><question-item v-if="item.question !== ''" :value="item.question" /><answer-item v-if="item.answer !== ''" :value="item.answer" /></template></div><div class="textarea-container"><el-input type="textarea" resize='none' placeholder="请输入内容" v-model="questionInputValue" :rows="6"class="custom-textarea"></el-input><el-button :disabled="submitButtonDisabled" type="primary" class="submit-button" @click="handleSubmit">提交</el-button></div></div>
</template>
<script>
import QuestionItem from "@/components/QuestionItem.vue";
import AnswerItem from "@/components/AnswerItem.vue";
import { marked } from 'marked'
export default {name: 'CustomerService',components: {'question-item': QuestionItem,'answer-item': AnswerItem},data() {return {question: '',submitButtonDisabled: false,questionInputValue: '',data: []}},methods: {async handleSubmit() {// 处理提交逻辑console.log('提交的内容:', this.questionInputValue);if (this.questionInputValue.trim() === '') {this.$message({type: "error",message: "你没有输入内容哦"})} else {this.question = this.questionInputValuethis.submitButtonDisabled = truethis.data.push({question: this.question,answer: '正在思考中...'})this.questionInputValue = ''try {// 发送请求let response = await fetch("http://localhost:9999/api/ollama/chat/v2?msg=" + this.question,{method: "get",responseType: "stream",});// ok字段判断是否成功获取到数据流if (!response.ok) {throw new Error("Network response was not ok");}// 用来获取一个可读的流的读取器(Reader)以流的方式处理响应体数据const reader = response.body.getReader();// 将流中的字节数据解码为文本字符串const textDecoder = new TextDecoder();let result = true;let answer = ''while (result) {// done表示流是否已经完成读取value包含读取到的数据块const { done, value } = await reader.read();if (done) {result = false;this.submitButtonDisabled = falsebreak;}answer += textDecoder.decode(value);this.$set(this.data, this.data.length - 1, {question: this.question,answer: marked(answer)});}} catch (err) {console.log("发生错误:", err)}}}}
}
</script>
<style scoped>
.title {text-align: center;font-size: larger;font-weight: bold;
}
.content {height: 460px;overflow-y: auto;
}
.question {border: 2px solid salmon;border-radius: 10px;
}
.textarea-container {position: relative;display: flex;flex-direction: column;
}
.custom-textarea {/* 为按钮留出空间 */box-sizing: border-box;/* 确保内边距不会增加元素的总宽度 */
}
.submit-button {position: absolute;bottom: 10px;/* 根据需要调整 */right: 10px;/* 根据需要调整 */z-index: 1;/* 确保按钮在文本域之上 */
}
</style>

之后我们在父组件调用该组件,即可,父组件示例代码如下:

…<el-drawer :visible.sync="customerService" :with-header="false" direction="rtl" size="45%"><div style="padding-left: 10px;padding-right:10px;"><customer-service /></div>
</el-drawer>
…
import CustomerService from "@/components/CustomerService.vue";
export default {name: "xxxx",components: {"customer-service": CustomerService},…
}
参考文档

1.ollama官网: Ollama

2. 报错 - 使用marked报错 marked__WEBPACK_IMPORTED_MODULE_4___default(...) is not a function_marked is not a function-CSDN博客

3.ollama readme : https://github.com/ollama/ollama?tab=readme-ov-file

4.vue中展示、读取.md 文件的方法(批量引入、自定义代码块高亮样式)_vue.js_脚本之家

5.在vue中解析md文档并显示-腾讯云开发者社区-腾讯云  

6.axios设置 responseType为 “stream“流式获取后端数据_axios stream-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/59648.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WPF 应用程序中使用 Prism 框架时,有多种方式可以注册服务和依赖项

Prism 提供了更多的注册方式&#xff0c;适应不同的需求和场景。下面我会全面列出 IContainerRegistry 提供的所有常见注册方式&#xff0c;并附带相应的示例。1. 注册单例&#xff08;Singleton&#xff09; 注册单例类型服务&#xff0c;整个应用生命周期内只会创建一个实例&…

基于lighthouse搭建私有网盘Cloudreve【开源应用实践】

基于lighthouse搭建私有网盘Cloudreve【超高性价比】 今天给大家分享一款私人网盘神器&#xff0c;既能存放你的文件文档&#xff0c;也能替你保存那不可告人的秘密~ 香菇今天将手把手教给大家如何在腾讯云轻量应用服务器上搭建个人专属网盘 1. 既爱又恨的网盘存储 很多小伙伴…

vue项目PC端和移动端实现在线预览docx、excel、pdf文件

可以参考vue-office官方github&#xff1a;​​​​​​​GitHub - loonghe/vue-office: 支持word(.docx)、excel(.xlsx,.xls)、pdf等各类型office文件预览的vue组件集合&#xff0c;提供一站式office文件预览方案&#xff0c;支持vue2和3&#xff0c;也支持React等非Vue框架。…

【CSS问题】margin塌陷

CSS中的margin塌陷是一个常见的布局问题&#xff0c;主要发生在垂直方向上&#xff0c;当两个或多个元素的垂直margin相遇时&#xff0c;它们不会按照预期叠加&#xff0c;而是会发生重叠&#xff0c;导致最终的外边距值比单独设置时小。 一、margin塌陷的原因 同级元素&#…

JavaScript高级篇 - 浏览器事件详解 DOM事件以及独立封装事件Util和Ajax封装

Dom事件 Model&#xff08;特定领域对象的抽象&#xff09;、Protocal&#xff08;针对数据格式的约定&#xff09; DOM(Document Object Model&#xff0c;文档对象模型)是针对HTML文档和XML文档的一个API。DOM描绘了一个层次化的节点树&#xff0c;允许开发人员添加、移出和…

MinIO 的 S3 over RDMA 计划: 为高速人工智能数据基础设施设定对象存储新标准

随着 AI 和机器学习的需求不断加速&#xff0c;数据中心网络正在迅速发展以跟上步伐。对于许多企业来说&#xff0c;400GbE 甚至 800GbE 正在成为标准选择&#xff0c;因为数据密集型和时间敏感型 AI 工作负载需要高速、低延迟的数据传输。用于大型语言处理、实时分析和计算机视…

git config是做什么的?

git config是做什么的&#xff1f; git config作用配置级别三种配置级别的介绍及使用&#xff0c;配置文件说明 使用说明git confi查看参数 默认/不使用这个参数 情况下 Git 使用哪个配置等级&#xff1f; 一些常见的行为查看配置信息设置配置信息删除配置信息 一些常用的配置信…

电能表预付费系统-标准传输规范(STS)(41)

7.3.7 TokenValidation Class 0 and Class 2 tokens shall primarily be validated against the TID encoded in the token, except for key change token set. 除密钥更改令牌集外&#xff0c;类别0和类别2令牌应主要针对令牌中编码的TID进行验证。 Key change tokens are va…

使用 npm 安装 Yarn

PS E:\WeChat Files\wxid_fipwhzebc1yh22\FileStorage\File\2024-11\spid-admin\spid-admin> yarn install yarn : 无法将“yarn”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写&#xff0c;如果包括路径&#xff0c;请确保路径正确&#xff0c;然后…

51单片机使用NRF24L01进行2.4G无线通信

本文并不打算详细介绍NRF24L01的各个功能寄存器及指令的详细用法&#xff0c;因为网上都可以搜到很多非常详细的教程文档&#xff0c;这里只是介绍一些基本概念、用法以及代码的解释&#xff0c;旨在帮助新手能够快速上手调通快速使用。 基础概念 该模块使用的是SPI协议&…

python怎么加锁

在Python中&#xff0c;加锁是一种常见的线程同步机制&#xff0c;用于防止多个线程同时访问共享资源&#xff0c;从而避免数据竞争和不一致的问题。Python提供了多种方式来实现加锁&#xff1a; 1. threading模块的Lock threading.Lock是最基本的锁机制&#xff0c;它允许一…

常用在汽车PKE无钥匙进入系统的高度集成SOC芯片:CSM2433

CSM2433是一款集成2.4GHz频段发射器、125KHz接收器和8位RISC&#xff08;精简指令集&#xff09;MCU的SOC芯片&#xff0c;用在汽车PKE无钥匙进入系统里。 什么是汽车PKE无钥匙进入系统&#xff1f; 无钥匙进入系统具有无钥匙进入并且启动的功能&#xff0c;英文名称是PKE&…

kafka消费者出现频繁Rebalance

kafka消费者在正常使用过程中&#xff0c;突然出现了不消费消息的情况&#xff0c;项目里是使用了多个消费者消费不同数据&#xff0c;按理不会相互影响&#xff0c;看日志&#xff0c;发现消费者出现了频繁的Rebalance。 Rebalance的触发条件 组成员发生变更(新consumer加入组…

QList和QSet常用操作(查找、插入、排序、交集)

1、QList常用操作&#xff08;查找、插入、排序&#xff09; &#xff08;1&#xff09;QList查找&#xff08;前提&#xff1a;已排序&#xff09; /*[查找val在列表&#xff08;已排序&#xff09;中的位置&#xff0c;返回值范围[-1,0,,size()-1]]*/ int posOf(const QLis…

机器学习基础05

目录 1.随机森林 1.1随机森林的介绍 1.2算法原理 1.3API 2.线性回归 2.1回归的含义 2.2线性回归 2.3损失函数 2.4多参数回归 2.5最小二乘法MSE 2.6API 1.随机森林 集成学习的基本思想就是将多个分类器组合&#xff0c;从而实现一个预测效果更好的集成分类器。 集成…

深度解析 Feign

一、引言 在当今微服务架构盛行的时代&#xff0c;众多微服务相互协作构成了复杂的分布式系统。然而&#xff0c;各个微服务之间的调用往往涉及到诸多繁琐的细节&#xff0c;比如网络请求的构建、参数的处理、响应的解析等。为了让开发人员能够更加专注于业务逻辑的实现&#x…

数据库范式、MySQL 架构、算法与树的深入解析

一、数据库范式 在数据库设计中&#xff0c;范式是一系列规则&#xff0c;用于确保数据的组织和存储具有良好的结构、完整性以及最小化的数据冗余。如果不遵循范式设计&#xff0c;数据可能会以平铺式罗列&#xff0c;仅使用冒号、分号等简单分隔。这种方式存在诸多弊端&#…

iOS swift开发--- 加载PDF文件并显示内容

iOS开发采用pdfkit &#xff0c;可以很方便的读取pdf的内容。以下是简易的显示pdf内容的代码 import UIKit import PDFKitclass ViewController: UIViewController, UIDocumentPickerDelegate {var pdfView: PDFView! //创建一个控件显示内容let selectPDFButton UIButton(ty…

统信操作系统离线安装JDK、Nginx、elasticsearch、kibana、ik、pinyin

第一步&#xff1a;挂载光盘 1、查看设备名称 查看光盘的名称&#xff0c;通常是以 /dev/sr0 或者类似格式显示lsblk 2、创建挂载点并挂载光盘 创建挂载目录sudo mkdir /mnt/cdrom 进行光盘目录挂载&#xff0c;/dev/sr0 要替换为实际查看到的光盘设备名称sudo mount /dev…

Linux服务器下连接kingbase并执行SQL的脚本

Linux服务器上实现通过shell脚本更新数据&#xff08;非信创服务器&#xff09; #!/bin/bash# PostgreSQL 连接信息 HOST"172.16.2.112" DBNAME"bxszf" USER"flexoffice" PASSWORD"123456789"# SQL 更新语句 SQL_QUERY"update f…