Dart笔记:build_runner-用于 Dart 代码生成和模块化编译的构建系统
作者:李俊才 (jcLee95):https://blog.csdn.net/qq_28550263
邮箱 :291148484@163.com
本文地址:https://blog.csdn.net/qq_28550263/article/details/134356076
【简介】build_runner 库是一个用于自动化代码生成的工具。文章首先解释了build_runner的用途和安装方法,然后详细介绍了其内置命令、选项以及输入和输出的处理方式。文章还通过两个实例(json_serializable和Floor ORM框架)展示了如何在实际项目中使用build_runner来自动生成代码。
目 录
1. 概述
2.1 build_runner 用于解决什么问题
build_runner
库是为了解决 Dart 和 Flutter 中代码生成的问题而创建的,用于生成代码。代码生成是一种常见的编程技术,它可以帮助开发者自动化一些重复或模板化的编程任务,从而提高开发效率和代码质量。
在 Dart 和 Flutter 中,有许多场景可能需要使用到代码生成。例如:
-
序列化 和 反序列化:对于复杂的数据结构,手动编写序列化和反序列化的代码可能会非常繁琐和容易出错。通过使用代码生成,我们可以自动地为数据结构生成序列化和反序列化的代码。
-
ORM(对象关系映射):在处理数据库时,我们通常需要将数据库中的表映射到Dart的对象。这个映射过程可以通过代码生成来自动化。
-
依赖注入:依赖注入是一种常见的设计模式,它可以帮助我们更好地组织和管理代码中的依赖关系。通过使用代码生成,我们可以自动地为依赖注入生成所需的代码。
然而,代码生成也有其挑战。其中一个主要的挑战是 处理文件和依赖关系。例如,当一个文件发生变化时,我们可能需要重新生成依赖于这个文件的所有其他文件的代码。build_runner 提供一个强大且灵活的方式来管理和自动化代码生成过程中的文件和依赖关系。
2.2 build_runner 的安装
使用 build_runner,你需要在你的 pubspec.yaml
文件中添加指定版本的 build_runner 作为开发依赖项。需要指出的是,通常,将它放在pubspec.yaml的dev_dependencies下:
dev_dependencies:build_runner:
然后,你可以在命令行中运行build_runner:
dart run build_runner build
这将运行所有配置的生成器,并将生成的代码输出到指定的目录。
注:当提供构建器的包通过 build.yaml 文件配置时,它们被设计为使用生成的构建脚本进行消费。大多数构建器应该需要很少或不需要配置,具体取决于构建器的文档。如果你需要将web代码编译为js,需要在 dev_dependencies 中添加 build_web_compilers。
2. build_runner 的用法介绍
2.1 内置命令和选项
除了 build
命令外, build_runner还提供了其它的内置命令,如 watch
、serve
等。其中:
命令 | 描述 |
---|---|
build | 运行一次构建并退出 |
watch | 运行一个持久的构建服务器,监视文件系统的编辑并在必要时进行重建 |
serve | 与 watch 相同,但同时运行一个开发服务器。默认情况下,它在 8080 和 8081 端口上分别提供 web 和 test 目录 |
test | 运行一次构建,创建一个合并的输出目录,然后运行 dart run test --precompiled <merged-output-dir> |
所有这些命令都支持以下选项:
选项 | 描述 |
---|---|
--help | 打印帮助信息 |
--delete-conflicting-outputs | 假设用户包中的冲突输出来自之前的构建,并跳过通常提供的用户提示 |
--[no-]fail-on-severe | 是否在记录错误时将构建视为失败。 默认情况下,为 false |
--build-filter | 构建过滤器允许你明确选择要构建的文件,而不是构建整个目录 |
2.2 输入和输出
输入
在Dart中,一个包(package)是包含一组相关Dart代码的目录。有效的输入遵循一般的Dart包规则,一个标准的Dart包通常会有如下的目录结构:
- lib:这个目录包含了包的公共代码。其他包可以导入这个目录下的Dart文件。
- test:这个目录包含了包的测试代码。
- example:这个目录包含了包的示例代码。
- bin:这个目录包含了包的可执行脚本。
有效的输入遵循一般的Dart包规则。
build_runner 可以从任何包依赖项的顶级 lib
文件夹下读取任何文件,也可以从当前包读取所有文件。这个映射定义了构建器(Builder)如何处理输入文件并生成输出文件。所有匹配此映射中任何键的输入源都将作为构建步骤传递给此构建器。只有具有相同基本名和来自此映射值的扩展名的文件才被期望作为输出。
一般来说,最好尽可能具体地指定你的输入集,因为所有匹配的文件都将根据构建器的 buildExtensions 进行检查。
【注】:
buildExtensions
是 Builder类(build库) 的一个属性,它是一个从输入文件扩展名到输出文件扩展名的映射。 例如,如果你有一个将.txt文件转换为.md和.html文件的构建器,那么你的buildExtensions可能如下:const buildExtensions = {'.txt': ['.md', '.html'], };
这意味着,对于每一个
.txt
文件,这个构建器都会生成一个对应的.md
文件和一个.html
文件。
如果存在一个空的键,那么所有的输入都被视为匹配。构建器的实例必须始终返回相同的配置。通常,构建器会返回一个常量映射。构建器也可以根据BuilderOptions选择扩展。
输出
你可以在当前包的任何地方输出文件。构建器不允许覆盖现有文件,只能创建新文件。先前构建的输出不会被视为后续构建的输入。
源代码控制
build_runner 会在你的包的顶级目录下创建一个 .dart_tool
文件夹,这个文件夹不应该提交到你的源代码控制仓库。对于生成的文件,通常最好不要提交它们到源代码控制,但是特定的构建器可能会提供其他的建议。
如果你将生成的文件提交到你的仓库,那么当你切换分支或合并更改时,你可能会在下一次构建时收到关于已存在的声明输出的警告。这将跟随一个提示删除这些文件的提示。你可以输入 l
来列出文件,然后如果一切看起来正确,可以输入 y
来删除它们。如果你认为有什么不对,你可以输入 n
来放弃构建,而不采取任何行动。
3. 应用举例:json_serializable
例如有一个用于生成 JSON 序列化代码的构建器。你可以使用 build_runner 来运行这个构建器,生成序列化代码。
在 Dart 中,我们经常使用 json_serializable 包来自动生成 JSON 序列化和反序列化的代码。这个包提供了一个构建器,我们可以使用 build_runner 来运行这个构建器。
其中:
- json_serializable 提供用于处理 JSON 的Dart 构建系统构建器。
你需要在你的模型类上添加 @JsonSerializable() 注解,并定义 fromJson 和 toJson 方法。然后,json_serializable 构建器会自动为你生成这些方法的实现; - build_runner 用于在 Dart 项目中运行构建器(可以使用 build_runner 来运行任何构建器,包括这里的 json_serializable 提供的构建器,build_runner会找到所有可用的构建器,并按照它们的配置运行它们。)。
也就是说,json_serializable 负责定义如何生成代码,而 build_runner 负责运行 json_serializable 构建器并将生成的代码写入到文件中。
接下来看一下具体的过程。首先安装到依赖:
dependencies:json_annotation: ^4.8.1dev_dependencies:build_runner: ^2.4.6json_serializable: ^6.1.4
然后,你可以定义一个 Model 类(数据模型),并使用 json_serializable 的注解:
import 'package:json_annotation/json_annotation.dart';// 这行是必须的,示user_model.dart文件是一个库的一部分
// 而 user_model.g.dart 文件是这个库的另一部分
part 'user_model.g.dart';()
class UserModel {final String name;final String email;UserModel(this.name, this.email);factory UserModel.fromJson(Map<String, dynamic> json) =>_$UserModelFromJson(json);Map<String, dynamic> toJson() => _$UserModelToJson(this);
}
其中,_$UserFromJson 和 _$UserToJson 是由 json_serializable
生成的函数,它们用于将 JSON 数据转换为 UserModel 对象,以及将User对象转换为JSON数据。
接着,在项目下运行 build_runner 的 build 命令来生成序列化代码:
dart run build_runner build
这将会生成一个对应的 user_model.g
文件,这个文件包含了 _$UserFromJson 和 _$UserToJson 的实现。生成的对应的 user_model.g.dart 的代码如下:
// GENERATED CODE - DO NOT MODIFY BY HANDpart of 'user_model.dart';// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************UserModel _$UserModelFromJson(Map<String, dynamic> json) => UserModel(json['name'] as String,json['email'] as String,);Map<String, dynamic> _$UserModelToJson(UserModel instance) => <String, dynamic>{'name': instance.name,'email': instance.email,};
4. 应用举例:在 Floor (ORM框架)中自动生成数据库代码
可以参考博文 《用于ORM的Floor框架》,地址:https://jclee95.blog.csdn.net/article/details/133377191
首先,你需要在pubspec.yaml文件中添加floor,floor_generator和build_runner的依赖。floor是运行时依赖,floor_generator和build_runner是开发时依赖。你的pubspec.yaml文件应该像这样:
dependencies:flutter:sdk: flutterfloor: ^1.4.2sqflite: ^2.3.0dev_dependencies:floor_generator: ^1.4.2build_runner: ^2.1.2
然后,运行flutter pub get命令来获取这些依赖。
接着创建实体:定义一个类,使用 @entity
注解标记这个类,这个类将会映射到数据库的一个表。使用 @primaryKey
注解标记主键。例如:
// person_entity.dart
import 'package:floor/floor.dart';
class PersonEntity {final int id;final String name;PersonEntity(this.id, this.name);
}
接下来创建DAO文件,定义一个抽象类,使用@dao注解标记这个类。在这个类中,你可以定义查询数据库的方法。使用@Query注解定义查询语句,使用@insert注解定义插入方法。例如:
// person_dao.dart
import 'package:floor/floor.dart';
import 'person_entity.dart';
abstract class PersonDao {('SELECT * FROM Person')Future<List<PersonEntity>> findAllPeople();Future<void> insertPerson(PersonEntity person);
}
接下来,你需要定义一个数据库类,这个类需要继承 FloorDatabase,并使用@Database注解。在这个类中,你可以定义获取PersonDao的方法。例如:
import 'package:floor/floor.dart';import 'person_dao.dart';
import 'person_entity.dart';part 'app_database.g.dart'; // 生成的代码会在那里(version: 1, entities: [PersonEntity])
abstract class AppDatabase extends FloorDatabase {PersonDao get personDao;
}
然后,你可以运行命令来生成数据库操作的代码:
dart run build_runner build
可以看到,在同一个目录下生成了一个名为 app_database.g.dart 的文件,生成的内容如下:
// GENERATED CODE - DO NOT MODIFY BY HANDpart of 'app_database.dart';// **************************************************************************
// FloorGenerator
// **************************************************************************// ignore: avoid_classes_with_only_static_members
class $FloorAppDatabase {/// Creates a database builder for a persistent database./// Once a database is built, you should keep a reference to it and re-use it.static _$AppDatabaseBuilder databaseBuilder(String name) =>_$AppDatabaseBuilder(name);/// Creates a database builder for an in memory database./// Information stored in an in memory database disappears when the process is killed./// Once a database is built, you should keep a reference to it and re-use it.static _$AppDatabaseBuilder inMemoryDatabaseBuilder() =>_$AppDatabaseBuilder(null);
}class _$AppDatabaseBuilder {_$AppDatabaseBuilder(this.name);final String? name;final List<Migration> _migrations = [];Callback? _callback;/// Adds migrations to the builder._$AppDatabaseBuilder addMigrations(List<Migration> migrations) {_migrations.addAll(migrations);return this;}/// Adds a database [Callback] to the builder._$AppDatabaseBuilder addCallback(Callback callback) {_callback = callback;return this;}/// Creates the database and initializes it.Future<AppDatabase> build() async {final path = name != null? await sqfliteDatabaseFactory.getDatabasePath(name!): ':memory:';final database = _$AppDatabase();database.database = await database.open(path,_migrations,_callback,);return database;}
}class _$AppDatabase extends AppDatabase {_$AppDatabase([StreamController<String>? listener]) {changeListener = listener ?? StreamController<String>.broadcast();}PersonDao? _personDaoInstance;Future<sqflite.Database> open(String path,List<Migration> migrations, [Callback? callback,]) async {final databaseOptions = sqflite.OpenDatabaseOptions(version: 1,onConfigure: (database) async {await database.execute('PRAGMA foreign_keys = ON');await callback?.onConfigure?.call(database);},onOpen: (database) async {await callback?.onOpen?.call(database);},onUpgrade: (database, startVersion, endVersion) async {await MigrationAdapter.runMigrations(database, startVersion, endVersion, migrations);await callback?.onUpgrade?.call(database, startVersion, endVersion);},onCreate: (database, version) async {await database.execute('CREATE TABLE IF NOT EXISTS `PersonEntity` (`id` INTEGER NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY (`id`))');await callback?.onCreate?.call(database, version);},);return sqfliteDatabaseFactory.openDatabase(path, options: databaseOptions);}PersonDao get personDao {return _personDaoInstance ??= _$PersonDao(database, changeListener);}
}class _$PersonDao extends PersonDao {_$PersonDao(this.database,this.changeListener,) : _queryAdapter = QueryAdapter(database),_personEntityInsertionAdapter = InsertionAdapter(database,'PersonEntity',(PersonEntity item) =><String, Object?>{'id': item.id, 'name': item.name});final sqflite.DatabaseExecutor database;final StreamController<String> changeListener;final QueryAdapter _queryAdapter;final InsertionAdapter<PersonEntity> _personEntityInsertionAdapter;Future<List<PersonEntity>> findAllPeople() async {return _queryAdapter.queryList('SELECT * FROM Person',mapper: (Map<String, Object?> row) =>PersonEntity(row['id'] as int, row['name'] as String));}Future<void> insertPerson(PersonEntity person) async {await _personEntityInsertionAdapter.insert(person, OnConflictStrategy.abort);}
}
可以看出,你可能需要手动在app_database.dart导入一些库,一般依据编辑器提示补上就可以:
import 'dart:async';
import 'package:sqflite/sqflite.dart' as sqflite;
在这个生成的文件中,可以看到:
$FloorAppDatabase
:这个类提供了创建AppDatabase实例的方法。你可以使用databaseBuilder方法来创建一个持久化的数据库,或者使用inMemoryDatabaseBuilder方法来创建一个内存数据库。_$AppDatabaseBuilder
:这个类用于构建AppDatabase实例。你可以使用addMigrations方法来添加数据库迁移,使用addCallback方法来添加数据库回调。_$AppDatabase
:这个类是AppDatabase类的实现。它包含了一个PersonDao实例,你可以使用这个实例来操作数据库。_$PersonDao
:这个类是PersonDao接口的实现。它包含了findAllPeople和insertPerson方法的实现,这些方法用于查询和插入数据。
最后,就可以使用生成的 $FloorAppDatabase
类来获取数据库实例,并使用这个实例来操作数据库了。例如:
final database = await $FloorAppDatabase.databaseBuilder('app_database.db').build();
final personDao = database.personDao;
final person = PersonEntity(1, 'Frank');
await personDao.insertPerson(person);
final result = await personDao.findAllPeople();
相关文章:
Dart笔记:build_runner-用于 Dart 代码生成和模块化编译的构建系统
Dart笔记 build_runner 用于 Dart 代码生成和模块化编译的构建系统 作者:李俊才 (jcLee95):https://blog.csdn.net/qq_28550263 邮箱 :291148484163.com 本文地址:https://blog.csdn.net/qq_28550263/artic…...
Ubuntu显示毫秒级时间
Ubuntu显示毫秒级时间 1. 打印当前时间 1. 打印当前时间 date 时间,转化成毫秒级 $ date # Mon 03 Apr 2023 11:09:47 PM CST$ echo -e "$(date %T).$((10#$(date %N)/1000000))" # 23:09:55.552谢谢...

