得闲这几天借公司的邮箱,搞了个Azure OpenAI的账号,OPENAI基本所有的模型都可以正常访问了,其中第一次比较快,第二次申请GPT-4需要了一段时间,成功了也没通知,我今天上去才看到的,体验了一下确实比3.5回答细致了一些,下载了BotGem,在手机端试用,感觉效果还不错,然后又开通了speech studio,体验了一下语音合成功能,感觉还不错。(写这个的时候baidu的copilot一直在提示,还凑合)
有几个注意点
1.BotGem输入账号的时候openai和azure是分开的
2.不管什么模型都是需要收费的,绑定信用卡
3.无GFW,除了公司邮箱开通服务,其他都很舒服
4.可以开通speech服务,botgem也提供接入,但是距离openai的那种自然人声自然对话还差很远

另外之前安卓和ios端都登录不了openai的app,一直都提示ISP的问题,感觉和代理有一定的关系,网页端换了个gmail的邮箱注册就进去了,不知道为什么只有3.5,目前还没有看到4o(这个是有免费的,azure的没有)。

对于CHATGPT,我还是很看好的,毕竟我之前接了个说明书展示的网页,底子就是国内的模型写的,很多布局你描述清楚了,js html css都能一次性给你搞出来。

最近又在折腾一些小东西,随便写了一个小工具,在同步代码的时候遇到了一些问题:无法推送代码到github上,于是就上网搜了一下,发现了一个方法:https://blog.csdn.net/weixin_46850857/article/details/126376489

缺点其实就是微信的这个开发者工具不会告诉你具体原因(因为贪图它的一键上传)
1.不能够使用https 只能使用ssh url
2.无法使用用户名/密码的方式,选择的指定密钥,添加了pub和private(口令我是空)

总的来说小程序的代码很简单,但是受限于微信的限制,有一些布局不如原生的随心所欲,项目还在编写,虽然初步的功能有了,但是还打算迭代一下。另外有个copilot的平替,百度的comate,目前看到代写UT comments感觉还是很实用的,包括tab的填充内容,我在写这一部分markdown的时候就有一部分语句采用的他的,感觉还是很智能的。

ChatGPT

目前利用chatgpt其实可以解决很多现实中的问题,比如说前一段时间帮我表姐写了一个简单的说明书网页显示,自己搞定了前端的页面(preview/login/admin page),配合eggjs的后端渲染能力轻松搞定增删改查,阿里云的部署,ICP备案一条龙服务,虽然是个很小的项目,大项目该走的流程也都走了一遍。
话具体的说来gpt的帮助远比我想象中的好一些,英文的答案也比想象中更加的充分一些,目前国内的访问途径基本就如下几种

  • 付费openai(direct/indirect)
  • 国产平替

目前github也有一些大模型的统一界面比如什么chatall什么的,今天我看了一眼chatGPT-NextWeb, 目前支持azure/openai/google,其他的一些软件可能支持的全一些。
巧的是我通过公司的邮箱地址成功申请下来了azure的openai服务,填了url和azure-api-key就可以直接访问了,提问了十几次,预算是CNY0.17,在gpt-3.5-turbo的下面也算是国内访问最便捷的方式了,缺点就是目前该项目只支持端侧和网页,不支持移动端,不过好消息是比较稳定目前。
GPT-4其实也可以在申请配额(quota increase)不过相对于几乎0.2元一次的价格(几乎),还是有一点肉疼,不过先尽量发挥3.5的潜力,毕竟有他的帮助,感觉还是很轻松。

另外提一嘴,azure的付费模式和阿里云完全不同,接口走的是先用后付,openai会挂载在subscription的下面,然后使用绑定信用卡就可以了(好像是要求visa/master,我正好有一张就没有在尝试别的,国内办理也很好办理)

很久没有打开hexo了,发现了很多新的功能

  1. 更便捷的theme管理方式
  2. 更友好的部署方式git action
1
2
3
4
5
6
cd hexo-site
$ npm install hexo-theme-next@latest
cp node_modules/hexo-theme-next/_config.yml _config.next.yml

//update theme in config.yml
theme: next

解决了早期theme无法很好备份的问题
link: https://theme-next.js.org/docs/getting-started/

另外介于typora已经开始收费了,vscode开启了markdwon all in one开始在vscode里面直接进行创作

