xiaoxx970 / chatgpt-in-terminal

Use ChatGPT in terminal
MIT License
201 stars 27 forks source link

Multi-Thread Update (CLI Titles Extension, tokens_count optimise...) #18

Closed Ace-Radom closed 1 year ago

Ace-Radom commented 1 year ago

Done, Ready to Merge

Link Issue #17

思路为 在输出ChatGPT的回复后检查messages list 如果是此chat的第一次conversation则~启动一个支线程~将对话传递给标题请求守护进程并向gpt请求标题 在正确回复后更改终端 (CLI) 的标题 主线程不会主动阻塞支线程 仅当在调用 /save ~/tokens~ /title 命令时会检查线程状态 若标题请求线程仍在运行则阻塞主线程直至标题请求线程join或异常退出

TO DO:

Updates:

Bugs need to fix:

Things need help:

个人建议在merge这个PR之前先按照目前的main分支发布一次release 这个多线程虽然我自己看上去是没问题了用也能用但我不知道是不是所有地方都考虑到了 先发一个没有多线程模块的release会不会好一点 不知道你怎么看

Ace-Radom commented 1 year ago

目前加了多线程锁的部分有:

在后台已经启动生成标题时主线程的阻塞则直接用 isAlivejoin 实现 不需要多线程锁 ~加上CLI标题更新锁后主线程不需要再阻塞标题请求支线程~

Ace-Radom commented 1 year ago

可以在 .env 内增加 AUTO_GENERATE_TITLE 开关 设置1为启用标题自动生成 设置为其他任何值则停用 默认启用 即:

OPENAI_API_KEY=sk-xxxx
AUTO_GENERATE_TITLE=1

此点需要在README内说明

xiaoxx970 commented 1 year ago

我看到了你在每个记录日志的地方都加入了线程锁,这是必要的么?我记得logging本身就是支持多线程的,不管是子线程还是主进程,都是只管写日志就好了

Ace-Radom commented 1 year ago

这点我不是非常清楚 昨天是没想太多就全部加了线程锁 我一会儿再去看一下文档

Ace-Radom commented 1 year ago

查过了 logging本身是线程安全的 那我就把所有logging的mt锁删掉了

Ace-Radom commented 1 year ago

基本完成 功能实现 但是我在使用的时候注意到他的响应速度变慢了【虽然目前main分支上的那个版本一样响应慢】但你要不看看代码里会不会出现什么冲突之类的 虽然我想应该不会

Ace-Radom commented 1 year ago

碎碎念:隔壁川虎一样响应慢 看来是我的key的问题或者服务器问题……吧 虽然我晚上还是会整个代码review一遍

xiaoxx970 commented 1 year ago

我又优化了一点,这个线程创建用默认类就可以了,而且它会自己分配唯一的name,ID也就不需要了。

xiaoxx970 commented 1 year ago

以及mac上测试也很完美,就是它创建标题的时机我觉得还可以再早一点,在发出第一条消息之后可以马上开始标题生成线程。

还有就是感觉线程list这个管理方式还可以改进,我之前写过一个多线程的项目,是初始化的时候直接开启一个daemon线程,这个线程以一个queue作为参数,是一个while true循环,每次循环读一个队列里的内容然后生产结果,主进程只管放内容到queue中就可以。在这里的话queue的内容就是第一个信息的str内容,通过判断queue长度可以知道当前队列的阻塞程度。具体的稍后我看看能不能实现

Ace-Radom commented 1 year ago

是threading内置的Queue吧 那个我有去看过但有点迷糊 所以用了python2里常用的list管理方法 如果能改用Queue自然更好

顺便我先处理一下主分支和fork的冲突

xiaoxx970 commented 1 year ago

哎这个冲突还不小,早知道等这个pull合并后再弄那个type了,现在不知道rebase main行不行

xiaoxx970 commented 1 year ago

时间消耗大的函数是count_token,在初始化的时候它自己就消耗了0.16秒。如果在初始化的时候不调用count_token,启动时间就是0.001秒,这个区别足以肉眼可见了,所以我在考虑把count_token也弄成线程

Ace-Radom commented 1 year ago

