docker安装dolphinscheduler添加数据源连接失败

2024-09-27 11:14:16 [ERROR] 2024-09-27 11:14:16.055 +0800 o.a.d.p.d.a.d.AbstractDataSourceProcessor:[130] - Check datasource connectivity for: MYSQL error
2024-09-27 11:14:16 java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver

看下docker-dolphinscheduler-api-1容器的日志中发现以上失败,通过检索发现,可以把驱动包放在lib/plugin/task/sql目录下,但是,这个目录在哪里却是个问题,后来查看源代码(https://github.com/apache/dolphinscheduler/blob/3.1.0/dolphinscheduler-api/src/main/docker/Dockerfile),确定ENV DOLPHINSCHEDULER_HOME /opt/dolphinscheduler,那么进入容器的/opt/dolphinscheduler这个目录确实能看到libs子目录,其中已经有一些连接器了,只不过那些就是官方所说的符合开源协议的已经内置的,像mysql的就不符合apache的开源协议,所以只能自己往里放,可是为什么官方文档里没有提到呢?

我是搜到了https://www.bookstack.cn/read/dolphinscheduler-3.1.0-zh/7667e5f48166e75f.md,这个来自官方的早期镜像版:

我们以 MySQL 为例,如果你想要使用 MySQL 数据源,你需要先在 mysql maven 仓库 中下载对应版本的 JDBC 驱动,将其移入 api-server/libs 以及 worker-server/libs 文件夹中,最后重启 api-server 和 worker-server 服务,即可使用 MySQL 数据源。如果你使用容器启动 DolphinScheduler,同样也是将 JDBC 驱动挂载放到以上两个服务的对应路径下后,重启驱动即可。

查看对应版本的官方文档却找不到对应的章节。

目前,以3.2.2版本来说,需要放连接器的容器包括:

docker-dolphinscheduler-api-1

docker-dolphinscheduler-worker-1

docker-dolphinscheduler-alert-1

以docker desktop操作说明,找到这两个容器,点击容器名进入容器,切换到Files,/opt/dolphinscheduler/libs,右键import,选择mysql-connector-j-8.2.0.jar,然后重启以上三个容器就可以了。

坚果R2连接三星watch5手表方法(2024)

之前费了很大劲绑定的,看了很多教程,以至于最后怎么连接的都搞不清楚了。因为手机摔坏了,换了一个手机,当然,还是坚果R2。

习惯性的先装上谷歌框架,按照原来收藏的信息,怎么都连不上。看到了https://help.wearosbox.com/faq/device/samsung.html收到启发,删掉谷歌框架,只安装了:

(1)wear os中国版(在中国的应用市场上安装就是中国版)

(2)三星智能穿戴

(3)三星健康

接下来是连接步骤:

(1)装好了之后,直接打开“三星智能穿戴”连接手表,如果提示手表需要重置,则在手表的设置中选择重置,手表重启(这个时间可能要几分钟)后,手机上的“正在扫描要添加的设备”就能看到手表型号,点击以后开始蓝牙配对,手机和手表都点击确认即可。

(2)接下来一系列确认。

(3)有一个自动备份手表的步骤,看似不能跳过,先点下一步,然后拒绝就行了,当然,如果用三星的换机助手备份一下也没有问题。

(4)然后接下来又是一系列确认,然后开始配置,估计有几分钟的时间。

(5)这样就好了。

估计是三星的app升级了,重新对接了wear os中国版,消除了bug,以至于以前的折腾终于可以免去,但如果按照了谷歌框架反而会造成上面链接提到的判断“该手机无法支持”等。

(6)最后,不要删除wear os,删除了三星智能穿戴的连接也就断了。如果你以为它已经没用,把它删掉了,那就去三星智能穿戴解绑,重新连接。

另外提一句,如果直接打开wear os,不点击三星的连接,而选择第二个wear os连接手表,虽然手表设置环节不能完成,但是这时候三星健康是可以连接上手表的,手表因为停在设置状态不可用,则可以通过重启后长按logo进入“独立使用模式”,但这个时候三星健康依然能同步,相当于跳过了三星智能穿戴,只是这个链接不稳定,而且不能通过手机app设置手表,所以还是按标准三步流程连接吧。

最后的最后,解决一下将手表步数同步到微信运动。

(1)安装谷歌框架,以在google play中去安装“健康平台”这个app,或者直接找到app安装包。参考https://www.bilibili.com/read/cv25382423/?jump_opus=1,这个app是装在手表上的,手机上看不到。

(2)然后打开这个链接https://ecommerce.samsungassistant.cn/index.html#/jd/activity/748/0

(3)“点击开启插件”,只有这样能找到这个插件,接下来是授权。这个虽然叫插件,但在手机的应用程序权限管理中可以看到,可以把自启动和第三方启动打开。

(4)授权时有可能失败,可以重新打开“三星健康”的设置“三星健康设置”中的应用程序,这时应该可以看到这个插件了,点击能确认权限。

需要说明的是,以上方法并没有让我能够确认微信运动能够获得同步的步数,用最新版的三星健康app的时候甚至有报错通知,我把版本降到了Samsung Health_6.23.0.047_APKPure.apk,不报错了,但依然无法同步,我问过三星客服,想给她要最新的插件,她说不能提供。最终在手机重启也或者是等待了一段时间之后,微信可以同步步数了。

另外一个就是三星健康监测功能,这个最主要的是提供心电图,心率在三星健康中就有,不需要单独装这个,心电图在中国版默认是用不了的。简单来说,就是先在手机上安装某个伴侣软件,具体操作可以看https://www.lxtend.com/miscs/SHM_MOD_Installation_and_Setup_Guide,也可以参考https://help.wearosbox.com/faq/device/samsung.html#%E4%B8%89%E6%98%9F%E5%81%A5%E5%BA%B7%E7%9B%91%E6%B5%8B 来操作,不过按照app中的说明一步一步走问题也不大,只是大部分人第一次搞不一定熟悉它的逻辑。

如何在nginx中将laravel配置到二级目录

    # 此处配置二级目录站点
    location /sso {
        rewrite /sso/(.*)$ /sso/index.php?=$1 last; break;
        location ~ \.php$ {   
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass php80:9000;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME /www/one/one-api-sso-ywcbs/public/index.php; 
        }
    }

参考:如何使用一个域名配置多个Laravel项目?

以前一直没有找到一个可用的配置,导致laravel一直挂在根目录,其他前端项目反而都要用二级目录,终于找到一个配置可用了。可怜我对nginx的了解还是不够多。

以上配置中,php80:9000是来自docker的php80,如果用的其他的php部署方式,请按指定方式配置该项即可。

qbittorrent使用小结

本来用qbittorrent下载东西已经是二十年前的记忆了,这么多年也不刷美剧,基本上就告别了bt,最近因为某项目需要采集数据,重新接触qbittorrent,但是真拿它来干活的时候,发现伺候起来并不简单。

这一个任务一共一万多个种子,尽管家里已经升级了2000M光纤宽带,但无论是网速还是连接数恐怕也远远达不到肆意下载的程度,于是确认了一下光猫里的默认连接数为4000,调整成了20000,不知道真的上到这个数字会不会崩,后来又改回了4000。

qbittorrent里面的每个种子的连接数设置成了50,似乎太大了也没用,因为实际上没有那么多源,平均每个任务也就是四五个连接。全局最大连接数曾一度设置为1000或者2000,但通过网络监测结果来看,这么多任务同时下载很多资源花在了任务调度上,带宽利用并不好,于是将总连接数限制到了500或者200,。

后来,系统崩了,不知道为什么崩的,但任务恢复之后就发现很多下载任务变成了检查恢复,这个特别消耗资源,一则要从存储上把资源都读出来,我用的千兆网连接,速度本身就受限,再加上可能是多个任务同时检查,内存就废了。后来我启用qb以后,把绝大部分任务都暂停,然后逐个继续,才慢慢解决崩溃的问题。

总结下来有几个原则可以遵循:

(1)批量添加种子之前,打开设置,在“下载”中修改“默认保存路径”,否则默认到C盘就惨了,我第一晚下载就把C盘搞爆了,批量添加种子时选择的保存位置只对第一个有效,后面的不行。

(2)继续设置“连接”,每torrent最大连接数可以设置为50,实际上有5到10个就够用了,按平均每个5个计算,同时下载10个torrent,全局最大连接数设置成50也行,可以稍微放大一点到100或者200,再大了意义不大。

(3)如果涉及到大量任务恢复的情况,可以在重载界面后,首先把全局最大连接数设置成20,同时把所有任务暂停,然后手动分批恢复继续。

锤子科技绝代产品坚果R2手机电源键失灵解救办法

中午微信语音的时候,手机突然黑屏,然后就没法点亮了,后来尝试:

(1)办法一:音量加+电源键强制重启,重启之后可以点亮屏幕,再划动屏幕进入。

然后上网搜了办法,比如清理垃圾文件以及清理内存,我没有找到清理内存在哪里搞,因为是微信语音的时候出的问题,我尝试了删除微信,但并不解决问题。总是强制重启进入系统也不是办法(似乎单独按音量加十几秒也能强制重启,所以貌似就只是电源键坏了),于是想到第二个办法。

(2)插上充电线,给手机充电的时候,屏幕也会亮,这个时候划屏幕也能进入。

但这依然也不是个好办法,总不能随时握着充电宝啊。继续尝试,终于找到第三个办法。

(3)左侧的快捷键设置了双击打开卡包,这个时候也能点亮屏幕。

但是,这个也不能解决问题,于是想到第四个办法。

(4)淘宝上找了下维修店,报价说如果主板不坏,修一下180,如果主板坏了,修好300封顶,我没舍得,再者也还需要备份数据以及找备用机。

那么还有没有别的办法呢?如果微信删掉还不行,那就有一个办法就是重置系统,如果是微信或者别的app造成键位定义冲突,那么这个冲突除了重置还有什么办法清除呢?于是,找到第五个办法。

(5)在设置中的“任意开关和快捷键”这里,把各个快件键的设置来回改了几下,估计是改到双击电源键打开相机的时候,问题解决了。电源键不再失灵,恢复正常了。

希望你很快就看到了最后一条并解决了问题。

阿里云不再提供一年期限的免费域名SSL证书的应对策略

毫无疑问,当然是用Let’s Encrypt

那么就开始搞吧,事实上真的很简单。只是首先要搞清楚自己的部署环境,我用的是基于yeszao/dnmp改写的一个环境,大体上一样,可以直接看yeszao/dnmp。

首先我把域名解析到我的服务器,如果是一个新的域名,则在得到ssl证书之前,给该域名的站点conf中只配置80端口,443端口等后续得到了数字证书以后再添加或解除注释,免得没有ssl的文件nginx无法启动。

然后在该域名的站点的conf中添加

location ^~ /.well-known/acme-challenge/ {
      default_type "text/plain";
      root /www/acme-challenge/;
    }

注意,上面root后面对应的地址是基于dnmp的env配置的映射地址,也就是dnmp目录下的www中再新建一个acme-challenge,如果dnmp在/,则实际目录地址是/dnmp/www/acme-challenge,这个地址在下一步用的到。

添加以上规则后,重启nginx。

然后就可以使用命令创建证书了:

sudo certbot certonly --webroot -w /dnmp/www/acme-challenge/ -d "*.isbn.ink" -d isbn.ink

命令也可以明确–server参数

sudo certbot certonly --webroot -w /dnmp/www/acme-challenge/ -d "*.isbn.ink" -d isbn.ink --server https://acme-v02.api.letsencrypt.org/directory

certbot如何安装请看https://certbot.eff.org/instructions?ws=nginx&os=ubuntufocal&tab=standard

按提示执行完就行了,甚至都自动创建好了更新任务,任务查看命令:systemctl list-timers

NEXT                        LEFT               LAST                        PASSED       UNIT                           ACTIVATES                       
Fri 2024-01-26 14:11:00 CST 19min left         n/a                         n/a          snap.certbot.renew.timer       snap.certbot.renew.service

ssl证书文件默认会放在/etc/letsencrypt下面,那么结合dnmp的env配置项:

NGINX_SSL_CERTIFICATE_DIR=/etc/letsencrypt

如果有其他站点需要用到NGINX_SSL_CERTIFICATE_DIR的默认配置./services/nginx/ssl,那么还有个办法,即使用ln到/etc/letsencrypt/live:

ln -s /etc/letsencrypt/live /dnmp/services/nginx/ssl

那么,在站点的conf文件中,对443部分的设置如下:

server {
    listen 443 ssl;
    server_name isbn.ink;
    charset utf8;
    #ssl on;
    ssl_certificate   /ssl/live/isbn.ink/fullchain.pem;
    ssl_certificate_key  /ssl/live/isbn.ink/privkey.pem;
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;

    root   /www/localhost;
    index  index.php index.html index.htm;

    location / {
        if (!-e $request_filename) {
            rewrite (.*) /index.php;
        }
    }

    location ~ [^/]\.php(/|$) {
        fastcgi_pass   php80:9000;
        include        fastcgi-php.conf;
        include        fastcgi_params;
    }

}

可以看到我把live放到了conf中,而没有放在NGINX_SSL_CERTIFICATE_DIR设置中,因为live/isbn.ink/fullchain.pem是个软地址,实际文件是指向../../archive/isbn.ink/fullchain1.pem的,这里用了两层父目录,站点域名一层,live占了一层,所以ssl的映射目录只能设置为/etc/letsencrypt。

jenkins FATAL: Failed to install https://nodejs.org/dist/v16.14.2/node-v16.14.2-linux-x64.tar.gz

 > git rev-list --no-walk 7756bc509c8ed181c19b8b725a3b395e13ee7539 # timeout=10
FATAL: Failed to install https://nodejs.org/dist/v16.14.2/node-v16.14.2-linux-x64.tar.gz to /var/jenkins_home/tools/jenkins.plugins.nodejs.tools.NodeJSInstallation/nodejs16.4.2
java.net.SocketTimeoutException: connect timed out
	at java.base/java.net.PlainSocketImpl.socketConnect(Native Method)
	at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:412)
	at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:255)
	at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:237)
	at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
	at java.base/java.net.Socket.connect(Socket.java:609)
	at java.base/sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:305)
	at java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:177)
	at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:507)
	at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:602)
	at java.base/sun.net.www.protocol.https.HttpsClient.<init>(HttpsClient.java:266)
	at java.base/sun.net.www.protocol.https.HttpsClient.New(HttpsClient.java:373)
	at java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(AbstractDelegateHttpsURLConnection.java:207)
	at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1187)
	at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1081)
	at java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:193)
	at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:168)
	at hudson.FilePath.installIfNecessaryFrom(FilePath.java:993)