github action遇到了一些问题,主要是一些保护规则,
//Branch x is not allowed to deploy to github-pages due to environment protection rules
比如我用的部署分支是source不是常见的main/master,在github 项目的setting–environment–里面改变规则即可,个人感觉action的方式比一键部署更加方便一些

144. 二叉树的前序遍历

总体思路递归,easy等级

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number[]}
*/
var preorderTraversal = function (root) {
const ans = [];
recursion(root, ans);
return ans
};
function recursion(root, ans) {
if (root === null) return;
ans.push(root.val);
recursion(root.left, ans)
recursion(root.right, ans)
}

Leetcode 671

671. 二叉树中第二小的节点

难度简单198收藏分享切换为英文接收动态反馈

给定一个非空特殊的二叉树,每个节点都是正数,并且每个节点的子节点数量只能为 20。如果一个节点有两个子节点的话,那么该节点的值等于两个子节点中较小的一个。

更正式地说,root.val = min(root.left.val, root.right.val) 总成立。

给出这样的一个二叉树,你需要输出所有节点中的第二小的值。如果第二小的值不存在的话,输出 -1

示例 1:

img

1
2
3
输入:root = [2,2,5,null,null,5,7]
输出:5
解释:最小的值是 2 ,第二小的值是 5 。

示例 2:

img

1
2
3
输入:root = [2,2,2]
输出:-1
解释:最小的值是 2, 但是不存在第二小的值。

提示:

  • 树中节点数目在范围 [1, 25]
  • 1 <= Node.val <= 231 - 1
  • 对于树中每个节点 root.val == min(root.left.val, root.right.val)

Solution

如题意,父节点就是最小值,借鉴了答案,递归条件写错了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
var findSecondMinimumValue = function (root) {

let ans = -1;
const parentValue = root.val;//root value

const dfs = (node) => {
if (node === null) {
return;
}
if (ans !== -1 && node.val >= ans) {
return;
}
if (node.val > parentValue) {
ans = node.val;
}
dfs(node.left);
dfs(node.right);
}

dfs(root);
return ans;
};

#Leetcode-1109. 航班预订统计

难度中等157收藏分享切换为英文接收动态反馈

这里有 n 个航班,它们分别从 1n 进行编号。

有一份航班预订表 bookings ,表中第 i 条预订记录 bookings[i] = [firsti, lasti, seatsi] 意味着在从 firstilasti包含 firstilasti )的 每个航班 上预订了 seatsi 个座位。

请你返回一个长度为 n 的数组 answer,其中 answer[i] 是航班 i 上预订的座位总数。

示例 1:

1
2
3
4
5
6
7
8
9
输入:bookings = [[1,2,10],[2,3,20],[2,5,25]], n = 5
输出:[10,55,45,25,25]
解释:
航班编号 1 2 3 4 5
预订记录 1 : 10 10
预订记录 2 : 20 20
预订记录 3 : 25 25 25 25
总座位数: 10 55 45 25 25
因此,answer = [10,55,45,25,25]

示例 2:

1
2
3
4
5
6
7
8
输入:bookings = [[1,2,10],[2,2,15]], n = 2
输出:[10,25]
解释:
航班编号 1 2
预订记录 1 : 10 10
预订记录 2 : 15
总座位数: 10 25
因此,answer = [10,25]

提示:

  • 1 <= n <= 2 * 104
  • 1 <= bookings.length <= 2 * 104
  • bookings[i].length == 3
  • 1 <= firsti <= lasti <= n
  • 1 <= seatsi <= 104

Solution

题目到是很简单,主要做的就是一维数组做个累加,时间复杂度O(N^2)

1
2
3
4
5
6
7
8
9
10
11
12
13
var corpFlightBookings = function (bookings, n) {
const answer = [];
for (let i = 0; i < n; i++)answer.push(0);
for (let item of bookings) {
const [first, last, seats] = item;
for (let j = first; j <= last; j++) {
answer[j-1] += seats;
}
}
return answer;

};
console.log(corpFlightBookings([[1, 2, 10], [2, 3, 20], [2, 5, 25]], 5))

但是时间只超过了50%,就考虑问题

问题应该在O^2的复杂度上

