Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/blindcreeper_counter-strike-2-skin-trading-system.json

1 line
6.9 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"repo": "blindcreeper/counter-strike-2-skin-trading-system", "files": {"src/aihelp_vision.py": {"62959fda8a350b18ff98876dbb3c1efddc07aa84": {"t": 1785674241.6323755, "n": 5940, "h": "86d38665d7a3b4ca", "c": "import os\nimport base64\nfrom io import BytesIO\nfrom pathlib import Path\nimport tkinter as tk\nfrom concurrent.futures import ThreadPoolExecutor\nimport queue\nimport threading\nimport re\nimport time\n\nimport keyboard\nimport pyautogui\nfrom openai import OpenAI\n\n# ================= 配置区域 =================\n\n# 替换为您的支持 Vision (视觉) 的 API Key\n# 推荐使用:\n# 1. OpenAI (gpt-4o-mini, gpt-4o) - 最稳\n# 2. DashScope (qwen-vl-max) - 中文最强\n# 3. Google Gemini (gemini-1.5-flash) - 免费且快\nAPI_KEY = \"sk-cfa012bef6554f65a635f21e2cbe9cd1\" # 请填写您的 API Key\nAI_BASE_URL = \"https://dashscope.aliyuncs.com/compatible-mode/v1\" # 请填写对应的 Base URL\nAI_MODEL = \"qwen-vl-plus\" # 请填写对应的模型名称\n\nOBSIDIAN_DIR = Path(os.getenv(\"OBSIDIAN_DIR\", r\"D:\\obsidian\\obsidiandata\\englishnote\"))\n\nHOTKEY_CAPTURE = \"F8\"\nHOTKEY_SELECT_REGION = \"F7\"\n\n# ===========================================\n\nREGION = None\ntask_queue = queue.Queue()\nprocessing_count = 0\nmax_concurrent_tasks = 2\n\nif not API_KEY or API_KEY.startswith(\"sk-...\"):\n raise RuntimeError(\"请在代码中配置真实的支持 Vision 的 API Key!\")\n\nclient = OpenAI(\n api_key=API_KEY,\n base_url=AI_BASE_URL,\n)\n\ndef encode_image(image):\n \"\"\"将 PIL Image 转换为 Base64 字符串\"\"\"\n buffered = BytesIO()\n image.save(buffered, format=\"JPEG\", quality=85)\n return base64.b64encode(buffered.getvalue()).decode('utf-8')\n\ndef select_region():\n \"\"\"手动框选截图区域\"\"\"\n result = {\"region\": None}\n root = tk.Tk()\n root.attributes(\"-fullscreen\", True)\n root.attributes(\"-alpha\", 0.25)\n root.configure(bg=\"black\")\n \n canvas = tk.Canvas(root, cursor=\"cross\", bg=\"gray\", highlightthickness=0)\n canvas.pack(fill=tk.BOTH, expand=True)\n\n start_x, start_y = 0, 0\n rect_id = None\n\n def on_press(event):\n nonlocal start_x, start_y, rect_id\n start_x, start_y = event.x, event.y\n if rect_id: canvas.delete(rect_id)\n rect_id = canvas.create_rectangle(start_x, start_y, start_x, start_y, outline=\"red\", width=2)\n\n def on_drag(event):\n if rect_id: canvas.coords(rect_id, start_x, start_y, event.x, event.y)\n\n def on_release(event):\n x1, y1, x2, y2 = start_x, start_y, event.x, event.y\n left, top = min(x1, x2), min(y1, y2)\n width, height = abs(x2 - x1), abs(y2 - y1)\n if width > 10 and height > 10:\n result[\"region\"] = (left, top, width, height)\n root.destroy()\n\n canvas.bind(\"<ButtonPress-1>\", on_press)\n canvas.bind(\"<B1-Motion>\", on_drag)\n canvas.bind(\"<ButtonRelease-1>\", on_release)\n root.bind(\"<Escape>\", lambda e: root.destroy())\n root.mainloop()\n return result[\"region\"]\n\ndef set_region_hotkey():\n global REGION\n print(\"[INFO] 请框选区域...\")\n region = select_region()\n if region:\n REGION = region\n print(f\"[OK] 区域已设置: {REGION}\")\n add_task_to_queue()\n\ndef capture_hotkey():\n global REGION\n if not REGION:\n print(\"[INFO] 请先框选区域...\")\n region = select_region()\n if not region: return\n REGION = region\n add_task_to_queue()\n\ndef add_task_to_queue():\n global processing_count\n if processing_count >= max_concurrent_tasks:\n print(f\"[INFO] 任务队列已满,请稍候...\")\n return\n \n # 立即截图(在主线程截图,避免 UI 变化)\n screenshot = pyautogui.screenshot(region=REGION)\n task_queue.put(screenshot)\n print(f\"[INFO] 截图已添加,队列长度: {task_queue.qsize()}\")\n \n if not hasattr(add_task_to_queue, 'worker_started'):\n threading.Thread(target=worker_loop, daemon=True).start()\n add_task_to_queue.worker_started = True\n\ndef worker_loop():\n global processing_count\n while True:\n try:\n image = task_queue.get(timeout=1)\n processing_count += 1\n print(f\"[INFO] 开始处理图片...\")\n try:\n process_image(image)\n except Exception as e:\n print(f\"[ERROR] 处理失败: {e}\")\n finally:\n processing_count -= 1\n task_queue.task_done()\n except queue.Empty:\n continue\n\ndef process_image(image):\n base64_image = encode_image(image)\n \n # 构造 Vision API 请求\n # 提示词要求输出 JSON 或特定 Markdown 格式\n prompt = \"\"\"\n 请识别这张图片中的英语题目。\n \n 请输出 Markdown 格式解析,包含以下部分:\n 1. # 重点单词\n (仅输出这道题最核心的一个单词)\n 2. # 题目\n (识别出的完整题目文本)\n 3. # 英语题目解析\n (尽量简洁)\n 4.# 相关单词\n \n 请严格按照上述标题输出,不要标注markdown\n \"\"\"\n\n try:\n response = client.chat.completions.create(\n model=AI_MODEL,\n messages=[\n {\n \"role\": \"user\", \n \"content\": [\n {\"type\": \"text\", \"text\": prompt},\n {\n \"type\": \"image_url\",\n \"image_url\": {\"url\": f\"data:image/jpeg;base64,{base64_image}\"}\n }\n ]\n }\n ],\n max_tokens=1000\n )\n content = response.choices[0].message.content\n save_note(content)\n \n except Exception as e:\n print(f\"[ERROR] API 调用失败: {e}\")\n\ndef save_note(content):\n OBSIDIAN_DIR.mkdir(parents=True, exist_ok=True)\n \n # 解析重点单词作为文件名\n keyword = \"english_note\"\n match = re.search(r\"# 重点单词\\s*\\n+([^\\n]+)\", content)\n if match:\n keyword = match.group(1).strip().split()[0] # 取第一行第一个词\n keyword = re.sub(r'[^\\w\\s-]', '', keyword).strip()\n\n file_path = OBSIDIAN_DIR / f\"{keyword}.md\"\n \n # 处理重名\n counter = 1\n original_kw = keyword\n while file_path.exists():\n file_path = OBSIDIAN_DIR / f\"{original_kw}_{counter}.md\"\n counter += 1\n \n file_path.write_text(content, encoding=\"utf-8\")\n print(f\"[SUCCESS] 笔记已保存: {file_path.name}\")\n\ndef main():\n keyboard.add_hotkey(HOTKEY_SELECT_REGION, set_region_hotkey)\n keyboard.add_hotkey(HOTKEY_CAPTURE, capture_hotkey)\n print(f\"Ready! 按 {HOTKEY_SELECT_REGION} 框选,按 {HOTKEY_CAPTURE} 识别。\")\n keyboard.wait()\n\nif __name__ == \"__main__\":\n main()"}}}}