news 2026/9/28 16:28:10

CLI-Anything:插件化命令行框架,让重复运维工作自动化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CLI-Anything:插件化命令行框架,让重复运维工作自动化

先说说我为什么折腾这个项目。干了这么多年开发和运维,我最深的感受就是:GUI 操作是给“人”看的,命令行操作是给“效率”用的。打开图形界面点十个按钮才能完成的事,命令行一句话就做完了。但现实问题是,日常工作中的需求太杂——批量重命名、日志分析、配置查找、系统巡检、定时备份……每一个都单独写脚本,维护成本极高;不写脚本,又得一次次手工操作,重复劳动让人烦躁。

所以我自己搭了一个轻量级的命令行框架,名字就叫CLI-Anything。它不是一个具体的单一工具,而是一个“插件式”的命令行入口:你可以把任意操作封装成模块,统一通过一条命令来调用,并且支持全局参数、配置文件、dry-run 预览、输出格式切换这些工程化能力。说白了,就是把“一切皆文件”的 Unix 哲学,平移成“一切皆命令”。

这篇文章我会把这套框架从思路、架构、核心实现到高频场景的完整写法都摊开讲,也包括我踩过的坑。如果你也经常被重复的零碎任务困扰,又不想为每个小需求写一堆互不相干的脚本,这篇内容应该能帮你省下不少时间。

1. 项目定位:为什么需要一个“什么都能干”的命令行框架

1.1 先想清楚:CLI 到底解决了什么问题

很多人对命令行的印象停留在“黑窗口里敲命令”,觉得那是上古时代的产物。但实际工作中,只要你面对的是批量、重复、需要被脚本自动化的任务,CLI 的效率优势是碾压级的。举个最直观的对比:你想把某个目录下几百个文件按日期重命名,用鼠标操作得一个一个来,或者靠第三方软件;而命令行只需要一条指令,还能同时加上“先预览、再执行、出错回滚”的保护机制。

我最初做 CLI-Anything 的动机,其实来自一次非常糟糕的经历:当时我要在十几台服务器上分别执行日志筛选、目录清理和配置备份,手头有旧的 shell 脚本、有 Python 脚本、还有一堆临时拼出来的命令。结果就是:参数记不住、输出格式对不上、有的机器还没装对应环境。那之后我意识到——缺的不是某个具体脚本,而是一个统一的、可扩展的命令入口。只要把任务封装成模块,剩下的就是记一条命令的事。

1.2 CLI-Anything 的核心定位

这个项目要解决的痛点可以归纳成三句话:

  • 任务入口统一:不管底层是 Node.js、Python、shell 还是调用外部工具,对外都统一成anything <command> [options]。
  • 模块可插拔:增加新能力不需要改框架本体,放一个模块文件进去就能被自动识别加载。
  • 输出和参数规范化:所有模块共用同一套参数解析、配置加载、日志输出、错误处理机制,避免每个脚本各自为政。

适合用 CLI-Anything 的人,我觉得主要分两类:一类是跟我一样的开发运维,每天大量处理文件、日志、进程、定时任务;另一类是产品、运营、数据分析这类“准技术”岗位,经常要做批量文本处理、数据格式转换、定时抓取——只要会写最基础的命令规则,就能把重复劳动固化成自己的工具箱。

1.3 常见方案的对比:为什么不自已写一个个单独的脚本

我知道有人会说:我直接写一个 shell 脚本不就得了?是的,脚本能解决单次问题。但当你积累到十几个脚本的时候,你就会面临几个新麻烦:

维度零散脚本CLI-Anything
参数处理每个脚本自己解析,规则混乱统一解析,支持全局参数和配置文件
输出格式有的输出文本,有的输出 JSON,没法直接对接下游统一支持 text / json / table 切换
错误处理崩了就是崩了,没有统一日志统一的错误码、日志级别、堆栈输出
可扩展性每次加功能都要复制脚本改参数新增模块文件即插即用
自动化对接难以嵌入更大流程输出可机读(JSON),命令可组合调用

所以 CLI-Anything 本质上不是重复造轮子,而是给“零散脚本”加了一层统一骨架。到后期你会发现,积累的模块本身就是你的个人知识库,新机器的环境初始化,只需要同步一个配置文件加一个模块目录。

2. 整体架构与设计思路:一切皆命令,但要守规矩

2.1 命令分发模型:anything <module> <action>

CLI-Anything 的命令模型我设计成了二级结构:模块 + 动作。模块是一个功能域,动作是该功能域下的具体操作。

