Files

1 line
23 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": "baizhixin/ai-rime", "files": {"bzx/bzx_config.json": {"c8b5d0f0a896b2acfa18a3d80caec972f587c70a": {"t": 1785746261.6035113, "n": 700, "h": "57319ad1c4d61c6e", "c": "{\n \"api_url\": \"https://api.deepseek.com/v1/chat/completions\",\n \"api_key\": \"sk-\",\n \"model\": \"deepseek-chat\",\n \"auto_trigger\": true,\n \"context_aware\": true,\n \"debug\": false,\n \"system_prompts\": {\n \"correct\": \"{\\\"role\\\":\\\"逆向拼音纠错专家\\\",\\\"protocol\\\":\\\"仅输出修正后汉字,严禁解释多言,长度严格守恒\\\",\\\"logic\\\":\\\"1.声学还原:兼容平翘舌、前后鼻音、fh模糊音;2.意境采样:文学语境(含山/巅/长风/明月/负/至)史诗感优先,即便原句通顺,若同音字张力更强(如负变扶)则强制替换;上下文原则:用户携带历史输入时,必须按照历史输入的信息推断预测内容,例如人称性别区分\\\",\\\"output\\\":\\\"直接输出修正后的文本\\\"}\",\n \"translate\": \"你是翻译专家。用户会给你一段文本,中文翻译成英文,英文翻译成中文。\\n\\n【输出要求】\\n- 只输出翻译结果\\n- 禁止任何解释或说明\",\n \"chat\": \"你是内容生成助手。根据用户的需求生成内容。\\n\\n【输出要求】\\n- 只输出生成的内容\\n- 禁止任何解释或前缀\\n- 严禁附带markdown语法的符号表示\\n- 所有回答应当尽可能简洁高效\\n- 对于命令的询问应当给出一条命令\"\n }\n}"}, "2be6903a18266992ac9777b0b17d6accf12008b7": {"t": 1785761239.2129946, "n": 700, "h": "57319ad1c4d61c6e", "c": "{\n \"api_url\": \"https://api.deepseek.com/v1/chat/completions\",\n \"api_key\": \"sk-\",\n \"model\": \"deepseek-chat\",\n \"auto_trigger\": true,\n \"context_aware\": true,\n \"debug\": false,\n \"system_prompts\": {\n \"correct\": \"{\\\"role\\\":\\\"逆向拼音纠错专家\\\",\\\"protocol\\\":\\\"仅输出修正后汉字,严禁解释多言,长度严格守恒\\\",\\\"logic\\\":\\\"1.声学还原:兼容平翘舌、前后鼻音、fh模糊音;2.意境采样:文学语境(含山/巅/长风/明月/负/至)史诗感优先,即便原句通顺,若同音字张力更强(如负变扶)则强制替换;上下文原则:用户携带历史输入时,必须按照历史输入的信息推断预测内容,例如人称性别区分\\\",\\\"output\\\":\\\"直接输出修正后的文本\\\"}\",\n \"translate\": \"你是翻译专家。用户会给你一段文本,中文翻译成英文,英文翻译成中文。\\n\\n【输出要求】\\n- 只输出翻译结果\\n- 禁止任何解释或说明\",\n \"chat\": \"你是内容生成助手。根据用户的需求生成内容。\\n\\n【输出要求】\\n- 只输出生成的内容\\n- 禁止任何解释或前缀\\n- 严禁附带markdown语法的符号表示\\n- 所有回答应当尽可能简洁高效\\n- 对于命令的询问应当给出一条命令\"\n }\n}"}}, "bzx/bzx_service.py": {"c8b5d0f0a896b2acfa18a3d80caec972f587c70a": {"t": 1785746388.7245853, "n": 8144, "h": "36f8e2ae258221e1", "c": "#!/usr/bin/env python3\n\"\"\"\nbzx_service.py - Rime AI 多功能后台服务\n\n通过临时文件与 Rime Lua 通信,处理纠错、翻译、对话请求。\n\n使用方法:\n python bzx_service.py [--config PATH]\n\"\"\"\n\nimport os\nimport sys\nimport json\nimport signal\nimport logging\nfrom logging.handlers import RotatingFileHandler\nfrom typing import Dict, Any\nimport argparse\n\n# 获取脚本所在目录\nSCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))\n\n# 导入 IPC 模块\ntry:\n from bzx_ipc import create_ipc_server\nexcept ImportError:\n sys.path.insert(0, SCRIPT_DIR)\n from bzx_ipc import create_ipc_server\n\n# 导入 AI 模块\nfrom bzx_ai import AIClient\n\n# 尝试导入 jieba\ntry:\n import jieba\n jieba.setLogLevel(jieba.logging.WARNING)\n JIEBA_AVAILABLE = True\nexcept ImportError:\n JIEBA_AVAILABLE = False\n\n\n# ============ 日志配置 ============\n\ndef setup_logging(debug: bool = False) -> logging.Logger:\n \"\"\"配置日志(带轮转)\"\"\"\n logger = logging.getLogger(\"bzx_service\")\n logger.setLevel(logging.DEBUG if debug else logging.INFO)\n \n # 日志文件在脚本目录\n log_file = os.path.join(SCRIPT_DIR, \"bzx_service.log\")\n \n # 轮转:最大 1MB,保留 3 个备份\n handler = RotatingFileHandler(\n log_file, \n maxBytes=1024 * 1024, # 1MB\n backupCount=3,\n encoding=\"utf-8\"\n )\n handler.setFormatter(logging.Formatter(\n \"%(asctime)s - %(levelname)s - %(message)s\"\n ))\n logger.addHandler(handler)\n \n # 同时输出到控制台\n console = logging.StreamHandler()\n console.setFormatter(logging.Formatter(\"%(message)s\"))\n logger.addHandler(console)\n \n return logger\n\n\n# ============ 默认配置 ============\n\nDEFAULT_CONFIG = {\n \"api_url\": \"https://api.deepseek.com/v1/chat/completions\",\n \"api_key\": \"sk-\",\n \"model\": \"deepseek-chat\",\n \"context_aware\": False,\n \"debug\": False,\n \"model_params\": {\n \"temperature\": 0.1,\n \"max_tokens\": 512,\n \"top_p\": 1.0,\n \"timeout\": 30\n },\n \"system_prompts\": {\n \"correct\": \"{\\\"role\\\":\\\"逆向拼音纠错专家\\\",\\\"protocol\\\":\\\"仅输出修正后汉字,严禁解释多言,长度严格守恒\\\",\\\"logic\\\":\\\"1.声学还原:兼容平翘舌、前后鼻音、fh模糊音;2.意境采样:文学语境(含山/巅/长风/明月/负/至)史诗感优先,即便原句通顺,若同音字张力更强(如负变扶)则强制替换;如果有上下文内容的话**必须**参考上下文内容的名词进行纠正,例如女性->她,男性->他。\\\",\\\"output\\\":\\\"直接输出修正后的文本\\\"}\",\n \"translate\": \"你是翻译专家。用户会给你一段文本,中文翻译成英文,英文翻译成中文。\\n\\n【输出要求】\\n- 只输出翻译结果\\n- 禁止任何解释或说明\",\n \"chat\": \"你是内容生成助手。根据用户的需求生成内容。\\n\\n【输出要求】\\n- 只输出生成的内容\\n- 禁止任何解释或前缀\\n- 严禁附带markdown语法的符号表示\\n- 所有回答应当尽可能简洁高效\\n- 对于命令的询问应当给出一条命令\"\n }\n}\n\nIPC_NAME = \"bzx_rime\"\n\n\n# ============ 配置加载 ============\n\ndef load_config(config_path: str = None) -> Dict[str, Any]:\n \"\"\"加载配置文件\"\"\"\n # 搜索路径:命令行指定 > 当前目录\n search_paths = []\n if config_path:\n search_paths.append(config_path)\n search_paths.append(os.path.join(SCRIPT_DIR, \"bzx_config.json\"))\n \n for path in search_paths:\n if os.path.exists(path):\n try:\n with open(path, \"r\", encoding=\"utf-8\") as f:\n config = json.load(f)\n print(f\"已加载配置: {path}\")\n merged = DEFAULT_CONFIG.copy()\n merged.update(config)\n if \"system_prompts\" in config:\n merged[\"system_prompts\"] = {**DEFAULT_CONFIG[\"system_prompts\"], **config[\"system_prompts\"]}\n return merged\n except Exception as e:\n print(f\"配置文件读取失败 {path}: {e}\")\n \n print(\"警告: 未找到配置文件,使用默认配置\")\n return DEFAULT_CONFIG.copy()\n\n\n# ============ 请求处理 ============\n\nclass RequestHandler:\n \"\"\"处理来自 Lua 的请求\"\"\"\n \n def __init__(self, config: Dict[str, Any], logger: logging.Logger):\n self.config = config\n self.logger = logger\n self.system_prompts = config.get(\"system_prompts\", {})\n self.context_enabled = config.get(\"context_aware\", False)\n self.ai_client = AIClient.from_config(config)\n \n def handle(self, request_json: str) -> str:\n \"\"\"处理请求并返回 JSON 响应\"\"\"\n try:\n req = json.loads(request_json)\n except json.JSONDecodeError as e:\n self.logger.error(f\"JSON 解析失败: {e}\")\n return json.dumps({\"error\": f\"Invalid JSON: {e}\", \"result\": None})\n \n req_type = req.get(\"type\", \"correct\")\n text = req.get(\"text\", \"\")\n pinyin = req.get(\"pinyin\", \"\")\n context = req.get(\"context\", \"\")\n reqid = req.get(\"reqid\", \"\")\n \n func_name = {\"correct\": \"纠错\", \"translate\": \"翻译\", \"chat\": \"对话\"}.get(req_type, req_type)\n self.logger.info(f\"[{func_name}] 收到请求: {text[:50]}{'...' if len(text) > 50 else ''}\")\n \n # 获取系统提示词\n system_prompt = self.system_prompts.get(req_type, \"\")\n \n # 构建用户消息\n user_text = text\n context_messages = [] # 额外的消息列表\n \n if req_type == \"correct\":\n if pinyin:\n user_text = f\"拼音:{pinyin}\\n待纠正:{text}\"\n self.logger.debug(f\" 拼音: {pinyin}\")\n \n if self.context_enabled and context:\n # 使用 jieba 分词\n if JIEBA_AVAILABLE:\n tokens = list(jieba.cut(context))\n tokens = [t.strip() for t in tokens if t.strip()]\n else:\n tokens = list(context)\n \n context_tokens = \" \".join(tokens)\n self.logger.info(f\" 上下文: {context_tokens}\")\n \n # 通过 assistant 消息传递上下文\n context_messages = [\n {\"role\": \"assistant\", \"content\": f\"用户历史输入:{context_tokens}\"}\n ]\n \n # 调用 AI(传递上下文消息)\n result = self.ai_client.chat(system_prompt, user_text, context_messages if context_messages else None)\n \n if result:\n self.logger.info(f\"[{func_name}] 结果: {result[:50]}{'...' if len(result) > 50 else ''}\")\n else:\n self.logger.warning(f\"[{func_name}] 处理失败,返回原文\")\n result = text\n \n return json.dumps({\n \"reqid\": reqid,\n \"result\": result,\n \"error\": None\n }, ensure_ascii=False)\n\n\n# ============ 主服务 ============\n\nclass BzxService:\n \"\"\"IPC 通信服务\"\"\"\n \n def __init__(self, config: Dict[str, Any], logger: logging.Logger):\n self.config = config\n self.logger = logger\n self.handler = RequestHandler(config, logger)\n self.server = None\n \n def start(self):\n \"\"\"启动服务\"\"\"\n self.logger.info(\"=\" * 50)\n self.logger.info(\"Rime AI 服务已启动\")\n self.logger.info(\"=\" * 50)\n self.logger.info(f\" API: {self.config.get('api_url', 'N/A')}\")\n self.logger.info(f\" 模型: {self.config.get('model', 'N/A')}\")\n self.logger.info(f\" IPC: {IPC_NAME}\")\n self.logger.info(f\" 上下文: {'开启' if self.config.get('context_aware') else '关闭'}\")\n self.logger.info(\"=\" * 50)\n self.logger.info(\"按 Ctrl+C 停止服务...\")\n \n self.server = create_ipc_server(IPC_NAME)\n \n try:\n self.server.run(self.handler.handle)\n except KeyboardInterrupt:\n pass\n finally:\n self.stop()\n \n def stop(self):\n \"\"\"停止服务\"\"\"\n if self.server:\n self.server.stop()\n self.server.cleanup()\n self.logger.info(\"服务已停止\")\n\n\n# ============ 主函数 ============\n\ndef main():\n parser = argparse.ArgumentParser(description=\"Rime AI 服务\")\n parser.add_argument(\"--config\", \"-c\", type=str, help=\"配置文件路径\")\n parser.add_argument(\"--debug\", \"-d\", action=\"store_true\", help=\"开启调试模式\")\n args = parser.parse_args()\n \n config = load_config(args.config)\n \n # 命令行 debug 优先\n if args.debug:\n config[\"debug\"] = True\n \n logger = setup_logging(config.get(\"debug\", False))\n \n if not config.get(\"api_key\"):\n logger.warning(\"=\" * 50)\n logger.warning(\"警告: 现已使用博主bzx的api_key\")\n logger.warning(\"有能力者请编辑配置文件改用自己的api_key!\")\n logger.warning(\"=\" * 50)\n \n service = BzxService(config, logger)\n \n def signal_handler(sig, frame):\n service.stop()\n sys.exit(0)\n \n signal.signal(signal.SIGINT, signal_handler)\n signal.signal(signal.SIGTERM, signal_handler)\n \n service.start()\n\n\nif __name__ == \"__main__\":\n main()\n"}, "2be6903a18266992ac9777b0b17d6accf12008b7": {"t": 1785761238.5677197, "n": 8144, "h": "36f8e2ae258221e1", "c": "#!/usr/bin/env python3\n\"\"\"\nbzx_service.py - Rime AI 多功能后台服务\n\n通过临时文件与 Rime Lua 通信,处理纠错、翻译、对话请求。\n\n使用方法:\n python bzx_service.py [--config PATH]\n\"\"\"\n\nimport os\nimport sys\nimport json\nimport signal\nimport logging\nfrom logging.handlers import RotatingFileHandler\nfrom typing import Dict, Any\nimport argparse\n\n# 获取脚本所在目录\nSCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))\n\n# 导入 IPC 模块\ntry:\n from bzx_ipc import create_ipc_server\nexcept ImportError:\n sys.path.insert(0, SCRIPT_DIR)\n from bzx_ipc import create_ipc_server\n\n# 导入 AI 模块\nfrom bzx_ai import AIClient\n\n# 尝试导入 jieba\ntry:\n import jieba\n jieba.setLogLevel(jieba.logging.WARNING)\n JIEBA_AVAILABLE = True\nexcept ImportError:\n JIEBA_AVAILABLE = False\n\n\n# ============ 日志配置 ============\n\ndef setup_logging(debug: bool = False) -> logging.Logger:\n \"\"\"配置日志(带轮转)\"\"\"\n logger = logging.getLogger(\"bzx_service\")\n logger.setLevel(logging.DEBUG if debug else logging.INFO)\n \n # 日志文件在脚本目录\n log_file = os.path.join(SCRIPT_DIR, \"bzx_service.log\")\n \n # 轮转:最大 1MB,保留 3 个备份\n handler = RotatingFileHandler(\n log_file, \n maxBytes=1024 * 1024, # 1MB\n backupCount=3,\n encoding=\"utf-8\"\n )\n handler.setFormatter(logging.Formatter(\n \"%(asctime)s - %(levelname)s - %(message)s\"\n ))\n logger.addHandler(handler)\n \n # 同时输出到控制台\n console = logging.StreamHandler()\n console.setFormatter(logging.Formatter(\"%(message)s\"))\n logger.addHandler(console)\n \n return logger\n\n\n# ============ 默认配置 ============\n\nDEFAULT_CONFIG = {\n \"api_url\": \"https://api.deepseek.com/v1/chat/completions\",\n \"api_key\": \"sk-\",\n \"model\": \"deepseek-chat\",\n \"context_aware\": False,\n \"debug\": False,\n \"model_params\": {\n \"temperature\": 0.1,\n \"max_tokens\": 512,\n \"top_p\": 1.0,\n \"timeout\": 30\n },\n \"system_prompts\": {\n \"correct\": \"{\\\"role\\\":\\\"逆向拼音纠错专家\\\",\\\"protocol\\\":\\\"仅输出修正后汉字,严禁解释多言,长度严格守恒\\\",\\\"logic\\\":\\\"1.声学还原:兼容平翘舌、前后鼻音、fh模糊音;2.意境采样:文学语境(含山/巅/长风/明月/负/至)史诗感优先,即便原句通顺,若同音字张力更强(如负变扶)则强制替换;如果有上下文内容的话**必须**参考上下文内容的名词进行纠正,例如女性->她,男性->他。\\\",\\\"output\\\":\\\"直接输出修正后的文本\\\"}\",\n \"translate\": \"你是翻译专家。用户会给你一段文本,中文翻译成英文,英文翻译成中文。\\n\\n【输出要求】\\n- 只输出翻译结果\\n- 禁止任何解释或说明\",\n \"chat\": \"你是内容生成助手。根据用户的需求生成内容。\\n\\n【输出要求】\\n- 只输出生成的内容\\n- 禁止任何解释或前缀\\n- 严禁附带markdown语法的符号表示\\n- 所有回答应当尽可能简洁高效\\n- 对于命令的询问应当给出一条命令\"\n }\n}\n\nIPC_NAME = \"bzx_rime\"\n\n\n# ============ 配置加载 ============\n\ndef load_config(config_path: str = None) -> Dict[str, Any]:\n \"\"\"加载配置文件\"\"\"\n # 搜索路径:命令行指定 > 当前目录\n search_paths = []\n if config_path:\n search_paths.append(config_path)\n search_paths.append(os.path.join(SCRIPT_DIR, \"bzx_config.json\"))\n \n for path in search_paths:\n if os.path.exists(path):\n try:\n with open(path, \"r\", encoding=\"utf-8\") as f:\n config = json.load(f)\n print(f\"已加载配置: {path}\")\n merged = DEFAULT_CONFIG.copy()\n merged.update(config)\n if \"system_prompts\" in config:\n merged[\"system_prompts\"] = {**DEFAULT_CONFIG[\"system_prompts\"], **config[\"system_prompts\"]}\n return merged\n except Exception as e:\n print(f\"配置文件读取失败 {path}: {e}\")\n \n print(\"警告: 未找到配置文件,使用默认配置\")\n return DEFAULT_CONFIG.copy()\n\n\n# ============ 请求处理 ============\n\nclass RequestHandler:\n \"\"\"处理来自 Lua 的请求\"\"\"\n \n def __init__(self, config: Dict[str, Any], logger: logging.Logger):\n self.config = config\n self.logger = logger\n self.system_prompts = config.get(\"system_prompts\", {})\n self.context_enabled = config.get(\"context_aware\", False)\n self.ai_client = AIClient.from_config(config)\n \n def handle(self, request_json: str) -> str:\n \"\"\"处理请求并返回 JSON 响应\"\"\"\n try:\n req = json.loads(request_json)\n except json.JSONDecodeError as e:\n self.logger.error(f\"JSON 解析失败: {e}\")\n return json.dumps({\"error\": f\"Invalid JSON: {e}\", \"result\": None})\n \n req_type = req.get(\"type\", \"correct\")\n text = req.get(\"text\", \"\")\n pinyin = req.get(\"pinyin\", \"\")\n context = req.get(\"context\", \"\")\n reqid = req.get(\"reqid\", \"\")\n \n func_name = {\"correct\": \"纠错\", \"translate\": \"翻译\", \"chat\": \"对话\"}.get(req_type, req_type)\n self.logger.info(f\"[{func_name}] 收到请求: {text[:50]}{'...' if len(text) > 50 else ''}\")\n \n # 获取系统提示词\n system_prompt = self.system_prompts.get(req_type, \"\")\n \n # 构建用户消息\n user_text = text\n context_messages = [] # 额外的消息列表\n \n if req_type == \"correct\":\n if pinyin:\n user_text = f\"拼音:{pinyin}\\n待纠正:{text}\"\n self.logger.debug(f\" 拼音: {pinyin}\")\n \n if self.context_enabled and context:\n # 使用 jieba 分词\n if JIEBA_AVAILABLE:\n tokens = list(jieba.cut(context))\n tokens = [t.strip() for t in tokens if t.strip()]\n else:\n tokens = list(context)\n \n context_tokens = \" \".join(tokens)\n self.logger.info(f\" 上下文: {context_tokens}\")\n \n # 通过 assistant 消息传递上下文\n context_messages = [\n {\"role\": \"assistant\", \"content\": f\"用户历史输入:{context_tokens}\"}\n ]\n \n # 调用 AI(传递上下文消息)\n result = self.ai_client.chat(system_prompt, user_text, context_messages if context_messages else None)\n \n if result:\n self.logger.info(f\"[{func_name}] 结果: {result[:50]}{'...' if len(result) > 50 else ''}\")\n else:\n self.logger.warning(f\"[{func_name}] 处理失败,返回原文\")\n result = text\n \n return json.dumps({\n \"reqid\": reqid,\n \"result\": result,\n \"error\": None\n }, ensure_ascii=False)\n\n\n# ============ 主服务 ============\n\nclass BzxService:\n \"\"\"IPC 通信服务\"\"\"\n \n def __init__(self, config: Dict[str, Any], logger: logging.Logger):\n self.config = config\n self.logger = logger\n self.handler = RequestHandler(config, logger)\n self.server = None\n \n def start(self):\n \"\"\"启动服务\"\"\"\n self.logger.info(\"=\" * 50)\n self.logger.info(\"Rime AI 服务已启动\")\n self.logger.info(\"=\" * 50)\n self.logger.info(f\" API: {self.config.get('api_url', 'N/A')}\")\n self.logger.info(f\" 模型: {self.config.get('model', 'N/A')}\")\n self.logger.info(f\" IPC: {IPC_NAME}\")\n self.logger.info(f\" 上下文: {'开启' if self.config.get('context_aware') else '关闭'}\")\n self.logger.info(\"=\" * 50)\n self.logger.info(\"按 Ctrl+C 停止服务...\")\n \n self.server = create_ipc_server(IPC_NAME)\n \n try:\n self.server.run(self.handler.handle)\n except KeyboardInterrupt:\n pass\n finally:\n self.stop()\n \n def stop(self):\n \"\"\"停止服务\"\"\"\n if self.server:\n self.server.stop()\n self.server.cleanup()\n self.logger.info(\"服务已停止\")\n\n\n# ============ 主函数 ============\n\ndef main():\n parser = argparse.ArgumentParser(description=\"Rime AI 服务\")\n parser.add_argument(\"--config\", \"-c\", type=str, help=\"配置文件路径\")\n parser.add_argument(\"--debug\", \"-d\", action=\"store_true\", help=\"开启调试模式\")\n args = parser.parse_args()\n \n config = load_config(args.config)\n \n # 命令行 debug 优先\n if args.debug:\n config[\"debug\"] = True\n \n logger = setup_logging(config.get(\"debug\", False))\n \n if not config.get(\"api_key\"):\n logger.warning(\"=\" * 50)\n logger.warning(\"警告: 现已使用博主bzx的api_key\")\n logger.warning(\"有能力者请编辑配置文件改用自己的api_key!\")\n logger.warning(\"=\" * 50)\n \n service = BzxService(config, logger)\n \n def signal_handler(sig, frame):\n service.stop()\n sys.exit(0)\n \n signal.signal(signal.SIGINT, signal_handler)\n signal.signal(signal.SIGTERM, signal_handler)\n \n service.start()\n\n\nif __name__ == \"__main__\":\n main()\n"}}}}