使用 gpt 改造你的小米音箱

前言 前段时间看到了一个项目 mi-gpt ,可以将你的小爱音箱接入 gpt,改造成专属于你的语音助手。 接下来就由作者来介绍小爱同学从零接入 deepseek 的过程。 设置环境变量和配置文件 mi-gpt 有两种部署方式,一是使用 docker 部署,二是使用 Node.js 进行部署,本文使用 docker 进行部署使用。 需要提供两个文件 .env 和 .migpt.js 文件,.migpt.js 是配置文件,包括一些配置,.env 是环境变量文件,存放 gpt 密钥相关文件。文件的例子可以从仓库里复制,然后进行相应的修改。 启动 使用以下命令启动 docker: docker run -d --env-file $(pwd)/.env -v $(pwd)/.migpt.js:/app/.migpt.js idootop/mi-gpt:latest windows 环境下需要将$(pwd)替换为绝对路径。 启动后可以通过 callAIKeywords 设置的关键字调用 ai 来响应用户的消息。 小结 本文介绍了使用 mi-gpt 升级你的闲置的小爱音箱,通过简单的测试和使用,个人感觉还不够完善,稳定性不够好,感兴趣的读者可以根据本文的内容进行自行搭建尝试. 参考 https://github.com/idootop/mi-gpt

一月 27, 2025 · overstarry

node.js项目构建问题及解决