anything <module> <action> [options]

举个例子:

anything file batch-rename --from "img_(\d+).png" --to "photo_$1.png" --path ./photos --dry-run anything analyze log --file app.log --level ERROR --top 20 anything sys collect --output json --save report.json anything schedule add --cron "0 2 * * *" --cmd "anything backup run --path ./data"

这样的好处是:命令的语义非常清晰,而且为后续自动补全、文档生成、配置校验提供了稳定的解析基础。很多人写 CLI 工具容易犯的一个错误是,把所有功能堆成一个个扁平的长命令,比如anything-batch-rename-with-regex-and-preview,参数又多又难记。拆成模块 + 动作之后,光靠anything --help就可以逐层探索能力,不用死记硬背。

2.2 插拔式模块加载:约定优于配置

模块加载我采用了一个极简约定:每个模块是一个 JS 文件,放在lib/modules/目录下,文件导出一个register(program)方法。框架启动时扫描该目录,自动注册所有模块。

lib/ cli.js # 入口,负责全局参数解析 config.js # 配置加载与合并 logger.js # 统一日志输出 loader.js # 扫描 modules 目录 modules/ file.js # 文件操作模块 analyze.js # 日志分析模块 sys.js # 系统信息模块 schedule.js # 定时任务模块 ...

为什么用自动扫描而不是在入口文件里手动require?因为当你模块数量越来越多时,手动维护一份注册列表就成了负担。自动扫描不仅不用改入口代码,还让“新增一个模块”的动作降维成了“放一个文件进去”。这和现代开发框架里“约定优于配置”的思路一脉相承。实际使用中,我还会在~/.anything/目录下创建一个plugins/文件夹,用于加载个人扩展模块,这样框架升级不会覆盖你自己的工具。

2.3 全局参数与模块参数的分层设计

CLI-Anything 把参数分成两层:全局参数和模块参数。全局参数写在命令最前面,作用于整个调用过程;模块参数跟在具体模块后面,只对该模块生效。

anything --config ~/.anything/config.yml --verbose file batch-rename --from "old" --to "new"

我定义的全局参数有这些:

参数说明
--config <path>指定配置文件路径,默认读取~/.anything/config.json
--verbose输出详细调试信息,含调用栈
--quiet只输出错误信息,适合写进 cron
--json输出机读 JSON,方便 jq 或下游程序处理
--dry-run全局试运行开关,模块自行决定如何预览
--format <text|table|json>输出格式,是--json的泛化版

这里有一个关键设计原则:模块不要自己去读全局参数,而是通过框架注入。否则每个模块都得重复解析一遍--verbose、--format,既增加工作量又容易产生不一致。正确的做法是,框架解析完全局参数后,把已经处理好的配置对象(包括 verbose 标志、输出格式等)传给模块。

2.4 配置优先级:参数 > 环境变量 > 配置文件 > 默认值

任何一种配置都可能来自四个渠道,如果处理不好优先级,就会出现“改了配置不生效”的诡异问题。CLI-Anything 的处理顺序是:

  1. 命令行参数(最高优先,本次调用生效)
  2. 环境变量(如ANYTHING_FORMAT=json)
  3. 配置文件(~/.anything/config.json或--config指定路径)
  4. 代码内置默认值(最低优先)

举个例子:如果配置文件里写死了"format": "table",但你敲命令时加了--json,最终输出应该是 JSON。我之前见过不少工具的困惑点就在这——命令行参数永远应该是用户最高权限的意图表达,任何配置文件都不该覆盖用户当场敲下的参数。实现时,只需要在读取配置后,把命令行参数一层层覆写上去即可。

3. 核心实现:从零搭起 CLI-Anything 的骨架

3.1 技术选型:为什么用 Node.js

语言选型我最终选了 Node.js。原因有三个:

  • 跨平台省心:Windows、macOS、Linux 都能跑,不用为各平台 shell 差异写兼容代码。
  • 生态成熟:commander做命令解析、chalk做彩色日志、js-yaml读配置文件,都是现成的轮子。
  • 脚本能力不弱:虽然性能不如编译型语言,但 CLI 工具的性能瓶颈通常不在语言本身,而在 IO。对绝大多数文件处理和系统调用来说,Node.js 完全够用。

当然,用 Python 写也完全可以,argparse或click同样能实现这套架构,思路是相通的。我个人没有选 Python 是因为团队环境里 Node 更容易统一版本,而且我后续想把模块分发做成 npm 包,Node 天然契合。

