关于springboot对接通义千问大模型的尝试

news2024/12/29 13:36:01

今天正在路上刷手机,突然看到群里有人发了一个链接,内容是Spring Cloud Alibaba AI 的使用,spring cloud AI的使用,于是就想着玩一玩试试,难度不大,就是有些文档的坑,这里做一个记录,后续会继续更新这个系列的,毕竟AI时代,我们springer也得搭一下顺风车。

一、文档阅读

我们看到文档其实描述了他的能力如下图,但是我们这里只尝试一下文生文的能力,其实说人话就是对话。
在这里插入图片描述

二、快速开始

我们基于文档描述开始搭建这个环境。

1、基于文档搭建环境

  • 1、 引入依赖
    我们按照文档的内容引入如下依赖。
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-alibaba-dependencies</artifactId>
      <version>2023.0.1.0</version>
      <type>pom</type>
      <scope>import</scope>
     </dependency>
   </dependencies>
</dependencyManagement>

<dependencies>
  <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-ai</artifactId>
  </dependency>
</dependencies>
  • 2、在 application.yml 配置文件中加入以下配置:
    这个API-KEY需要你通过阿里云去获取,具体操作步骤:获取通义千问api-key
spring:
  cloud:
    ai:
      tongyi:
        chat:
          options:
            # Replace the following key with a valid API-KEY.
            api-key: sk-a3d73b1709bf4a178c28ed7c8b3b5axx
  • 3、编写聊天服务实现类,由 Spring AI 自动注入 ChatClient、StreamingChatClient,ChatClient 屏蔽底层通义大模型交互细节。
@Service
public class TongYiSimpleServiceImpl extends AbstractTongYiServiceImpl {

  private final ChatClient chatClient;

  private final StreamingChatClient streamingChatClient;

  @Autowired
  public TongYiSimpleServiceImpl(ChatClient chatClient, StreamingChatClient streamingChatClient) {
    this.chatClient = chatClient;
    this.streamingChatClient = streamingChatClient;
  }
}

提供具体聊天逻辑实现

@Service
public class TongYiSimpleServiceImpl extends AbstractTongYiServiceImpl {

  // ......

  @Override
  public String completion(String message) {

    Prompt prompt = new Prompt(new UserMessage(message));

    return chatClient.call(prompt).getResult().getOutput().getContent();
  }

  @Override
  public Map<String, String> streamCompletion(String message) {

    StringBuilder fullContent = new StringBuilder();

    streamingChatClient.stream(new Prompt(message))
        .flatMap(chatResponse -> Flux.fromIterable(chatResponse.getResults()))
        .map(content -> content.getOutput().getContent())
        .doOnNext(fullContent::append)
        .last()
        .map(lastContent -> Map.of(message, fullContent.toString()))
        .block();

    log.info(fullContent.toString());

    return Map.of(message, fullContent.toString());
  }

}

编写 Spring 入口类并启动应用

@SpringBootApplication
public class TongYiApplication {
  public static void main(String[] args) {
    SpringApplication.run(TongYiApplication.class);
  }
}

2、踩坑

2.1、maven导入失败

我在按照如上环境搭建好之后,reload maven发现报错。
在这里插入图片描述
从阿里云的maven镜像库里面拉不下来这些依赖。我用的maven库如下:

<mirror>
	<id>alimaven</id>
	<name>aliyun maven</name>
	<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
	<mirrorOf>central</mirrorOf>
</mirror>

既然踩了坑,那就去文档找吧,估计不止我一个人踩坑。翻了一下找到了一个阿里cloud答疑问题的网址。spring cloud alibaba答疑区
最后翻到了一个这个spring ai maven无法引入问题解决
我们就按照他这个加一个maven的仓库配置,

<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>spring-snapshots</id>
        <name>Spring Snapshots</name>
        <url>https://repo.spring.io/snapshot</url>
        <releases>
            <enabled>false</enabled>
        </releases>
    </repository>
</repositories>

2.2、yml配置问题