后来想遍历的时候

  • Array(n).fill(0) 代码更优美
  • 增量加在数组里,最后走for循环跑一次就可以降一层for循环
1
2
3
const [first, last, seats] = item;
answer[first - 1] += seats;
if (last < n) answer[last] -= seats;

LeetCode:剑指 Offer 53

打开网页,突然看到日推是easy难度,本来想就几行代码的事情,弄完了就休息了,提交后–傻了眼–:cry:,居然只打败了6.27%的人,草率了

题目:

剑指 Offer 53 - I. 在排序数组中查找数字 I

统计一个数字在排序数组中出现的次数。

示例 1:

输入: nums = [5,7,7,8,8,10], target = 8
输出: 2
示例 2:

输入: nums = [5,7,7,8,8,10], target = 6
输出: 0

限制:

0 <= 数组长度 <= 50000

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// first commit
// 执行用时:2 ms, 在所有 Java 提交中击败了6.27%的用户
// 内存消耗:40.8 MB, 在所有 Java 提交中击败了98.84%的用户
class Solution {
public int search(int[] nums, int target) {
if(nums==null||nums.length<0){
return 0;
}
int count = 0;
for (Integer num : nums) {
if(num>target)break;
if (target == num)
count++;
}
return count;
}
}

找到了耗时1ms的答案一看,是foreach替换成了for循环 果然下标访问更快一些

以下贴一个最优解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public int search(int[] nums, int target) {
// 就是left right 更快的定位,总体复杂度差不多,不过
int left = getRight(nums,target-1);
int right = getRight(nums,target);
return right-left;

}
public int getRight(int[] nums ,int target){
int left = 0;
int right = nums.length-1;

while(left<=right){
int mid = (left+right)/2;
if(nums[mid]>target){
right = mid-1;
}
else if(nums[mid]<=target){
left = mid + 1;
}
}
return left;
}

}

Prototype

含义:proto(/ˈproʊtə/)原始, 原型, 原始的

目的:补充JavaScript对于对象的支持,通过protype来实现class中的method

过程:熟悉实例对象<—>构造函数<—>原型 三者之间的关系