3.2 初始化项目与依赖安装

先建目录、初始化package.json、安装核心依赖:

mkdir cli-anything && cd cli-anything npm init -y npm install commander glob chokidar js-yaml chalk

各依赖的职责:

  • commander:命令解析与帮助文档生成
  • glob:文件名匹配(递归查找目录时用)
  • chokidar:文件监听(定时任务模块里用)
  • js-yaml:配置文件解析(支持 JSON 和 YAML 两种格式)
  • chalk:终端彩色输出

然后在package.json里声明 bin:

{ "bin": { "anything": "./lib/cli.js" } }

给cli.js加上可执行权限,并以 shebang 开头:

#!/usr/bin/env node

3.3 入口文件:全局参数的解析

lib/cli.js的职责很简单——先加载配置、初始化 logger,再启动模块扫描。

#!/usr/bin/env node const { Command } = require('commander'); const { loadConfig } = require('./config'); const { logger } = require('./logger'); const { loadModules } = require('./loader'); const program = new Command(); program .name('anything') .description('CLI-Anything: 一切皆命令的个人工具箱') .version('1.0.0') .option('--config <path>', '指定配置文件路径') .option('--verbose', '输出调试日志') .option('--quiet', '仅输出错误') .option('--dry-run', '试运行,不执行真实变更') .option('--format <format>', '输出格式: text|table|json', 'text'); program.parseOptions(process.argv); const options = program.opts(); const config = loadConfig(options.config); loadModules(program, config, options); program.parse(process.argv);

这里要注意:parseOptions和parse我拆开了用。先用parseOptions把全局参数摘出来,再去加载配置和模块,最后才让 commander 解析完整命令。这样模块注册时就能拿到全局配置,模块内部可以根据 verbose 决定是否输出调试信息。

3.4 模块加载器:自动发现并注册

lib/loader.js实现模块扫描:

const fs = require('fs'); const path = require('path'); function loadModules(program, config, globalOptions) { const moduleDir = path.join(__dirname, 'modules'); const pluginDir = path.join(process.env.HOME || process.env.USERPROFILE, '.anything', 'plugins'); [moduleDir, pluginDir].forEach((dir) => { if (!fs.existsSync(dir)) return; fs.readdirSync(dir).forEach((file) => { if (!file.endsWith('.js')) return; const modulePath = path.join(dir, file); const mod = require(modulePath); if (typeof mod.register === 'function') { mod.register(program, { config, globalOptions }); } }); }); return program; } module.exports = { loadModules };

个人插件目录放在~/.anything/plugins/这个路径,是为了把“自带模块”和“个人扩展”分开。实际体验下来,这样做非常有用:比如我换了新电脑,只需把~/.anything/整个目录同步过来,所有个人模块和配置就都回来了,框架本体甚至不用安装太多东西。

3.5 一个完整模块的写法:以文件批量重命名为例

我拿最常用的文件操作模块来示范。模块就是导出一个register函数,注册子命令:

// lib/modules/file.js const fs = require('fs'); const path = require('path'); const glob = require('glob'); function register(program, ctx) { const { logger, format } = ctx; program .command('file batch-rename') .description('按正则批量重命名文件') .requiredOption('--from <pattern>', '匹配文件名用的正则,如 "img_(\\d+)\\.png"') .requiredOption('--to <template>', '替换模板,支持 $1 捕获组,如 "photo_$1.png"') .option('--path <dir>', '目标目录', '.') .option('--dry-run', '只预览不执行') .action(async (options) => { const files = glob.sync('**/*', { cwd: options.path, nodir: true, absolute: true }); const regex = new RegExp(options.from); let changedCount = 0; for (const file of files) { const filename = path.basename(file); const newName = filename.replace(regex, options.to); if (newName === filename) continue; const newPath = path.join(path.dirname(file), newName); if (options.dryRun) { console.log(`${filename} -> ${newName}`); } else { fs.renameSync(file, newPath); logger.info(`Renamed: ${filename} -> ${newName}`); } changedCount++; } if (options.dryRun) { console.log(`[dry-run] 预计影响 ${changedCount} 个文件`); } else { console.log(`完成,共重命名 ${changedCount} 个文件`); } }); } module.exports = { register };

这里有几个细节值得展开:

  • requiredOption保证关键参数缺失时直接报错退出,避免模块内部到处做判空。
  • --dry-run是每个模块都必须支持的选项,输出“将发生什么”而不真正执行。这个习惯能让你在跑批量操作前永远有个安全的预演环节。
  • 我自己在实际使用中还会打印新旧文件名对照表,这样预览结果一眼就能看清,而不是只给个“预计影响 X 个文件”的模糊数字。

