Skip to content

Repository files navigation

Typeless — Windows AI 语音听写工具

按住热键说话,松开即得润色后的文字,自动注入到当前输入框。


目录


功能概览

功能 状态 说明
全局热键 Push-to-talk 在任意应用中按住热键录音,松开结束
实时音量波形 悬浮窗显示随麦克风输入跳动的波形条
Whisper 语音转文字 调用 OpenAI Whisper API,支持中英日等多语言
GPT 文字润色 自动去除语气词、修复语法、提升流畅度
全局文字注入 Win32 SendInput Unicode 方案,支持中文/Emoji
悬浮状态窗口 5 种状态(待机/录音/处理中/完成/错误)平滑动画
系统托盘常驻 不占任务栏,双击托盘图标打开设置
设置界面 API Key、热键、模型、注入方式均可配置

快速开始

环境要求

  • Windows 10 / 11(文字注入功能仅限 Windows)
  • Python 3.10 或更高版本
  • 麦克风设备
  • OpenAI API Key(获取地址

安装步骤

:: 1. 克隆或下载项目
cd typeless

:: 2. 创建虚拟环境
python -m venv .venv
.venv\Scripts\activate

:: 3. 安装依赖
pip install -r requirements.txt

:: 4. 配置 API Key
copy .env.example .env
notepad .env

.env 文件中填入你的 OpenAI API Key:

OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx
:: 5. 启动
python main.py

或者直接双击 run.bat,它会自动完成环境创建和启动。


配置说明

所有配置通过项目根目录的 .env 文件管理,修改后重启生效(部分配置支持通过设置界面热重载)。

# ── 必填 ──────────────────────────────────────────────────────
OPENAI_API_KEY=sk-your-key-here

# ── 热键 ──────────────────────────────────────────────────────
# 使用 keyboard 库的按键名称
# 推荐:right alt(不与大多数应用冲突)
# 其他示例:f9 | ctrl+shift+space | caps lock
TYPELESS_HOTKEY=right alt

# ── Whisper 语音识别 ──────────────────────────────────────────
WHISPER_MODEL=whisper-1
# 语言提示(留空自动检测,填写可提升速度和准确率)
# 可选值:zh | en | ja | ko | fr | de | es ...
WHISPER_LANGUAGE=

# ── GPT 文字润色 ──────────────────────────────────────────────
POLISH_ENABLED=true
# 推荐模型:gpt-4o-mini(便宜快速)| gpt-4o(质量最高)
POLISH_MODEL=gpt-4o-mini

# ── 文字注入方式 ──────────────────────────────────────────────
# sendinput:Win32 SendInput,逐字符注入,不影响剪贴板(推荐)
# clipboard:复制到剪贴板再模拟 Ctrl+V,速度更快但会覆盖剪贴板
INJECTION_METHOD=sendinput

# ── 调试 ──────────────────────────────────────────────────────
LOG_LEVEL=INFO

配置优先级

.env 文件  →  环境变量  →  config.py 中的默认值

使用方法

基本流程

① 启动程序 → 系统托盘出现麦克风图标
② 切换到任意应用(Word、浏览器、微信、IDE...)
③ 按住 Right Alt(或你配置的热键)
④ 说话 — 悬浮窗显示红色波形,表示正在录音
⑤ 松开按键
⑥ 悬浮窗变为蓝色旋转动画,表示正在转录/润色
⑦ 润色后的文字自动输入到当前光标位置
⑧ 悬浮窗短暂显示绿色确认,2 秒后自动消失

悬浮窗状态说明

🔴 红色波形 + "Listening…"     → 正在录音,波形高度反映麦克风音量
🔵 蓝色旋转 + "Processing…"    → 调用 Whisper + GPT,通常 1-3 秒
🟢 绿色对勾 + 文字预览          → 注入完成,2 秒后自动消失
🔴 红色叉号 + 错误信息          → 出错(API 失败、无麦克风等),3 秒后消失

系统托盘

操作 效果
左键单击 无操作(避免误触)
左键双击 打开设置界面
右键 显示菜单(设置 / 退出)

录音时托盘图标变为红色,提供视觉反馈。


架构设计

数据流

┌─────────────────────────────────────────────────────────────┐
│                        用户操作                              │
│                    按住 Right Alt                            │
└────────────────────────┬────────────────────────────────────┘
                         │  keyboard hook (后台线程)
                         ▼
                  HotkeyManager
                  press / release
                  (Qt Signal 跨线程安全)
                         │
          ┌──────────────┴──────────────┐
          ▼                             ▼
   recorder.start()             overlay.show_recording()
          │
   sounddevice.InputStream
   (QThread, 16kHz mono)
          │ level_updated (每 40ms)
          ├──────────────────────────► overlay 波形动画
          │
   [松开热键]
          │
   recorder.stop()
          │ finished(wav_path)
          ▼
   overlay.show_processing()
   Transcriber (QThread)
   POST /audio/transcriptions
          │ finished(raw_text)
          ▼
   TextPolisher (QThread)
   POST /chat/completions
          │ finished(polished_text)
          ▼
   TextInjector
   Win32 SendInput ──────────────► 当前焦点输入框
          │ done
          ▼
   overlay.show_done(preview)

线程模型

主线程 (Qt Event Loop)
├── UI 更新(Overlay 动画、托盘图标)
├── 信号分发
└── 设置对话框

keyboard 内部线程
└── WH_KEYBOARD_LL hook → emit Qt Signal → 主线程处理

QThread: _RecordWorker
└── sounddevice 采集循环 → emit level_updated, finished

QThread: _TranscribeWorker
└── HTTP POST to Whisper API → emit finished

QThread: _PolishWorker
└── HTTP POST to Chat API → emit finished

主线程(注入)
└── SendInput(同步,速度足够快无需线程)

所有跨线程通信均通过 Qt Signal/Slot 完成,线程安全,无需手动加锁。


模块文档

config.py — 配置管理

from config import cfg

cfg.openai_api_key   # str
cfg.hotkey           # str,如 "right alt"
cfg.polish_enabled   # bool
cfg.is_valid()       # -> bool,检查最低配置是否满足
cfg.save_to_env()    # 将当前配置写回 .env 文件

core/hotkey.py — 全局热键

class HotkeyManager(QObject):
    press   = pyqtSignal()   # 按下时触发
    release = pyqtSignal()   # 松开时触发

    def start(self) -> None    # 安装钩子(非阻塞)
    def stop(self) -> None     # 卸载钩子
    def set_hotkey(key: str)   # 运行时切换热键,无需重启

实现原理:使用 keyboard.on_press / keyboard.on_release 安装 WH_KEYBOARD_LL 低级键盘钩子。该 Hook 在 Windows 用户模式下无需管理员权限。通过内部 _recording 标志防止按键重复触发。


core/recorder.py — 音频采集

class AudioRecorder(QObject):
    level_updated = pyqtSignal(float)   # RMS 电平 [0.0, 1.0],每 40ms 一次
    finished      = pyqtSignal(str)     # WAV 临时文件路径
    error         = pyqtSignal(str)

    def start_recording(self) -> None
    def stop_recording(self) -> None
    @property
    def is_recording(self) -> bool

参数:16kHz,单声道,float32(Whisper 最佳输入格式)。录音结束后写入系统临时目录的 .wav 文件,转录完成后自动删除。


core/transcriber.py — 语音转文字

class Transcriber(QObject):
    finished = pyqtSignal(str)   # 原始转录文本
    error    = pyqtSignal(str)

    def transcribe(self, wav_path: str) -> None   # 异步,结果通过信号返回

调用 OpenAI.audio.transcriptions.create,使用 response_format="text" 直接获取字符串。支持通过 WHISPER_LANGUAGE 提示语言以提升准确率和速度。


core/polisher.py — AI 文字润色

class TextPolisher(QObject):
    finished = pyqtSignal(str)   # 润色后文本(失败时 fallback 到原文)
    error    = pyqtSignal(str)   # 非致命,finished 仍会触发

    def polish(self, raw_text: str) -> None

默认 Prompt(可在 .env 中覆盖):

你是专业的文字助手。将语音转录文本改写为流畅自然的书面语,修正语法,去除语气词(嗯、啊、那个),保持原意和语气。只输出润色后的文本,不加任何说明。

POLISH_ENABLED=false,原文直接透传,跳过 API 调用。API 失败时自动 fallback 到原始转录文本,用户总能得到结果。


core/injector.py — 文字注入

class TextInjector(QObject):
    done  = pyqtSignal()
    error = pyqtSignal(str)

    def inject(self, text: str) -> None

SendInput 模式(默认)

对每个 Unicode 字符:
  SendInput([KEY_DOWN(KEYEVENTF_UNICODE, codepoint),
             KEY_UP  (KEYEVENTF_UNICODE, codepoint)])
  • 支持全部 Unicode:中文、日文、Emoji、特殊符号
  • 不影响剪贴板
  • 注入速度:约 5000 字符/秒

Clipboard 模式

保存当前剪贴板 → 写入新文本 → 模拟 Ctrl+V → 恢复剪贴板
  • 适合部分不响应 SendInput 的应用(如某些游戏输入框)
  • 速度与文本长度无关,始终毫秒级

ui/overlay.py — 悬浮状态窗口

class OverlayWindow(QWidget):
    clicked = pyqtSignal()

    def show_recording(self) -> None
    def show_processing(self) -> None
    def show_done(self, preview: str = "") -> None
    def show_error(self, message: str) -> None
    def update_level(self, level: float) -> None   # 喂入音量电平

窗口属性

  • 尺寸:320×64 像素,圆角药丸形
  • 位置:主屏幕底部居中,距底边 48px
  • 层级:WindowStaysOnTopHint + WA_ShowWithoutActivating(不抢焦点)
  • 透明度:0.93,深色玻璃背景 rgba(18,18,24,235)
  • 淡入/淡出动画:150ms EaseInOut

ui/tray.py — 系统托盘控制器

SystemTrayApp 是应用的"大脑",负责:

  1. 创建所有核心对象
  2. 连接完整信号链
  3. 管理托盘图标和菜单
  4. 热重载设置
app = SystemTrayApp(q_application)
app.initialize()   # 一次性启动全部功能

ui/settings_dialog.py — 设置界面

三个 Tab 页:

  • General:API Key、热键
  • AI / Models:Whisper 模型、语言、GPT 模型、润色开关
  • Text Injection:注入方式选择及说明

点击 OK 后调用 cfg.save_to_env() 持久化,并通过 settings_saved 信号触发热重载。


技术栈选型

为什么选择 Python + PyQt6?

需求 方案 原因
Windows 系统级热键 keyboard 支持 push-to-talk(按住/松开),无需管理员,跨会话
Unicode 文字注入 ctypes + Win32 SendInput 官方 Windows API,支持全部 Unicode,无剪贴板副作用
无边框透明悬浮窗 PyQt6 WA_TranslucentBackground + 自定义 paintEvent,渲染质量高
异步不阻塞 UI PyQt6 QThread Qt 信号天然线程安全,避免手动锁
系统托盘 QSystemTrayIcon 与 Qt 事件循环无缝集成,避免 pystray 的线程冲突
音频采集 sounddevice 低延迟,支持实时回调获取电平数据
API 调用 openai SDK 官方 SDK,维护好,Whisper + Chat 统一接口

为什么不选择其他方案?

  • Electron:文字注入复杂,需要额外 native addon,包体积 200MB+
  • C# WPF:开发速度慢,与 Python AI 生态割裂
  • Tauri:Rust 学习成本高,Windows 系统 API 绑定不成熟
  • tkinter:动画能力差,无法实现半透明效果

常见问题

热键在某些应用中不生效?

部分以管理员权限运行的应用(如任务管理器、某些游戏反作弊)会屏蔽低权限进程的键盘钩子。解决方法:以管理员身份运行 Typeless。

:: 右键 run.bat → 以管理员身份运行
:: 或在终端中:
runas /user:Administrator "python main.py"

转录结果是乱码或识别率低?

  1. .env 中明确指定语言:WHISPER_LANGUAGE=zh
  2. 检查麦克风采样率是否为 16kHz(sounddevice 会自动重采样,但某些驱动例外)
  3. 确保录音环境安静,距麦克风 20-40cm

文字注入到某个应用无效?

切换为剪贴板模式:

INJECTION_METHOD=clipboard

部分应用(如远程桌面、某些 UWP 应用)不响应 SendInput,剪贴板粘贴方式更兼容。

API 调用失败,提示 401?

检查 .env 中的 OPENAI_API_KEY 是否正确,注意不要有多余空格。也可以通过系统托盘 → 设置 → General 重新填写。

程序启动后托盘没有图标?

确认 PyQt6 安装成功,且 Windows 通知区域未隐藏该图标(任务栏右键 → 任务栏设置 → 其他系统托盘图标)。

能在 macOS / Linux 上运行吗?

核心逻辑(录音、转录、润色)跨平台,但 文字注入仅限 Windows(使用 Win32 SendInput)。在非 Windows 系统上启动时,injector.py 会自动降级为打印到控制台,方便开发调试。macOS/Linux 的注入支持(xdotool / Accessibility API)列入路线图。


开发路线图

第二轮(功能完善)

  • Whisper 本地模型支持(faster-whisper),离线可用
  • GPT 流式输出 — 边生成边注入,减少等待感
  • 自动标点符号(句号、问号根据语气自动添加)
  • 录音时长限制与提示(防止意外超长录音)
  • 注入超长文本(>500 字)异步化,避免主线程卡顿

第三轮(体验优化)

  • 设置界面:快捷键录制 UI(点击按钮录制新热键)
  • 设置界面:自定义润色 Prompt 编辑框
  • 设置界面:按应用配置注入方式的规则列表
  • 历史记录面板(最近 N 条转录记录,支持复制)
  • 悬浮窗位置可拖动并记忆
  • 多语言 UI(中文/英文界面切换)

第四轮(高级功能)

  • 自定义词汇表(提升专有名词识别率)
  • 快捷短语模板(说"发邮件模板"自动填充)
  • 声纹识别多用户配置
  • 开机自启动配置
  • 自动更新机制

项目结构

typeless/
├── main.py                    # 入口,QApplication 初始化
├── config.py                  # 配置单例(读取 .env)
├── requirements.txt           # Python 依赖
├── run.bat                    # Windows 一键启动脚本
├── .env.example               # 配置模板(复制为 .env 后填写)
│
├── core/                      # 业务逻辑(无 UI 依赖)
│   ├── hotkey.py              # 全局热键监听
│   ├── recorder.py            # 麦克风音频采集
│   ├── transcriber.py         # Whisper API 调用
│   ├── polisher.py            # GPT 润色
│   └── injector.py            # Win32 文字注入
│
├── ui/                        # 界面层(PyQt6)
│   ├── overlay.py             # 悬浮状态药丸窗口
│   ├── settings_dialog.py     # 设置对话框
│   └── tray.py                # 系统托盘 + 信号连线(主控制器)
│
├── utils/
│   └── logger.py              # 日志配置
│
└── logs/                      # 运行日志(自动创建)
    └── typeless.log

许可证

MIT License — 自由使用、修改和分发。

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages