go-kratos使用备忘

我搭建的一个kratos项目模板,欢迎使用,仓库地址 需要特别注意的一些建议 API路由覆盖的问题 比如有两个接口 A get /v1/user/{user_id}和 B get /v1/user/profile如果A定义在B之前,那么B可能会被A覆盖路由。需要将A放到B之前。 JWT使用的建议 摘自极客时间课程《高并发系统实战课》 通讯过程必须使用 HTTPS 协议,这样才可以降低被拦截的可能。 要注意限制 token 的更换次数,并定期刷新 token,比如用户的 access_token 每天只能更换 50 次,超过了就要求用户重新登陆,同时 token 每隔 15 分钟更换一次。这样可以降低 token 被盗取后给用户带来的影响。 Web 用户的 token 保存在 cookie 中时,建议加上 httponly、SameSite=Strict 限制,以防止 cookie 被一些特殊脚本偷走。 配置文件 配置文件校验 配合buf的validate可以方便地进行配置文件的校验,在程序启动之前就对配置文件进行一次校验。下面是一个简单的proto配置定义 syntax = "proto3"; package conf; import "buf/validate/validate.proto"; import "google/protobuf/duration.proto"; option go_package = "github.com/tpl-x/kratos/internal/conf;conf"; message Bootstrap { Server server = 1; Data data = 2; Log log = 3; } message Server { message HTTP { string network = 1; string addr = 2; google....

Sherpa Go语言实战

简介 sherpa 是 Next-gen Kaldi 项目的部署框架。 使用 VAD 语音活动检测(Voice Activity Detection,简称VAD)是一种技术,用于检测音频信号中是否存在语音或其他声音活动。它在语音处理、语音识别、音频压缩等领域有广泛的应用。 VAD的主要功能 语音识别系统:通过VAD,系统可以在检测到语音时启动识别过程,提高效率。 音频压缩:在语音通信中,VAD可以帮助压缩算法仅对有效语音信号进行压缩,减少传输数据量。 噪声抑制系统:通过检测语音活动,系统可以在静默时段增强噪声抑制效果。 在GO中使用 todo KWS 关键词唤醒(Keyword Spotting,简称KWS)是一种技术,用于检测音频信号中特定的关键词或短语。它广泛应用于语音助手、智能家居设备、车载系统等领域,通过识别特定关键词来激活设备或执行特定命令。 主要功能 关键词检测:识别音频信号中是否包含预定义的关键词或短语。 唤醒设备:当检测到关键词时,激活设备或应用程序。 提高用户体验:通过语音命令简化操作流程,增强用户体验。 自定义keywords 通过官方的工具sherpa-onnx-cli,可以实现自定义关键字,下面是简单的介绍 原文 # Note: You need to run pip install sherpa-onnx to get the commandline tool: sherpa-onnx-cli sherpa-onnx-cli text2token --help Usage: sherpa-onnx-cli text2token [OPTIONS] INPUT OUTPUT Options: --text TEXT Path to the input texts. Each line in the texts contains the original phrase, it might also contain some extra items, for example, the boosting score (startting with :), the triggering threshold (startting with #, only used in keyword spotting task) and the original phrase (startting with @)....

在Go程序中使用Vosk进行语音识别STT

Vosk 介绍 Vosk是一款基于深度学习的开源语音识别工具,能够在没有云连接的情况下进行高效的离线语音识别。它通过对语音信号进行预处理、特征提取和模型推断,将语音转换成文本。Vosk不仅支持多种主流编程语言,还覆盖了20多种语言和方言,包括英语、中文、法语、德语等,为跨语言应用提供了强大的支持。 工作原理 Vosk的语音识别过程可以分为以下几个关键步骤: 语音信号预处理:对输入的语音信号进行去噪、增强等处理,以提高识别准确性。 特征提取:从处理后的语音信号中提取出能够表征语音特性的关键特征。 模型推断:利用预训练的深度学习模型对提取的特征进行识别,输出对应的文本。 优势解析 隐私保护:Vosk的离线特性意味着用户的语音数据不会离开设备,有效保护了用户的隐私。 实时性:在设备端进行语音识别,减少了网络传输时间和延迟,使得识别过程更加实时。 跨平台:支持Windows、Linux、macOS以及嵌入式设备等多种平台,便于在不同场景下的应用。 可扩展性:作为开源项目,Vosk允许开发者根据自己的需求进行定制和优化,以适应不同的应用场景。 多语言支持:提供对多种语言和方言的识别能力,为跨国应用提供了便利。 官方 https://alphacephei.com/vosk/ 模型下载 https://alphacephei.com/vosk/models GO项目搭建 本文基于Linux,Windows请参考官方仓库的说明 创建go程序 创建go程序内容如下: package main import ( "encoding/json" "flag" "fmt" "io" "log" "os" vosk "github.com/alphacep/vosk-api/go" ) func main() { var filename string flag.StringVar(&filename, "f", "", "file to transcribe") flag.Parse() model, err := vosk.NewModel("model") if err != nil { log.Fatal(err) } // we can check if word is in the vocabulary // fmt....

Go程序自动升级的方案探究

前导 2024年的最后一天看见v站的这个帖子,故整理下,备忘。 常用的库 cloudflare tableflip 仓库为 https://github.com/cloudflare/tableflip 官方示例 package tableflip_test import ( "context" "flag" "fmt" "log" "net/http" "os" "os/signal" "syscall" "time" "github.com/cloudflare/tableflip" ) // This shows how to use the upgrader // with the graceful shutdown facilities of net/http. func Example_httpShutdown() { var ( listenAddr = flag.String("listen", "localhost:8080", "`Address` to listen on") pidFile = flag.String("pid-file", "", "`Path` to pid file") ) flag.Parse() log.SetPrefix(fmt.Sprintf("%d ", os.Getpid())) upg, err := tableflip.New(tableflip.Options{ PIDFile: *pidFile, }) if err !...

对称和反向gRPC连接【译】

原文链接为 https://tilde.town/~hut8/post/grpc-connections/ 使用kimi进行翻译 背景 gRPC是一项出色的现代技术,用于远程过程调用。它允许你在客户端创建一个“存根”对象,该对象的目的是调用服务器上的方法。它是许多情况下REST或GraphQL的绝佳替代品,通常值得学习这项技术。更多信息可以在官方文档中找到。 网络 概念上,我们对客户端和服务器有两种不同的想法。 TCP服务器和客户端 - gRPC在HTTP/2之上运行,HTTP/2在TCP之上运行,所以我将讨论TCP中“服务器”和“客户端”的含义。在TCP连接中,客户端是连接的发起者,服务器是连接的接收者。然而,一旦建立了连接,连接就是对称的;客户端和服务器都可以发送和接收消息,直到一方通过shutdown(2)关闭,或通过close(2)关闭连接。 gRPC服务器和客户端 - gRPC客户端通过存根调用在服务器上运行的方法。这不是对称的。服务器不能在客户端上调用方法。 服务器/客户端类型耦合问题 如果你有一个gRPC客户端,它也是TCP客户端(它调用connect(2))。如果你有一个gRPC服务器,它也是TCP服务器(它调用listen(2)和accept(2))。 因此,如果你想让两台机器可以相互调用gRPC,那么每台机器都是客户端和服务器(在TCP和gRPC两种意义上),现在你有了两个与彼此无关的TCP连接。在有两朵云实例的场景中,这种架构通常并不复杂。但TCP通常很混乱。防火墙、NAT和动态分配的IP地址可能会使客户端到服务器的单向连接变得复杂。 这里有一个这样的情况的例子:假设你的“服务器”是一个在家庭路由器后面的笔记本电脑上运行的程序,它必须接收命令(例如,远程控制)来自“客户端”(例如,云计算实例)。根据gRPC,客户端必须是云计算实例(这很容易被称为“服务器”),因为那是创建远程过程调用的一方。服务器是笔记本电脑,因为那是实际发生过程调用的地方。 当你在客户端(即云计算实例)上创建一个“存根”时,你必须创建一个TCP连接并连接到服务器(即笔记本电脑)。现在你遇到了几个可能的问题: 你不知道笔记本电脑的IP地址,所以你现在需要一个反向服务,让笔记本电脑告诉云它的IP地址。 笔记本电脑可能在NAT后面,所以一旦你找到了IP地址,笔记本电脑将不得不配置端口转发。这在企业环境中很可能是不可能的。 笔记本电脑可能在防火墙后面,这将禁止传入连接。这可能是本地机器上的,也可能是在网关路由器上的。 这些问题中的一些可能是无法解决的,所以我们需要另一种方法。 gRPC独有的解决方案 服务器不能在客户端gRPC上调用方法。也许你可以让客户端在服务器上调用一个方法,其唯一目的是接收描述服务器希望客户端运行的方法的消息。这可以通过流式响应来完成。但这很复杂,需要大量的代码来绕过gRPC的设计。我在其他地方看到过这个建议,但我认为这是一个丑陋的临时解决方案,它制造的问题比它解决的还要多。考虑一下,你将如何在静态类型的方式中实际调用这些“客户端方法”。 基于隧道的解决方案 将TCP客户端/服务器从gRPC客户端/服务器中解耦的一个好方法是实现某种隧道。在上面的例子中,笔记本电脑可以向云计算实例发起一个TCP连接,然后通过实现特定于语言的接口,“拨号”操作让云计算实例(gRPC客户端)连接到笔记本电脑(gRPC服务器)可以简单地使用现有的TCP连接。 SSH是一个不可思议的协议,它的用途比大多数用户知道的还要多。在我们的情况下,它是将我们的TCP连接从gRPC连接中解耦的完美方式。它还有其他好处:尽管gRPC提供认证和加密,但如果更方便,你可以使用SSH提供的。 这些例子是Go语言特有的,但你可以在任何语言中做类似的事情。gRPC服务器不需要监听端口;你可以传入任何实现了Go的net.Listener的类型。所以我们可以做一个net.Listener,它将接受SSH连接,任何时候请求我们的自定义类型的新SSH通道,我们将接受它并返回一个新的net.Conn,这是我们将实现的另一个类型,它只是通过我们的隧道传输数据。 让我们从SSHDataTunnel开始,它是我们的net.Conn。 import ( "net" "time" "golang.org/x/crypto/ssh" ) // SSHDataTunnel实现了net.Conn type SSHDataTunnel struct { Chan ssh.Channel Conn net.Conn } func NewSSHDataTunnel(sshChan ssh.Channel, carrier net.Conn) *SSHDataTunnel { return &SSHDataTunnel{ Chan: sshChan, Conn: carrier, } } func (c *SSHDataTunnel) Read(b []byte) (n int, err error) { return c....

在Go语言中使用Arrow、Flight和Duckdb

从duckdb开始 DuckDB 是一个嵌入式分析型数据库,专为 OLAP(在线分析处理)工作负载设计。本文将基于 go-duckdb 项目的示例,详细介绍 DuckDB 在 Go 语言中的各种使用场景。 基础使用 简单查询 package main import ( "database/sql" _ "github.com/marcboeker/go-duckdb" ) func main() { db, err := sql.Open("duckdb", ":memory:") if err != nil { panic(err) } defer db.Close() // 执行查询 rows, err := db.Query("SELECT 42") if err != nil { panic(err) } defer rows.Close() } 高级特性 Copy COPY 函数可以用于导入导出数据: package main import ( "database/sql" "fmt" _ "github.com/marcboeker/go-duckdb" ) func main() { db, err := sql....

golang检测字节是否为utf-8字节的起始字节

原理 UTF-8 编码使用不同长度的字节序列来表示 Unicode 字符。这些序列的长度从一个字节到四个字节不等,每个字节都有特定的比特模式。您可以通过观察任何字节的最高位(也就是最左边的几位比特),来判断这个字节是不是某个字符的 UTF-8 编码的起始字节或中间字节: 单字节字符(U+0000 到 U+007F)以 0xxxxxxx 为模式,其中 x 可以是 0 或 1。这种单字节的高位为 0,表示它是 ASCII 字符的起始(也是唯一)字节。 UTF-8 编码的起始字节(即多字节序列的第一个字节)模式为 110xxxxx(对于两字节编码)、1110xxxx(对于三字节编码)或 11110xxx(对于四字节编码)。 对于一个 UTF-8 字符的非起始字节(也称为连续字节或中间字节),其模式为 10xxxxxx。 因此,如果你看到一个字节,它的最高两位是 10,那么它是 UTF-8 编码中的一个连续字节。如果最高一位是 0 或者高位模式匹配 110、1110 或 11110,它就是起始字节。 举例来说: 0xxxxxxx - UTF-8 字符的起始字节(单字节 ASCII 字符) 110xxxxx - 两字节编码的起始字节 1110xxxx - 三字节编码的起始字节 11110xxx - 四字节编码的起始字节 10xxxxxx - 中间字节 通过检查字节的最高位,您就可以迅速确定它是 UTF-8 编码序列的起始字节还是中间字节。 实现 go语言实现 package main import ( "fmt" ) // isUTF8StartByte checks whether a byte is a UTF-8 start byte....

go switch的6种用法【译】

文章原文链接为 https://blog.devtrovert.com/p/switch-in-go-6-ways-to-use-it 照片由 Zbyněk Skrčený 在 Unsplash 上拍摄 Go 以其简单而闻名,但我注意到并不是每个人都熟悉 switch 语句在这种语言中的多功能性。 首先,如果您不熟悉 Go 的 switch 语句,与其他语言相比,它可能看起来有点不同。这是一个简单的例子来展示它的样子: func main() { var i int = 1 switch i { case 1: fmt.Println("i is 1") case 2: fmt.Println("i is 2") default: fmt.Println("i is not 1 or 2") } } Go 的 switch 的一个很酷的事情是,一旦找到匹配项,它就会停止,你不需要在每个 case 的末尾添加一个 break 语句。 但不仅仅如此。 Go 中的 switch 语句有两部分:分号之前的部分是初始化器,分号之后的部分是我们要检查的值。 我们可以选择同时使用、使用其中之一或都不使用: switch initializer; value {} switch initializer {} switch value {} switch {} 有趣,对吧?...

使用结构或可变参数选项简化go函数签名【译】

文章内容来自func25的 twitter 在Go中设计函数时,我们可能会遇到需要传递大量参数的情况。 这可能会影响函数的目的,并使维护代码成为一件苦差事,特别是当涉及相同类型的参数时。 为了保持整洁,请考虑两种策略: 选项结构。 可变选项。 选项结构体 将参数捆绑到一个结构中,这不仅增强了可读性,还简化了参数传递。 什么时候使用它? 你的函数有一个很长的参数列表。 您的目标是自记录代码,因为结构字段本质上描述了它们的用途(通过名称)。 您希望轻松设置默认值或灵活修改选项。 使用此模式时, context.Context 应保留为单独的参数,而不应包含在选项结构中。 这是由于上下文在控制请求范围值、截止日期和取消信号方面的独特作用。 但在使用时有一些小技巧: 该结构应该向后兼容,以便在添加新字段时,我们不会破坏之前的任何内容。 我们始终可以在处理结构之前对其进行验证。 考虑隐藏您的选项结构(使其不导出),然后公开 NewXXX() 函数并在那里设置默认值。 可变参数选项 此方法利用 Go 的函数功能,允许您以更简洁的方式传递灵活数量的选项。 它在以下情况下是理想的: 该功能需要高度可配置。 大多数选项是可选的或很少使用。 您更喜欢简洁的调用站点。 设置默认值比使用可选结构更容易,您不需要隐藏它,只需将默认值直接放在 ConnectToDatabase 中即可。

关于七牛qetag算法的一些记录

背景 今天做七牛相关接口开发的时候发现七牛的文件查询列表返回,有个hash字段,但是不知道是怎么进行计算的。后来查询到七牛的官方仓库 qetag.官方对这个算法的描述是这样的: qetag 是一个计算文件在七牛云存储上的 hash 值(也是文件下载时的 etag 值)的实用程序。 七牛的 hash/etag 算法是公开的。算法大体如下: 如果你能够确认文件 <= 4M,那么 hash = UrlsafeBase64([0x16, sha1(FileContent)])。也就是,文件的内容的sha1值(20个字节),前面加一个byte(值为0x16),构成 21 字节的二进制数据,然后对这 21 字节的数据做 urlsafe 的 base64 编码。 如果文件 > 4M,则 hash = UrlsafeBase64([0x96, sha1([sha1(Block1), sha1(Block2), …])]),其中 Block 是把文件内容切分为 4M 为单位的一个个块,也就是 BlockI = FileContent[I*4M:(I+1)*4M]。 为何需要公开 hash/etag 算法?这个和 “消重” 问题有关,详细见: https://developer.qiniu.com/kodo/kb/1365/how-to-avoid-the-users-to-upload-files-with-the-same-key http://segmentfault.com/q/1010000000315810 为何在 sha1 值前面加一个byte的标记位(0x16或0x96)? 0x16 = 22,而 2^22 = 4M。所以前面的 0x16 其实是文件按 4M 分块的意思。 0x96 = 0x80 | 0x16。其中的 0x80 表示这个文件是大文件(有多个分块),hash 值也经过了2重的 sha1 计算。 语言封装 C# 实现 基于官方仓库的csharp代码做了部分修改...