2、SpringAI接入ChatGPT與微服務整合

2、SpringAI接入ChatGPT與微服務整合

小薛博客AI 大模型資料

1、SpringAI簡介

https://spring.io/projects/spring-ai

image-20250219110422639

Spring AI是一個人工智能工程的應用框架。其目標是將Spring生態系統的設計原則(如可移植性和模塊化設計)應用于人工智能領域,并推動將POJO作為應用程序的構建塊應用于AI領域。

SpringAI 是一個基于人工智能技術的工具或平臺,通常用于構建、優化和部署AI模型。

  • 簡化AI開發:提供易用的接口和框架,加速AI模型的創建與訓練。

  • 可移植的API支持跨人工智能提供商的聊天,文本到圖像,和嵌入模型。

2、環境要求

<properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><java.version>17</java.version><spring-ai.version>1.0.0-M7</spring-ai.version>
</properties><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency><dependencyManagement><dependencies><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-bom</artifactId><version>${spring-ai.version}</version><type>pom</type><scope>import</scope></dependency></dependencies>
</dependencyManagement>

Java 17 或更高版本

  • Spring AI 和 Spring Boot 3.x 需要 Java 17 或更高版本。確保您的開發環境已安裝并配置了正確的 Java 版本。
  • spring-ai-starter-model-openai 是為 Spring Boot 3.x 設計的,因此需要確保您的項目基于 Spring Boot 3.x。

3、新建工程 xx-ai

一并整合

  • spring-ai
  • mybatis plus
  • knife4j swagger3

