关于划词工具的 「AI 提问」功能易用性引发的探索思路

本贴最后更新于 189 天前,其中的信息可能已经事过境迁

一篇散乱的思路整理

最近浏览器上用 kimi 拓展各种划词提问辅助阅读体验可以说非常棒。

特别是上下文识别能力、划词打开提问窗口后可以继续提问对话这两点。

但是脱离浏览器后,在编辑场景下就很难获得这种快速易用的辅助搜索体验了。在主流编辑器倒是还是通过 copilot 的 ctrl + i 快捷键来快速提问。

但是像写个文档辅助查资料(思源里可以通过直接开伺服在浏览器里临时解决)、一些复杂任务的临时查询还是需要回归到传统的切换窗口然后搜索(包括多屏幕下的切屏),于是最近就想着看一下有哪些能够实现全局划线提问能力的 AI 方案。

在简单搜索后,找到了 讯飞星火豆包 这样标榜包括全局任意划词提问以及全功能 AI 能力并附赠 chromium 内核的方案。实际体验后,都存在一次划线解释提问后继续对话就必须打开它的软件本体切换窗口来继续对话的以及功能太繁杂而没有足够的配置项隐藏它们的问题。

于是就开始想:

“像 pot 这类划词翻译工具是否能拓展一个 AI 搜索功能呢?”

于是顺着在 Github 上搜索划词关键词找到了以下两个具有参考意义的应用

openai-translator: 基于 ChatGPT API 的划词翻译浏览器插件和跨平台桌面端应用

Borber/Tran at v0.2.17

