当前位置: 首页 > ai >正文

dify + mcp 实现图片 ocr 识别

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.5</version><relativePath /></parent><groupId>com.example</groupId><artifactId>mcp-server</artifactId><version>0.0.1-SNAPSHOT</version><name>Spring AI MCP Weather Sample</name><description>Sample Spring Boot application demonstrating MCP client and server usage</description><properties><spring-cloud.version>2023.0.4</spring-cloud.version><java.version>17</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><maven.test.skip>true</maven.test.skip><easypoi.version>4.1.2</easypoi.version></properties><dependencyManagement><dependencies><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-bom</artifactId><version>1.1.0-SNAPSHOT</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.78</version></dependency><dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-base</artifactId><version>${easypoi.version}</version></dependency><dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-web</artifactId><version>${easypoi.version}</version></dependency><dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-annotation</artifactId><version>${easypoi.version}</version></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-mcp-server-webmvc</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.session</groupId><artifactId>spring-session-data-redis</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.session</groupId><artifactId>spring-session-core</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.6</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version></dependency><dependency><groupId>com.github.jsqlparser</groupId><artifactId>jsqlparser</artifactId><version>4.9</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>3.5.7</version></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>8.0.33</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.13.0</version><configuration><source>17</source><target>17</target></configuration></plugin></plugins></build><profiles><profile><id>dev</id><properties><profileActive>dev</profileActive></properties><activation><activeByDefault>true</activeByDefault></activation></profile><profile><id>test</id><properties><profileActive>test</profileActive></properties></profile></profiles><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><repository><id>central-portal-snapshots</id><name>Central Portal Snapshots</name><url>https://central.sonatype.com/repository/maven-snapshots/</url><releases><enabled>false</enabled></releases><snapshots><enabled>true</enabled></snapshots></repository></repositories>
</project>

application.yml:

server:port: 9090
spring:ai:mcp:server:version: 0.0.1name: my-weather-server#stdio: false#main:#  web-application-type: none#  banner-mode: offdatasource:driverClassName: com.mysql.jdbc.Driver#driverClassName: "com.mysql.cj.jdbc.Driver"type: "com.alibaba.druid.pool.DruidDataSource"initialSize: 1minIdle: 3maxActive: 40maxWait: 60000timeBetweenEvictionRunsMillis: 60000minEvictableIdleTimeMillis: 30000validationQuery: select 'x'testWhileIdle: truetestOnBorrow: falsetestOnReturn: falsepoolPreparedStatements: truemaxPoolPreparedStatementPerConnectionSize: 20filters: "slf4j,stat"connectionProperties: "druid.stat.mergeSql=true;druid.stat.slowSqlMillis=3000"profiles:active: @profileActive@logging:level:#org.springframework.boot: DEBUGorg.springframework.boot: INFO#com.baomidou: DEBUGcom.baomidou: INFOfile:name: ./model-context-protocol/weather/starter-webmvc-server/target/starter-webmvc-server.log#pattern:# 改配置会导致 spring 工程启动后控制台没任何输出#  console:mybatis-plus:mapper-locations: "classpath*:/mapper/*Mapper.xml"debug: true

application-dev.yml:

spring:datasource:url: jdbc:mysql://127.0.0.1:3306/gw_image_search?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNullusername: xxxpassword: xxx

BootApplication.java:

package com.xxx.ipark.base;import com.xxx.ipark.base.service.IOcrService;
import com.xxx.ipark.base.service.IUserService;
import com.xxx.ipark.common.config.datasource.DataSourceConfig;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.function.FunctionToolCallback;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.bind.ServletRequestUtils;@EnableAsync
@EnableTransactionManagement
@ComponentScan(basePackages = {"com.xxx.ipark"})
@SpringBootApplication(exclude = {RedisAutoConfiguration.class,MongoAutoConfiguration.class,MongoDataAutoConfiguration.class})
@EnableConfigurationProperties( DataSourceConfig.class )
@Slf4j
public class BootApplication {public static void main(String[] args) {try {System.setProperty("spring.devtools.restart.enabled", "false");System.setProperty("es.set.netty.runtime.available.processors","false");ConfigurableApplicationContext application = SpringApplication.run(BootApplication.class, args);System.out.println( "启动成功..." );Environment env = application.getEnvironment();String applicationName = env.getProperty("spring.application.name");String port = env.getProperty("server.port");String path = env.getProperty("server.servlet.context-path");String ip = "";log.info("\n----------------------------------------------------------\n" +"Application " + applicationName + " is running. Access URLs:\n" +"Local: http://localhost:" + port + path + "/\n" +"External: http://" + ip + ":" + port + path + "/\n" +"Swagger-UI: http://" + ip + ":" + port + path + "/swagger-ui.html\n" +"----------------------------------------------------------");} catch (Exception e) {log.error("", e);}}@Beanpublic ToolCallbackProvider userTools(IUserService userService) {return MethodToolCallbackProvider.builder().toolObjects(userService).build();}@Beanpublic ToolCallbackProvider ocrTools(IOcrService ocrService) {return MethodToolCallbackProvider.builder().toolObjects(ocrService).build();}public record TextInput(String input) {}@Beanpublic ToolCallback toUpperCase() {return FunctionToolCallback.builder("toUpperCase", (TextInput input) -> input.input().toUpperCase()).inputType(TextInput.class).description("Put the text to upper case").build();}}