这conflicts怎么还越弄越大了呢(玩脱了 我回退一下分支版本重新解决 这个可能真麻烦了

时间消耗大的函数是count_token,在初始化的时候它自己就消耗了0.16秒。如果在初始化的时候不调用count_token,启动时间就是0.001秒,这个区别足以肉眼可见了,所以我在考虑把count_token也弄成线程

是一个方法 锁好tokens spent应该问题不大

xiaoxx970 commented 1 year ago

这conflicts怎么还越弄越大了呢(玩脱了 我回退一下分支版本重新解决 这个可能真麻烦了

没事到最后merge的时候再手动解决也行

Ace-Radom commented 1 year ago

好那我就先不处理冲突了 版本退回到尝试解决之前了 也就是你上次在分支里push的那个commit

Ace-Radom commented 1 year ago

是threading内置的Queue吧 那个我有去看过但有点迷糊 所以用了python2里常用的list管理方法

啊之前是理解错了 现在明白你那个啥意思了【把标题更新的请求往队列里丢然后背后运行的支线程在收到了就发送……?】 如果我理解的对的话我应该也能写 但这个看你吧不知道你是不是已经开始了

xiaoxx970 commented 1 year ago

其实是【把新的第一个提问内容往队列里丢然后背后运行的支线程,支线程把提问内容从队列中取出来后开始运作修改title】,我还没写,你想写的话可以试试,不然我明天写。刚才在尝试rebase,结果一团糟,睡了睡了。

Ace-Radom commented 1 year ago

ok那我这晚上尝试一下

顺便冲突貌似解决了 在自己的fork里成功合并了 现在应该是没问题了

Ace-Radom commented 1 year ago

上两次commits的更改如下:

gen_title 函数的重写细节则为:

Ace-Radom commented 1 year ago

至于 count_tokens 我个人电脑上测试下来确实有一些慢 0.1s左右 但还是可以接受的范围内 感觉我这的一秒左右的启动时间主要是花在了加载解释器上 所以我没有直接改进支线程或者守护线程 你看你需要改吧

xiaoxx970 commented 1 year ago

发现了一个非预期行为,我在windows11(arm)的终端app里从powershell运行的,标题能正常设置,就是会提示这个

image
Ace-Radom commented 1 year ago

额能说一下你的win11具体环境嘛 我尝试一下在我电脑上重现这个问题

xiaoxx970 commented 1 year ago

还有就是title命令的force选项,我觉得没必要,可以直接默认force。因为如果自动生成title是开启的,那么运行title命令不会有任何变化,相当于只是输出下当前title;如果自动生成title关闭,那么运行title 和title force 效果是一样的,都会生成并且设置title。你觉得呢?

写到这里我又想到,如果是load的聊天记录是不是也应该根据第一个问题生成下title或者直接用文件名作为title,我觉得用文件名就挺好

xiaoxx970 commented 1 year ago

额能说一下你的win11具体环境嘛 我尝试一下在我电脑上重现这个问题

这个说来话长,我是在mac的虚拟机里运行的arm版本的windows11,但是我觉得是使用Windows terminal造成的

噢还有可能是因为我的python脚本位于smb目录(//目录),要是这样的话那也就没有解决的必要了

Ace-Radom commented 1 year ago

这个说来话长,我是在mac的虚拟机里运行的arm版本的windows11,但是我觉得是使用Windows terminal造成的

你是在用虚拟机访问共享文件夹来启动嘛 如果是的话那这个问题就不是win terminal的问题而是cmd的问题了 如果我没有记错的话cmd不支持访问共享目录 所以会出现这种错误【就像我电脑上的cmd一样没法进WSL的用户目录一样】 }59$HYAH(_B1H$L1)GQOD@2

Ace-Radom commented 1 year ago

还有就是title命令的force选项,我觉得没必要,可以直接默认force。因为如果自动生成title是开启的,那么运行title命令不会有任何变化,相当于只是输出下当前title;如果自动生成title关闭,那么运行title 和title force 效果是一样的,都会生成并且设置title。你觉得呢?

当时加入force选项是因为想在比如标题生成不满意的时候强制重新生成 但现在看这个temperature设0.5貌似结果基本不会有变 去掉貌似也没什么问题

写到这里我又想到,如果是load的聊天记录是不是也应该根据第一个问题生成下title或者直接用文件名作为title,我觉得用文件名就挺好

是一种思路 但可能的问题是未必所有人都会喜欢预定的以 chat_histroy 为开头的模式来保存聊天记录 这样加入特判会不会有很多特殊情况……?毕竟在标题开头有一个chat_history或者别的东西占着有点不太好 CLI的标题一般性都不会太长 那么在json里专门加入一条来记载需要重现的title会不会也是一种选择 在 /save 确定保存文件名后再加入一条保存title的确认 默认使用【如果已经生成】目前的title 或者自定义

xiaoxx970 commented 1 year ago

改聊天记录json的结构还是不太优雅。我就弄成直接显示文件名了,毕竟文件名里即便包含chat_history也是在提示用户这是一个加载的会话。这个时候如果不满意,用/title 新标题自定义标题或者/title生成标题也是可以的

Ace-Radom commented 1 year ago

looks fine 直接显示文件名确实不错 从我这看没什么问题了应该 如果没有什么别的更改或增加的话应该可以merge了我想

Ace-Radom commented 1 year ago

我在程序启动的部分加了点log记录 最初是debug用的但后来想想也有一定的用处所以就没删push上来了 你可以看看要不要保留

xiaoxx970 commented 1 year ago

可以保留,但是换成log.debug级别吧,正常日志只显示聊天内容和报错就好了。包括生成标题的日志我也是打算在merge前弄成debug级别的,你要是改的话也可以一起改改

Ace-Radom commented 1 year ago

在INFO级别就保留了程序启动时候的 ChatGPT-in-Terminal Start 别的都放进了DEBUG级别 标题生成日志也改了 然后在程序头加了一段注释掉的启用debug级别log记录的程序段

xiaoxx970 commented 1 year ago

好的辛苦了,晚点我更新下readme就merge了

Ace-Radom commented 1 year ago

没事没事 顺便你之前在虚拟机里出现的问题其实有解决方法 就是 os.chdir 回到home目录后才启动 title 命令 但我没有详细研究过 而且这个情况确实比较少见所以我就没有改 你可以考虑一下

可能的实现方法为:

home_dir = os.path.expandvars('%USERPROFILE%')
os.chdir(home_dir)
os.system(f"title {new_title}")
xiaoxx970 commented 1 year ago

没事没事 顺便你之前在虚拟机里出现的问题其实有解决方法 就是 os.chdir 回到home目录后才启动 title 命令 但我没有详细研究过 而且这个情况确实比较少见所以我就没有改 你可以考虑一下

可能的实现方法为:

home_dir = os.path.expandvars('%USERPROFILE%')
os.chdir(home_dir)
os.system(f"title {new_title}")

要chdir的话就算了,我怕影响/save功能,它默认存到相对目录的