前言 今天在编译构建一个 node.js 项目时,在构建过程中遇到了一些问题,本文将记录问题及对应的解决方案。 问题1 在执行 npm run build 遇到此提示: error Expected linebreaks to be 'LF' but found 'CRLF' linebreak-style 根据信息可以看出是 eslint 的报错,查看 .eslintrc.js 文件,修改linebreak-style对应的行: 'linebreak-style': ['error', process.platform === 'win32' ? 'windows' : 'unix'], 重新运行命令,顺利构建成功。 这个问题的原因是项目的作者可能是使用 Linux 或 Mac 构建的,没有考虑 Windows 的情况,通过这行配置,可以根据运行的环境来决定 lint 规则。 问题2 在执行 npm start 遇到了第二个问题: Generating browser application bundles (phase: building)...node:internal/crypto/hash:79 this[kHandle] = new _Hash(algorithm, xofLen, algorithmId, getHashCache()); ^ Error: error:0308010C:digital envelope routines::unsupported at new Hash (node:internal/crypto/hash:79:19) at Object.createHash (node:crypto:139:10) at BulkUpdateDecorator.hashFactory (D:\code\xx\node_modules\webpack\lib\util\createHash.js:145:18) at BulkUpdateDecorator.update (D:\code\xx\node_modules\webpack\lib\util\createHash.js:46:50) at RawSource.updateHash (D:\code\xx\node_modules\webpack\node_modules\webpack-sources\lib\RawSource.js:77:8) at NormalModule._initBuildHash (D:\code\xx\node_modules\webpack\lib\NormalModule.js:880:17) at handleParseResult (D:\code\xx\node_modules\webpack\lib\NormalModule.js:946:10) at D:\code\xx\node_modules\webpack\lib\NormalModule.js:1040:4 at processResult (D:\code\xx\node_modules\webpack\lib\NormalModule.js:755:11) at D:\code\xx\node_modules\webpack\lib\NormalModule.js:819:5 { opensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error', 'error:0308010C:digital envelope routines::unsupported' ], library: 'digital envelope routines', reason: 'unsupported', code: 'ERR_OSSL_EVP_UNSUPPORTED' } 根据这个报错,推测可能是啥 hash 算法不支持,通过查阅相关资料,得到以下解决方案: ...

十二月 28, 2024 · overstarry

go 解析 csv 文件报错

问题 最近在使用 go 解析 csv 文件时,读取并打印 csv 的每行内容时,读取到第11行时,程序报错,提示: record on line 11: wrong number of fields 分析 遇到这个问题,我第一反应是 csv 文件的格式有问题,于是我使用 cat 命令查看 csv 文件,发现 csv 文件的格式是正确的,没有问题。 并查看分隔符是正确的,于是可以得出 csv 文件是没有问题的。 接下来就查看所使用的标准库 encoding/csv, 通过查阅文档及 issue, 发现 csv 包中的 FieldsPerRecord 字段,FieldsPerRecord表示csv 文件每行的预期字段数, 如果为正数,则读取的每条记录都必须有对应的字段数,如果为0,则会以第一条记录的数量为标准,接下来每行都必须有对应的字段数,如果为负数,则不会检查字段数。 修改后的代码如下: package main import ( "encoding/csv" "fmt" "io" "log" "os" ) func main() { file, err := os.Open("./xx.csv") if err != nil { log.Fatal(err) } defer file.Close() // 创建一个 CSV reader reader := csv.NewReader(file) reader.FieldsPerRecord = -1 // 循环读取 CSV 文件中的每一行数据 for { record, err := reader.Read() if err == io.EOF { break } if err != nil { log.Fatal(err) } // 处理每一行数据 fmt.Println(record) fmt.Println(len(record)) } } 小结 本文记录了在使用 go 解析csv时遇到字段数不匹配的问题,并分析了问题的原因,并给出了相应的解决方法。 ...

十二月 5, 2024 · overstarry

Go Recivie Email

前言 电子邮件是现代办公和通信中不可或缺的工具,它广泛应用于数据交换和工作沟通。为了更高效地处理邮件内容,我们可以借助程序来实现自动化处理。本文将详细介绍如何使用 Go 语言来接收和处理电子邮件。 通过查阅资料,了解到可以通过 IMAP 协议来接收电子邮件,IMAP 协议是电子邮件接收协议,它允许客户端通过网络连接到邮件服务器,并从服务器上下载邮件。除了 IMAP 协议,还有 POP3 协议,POP3 协议与 IMAP 协议类似,但它在在客户端上对邮件的操作不会反馈到邮件服务器上,也就是说,在客户端的操作不会影响服务器上的邮件。当你需要从多个邮件客户端访问邮件时,IMAP 协议是一个更好的选择。 go-imap 通过对比不同的库,最后选择了 go-imap 库,它是一个基于 IMAP 协议的 Go 语言库,可以通过它构建客户端或者服务端。 安装 可以通过以下命令安装: go get github.com/emersion/go-imap 使用 我们将通过官方的例子进行切入: 先通过 DialTLS 连接对应的电子邮箱 IMAP 服务器,然后通过登录邮箱,获取所有的邮箱文件夹,最后选择收件箱,获取收件箱中最新的4封邮件,并打印没封邮件的主题。 运行代码: 2024/11/23 16:16:11 Connecting to server... 2024/11/23 16:16:11 Connected 2024/11/23 16:16:12 Logged in 2024/11/23 16:16:12 Mailboxes: 2024/11/23 16:16:13 * 其他文件夹 2024/11/23 16:16:13 * Drafts 2024/11/23 16:16:13 * Deleted Messages 2024/11/23 16:16:13 * Sent Messages 2024/11/23 16:16:13 * Junk 2024/11/23 16:16:13 * INBOX 2024/11/23 16:16:13 Flags for INBOX: [\Answered \Flagged \Deleted \Draft \Seen] 2024/11/23 16:16:13 Last 4 messages: 2024/11/23 16:16:13 * =?GBK?B?xx?= 2024/11/23 16:16:13 * =?GBK?B?xxx?= 2024/11/23 16:16:13 * =?GBK?B?xx==?= 2024/11/23 16:16:13 * =?GBK?B?xx+k=?= 2024/11/23 16:16:13 Done! 可以看到打印出来的邮件主题是乱码,通过查询资料,了解到邮件的字段是采用特殊编码的,需要进行解码。可以通过https://github.com/emersion/go-message 这个库进行解码。 ...

十一月 23, 2024 · overstarry

go-soap 简介

前言 最近需要调用一个第三方的接口进行数据的采集,这个接口是基于 SOAP 协议的,所以需要使用soap 相关的客户端进行调用。于是我调研了一些开源的 golang 的 soap 客户端,发现 go-soap 这个库的文档比较完善,而且使用起来也比较简单,所以就选择了这个库。 安装 使用以下命令进行安装: go get github.com/tiaguinho/gosoap 使用 由于目前没有特别好的例子,这里就以官方的例子进行说明。 官方的代码如下: package main import ( "encoding/xml" "log" "net/http" "time" "github.com/tiaguinho/gosoap" ) // GetIPLocationResponse will hold the Soap response type GetIPLocationResponse struct { GetIPLocationResult string `xml:"GetIpLocationResult"` } // GetIPLocationResult will type GetIPLocationResult struct { XMLName xml.Name `xml:"GeoIP"` Country string `xml:"Country"` State string `xml:"State"` } var ( r GetIPLocationResponse ) func main() { httpClient := &http.Client{ Timeout: 1500 * time.Millisecond, } soap, err := gosoap.SoapClient("http://wsgeoip.lavasoft.com/ipservice.asmx?WSDL", httpClient) if err != nil { log.Fatalf("SoapClient error: %s", err) } // Use gosoap.ArrayParams to support fixed position params params := gosoap.Params{ "sIp": "8.8.8.8", } res, err := soap.Call("GetIpLocation", params) if err != nil { log.Fatalf("Call error: %s", err) } res.Unmarshal(&r) // GetIpLocationResult will be a string. We need to parse it to XML result := GetIPLocationResult{} err = xml.Unmarshal([]byte(r.GetIPLocationResult), &result) if err != nil { log.Fatalf("xml.Unmarshal error: %s", err) } if result.Country != "US" { log.Fatalf("error: %+v", r) } log.Println("Country: ", result.Country) log.Println("State: ", result.State) } 可以看到 go-soap的使用跟常规的 http client的使用方法类似,都是创建一个连接,准备方法的参数,然后调用相应的方法。 这段代码展示了如何使用 go-soap 库连接 SOAP 服务、发送请求、处理响应,以及如何解析 XML 格式的返回数据。 ...

十月 4, 2024 · overstarry

Docker Desktop 设置网络代理

前言 最近遇到 Docker Desktop 构建 node 项目时,由于网络问题导致的构建失败问题,本文将介绍两个给 Docker Desktop 设置网络代理的方法。 修改 WSL2 配置 为了测试代理的效果,这里创建一个go服务,代码很简单,就是访问 https://www.google.com/ 并返回结果。如果能正常访问,说明代理设置成功。 package main import "net/http" func main() { resp, err := http.Get("https://www.google.com/") if err != nil { panic(err) } defer resp.Body.Close() println(resp.Status) } 第一种方法是修改 WSL2 的配置,在 windows C:\Users<your_username> 目录下创建 .wslconfig 文件,输入以下内容: [experimental] autoMemoryReclaim=gradual networkingMode=mirrored dnsTunneling=true firewall=true autoProxy=true 然后重启 WSL: wsl --shutdown networkingMode 为mirrored 表示网络模式使用镜像模式,会镜像宿主机的网络设置,能更好的集成宿主机和WSL的网络。 autoProxy 开启了自动代理的功能,意味 WSL 自动配置代理设置。 配置好,我们构建 Docker 镜像,运行: 可以看到代理成功生效,可以正常访问。 接下来介绍通过修改 Docker Desktop 的配置文件,设置代理。 修改 Docker Desktop 配置 打开 Docker Desktop 的设置,找到 Resources Proxies 选项,设置代理。 ...

九月 21, 2024 · overstarry

如何在 Github Pages 上部署 Hugo 网站

前言 本文将介绍当初我搭建这个博客网站的时候,是如何将 Hugo 网站部署到 GitHub 上的,本文会采用与 hugo 官方不同的方式进行部署。 创建仓库 首先我们在 GitHub 上创建一个仓库,仓库名称为 username.github.io,其中 username 为你的 GitHub 用户名。这个仓库是用来存储hugo最终生成的静态网站文件的。再创建一个名称为 blogs 的仓库,这个仓库是用来存储 hugo 网站源内容文件的。 启用 GitHub Pages 在 username.github.io 仓库中,点击 Settings 选项卡,在 GitHub Pages 中选择 Source 为 从分支部署,然后点击 Save 按钮。 启用 GitHub Actions 接下来要实现提交 hugo 网站源文件到 blogs 仓库后,自动将 hugo 网站源文件编译成静态网站文件,并提交到 username.github.io 仓库中,这样就可以通过访问 username.github.io 仓库来访问 hugo 网站了。 生成 personal_token 在配置 Actions 前,需要先生成 personal_token,用于在 GitHub Actions 中使用。我们进入 Settings 选项卡,在 Developer settings 中选择 Personal access tokens,然后选择 Tokens (classic), 然后点击 Generate new token 下的Generate new token(classic)按钮,在 Note 中输入 blog,在 Expiration 中选择 No expiration,在 Select scopes 中选择 repo 和 admin:repo_hook,然后点击 Generate token 按钮,生成 personal_token。 ...

八月 31, 2024 · overstarry

V0.dev chat

v0.dev chat 介绍 v0.dev chat 是 vercel 推出的最新的生成式 AI 聊天机器人,可以通过用户对话的方式来生成相应的 react 代码。 v0.dev chat 相比 V0.dev 有以下优点: 最新的 react、next.js、web 技术知识 可以运行 npm 包 更快更可靠的流失传输 接下来将通过官方的几个例子及个人尝试的效果来讲解。 官方例子 解释 next 缓存机制 打开 https://v0.dev/chat/E8fIPvg, 可以看到 bot 很好的通过图表及文字讲述了 next 的缓存机制。 贪吃蛇游戏 打开这个 https://v0.dev/chat/AjJVzgx ,可以看到用户上传蛇的皮肤并一步步引导 bot 生成贪吃蛇游戏。 个人尝试 接下来将通过一个简单的视频网站例子来尝试 v0.dev chat 的效果。 先通过简单的提示生成视频网站的初始代码: 可以看到 bot 生成的代码是非常完整的,并且可以运行预览的。接下来继续完善视频网站。 接下来添加视频下载保存功能 接下来添加视频网站首页功能 通过不断的调整,可以慢慢的形成一个视频网站的雏形。 ...

八月 24, 2024 · overstarry

Markdown Preview Enhanced plugin introduction and simple use

前言 最近需要写总结报告,以前写总结报告时,往往使用 Word 进行编写,但由于显示排版等问题,本次采用了 Markdown 进行编写,在编写时使用了 Markdown Preview Enhanced 插件。本文介绍 Markdown Preview Enhanced 插件的安装及所使用的功能。 安装 打开 vscode编辑器,打开扩展栏,输入 Markdown Preview Enhanced ,第一个就是,点击安装后即可。 功能介绍 接下来将介绍一些在编写文档中所使用的功能。 diagrams Markdown Preview Enhanced 插件支持 low charts, sequence diagrams, mermaid, PlantUML, WaveDrom, GraphViz,Vega & Vega-lite,Ditaa 图像渲染。 在文档中我使用了 mermaid 和 Vega-lite,Vega-lite 用于绘制图表,mermaid 用于绘制流程图。 接下来介绍 markdown 中如何使用 Vega-lite 绘制图表,使用以下代码即可绘制一个漂亮的饼图: 如果想要居中的效果,可以添加 {align="center"}来设置居中的效果。 mermaid 可以用来绘制流程图,使用以下代码即可绘制一个简单的流程图: 如果我们想要添加 css 效果该怎么办呢,可以通过 HTML + css 的形式来显示我们想要的效果: ...

八月 23, 2024 · overstarry

go humanize介绍

前言 今天在 Github 查看一些开源项目时,发现了一个"人性化"的项目 go-humanize,此项目可以将一些常见的容量、时间、千分位转换为人们可以理解的形式,例如一个文件大小是 2000000 bytes,我们不能很好的理解,但如果告诉你是 2mb,我们就能很好的理解了。 go-humanize 就是方便的将一些不太能快速理解的数字转换为人们可以理解的形式。 安装 使用以下命令安装: go get github.com/dustin/go-humanize 使用 接下来分别介绍一些常见的功能。 容量转换 现在我们有一个文件大小是 52854982 bytes,我们使用 humanize 包的 Bytes 方法将其转换为人们可以理解的形式 53MB,也可以使用IBytes方法转换为MIB单位的值。也可以使用ParseBytes方法将可以理解的形式转换为bytes单位的值。 fmt.Printf("That file is %s.\n", humanize.IBytes(52854982)) fmt.Printf("That file is %s.", humanize.Bytes(52854982)) 时间转换 时间转换与容量转换类型,使用方法十分类似,使用方法如下: t := time.Now().Add(time.Hour * -7) fmt.Printf("This was touched %s.", humanize.Time(t)) //This was touched 7 hours ago. Time 根据相对时间转换为人们可以理解的形式,例如: xx天之前、xx小时之后等形式。 千分位转换 如果我们想在数字中添加逗号,就可以使用 Comma 方法,例如在处理金额时,我们通常会使用逗号将数字分隔开,例如 1,000,000,000 fmt.Printf("num is %s.", humanize.Comma(1000000000)) 还可以使用 Commaf 方法将浮点数转换为千分位形式。 位序 在日常使用中,我们有时需要表示位序例如 1st、2nd、3rd、4th 等,humanize 包也提供了相应的功能。 fmt.Printf("num is %s.", humanize.Ordinal(1000000000)) 简单看了下源码,发现函数十分简单: func Ordinal(x int) string { suffix := "th" switch x % 10 { case 1: if x%100 != 11 { suffix = "st" } case 2: if x%100 != 12 { suffix = "nd" } case 3: if x%100 != 13 { suffix = "rd" } } return strconv.Itoa(x) + suffix } 小结 本文介绍了 go-humanize 包的一些使用方法,可以方便的将一些数字转换为人们可以理解的形式。go-humanize 还有一些格式化的函数,感兴趣的读者可以自行查看源码。 ...

八月 10, 2024 · overstarry