我按照上面的配置启动服务,发现报错。找不到配置文件的这个api-key.
在这里插入图片描述
应该是配置的路径不对,但是我是按照官方配置的。所以我们来看下源码吧还是。
在这里插入图片描述
我们看到他的前缀spring.cloud.ai.tongyi和我们的文档的不一样层级,所以我们还是改一下吧。
改为如下图所示:
在这里插入图片描述
OK,此时就已经可以启动了。
在这里插入图片描述

3、完整代码

3.1、controller

package com.test.controller;

import com.test.utils.SseEmitterUtils;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.StreamingChatClient;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import com.test.service.TongYiSimpleServiceImpl;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import reactor.core.publisher.Flux;

@RestController
@RequestMapping("/chat")
public class TongYiSimpleController {

    @Resource
    StreamingChatClient streamingChatClient;


    @GetMapping("/connect")
    @ApiResponse(description = "用户创建连接")
    public SseEmitter connect(@RequestParam(name = "username") String username) {
        return SseEmitterUtils.getConnection(username);
    }

    @PostMapping(value = "/send")
    @ApiResponse(description = "用户发送消息")
    public void sendMessage(@RequestParam(name = "username") String username, @RequestParam(name = "message") String message) {
        try {
            TongYiSimpleServiceImpl tongYiSimpleService = new TongYiSimpleServiceImpl(streamingChatClient);
            tongYiSimpleService.sendMsg(username,message);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

3.2、service

package com.test.service;

import com.test.utils.SseEmitterUtils;
import org.springframework.ai.chat.StreamingChatClient;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.io.IOException;
import java.util.Map;


@Service
public class TongYiSimpleServiceImpl{


    private final StreamingChatClient streamingChatClient;

    @Autowired
    public TongYiSimpleServiceImpl(StreamingChatClient streamingChatClient) {
        this.streamingChatClient = streamingChatClient;
    }

    public Map<String, String> sendMsg(String userName,String message) {
        StringBuilder fullContent = new StringBuilder();
        // 流式调用大模型,以响应式的方式返回结果
        streamingChatClient.stream(new Prompt(message))
                .flatMap(chatResponse -> Flux.fromIterable(chatResponse.getResults()))
                .map(content -> content.getOutput().getContent())
                .doOnNext(fullContent::append)
                .subscribe(item ->{
                    try {
                        SseEmitterUtils.sendMsg(userName,item);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                });

        return Map.of(message, fullContent.toString());
    }

    public Mono<Map<String, String>> streamCompletion(String message) {
        return streamingChatClient.stream(new Prompt(message))
                .flatMapIterable(chatResponse -> chatResponse.getResults())
                .map(item->item.getOutput())
                .map(item->item.getContent())
                .reduce(new StringBuilder(), (builder, content) -> builder.append(content))
                .map(builder -> Map.of(message, builder.toString()));
    }

}

3.3、sse工具类

package com.test.utils;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class SseEmitterUtils {

    private static final Logger logger = LoggerFactory.getLogger(SseEmitterUtils.class);

    private static final ThreadPoolExecutor ssePool =  new ThreadPoolExecutor(
                20,
                200,
                30,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(1000),
                runnable -> new Thread(runnable, "sse-sendMsg-pool"),
                new ThreadPoolExecutor.AbortPolicy()
    );

    // SSE连接关闭延迟时间
    private static final Integer EMITTER_COMPLETE_DELAY_MILLISECONDS = 500;

    // SSE连接初始化超时时间
    private static final Long EMITTER_TIME_OUT_MILLISECONDS = 600_000L;

    // 缓存 SSE连接
    private static final Map<String, SseEmitter> SSE_CACHE = new ConcurrentHashMap<>();

    /**
     * 获取 SSE连接 默认超时时间EMITTER_TIME_OUT_MILLISECONDS 毫秒
     *
     * @param clientId 客户端 ID
     * @return 连接对象
     */
    public static SseEmitter getConnection(String clientId) {
       return getConnection(clientId,EMITTER_TIME_OUT_MILLISECONDS);
    }

    /**
     * 获取 SSE连接
     *
     * @param clientId 客户端 ID
     * @param timeout  连接超时时间,单位毫秒
     * @return 连接对象
     */
    public static SseEmitter getConnection(String clientId,Long timeout) {
        final SseEmitter sseEmitter = SSE_CACHE.get(clientId);
        if (Objects.nonNull(sseEmitter)) {
            return sseEmitter;
        } else {
            final SseEmitter emitter = new SseEmitter(timeout);

            // 初始化emitter回调
            initSseEmitter(emitter, clientId);

            // 连接建立后,将连接放入缓存
            SSE_CACHE.put(clientId, emitter);
            logger.info("[SseEmitter] 连接已建立,clientId = {}", clientId);
            return emitter;
        }
    }

    /**
     * 关闭指定的流连接
     *
     * @param clientId 客户端 ID
     */
    public static void closeConnection(String clientId) {
        final SseEmitter sseEmitter = SSE_CACHE.get(clientId);
        logger.info("[流式响应-停止生成] 收到客户端关闭连接指令,Emitter is {},clientId = {}", null == sseEmitter ? "NOT-Exist" : "Exist", clientId);
        if (Objects.nonNull(sseEmitter)) {
            SSE_CACHE.remove(clientId);
            sseEmitter.complete();
        }
        try {
            TimeUnit.MILLISECONDS.sleep(EMITTER_COMPLETE_DELAY_MILLISECONDS);
        } catch (InterruptedException ex) {
            logger.error("流式响应异常", ex);
            Thread.currentThread().interrupt();
        }
    }

    /**
     * 推送消息
     *
     * @param clientId 客户端 ID
     * @param msg      消息
     * @return 连接是否存在
     * @throws IOException IO异常
     */
    public static boolean sendMsg(String clientId, String msg) throws IOException {
        final SseEmitter sseEmitter = SSE_CACHE.get(clientId);
        if (Objects.nonNull(sseEmitter)) {
            try {
                sseEmitter.send(msg);
            } catch (Exception e) {
                logger.error("[流式响应-停止生成] ");
                return true;
            }
            return false;
        } else {
            return true;
        }
    }

    /**
     * 异步推送消息 TODO 目前未实现提供回调
     *
     * @param clientId 客户端 ID
     * @param msg      消息
     * @return 连接是否存在
     * @throws IOException IO异常
     */
    public static boolean sendMsgAsync(String clientId, String msg){
        final SseEmitter sseEmitter = SSE_CACHE.get(clientId);
        if (Objects.nonNull(sseEmitter)) {
            try {
                ssePool.submit(()->{
                    try {
                        sseEmitter.send(msg);
                    } catch (IOException e) {
                        logger.error("[流式响应-停止生成] ");
                    }
                });
            } catch (Exception e) {
                logger.error("[流式响应-停止生成] ");
                return true;
            }
            return false;
        } else {
            return true;
        }
    }


    /**
     * 立即关闭SseEmitter,可能存在推流不完全的情况,谨慎使用
     *
     * @param clientId
     */
    public static void complete(String clientId) {
        completeDelay(clientId,0);
    }

    /**
     * 延迟关闭 SseEmitter,延迟一定时长时为了尽量保证最后一次推送数据被前端完整接收
     *
     * @param clientId 客户端ID
     */
    public static void completeDelay(String clientId) {
        completeDelay(clientId,EMITTER_COMPLETE_DELAY_MILLISECONDS);
    }

    /**
     * 延迟关闭 SseEmitter,延迟指定时长时为了尽量保证最后一次推送数据被前端完整接收
     *
     * @param clientId 客户端ID
     */
    public static void completeDelay(String clientId,Integer delayMilliSeconds) {
        final SseEmitter sseEmitter = SSE_CACHE.get(clientId);
        if (Objects.nonNull(sseEmitter)) {
            try {
                TimeUnit.MILLISECONDS.sleep(delayMilliSeconds);
                sseEmitter.complete();
            } catch (InterruptedException ex) {
                logger.error("流式响应异常", ex);
                Thread.currentThread().interrupt();
            }
        }
    }

    /**
     * 初始化 SSE连接 设置一些属性和回调之类的
     *
     * @param emitter 连接对象
     * @param clientId 客户端 ID
     */
    private static void initSseEmitter(SseEmitter emitter, String clientId){
        // 设置SSE的超时回调
        emitter.onTimeout(() -> {
            logger.info("[SseEmitter] 连接已超时,正准备关闭,clientId = {}", clientId);
            SSE_CACHE.remove(clientId);
        });

        // 设置SSE的结束回调
        emitter.onCompletion(() -> {
            logger.info("[SseEmitter] 连接已释放,clientId = {}", clientId);
            SSE_CACHE.remove(clientId);
        });

        // 设置SSE的异常回调
        emitter.onError(throwable -> {
            logger.error("[SseEmitter] 连接已异常,正准备关闭,clientId = {}", clientId);
            SSE_CACHE.remove(clientId);
        });
    }
}

3.4、配置文件

spring:
  cloud:
    ai:
      tongyi:
        # Replace the following key with a valid API-KEY.
        api-key: 替换你的
        model: qwen-max

3.5、maven配置

<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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.example</groupId>
  <artifactId>test</artifactId>
  <version>1.0-SNAPSHOT</version>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-dependencies</artifactId>
        <version>2023.0.1.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-ai</artifactId>
    </dependency>
  </dependencies>
  <repositories>
    <repository>
      <id>spring-milestones</id>
      <name>Spring Milestones</name>
      <url>https://repo.spring.io/milestone</url>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
    <repository>
      <id>spring-snapshots</id>
      <name>Spring Snapshots</name>
      <url>https://repo.spring.io/snapshot</url>
      <releases>
        <enabled>false</enabled>
      </releases>
    </repository>
  </repositories>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>9</source>
          <target>9</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

3.6、简单前端页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>SSE Chat</title>
</head>
<body>
<h1>橘子-Chat</h1>

<div id="chat-messages"></div>
<form id="message-form">
    <input type="text" id="message-input" placeholder="输入消息">
    <button type="submit">发送</button>
</form>

<script>
    const chatMessages = document.getElementById('chat-messages');
    const messageForm = document.getElementById('message-form');
    const messageInput = document.getElementById('message-input');

    // 连接到聊天室
    const connectToChat = () => {
        const username = prompt('Enter your username:');
        const eventSource = new EventSource(`/chat/connect?username=${encodeURIComponent(username)}`);

        // 接收来自服务器的消息
        eventSource.onmessage = function(event) {
            const message = event.data;
            displayMessage(message);
        };

        // 处理连接错误
        eventSource.onerror = function(event) {
            console.error('EventSource error:', event);
            eventSource.close();
        };

        // 提交消息表单
        messageForm.addEventListener('submit', function(event) {
            event.preventDefault();
            const message = messageInput.value.trim();
            if (message !== '') {
                sendMessage(username, message);
                messageInput.value = '';
            }
        });
    };

    // 发送消息到服务器
    const sendMessage = (username, message) => {
        fetch(`/chat/send?username=${encodeURIComponent(username)}&message=${encodeURIComponent(message)}`, {
            method: 'POST'
        })
        .catch(error => console.error('Error sending message:', error));
    };

    // 在界面上显示消息
    const displayMessage = (message) => {
        const messageElement = document.createElement('div');
        messageElement.textContent = message;
        chatMessages.appendChild(messageElement);
    };
    // 发起连接
    connectToChat();

</script>
</body>
</html>

至此就完成了对接。

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

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

相关文章

基于RK3588+MCU智能清洁车应用解决方案

智能清洁车应用解决方案 在智慧城市建设发展的过程中&#xff0c;智慧环卫是打造智慧城市的重要组成部分&#xff0c;智能清洁车作为实现环卫智能化、提升作业效率和服务质量的关键工具&#xff0c;发挥着不可或缺的作用。 智能清洁车集成了激光雷达、双目视觉、多重传感器以及…

九月更新|用这5个简单技巧,新手在国内也能轻松使用ChatGPT,GPT新手使用手册(学术教师)

一、 ChatGPT可以做什么&#xff1f; 简单来说&#xff0c;ChatGPT就像一个超级智能的聊天机器人&#xff0c;它可以做很多事情。你可以把它想象成一个非常聪明的助手&#xff0c;随时随地帮你解答问题、提供建议、写文章、甚至讲笑话。以下是几个具体的例子&#xff1a; 1. …

论文浅尝 | 超越实体对齐: 通过实体关系协同实现完整的知识图谱对齐

笔记整理&#xff1a;米尔扎提阿力木&#xff0c;天津大学硕士&#xff0c;研究方向为大模型 论文链接&#xff1a;https://arxiv.org/abs/2407.17745 摘要 知识图谱对齐(Knowledge Graph Alignment, KGA)旨在整合来自多个来源的知识&#xff0c;以解决单个知识图谱在覆盖范围和…

一文带你了解可观测领域中APM与eBPF的技术差异

近年来&#xff0c;随着eBPF技术的兴起&#xff0c;很多人有这样的疑惑&#xff1a;eBPF和APM有什么区别&#xff1f;他们是竞争关系还是合作关系&#xff1f;本文将就此展开讨论&#xff0c;并给出切实有效的落地方案。 01APM APM全称&#xff1a;Application Performance Ma…

vulhub xxe靶机

步骤一&#xff0c;访问浏览器 步骤二&#xff0c;输入/robots.txt 步骤三&#xff0c;发现存在用户登录的一个界面/xxe 我们登录进去 步骤四&#xff0c;随便输入一个数字或者字母打开BP 抓到包之后发送的重放器里边 通过抓包发现是XML数据提交 步骤五&#xff0c;通过php…

【采集软件】抖音根据关键词批量采集搜索结果工具

这是我用Python开发的抖音关键词搜索采集工具软件。 软件界面截图&#xff1a; 爬取结果截图&#xff1a; 软件演示视频&#xff1a; https://www.bilibili.com/video/BV1Fc41147Be 完整讲解文章&#xff1a; https://www.bilibili.com/read/cv33750458

高翔【自动驾驶与机器人中的SLAM技术】学习笔记(九)imu运动学;lambda表达式;bind;function;std::move()

一、IMU运动学 1、测量值&#xff1a; 常用六轴IMU是由陀螺仪&#xff08;Gyroscope&#xff09;和加速度计&#xff08;Acclerator&#xff09;两部分组成。 陀螺仪测量&#xff1a;角速度。加速度计&#xff1a;加速度。 安装要尽量保证IMU的安装位置在车辆中心。避免由I…

基于SOA-BP海鸥优化BP神经网络实现数据预测Python实现

BP神经网络是一种多层前馈神经网络&#xff0c;它通过反向传播算法来训练网络中的权重和偏置&#xff0c;以最小化预测误差。然而&#xff0c;BP神经网络的性能很大程度上依赖于其初始参数的选择&#xff0c;这可能导致训练过程陷入局部最优解。海鸥优化算法因其探索和开发能力…

基于vue框架的残疾人就业帮扶平台97c5w(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,企业,招聘信息,类型,求职信息,投递信息,邀请信息,通知信息,帮扶政策,申请信息,意见反馈 开题报告内容 基于Vue框架的残疾人就业帮扶平台开题报告 一、选题背景与意义 随着社会的文明进步和经济的快速发展&#xff0c;残疾人群体…

flannel,etcd,docker

bridge容器 听有容器连接到桥就可以使用外网&#xff0c;使用nat让容器可以访问外网使用ipas指令查看桥&#xff0c;所有容器连接到此桥&#xff0c;ip地址都是172.17.0.0/16网段&#xff0c;桥是启动docker服务后出现&#xff0c;在centos使用bridge-utils安装 跨主机的容器…

第一次使用PyCharm写C++(失败)

前言&#xff1a; 由于我已经非常习惯使用PyCharm远程连接服务器了&#xff0c;我认为非常方便&#xff0c;所以希望C也能直接用Pycharm。于是尝试在PyCharm上部署C环境。 但是&#xff0c;我失败了。如果您知道问题所在&#xff0c;欢迎给我留言。我认为Pycharm并没有编译C/C…

Windows电脑微信可以登录发消息,但是网页打不开的解决方法:刷新DNS缓存

遇到的问题 今天实验室的电脑突然网页打不开&#xff0c;baidu上不了&#xff0c;chrome浏览器也上不了。但是ping baidu.com能够ping通&#xff0c;github pull也可以&#xff0c;网易云可以听歌。也就是说网络是通的&#xff0c;但是浏览器无法上网。 解决方法 我是通过 W…

直播商城APP开发指南:基于多商户商城系统源码的实现

对于开发者而言&#xff0c;构建一个功能完备、性能优越的直播商城APP已经成为当前技术领域的一个重要方向。本文将以多商户商城系统源码为基础&#xff0c;深入探讨如何高效开发一个直播商城APP。 一、多商户商城系统的核心概念 多商户商城系统是一种支持多个商家在同一平台…

深度解读SGM41511电源管理芯片I2C通讯协议REG09寄存器解释

REG09 是 SGM41511 的第十个寄存器&#xff0c;地址为 0x09。这是一个只读&#xff08;R&#xff09;寄存器&#xff0c;用于报告各种故障状态。上电复位值&#xff08;PORV&#xff09;为 xxxxxxxx&#xff0c;表示上电时的初始状态是不确定的。这个寄存器提供了充电器当前故障…

【Python机器学习】NLP词频背后的含义——从词频到主题得分

目录 TF-IDF向量及词形归并 主题向量 一个思想实验 一个主题评分算法 一个LDA分类器 LDiA TF-IDF向量&#xff08;词项频率—逆文档频率向量&#xff09;可以帮助我们估算词在文本块中的重要度&#xff0c;我们使用TF-IDF向量和矩阵可以表明每个词对于文档集合中的一小段…

【hot100篇-python刷题记录】【跳跃游戏】

R6-贪心算法 符合贪心的原因是&#xff1a; 我们要走到最后可以每次都选择尽可能远的来走&#xff0c;其次&#xff0c;能走到该步意味着该步以前都能到达。因此&#xff0c;局部最优解可以代表全局最优解。 class Solution:def canJump(self, nums: List[int]) -> bool:#最…

全志/RK安卓屏一体机:智能家居中控屏,支持鸿蒙国产化

智能家居中控屏 智能家居中控屏功能 智能中控屏作为全屋智能解决方案中的重要组成部分&#xff0c;融合智能开关面板、智能音箱、万能遥控、可视对讲、智能网关等设备&#xff0c;用一块屏承担起联动控制、人机交互、信息显示、个性化服务等功能。 智能中控屏是智能家居控制管…

cesium 轨迹线

在智慧城市项目中&#xff0c;轨迹线一般用来表现城市道路的流动效果。和cesium动态线篇效果类似&#xff0c;只是这里是通过设置高亮占比&#xff0c;而不是通过传入一张图片。 1. 自定义TrialFlowMaterialProperty类 1.1. 自定义 TrialFlowMaterialProperty 类 /** Descri…

MES管理系统助力印刷企业实现智能化工艺流程

在印刷这一古老而充满活力的行业中&#xff0c;科技的浪潮正以前所未有的速度重塑着每一个生产环节。随着制造业数字化转型的深入&#xff0c;引入MES管理系统&#xff0c;为印刷企业带来了从原材料入库到成品出库的全流程智能化变革&#xff0c;不仅提升了生产效率&#xff0c…

基于SpringBoot+Vue+MySQL的网上商城系统

系统背景 随着社会的快速发展&#xff0c;计算机的影响是全面且深入的。人们生活水平的不断提高&#xff0c;日常生活中人们对网上商城购物系统方面的要求也在不断提高&#xff0c;购物的人数更是不断增加&#xff0c;使得网上商城购物系统的开发成为必需而且紧迫的事情。网上商…