一个是 ai 翻译, 一个是功能足够轻量。
第一个虽然已经引入 ai 润色了,但却没有提问功能(
第二个是功能做到了相对的极简,作为一个临时翻译方案也不错就保留了。

然后思路变成

“如果自己写一个类似的工具需要考虑那些方面呢”

于是问了问 GPT + 之前用 Quicker 写一些获取划选内容的脚本时快捷键设置为 ctrl+c 发生的循环问题。可以确认大概是通过检测

  • 鼠标按下
  • 检测鼠标移动范围
  • 鼠标释放
  • 发送复制事件(模拟 ctrl+c)复制内容,然后通过剪切板获取划取内容
  • 最后通过向剪切板写入空白信息覆盖刚才复制的内容避免污染剪切板

就实现了最关键的全局获取划线内容这一项功能(进一步的监听键盘 shift+方向键ctrl+a 都差不多)

接着让 GPT 补全处理多屏幕问题,就简单实现了一个全局划线后显示一个 web 窗口查询内容的功能。似乎进一步优化性能和逻辑就能够实现一个符合自己需求的划词 AI 提问工具了。

但当前 GPT 给出的都是 python QT 代码,没什么改的欲望,就先贴一份在这吧

1686924591925.jpeg

import sys import threading import time from pynput import mouse, keyboard import pyperclip import pyautogui from PyQt5 import QtWidgets, QtCore, QtGui, QtWebEngineWidgets class SelectionListener(QtCore.QObject): # 定义信号,传递选中文本和坐标 selection_made = QtCore.pyqtSignal(str, int, int) selection_cleared = QtCore.pyqtSignal() def __init__(self): super().__init__() self.current_selection = "" self.run_service = True # 鼠标状态变量 self.mouse_listener = mouse.Listener(on_click=self.on_click, on_move=self.on_move) self.is_dragging = False self.mouse_pressed = False self.last_mouse_time = 0 self.click_count = 0 # 键盘状态变量 self.keyboard_listener = keyboard.Listener(on_press=self.on_press, on_release=self.on_release) self.shift_pressed = False self.arrow_key_pressed = False # 鼠标事件处理 def on_click(self, x, y, button, pressed): if pressed: self.mouse_pressed = True current_time = time.time() if current_time - self.last_mouse_time < 0.4: self.click_count += 1 else: self.click_count = 1 self.last_mouse_time = current_time if self.click_count == 2: # 检测到双击 time.sleep(0.1) self.simulate_copy_and_get_selection() self.click_count = 0 else: if self.mouse_pressed: if self.is_dragging: # 拖拽选择完成 time.sleep(0.1) self.simulate_copy_and_get_selection() else: # 单击未拖拽,可能清除了选择 self.selection_cleared.emit() self.is_dragging = False self.mouse_pressed = False def on_move(self, x, y): if self.mouse_pressed: if not self.is_dragging: pass # 开始拖拽 self.is_dragging = True # 键盘事件处理 def on_press(self, key): try: if key == keyboard.Key.shift: self.shift_pressed = True elif self.shift_pressed and key in [keyboard.Key.left, keyboard.Key.right, keyboard.Key.up, keyboard.Key.down]: self.arrow_key_pressed = True except AttributeError: pass def on_release(self, key): try: if key == keyboard.Key.shift: if self.arrow_key_pressed: # Shift选择完成 time.sleep(0.1) self.simulate_copy_and_get_selection() else: # Shift释放,无箭头键,可能清除了选择 self.selection_cleared.emit() self.shift_pressed = False self.arrow_key_pressed = False except AttributeError: pass def simulate_copy_and_get_selection(self): try: # 保存当前剪贴板内容 previous_clipboard_content = pyperclip.paste() # 模拟复制 pyautogui.hotkey("ctrl", "c") time.sleep(0.05) # 等待剪贴板更新 # 获取选中文本 new_clipboard_content = pyperclip.paste() # 恢复之前的剪贴板内容 pyperclip.copy(previous_clipboard_content) # 获取鼠标位置 cursor_pos = QtGui.QCursor.pos() x = cursor_pos.x() y = cursor_pos.y() # 如果有新文本被选中,发射信号 if new_clipboard_content != previous_clipboard_content and new_clipboard_content.strip(): self.current_selection = new_clipboard_content self.selection_made.emit(self.current_selection, x, y) else: # 没有选中文本,可能清除了选择 self.selection_cleared.emit() except Exception as e: print(f"模拟复制时出错: {e}") def start(self): self.mouse_listener.start() self.keyboard_listener.start() try: while self.run_service: time.sleep(1) # 保持线程存活 except KeyboardInterrupt: self.stop() def stop(self): self.mouse_listener.stop() self.keyboard_listener.stop() self.run_service = False class FloatingWindow(QtWidgets.QWidget): def __init__(self, text, x, y, parent=None): super().__init__(parent) self.text = text self.initUI(x, y) def initUI(self, x, y): self.setWindowFlags( QtCore.Qt.Popup | QtCore.Qt.FramelessWindowHint | QtCore.Qt.WindowStaysOnTopHint ) self.setAttribute(QtCore.Qt.WA_TranslucentBackground) self.setAttribute(QtCore.Qt.WA_ShowWithoutActivating) # 调整位置,适应多显示器环境 cursor_pos = QtCore.QPoint(x, y) screen = QtGui.QGuiApplication.screenAt(cursor_pos) if screen is None: screen = QtWidgets.QApplication.primaryScreen() # 创建按钮 self.button = QtWidgets.QPushButton("🔍", self) self.button.setStyleSheet(""" QPushButton { font-size: 18px; background-color: rgba(255, 255, 255, 200); border: none; border-radius: 15px; } QPushButton::hover { background-color: rgba(200, 200, 200, 200); } """) self.button.setFixedSize(30, 30) self.button.clicked.connect(self.show_webview) # 调整大小 self.resize(30, 30) # 移动窗口到鼠标位置 self.move(x - self.width() // 2, y - self.height() // 2) # 设置焦点策略 self.setFocusPolicy(QtCore.Qt.StrongFocus) self.button.setFocusPolicy(QtCore.Qt.NoFocus) # 显示窗口 self.show() def show_webview(self): self.webview = WebViewWindow(self.text) self.webview.show() # 关闭浮动窗口 self.close() def focusOutEvent(self, event): self.close() class WebViewWindow(QtWidgets.QWidget): def __init__(self, text): super().__init__() self.text = text self.initUI() def initUI(self): # 设置无边框窗口 self.setWindowFlags(QtCore.Qt.FramelessWindowHint) self.resize(800, 600) layout = QtWidgets.QVBoxLayout(self) # 创建 QWebEngineView self.browser = QtWebEngineWidgets.QWebEngineView(self) # 执行搜索 query = QtCore.QUrl.fromUserInput(f"https://www.google.com/search?q={self.text}") self.browser.load(query) layout.addWidget(self.browser) # 显示窗口 self.show() def start_selection_listener(listener): listener.start() def main(): app = QtWidgets.QApplication(sys.argv) # 创建选择监听器 listener = SelectionListener() # 在单独的线程中启动监听器 listener_thread = threading.Thread(target=start_selection_listener, args=(listener,)) listener_thread.daemon = True listener_thread.start() # 保持浮动窗口的引用 floating_window = None # 处理监听器发出的信号 def on_selection_made(text, x, y): nonlocal floating_window # 关闭任何已存在的浮动窗口 if floating_window is not None: floating_window.close() floating_window = FloatingWindow(text, x, y) def on_selection_cleared(): nonlocal floating_window if floating_window is not None: floating_window.close() floating_window = None listener.selection_made.connect(on_selection_made) # listener.selection_cleared.connect(on_selection_cleared) sys.exit(app.exec_()) if __name__ == "__main__": main()
  • 人工智能

    人工智能(Artificial Intelligence)是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门技术科学。

    115 引用 • 318 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • 微服务

    微服务架构是一种架构模式,它提倡将单一应用划分成一组小的服务。服务之间互相协调,互相配合,为用户提供最终价值。每个服务运行在独立的进程中。服务于服务之间才用轻量级的通信机制互相沟通。每个服务都围绕着具体业务构建,能够被独立的部署。

    96 引用 • 155 回帖
  • 反馈

    Communication channel for makers and users.

    120 引用 • 906 回帖 • 279 关注
  • LaTeX

    LaTeX(音译“拉泰赫”)是一种基于 ΤΕΧ 的排版系统,由美国计算机学家莱斯利·兰伯特(Leslie Lamport)在 20 世纪 80 年代初期开发,利用这种格式,即使使用者没有排版和程序设计的知识也可以充分发挥由 TeX 所提供的强大功能,能在几天,甚至几小时内生成很多具有书籍质量的印刷品。对于生成复杂表格和数学公式,这一点表现得尤为突出。因此它非常适用于生成高印刷质量的科技和数学类文档。

    12 引用 • 59 回帖 • 4 关注
  • 微软

    微软是一家美国跨国科技公司,也是世界 PC 软件开发的先导,由比尔·盖茨与保罗·艾伦创办于 1975 年,公司总部设立在华盛顿州的雷德蒙德(Redmond,邻近西雅图)。以研发、制造、授权和提供广泛的电脑软件服务业务为主。

    8 引用 • 44 回帖 • 1 关注
  • 深度学习

    深度学习(Deep Learning)是机器学习的分支,是一种试图使用包含复杂结构或由多重非线性变换构成的多个处理层对数据进行高层抽象的算法。

    43 引用 • 44 回帖
  • Ubuntu

    Ubuntu(友帮拓、优般图、乌班图)是一个以桌面应用为主的 Linux 操作系统,其名称来自非洲南部祖鲁语或豪萨语的“ubuntu”一词,意思是“人性”、“我的存在是因为大家的存在”,是非洲传统的一种价值观,类似华人社会的“仁爱”思想。Ubuntu 的目标在于为一般用户提供一个最新的、同时又相当稳定的主要由自由软件构建而成的操作系统。

    127 引用 • 169 回帖
  • 印象笔记
    3 引用 • 16 回帖
  • 单点登录

    单点登录(Single Sign On)是目前比较流行的企业业务整合的解决方案之一。SSO 的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

    9 引用 • 25 回帖 • 3 关注
  • NetBeans

    NetBeans 是一个始于 1997 年的 Xelfi 计划,本身是捷克布拉格查理大学的数学及物理学院的学生计划。此计划延伸而成立了一家公司进而发展这个商用版本的 NetBeans IDE,直到 1999 年 Sun 买下此公司。Sun 于次年(2000 年)六月将 NetBeans IDE 开源,直到现在 NetBeans 的社群依然持续增长。

    78 引用 • 102 回帖 • 707 关注
  • 大疆创新

    深圳市大疆创新科技有限公司(DJI-Innovations,简称 DJI),成立于 2006 年,是全球领先的无人飞行器控制系统及无人机解决方案的研发和生产商,客户遍布全球 100 多个国家。通过持续的创新,大疆致力于为无人机工业、行业用户以及专业航拍应用提供性能最强、体验最佳的革命性智能飞控产品和解决方案。

    2 引用 • 14 回帖 • 1 关注
  • SpaceVim

    SpaceVim 是一个社区驱动的模块化 vim/neovim 配置集合,以模块的方式组织管理插件以
    及相关配置,为不同的语言开发量身定制了相关的开发模块,该模块提供代码自动补全,
    语法检查、格式化、调试、REPL 等特性。用户仅需载入相关语言的模块即可得到一个开箱
    即用的 Vim-IDE。

    3 引用 • 31 回帖 • 109 关注
  • 智能合约

    智能合约(Smart contract)是一种旨在以信息化方式传播、验证或执行合同的计算机协议。智能合约允许在没有第三方的情况下进行可信交易,这些交易可追踪且不可逆转。智能合约概念于 1994 年由 Nick Szabo 首次提出。

    1 引用 • 11 回帖 • 2 关注
  • 旅游

    希望你我能在旅途中找到人生的下一站。

    98 引用 • 903 回帖
  • CloudFoundry

    Cloud Foundry 是 VMware 推出的业界第一个开源 PaaS 云平台,它支持多种框架、语言、运行时环境、云平台及应用服务,使开发人员能够在几秒钟内进行应用程序的部署和扩展,无需担心任何基础架构的问题。

    5 引用 • 18 回帖 • 190 关注
  • WordPress

    WordPress 是一个使用 PHP 语言开发的博客平台,用户可以在支持 PHP 和 MySQL 数据库的服务器上架设自己的博客。也可以把 WordPress 当作一个内容管理系统(CMS)来使用。WordPress 是一个免费的开源项目,在 GNU 通用公共许可证(GPLv2)下授权发布。

    45 引用 • 114 回帖 • 171 关注
  • 运维

    互联网运维工作,以服务为中心,以稳定、安全、高效为三个基本点,确保公司的互联网业务能够 7×24 小时为用户提供高质量的服务。

    151 引用 • 257 回帖
  • Elasticsearch

    Elasticsearch 是一个基于 Lucene 的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于 RESTful 接口。Elasticsearch 是用 Java 开发的,并作为 Apache 许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。

    117 引用 • 99 回帖 • 196 关注
  • Swift

    Swift 是苹果于 2014 年 WWDC(苹果开发者大会)发布的开发语言,可与 Objective-C 共同运行于 Mac OS 和 iOS 平台,用于搭建基于苹果平台的应用程序。

    34 引用 • 37 回帖 • 553 关注
  • SQLite

    SQLite 是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是全世界使用最为广泛的数据库引擎。

    4 引用 • 7 回帖 • 5 关注
  • 笔记

    好记性不如烂笔头。

    310 引用 • 794 回帖 • 1 关注
  • AWS
    11 引用 • 28 回帖 • 9 关注
  • 脑图

    脑图又叫思维导图,是表达发散性思维的有效图形思维工具 ,它简单却又很有效,是一种实用性的思维工具。

    32 引用 • 99 回帖 • 1 关注
  • QQ

    1999 年 2 月腾讯正式推出“腾讯 QQ”,在线用户由 1999 年的 2 人(马化腾和张志东)到现在已经发展到上亿用户了,在线人数超过一亿,是目前使用最广泛的聊天软件之一。

    45 引用 • 557 回帖 • 1 关注
  • Gzip

    gzip (GNU zip)是 GNU 自由软件的文件压缩程序。我们在 Linux 中经常会用到后缀为 .gz 的文件,它们就是 Gzip 格式的。现今已经成为互联网上使用非常普遍的一种数据压缩格式,或者说一种文件格式。

    9 引用 • 12 回帖 • 175 关注
  • uTools

    uTools 是一个极简、插件化、跨平台的现代桌面软件。通过自由选配丰富的插件,打造你得心应手的工具集合。

    7 引用 • 28 回帖 • 1 关注
  • PostgreSQL

    PostgreSQL 是一款功能强大的企业级数据库系统,在 BSD 开源许可证下发布。

    22 引用 • 22 回帖
  • 尊园地产

    昆明尊园房地产经纪有限公司,即:Kunming Zunyuan Property Agency Company Limited(简称“尊园地产”)于 2007 年 6 月开始筹备,2007 年 8 月 18 日正式成立,注册资本 200 万元,公司性质为股份经纪有限公司,主营业务为:代租、代售、代办产权过户、办理银行按揭、担保、抵押、评估等。

    1 引用 • 22 回帖 • 796 关注