3.6 统一配置加载与输出格式处理

配置加载的核心逻辑是“按优先级合并”。lib/config.js简化实现:

const fs = require('fs'); const path = require('path'); const yaml = require('js-yaml'); const DEFAULTS = { format: 'text', dryRun: false, logLevel: 'info', backupDir: './backup' }; function loadConfig(customPath) { const home = process.env.HOME || process.env.USERPROFILE; const configPath = customPath || path.join(home, '.anything', 'config.json'); let fileConfig = {}; if (fs.existsSync(configPath)) { const raw = fs.readFileSync(configPath, 'utf8'); fileConfig = configPath.endsWith('.yaml') || configPath.endsWith('.yml') ? yaml.load(raw) : JSON.parse(raw); } const envConfig = { format: process.env.ANYTHING_FORMAT, dryRun: process.env.ANYTHING_DRY_RUN === 'true', logLevel: process.env.ANYTHING_LOG_LEVEL }; return { ...DEFAULTS, ...fileConfig, ...envConfig }; }

关于输出格式,我提一个比较重要的点:当输出格式是 JSON 时,日志信息与正式输出必须分离。也就是说,调试日志走stderr,正式结果走stdout。这样用户执行anything analyze log --json | jq .时,日志不会混进管道导致 JSON 解析失败。在我最初的一版实现里,就犯过把日志直接console.log出去的错误,结果接了管道之后下游程序全都因为多余的日志行而崩溃。

4. 实操:五个高频场景的模块实现

4.1 批量文本替换:一处修改,全局生效

这个模块适合在多个文件里统一替换某个字符串或正则。设计很简单:指定目录、指定匹配规则、指定替换模板,然后先预览后执行。

anything text replace --path ./src --from "oldFunction\(\)" --to "newFunction()" --dry-run

关键点是要支持文件编码检测。很多文本文件看着是 UTF-8,实际上可能是 GBK 或者其他编码。我遇到过最典型的坑,就是替换之后中文全部变成乱码。解决办法是:读文件时先尝试 UTF-8,如果解码出现异常再尝试 GBK;写入时统一用 UTF-8 并注意是否带 BOM。匹配规则上,区别“字面量替换”和“正则替换”也很重要,我用一个--type literal|regex的选项来实现两种模式,默认字面量,避免用户误写正则导致替换结果和预期不符。

4.2 日志分析:哪类错误最多,一眼看清

排查线上问题时,我最常用的手段是把日志里的错误按类型聚合。CLI-Anything 的analyze log模块直接支持按正则提取内容并统计 Top N:

anything analyze log --file app.log --type error --top 10 --format table

内部逻辑是读取日志文件,用正则库匹配错误行,提取错误码或关键字,然后按出现次数排序输出。输出表格包含三列:排名、出现次数、错误关键词。这个模块真正方便的地方在于:它可以直接接上一个模块——比如先anything text replace批量清理掉旧格式日志里的无用字段,再anything analyze log做聚合,两个命令用管道串联,一气呵成。

对于超大日志文件,我建议加一个--tail 5000选项,只处理文件最后五千行。因为出问题时,通常最新的多次报错就足够定位了,没必要扫描整个 GB 级别的日志。

4.3 系统巡检:一条命令拿到全貌

系统信息采集模块sys collect的任务是汇总 CPU、内存、磁盘、负载、网络等状态,输出成 JSON 或表格。

anything sys collect --format json --save /tmp/sys-report.json

实现上,Node.js 没有直接内置系统信息 API,但可以通过读取/proc/下的文件(Linux)或使用os模块拿到内存和 CPU 信息。磁盘信息则依赖df命令的输出来解析,或者调用系统工具获取。我实际使用中会给模块加一个--baseline参数:把当前状态和上个时间点的基线做对比,直接输出“CPU 使用率上升 20%”“磁盘剩余空间下降 30%”这样有结论的报告,而不是冷冰冰的数字。

注意:不同操作系统的/proc/stat和df输出格式有差异,所以这个模块一定要做平台判断,保证 Linux、macOS 下都能正常运行。

4.4 文件监听与自动执行:任务触发好帮手

定时任务需求大家都有,但我个人更常用的是“监听目录变化后自动触发命令”。比如把文件丢进某个目录,就自动完成压缩、转码或备份。

