自定义图片作为Emoji表情的三种技术实现路径
2026/10/9 8:34:20
<?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 https://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>4.1.1</version> <relativePath/> </parent> <groupId>com.hejie</groupId> <artifactId>ai-study</artifactId> <version>0.0.1-SNAPSHOT</version> <name>ai-study</name> <properties> <java.version>21</java.version> <spring-ai.version>2.0.1</spring-ai.version> </properties> <dependencies> <!-- Spring Boot Starter Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Spring AI --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-openai</artifactId> </dependency> <!-- Resilience4j --> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-spring-boot3</artifactId> <version>2.1.0</version> </dependency> <!-- Lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </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> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>server: port: 8080 spring: application: name: ai-study servlet: encoding: enabled: true force-response: true charset: UTF-8 threads: virtual: enabled: true ai: openai: api-key: ${OPENAI_API_KEY} # DeepSeek # base-url: https://api.deepseek.com # chat: # model: deepseek-chat # temperature: 0.7 # 通义千问 base-url: https://dashscope.aliyuncs.com/compatible-mode/v1 chat: model: qwen3.8-27b temperature: 0.7 logging: level: org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor: DEBUG resilience4j: circuitbreaker: configs: default: slidingWindowSize: 10 failureRateThreshold: 50 waitDurationInOpenState: 10000 permittedNumberOfCallsInHalfOpenState: 5 registerHealthIndicator: true instances: default: baseConfig: default chat-service: slidingWindowSize: 10 failureRateThreshold: 50 waitDurationInOpenState: 10000 permittedNumberOfCallsInHalfOpenState: 5 registerHealthIndicator: true ratelimiter: configs: default: limitForPeriod: 100 limitRefreshPeriod: 1000ms timeoutDuration: 0ms instances: default: baseConfig: default chat-service: limitRefreshPeriod: 1000ms limitForPeriod: 5 timeoutDuration: 0 timelimiter: configs: default: timeoutDuration: 3000ms instances: default: baseConfig: default chat-service: timeoutDuration: 3000ms bulkhead: configs: default: maxConcurrentCalls: 50 maxWaitDuration: 500ms instances: default: baseConfig: default chat-service: maxConcurrentCalls: 10@Configuration public class PromptClientConfiguration { @Bean public ChatClient conceptExplainChatClient(ChatModel chatModel) throws IOException { return ChatClient.builder(chatModel) .defaultSystem(new String(Files.readAllBytes(Paths.get("src/main/resources/templates/concept-explain-prompt.txt")))) .defaultUser("从以下内容中提取技术概念的名称、分类、一句话解释:\n") .build(); } @Bean public ChatClient codeReviewChatClient(ChatModel chatModel) throws IOException { return ChatClient.builder(chatModel) .defaultSystem(new String(Files.readAllBytes(Paths.get("src/main/resources/templates/code-review-prompt.txt")))) .defaultUser("请审查以下代码:\n") .build(); } }@Configuration public class MultModelsClientConfiguration { @Bean("fastChatClient") public ChatClient fastChatClient(ChatClient.Builder builder) { return builder .defaultSystem("你是一个简洁的技术助手,回答控制在100字以内。") .defaultOptions(ChatOptions.builder() .model("deepseek-chat") .temperature(0.3)) .build(); } @Bean("deepChatClient") public ChatClient deepChatClient(ChatClient.Builder builder) { return builder .defaultSystem("你是一个资深架构师,回答要详细、有深度,先给框架再逐步分析。") .defaultOptions(ChatOptions.builder() .model("qwen3.8-27b") .temperature(0.7)) .build(); } }@RestController @RequestMapping("/chat") public class ChatController { @Resource private ChatClient conceptExplainChatClient; @GetMapping("/chat") @CircuitBreaker(name = "chat-service", fallbackMethod = "chatFallback") @RateLimiter(name = "chat-service") @TimeLimiter(name = "chat-service") @Bulkhead(name = "chat-service", type = Bulkhead.Type.SEMAPHORE) public String chat(@RequestParam String message) { return conceptExplainChatClient.prompt() .user(message) .call() .content(); } public CompletableFuture<String> chatFallback(String message, Exception e) { return CompletableFuture.supplyAsync(() -> "服务繁忙,请稍后重试"); } @GetMapping("/detail") public Map<String, Object> chatDetail(@RequestParam String message) { ChatResponse response = conceptExplainChatClient.prompt() .user(message) .call() .chatResponse(); return Map.of( "content", response.getResult().getOutput().getText(), "model", response.getMetadata().getModel(), "usage", response.getMetadata().getUsage().toString() ); } @GetMapping("/extract") public TechConceptVO extract(@RequestParam String text) { return conceptExplainChatClient.prompt() .user(text) .call() .entity(TechConceptVO.class); } @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<String> chatStream(@RequestParam String message) { SimpleLoggerAdvisor customLogger = SimpleLoggerAdvisor.builder() .requestToString(request -> "【用户提问】: " + request.prompt().getUserMessage()) .responseToString(response -> "【AI回复】: " + response.getResult().getOutput().getText()) .build(); return conceptExplainChatClient.prompt() .user(message) .advisors(customLogger) .stream() .content(); } }@Data public class TechConceptVO { String name; // 概念名称 String category; // 分类 String explanation;// 一句话解释 }@RestController @RequestMapping("/code") public class CodeReviewController { @Resource private ChatClient codeReviewChatClient; @GetMapping("/review") public String reviewCode(@RequestParam String code) { return codeReviewChatClient.prompt() .user(code) .call() .content(); } }@RestController @RequestMapping("/model") public class MutiModelController { @Resource private ChatClient fastChatClient; @Resource private ChatClient deepChatClient; @GetMapping("/smart-chat") public String smartChat(@RequestParam String message, @RequestParam(defaultValue = "fast") String mode) { ChatClient client = "deep".equals(mode) ? deepChatClient : fastChatClient; return client.prompt() .user(message) .call() .content(); } }