模板——“C++”
各位CSDN的uu们你们好呀,今天,小雅兰的内容是C中的模板初阶的内容,下面,让我们进入C模板的世界吧!!! 1. 泛型编程 2. 函数模板 3. 类模板 泛型编程 如何实现一个通用的交换函数呢?…...

分类预测 | Matlab实现PSO-BiLSTM粒子群算法优化双向长短期记忆神经网络的数据多输入分类预测
分类预测 | Matlab实现PSO-BiLSTM粒子群算法优化双向长短期记忆神经网络的数据多输入分类预测 目录 分类预测 | Matlab实现PSO-BiLSTM粒子群算法优化双向长短期记忆神经网络的数据多输入分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现PSO-BiLSTM粒子…...

Spring面试题:(六)Spring注解开发原理
ioc过程 发现只要将bean注册到BeanDefinitionMap中就可以创建bean对象 如何将xml配置的bean注册到BeanDefinitionMap 通过注解注册的bean过程一样 注册bean的接口:BeanDefinitionRegistryPostProcessor 开启组件扫描的两种方式:xml和注解 xml方式…...

ROS基础知识复习
【置顶】感谢参考:https://zhuanlan.zhihu.com/p/662074088 0.背景 工作一年多没有做 ROS 相关的开发了,最近找工作想做回这一块来,根据参考内容,抽时间给这边的基础知识敲一遍复习一下 1.环境检查 打开了之前的笔记本&#x…...