anything watch run --path ./inbox --exec "anything text replace --from 'TODO' --to 'DONE' --path ./inbox"

chokidar库监听目录新增、修改、删除事件,在事件回调里调用child_process.exec执行指定的命令。我踩过的坑是:监听目录内文件被修改,触发命令后命令又写回该目录,导致再次触发,形成死循环。解决办法是:事件回调里设置一个短暂延迟,并且只响应文件类型的变化,忽略目录本身;同时明确指定要监听的文件扩展名列表,减少无效触发。

4.5 定时备份:简单可靠的数据保险

定时任务模块schedule用node-cron实现,支持标准 cron 表达式:

anything schedule add --name "daily-backup" --cron "0 2 * * *" --cmd "bash /opt/backup.sh"

内部实现就是把任务记录保存到一个 JSON 文件里,然后由后台守护进程读取并执行。写这个模块时我最大的体会是:任务持久化文件和执行日志必须分开存。任务文件只记录“什么时候执行什么命令”,执行日志则记录每次运行的时间和输出,两者混淆会导致后续排查困难。另外,命令执行前最好把工作目录切换到一个确定的目录(比如~/.anything/workdir),避免 cron 的默认工作目录和你预期的不同,导致命令找不到文件。

5. 常见问题与排查技巧实录

5.1 命令找不到:PATH 与环境问题

装好全局命令后,终端却报anything: command not found,这是最常见的起步问题。原因基本就两个:一是npm link没有成功建立软链;二是全局 bin 目录不在你的PATH中。排查办法:

npm link # 在项目目录执行,建立全局链接 which anything # 看实际二进制路径 echo $PATH # 检查 bin 目录是否在里面

如果是 npm 全局目录未加入 PATH,最稳妥的做法是把$(npm prefix -g)/bin加入 shell 配置文件(.bashrc或.zshrc)。这个问题在 Windows 上更常见一些,因为 Node 的全局 bin 目录可能不在系统 PATH 中。

5.2 参数解析意外:引号在作怪

正则表达式里的\d在命令行里经常会因为引号处理不当而失效。比如:

# 错误:正则里的反斜杠在多数 shell 中会先被解释一层 anything file batch-rename --from "img_(\d+).png" --to "photo_$1.png"

实际传递到 Node.js 里的字符串可能已经变成了img_(d+).png,导致匹配失败。解决办法有两个:要么在参数值外面用单引号包裹('img_(\d+).png'),要么在正则里把反斜杠写成双反斜杠。我一直以来的习惯是:涉及正则的命令一律用单引号,并且先在--dry-run下测试匹配是否生效,再真正执行。

5.3 中文乱码:编码不一致问题

文件读写、日志输出中文字符乱码,绝大多数是因为源文件不是 UTF-8,或者终端本身不是 UTF-8 编码。CLI-Anything 的处理原则是:

  • 读取文本文件时,先用iconv-lite做编码嗅探,避免直接按 UTF-8 解码导致 GBK 文件乱码。
  • 所有输出统一用process.stdout.write,且检查终端LANG环境变量是否包含UTF-8。
  • Windows 下建议在命令前设置chcp 65001切换代码页,或者直接在 Node 里设置process.env.NODE_ENV。

5.4 大文件处理卡顿:流式读取

第一次用这个框架处理一个 3GB 的日志文件时,我直接fs.readFileSync把整个文件读进内存,结果进程崩溃了。后来所有文件处理模块都改成了流式读取方式:

