2024年10月

说明

该文章是属于OverallAuth2.0系列文章,每周更新一篇该系列文章(从0到1完成系统开发)。

该系统文章,我会尽量说的非常详细,做到不管新手、老手都能看懂。

说明:OverallAuth2.0 是一个简单、易懂、功能强大的权限+可视化流程管理系统。

友情提醒:本篇文章是属于系列文章,看该文章前,建议先看之前文章,可以更好理解项目结构。

有兴趣的朋友,请关注我吧(*^▽^*)。

关注我,学不会你来打我

说明

该篇文章,属于
从0到1完成权限管理系统开发
之前系列文章的总结。

总结

本webApi框架轮子,是根据OverallAuth2.0(权限管理+可视化流程管理系统)项目情况而制定的webApi轮子。

虽说是根据该系列项目搭建的框架轮子,
但可以说,基本适合大多数项目的底层架构(ps:复杂的项目自动忽略)
(需要者在文章末尾处下载,根据项目情况,酌情修改)。

webApi框架轮子结构(还会不断完善,只是通用轮子)。

图上所有,除了缓存机制以为,在OverallAuth2.0 WebApi轮子中,基本都是实现,并且每一块都有单独的文章说明。
前往观看

下一步:Vue3前端框架轮子搭建

目前后端框架已经【初具雏形】,下一步,我先暂缓后端的开发,把目标放在Vue3前端框架上。

因为OverallAuth2.0,它是一个前后端完全独立分离的权限+流程管理系统,后端采用.Net8 webApi  ,前端采用Vue3+element plus。

如果有对Vue3+element plus创建前端框架不熟悉的
,请关注我的博客园和微信公众号,和后端框架轮子一样,我会一步一步分享前端框架的搭建过程。

上图为前端轮子大概搭建过程,如果你喜欢,请关注,不错过每一篇文章。

WebApi 源代码地址:https://gitee.com/yangguangchenjie/overall-auth2.0-web-api

WebApi
预览地址:http://139.155.137.144:8880/swagger/index.html

帮我Star,谢谢。

有兴趣的朋友,请关注我微信公众号吧(*^▽^*)。

关注我:一个全栈多端的宝藏博主,定时分享技术文章,不定时分享开源项目。关注我,带你认识不一样的程序世界

转载请注明出处:

oplog(操作日志)是MongoDB中用于记录所有写操作的日志。它是一个特殊的集合,存储在副本集的主节点中。oplog用于确保副本集中的副节点与主节点的数据保持一致。当主节点执行写操作时,相应的操作将被记录到oplog中,副节点则通过读取oplog来获取最新的数据变化。

数据结构

oplog在mongo数据库主节点的local数据下,进入local数据库可以查看这个集合中存储数据的结构:

进入oplog数据库:

use local

查看数据结构:

rs0:PRIMARY>db.oplog.rs.findOne()
{
"ts" : Timestamp(1729001735, 165),"t" : NumberLong(187),"h" : NumberLong(0),"v" : 2,"op" : "i","ns" : "topology.filteredReason","ui" : UUID("94a529f7-dbf1-4be0-b296-361094515e13"),"wall" : ISODate("2024-10-15T14:15:35.636Z"),"lsid": {"id" : UUID("bbf4c6e6-e139-48e2-82df-a0b15bd0a89f"),"uid" : BinData(0,"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=")
},
"txnNumber" : NumberLong(29170),"stmtId" : 0,"prevOpTime": {"ts" : Timestamp(0, 0),"t" : NumberLong(-1)
},
"o": {"_id" : "75a4d50f-8f37-4d06-8abe-d1c2b0de97a0","reason" : "link[maipu_3:gigabitethernet3>maipu_2:gigabitethernet3] has no label","type" : "LINK","key" : "maipu_3:gigabitethernet3>maipu_2:gigabitethernet3","tePolicyColorTupleId" : "maipu_3_maipu_1_MaiPu31_3628","_class" : "com.tethrnet.terra.service.sr.topology.lib.model.terra.te.svc.filteredreasontop.FilteredReason"}
}
rs0:PRIMARY
>

oplog是一个无限增长的集合,包含以下主要字段:

  • ts:时间戳,表示操作的时间。
  • h:哈希值,用于唯一标识该操作。
  • op:操作类型,可能的值包括“i”(插入)、“u”(更新)、“d”(删除)。
  • ns:命名空间,表示操作所属的数据库和集合。
  • o:操作的详细内容,具体取决于操作类型。