2390 高校实验室预约系统JSP【程序源码+文档+调试运行】
摘要 本文介绍了一个高校实验室预约系统的设计和实现。该系统包括管理员、教师和学生三种用户,具有基础数据管理、学生管理、教师管理、系统公告管理、实验室管理、实验室预约管理和系统管理等模块。通过数据库设计和界面设计,实现了用户友好的操作体验…...

C++进阶篇4---番外-红黑树
一、红黑树的概念 红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或 Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路 径会比其他路径长出俩倍࿰…...

《网络协议》05. 网络通信安全 · 密码技术
title: 《网络协议》05. 网络通信安全 密码技术 date: 2022-09-10 15:16:15 updated: 2023-11-12 07:03:52 categories: 学习记录:网络协议 excerpt: 网络通信安全(ARP 欺骗,DoS & DDoS,SYN 洪水攻击,LAND 攻击&a…...

通信信道:无线信道中衰落的类型和分类
通信信道:无线信道中衰落的类型和分类 在进行通信系统仿真时,简单的情况下选择AWGN信道,但是AWGN信道和真是通信中的信道相差甚远,所以需要仿真各种其他类型的信道,为了更清楚理解仿真信道的特点,首先回顾…...

4.HTML网页开发的工具
4. 网页开发的工具 4.1 快捷键 4.1.1 快速复制一行 快捷键:shiftalt下箭头(上箭头) 或者ctrlc 然后 ctrlv 4.1.2 选定多个相同的单词 快捷键: ctrld 4.1.3 添加多个光标 快捷键:ctrlalt上箭头(下箭头&…...
【Qt5 VS2019 (C++)编译报错解决】ASSERT failure in QList<T>::at: “index out of range“
Qt编译报错提示: ASSERT failure in QList<T>::at: "index out of range", file C:\Qt5\5.15.2\msvc2019_64\include\QtCore/qlist.h, line 571 //load 1st imageQFileInfo fileInfo1 list.at(2);原因: QList的索引越界,超…...
linux环境安装redis,以及常用的操作
1. 下载安装文件 http://download.redis.io/releases/redis-5.0.7.tar.gz 2. 把安装文件上传到 /usr/local/ 目录,并解压缩 tar -zvxf redis-5.0.7.tar.gz 3. 重命名文件夹 mv redis-5.0.7/ redis/ 4. 进入 /usr/local/redis/ 进行编译和安装 make make PREF…...

C++ Qt 学习(六):Qt http 编程
1. http 基础 HTTP 基础教程C Web 框架 drogonoatpp 2. C Qt 用户登录、注册功能实现 login_register.h #pragma once#include <QtWidgets/QDialog> #include "ui_login_register.h" #include <QNetworkReply>class login_register : public QDialog…...

38 路由的过滤器配置
3.3.断言工厂 我们在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件 例如Path/user/**是按照路径匹配,这个规则是由 org.springframework.cloud.gateway.handler.predicate.PathRoute…...

3分钟带你了解前端缓存-HTTP缓存
前情提要 前端缓存分为下面三大类,本文主要讲解HTTP缓存~ 1. HTTP缓存 强缓存协商缓存 2. 浏览器缓存 本地小容量缓存本地大容量缓存 3. 应用程序缓存 HTML5应用程序缓存 缓存作用 减少了冗余的数据传输减少服务器的负担提高了网站的性能加快加载网页速度 …...

【多线程 - 03、线程的生命周期】
生命周期 当线程被创建并启动以后,它不是一启动就进入执行状态,也不会一直处于执行状态,而是会经历五种状态。 线程状态的五个阶段: 新建状态(New)就绪状态(Runnable)运行状态&…...

excel表的筛选后自动求和
一般都使用subtotal函数。 通过看一个大佬的视频,发现可以有更简单的方法。 首先任意筛选数据(ctrlshiftl), 然后选中需要求和的列的最下方的空白单元格,再按alt。 回车即可。 实质它还是用的subtotal函数...
2311rust特征
Rust无成本抽象 Rust中抽象基石是trait: 1,Trait是Rust中唯一的接口概念.多个类型可实现一个特征,事实上,可为现有类型提供新的特征实现.另一方面,想抽象未知类型时,找特征就行了. 2,与C模板一样,可静态分发特征. 3,可动态分发特征.有时确实需要间接,所以不必运行时"擦除…...

原型模式 rust和java的实现
文章目录 原型模式介绍优点缺点使用场景 实现java 实现rust 实现 rust代码仓库 原型模式 原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。 这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...

Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...

srs linux
下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935,SRS管理页面端口是8080,可…...

Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...