Caused: java.io.IOException: Failed to install https://nodejs.org/dist/v16.14.2/node-v16.14.2-linux-x64.tar.gz to /var/jenkins_home/tools/jenkins.plugins.nodejs.tools.NodeJSInstallation/nodejs16.4.2
	at hudson.FilePath.installIfNecessaryFrom(FilePath.java:1067)
	at hudson.FilePath.installIfNecessaryFrom(FilePath.java:980)
	at jenkins.plugins.nodejs.tools.NodeJSInstaller.performInstallation(NodeJSInstaller.java:145)
	at hudson.tools.InstallerTranslator.getToolHome(InstallerTranslator.java:70)
	at hudson.tools.ToolLocationNodeProperty.getToolHome(ToolLocationNodeProperty.java:109)
	at hudson.tools.ToolInstallation.translateFor(ToolInstallation.java:221)
	at jenkins.plugins.nodejs.tools.NodeJSInstallation.forNode(NodeJSInstallation.java:95)
	at jenkins.plugins.nodejs.NodeJSBuildWrapper.setUp(NodeJSBuildWrapper.java:158)
	at jenkins.tasks.SimpleBuildWrapper.setUp(SimpleBuildWrapper.java:294)
	at hudson.model.Build$BuildExecution.doRun(Build.java:158)
	at hudson.model.AbstractBuild$AbstractBuildExecution.run(AbstractBuild.java:526)
	at hudson.model.Run.execute(Run.java:1900)
	at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:44)
	at hudson.model.ResourceController.execute(ResourceController.java:101)
	at hudson.model.Executor.run(Executor.java:442)