1
2
3
4
5
6
7
//构造函数 创建对象
function Dog() {

}
var dog = new Dog();//Person 为构造函数,person为实例对象
dog.name = '柯基';
console.log(dog.name) // 柯基
  • 构造函数通过prototype访问原型(一个类的属性,对象都可以访问)
  • 实例对象通过 _proto_ 访问原型 === 构造函数通过prototype访问原型(原型也有_proto_
  • 实例原型通过constructor访问构造函数(Dog=== Dog.prototype.constructor)

image-20210224154735705

  • 原型遵循向上原则,即找不到就不断向上(prototype)查询
  • 原型因为不停延长形成链,称作原型链,但是 Object.prototype.__proto__ 的值为 null 跟 Object.prototype 没有原型
  • 原型链大概实现了类(Class)以及继承(Extend)的问题,但它并不是复制,是建立一种关联,通过prototype/_proto_ 来访问其他对象的属性和方法,属于委托/借用

Extend

一共分为6种

  • 原型链继承
  • 借用构造函数(经典继承)
  • 组合继承
  • 原型式继承
  • 寄生式继承
  • 寄生组合式继承

原型链继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Parent () {
this.names = ['kevin', 'daisy'];
}
function Child () {}
Child.prototype = new Parent();

var child1 = new Child();

child1.names.push('yayu');

console.log(child1.names); // ["kevin", "daisy", "yayu"]

var child2 = new Child();

console.log(child2.names); // ["kevin", "daisy", "yayu"]

问题:

  • 属性被所有child共享
  • 创建child实例时,不能向parent传参

借用构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Parent (name) {
this.name = name;
}

function Child (name) {
Parent.call(this, name);
}

var child1 = new Child('kevin');

console.log(child1.name); // kevin

var child2 = new Child('daisy');

console.log(child2.name); // daisy

有点:

  • 避免引用类型的属性被所有实例共享
  • 可以在Child中间parent传参

缺点:

  • 方法在构造函数中定义,每次创建势力都会创建一遍方法

组合继承

以上两种方法的组合,为最常用的继承方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function Parent (name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}

Parent.prototype.getName = function () {
console.log(this.name)
}

function Child (name, age) {
Parent.call(this, name);
this.age = age;
}

Child.prototype = new Parent();
Child.prototype.constructor = Child;

var child1 = new Child('kevin', '18');

child1.colors.push('black');
console.log(child1.name); // kevin
console.log(child1.age); // 18
console.log(child1.colors); // ["red", "blue", "green", "black"]

var child2 = new Child('daisy', '20');

console.log(child2.name); // daisy
console.log(child2.age); // 20
console.log(child2.colors); // ["red", "blue", "green"]

link:mysql-docker

支持标签

快速手册

什么是 MySQL?

MySQL 是最受欢迎的,开源的数据库. 凭借被验证过的性能表现,可靠性,易用性, MySQL已经成为基于web的应用程序的 主要选择,包括完整得个人项目和网站项目(电子上午,信息服务),也包括优秀的Facebook Facebook, Twitter, YouTube, Yahoo!

如何使用mysql image

创建 mysql 服务实例

启动 MySQL 比较简单:

1
$ docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
  • some-mysql 容器名称
  • my-secret-pw 是root账户的密码
  • tag 是mysql的版本

通过mysql命令行连接mysql

以下命令可以启动mysql容器并运行终端,执行SQL语句

1
$ docker run -it --network some-network --rm mysql mysql -hsome-mysql -uexample-user -p
  • some-mysql 容器名称
  • some-network 连接网络(方便容器间访问)

也可以直接运行客户端,访问远程数据库

1
$ docker run -it --rm mysql mysql -hsome.mysql.host -usome-mysql-user -p

更多命令请访问 MySQL documentation

使用docker stack 或docker-compose部署

示例stack.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Use root/example as user/password credentials
version: '3.1'
services:

db:
image: mysql
command: --default-authentication-plugin=mysql_native_password
restart: always
environment:
MYSQL_ROOT_PASSWORD: example

adminer:
image: adminer
restart: always
ports:
- 8080:8080
  • docker stack deploy -c stack.yml mysql
  • docker-compose -f stack.yml up

启动后, 访问 http://swarm-ip:8080, http://localhost:8080, or http://host-ip:8080

shell访问查看 MySQL 日志

使用 docker exec 可以让你在容器内执行命令,命令如下

1
$ docker exec -it some-mysql bash

容器日志:

1
$ docker logs some-mysql

自定义 MySQL 配置文件

mysql默认配置文件在 /etc/mysql/my.cnf, 也可能指定了额外文件如: /etc/mysql/conf.d or /etc/mysql/mysql.conf.d. 请检查mysqlimage本身的相关文件和目录以了解更多信息

如果 /my/custom/config-file.cnf 是你自定义的文件未知和名字, 你可以这样启动你的mysql 容器

1
$ docker run --name some-mysql -v /my/custom:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag

你会启动一个用你自定义配置 /etc/mysql/my.cnf and /etc/mysql/conf.d/config-file.cnf, 的mysql容器

不使用cnf 文件配置

很多配置都可以传给 mysqld. 使你自定义容器而不需要 cnf 文件. 如当你想改变默认编码和排序规则,使用 UTF-8 (utf8mb4) 只需要执行如下命令:

1
$ docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

如果你想看到所有的配置项,只需要执行:

1
$ docker run -it --rm mysql:tag --verbose --help

环境变量

docker run 时,可以一个或多个参数进行配置. 不过需要注意,如果使用已经包含数据库的数据目录启动容器,以下变量不会产生影响,在启动时,任何预先存在的数据库都保持不变,任何之前存在的数据库在容器启动时将保持不变.

MYSQL_ROOT_PASSWORD

该变量是必须的,是root账户的密码.

MYSQL_DATABASE

该变量可选,允许在启动时,指定数据库的名称. 如果提供了用户名/密码,用户会被赋予超级权限.

MYSQL_USER, MYSQL_PASSWORD

可选变量,用于创建新用户和密码,用户将获得超级管理员权限,两个参数都是必须的.

注意:不需要使用该机制来创建root超级用户,默认使用 MYSQL_ROOT_PASSWORD 来创建密码

MYSQL_ALLOW_EMPTY_PASSWORD

可选变量,设置非空值(如yes),允许root用户无密码启动容器. 注意: 除非你知道你在做什么,否则不建议设置为 yes ,因为这将使mysql实例完全不受保护,允许所有人获得完全的超级用户权限.

MYSQL_RANDOM_ROOT_PASSWORD

可选变量,设置非空值(如yes),使用pwgen , 为root用户随机生成密码 .密码将被打印.

MYSQL_ONETIME_PASSWORD

设置用户 初始化完成后过期,在首次登录时候强制修改密码. 任何非空值将激活这个配置,注意:仅支持5.6+版本,以下版本会报错

MYSQL_INITDB_SKIP_TZINFO

默认,entrypoint脚本自动加载CONVERT_TZ()函数需要的时区数据,如果不需要,任何非空值都将禁用时区加载

Docker Secrets

通过环境变量传递敏感信息,还有另一种方法, _FILE 可以附加到前面列的环境变量,使得可以从文件中的变量初始化脚本,特别是,这可以用于存在/run/secrets/<secret_name>中的docker screts从加载密码, 如 :

1
$ docker run --name some-mysql -e MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql-root -d mysql:tag

目前仅支持: MYSQL_ROOT_PASSWORD, MYSQL_ROOT_HOST, MYSQL_DATABASE, MYSQL_USER, 和MYSQL_PASSWORD.

初始化新实例

刚启动容器,指定名字的新数据库会被创建,并且根据提供的变量初始化. 此外,它将执行扩展名为.sh, .sql.sql.gz/docker-entrypoint-initdb.d文件夹中).文件将按照字幕顺序执行. 你可以轻松使用dump备份填充,. 默认情况下,sql文件将被保存在 MYSQL_DATABASE 指定的数据库中.