1、pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.4.4</version><relativePath/></parent><artifactId>xx-ai</artifactId><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><java.version>17</java.version><spring-ai.version>1.0.0-M7</spring-ai.version><mysql.version>8.0.27</mysql.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-openai</artifactId></dependency><dependency><groupId>com.xx</groupId><artifactId>xx-common-core</artifactId><version>1.7.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- mybatis-plus-spring-boot3-starter --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>3.5.7</version></dependency><!--SpringBoot集成druid連接池druid-spring-boot-starter --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.23</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.version}</version></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-bom</artifactId><version>${spring-ai.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement></project>

2、application.yml

server:port: 8001spring:application:name: xx-aiai:openai:api-key: ${OPENAI_KEY} # OpenAI API 密鑰base-url: https://gitaigc.com  # OpenAI 基礎 URL# 以下是可選的配置,已經被注釋掉# spring.ai.openai.base-url: https://api.openai.com# spring.ai.openai.api-key:# 生成文本(text-to-text)模型配置# spring.ai.openai.chat.options.model: gpt-3.5-turbo# spring.ai.openai.chat.options.temperature: 0.4# 生成圖像(text-to-image)模型配置#spring.ai.openai.image.options.model: gpt-4-dalle# ========================Redis 配置=====================
---
spring:data:redis:host: 127.0.0.1  # Redis 主機password: 123456  # Redis 密碼port: 6379  # Redis 端口timeout: 1s  # Redis 連接超時# ========================SQL 初始化配置===================
---
spring:sql:init:mode: always  # 總是初始化數據庫schema-locations: classpath:db/init.sql  # 初始化SQL文件位置# ========================數據庫配置(Druid + MySQL 8)=======================
---
spring:datasource:type: com.alibaba.druid.pool.DruidDataSource  # 數據源類型driver-class-name: com.mysql.cj.jdbc.Driver  # MySQL JDBC 驅動類名url: jdbc:mysql://127.0.0.1:3306/aicloud?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true  # 數據庫連接 URLusername: root  # 數據庫用戶名password: mac_root  # 數據庫密碼druid:test-while-idle: false  # 配置 Druid 數據源的空閑連接檢測# ========================MyBatis-Plus 配置===================
mybatis-plus:configuration:map-underscore-to-camel-case: true  # 將數據庫表字段的下劃線轉為駝峰命名法mapper-locations: classpath:mapper/*.xml  # MyBatis 映射器文件的位置type-aliases-package: com.xx.entities  # MyBatis 類型別名包路徑# ========================日志配置=======================
logging:level:com.xx: info  # 設置特定包的日志級別# ========================JSON 日期格式配置===================
---
spring:jackson:date-format: yyyy-MM-dd HH:mm:ss  # JSON 日期格式time-zone: GMT+8  # 設置時區為 GMT+8

API Key

# mac 版
open ~/.zshrcexport OPENAI_KEY="換成自己的"source ~/.zshrc# windows 自己配置環境變量即可

3、啟動類

package com.xx;import com.xx.utils.LocalIpUtil;
import com.xx.utils.ValidationUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.Environment;/*** @Author: xueqimiao* @Date: 2025/4/15 10:34*/
@SpringBootApplication
@Slf4j
public class AiApplication {public static void main(String[] args) {ConfigurableApplicationContext application = SpringApplication.run(AiApplication.class, args);Environment env = application.getEnvironment();String ip = LocalIpUtil.getLocalIp();String port = env.getProperty("server.port");String path = ValidationUtil.isEmpty(env.getProperty("server.servlet.context-path")) ? "" : env.getProperty("server.servlet.context-path");log.info("\n----------------------------------------------------------\n" +"Welcome to the 小薛博客 AI大模型項目 Interface documentation:\n\t" +"Local: \t\thttp://127.0.0.1:" + port + path + "/doc.html\n" +"Swagger文檔: \thttp://" + ip + ":" + port + path + "/doc.html\n" +"進入首頁: \thttp://" + ip + ":" + port + path + "\n" +"----------------------------------------------------------");}}

4、日志文件

logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false"><!--定義日志文件的存儲地址 --><property name="LOG_HOME" value="../logs/xx-ai" /><!--<property name="COLOR_PATTERN" value="%black(%contextName-) %red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta( %replace(%caller{1}){'\t|Caller.{1}0|\r\n', ''})- %gray(%msg%xEx%n)" />--><!-- 控制臺輸出 --><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><!--格式化輸出:%d表示日期,%thread表示線程名,%-5level:級別從左顯示5個字符寬度%msg:日志消息,%n是換行符<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%L - %msg%n</pattern>--><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [traceId:%X{traceId}] %highlight(%-5level) %cyan(%logger{50}:%L) - %msg%n</pattern></encoder></appender><!-- 按照每天生成日志文件 --><appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!--日志文件輸出的文件名 --><FileNamePattern>${LOG_HOME}/xx-%d{yyyy-MM-dd}.%i.log</FileNamePattern><!--日志文件保留天數 --><MaxHistory>10</MaxHistory><maxFileSize>10MB</maxFileSize></rollingPolicy><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><!--格式化輸出:%d表示日期,%thread表示線程名,%-5level:級別從左顯示5個字符寬度%msg:日志消息,%n是換行符 --><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [traceId:%X{traceId}] %-5level %logger{50}:%L - %msg%n</pattern></encoder></appender><!-- 生成 error html格式日志開始 --><appender name="HTML" class="ch.qos.logback.core.FileAppender"><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><!--設置日志級別,過濾掉info日志,只輸入error日志--><level>ERROR</level></filter><encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"><layout class="ch.qos.logback.classic.html.HTMLLayout"><pattern>%p%d%msg%M%F{32}%L</pattern></layout></encoder><file>${LOG_HOME}/error-log.html</file></appender><!-- 生成 error html格式日志結束 --><!-- 每天生成一個html格式的日志開始 --><!--<appender name="FILE_HTML" class="ch.qos.logback.core.rolling.RollingFileAppender"><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">&lt;!&ndash;日志文件輸出的文件名 &ndash;&gt;<FileNamePattern>${LOG_HOME}/xx-%d{yyyy-MM-dd}.%i.html</FileNamePattern>&lt;!&ndash;日志文件保留天數 &ndash;&gt;<MaxHistory>10</MaxHistory><MaxFileSize>10MB</MaxFileSize></rollingPolicy><encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"><layout class="ch.qos.logback.classic.html.HTMLLayout"><pattern>%p%d%msg%M%F{32}%L</pattern></layout></encoder></appender>--><!-- 每天生成一個html格式的日志結束 --><!--myibatis log configure --><logger name="com.apache.ibatis" level="TRACE" /><logger name="java.sql.Connection" level="DEBUG" /><logger name="java.sql.Statement" level="DEBUG" /><logger name="java.sql.PreparedStatement" level="DEBUG" /><!-- 日志輸出級別 --><root level="INFO"><appender-ref ref="STDOUT" /><appender-ref ref="FILE" /><appender-ref ref="HTML" /><!--<appender-ref ref="FILE_HTML" />--></root></configuration>

5、HelloOpenAIController

package com.xx.controller;import com.xx.common.Result;
import jakarta.annotation.Resource;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.util.StopWatch;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;/*** @Author: xueqimiao* @Date: 2025/4/15 10:35*/
@RestController
public class HelloOpenAIController {@Resourceprivate OpenAiChatModel chatClient;@GetMapping("/txtToTxt")public Result txtToTxt(@RequestParam String keyword) {StopWatch stopWatch = new StopWatch();stopWatch.start();String retValue = chatClient.call(keyword);System.out.println(retValue);stopWatch.stop();System.out.println("耗時: " + stopWatch.getTotalTimeSeconds() + " 毫秒");return Result.ok(retValue);}}

6、不記錄日志注解

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>
package com.xx.annotations;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @auther xx* @create 2024-04-20 21:57*/
@Target({ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface NoLogParam {// 我可以用在參數列表或者方法上,屏蔽不愿意記錄的參數
}
package com.xx.aspect;import cn.hutool.json.JSONUtil;
import com.xx.annotations.NoLogParam;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;/*** @auther xx* @create 2024-04-20 21:59*/
@Order(value = Ordered.HIGHEST_PRECEDENCE)
@Aspect
@Component
public class NoLogAspect {private Logger log = LoggerFactory.getLogger(this.getClass());@Around("execution(* com.xx..*Controller.*(..))")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {Object result = null;MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();try {//打印處理當前請求的完整類名和方法名稱log.info("接口方法:{}.{}", methodSignature.getDeclaringTypeName(), methodSignature.getName());//獲取所有要打印的參數,丟到map中,key為參數名稱,value為參數的值,然后會將這個map以json格式輸出Map<String, Object> logParamsMap = new LinkedHashMap<>();String[] parameterNames = methodSignature.getParameterNames();Object[] args = joinPoint.getArgs();for (int i = 0; i < args.length; i++) {if (parameterIsLog(methodSignature, i)) {//參數名稱String parameterName = parameterNames[i];//參數值Object parameterValue = args[i];//將其放入到map中,稍后會以json格式輸出logParamsMap.put(parameterName, parameterValue);}}log.info("方法參數列表:{}", JSONUtil.toJsonStr(logParamsMap));result = joinPoint.proceed();//程序放行......return result;} finally {//判斷方法的返回值是否需要打印?方法上有 @NoLogAnnotation 注解的,表示結果不打印方法返回值if (this.resultIsLog(methodSignature)) {log.info("方法返回值:{}", JSONUtil.toJsonStr(result));}}}/*** 指定位置的參數是否需要打印出來?** @param methodSignature* @param paramIndex* @return*/private boolean parameterIsLog(MethodSignature methodSignature, int paramIndex) {if (methodSignature.getMethod().getParameterCount() == 0) {return false;}// 參數上有 @NoLogAnnotation注解的不會打印Annotation[] parameterAnnotation = methodSignature.getMethod().getParameterAnnotations()[paramIndex];if (parameterAnnotation != null && parameterAnnotation.length > 0) {for (Annotation annotation : parameterAnnotation) {if (annotation.annotationType() == NoLogParam.class) {return false;}}}// 參數類型是下面這些類型的,也不會打印,比如:ServletRequest、ServletResponseClass parameterType = methodSignature.getParameterTypes()[paramIndex];for (Class<?> type : noLogTypes) {if (type.isAssignableFrom(parameterType)) {return false;}}return true;}// 參數類型是下面這些類型的,也不會打印,比如:ServletRequest、ServletResponse,大家可以擴展private static List<Class<?>> noLogTypes = Arrays.asList(ServletRequest.class, ServletResponse.class);/*** 判斷方法的返回值是否需要打印?方法上有 @NoLogAnnotation 注解的,表示結果不打印方法返回值** @param methodSignature* @return*/private boolean resultIsLog(MethodSignature methodSignature) {return methodSignature.getMethod().getAnnotation(NoLogParam.class) == null;}
}

7、RedisConfig

  <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>
package com.xx.config;import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;/*** @auther xx* @create 2024-03-13 11:51*/
@Configuration
@Slf4j
public class RedisConfig {/*** redis序列化的工具配置類,下面這個請一定開啟配置* 127.0.0.1:6379> keys ** 1) "ord:102"  序列化過* 2) "\xac\xed\x00\x05t\x00\aord:102"   野生,沒有序列化過* this.redisTemplate.opsForValue(); //提供了操作string類型的所有方法* this.redisTemplate.opsForList(); // 提供了操作list類型的所有方法* this.redisTemplate.opsForSet(); //提供了操作set的所有方法* this.redisTemplate.opsForHash(); //提供了操作hash表的所有方法* this.redisTemplate.opsForZSet(); //提供了操作zset的所有方法** @param redisConnectionFactor* @return*/@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactor) {RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(redisConnectionFactor);//設置key序列化方式stringredisTemplate.setKeySerializer(new StringRedisSerializer());//設置value的序列化方式json,使用GenericJackson2JsonRedisSerializer替換默認序列化redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.afterPropertiesSet();return redisTemplate;}
}

8、MybatisPlusConfig

package com.xx.config;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;@Configuration
@MapperScan(value = {"com.xx.mapper"})
public class MybatisPlusConfig {}

9、Trace日志跟蹤

詳情見架構設計之請求鏈路日志追蹤快速定位程序Bug設計

package com.xx.trace;import org.slf4j.MDC;/*** @auther xx* @create 2024-04-18 19:32* <p>* org.slf4j.MDC;* 是 SLF4J(Simple Logging Facade for Java)庫中的一個組件,它代表 Mapped Diagnostic Context。MDC* 提供了一種機制,允許你在日志消息中插入上下文信息,這些信息可以跨多個方法調用和線程邊界傳播。* 這對于跟蹤和調試分布式系統或多線程應用程序中的請求非常有用。* <p>* MDC 允許你將鍵值對與當前線程關聯起來。然后,你可以在你的日志語句中引用這些值,* 從而能夠更容易地識別和理解日志消息產生的上下文。* <p>* 例如,你可能會在 Web 應用程序的每個請求開始時,將用戶的 ID 或會話 ID 放入 MDC,* 然后在你的日志語句中引用這個值。這樣,當你查看日志時,你可以很容易地看到哪個用戶的哪個請求產生了哪些日志消息。* <p>* 使用 MDC 的基本步驟如下:* 設置值:                 MDC.put("userId", "12345");* 在日志語句中使用值:       logger.info("Processing request for user: {}", MDC.get("userId"));* 清除值:                 MDC.remove("userId");*/
public class TraceUtils {public static final String TRACE_ID = "traceId";public static ThreadLocal<String> traceIdThreadLocal = new ThreadLocal<>();public static void setTraceId(String traceId) {traceIdThreadLocal.set(traceId);MDC.put(TRACE_ID, traceId);}public static String getTraceId() {return traceIdThreadLocal.get();}public static void removeTraceId() {traceIdThreadLocal.remove();MDC.remove(TRACE_ID);}
}
package com.xx.trace;import cn.hutool.core.util.IdUtil;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.web.filter.OncePerRequestFilter;import java.io.IOException;/*** @auther xx* @create 2024-04-18 19:36*/
@Order(Ordered.HIGHEST_PRECEDENCE)
@WebFilter(urlPatterns = "/**", filterName = "TraceFilter")
public class TraceFilter extends OncePerRequestFilter {private Logger log = LoggerFactory.getLogger(this.getClass());@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException {String traceID = IdUtil.fastSimpleUUID();TraceUtils.setTraceId(traceID); //ThreadLocal.set(traceID);long startTime = System.currentTimeMillis();try {filterChain.doFilter(request, response);} finally {TraceUtils.removeTraceId();}long endTime = System.currentTimeMillis();log.info("請求地址:{},耗時(毫秒):{}", request.getRequestURL().toString(), (endTime - startTime));}
}
package com.xx.trace;import com.xx.aspect.ResultTraceIdAspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @auther xx* @create 2024-04-18 20:03* @Configuration注解的proxyBeanMethods屬性的作用 注解的意思是proxyBeanMethods配置類是用來指定@Bean注解標注的方法是否使用代理,* 2.1 默認是true使用代理,直接從IOC容器之中取得對象;* <p>* 2.2 如果設置為false,也就是不使用注解,每次調用@Bean標注的方法獲取到的對象和IOC容器中的都不一樣,* 是一個新的對象,所以我們可以將此屬性設置為false來提高性能。*/
@Configuration(proxyBeanMethods = false)
public class TraceConfiguration {@Beanpublic TraceFilter traceFilter() {return new TraceFilter();}@Beanpublic ResultTraceIdAspect fillRequestIdAspect() {return new ResultTraceIdAspect();}
}
package com.xx.aspect;import com.xx.common.Result;
import com.xx.trace.TraceUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;/*** @auther xx* @create 2024-04-18 19:43*/
@Order
@Aspect
@Component
public class ResultTraceIdAspect {@Pointcut("execution(* com.xx..*Controller.*(..)) || execution(* com.xx.exception.GlobalExceptionHandler.*(..))")public void pointCut() {}@Around("pointCut()")public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {Object result = null;result = proceedingJoinPoint.proceed(); //放行if (result instanceof Result<?>) {((Result<?>) result).setTraceId(TraceUtils.getTraceId());}return result;}
}

10、文生文

package com.xx.controller;import com.xx.common.Result;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.util.StopWatch;
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;/*** @Author: xueqimiao* @Date: 2025/4/15 10:35*/
@RestController
@RequestMapping("/hello")
@Tag(name = "文生文")
public class HelloOpenAIController {@Resourceprivate OpenAiChatModel chatClient;@GetMapping("/txtToTxt")@Operation(summary = "文生文")@Parameter(name = "keyword", description = "關鍵字", required = true)public Result txtToTxt(@RequestParam /*@NoLogParam*/ String keyword) {StopWatch stopWatch = new StopWatch();stopWatch.start();String retValue = chatClient.call(keyword);System.out.println(retValue);stopWatch.stop();System.out.println("耗時: " + stopWatch.getTotalTimeSeconds() + " 毫秒");return Result.ok(retValue);}
}

外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳

4、整合阿里通義千問

有些同學沒有chatgpt賬號,就用以下的方式

1、langchain4j

langchain4j是什么 請見后續講解

<!--所有調用均基于 OpenAI 協議標準,實現一致的接口設計與規范
LangChain4j 提供與許多 LLM 提供商的集成。每個集成都有自己的 maven 依賴項。
最簡單的開始方式是從 OpenAI 集成開始-->
<dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
</dependency>

2、ChatLanguageModelConfig

package com.xx.config;import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @Author: xueqimiao* @Date: 2025/3/4 10:14* 默認情況下,Spring 會為配置類創建代理,這意味著每次調用 @Bean 方法時都會經過代理處理,這可能會增加一些性能開銷。如果你確定不需要這種代理(比如配置類中的方法沒有相互調用),可以通過 proxyBeanMethods = false 來禁用代理,減少不必要的開銷。*/
@Configuration(proxyBeanMethods = false)
public class ChatLanguageModelConfig {@Beanpublic ChatLanguageModel chatLanguageModel() {returnOpenAiChatModel.builder().apiKey(System.getenv("LANGCHAIN4J_KEY")).modelName("qwen-turbo-0624").baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1").build();}
}

3、HelloALiAIController

package com.xx.controller;import com.xx.common.Result;
import dev.langchain4j.model.chat.ChatLanguageModel;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
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;/*** @Author: xueqimiao* @Date: 2025/4/15 14:12*/
@RequestMapping("/helloALiAI")
@Tag(name = "ALi AI")
@RestController
public class HelloALiAIController {@Resourceprivate ChatLanguageModel chatLanguageModel;// http://127.0.0.1:8001/chatlanguagemodel/hello@GetMapping(value = "/hello")public Result hello(@RequestParam(value = "prompt", defaultValue = "你是誰") String prompt) {String result = chatLanguageModel.generate(prompt);System.out.println("通過langchain4j調用模型返回結果:" + result);return Result.ok(result);}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/77832.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/77832.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/77832.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

基于ubuntu24.10安裝NACOS2.5.1的簡介

基于ubuntu24.10安裝NACOS2.5.1的簡介 官方網站地址&#xff1a; https://nacos.io 可訪問nacos站點 https://nacos.io/zh-cn/ 2025年04月記錄發布 V2.5.1 版本 一、環境預準備 64 bit JDK 1.8&#xff1b; sudo apt update sudo apt install openjdk-8-jdk sudo apt upda…

神經網絡:從基礎到應用,開啟智能時代的大門

在當今數字化時代&#xff0c;神經網絡已經成為人工智能領域最熱門的技術之一。從語音識別到圖像分類&#xff0c;從自然語言處理到自動駕駛&#xff0c;神經網絡的應用無處不在。它不僅改變了我們的生活方式&#xff0c;還為各個行業帶來了前所未有的變革。本文將帶你深入了解…

[k8s實戰]Containerd 1.7.2 離線安裝與配置全指南(生產級優化)

[k8s實戰]Containerd 1.7.2 離線安裝與配置全指南&#xff08;生產級優化&#xff09; 摘要&#xff1a;本文詳細講解在無外網環境下部署 Containerd 1.7.2 容器運行時的完整流程&#xff0c;涵蓋二進制包安裝、私有鏡像倉庫配置、Systemd服務集成等關鍵步驟&#xff0c;并提供…

【CPU】結合RISC-V CPU架構回答中斷系統的7個問題(個人草稿)

結合RISC-V CPU架構對中斷系統七個關鍵問題的詳細解析&#xff0c;按照由淺入深的結構進行說明&#xff1a; 一、中斷請求機制&#xff08;問題①&#xff09; 硬件基礎&#xff1a; RISC-V通過CLINT&#xff08;Core Local Interrupter&#xff09;和PLIC&#xff08;Platfor…

[密碼學實戰]國密算法面試題解析及應用

以下是密碼學領域常見的面試題及其詳細解析,涵蓋基礎理論、算法實現與應用場景,幫助系統化備戰技術面試 一、基礎概念類 1. 密碼學的主要目標是什么? 答案: 確保數據的機密性(加密防止竊聽)、完整性(哈希校驗防篡改)、認證性(數字簽名驗證身份)和不可否認性(簽名防…

Spring Boot 實現 Excel 導出功能(支持前端下載 + 文件流)

&#x1f9e0; 一、為什么用 EasyExcel&#xff1f; 在 Java 開發中&#xff0c;操作 Excel 的框架主要有&#xff1a; Apache POI&#xff08;經典但慢、內存占用大&#xff09; JXL&#xff08;老舊不維護&#xff09; Alibaba EasyExcel&#xff08;阿里出品&#xff0c;…

【論文速遞】2025年06周 (Robotics/Embodied AI/LLM)

目錄 SMOLLM2&#xff1a;當Smol變得大 - 以數據為中心的小語言模型英文摘要中文摘要 OmniHuman-1&#xff1a;重新考慮一階段的人類動畫模型的擴展英文摘要中文摘要 S1&#xff1a;簡單的測試時間縮放英文摘要中文摘要 直接對齊算法間的差異日漸模糊英文摘要中文摘要 VideoJAM…

學習深度學習是否要先學習機器學習?工程師的路徑選擇策略

深度學習與機器學習的關系&#xff0c;如同摩天大樓與地基——前者是后者的高階延伸&#xff0c;但能否繞過地基直接造樓&#xff1f;本文從技術本質、學習曲線、應用場景三個維度剖析這一關鍵問題。 一、技術血脈的承繼關系 概念體系同源&#xff1a; 損失函數、梯度下降、過擬…

開始放飛之先搞個VSCode

文章目錄 開始放飛之先搞個VSCode重要提醒安裝VSCode下載MinGW-w64回到VSCode中去VSCode原生調試鍵盤問題遺留問題參考文獻 開始放飛之先搞個VSCode 突然發現自己的新臺式機上面連個像樣的編程環境都沒有&#xff0c;全是游戲了&#xff01;&#xff01;&#xff01;&#xff…

【2025“華中杯”大學生數學建模挑戰賽】選題分析 A題 詳細解題思路

目錄 2025“華中杯”大學生數學建模挑戰賽選題分析A題&#xff1a;晶硅片產銷策略優化B題&#xff1a;校園共享單車的調度與維護問題C題&#xff1a;就業狀態分析與預測D題&#xff1a;患者院內轉運不良事件的分析與預測 A 題 晶硅片產銷策略優化問題 1&#xff1a;月利潤計算模…

YOLO11改進,尺度動態損失函數Scale-based Dynamic Loss,減少標簽不準確對損失函數穩定性的影響

在目標檢測領域,標簽噪聲與尺度敏感問題始終是制約模型性能提升的"阿喀琉斯之踵"。2025年CVPR最佳論文提出的尺度動態損失函數(Scale-based Dynamic Loss, SDL),通過構建自適應損失調節機制,不僅實現了對YOLOv11檢測精度的指數級提升,更重新定義了損失函數的設…

緩存 --- 內存緩存 or 分布式緩存

緩存 --- 內存緩存 or 分布式緩存 內存緩存&#xff08;In-Memory Cache&#xff09;分布式緩存&#xff08;Distributed Cache&#xff09;內存緩存 vs 分布式緩存 內存緩存和分布式緩存是兩種常見的緩存策略&#xff0c;它們在存儲位置、訪問速度和適用場景上有所不同。下面分…

Python+CoppeliaSim+ZMQ remote API控制機器人跳舞

這是一個使用Python和CoppeliaSim&#xff08;V-REP&#xff09;控制ASTI人型機器人進行舞蹈動作的演示項目。 項目描述 本項目展示了如何使用Python通過ZeroMQ遠程API與CoppeliaSim仿真環境進行交互&#xff0c;控制ASTI人型機器人執行預定義的舞蹈動作序列。項目包含完整的機…

進程管理,關閉進程

查看Linux系統中的進程信息 語法&#xff1a;ps【-e -f】 一般與管道符與grep配合使用&#xff0c;&#xff0c;去過濾指定的信息 -e&#xff1a;顯示出全部的進程 -f&#xff1a;以完全格式化的形式展示信息&#xff08;展示全部信息&#xff09; 簡單用法&#xff1a;p…

線性代數-矩陣的秩

矩陣的秩&#xff08;Rank&#xff09;是線性代數中的一個重要概念&#xff0c;表示矩陣中線性無關的行&#xff08;或列&#xff09;的最大數量。它反映了矩陣所包含的“有效信息”的維度&#xff0c;是矩陣的核心特征之一。 直觀理解 行秩與列秩&#xff1a; 行秩&#xff1…

CSS偽類、clip-path實現三角形、箭頭繪制

<template><div :class"$options.name"><div class"triangle-container1"><!-- 偽類三角形&#xff1a;向右 --><div class"triangle-RM"></div><!-- 偽類三角形&#xff1a;向下 --><div class&q…

numpy、pandas內存優化操作整理

前言 python作為一款不怎么關注數據類型的語言&#xff0c;不同類型的數據可以往同一個變量中放置 這也就直接導致&#xff0c;作為熟悉C這種一個變量只有一個類型的程序員來說&#xff0c;在解讀python程序時&#xff0c;想搞清楚變量中到底存的是什么數據類型的時候時常很頭…

Linux本地&遠程主機文件傳輸

一.實驗環境 sshd 是SSH (Secure Shell)協議的守護進程。 功能用途 遠程安全連接: sshd允許用戶通過網絡安全地登錄到遠程服務器。在傳統的Telnet等協議中&#xff0c;數據傳輸是明文的&#xff0c; 容易被竊取和篡改。而SSH協議通過加密技術&#xff0c;對傳輸的數據進行加…

Windows網絡及服務:制作系統盤

今天我要介紹的是一個比較有意思且好玩的一個小玩意兒&#xff1a;關于系統盤的制作&#xff1b; 注明&#xff1a;對于系統盤的制作&#xff0c;以及接下來的課程&#xff0c;基本是作為動手課業來進行的&#xff0c;這也是作為程序員的必要進行的一項活動。 對于系統盤&…

【人工智能】大模型的Prompt工程:釋放DeepSeek潛能的藝術與科學

《Python OpenCV從菜鳥到高手》帶你進入圖像處理與計算機視覺的大門! 解鎖Python編程的無限可能:《奇妙的Python》帶你漫游代碼世界 Prompt工程是大模型應用中的關鍵技術,通過精心設計的提示詞(Prompt),用戶能夠有效引導模型生成高質量輸出。本文深入探討了優化DeepSee…