DataSourceConfig.java:

package com.xxx.ipark.common.config.datasource;import com.alibaba.druid.pool.DruidDataSource;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.bind.ConstructorBinding;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;import javax.sql.DataSource;
import java.sql.SQLException;@Data
@Slf4j
@Configuration
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceConfig {private String name = "xxx";private String url;private String username;private String password;private String driverClassName;private int initialSize;private int minIdle;private int maxActive;private int maxWait;private int timeBetweenEvictionRunsMillis;private int minEvictableIdleTimeMillis;private String validationQuery;private boolean testWhileIdle;private boolean testOnBorrow;private boolean testOnReturn;private boolean poolPreparedStatements;private int maxPoolPreparedStatementPerConnectionSize;private String filters;private String connectionProperties;@Bean(name = "dataSource")@Primarypublic DataSource dataSource() {DruidDataSource datasource = new DruidDataSource();datasource.setName(name);datasource.setUrl(url);datasource.setUsername(username);datasource.setPassword(password);datasource.setDriverClassName(driverClassName);//configurationdatasource.setInitialSize(initialSize);datasource.setMinIdle(minIdle);datasource.setMaxActive(maxActive);datasource.setMaxWait(maxWait);datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);datasource.setValidationQuery(validationQuery);datasource.setTestWhileIdle(testWhileIdle);datasource.setTestOnBorrow(testOnBorrow);datasource.setTestOnReturn(testOnReturn);datasource.setPoolPreparedStatements(poolPreparedStatements);datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);try {datasource.setFilters(filters);} catch (SQLException e) {log.error("Druid initialize filter failed. ", e);}datasource.setConnectionProperties(connectionProperties);return datasource;}
}

MybatisConfig.java:

package com.xxx.ipark.common.config.datasource;import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;import javax.sql.DataSource;
import java.util.Properties;/*** Mybatis 配置文件,加入了分页器,分页器的使用:* com.github.pagehelper.PageHelper.startPage(1, 10);* List<User> list = mapper.queryUsers();* com.github.pagehelper.PageInfo<User> pagelist=new com.github.pagehelper.PageInfo<User>(list);* pageList 封装了分页列表以及其他分页相关的所有信息*/
@Configuration( proxyBeanMethods = false )
@EnableTransactionManagement
@AutoConfigureAfter({DataSourceConfig.class})
public class MybatisConfig {private static final Logger logger = LoggerFactory.getLogger(MybatisConfig.class);@Bean(name = "sqlSessionFactoryBean")public SqlSessionFactory sqlSessionFactoryBean(@Qualifier("dataSource") DataSource dataSource) {try {//SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(dataSource);// 必须添加类型别名包扫描sqlSessionFactoryBean.setTypeAliasesPackage("com.xxx.ipark.base.entity");//org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();MybatisConfiguration configuration = new MybatisConfiguration();configuration.setJdbcTypeForNull(JdbcType.NULL);configuration.setMapUnderscoreToCamelCase(true);configuration.setCacheEnabled(false);sqlSessionFactoryBean.setConfiguration(configuration);// sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(environment.getProperty("mybatis-plus.mapper-locations")));sqlSessionFactoryBean.setMapperLocations( new PathMatchingResourcePatternResolver().getResources( "classpath*:/mapper/*Mapper.xml" ) );Interceptor[] plugins = { this.mybatisPlusInterceptor() };sqlSessionFactoryBean.setPlugins(plugins);return sqlSessionFactoryBean.getObject();} catch (Exception e) {logger.error("", e);}return null;}@Bean(name = "transactionManager")public DataSourceTransactionManager testTransactionManager(@Qualifier("dataSource") DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}@Beanpublic MapperScannerConfigurer mapperScannerConfigurer() {MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactoryBean");mapperScannerConfigurer.setBasePackage("com.xxx.ipark.*.mapper");return mapperScannerConfigurer;}@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}
}

CorsConfig.java:

package com.xxx.ipark.common.config;import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;// 全局配置类
@Configuration
public class CorsConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {// registry.addMapping("/sse/**")  // 匹配 SSE 端点registry.addMapping("/**")  // 匹配 SSE 端点.allowedOrigins("http://localhost:63342")  // 客户端域名.allowedMethods("GET", "POST").allowCredentials(true)  // 允许凭证(如 Cookies).exposedHeaders("Content-Type", "X-Custom-Header");  // 暴露自定义头}
}

IOcrService.java:

package com.xxx.ipark.base.service;import com.xxx.ipark.base.entity.UserEntity;public interface IOcrService {String driversLicenseOcr( String driversLicenseImageUrl );
}

OcrServiceImpl.java:

package com.xxx.ipark.base.service.impl;import com.xxx.ipark.base.entity.UserEntity;
import com.xxx.ipark.base.service.IOcrService;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.stereotype.Service;@Service
public class OcrServiceImpl implements IOcrService {@Tool( description = "个人驾驶证图片ocr识别(该方法请求参数 driversLicenseImageUrl 是 String 类型,表示用户上传的驾驶证的图片的 url 地址)")@Overridepublic String driversLicenseOcr(String driversLicenseImageUrl) {// todo 换成调用大厂的 ocr apiSystem.out.println( "call driversLicenseOcr with param driversLicenseImageUrl = " + driversLicenseImageUrl );return "驾驶员姓名:张三风,驾照生效开始日期:2024-01-01,驾照生效结束日期:2025-01-01,车牌号:京A-88888";}
}

dify 上安装如下所示的 mcp 工具和 agent 策略插件:

dify 开始节点:

dify agent 节点-part1:

dify agent 节点-part2:

结束节点:

完整工作流概览:

测试:

输出:

返回的是我们代码里 mock 的数据,可以修改下代码,调用大厂的 ocr 接口。

下面我们换成直接调用百度的个人证照识别的 mcp 服务:

例如使用百度的 个人证照识别 mcp 服务

 将dify 工作流中的 mcp 地址换成 如下:

 {"server_name": {"url": "https://aip.baidubce.com/mcp/ocr_personal_card/sse?Authorization=Bearer%20xxxxxxxxxxxxxx","headers": {"Content-Type":"application/json"},"timeout": 50,"sse_read_timeout": 50}
}

测试后结果如下:

应该通了,这个是百度ocr接口返回的错误信息。

查看 agent 节点的详细输出:

 

拷贝出来发现包含如下信息:

"<think>\n\n好的,用户上传了一个驾驶证图片的URL,需要我来处理。首先,我要确定用户的需求是什么。他们可能想通过OCR识别驾驶证上的信息,比如姓名、证号、有效期等。根据提供的工具列表,ocr_driving_license  这个函数是专门用来处理驾驶证的。\n\n接下来,我需要检查这个函数的参数。ocr_driving_license的参数包括image、url、detect_direction、driving_license_side等。用户提供的只是一个URL,所以应该使用url参数。需要注意的是,当image存在时,url会被忽略,但这里用户只给了URL,没有提供image数据,所以应该正确传递url参数。\n\n然后,确认其他参数是否有默认值。例如,driving_license_side默认是front,即识别正页。如果用户提供的图片是副页,可能需要调整这个参数,但用户没有说明,所以保持默认。同样,detect_direction默认是false,不检测方向,除非用户提到图片可能旋转,但这里也没有相关信息,所以保持默认。\n\n还要注意函数的限制条件,比如URL对应的图片大小不能超过10M,分辨率符合要求。用户提供的URL看起来是有效的,所以直接调用函数即可。不需要其他参数,除非用户有特殊要求,但这里没有提到,所以只需要传递url参数。\n\n综上所述,调用ocr_driving_license函数,参数中填入提供的URL,其他参数使用默认值。这样就能正确识别驾驶证的信息返回给用户了。\n\n</think>\n\n<think>\n\n好的,用户刚才上传了一个驾驶证图片的URL,我调用了ocr_driving_license工具来处理。但是返回了一个错误,说QPS请求限制达到了。现在需要想想怎么解决这个问题。\n\n首先,用户的需求是识别驾驶证图片,所以必须找到其他方法来处理。可能的问题在于当前使用的工具访问量太大,被限制了。这时候应该看看有没有其他类似功能的工具可以使用。例如,如果用户可以上传图片数据而不是URL的话,或者如果有备用的API端点,或者是否有其他服务可以处理。\n\n检查可用的工具列表,有没有其他相关的OCR功能。比如,用户有提到过是否还有其他工具支持驾驶证识别。例如,可能还有另一个版本的OCR驾驶执照工具,或者是否有其他类似的工具。不过根据原先提供的工具列表里,ocr_driving_license似乎是唯一的驾驶证识别工具。\n\n这时候可能需要考虑是否可以直接让用户将图片转换为base64并再次尝试调用,但用户目前是通过URL提交的,所以可能需要更替其他方式,但用户可能无法立即提供base64编码的数据。或者是否可以设置一个服务器配置(servers_config)来指定备用服务,但工具的具体参数可能需要进一步确认。\n\n查看mcp_sse_call_tool的参数,需要tool_name和arguments。是否有其他工具名称可以调用?例如是否有备用的路径或不同的服务实例。或者是否可以汇总其他工具,但用户已经看到提供的工具中并没有其他驾驶证工具。所以可能需要告知用户当前达到限流,需要重试或联系管理员处理。但如果用户需要即时解决,可能需要其他途径,例如更换API配置,但缺乏相关参数。\n\n可能的话,可以尝试调用其他可用工具吗?比如是否有其他支持驾驶证的OCR服务,但根据给定的工具列表中没有其他工具。这时候,可能需要向用户说明无法继续,并建议稍后再试或检查他们的上传方式是否有误。也可能用户需要切换到base64上传,但用户可能无法立即处理。\n\n因此,最终的回应应该是告知用户当前系统达到请求上限,建议稍后再试,或者由他们提供base64编码的图片数据以便使用备用方法。不过根据用户目前的情况,可能无法提供更多数据,所以应该确认错误并提供相关的解决方案。\n\n</think>\n\n当前识别服务达到请求上限,请稍后再试或联系管理员提升配额。若需立即处理,可提供证件头像区域截图或base64编码,我将尝试调用备用通道进行识别。",

可以看出大模型思考过程中说 "ocr_driving_license  这个函数是专门用来处理驾驶证的",函数 "ocr_driving_license  " 在百度个人证照识别下确实存在,如下所示:

进入 ocr_driving_license(驾驶证识别) 的文档:

发现大模型思考过程中对 ocr_driving_license函数如下所示的分析: 

ocr_driving_license 的参数包括image、url、detect_direction、driving_license_side等。
用户提供的只是一个URL,所以应该使用url参数。
需要注意的是,当image存在时,url会被忽略,但这里用户只给了URL,没有提供image数据,所以应该正确传递url参数。
\n\n然后,确认其他参数是否有默认值。例如,driving_license_side默认是front,即识别正页。
如果用户提供的图片是副页,可能需要调整这个参数,但用户没有说明,所以保持默认。
同样,detect_direction默认是false,不检测方向,除非用户提到图片可能旋转,但这里也没有相关信息,所以保持默认。
\n\n还要注意函数的限制条件,比如URL对应的图片大小不能超过10M,分辨率符合要求。
用户提供的URL看起来是有效的,所以直接调用函数即可。

也基本符合驾驶证识别接口的请求参数说明,这就证明是调通了,只是没配额了。有条件的可以充值测试一下。

http://www.xdnf.cn/news/16538.html

相关文章:

  • 实例教学FPN原理与PANet,Pytorch逐行精讲实现
  • [leetcode] Z字型变换
  • dify离线插件打包步骤
  • 手撕设计模式——智能家居之外观模式
  • C++线程详解
  • C++11 std::function 详解:通用多态函数包装器
  • 从0开始学习R语言--Day62--RE插补
  • 【ssh】ubuntu服务器+本地windows主机,使用密钥对进行ssh链接
  • Linux常用基础命令
  • 反射核心:invoke与setAccessible方法详解
  • Git 从入门到精通
  • linux命令ps的实际应用
  • SQL注入SQLi-LABS 靶场less26-30详细通关攻略
  • 深入解析Java元注解与运行时处理
  • ​第七篇:Python数据库编程与ORM实践
  • 前缀和-974.和可被k整除的子数组-力扣(LeetCode)
  • [mcp: JSON-RPC 2.0 规范]
  • 机器学习之线性回归——小白教学
  • LRU(Least Recently Used)原理及算法实现
  • 最新优茗导航系统源码/全开源版本/精美UI/带后台/附教程
  • BreachForums 黑客论坛强势回归
  • sqLite 数据库 (2):如何复制一张表,事务,聚合函数,分组加过滤,列约束,多表查询,视图,触发器与日志管理,创建索引
  • JAVA_TWENTY—ONE_单元测试+注解+反射
  • 学习Python中Selenium模块的基本用法(3:下载浏览器驱动续)
  • Seq2Seq学习笔记
  • 前端优化之虚拟列表实现指南:从库集成到手动开发
  • 嵌入式学习日志————TIM定时中断之定时器定时中断
  • Python算法实战:从排序到B+树全解析
  • 算法精讲:二分查找(一)—— 基础原理与实现
  • 自学嵌入式 day37 HTML