const readline = require('readline'); const rl = readline.createInterface({ input: fs.createReadStream(filePath), crlfDelay: Infinity }); rl.on('line', (line) => { // 逐行处理,不占用大量内存 });

流式处理配合--tail N参数,基本能覆盖 99% 的大文件分析场景。我在项目里也预留了并行处理的空间:需要做 CPU 密集型任务时,用worker_threads把文件按行数切片分给多个 worker,实测在四核机器上提速接近 3 倍。

5.5 权限不足:批量操作需谨慎

批量重命名和删除文件时,偶尔会遇到 EACCES 权限错误。我的处理建议是:先以当前用户身份试跑一次 dry-run,再检查目标目录是否有写权限,最后执行真实操作。遇到权限不足时不要无脑sudo,因为 sudo 执行的进程环境、PATH、配置路径可能都不一样,很容易造成“命令在 sudo 下找不到配置”或“生成的文件归 root 所有”的麻烦。更好的做法是把当前用户加入目标目录的权限组。

6. 经验总结与扩展方向

这个项目做到现在,我最大的一个体会是:CLI 工具的价值不在于它本身多复杂,而在于它把复杂留给了封装者,把简单留给了使用者。我封装一个模块可能需要二十分钟,但之后每次使用只需要几秒钟。从次数上看,一个高频模块哪怕为我省下两分钟,用上一百次就回本了。这也是我把所有琐碎任务都往 CLI-Anything 里塞的根本原因。

在实际操作中,我还有一个特别推荐的扩展方向,就是给 CLI-Anything 加上“命令别名”和“组合命令”的能力。比如我在~/.anything/aliases.yml里定义了:

backup: - anything file batch-rename --from "temp" --to "bak" --path ./data - anything schedule add --name "auto-backup" --cron "0 3 * * *" --cmd "tar -czf data.tar.gz ./data"

然后执行anything go backup,框架会按顺序执行这两条命令。这让 CLI-Anything 从“单命令工具箱”升级成了“工作流编排器”。后续我还想加入交互式选择面板,让不熟悉命令行的人也可以用方向键挑选命令执行。

最后再分享一个小技巧:把常用命令写成 shell 函数包装。我自己的~/.bashrc里就有一行:

alias rr="anything file batch-rename --dry-run"

这样我只需要敲rr --from 'x' --to 'y',即使只是临时预览一下匹配结果,也能享受框架带来的统一体验。工具这种东西,用久了就会形成肌肉记忆,而一个好的 CLI 框架,值得你花时间把肌肉记忆打磨得更顺手一些。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 16:27:50

Redis密码设置全攻略:配置文件、Docker、命令行三种场景一次搞定

不少人的Redis从安装到现在&#xff0c;一直是“裸奔”状态——没有密码、没有认证&#xff0c;任何一个能访问到6379端口的人都能执行FLUSHALL把数据刷干净。我自己就见过好几起因Redis未授权访问导致的事故&#xff1a;轻则缓存被清空&#xff0c;重则服务器被植入挖矿程序、…

作者头像 李华
网站建设 2026/9/28 16:25:27

微信小程序支付与浏览器支付怎么区分?JSAPI和H5全流程对比

做了好几年微信生态开发&#xff0c;微信小程序支付和微信浏览器支付这两个词几乎每次做商城类项目都会被一起提出来。我自己的体会是&#xff0c;大部分新手踩坑不是因为代码写错&#xff0c;而是压根没搞清楚这两者到底是不是同一个东西。先说结论&#xff1a;小程序支付和微…

作者头像 李华
网站建设 2026/9/28 16:24:23

暑期科研与求职工作总结

暑期科研与求职工作总结一、引言本总结对阶段性科研工作与综合事务进行系统梳理。暑期是研究生科研产出与职业准备的关键窗口期&#xff0c;本人在这一时期并行推进了学位论文开题、网络安全科研项目收尾、期刊论文的投稿与修改、以及秋季校园招聘的筹备与投递。总体而言&#…

作者头像 李华
网站建设 2026/9/28 16:22:53

基于4,200张已标注图像的果蔬分类迁移学习实战指南

简介&#xff1a;本资源为常见果蔬多类别图像分类数据集&#xff0c;面向从事图像分类、分割网络改进及计算机视觉项目实践的学生与开发者&#xff0c;可直接作为分类网络输入使用。数据集共标注36个类别&#xff0c;涵盖香蕉、苹果、梨、葡萄、橙子、黄瓜、胡萝卜、辣椒、洋葱…

作者头像 李华
网站建设 2026/9/28 16:22:14

微信小程序+Java后端马拉松报名系统:高并发抢名额与毕业设计实战

简介&#xff1a;这是一套面向高校计算机相关专业学生的毕业设计/课程设计完整项目&#xff0c;采用微信小程序前端搭配Java后端与MySQL数据库&#xff0c;实现马拉松赛事报名与活动商城一体化业务。系统区分管理员与普通用户两类角色&#xff1a;管理员可管理个人中心、用户、…

作者头像 李华
网站建设 2026/9/28 16:21:31

基于YOLOv5的步态识别多目标跨镜头跟踪系统实战

简介&#xff1a;这份资源是面向人工智能、计算机视觉方向本科生与研究者的毕业设计完整源码包&#xff0c;围绕「基于步态识别的多目标跨镜头跟踪算法研究」展开&#xff0c;核心采用YOLOv5-DeepSORT框架完成目标检测与多目标跟踪&#xff0c;并融合GaitSet步态识别算法实现跨…

作者头像 李华