Finished: FAILURE

我的服务器环境是在docker中跑的jenkins,幸会我是把jenkins_home绑定到宿主机了。

  jenkins:
    image: jenkins/jenkins:${JENKINS_VERSION}
    container_name: jenkins
    volumes:
        - ${JENKINS_HOME_DIR}:/var/jenkins_home
        - ${JENKINS_CERTS_DIR}:/certs/client
        - ${SOURCE_DIR}:/www/:rw
        - ${TOMCAT_WEBAPPS_DIR}:/webapps/:rw
        - /var/run/docker.sock:/var/run/docker.sock
        - /usr/bin/docker:/usr/bin/docker
        - /usr/lib/x86_64-linux-gnu/libltdl.so.7:/usr/lib/x86_64-linux-gnu/libltdl.so.7
    ports:
        - "${JENKINS_HTTP_PORT}:8080"
        - 50000:50000
    privileged: true
    user: root
    restart: always
    environment:
        TZ: "$TZ"
        JAVA_OPTS: '-Djava.util.logging.config.file=/var/jenkins_home/log.properties'
        JENKINS_OPTS: '--prefix=/jenkins'
    networks:
      - default

根据错误提示,我可以确定需要哪个文件,以及要放到什么地方。那我就从别的地方下载https://nodejs.org/dist/v16.14.2/node-v16.14.2-linux-x64.tar.gz,然后解压到/var/jenkins_home/tools/jenkins.plugins.nodejs.tools.NodeJSInstallation/nodejs16.4.2这个目录,实际上这个目录对应的是我宿主机的某个文件夹,这样也方便操作。

