Enhance code quality with linting and type hints#191
Enhance code quality with linting and type hints#191PabloLION wants to merge 49 commits intoHaujetZhao:masterfrom
Conversation
…o the new syntax (just use list, dict, | , etc). We can keep Any.
…rong-import-position)
我感觉iPhone的不是很好用啊,macOS自带的也很难用,我感觉这个项目比苹果自带的好太多了。苹果的必须吐字非常清晰才能识别出来。
稍微说下吧。
例子此处创建的这两个变量的目的不是很清晰,注释虽然写了但是我也没看懂。我最后把它改成了一个`class AudioFileManger`,然后只有在`save_audio`的时候才会创建一个实例。这样可以把三个文件和在一起。 # 保存音频文件
file_path: str | Path = ""
file: Popen[bytes] | Wave_write | None = None我阅读的障碍主要是变量有点混乱。例如
这个好像是我想加的取消功能啊 @H1DDENADM1N 我前两天看了你的fork,感觉做的很棒
他没有依赖LLM,具体实现我也不知道。 |
|
iPhone的语音输入非常好用,特别是对比windows自带的Win+H快捷键启动语音输入来说,在准确度,速度,交互体验上全面领先。我平时聊天或问ai用capswriter,但大段文字是用iPhone配合实时同步剪贴板 etherpad-lite 非常折中的实现windows流式语音输入。之前用过vscode的流式语音输入插件,但不如iPhone好用,大概是我电脑这个老麦克风问题。你觉得iPhone的不好用可能你口音比较重吧,我这里用起来iPhone的语音输入非常好使。 |
我感觉他没微信转语音识别的准确,很多生活化的表达他都不知道,而且经常识别不上(我说了一大堆,没有出字)。 我刚换的16PM,用的iOS 18.1.1。用了十几年iPhone在这方面还是有点羡慕安卓用户的。 而且iOS不让第三方做语音输入。第三方键盘我试过:谷歌家的会跳转到另一个全屏幕app。微软家的键盘干脆不支持中文。我目前没什么好办法。 vscode的copilot里我一直说的英语,尴尬的是我一停下来思考他就会自动发送。有那么点烦人。 你如果有什么好用的工具请给我推荐一下!谢谢! |
|
试试这个, VS Code Speech 支持流式语音输入,而且也是离线的,只是可惜只能用在 vs code 微信的交互必须按着按钮,而且只能用在微信,不方便编辑,我几乎不用,毕竟都开微信了,还不如直接发语音或视频 |
|
@H1DDENADM1N 你说的这个我知道,他前身应该是 https://githubnext.com/projects/copilot-voice/ 我很早用过。现在也在用,咱俩说的应该一样。 |
|
https://www.bilibili.com/video/av616320040?unique_k=114514 这个听风转录可以实时语音识别并翻译,用的sensevoice加qwen,但他主要是实时字幕,也不方便编辑 |
|
回答下问题。 Queue_in 和 Queue_out 方面:
关于你的举例:
# 开始取数据
while task := await Cosmic.queue_in.get():
Cosmic.queue_in.task_done()
...
# 创建音频文件
if Config.save_audio and 'file_path' not in locals(): # 如果之后我想重命名 file_path 变量,还得回到这里修改字符串
file_path, file = create_file(task['data'].shape[1], time_start)
Cosmic.audio_files[task_id] = file_path所以我干脆在 while 之前新建这个变量,把它赋值为空,在 while 里面用 # 保存音频文件
file_path, file = '', None
# 开始取数据
while task := await Cosmic.queue_in.get():
...
# 创建音频文件
if Config.save_audio and not file_path:
file_path, file = create_file(task['data'].shape[1], time_start)
Cosmic.audio_files[task_id] = file_path |
我遇到过几次录音文件被放到1970年的情况,困扰了我很久,但又没见有其他人提issue,我注意到那是UTC时间戳起始点,但这个bug较难复现,可能是这里造成的吗?还是什么其他? |
我也遇见过 @H1DDENADM1N 你既然有源代码,可以加一个条件,用 log 看一下。 |
|
@HaujetZhao Server Cosmic 的 Queue_in 和 Queue_out 还挺容易读懂的。 client 的花了点时间也读懂了。我感觉用 我还有个问题想请教: message={
# ...
"seg_duration": 15,
"seg_overlap": 2,
} |
这个功能可能放在 client_stream.py 的 record_callback 里面可能好一点,可以存的更完整。不过我看到要改文件名,这个可能不太好办。我没仔细考虑过,可能mktemp有点多余? |
我想是的 haha
我知道原因了。但懒得改了。复现概率较小。位置在 async def send_audio():
try:
...
# 任务起始时间
time_start = 0
...
# 开始取数据
while task := await Cosmic.queue_in.get():
...
if task['type'] == 'begin':
time_start = task['time']修改 time_start 初始化为 0,只在一处修改过。如果某一个任务的 start 在队列中排错位置了,就有可能在应有的一次任务中取不到它,就改不了时间了。 |
|
我想把创建文件的放到 |
不多余的。要确保文件名的唯一性,就得用它。另外,识别完成后,还会重命名为有意义的文件。 |
我感觉是因为 |
不安全。如你所见,当队列出错时,time_start 没有被正确的赋值,导致了 1970 年的 bug。所以这个队列顺序可能不可靠。具体什么情况下队列顺序出错了,我也不知道怎么复现。
|
|
是我记错了。你说的对。我看了文档,GPT说他还有一个作用是block下一次 |
我估计我找到原因了。录音时长不到threshold时候,因为 cancel task 直接取消了“收集并发送数据的任务”( 我没测试能不能复现,我现在有点乱,还在看其他部分。你们有想法可以试试 @HaujetZhao @H1DDENADM1N |
| else: # 用户未安装 ffmpeg,则输出为 wav 格式 | ||
| file_path = file_path.with_suffix('.wav') | ||
| file = wave.open(str(file_path), 'w') | ||
| with Popen( |
There was a problem hiding this comment.
此处引入了一个Bug。这个with在退出时会关闭Popen,导致后面的file不可写。需要在merge前修复这个bug。
可行 |
因为有一个发送和接收。我的策略并不是发送完音频,然后去建立接收任务等待或轮询,因为我不能保证服务端在零点几秒内就把结果立马给我,我不能一直等(在这个期间 可能我又会建立新的语音任务)。所以等待不能阻塞,我需要左手随便发,右手一直等,只要等到一个回复就立马输出,不管这个回复是不是左手刚发出的任务结果。 能够一直等,不需要轮询,一有结果就能立马输出的,只有 asyncio。 |
|
@HaujetZhao 我回来了,感谢你的解释。我发现这么写确实有好处,本来决定暂时不改这个逻辑。后来有了第二个担心的点,可能还是需要改一下。 我主要担心的有两点: recording_task = asyncio.run_coroutine_threadsafe(
send_mic_recording(),
client_app.loop,
)第一是在上面的
第二:假设我们应用了上面的更改,现在是 Python 在管理 想问一下你的建议 |
|
我使用一个队列是基于以下的逻辑:用户在使用的时候一定是先按下大写锁定键,再松开。再次按下之前必定松开,松开之前必定有按下。那队列里面就一定是这样的状态:启动之后必有对应的结束(或cancel),队列里不会有连续的启动。 启动之前必有结束,就是新的 task 覆盖旧的 task 之前,结束命令必然已经被发出应用到旧的task上。 |
|
你的意思是,正常情况下,至多有一个 send recording 在运行,我刚才也是这么想的。我的意思是,让python也确认一下这个逻辑,有两种做法:
|
|
另外,这么改其实还有一个目的:我想把 click mode 和 hold mode 的快捷键分开。这样比切换 config 要方便的多。但是这就会引入 “有两个 send recording 同时运行” 的问题。
|
|
我的建议是 奥卡姆剃刀 如无必要 勿增实体,从第一性原理出发做开发。架构是服务于需求的。 你为什么想做这个功能,是你真的需要吗,还是做出来能增加你的收入,是真的有用户会在生活中这样干吗?这个需求真的很强烈吗? 你当然可以去改进架构呀,现在的录音数据是往一个队列里面灌,需要的时候就往里灌,不需要的时候就停止,接受者只能有一个,只能有一个正在进行的任务。 如果你真的想做,那你可以改进,抽象点设计,让这个录音数据像喷泉一样不断往外喷,有一个任务的时候就拿一个水管去接,这个任务停止的时候就把水管拔掉拿走,有多个任务的时候就插入多个水管。 |
|
嗯,有道理,确实是个伪需求(连我自己都没这个需求)。学习了。 |
参考 HaujetZhao#191 (comment) 中的建议:cancel的时候发送一个type='cancel'的事件,取代task.cancel()

This update introduces a comprehensive linting script, improves code style, and adds type hints across multiple files. It also updates dependencies and addresses various style issues to ensure better maintainability and readability of the codebase.