特性

  1. oplog(操作日志)是一个特殊的固定大小集合,记录所有修改数据库数据的操作。
  1. 它可以超越其配置大小限制,以避免删除大多数提交点。
  1. 每个副本集成员都包含oplog的副本,位于local.oplog.rs集合中。
  1. 操作日志中的每个操作都是幂等的,即应用一次或多次都会产生相同的结果。
  1. oplog用于复制和恢复节点,如果节点下线,需要oplog来恢复状态。

配置

  1. 默认情况下,MongoDB会自动创建oplog,但可以自定义其大小。
  1. 可以通过oplogSizeMB选项指定初始oplog大小。
  1. 使用replSetResizeOplog命令动态更改oplog大小,无需重启mongod。
  1. 可以设置最小保留时间,防止删除最近的操作日志条目。

oplog的作用

  • 数据同步:副节点通过读取oplog来同步主节点的写入操作,确保数据一致性。
  • 故障恢复:在主节点发生故障时,可以根据oplog中的信息快速恢复数据。
  • 查询历史:oplog提供了一个操作历史的记录,有助于审计和问题排查。

命令

oplog存储在
local
数据库中。进入MongoDB shell后,您需要切换到
local
数据库:

  1. 查看当前最大oplog大小:
    db.getSiblingDB("local").oplog.rs.stats(1024*1024).maxSize
  2. 更改最大oplog大小:
    db.adminCommand({
    replSetResizeOplog:
    1,
    size: Double(
    16384) //megabytes })
  3. 过滤oplog日志


    只对特定操作或特定时间范围内的日志,可以使用查询条件过滤结果。例如,查看类型为“插入”的操作:


    db.oplog.rs.find({ op: "i" }).pretty()
  4. 设置最小保留时间:
    db.adminCommand({
    replSetResizeOplog:
    1,
    minRetentionHours:
    24 //保留至少24小时的日志条目 })

其他重要信息

  1. oplog大小取决于存储引擎和可用空间。内存存储引擎使用5%物理内存,WiredTiger使用5%可用空间。
  1. 默认情况下,不设置最小保留时间,系统会自动截断以维持配置的最大oplog大小。
  1. 在副本集中运行时,不能手动对oplog执行写操作。
  1. oplog对于复制和恢复节点至关重要,不能删除local.oplog.rs集合。
  1. 在sharded集群中,每个副本组都有自己的oplog。

通过理解和正确配置oplog,您可以优化MongoDB的复制性能,并确保数据的一致性和可用性。适当的oplog大小对于高效的复制和恢复至关重要。

最近我遇到了一个比较棘手的问题:在工作中,各个项目所使用的数据库类型各不相同。这导致我习惯性地使用Oracle的SQL语句进行编写,但每次完成后都会遇到报错,最终才意识到项目的数据库并非Oracle。为了避免这种情况,我需要额外花时间去查找不同数据库版本的SQL语法,这严重耽误了我的工作效率。

为了提高我的工作效率,我决定自己编写一个脚本,以便能够快速获取所需的数据库语法,从而节省时间,专注于其他更重要的任务。

今天我使用了utools平台,专注于自动化脚本的编写。这个平台的搭建工作已经完成,所有的环境和依赖都已配置妥当。现在,剩下的任务就是我亲自撰写脚本,将自己的需求和功能实现出来。

准备工作

首先,你需要下载utools工具。这款工具以其便捷性和高效性著称,能够让你在需要的时候迅速调出所需功能,真正实现“呼之即来、即用即走”。

image

这款工具应该是许多程序员在日常工作中必不可少的利器。它不仅提供了丰富的功能,还有广泛的社区支持。接下来,你需要前往商店,免费下载两个非常实用的插件——自动化脚本和JSON编辑器。

image

在这个工具中,你可以找到许多现成的自动化脚本,随时下载并使用。然而,这些脚本并不完全适合我的需求,因此我决定自己实现一个。

由于不同版本的数据库在语法上存在差异,我选择将我的实现以JSON格式进行展示,方便大家查看和理解。在这个过程中,由于涉及到数据的可视化展示,我还下载了JSON编辑器。这样一来,大家就可以更直观地操作和分析数据,而不仅仅是看一个简单的字符串,这样大大提升了操作的便利性和有效性。

编写脚本

接下来,我们可以自行创建这个脚本,具体步骤如下。

image

我会将基本代码写出来,以便大家参考和学习。

var conver = parseToJson(ENTER.payload)
var res = JSON.stringify(conver, null, 4);
utools.showNotification('"'+conver+'"'+'已生成完毕')
utools.redirect('Json', res);

function parseToJson(data) {
    const json = {"type":"text","word":"word"};
    return json;
}

这段代码的主要目的是将JSON数据传递给JSON编辑器插件,以便进行可视化展示和更便捷的操作。如图所示:

image

由于这段代码是基于utools平台开发的,因此其中的一些写法使用了utools集成的API。为了便于大家更好地理解这些写法及其背后的实现逻辑,建议大家参考utools的开发文档,那里提供了详细的说明和示例。在这里,我就不再逐一介绍每个API的细节。

各版本写法

剩下的部分就留给大家自行探索和尝试各种写法了。根据各自的需求,大家可以灵活添加或修改代码,以实现特定的功能或优化。

为了帮助大家更快入手,我在这里分享一些我常用的写法,供大家参考。

// 获取当前时间
const now = new Date();
const formattedDate = now.toISOString().slice(0, 19).replace('T', ' '); // 格式化为 'YYYY-MM-DD HH:mm:ss'

const json = {
    "指定时间": {
        "Oracle": `to_date('${formattedDate}', 'yyyy-mm-dd hh24:mi:ss')`,
        "MySQL": `STR_TO_DATE('${formattedDate}', '%Y-%m-%d %H:%i:%s')`,
        "PostgreSQL": `TO_TIMESTAMP('${formattedDate}', 'YYYY-MM-DD HH24:MI:SS')`,
        "SQL Server": `CONVERT(DATETIME, '${formattedDate}', 120)`,
        "SQLite": `DATETIME('${formattedDate}')`
    },
    "当前时间": {
        "Oracle": "SYSDATE",
        "MySQL": "NOW()",
        "PostgreSQL": "CURRENT_TIMESTAMP",
        "SQL Server": "GETDATE()",
        "SQLite": "CURRENT_TIMESTAMP"
    },
    "时间转字符串": {
        "Oracle": "TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS')",
        "MySQL": "DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s')",
        "PostgreSQL": "TO_CHAR(CURRENT_TIMESTAMP, 'YYYY-MM-DD HH24:MI:SS')",
        "SQL Server": "CONVERT(VARCHAR, GETDATE(), 120)",
        "SQLite": "STRFTIME('%Y-%m-%d %H:%M:%S', 'now')"
    }
};

实现效果

接下来的步骤是自动发起JSON调用,之后只需将生成的结果复制下来进行使用即可。尽管这个工具体积较小,但它能够帮助我节省大量的时间和精力。

将自己的脚本上架之后,只需在utools中输入相应的配置关键字即可轻松调用。

image

运行成功,系统已顺利完成操作,具体结果如图所示。

image

希望这个工具能够为大家提供帮助,提升工作效率。

总结

如果你们有任何想要实现的小工具,utools绝对是一个值得考虑的平台。它不仅功能强大,而且特别适合程序员的工作方式,能够满足我们对灵活性和可定制性的需求。

一、环境搭建

1.安装cuda,本人使用的是12.1版本,下载地址:
https://developer.nvidia.com/cuda-12-1-1-download-archive

image

2.安装conda3,
https://blog.csdn.net/m0_73634846/article/details/136378350

3.准备代码环境

原文:
https://mp.weixin.qq.com/s/PQVrlr5FoVb89Mivzi7pLA

顺序执行:

git clone
https://github.com/Ucas-HaoranWei/GOT-OCR2.0.git
conda create -n got python=3.10 -y #创建虚拟环境
conda activate got #激活虚拟环境
pip install -e . # 使用项目里面pyproject.toml安装依赖

安装 Flash-Attention:

pip install ninja
pip install flash-attn --no-build-isolation
ps:以上是官方的安装教程,但是其实会遇到很多问题,以下进行逐一说明,不保证能解决所有问题,但是大部分问题都能解决

二、问题序列:

1.python安装cuda出现错误提示:AssertionError: Torch not compiled with CUDA enabled

https://blog.csdn.net/qq_44750293/article/details/129685556
问题本质是pytorch无法调用cuda,原因是国内加速镜像默认会安装cpu版本,安装gpu版本即可,及torch.cuda.is_available输出为false即代表安装的版本为cpu版本,安装gpu版本后即可输出为true
###1、torch.cuda.is_available()显示false解决方法:
	使用pytorch官方推荐的版本安装:
		https://pytorch.org/
		例如cuda12.1的安装命令: 
			conda:	conda install pytorch torchvision torchaudio pytorch-cuda=12.1 -c pytorch -c nvidia
			pip:	
				pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 (亲测有效,这个需要下载2小时+)
				阿里云加速(使用这个最快,推荐,只需要下载2min+):
					pip install torch==2.3.1 torchvision==0.18.1 torchaudio==2.3.1 -f https://mirrors.aliyun.com/pytorch-wheels/cu121

2.遇到deepspeed安装报错

Python|Windows 安装 DeepSpeed 安装方法及报错 Unable to pre-compile async_io 处理:
	https://blog.csdn.net/Changxing_J/article/details/139789110

配置visual studio
运行Anaconda Powershell Prompt,执行 Set-Item Env:\DS_BUILD_OPS 0,切换到deepspeed目录,再次执行 :  .\build_win.bat

3.pip错误

ERROR: Could not find a version that satisfies the requirement setuptools_scm (from versions: none)
	尝试切换pip源试试,pip install -i 源地址

4.conda错误

在VS界面激活anaconda,但是报错”CondaError: Run 'conda init' before 'conda activate'“,该如何解决?
	打开Anaconda Prompt
	conda init
	conda activate 环境

5.遇到依赖C++环境的库错误解决

【报错】fatal error C1189
visual studio 版本过高或过低导致,目前2019版本兼容性相对较好

https://blog.csdn.net/thisjuly/article/details/136260069

6.flash_attn安装后执行失败,本质是编译的包不对

text-generation-webui加载codellama报错DLL load failed while importing flash_attn_2_cuda: 找不到指定的模块。:
https://blog.csdn.net/dandandancpop/article/details/134729988
解决: https://github.com/Dao-AILab/flash-attention/releases ,在此链接中下载与本地cuda与torch且python相对应的版本即可,cuda12.1下载cu123亲测可用,cp310为python3.10,cp311为python3.11其他同理

7.本地无法启动大模型

因为默认的源是hugging-face,但是国内无法访问,国内可使用modelscope(魔塔社区)的模型
hugging-face模型下载不成功?
	https://zhuanlan.zhihu.com/p/722248326?utm_campaign=shareopn&utm_medium=social&utm_psn=1824225242303819776&utm_source=wechat_session
	使用modelscope提供的模型

8.cudnn部署

https://blog.csdn.net/retainenergy/article/details/126183711
cuDNN下载链接:
https://developer.nvidia.com/rdp/cudnn-archive
,本人使用的8.9.7,安装链接中进行配置即可

三、需要用到的资源下载链接(只上传了下载很慢的资源):

通过网盘分享的文件:GOT-OCR大模型部署相关
百度云链接:
https://pan.baidu.com/s/1s18O0kS3apBvs-L35KB-qw?pwd=y4ht
提取码: y4ht
阿里云盘链接:
https://www.cnblogs.com/qtclm/p/18475732
提取码 6mw7

四、执行代码与输出

from modelscope import AutoModel, AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained('stepfun-ai/GOT-OCR2_0', trust_remote_code=True)
model = AutoModel.from_pretrained('stepfun-ai/GOT-OCR2_0', trust_remote_code=True, low_cpu_mem_usage=True, device_map='cuda', use_safetensors=True, pad_token_id=tokenizer.eos_token_id)
model = model.eval().cuda()


# input your test image
# image_file = '/mnt/workspace/58F3EF14-E073-4BBE-B9D9-53CCFE6AE183.png'
image_file = 'benchmarks/format_doc_benchmark/2020-03-27__潍柴动力股份有限公司__000338__潍柴动力__2019年__年度报告/38.jpg'

# plain texts OCR
res = model.chat(tokenizer, image_file, ocr_type='ocr')

# format texts OCR:
# res = model.chat(tokenizer, image_file, ocr_type='format')

# fine-grained OCR:
# res = model.chat(tokenizer, image_file, ocr_type='ocr', ocr_box='')
# res = model.chat(tokenizer, image_file, ocr_type='format', ocr_box='')
# res = model.chat(tokenizer, image_file, ocr_type='ocr', ocr_color='')
# res = model.chat(tokenizer, image_file, ocr_type='format', ocr_color='')

# multi-crop OCR:
# res = model.chat_crop(tokenizer, image_file, ocr_type='ocr')
# res = model.chat_crop(tokenizer, image_file, ocr_type='format')

# render the formatted OCR results:
# res = model.chat(tokenizer, image_file, ocr_type='format', render=True, save_render_file = './demo.html')

print(res) 

原图
image

输出
image

结论: 识别率还是很不错的,后面在使用大量图片测试

五、其他补充

1.modelscope默认下载的模型目录:
~/.cache/modelscope/hub
2.一定要注意cuda版本与torch的版本要对应
https://blog.csdn.net/u011489887/article/details/135250561
查看cuda版本,执行命令,nvcc -V 或 nvcc --version可查看
image
查看cuda配置的环境变量,set cuda
image

显卡驱动版本可高于cuda版本,会向下兼容,但是不可小于,执行命令,nvidia-smi可查看显卡目前的状态以及运行中的进程
image


《FFmpeg开发实战:从零基础到短视频上线》一书的“5.1.2  把音频流保存为PCM文件”介绍了如何把媒体文件中的音频流转存为原始的PCM音频,在样例代码的转存过程中,解码后的PCM数据未经任何加工处理,就直接保存到二进制文件。也就是说,原音频的采样频率是多少,PCM文件的采样频率也是多少;原音频的声道数量是多少,PCM文件的声道数量也是多少;原音频的采样位数是多少,PCM文件的采样位数也是多少。

原汁原味保存的PCM文件本来也没什么问题,可是在实际应用中,有的业务场景需要特定规格的PCM音频。比如某厂家的语音识别引擎,要求只能输入16位的PCM数据,然而标准的MP3音频都采用32位采样,如此一来,得想办法把32位的MP3音频转换为16位的PCM音频才行。
考虑到使用FFmpeg的命令行转换比较方便,于是在控制台执行下面的ffmpeg格式转换指令,在转换采样频率和声道数量的同时一起转换采样位数。

ffmpeg -i night.mp3 -ar 16000 -ac 1 -acodec pcm_s16le night.pcm

谁知控制台输出以下的报错信息“pcm_s16le codec not supported”,意思是不支持16位的PCM编码器。

pcm_s16le codec not supported

咦,FFmpeg怎么会不支持这么基本的PCM编码器呢?继续执行下面的编码器查看命令:

ffmpeg -encoders | grep pcm

发现输出的查询结果赫然出现下面的pcm_s16le信息,说明FFmpeg默认已经支持该编码器。

A....D pcm_s16le            PCM signed 16-bit little-endian

那么为啥ffmpeg命令行无法正常转换PCM音频的采样位数呢?
搜了一圈发现没有使用ffmpeg成功转换采样位数的案例,只好先把原音频转换为32位采样的PCM文件,转换命令如下所示:

ffmpeg -i night.mp3 -ar 16000 -ac 1 -acodec pcm_f32le -f f32le night.pcm

接下来另外编写转换音频采样位数的代码convertpcm.c,代码内容如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int pcm32_to_pcm16(const char *filename)
{  
    FILE *fp =  fopen(filename, "rb");
    FILE *fp1 = fopen("output_16.pcm", "wb");
    unsigned char *sample = (unsigned char*)calloc(1, 4+1);
    while(!feof(fp))
    {
        fread(sample, 4, 1, fp);
        sample[4] = '\0';
        float *sample32 = (float*)sample;
        short sample16 = (short)floor( (*sample32) * 32767 );
        fwrite(&sample16, 2, 1, fp1);
    }
    free(sample);
    fclose(fp);
    fclose(fp1);
    return 0;  
}

int main(int argc, char **argv) {
    const char *src_name = "night.pcm";
    if (argc > 1) {
        src_name = argv[1];
    }
    pcm32_to_pcm16(src_name);
}

保存代码,然后执行下面的编译命令。

gcc convertpcm.c -o convertpcm 

编译完成,再执行下面的采样位数转换命令。

./convertpcm night.pcm

现在生成的output_16.pcm就是16位采样的PCM文件,可以用作语音识别了。

更多详细的FFmpeg开发知识参见
《FFmpeg开发实战:从零基础到短视频上线》
一书。