Caveats//告诫

数据存储在哪里

重要内容:有几种方式在容器运行时存储数据. 我们推荐 mysql 用户熟悉可用的选项,包括:

  • 让docker使用自己的内部volume 将数据库文件写入主机系统上的磁盘(而不在容器内)从而管理数据库数据的存储。这也是默认的配置,也非常简单透明。缺点是相比直接部署找文件困难.
  • 在主机上创建一个数据目录,并将其装载到容器内部的一个目录中,使得数据库文件放置在主机已知的位置上,更轻松访问文件,缺点是需要确保目录存在,且有权限和安全机制

Docker 文档是理解不同存储选项和变量的最好起步,并且有很多博客论坛讨论并提供建议,我们将简单展示基本过程:

  1. 创建文件夹在主机如 /my/own/datadir.

  2. 启动 mysql 容器

    1
    $ docker run --name some-mysql -v /my/own/datadir:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag

-v /my/own/datadir:/var/lib/mysql/my/own/datadir 目录从主机装入容器中作为 /var/lib/mysql 默认不传-v情况下,mysql将写入其他数据文件.

直到初始化完成才有连接

如果容器启动没有初始化数据库,则创建默认数据库. 初始化完成之前不会接受传入连接. 在使用自动化工具如 docker-compose同时启动多个容器时,这可能会导致问题.

如果应用尝试连接不提供服务的mysql,需要继续重试等待连接成功. 官方示例, 详见 WordPress or Bonita.

现用数据库使用

如果在一个有mysql数据目录的volume启动mqsql,应省略 $MYSQL_ROOT_PASSWORD命令; 及时填写也不会生效, 且不会更改预先存在的数据库.

以任意用户身份运行

如果你正确设置了目录权限,或者你需要使用特定的uid/gid运行mysqld,则可以通过 --user 设为任意值(root/0外)来实现所需的权限/配置:

1
2
3
4
$ mkdir data
$ ls -lnd data
drwxr-xr-x 2 1000 1000 4096 Aug 27 15:54 data
$ docker run -v "$PWD/data":/var/lib/mysql --user 1000:1000 --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag

创建备份

大多数工具都会正常工作,尽管他们的使用在某些情况下可能有点复杂, 以确保可以访问mysqld服务器,确保这一点的一个简单方法是使用 docker exec 并从同一容器运行工具,如:

1
$ docker exec some-mysql sh -c 'exec mysqldump --all-databases -uroot -p"$MYSQL_ROOT_PASSWORD"' > /some/path/on/your/host/all-databases.sql

从备份还原数据

1
$ docker exec -i some-mysql sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD"' < /some/path/on/your/host/all-databases.sqlwith any relevant licenses for all software contained within.1
0%