没想到他们连nodejs都要封。

完美解决wsl+docker的二级代理上网问题

继续上一篇,基于wsl2的docker-desktop创建fast-whisper无法正常运行,错误日志如下:

2023-07-06 17:10:29 Traceback (most recent call last):
2023-07-06 17:10:29   File "/usr/local/lib/python3.8/dist-packages/gradio/routes.py", line 394, in run_predict
2023-07-06 17:10:29     output = await app.get_blocks().process_api(
2023-07-06 17:10:29   File "/usr/local/lib/python3.8/dist-packages/gradio/blocks.py", line 1075, in process_api
2023-07-06 17:10:29     result = await self.call_function(
2023-07-06 17:10:29   File "/usr/local/lib/python3.8/dist-packages/gradio/blocks.py", line 884, in call_function
2023-07-06 17:10:29     prediction = await anyio.to_thread.run_sync(
2023-07-06 17:10:29   File "/usr/local/lib/python3.8/dist-packages/anyio/to_thread.py", line 31, in run_sync
2023-07-06 17:10:29     return await get_asynclib().run_sync_in_worker_thread(
2023-07-06 17:10:29   File "/usr/local/lib/python3.8/dist-packages/anyio/_backends/_asyncio.py", line 937, in run_sync_in_worker_thread
2023-07-06 17:10:29     return await future
2023-07-06 17:10:29   File "/usr/local/lib/python3.8/dist-packages/anyio/_backends/_asyncio.py", line 867, in run
2023-07-06 17:10:29     result = context.run(func, *args)
2023-07-06 17:10:29   File "app.py", line 103, in transcribe_webui_simple_progress
2023-07-06 17:10:29     return self.transcribe_webui(modelName, languageName, urlData, multipleFiles, microphoneData, task, vadOptions,
2023-07-06 17:10:29   File "app.py", line 197, in transcribe_webui
2023-07-06 17:10:29     result = self.transcribe_file(model, source.source_path, selectedLanguage, task, vadOptions, scaled_progress_listener, **decodeOptions)
2023-07-06 17:10:29   File "app.py", line 280, in transcribe_file
2023-07-06 17:10:29     process_gaps = self._create_silero_config(NonSpeechStrategy.CREATE_SEGMENT, vadOptions)
2023-07-06 17:10:29   File "app.py", line 368, in _create_silero_config
2023-07-06 17:10:29     self.vad_model = VadSileroTranscription()
2023-07-06 17:10:29   File "/opt/whisper-webui/src/vad.py", line 437, in __init__
2023-07-06 17:10:29     self._initialize_model()
2023-07-06 17:10:29   File "/opt/whisper-webui/src/vad.py", line 445, in _initialize_model
2023-07-06 17:10:29     self.model, self.get_speech_timestamps = self._create_model()
2023-07-06 17:10:29   File "/opt/whisper-webui/src/vad.py", line 449, in _create_model
2023-07-06 17:10:29     model, utils = torch.hub.load(repo_or_dir='snakers4/silero-vad', model='silero_vad')
2023-07-06 17:10:29   File "/usr/local/lib/python3.8/dist-packages/torch/hub.py", line 537, in load
2023-07-06 17:10:29     repo_or_dir = _get_cache_or_reload(repo_or_dir, force_reload, trust_repo, "load",
2023-07-06 17:10:29   File "/usr/local/lib/python3.8/dist-packages/torch/hub.py", line 180, in _get_cache_or_reload
2023-07-06 17:10:29     repo_owner, repo_name, ref = _parse_repo_info(github)
2023-07-06 17:10:29   File "/usr/local/lib/python3.8/dist-packages/torch/hub.py", line 133, in _parse_repo_info
2023-07-06 17:10:29     with urlopen(f"https://github.com/{repo_owner}/{repo_name}/tree/main/"):
2023-07-06 17:10:29   File "/usr/lib/python3.8/urllib/request.py", line 222, in urlopen
2023-07-06 17:10:29     return opener.open(url, data, timeout)
2023-07-06 17:10:29   File "/usr/lib/python3.8/urllib/request.py", line 525, in open
2023-07-06 17:10:29     response = self._open(req, data)
2023-07-06 17:10:29   File "/usr/lib/python3.8/urllib/request.py", line 542, in _open
2023-07-06 17:10:29     result = self._call_chain(self.handle_open, protocol, protocol +
2023-07-06 17:10:29   File "/usr/lib/python3.8/urllib/request.py", line 502, in _call_chain
2023-07-06 17:10:29     result = func(*args)
2023-07-06 17:10:29   File "/usr/lib/python3.8/urllib/request.py", line 1397, in https_open
2023-07-06 17:10:29     return self.do_open(http.client.HTTPSConnection, req,
2023-07-06 17:10:29   File "/usr/lib/python3.8/urllib/request.py", line 1357, in do_open
2023-07-06 17:10:29     raise URLError(err)
2023-07-06 17:10:29 urllib.error.URLError: <urlopen error [Errno 111] Connection refused>
2023-07-06 17:10:29 Traceback (most recent call last):
2023-07-06 17:10:29   File "/usr/lib/python3.8/urllib/request.py", line 1354, in do_open
2023-07-06 17:10:29     h.request(req.get_method(), req.selector, req.data, headers,
2023-07-06 17:10:29   File "/usr/lib/python3.8/http/client.py", line 1256, in request
2023-07-06 17:10:29     self._send_request(method, url, body, headers, encode_chunked)
2023-07-06 17:10:29   File "/usr/lib/python3.8/http/client.py", line 1302, in _send_request
2023-07-06 17:10:29     self.endheaders(body, encode_chunked=encode_chunked)
2023-07-06 17:10:29   File "/usr/lib/python3.8/http/client.py", line 1251, in endheaders
2023-07-06 17:10:29     self._send_output(message_body, encode_chunked=encode_chunked)
2023-07-06 17:10:29   File "/usr/lib/python3.8/http/client.py", line 1011, in _send_output
2023-07-06 17:10:29     self.send(msg)
2023-07-06 17:10:29   File "/usr/lib/python3.8/http/client.py", line 951, in send
2023-07-06 17:10:29     self.connect()
2023-07-06 17:10:29   File "/usr/lib/python3.8/http/client.py", line 1418, in connect
2023-07-06 17:10:29     super().connect()
2023-07-06 17:10:29   File "/usr/lib/python3.8/http/client.py", line 922, in connect
2023-07-06 17:10:29     self.sock = self._create_connection(
2023-07-06 17:10:29   File "/usr/lib/python3.8/socket.py", line 808, in create_connection
2023-07-06 17:10:29     raise err
2023-07-06 17:10:29   File "/usr/lib/python3.8/socket.py", line 796, in create_connection
2023-07-06 17:10:29     sock.connect(sa)
2023-07-06 17:10:29 ConnectionRefusedError: [Errno 111] Connection refused

很明显是github无法访问,我首先想到的是docker无法走系统的代理,wsl也不行,通过在docker和wsl中运行curl https://www.google.com可以测试。(fast-whisper镜像不像whiper那样把东西都放进去了,每次运行时还要加载东西,造成这个问题。也就是说whisper官方镜像可以全脱网运行,fast-whisper则不行。)

那么怎么让没有开通局域网共享功能的梯子来分享网络呢?通过一阵子检索,终于发现了二级代理和链式代理这个概念,最终确定用gost试一试。

1 在windows上找到当前的代理

打开网络连接的“网络和Internet设置”,打开设置中的“代理”。如果你安装了某个代理程序,则这里应该能够看到设置的端口。比如地址:http://localhost,端口:15236。

注意,这里的localhost很重要,因为收费的代理不希望你局域网共享,所以限制只能通过localhost访问。如果没有这个限制,那就简单了,直接把代理设置为主机的IP和端口就行了。

2 安装gost作为二级代理

由于我的梯子是在win10上的,所以需要让gost也在win上运行,所以安装了win版的go,然后安装/build这个gost,目录下就有gost.ext了,运行:

.\gost -L=:15230 -F=localhost:15236

二级代理就启动了,最直接的是在另外一台电脑上设置这个IP加端口15230试试,发现代理成功。试了一下,必须是localhost,不能是127.0.0.1。

为了方便,我把这个设置了自动启动,在gost.exe所在目录增加一个名为gost.ps1的文件,内容如下:

.\gost.exe -L=:16236 -F=localhost:15236

同样在这个目录再增加一个gost.bat,内容如下:

Powershell.exe -executionpolicy remotesigned -File ./gost.ps1

然后在gost.bat上右键创建一个快捷方式,把这个快捷方式放到开机启动目录C:\Users\PS\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup

可以通过徽标键+R打开shell:startup

3 在wsl中配置代理的启用

然后可以借鉴WSL2配置代理 – Leaos – 博客园 (cnblogs.com)来设置wsl2中的代理。

还有个问题,DNS也要先加上8.8.8.8,不然域名解析被污染了,依然无法访问github。

一个更方便的方法,在wsl的用户主目录增加一个文件proxy.sh,内容如下:

#!/bin/sh
# hostip=$(cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }')
hostip='192.168.0.200'
wslip=$(hostname -I | awk '{print $1}')
port=16236
 
PROXY_HTTP="http://${hostip}:${port}"
PROXY_SOCKS5="socks5://${hostip}:${port}"
 
set_proxy(){
  export http_proxy="${PROXY_HTTP}"
  export HTTP_PROXY="${PROXY_HTTP}"
 
  export https_proxy="${PROXY_HTTP}"
  export HTTPS_proxy="${PROXY_HTTP}"
 
  export ALL_PROXY="${PROXY_SOCKS5}"
  export all_proxy="${PROXY_SOCKS5}"
 
  git config --global http.https://github.com.proxy ${PROXY_HTTP}
  git config --global https.https://github.com.proxy ${PROXY_HTTP}
 
  echo "Proxy has been opened."

  test_setting
}
 
unset_proxy(){
  unset http_proxy
  unset HTTP_PROXY
  unset https_proxy
  unset HTTPS_PROXY
  unset ALL_PROXY
  unset all_proxy
  git config --global --unset http.https://github.com.proxy
  git config --global --unset https.https://github.com.proxy
 
  echo "Proxy has been closed."
}
 
test_setting(){
  echo "Host IP:" ${hostip}
  echo "WSL IP:" ${wslip}
  echo "Current https_proxy:" $https_proxy
  echo "Current all_proxy:" $all_proxy
  echo "Try to connect to Google..."
  resp=$(curl -I -s --connect-timeout 5 -m 5 -w "%{http_code}" -o /dev/null www.google.com)
  if [ ${resp} = 200 ]; then
    echo "Proxy setup succeeded!"
  else
    echo "Proxy setup failed!"
  fi
}
 
if [ "$1" = "set" ]
then
  set_proxy
 
elif [ "$1" = "unset" ]
then
  unset_proxy
 
elif [ "$1" = "test" ]
then
  test_setting
else
  echo "Unsupported arguments."
fi

注意,其中的hostip我没有用其他文档给的方法,因为不确定一定对,我改成了本机的固定IP。

然后在.bashrc文件结尾增加

alias proxy="source ~/proxy.sh set"
alias unproxy="source ~/proxy.sh unset"

这样,在source ~/.bashrc之后,就可以直接在shell中输入proxy来启用,或者输入unproxy来停用了。

再进一步,想要在打开shell时自动配置,可以新建一个autoproxy.sh

#!/bin/sh
# hostip=$(cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }')
hostip='192.168.0.200'
wslip=$(hostname -I | awk '{print $1}')
port=16236
 
PROXY_HTTP="http://${hostip}:${port}"
PROXY_SOCKS5="socks5://${hostip}:${port}"


export http_proxy="${PROXY_HTTP}"
export HTTP_PROXY="${PROXY_HTTP}"

export https_proxy="${PROXY_HTTP}"
export HTTPS_proxy="${PROXY_HTTP}"

export ALL_PROXY="${PROXY_SOCKS5}"
export all_proxy="${PROXY_SOCKS5}"

git config --global http.https://github.com.proxy ${PROXY_HTTP}
git config --global https.https://github.com.proxy ${PROXY_HTTP}

echo "Proxy has been opened."

然后在.bashrc中增加


if [ -f "/home/yourusername/autoproxy.sh" ]; then
    . "/home/yourusername/autoproxy.sh"
fi

本地化搭建fast-whisper+ChatGLM2-6B出来会谈记录

ffmpeg -i  20230703am.mp3 -f segment -segment_time 1755 -write_xing 0 -c copy  20230703am/out%03d.mp3

首先用以上命令将长音频切分为每30分钟一段,因为fast-whisper有这样的限制,实际切分的时候不要设置为1800秒,因为会多一点点,无法通过,可以设置到1799秒。

fast-whisper用官方的docker方案直接跑,试了一下medium模型和largv2都还行,默认就用medium了。

转录出来的文本用ChatGLM2-6B来处理,比如用这样的提示词:“请整理以下录音识别的文字,去掉其中的语气词等多余的部分,将语句调整通顺,修复可能因为语音识别产生的错误。”

ChatGLM2-6B直接按官方库的方法部署即可,通过webui访问。

如果希望自己对照查看文本,可以用VLC打开audio的visualizations效果即可显示字幕,也可以用subtitle编辑。

用VLC播放mp3的时候,默认看不到字幕,需要手动打开音频可视化。

图形默认是正方的,看着有点别扭,那么再调整一下视频比例。

更详细的情况欢迎联系我交流。

自动压缩当前文件夹及所有子文件夹的图片代码

#!/usr/bin/python
# -*- coding: UTF-8 -*-

'''
Author: be_loving@163.com 
Date: 2023-06-26 20:13:21
LastEditors: be_loving@163.com 
LastEditTime: 2023-06-26 21:28:50
Description: 

Copyright (c) 2023 Jiulu LTD, All Rights Reserved. 
'''
# pip install Pillow
import os
from PIL import Image
Image.MAX_IMAGE_PIXELS = None

for root, dirs, files in os.walk(".", topdown=False):
    for name in files:

        if name.endswith(".jpg") or name.endswith(".jpeg") or name.endswith(".png") or name.endswith(".tif"):
            img_path = os.path.join(root, name)
            print(img_path)
            if img_path.count('_144') > 1:
                os.remove(img_path)
            elif img_path.count('_144') == 0:
                new_img_path = os.path.join(
                    root, f"{name}_144.jpg")
                print(new_img_path)
                if not os.path.isfile(new_img_path):
                    try:
                        with Image.open(img_path) as img:
                            img.save(new_img_path, dpi=(144, 144))
                    except(OSError, NameError):
                        print('OSError,Path:', img_path)

    # for name in dirs:
    #     print(os.path.join(root, name))

具体压缩参数及文件命名方式请自己参照pillow的文档修改。

脚本运行时可执行

python ./resize.py

但需要当前的python环境支持pillow,可以直接安装,也可以用conda来定制环境,比如在conda create命令下安装pillow之后用conda activate pillow激活该环境。