{"id":1249,"date":"2025-12-02T17:44:54","date_gmt":"2025-12-02T09:44:54","guid":{"rendered":"http:\/\/www.preluna.xyz\/?p=1249"},"modified":"2025-12-03T07:42:15","modified_gmt":"2025-12-02T23:42:15","slug":"nagaagent1","status":"publish","type":"post","link":"http:\/\/www.preluna.xyz\/index.php\/2025\/12\/02\/nagaagent1\/preluna\/technology\/career-skills\/open-source-analysis\/","title":{"rendered":"NagaAgent\u4e3b\u6587\u4ef6\u5939\u76ee\u5f55"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">\u5148\u62ce\u4e3b\u6b21<\/h2>\n\n\n\n<p>\u8981\u5206\u6790\u8fd9\u4e2a\u9879\u76ee\u7684\u6587\u4ef6\u7ed3\u6784\uff0c\u6211\u4eec\u53ef\u4ee5<strong>\u4ece\u201c\u6838\u5fc3\u5165\u53e3\u201d\u5230\u201c\u8f85\u52a9\u914d\u7f6e\u201d<\/strong>\u7684\u987a\u5e8f\u62c6\u89e3\uff0c\u5148\u6293\u5173\u952e\u6587\u4ef6\uff0c\u518d\u770b\u8f85\u52a9\u7ec4\u4ef6\uff1a<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><div class='fancybox-wrapper lazyload-container-unload' data-fancybox='post-images' href='http:\/\/www.preluna.xyz\/wp-content\/uploads\/2025\/12\/NagaAgent\u4e3b\u6587\u4ef6\u5939\u76ee\u5f551.png'><img class=\"lazyload lazyload-style-1\" src=\"data:image\/svg+xml;base64,PCEtLUFyZ29uTG9hZGluZy0tPgo8c3ZnIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjZmZmZmZmMDAiPjxnPjwvZz4KPC9zdmc+\"  loading=\"lazy\" decoding=\"async\" width=\"783\" height=\"634\" data-original=\"http:\/\/www.preluna.xyz\/wp-content\/uploads\/2025\/12\/NagaAgent\u4e3b\u6587\u4ef6\u5939\u76ee\u5f551.png\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB\/AAffA0nNPuCLAAAAAElFTkSuQmCC\" alt=\"\" class=\"wp-image-1253\"  sizes=\"auto, (max-width: 783px) 100vw, 783px\" \/><\/div><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">\u7b2c\u4e00\u6b65\uff1a\u5148\u5206\u6790\u6700\u5916\u5c42\u7684\u6838\u5fc3\u6587\u4ef6\uff08\u4f18\u5148\u7ea7\u6700\u9ad8\uff09<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li>main.py&nbsp;\n<ul class=\"wp-block-list\">\n<li>\u4f5c\u7528\uff1a\u9879\u76ee\u7684\u4e3b\u5165\u53e3\u6587\u4ef6\uff0c\u662f\u4ee3\u7801\u6267\u884c\u7684\u8d77\u70b9\uff0c\u51e0\u4e4e\u5305\u542b\u4e86\u9879\u76ee\u7684\u6838\u5fc3\u903b\u8f91\u6216\u542f\u52a8\u6d41\u7a0b\u3002<\/li>\n\n\n\n<li>\u5206\u6790\u4ef7\u503c\uff1a\u770b\u5b83\u80fd\u5feb\u901f\u77e5\u9053\u9879\u76ee\u662f\u505a\u4ec0\u4e48\u7684\u3001\u600e\u4e48\u542f\u52a8\u7684\u3002<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>build.py&nbsp; + &nbsp;main.spec&nbsp;\n<ul class=\"wp-block-list\">\n<li>\u4f5c\u7528\uff1a&nbsp;build.py&nbsp;\u662f\u6253\u5305\u811a\u672c\uff0c&nbsp;main.spec&nbsp;\u662f\u6253\u5305\u914d\u7f6e\u6587\u4ef6\uff08\u901a\u5e38\u7528\u4e8e&nbsp;PyInstaller&nbsp;\uff09\uff0c\u8d1f\u8d23\u628aPython\u9879\u76ee\u6253\u5305\u6210\u53ef\u6267\u884c\u7a0b\u5e8f\u3002<\/li>\n\n\n\n<li>\u5206\u6790\u4ef7\u503c\uff1a\u4e86\u89e3\u9879\u76ee\u7684\u5206\u53d1\u3001\u90e8\u7f72\u65b9\u5f0f\u3002<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>tart.bat&nbsp;\/&nbsp;start.sh&nbsp;\n<ul class=\"wp-block-list\">\n<li>\u4f5c\u7528\uff1a\u542f\u52a8\u811a\u672c\uff08&nbsp;bat&nbsp;\u662fWindows\u7528\uff0c&nbsp;sh&nbsp;\u662fLinux\/macOS\u7528\uff09\uff0c\u4e00\u952e\u542f\u52a8\u9879\u76ee\u7684\u5feb\u6377\u65b9\u5f0f\uff0c\u91cc\u9762\u4f1a\u5199\u542f\u52a8&nbsp;main.py&nbsp;\u7684\u547d\u4ee4\u3002<\/li>\n\n\n\n<li>\u5206\u6790\u4ef7\u503c\uff1a\u5feb\u901f\u77e5\u9053\u9879\u76ee\u7684\u542f\u52a8\u6b65\u9aa4\u3002<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">\u7b2c\u4e8c\u6b65\uff1a\u5206\u6790\u914d\u7f6e\/\u4f9d\u8d56\u6587\u4ef6\uff08\u4f18\u5148\u7ea7\u4e2d\u7b49\uff09<\/h3>\n\n\n\n<p>\u8fd9\u4e9b\u662f\u9879\u76ee\u8fd0\u884c\u7684\u201c\u73af\u5883\u652f\u6491\u201d\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>config.json.example&nbsp;\n<ul class=\"wp-block-list\">\n<li>\u4f5c\u7528\uff1a\u914d\u7f6e\u6587\u4ef6\u6a21\u677f\uff0c\u9879\u76ee\u8fd0\u884c\u9700\u8981\u7684\u53c2\u6570\uff08\u6bd4\u5982\u7aef\u53e3\u3001\u6570\u636e\u5e93\u5730\u5740\uff09\u90fd\u5728\u8fd9\u91cc\u5b9a\u4e49\uff0c\u5b9e\u9645\u7528\u7684\u65f6\u5019\u4f1a\u6539\u6210&nbsp;config.json&nbsp;\u3002<\/li>\n\n\n\n<li>\u5206\u6790\u4ef7\u503c\uff1a\u4e86\u89e3\u9879\u76ee\u7684\u53ef\u914d\u7f6e\u9879\uff0c\u4ee5\u53ca\u8fd0\u884c\u9700\u8981\u7684\u5916\u90e8\u4f9d\u8d56\uff08\u6bd4\u5982\u8981\u8fde\u54ea\u4e2a\u670d\u52a1\uff09\u3002<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>requirements.txt&nbsp;\n<ul class=\"wp-block-list\">\n<li>\u4f5c\u7528\uff1aPython\u4f9d\u8d56\u6e05\u5355\uff0c\u8bb0\u5f55\u9879\u76ee\u9700\u8981\u5b89\u88c5\u7684\u7b2c\u4e09\u65b9\u5e93\uff08\u6bd4\u5982&nbsp;requests&nbsp;\u3001&nbsp;flask&nbsp;\u7b49\uff09\u3002<\/li>\n\n\n\n<li>\u5206\u6790\u4ef7\u503c\uff1a\u901a\u8fc7\u4f9d\u8d56\u80fd\u63a8\u6d4b\u9879\u76ee\u7528\u5230\u7684\u6280\u672f\u6808\uff08\u6bd4\u5982\u7528\u4e86&nbsp;flask&nbsp;\u8bf4\u660e\u662fWeb\u670d\u52a1\uff09\u3002<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>setup.py&nbsp;\/&nbsp;setup.bat&nbsp;\/&nbsp;setup.sh\n<ul class=\"wp-block-list\">\n<li>\u4f5c\u7528\uff1a\u73af\u5883\u521d\u59cb\u5316\u811a\u672c\uff0c\u8d1f\u8d23\u5b89\u88c5\u4f9d\u8d56\u3001\u914d\u7f6e\u73af\u5883\u7b49\uff08\u6bd4\u5982&nbsp;setup.sh&nbsp;\u91cc\u53ef\u80fd\u4f1a\u5199&nbsp;pip install -r requirements.txt&nbsp;\uff09\u3002<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">\u7b2c\u4e09\u6b65\uff1a\u5206\u6790\u6587\u4ef6\u5939\uff08\u4f18\u5148\u7ea7\u6309\u201c\u529f\u80fd\u91cd\u8981\u6027\u201d\u6392\u5e8f\uff09<\/h3>\n\n\n\n<p>\u6587\u4ef6\u5939\u662f\u6309\u529f\u80fd\u5206\u7c7b\u7684\u6a21\u5757\uff0c\u5148\u770b\u6838\u5fc3\u529f\u80fd\u6587\u4ef6\u5939\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>agentserver&nbsp;\/&nbsp;apiserver\n<ul class=\"wp-block-list\">\n<li>\u4f5c\u7528\uff1a\u4ece\u540d\u79f0\u770b\u662f\u670d\u52a1\u7aef\u6a21\u5757\uff08&nbsp;agent&nbsp;\u670d\u52a1\u3001&nbsp;api&nbsp;\u63a5\u53e3\u670d\u52a1\uff09\uff0c\u662f\u9879\u76ee\u7684\u6838\u5fc3\u529f\u80fd\u8f7d\u4f53\uff08\u6bd4\u5982\u63d0\u4f9b\u63a5\u53e3\u3001\u5904\u7406\u4e1a\u52a1\u903b\u8f91\uff09\u3002<\/li>\n\n\n\n<li>\u5206\u6790\u987a\u5e8f\uff1a\u5148\u770b\u8fd9\u4e24\u4e2a\u6587\u4ef6\u5939\u91cc\u7684\u4ee3\u7801\uff0c\u5bf9\u5e94&nbsp;main.py&nbsp;\u7684\u6838\u5fc3\u903b\u8f91\u3002<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>game&nbsp;\n<ul class=\"wp-block-list\">\n<li>\u4f5c\u7528\uff1a\u5982\u679c\u9879\u76ee\u548c\u201c\u6e38\u620f\u201d\u76f8\u5173\uff0c\u8fd9\u662f\u6e38\u620f\u529f\u80fd\u7684\u6a21\u5757\uff1b\u5982\u679c\u662f\u5176\u4ed6\u573a\u666f\uff0c\u53ef\u80fd\u662f\u4e1a\u52a1\u903b\u8f91\u7684\u6838\u5fc3\u6a21\u5757\u3002<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>mqtt_tool&nbsp;\n<ul class=\"wp-block-list\">\n<li>\u4f5c\u7528\uff1a&nbsp;MQTT&nbsp;\u662f\u7269\u8054\u7f51\/\u6d88\u606f\u901a\u4fe1\u534f\u8bae\uff0c\u8fd9\u4e2a\u6587\u4ef6\u5939\u662fMQTT\u76f8\u5173\u7684\u5de5\u5177\/\u5ba2\u6237\u7aef\uff0c\u8d1f\u8d23\u6d88\u606f\u6536\u53d1\u3002<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>system&nbsp;\/&nbsp;ui&nbsp;\/&nbsp;voice&nbsp;\n<ul class=\"wp-block-list\">\n<li>\u4f5c\u7528\uff1a&nbsp;system&nbsp;\u662f\u7cfb\u7edf\u5de5\u5177\u6a21\u5757\uff1b&nbsp;ui&nbsp;\u662f\u524d\u7aef\u754c\u9762\u6a21\u5757\uff1b&nbsp;voice&nbsp;\u662f\u8bed\u97f3\u529f\u80fd\u6a21\u5757\uff0c\u5c5e\u4e8e\u201c\u6269\u5c55\u529f\u80fd\u201d\u3002<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>logs&nbsp;\n<ul class=\"wp-block-list\">\n<li>\u4f5c\u7528\uff1a\u65e5\u5fd7\u6587\u4ef6\u5939\uff0c\u9879\u76ee\u8fd0\u884c\u65f6\u7684\u65e5\u5fd7\u4f1a\u5b58\u5728\u8fd9\u91cc\uff0c\u8c03\u8bd5\u65f6\u7528\uff0c\u6682\u65f6\u53ef\u4ee5\u540e\u770b\u3002<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">\u7b2c\u56db\u6b65\uff1a\u8f85\u52a9\u6587\u4ef6<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>&nbsp;README.*.md&nbsp;\uff1a\u867d\u7136\u8fd9\u91cc\u7684md,\u4f5c\u8005\u5df2\u7ecf\u5199\u5f97\u5c3d\u53ef\u80fd\u7684\u8be6\u5b9e\u4e86\uff0c\u4f46\u662f\u6211\u770b\u8d77\u6765\u8fd8\u662f\u6709\u70b9\u4e0d\u592a\u660e\u767d\uff0c\u6240\u4ee5\u8bf4\u6211\u8fd8\u662f\u9700\u8981\u8fdb\u884c\u518d\u63a2\u7a76\u7684\u3002<\/li>\n\n\n\n<li>&nbsp;.gitattributes&nbsp;\/&nbsp;.gitignore&nbsp;\uff1aGit\u7248\u672c\u7ba1\u7406\u7684\u914d\u7f6e\u6587\u4ef6\uff0c\u4e0d\u5f71\u54cd\u9879\u76ee\u529f\u80fd\uff0c\u6700\u540e\u770b\uff1b<\/li>\n\n\n\n<li>&nbsp;uv.lock&nbsp;\uff1aPython\u865a\u62df\u73af\u5883\uff08&nbsp;uv&nbsp;\u5de5\u5177\uff09\u7684\u4f9d\u8d56\u9501\u6587\u4ef6\uff0c\u8bb0\u5f55\u4f9d\u8d56\u7684\u5177\u4f53\u7248\u672c\uff0c\u8f85\u52a9\u770b\u73af\u5883\u7528\u3002<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">\u5177\u4f53\u5206\u6790<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">main.py<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code># pyinstaller\u9002\u914d\nimport os\nimport sys\nif os.path.exists(\"_internal\"):\n    os.chdir(\"_internal\")\n#\u76ee\u7684\uff1a\u8ba9\u7a0b\u5e8f\u5728\u6253\u5305\u540e\u80fd\u6b63\u5e38\u8fd0\u884c\n###\u505a\u4e86\u4ec0\u4e48\uff1a\n# os.exists(\"_internal\")\uff1a\u68c0\u67e5\u5f53\u524d\u6587\u4ef6\u5939\u4e0b\u6709\u6ca1\u6709\u53eb\"_internal\"\u7684\u6587\u4ef6\u5939\n#os.chdir(\"_internal\")\uff1a\u5982\u679c\u6709\u8fd9\u4e2a\u6587\u4ef6\u5939\uff0c\u5c31\u8fdb\u5165\u5b83\uff08\u6539\u53d8\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\uff09\n#\u4e3a\u4ec0\u4e48\u8fd9\u4e48\u505a\uff1aPyInstaller\u6253\u5305\u65f6\u4f1a\u628a\u7a0b\u5e8f\u9700\u8981\u7684\u6587\u4ef6\u653e\u5230\"_internal\"\u6587\u4ef6\u5939\u91cc\n#\n# \u68c0\u6d4b\u662f\u5426\u5728\u6253\u5305\u73af\u5883\u4e2d\n# PyInstaller\u6253\u5305\u540e\u7684\u7a0b\u5e8f\u4f1a\u8bbe\u7f6esys.frozen\u5c5e\u6027\nIS_PACKAGED = getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS')\n###\u76ee\u7684\uff1a\u5224\u65ad\u7a0b\u5e8f\u662f\u88ab\u6253\u5305\u6210exe\uff0c\u8fd8\u662f\u76f4\u63a5\u8fd0\u884c\u7684.py\u6587\u4ef6\n#\u51fd\u6570\u8bf4\u660e\uff1a\n'''\n\u51fd\u6570\u8bf4\u660e\uff1a\ngetattr(sys, 'frozen', False)\uff1a\u83b7\u53d6sys.frozen\u5c5e\u6027\uff0c\u5982\u679c\u4e0d\u5b58\u5728\u5c31\u8fd4\u56deFalse\nhasattr(sys, '_MEIPASS')\uff1a\u68c0\u67e5sys\u6709\u6ca1\u6709'_MEIPASS'\u5c5e\u6027\n\u903b\u8f91\u5224\u65ad\uff1a\n\u5982\u679c\u4e24\u4e2a\u6761\u4ef6\u90fd\u6210\u7acb\u2192IS_PACKAGED = True\uff08\u7a0b\u5e8f\u88ab\u6253\u5305\u4e86\uff09\n\u4efb\u4f55\u4e00\u4e2a\u4e0d\u6210\u7acb\u2192IS_PACKAGED = False\uff08\u76f4\u63a5\u8fd0\u884cPython\u811a\u672c\uff09\n'''\n# \u6807\u51c6\u5e93\u5bfc\u5165\nimport asyncio  # \u5f02\u6b65\u7f16\u7a0b\u5e93\uff08\u8ba9\u7a0b\u5e8f\u53ef\u4ee5\u540c\u65f6\u505a\u591a\u4ef6\u4e8b\uff09\nimport logging  # \u65e5\u5fd7\u8bb0\u5f55\uff08\u8bb0\u5f55\u7a0b\u5e8f\u8fd0\u884c\u4fe1\u606f\uff09\nimport socket   # \u7f51\u7edc\u901a\u4fe1\uff08\u8fde\u63a5\u7f51\u7edc\uff09\nimport threading  # \u591a\u7ebf\u7a0b\uff08\u8ba9\u7a0b\u5e8f\u540c\u65f6\u8fd0\u884c\u591a\u4e2a\u4efb\u52a1\uff09\nimport time     # \u65f6\u95f4\u76f8\u5173\u529f\u80fd\uff08\u7b49\u5f85\u3001\u8ba1\u65f6\u7b49\uff09\nimport warnings   # \u8b66\u544a\u5904\u7406\nimport requests  # HTTP\u8bf7\u6c42\uff08\u8bbf\u95ee\u7f51\u9875\uff09\n\n# \u8fc7\u6ee4\u5f03\u7528\u8b66\u544a\uff0c\u63d0\u5347\u542f\u52a8\u4f53\u9a8c\nwarnings.filterwarnings(\"ignore\", category=DeprecationWarning, module=\"websockets\")\nwarnings.filterwarnings(\"ignore\", category=DeprecationWarning, module=\"uvicorn\")\nwarnings.filterwarnings(\"ignore\", category=DeprecationWarning, message=\".*websockets.legacy.*\")\nwarnings.filterwarnings(\"ignore\", category=DeprecationWarning, message=\".*WebSocketServerProtocol.*\")\nwarnings.filterwarnings(\"ignore\", category=DeprecationWarning, message=\".*websockets.*\")\nwarnings.filterwarnings(\"ignore\", category=DeprecationWarning, message=\".*uvicorn.*\")\n'''\n\u76ee\u7684\uff1a\u5c4f\u853d\u4e00\u4e9b\u70e6\u4eba\u7684\u8b66\u544a\u4fe1\u606f\uff0c\u8ba9\u7a0b\u5e8f\u542f\u52a8\u65f6\u63a7\u5236\u53f0\u66f4\u5e72\u51c0\n\u8fc7\u6ee4\u4e86\u54ea\u4e9b\uff1a\nwebsockets\u5e93\u7684\u5f03\u7528\u8b66\u544a\nuvicorn\u5e93\u7684\u5f03\u7528\u8b66\u544a\n\u5404\u79cd\u76f8\u5173\u6a21\u5757\u7684\u5f03\u7528\u8b66\u544a\n'''\n\n# \u4fee\u590dWindows socket\u517c\u5bb9\u6027\u95ee\u9898\nif not hasattr(socket, 'EAI_ADDRFAMILY'):\n    # Windows\u7cfb\u7edf\u7f3a\u5c11\u8fd9\u4e9b\u9519\u8bef\u7801\uff0c\u6dfb\u52a0\u517c\u5bb9\u6027\u5e38\u91cf\n    socket.EAI_ADDRFAMILY = -9\n    socket.EAI_AGAIN = -3\n    socket.EAI_BADFLAGS = -1\n    socket.EAI_FAIL = -4\n    socket.EAI_MEMORY = -10\n    socket.EAI_NODATA = -5\n    socket.EAI_NONAME = -2\n    socket.EAI_OVERFLOW = -12\n    socket.EAI_SERVICE = -8\n    socket.EAI_SOCKTYPE = -7\n    socket.EAI_SYSTEM = -11\n'''\n\u505a\u4e86\u4ec0\u4e48\uff1a\nhasattr(socket, 'EAI_ADDRFAMILY')\uff1a\u68c0\u67e5socket\u6a21\u5757\u6709\u6ca1\u6709EAI_ADDRFAMILY\u5c5e\u6027\n\u5982\u679c\u6ca1\u6709\uff08Windows\u7cfb\u7edf\uff09\uff0c\u5c31\u624b\u52a8\u6dfb\u52a011\u4e2a\u9519\u8bef\u7801\u5e38\u91cf\n\u4e3a\u4ec0\u4e48\uff1aLinux\/macOS\u6709\u8fd9\u4e9b\u9519\u8bef\u7801\uff0cWindows\u6ca1\u6709\uff0c\u6dfb\u52a0\u5b83\u4eec\u8ba9\u7a0b\u5e8f\u5728\u4e0d\u540c\u7cfb\u7edf\u8868\u73b0\u4e00\u81f4\n'''\n\n\n# \u7b2c\u4e09\u65b9\u5e93\u5bfc\u5165\n# \u4f18\u5148\u4f7f\u7528\u4ed3\u5e93\u5185\u7684\u672c\u5730\u5305\uff0c\u9632\u6b62\u5bfc\u5165\u5230\u7cfb\u7edf\u5df2\u5b89\u88c5\u7684\u65e7\u7248 nagaagent_core #\nREPO_ROOT = os.path.dirname(os.path.abspath(__file__))  # \u7edf\u4e00\u5165\u53e3 #\nLOCAL_PKG_DIR = os.path.join(REPO_ROOT, \"nagaagent-core\")  # \u7edf\u4e00\u5165\u53e3 #\nif LOCAL_PKG_DIR not in sys.path:\n    sys.path.insert(0, LOCAL_PKG_DIR)  # \u4f18\u5148\u4f7f\u7528\u672c\u5730\u5305 #\n'''\n\u8bbe\u7f6e\u672c\u5730\u5305\u8def\u5f84\n\u76ee\u7684\uff1a\u4f18\u5148\u4f7f\u7528\u7a0b\u5e8f\u81ea\u5df1\u7684\u5e93\uff0c\u800c\u4e0d\u662f\u7cfb\u7edf\u5b89\u88c5\u7684\u5e93\n\u505a\u4e86\u4ec0\u4e48\uff1a\nos.path.abspath(__file__)\uff1a\u83b7\u53d6\u5f53\u524d\u6587\u4ef6\u7684\u7edd\u5bf9\u8def\u5f84\nos.path.dirname(...)\uff1a\u83b7\u53d6\u8fd9\u4e2a\u6587\u4ef6\u6240\u5728\u7684\u6587\u4ef6\u5939\u8def\u5f84\nos.path.join(..., \"nagaagent-core\")\uff1a\u62fc\u63a5\u51fanagaagent-core\u6587\u4ef6\u5939\u7684\u8def\u5f84\nsys.path.insert(0, ...)\uff1a\u628a\u8fd9\u4e2a\u8def\u5f84\u63d2\u5165\u5230Python\u7684\u641c\u7d22\u8def\u5f84\u6700\u524d\u9762\uff08\u4f18\u5148\u641c\u7d22\uff09\n'''\nfrom nagaagent_core.vendors.PyQt5.QtGui import QIcon  # \u7edf\u4e00\u5165\u53e3 #\nfrom nagaagent_core.vendors.PyQt5.QtWidgets import QApplication  # \u7edf\u4e00\u5165\u53e3 #\n'''\n \u5bfc\u5165PyQt5\u7ec4\u4ef6\n \u5bfc\u5165\u7684\u5185\u5bb9\uff1a\n QIcon\uff1a\u56fe\u6807\u7c7b\uff08\u7528\u4e8e\u663e\u793a\u7a0b\u5e8f\u56fe\u6807\uff09\nQApplication\uff1a\u5e94\u7528\u7a0b\u5e8f\u7c7b\uff08PyQt5\u7a0b\u5e8f\u7684\u6838\u5fc3\uff09\n'''\n# \u672c\u5730\u6a21\u5757\u5bfc\u5165\nfrom system.system_checker import run_system_check, run_quick_check\nfrom system.config import config, AI_NAME\n\n# V14\u7248\u672c\u5df2\u79fb\u9664\u65e9\u671f\u62e6\u622a\u5668\uff0c\u91c7\u7528\u8fd0\u884c\u65f6\u7334\u5b50\u8865\u4e01\n\n# conversation_core\u5df2\u5220\u9664\uff0c\u76f8\u5173\u529f\u80fd\u5df2\u8fc1\u79fb\u5230apiserver\nfrom summer_memory.memory_manager import memory_manager\nfrom summer_memory.task_manager import start_task_manager, task_manager\nfrom ui.pyqt_chat_window import ChatWindow\nfrom ui.tray.console_tray import integrate_console_tray\n'''\n\u5bfc\u5165\u672c\u5730\u6a21\u5757\n'''\n\n\n# \u914d\u7f6e\u65e5\u5fd7\nlogging.basicConfig(level=logging.INFO)\nlogger = logging.getLogger(\"summer_memory\")\nlogger.setLevel(logging.INFO)\n'''\n\u57fa\u672c\u914d\u7f6e\n\u505a\u4e86\u4ec0\u4e48\uff1a\n\u8bbe\u7f6e\u5168\u5c40\u65e5\u5fd7\u7ea7\u522b\u4e3aINFO\uff08\u53ea\u8bb0\u5f55\u91cd\u8981\u4fe1\u606f\uff09\n\u521b\u5efa\u540d\u4e3a\"summer_memory\"\u7684\u65e5\u5fd7\u8bb0\u5f55\u5668\n\u8bbe\u7f6e\u8fd9\u4e2a\u8bb0\u5f55\u5668\u7684\u7ea7\u522b\u4e5f\u662fINFO\n'''\n# \u8fc7\u6ee4HTTP\u76f8\u5173\u65e5\u5fd7\nlogging.getLogger(\"httpcore\").setLevel(logging.WARNING)\nlogging.getLogger(\"httpx\").setLevel(logging.WARNING)\n\n# \u4f18\u5316Live2D\u76f8\u5173\u65e5\u5fd7\u8f93\u51fa\uff0c\u51cf\u5c11\u542f\u52a8\u65f6\u7684\u4fe1\u606f\u566a\u97f3\nlogging.getLogger(\"live2d\").setLevel(logging.WARNING)  # Live2D\u5e93\u65e5\u5fd7\nlogging.getLogger(\"live2d.renderer\").setLevel(logging.WARNING)  # \u6e32\u67d3\u5668\u65e5\u5fd7\nlogging.getLogger(\"live2d.animator\").setLevel(logging.WARNING)  # \u52a8\u753b\u5668\u65e5\u5fd7\nlogging.getLogger(\"live2d.widget\").setLevel(logging.WARNING)  # \u7ec4\u4ef6\u65e5\u5fd7\nlogging.getLogger(\"live2d.config\").setLevel(logging.WARNING)  # \u914d\u7f6e\u65e5\u5fd7\nlogging.getLogger(\"live2d.config_dialog\").setLevel(logging.WARNING)  # \u914d\u7f6e\u5bf9\u8bdd\u6846\u65e5\u5fd7\nlogging.getLogger(\"OpenGL\").setLevel(logging.WARNING)  # OpenGL\u65e5\u5fd7\nlogging.getLogger(\"OpenGL.acceleratesupport\").setLevel(logging.WARNING)  # OpenGL\u52a0\u901f\u65e5\u5fd7\n'''\n\u76ee\u7684\uff1a\u51cf\u5c11\u4e0d\u5fc5\u8981\u7684\u65e5\u5fd7\u8f93\u51fa\uff0c\u8ba9\u63a7\u5236\u53f0\u66f4\u5e72\u51c0\n\u903b\u8f91\uff1a\n\u628a\u8fd9\u4e9b\u6a21\u5757\u7684\u65e5\u5fd7\u7ea7\u522b\u8bbe\u4e3aWARNING\n\u53ea\u6709\u8b66\u544a\u548c\u9519\u8bef\u7ea7\u522b\u7684\u4fe1\u606f\u624d\u4f1a\u88ab\u8f93\u51fa\nINFO\u548cDEBUG\u7ea7\u522b\u7684\u4fe1\u606f\u4f1a\u88ab\u5ffd\u7565\n'''\n# \u670d\u52a1\u7ba1\u7406\u5668\u7c7b\nclass ServiceManager:\n    \"\"\"\u670d\u52a1\u7ba1\u7406\u5668 - \u7edf\u4e00\u7ba1\u7406\u6240\u6709\u540e\u53f0\u670d\u52a1\"\"\"\n    \n    def __init__(self): #__init__\u65b9\u6cd5\uff08\u521d\u59cb\u5316\u65b9\u6cd5\uff09,\u8fd9\u4e2a\u65b9\u6cd5\u5728\u521b\u5efaServiceManager\u5bf9\u8c61\u65f6\u81ea\u52a8\u8c03\u7528\uff1a\n        self.loop = asyncio.new_event_loop()\n        '''\n        \u76ee\u7684\uff1a\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u4e8b\u4ef6\u5faa\u73af\uff08event loop\uff09\n        \u4e8b\u4ef6\u5faa\u73af\u662f\u4ec0\u4e48\uff1a\u60f3\u8c61\u6210\u4e00\u4e2a\u5927\u603b\u7ba1\uff0c\u8d1f\u8d23\u534f\u8c03\u548c\u7ba1\u7406\u6240\u6709\u7684\u5f02\u6b65\u4efb\u52a1\uff08\u8ba9\u7a0b\u5e8f\u53ef\u4ee5\u540c\u65f6\u505a\u591a\u4ef6\u4e8b\u60c5\uff09\n        '''\n        #\u76ee\u7684\uff1a\u521d\u59cb\u53164\u4e2a\u53d8\u91cf\uff0c\u90fd\u8bbe\u4e3aNone\uff08\u7a7a\uff09\n        self.bg_thread = None  #bg_thread\uff1a\u540e\u53f0\u7ebf\u7a0b\n        self.api_thread = None  #api_thread\uff1aAPI\u670d\u52a1\u5668\u7ebf\u7a0b\n        self.agent_thread = None   #  gent_thread\uff1aAgent\u670d\u52a1\u5668\u7ebf\u7a0b\n        self.tts_thread = None    #  gent_thread\uff1aAgent\u670d\u52a1\u5668\u7ebf\u7a0b\n        self._services_ready = False  # \u670d\u52a1\u5c31\u7eea\u72b6\u6001\n        '''\n        \u8bbe\u7f6e\u4e00\u4e2a\u6807\u8bb0\uff0c\u7528\u6765\u8bb0\u5f55\u670d\u52a1\u662f\u5426\u51c6\u5907\u597d\u4e86\n        \u4e0b\u5212\u7ebf\u5f00\u5934\uff1aPython\u7ea6\u5b9a\uff0c\u8868\u793a\u8fd9\u662f\"\u5185\u90e8\u4f7f\u7528\u7684\u53d8\u91cf\"\uff0c\u5176\u4ed6\u4ee3\u7801\u4e0d\u8981\u76f4\u63a5\u4fee\u6539\u5b83\n        '''\n'''\n\u6bb5\u4ee3\u7801\u505a\u4e86\u4ec0\u4e48\uff1f\n\u521b\u5efa\u4e86\u4e00\u4e2a\u53ebServiceManager\u7684\u7c7b\n\u8fd9\u4e2a\u7c7b\u7684\u4f5c\u7528\u662f\uff1a\u7edf\u4e00\u7ba1\u7406\u6240\u6709\u540e\u53f0\u670d\u52a1\n '''\n    def start_background_services(self):\n        \"\"\"\u542f\u52a8\u540e\u53f0\u670d\u52a1 - \u5f02\u6b65\u975e\u963b\u585e\"\"\"\n        # \u542f\u52a8\u540e\u53f0\u4efb\u52a1\u7ba1\u7406\u5668\n        self.bg_thread = threading.Thread(target=self._run_event_loop, daemon=True)\n        #\u521b\u5efa\u7ebf\u7a0b\uff1a\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u7ebf\u7a0b\n        '''\n        \u53c2\u6570\u8bf4\u660e\uff1a\n        target=self._run_event_loop\uff1a\u8fd9\u4e2a\u7ebf\u7a0b\u8981\u6267\u884c_run_event_loop\u65b9\u6cd5\n        daemon=True\uff1a\u8bbe\u4e3a\u5b88\u62a4\u7ebf\u7a0b\uff08\u5f53\u4e3b\u7a0b\u5e8f\u9000\u51fa\u65f6\uff0c\u8fd9\u4e2a\u7ebf\u7a0b\u4e5f\u4f1a\u81ea\u52a8\u9000\u51fa\uff09\n        '''\n        self.bg_thread.start()  #\u542f\u52a8\u7ebf\u7a0b\uff1a\u5f00\u59cb\u8fd0\u884c\u8fd9\u4e2a\u7ebf\u7a0b\n        logger.info(f\"\u540e\u53f0\u670d\u52a1\u7ebf\u7a0b\u5df2\u542f\u52a8: {self.bg_thread.name}\")  #  \u8bb0\u5f55\u65e5\u5fd7\uff1a\u8bb0\u5f55\u540e\u53f0\u670d\u52a1\u7ebf\u7a0b\u5df2\u7ecf\u542f\u52a8\u4e86\uff0c\u5e76\u663e\u793a\u7ebf\u7a0b\u7684\u540d\u5b57\n        # \u8fd9\u4e2a\u65b9\u6cd5\u7684\u4f5c\u7528\uff1a\u542f\u52a8\u540e\u53f0\u670d\u52a1\uff0c\u4f46\u4e0d\u963b\u585e\u4e3b\u7a0b\u5e8f\uff08\u4e3b\u7a0b\u5e8f\u53ef\u4ee5\u7ee7\u7eed\u505a\u5176\u4ed6\u4e8b\u60c5\uff09\n        # \u79fb\u9664\u963b\u585e\u7b49\u5f85\uff0c\u6539\u4e3a\u5f02\u6b65\u68c0\u67e5\n        # time.sleep(1)  # \u5220\u9664\u963b\u585e\u7b49\u5f85\n    \n    def _run_event_loop(self):\n        \"\"\"\u8fd0\u884c\u4e8b\u4ef6\u5faa\u73af\uff08\u5c31\u662f\u521a\u624d\u8bf4\u7684\u90a3\u4e2a\uff08event loop\uff09\uff09\"\"\"\n        # \u542f\u52a8\u540e\u53f0\u670d\u52a1\uff0c\u4f46\u4e0d\u963b\u585e\u4e3b\u7a0b\u5e8f\uff08\u4e3b\u7a0b\u5e8f\u53ef\u4ee5\u7ee7\u7eed\u505a\u5176\u4ed6\u4e8b\u60c5\uff09\n        asyncio.set_event_loop(self.loop)  #\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u7ebf\u7a0b,\u8bbe\u7f6e\u4e8b\u4ef6\u5faa\u73af\uff1a\u544a\u8bc9asyncio\u5e93\uff0c\u4f7f\u7528\u6211\u4eec\u521a\u624d\u521b\u5efa\u7684\u4e8b\u4ef6\u5faa\u73af\n        '''\u53c2\u6570\u8bf4\u660e\uff1a\n          target=self._run_event_loop\uff1a\u8fd9\u4e2a\u7ebf\u7a0b\u8981\u6267\u884c_run_event_loop\u65b9\u6cd5\n          daemon=True\uff1a\u8bbe\u4e3a\u5b88\u62a4\u7ebf\u7a0b\uff08\u5f53\u4e3b\u7a0b\u5e8f\u9000\u51fa\u65f6\uff0c\u8fd9\u4e2a\u7ebf\u7a0b\u4e5f\u4f1a\u81ea\u52a8\u9000\u51fa\uff09\n        '''\n        self.loop.run_until_complete(self._init_background_services())\n        #\u8fd0\u884c\u4e8b\u4ef6\u5faa\u73af\uff1a\u542f\u52a8\u4e8b\u4ef6\u5faa\u73af\uff0c\u5e76\u4e14\u7b49_init_background_services\u65b9\u6cd5\u5b8c\u6210\n        #run_until_complete\uff1a\u4e00\u76f4\u8fd0\u884c\uff0c\u76f4\u5230\u62ec\u53f7\u91cc\u7684\u4efb\u52a1\u5b8c\u6210\n        logger.info(\"\u540e\u53f0\u670d\u52a1\u4e8b\u4ef6\u5faa\u73af\u5df2\u542f\u52a8\") # \u8bb0\u5f55\u65e5\u5fd7\uff1a\u8bb0\u5f55\u4e8b\u4ef6\u5faa\u73af\u5df2\u7ecf\u542f\u52a8\u4e86\n\n    async def _init_background_services(self):\n        \"\"\"\u521d\u59cb\u5316\u540e\u53f0\u670d\u52a1 - \u4f18\u5316\u542f\u52a8\u6d41\u7a0b\"\"\"\n        logger.info(\"\u6b63\u5728\u542f\u52a8\u540e\u53f0\u670d\u52a1...\") # \u8bb0\u5f55\u65e5\u5fd7\uff1a\u544a\u8bc9\u7528\u6237\u6b63\u5728\u542f\u52a8\u540e\u53f0\u670d\u52a1\n        try:  # \u5f02\u5e38\u5904\u7406\uff1a\n            # \u4efb\u52a1\u7ba1\u7406\u5668\u7531memory_manager\u81ea\u52a8\u542f\u52a8\uff0c\u65e0\u9700\u624b\u52a8\u542f\u52a8\n            # await start_task_manager()\n            \n            # \u6807\u8bb0\u670d\u52a1\u5c31\u7eea\n            self._services_ready = True  # \u8bbe\u7f6e\u6807\u8bb0\uff1a\u628a\u670d\u52a1\u5c31\u7eea\u6807\u8bb0\u8bbe\u4e3aTrue\uff08\u771f\uff09\uff0c\u8868\u793a\u670d\u52a1\u5df2\u7ecf\u51c6\u5907\u597d\u4e86\n            logger.info(f\"\u4efb\u52a1\u7ba1\u7406\u5668\u72b6\u6001: running={task_manager.is_running}\")\n            # \u8bb0\u5f55\u65e5\u5fd7\uff1a\u663e\u793a\u4efb\u52a1\u7ba1\u7406\u5668\u7684\u8fd0\u884c\u72b6\u6001\n            # f\u5b57\u7b26\u4e32\uff1a{task_manager.is_running}\u4f1a\u66ff\u6362\u4e3atask_manager.is_running\u7684\u5b9e\u9645\u503c\n\n            # \u4fdd\u6301\u4e8b\u4ef6\u5faa\u73af\u6d3b\u8dc3\n            while True:  # \u65e0\u9650\u5faa\u73af\uff1a\u4fdd\u6301\u4e8b\u4ef6\u5faa\u73af\u4e00\u76f4\u8fd0\u884c\n                await asyncio.sleep(3600)  # \u6bcf\u5c0f\u65f6\u68c0\u67e5\u4e00\u6b21\n                #\u9632\u6b62\u4e8b\u4ef6\u5faa\u73af\u9000\u51fa\uff0c\u8ba9\u5b83\u4e00\u76f4\u4fdd\u6301\u5728\u540e\u53f0\u8fd0\u884c\n        except Exception as e: # except Exception as e\uff1a\u5982\u679c\u53d1\u751f\u4efb\u4f55\u5f02\u5e38\uff0c\u5c31\u6355\u83b7\u5b83\uff0c\u5e76\u628a\u5f02\u5e38\u4fe1\u606f\u4fdd\u5b58\u5230\u53d8\u91cfe\u4e2d\n            logger.error(f\"\u540e\u53f0\u670d\u52a1\u5f02\u5e38: {e}\") # \u8bb0\u5f55\u9519\u8bef\u65e5\u5fd7\n         '''\u8fd9\u4e2a\u65b9\u6cd5\u7684\u7279\u70b9\uff1a\n         \u524d\u9762\u6709async\u5173\u952e\u5b57\uff0c\u8868\u793a\u8fd9\u662f\u4e00\u4e2a\u5f02\u6b65\u65b9\u6cd5\n         \u53ef\u4ee5\u5728\u91cc\u9762\u4f7f\u7528await\u7b49\u5f85\u5176\u4ed6\u5f02\u6b65\u4efb\u52a1\n         '''\n    def check_port_available(self, host, port):\n        \"\"\"\u68c0\u67e5\u7aef\u53e3\u662f\u5426\u53ef\u7528\"\"\"\n        try:\n            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:\n                '''\n                \u521b\u5efasocket\uff1a\n                socket.AF_INET\uff1a\u4f7f\u7528IPv4\u5730\u5740\n                socket.SOCK_STREAM\uff1a\u4f7f\u7528TCP\u534f\u8bae\n                with ... as s\uff1a\u81ea\u52a8\u7ba1\u7406socket\u7684\u521b\u5efa\u548c\u5173\u95ed\n                '''\n                s.bind((host, port))\n                '''\u5c1d\u8bd5\u7ed1\u5b9a\u7aef\u53e3\uff1a\u628asocket\u7ed1\u5b9a\u5230\u6307\u5b9a\u7684\u4e3b\u673a\u548c\u7aef\u53e3\n                \u5982\u679c\u6210\u529f\uff1a\u8bf4\u660e\u7aef\u53e3\u53ef\u7528\uff0c\u6ca1\u6709\u88ab\u5360\u7528\n                \u5982\u679c\u5931\u8d25\uff1a\u8bf4\u660e\u7aef\u53e3\u5df2\u7ecf\u88ab\u5176\u4ed6\u7a0b\u5e8f\u5360\u7528\u4e86\n                '''\n                return True\n        except OSError:  #\u7aef\u53e3\u88ab\u5360\u7528\uff1a\u6355\u83b7OSError\u5f02\u5e38\uff0c\u8fd4\u56deFalse\n            return False\n    \n    def start_all_servers(self):  #\u8fd9\u662f\u6700\u91cd\u8981\u7684\u65b9\u6cd5\u4e4b\u4e00\n        \"\"\"\u5e76\u884c\u542f\u52a8\u6240\u6709\u670d\u52a1\uff1aAPI(\u53ef\u9009)\u3001MCP\u3001Agent\u3001TTS - \u540c\u65f6\u542f\u52a8\uff0c\u800c\u4e0d\u662f\u4e00\u4e2a\u63a5\u4e00\u4e2a\uff09\u4f18\u5316\u7248\u672c\"\"\"\n        print(\"\ud83d\ude80 \u6b63\u5728\u5e76\u884c\u542f\u52a8\u6240\u6709\u670d\u52a1...\")\n        print(\"=\" * 50)\n        threads = &#91;]  #  \u7528\u6765\u5b58\u50a8\u6240\u6709\u8981\u542f\u52a8\u7684\u7ebf\u7a0b\n        service_status = {}  # \u670d\u52a1\u72b6\u6001\u8ddf\u8e2a\n        \n        try:  #\u5f02\u5e38\u5904\u7406\u5f00\u59cb\uff1atry\u8868\u793a\u5f00\u59cb\u5c1d\u8bd5\u6267\u884c\n            self._init_proxy_settings()\n            # \u9884\u68c0\u67e5\u6240\u6709\u7aef\u53e3\uff0c\u51cf\u5c11\u91cd\u590d\u68c0\u67e5\n            from system.config import get_server_port #\u4ecesystem.config\u5bfc\u5165get_server_port\u51fd\u6570\n            #\u521b\u5efa\u5b57\u5178\uff1a\u68c0\u67e54\u4e2a\u670d\u52a1\u7684\u7aef\u53e3\u662f\u5426\u53ef\u7528\n            port_checks = {\n                'api': config.api_server.enabled and config.api_server.auto_start and \n                      self.check_port_available(config.api_server.host, config.api_server.port),\n                #\u5bf9\u4e8eAPI\u670d\u52a1\u5668\uff1a\u9700\u8981\u540c\u65f6\u6ee1\u8db33\u4e2a\u6761\u4ef6\uff08\u542f\u7528\u3001\u81ea\u52a8\u542f\u52a8\u3001\u7aef\u53e3\u53ef\u7528\uff09\n                'mcp': self.check_port_available(\"0.0.0.0\", get_server_port(\"mcp_server\")),\n                'agent': self.check_port_available(\"0.0.0.0\", get_server_port(\"agent_server\")),\n                'tts': self.check_port_available(\"0.0.0.0\", config.tts.port)\n                #\u5bf9\u4e8e\u5176\u4ed6\u670d\u52a1\u5668\uff1a\u53ea\u68c0\u67e5\u7aef\u53e3\u662f\u5426\u53ef\u7528\n            }\n            \n            # API\u670d\u52a1\u5668\uff08\u53ef\u9009\uff09\n            if port_checks&#91;'api']:\n                api_thread = threading.Thread(target=self._start_api_server, daemon=True)\n                threads.append((\"API\", api_thread))\n                service_status&#91;'API'] = \"\u51c6\u5907\u542f\u52a8\"\n            elif config.api_server.enabled and config.api_server.auto_start:\n                print(f\"\u26a0\ufe0f  API\u670d\u52a1\u5668: \u7aef\u53e3 {config.api_server.port} \u5df2\u88ab\u5360\u7528\uff0c\u8df3\u8fc7\u542f\u52a8\")\n                service_status&#91;'API'] = \"\u7aef\u53e3\u5360\u7528\"\n            '''\u903b\u8f91\u6d41\u7a0b\uff1a\n            \u5982\u679cAPI\u7aef\u53e3\u53ef\u7528 \u2192 \u521b\u5efa\u7ebf\u7a0b\uff0c\u51c6\u5907\u542f\u52a8\n            \u5426\u5219\u5982\u679cAPI\u542f\u7528\u4e86\u4e14\u8981\u81ea\u52a8\u542f\u52a8 \u2192 \u6253\u5370\u8b66\u544a\uff0c\u6807\u8bb0\u7aef\u53e3\u88ab\u5360\u7528\n            '''\n            # MCP\u670d\u52a1\u5668\n            if port_checks&#91;'mcp']:\n                mcp_thread = threading.Thread(target=self._start_mcp_server, daemon=True)\n                threads.append((\"MCP\", mcp_thread))\n                service_status&#91;'MCP'] = \"\u51c6\u5907\u542f\u52a8\"\n            else:\n                print(f\"\u26a0\ufe0f  MCP\u670d\u52a1\u5668: \u7aef\u53e3 {get_server_port('mcp_server')} \u5df2\u88ab\u5360\u7528\uff0c\u8df3\u8fc7\u542f\u52a8\")\n                service_status&#91;'MCP'] = \"\u7aef\u53e3\u5360\u7528\"\n            \n            # Agent\u670d\u52a1\u5668\n            if port_checks&#91;'agent']:\n                agent_thread = threading.Thread(target=self._start_agent_server, daemon=True)\n                threads.append((\"Agent\", agent_thread))\n                service_status&#91;'Agent'] = \"\u51c6\u5907\u542f\u52a8\"\n            else:\n                print(f\"\u26a0\ufe0f  Agent\u670d\u52a1\u5668: \u7aef\u53e3 {get_server_port('agent_server')} \u5df2\u88ab\u5360\u7528\uff0c\u8df3\u8fc7\u542f\u52a8\")\n                service_status&#91;'Agent'] = \"\u7aef\u53e3\u5360\u7528\"\n            \n            # TTS\u670d\u52a1\u5668\n            if port_checks&#91;'tts']:\n                tts_thread = threading.Thread(target=self._start_tts_server, daemon=True)\n                threads.append((\"TTS\", tts_thread))\n                service_status&#91;'TTS'] = \"\u51c6\u5907\u542f\u52a8\"\n            else:\n                print(f\"\u26a0\ufe0f  TTS\u670d\u52a1\u5668: \u7aef\u53e3 {config.tts.port} \u5df2\u88ab\u5360\u7528\uff0c\u8df3\u8fc7\u542f\u52a8\")\n                service_status&#91;'TTS'] = \"\u7aef\u53e3\u5360\u7528\"\n            \n            # \u663e\u793a\u670d\u52a1\u542f\u52a8\u8ba1\u5212\n            print(\"\\n\ud83d\udccb \u670d\u52a1\u542f\u52a8\u8ba1\u5212:\")\n            for service, status in service_status.items():\n                if status == \"\u51c6\u5907\u542f\u52a8\":\n                    print(f\"   \ud83d\udd04 {service}\u670d\u52a1\u5668: \u6b63\u5728\u542f\u52a8...\")\n                else:\n                    print(f\"   \u26a0\ufe0f  {service}\u670d\u52a1\u5668: {status}\")\n            \n            print(\"\\n\ud83d\ude80 \u5f00\u59cb\u542f\u52a8\u670d\u52a1...\")\n            print(\"-\" * 30)\n            \n            # \u6279\u91cf\u542f\u52a8\u6240\u6709\u7ebf\u7a0b\n            for name, thread in threads:\n                thread.start()\n                print(f\"\u2705 {name}\u670d\u52a1\u5668: \u542f\u52a8\u7ebf\u7a0b\u5df2\u521b\u5efa\")\n            \n            print(\"-\" * 30)\n            print(f\"\ud83c\udf89 \u670d\u52a1\u542f\u52a8\u5b8c\u6210: {len(threads)} \u4e2a\u670d\u52a1\u6b63\u5728\u540e\u53f0\u8fd0\u884c\")\n            print(\"=\" * 50)\n            '''\n            \u663e\u793a\u8ba1\u5212\uff1a\u5148\u544a\u8bc9\u7528\u6237\u54ea\u4e9b\u670d\u52a1\u8981\u542f\u52a8\n            \u6279\u91cf\u542f\u52a8\uff1a\u5faa\u73af\u542f\u52a8\u6240\u6709\u7ebf\u7a0b\n            \u663e\u793a\u7ed3\u679c\uff1a\u544a\u8bc9\u7528\u6237\u542f\u52a8\u4e86\u591a\u5c11\u4e2a\u670d\u52a1\n            '''\n            \n        except Exception as e:\n            print(f\"\u274c \u5e76\u884c\u542f\u52a8\u670d\u52a1\u5f02\u5e38: {e}\")\n\n    def _init_proxy_settings(self):\n        \"\"\"\u521d\u59cb\u5316\u4ee3\u7406\u8bbe\u7f6e\uff1a\u82e5\u4e0d\u542f\u7528\u4ee3\u7406\uff0c\u5219\u6e05\u7a7a\u7cfb\u7edf\u4ee3\u7406\u73af\u5883\u53d8\u91cf\"\"\"\n        # \u68c0\u6d4b applied_proxy \u72b6\u6001\n        if not config.api.applied_proxy:  # \u5f53 applied_proxy \u4e3a False \u65f6\n            print(\"\u68c0\u6d4b\u5230\u4e0d\u542f\u7528\u4ee3\u7406\uff0c\u6b63\u5728\u6e05\u7a7a\u7cfb\u7edf\u4ee3\u7406\u73af\u5883\u53d8\u91cf...\")\n\n            # \u6e05\u7a7a HTTP\/HTTPS \u4ee3\u7406\u73af\u5883\u53d8\u91cf\uff08\u8de8\u5e73\u53f0\u517c\u5bb9\uff09\n            proxy_vars = &#91;\"HTTP_PROXY\", \"HTTPS_PROXY\", \"http_proxy\", \"https_proxy\"]\n            for var in proxy_vars:\n                if var in os.environ:  #os.environ\uff1a\u64cd\u4f5c\u7cfb\u7edf\u7684\u73af\u5883\u53d8\u91cf\n                    #if var in os.environ\uff1a\u68c0\u67e5\u53d8\u91cf\u662f\u5426\u5b58\u5728\n                    del os.environ&#91;var]  # \u5220\u9664\u73af\u5883\u53d8\u91cf\n                    # del os.environ&#91;var]\uff1a\u5220\u9664\u8fd9\u4e2a\u73af\u5883\u53d8\u91cf\n                    print(f\"\u5df2\u6e05\u9664\u4ee3\u7406\u73af\u5883\u53d8\u91cf: {var}\")\n\n            # \u989d\u5916\uff1a\u786e\u4fdd requests Session \u6ca1\u6709\u5168\u5c40\u4ee3\u7406\u914d\u7f6e\n            global_session = requests.Session()\n           #requests.Session()\uff1a\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u4f1a\u8bdd\n            if global_session.proxies:\n                global_session.proxies.clear() # \u6e05\u9664\u4f1a\u8bdd\u4e2d\u7684\u6240\u6709\u4ee3\u7406\u8bbe\u7f6e\n                print(\"\u5df2\u6e05\u7a7a requests Session \u5168\u5c40\u4ee3\u7406\u914d\u7f6e\")\n\n    # \u5404\u4e2a\u670d\u52a1\u5668\u7684\u542f\u52a8\u65b9\u6cd5\n    # \u8fd9\u4e9b\u65b9\u6cd5\u7684\u7ed3\u6784\u90fd\u5f88\u76f8\u4f3c\uff0c\u6211\u4eec\u770b\u4e00\u4e2a\u4f8b\u5b50\uff1a\n    '''\n    \u90fd\u4f7f\u7528try...except\u8fdb\u884c\u9519\u8bef\u5904\u7406\n    \u90fd\u4f7f\u7528uvicorn.run()\u542f\u52a8\u670d\u52a1\u5668\n    \u53c2\u6570\u90fd\u7c7b\u4f3c\uff1a\n      host\uff1a\u76d1\u542c\u7684\u4e3b\u673a\u5730\u5740\n      port\uff1a\u76d1\u542c\u7684\u7aef\u53e3\n      log_level=\"error\"\uff1a\u53ea\u8bb0\u5f55\u9519\u8bef\u65e5\u5fd7\n      access_log=False\uff1a\u4e0d\u8bb0\u5f55\u8bbf\u95ee\u65e5\u5fd7\n      reload=False\uff1a\u4e0d\u81ea\u52a8\u91cd\u8f7d\n    '''\n    def _start_api_server(self):\n        \"\"\"\u5185\u90e8API\u670d\u52a1\u5668\u542f\u52a8\u65b9\u6cd5\"\"\"\n        try:\n            from nagaagent_core.api import uvicorn\n\n            uvicorn.run(\n                \"apiserver.api_server:app\",\n                host=config.api_server.host,\n                port=config.api_server.port,\n                log_level=\"error\",\n                access_log=False,\n                reload=False,\n                ws_ping_interval=None,  # \u7981\u7528WebSocket ping\n                ws_ping_timeout=None    # \u7981\u7528WebSocket ping\u8d85\u65f6\n            )\n        except ImportError as e:\n            print(f\"   \u274c API\u670d\u52a1\u5668\u4f9d\u8d56\u7f3a\u5931: {e}\")\n        except Exception as e:\n            print(f\"   \u274c API\u670d\u52a1\u5668\u542f\u52a8\u5931\u8d25: {e}\")\n\n    def _start_mcp_server(self):\n        \"\"\"\u5185\u90e8MCP\u670d\u52a1\u5668\u542f\u52a8\u65b9\u6cd5\"\"\"\n        try:\n            import uvicorn\n            from mcpserver.mcp_server import app\n            from system.config import get_server_port\n            \n            uvicorn.run(\n                app,\n                host=\"0.0.0.0\",\n                port=get_server_port(\"mcp_server\"),\n                log_level=\"error\",\n                access_log=False,\n                reload=False,\n                ws_ping_interval=None,  # \u7981\u7528WebSocket ping\n                ws_ping_timeout=None    # \u7981\u7528WebSocket ping\u8d85\u65f6\n            )\n        except Exception as e:\n            print(f\"   \u274c MCP\u670d\u52a1\u5668\u542f\u52a8\u5931\u8d25: {e}\")\n    \n    def _start_agent_server(self):\n        \"\"\"\u5185\u90e8Agent\u670d\u52a1\u5668\u542f\u52a8\u65b9\u6cd5\"\"\"\n        try:\n            import uvicorn\n            from agentserver.agent_server import app\n            from system.config import get_server_port\n            \n            uvicorn.run(\n                app,\n                host=\"0.0.0.0\",\n                port=get_server_port(\"agent_server\"),\n                log_level=\"error\",\n                access_log=False,\n                reload=False,\n                ws_ping_interval=None,  # \u7981\u7528WebSocket ping\n                ws_ping_timeout=None    # \u7981\u7528WebSocket ping\u8d85\u65f6\n            )\n        except Exception as e:\n            print(f\"   \u274c Agent\u670d\u52a1\u5668\u542f\u52a8\u5931\u8d25: {e}\")\n    \n    def _start_tts_server(self):\n        \"\"\"\u5185\u90e8TTS\u670d\u52a1\u5668\u542f\u52a8\u65b9\u6cd5\"\"\"\n        try:\n            from voice.output.start_voice_service import start_http_server\n            start_http_server()\n        except Exception as e:\n            print(f\"   \u274c TTS\u670d\u52a1\u5668\u542f\u52a8\u5931\u8d25: {e}\")\n    # NagaPortal\u81ea\u52a8\u767b\u5f55\u76f8\u5173\u65b9\u6cd5\n    def _start_naga_portal_auto_login(self):\n        \"\"\"\u542f\u52a8NagaPortal\u81ea\u52a8\u767b\u5f55\uff08\u5f02\u6b65\uff09\"\"\"\n        try:\n            # \u68c0\u67e5\u662f\u5426\u914d\u7f6e\u4e86NagaPortal,\u5982\u679c\u7528\u6237\u540d\u6216\u5bc6\u7801\u6ca1\u6709\u914d\u7f6e \u2192 \u76f4\u63a5\u8fd4\u56de\uff08\u4e0d\u6267\u884c\u540e\u9762\u7684\u4ee3\u7801\uff09\n            if not config.naga_portal.username or not config.naga_portal.password:\n                return  # \u9759\u9ed8\u8df3\u8fc7\uff0c\u4e0d\u8f93\u51fa\u65e5\u5fd7\n            \n            # \u5728\u65b0\u7ebf\u7a0b\u4e2d\u5f02\u6b65\u6267\u884c\u767b\u5f55\n            def run_auto_login():\n                try:\n                    import sys\n                    import os\n                    # \u6dfb\u52a0\u9879\u76ee\u6839\u76ee\u5f55\u5230Python\u8def\u5f84\n                    project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\n                    sys.path.insert(0, project_root)\n                    \n                    from mcpserver.agent_naga_portal.portal_login_manager import auto_login_naga_portal\n                    \n                    # \u521b\u5efa\u65b0\u7684\u4e8b\u4ef6\u5faa\u73af\n                    import asyncio\n                    loop = asyncio.new_event_loop()\n                    asyncio.set_event_loop(loop)\n                    # result = loop.run_until_complete(auto_login_naga_portal())\n                    '''\u4e8b\u4ef6\u5faa\u73af\u7684\u521b\u5efa\u548c\u4f7f\u7528\uff1a\n                    \u521b\u5efa\u65b0\u7684\u4e8b\u4ef6\u5faa\u73af\uff1a\u6bcf\u4e2a\u7ebf\u7a0b\u9700\u8981\u81ea\u5df1\u7684\u4e8b\u4ef6\u5faa\u73af\n                    \u8bbe\u7f6e\u4e8b\u4ef6\u5faa\u73af\uff1a\u544a\u8bc9asyncio\u4f7f\u7528\u8fd9\u4e2a\u65b0\u7684\u4e8b\u4ef6\u5faa\u73af\n                    \u8fd0\u884c\u5f02\u6b65\u51fd\u6570\uff1a\u7b49\u5f85\u81ea\u52a8\u767b\u5f55\u5b8c\u6210\n                    '''\n                    try:\n                        # \u6267\u884c\u81ea\u52a8\u767b\u5f55\n                        result = loop.run_until_complete(auto_login_naga_portal())\n                        \n                        if result&#91;'success']:\n                            # \u767b\u5f55\u6210\u529f\uff0c\u663e\u793a\u72b6\u6001\n                            print(\"\u2705 NagaPortal\u81ea\u52a8\u767b\u5f55\u6210\u529f\")\n                            self._show_naga_portal_status()\n                        else:\n                            # \u767b\u5f55\u5931\u8d25\uff0c\u663e\u793a\u9519\u8bef\n                            error_msg = result.get('message', '\u672a\u77e5\u9519\u8bef')\n                            print(f\"\u274c NagaPortal\u81ea\u52a8\u767b\u5f55\u5931\u8d25: {error_msg}\")\n                            self._show_naga_portal_status()\n                    finally:\n                        loop.close()\n                        \n                except Exception as e:\n                    # \u767b\u5f55\u5f02\u5e38\uff0c\u663e\u793a\u9519\u8bef\n                    print(f\"\u274c NagaPortal\u81ea\u52a8\u767b\u5f55\u5f02\u5e38: {e}\")\n                    self._show_naga_portal_status()\n            '''\u5d4c\u5957\u51fd\u6570\uff1a\n            run_auto_login\uff1a\u5728\u65b9\u6cd5\u5185\u90e8\u5b9a\u4e49\u7684\u51fd\u6570\uff0c\u53ea\u5728\u5f53\u524d\u65b9\u6cd5\u4e2d\u4f7f\u7528\n            \u4e3a\u4ec0\u4e48\u8fd9\u6837\u8bbe\u8ba1\uff1a\u8ba9\u767b\u5f55\u903b\u8f91\u5728\u4e00\u4e2a\u72ec\u7acb\u7684\u7ebf\u7a0b\u4e2d\u8fd0\u884c\uff0c\u4e0d\u963b\u585e\u4e3b\u7a0b\u5e8f\n            '''\n\n            # \u542f\u52a8\u540e\u53f0\u7ebf\u7a0b\n            import threading\n            login_thread = threading.Thread(target=run_auto_login, daemon=True)\n            login_thread.start()\n            \n        except Exception as e:\n            # \u542f\u52a8\u5f02\u5e38\uff0c\u663e\u793a\u9519\u8bef\n            print(f\"\u274c NagaPortal\u81ea\u52a8\u767b\u5f55\u542f\u52a8\u5931\u8d25: {e}\")\n            self._show_naga_portal_status()\n\n    def _show_naga_portal_status(self):\n        \"\"\"\u663e\u793aNagaPortal\u72b6\u6001\uff08\u767b\u5f55\u5b8c\u6210\u540e\u8c03\u7528\uff09\"\"\"\n        try:\n            from mcpserver.agent_naga_portal.portal_login_manager import get_portal_login_manager\n            login_manager = get_portal_login_manager()\n            status = login_manager.get_status()\n            cookies = login_manager.get_cookies()\n            #\u4ece\u767b\u5f55\u7ba1\u7406\u5668\u83b7\u53d6\u72b6\u6001\u548ccookie\u4fe1\u606f\n\n            print(f\"\ud83c\udf10 NagaPortal\u72b6\u6001:\")\n            print(f\"   \u5730\u5740: {config.naga_portal.portal_url}\")\n            print(f\"   \u7528\u6237: {config.naga_portal.username&#91;:3]}***{config.naga_portal.username&#91;-3:] if len(config.naga_portal.username) &gt; 6 else '***'}\")\n            #\u5b89\u5168\u663e\u793a\u7528\u6237\u540d\uff1ausername&#91;:3]\uff1a\u663e\u793a\u524d3\u4e2a\u5b57\u7b26,username&#91;-3:]\uff1a\u663e\u793a\u6700\u540e3\u4e2a\u5b57\u7b26,***\uff1a\u4e2d\u95f4\u7528\u661f\u53f7\u4ee3\u66ff,\u76ee\u7684\uff1a\u4fdd\u62a4\u7528\u6237\u9690\u79c1\uff0c\u4e0d\u5b8c\u5168\u663e\u793a\u7528\u6237\u540d\n\n            if cookies:\n                print(f\"\ud83c\udf6a Cookie\u4fe1\u606f ({len(cookies)}\u4e2a):\")\n                for name, value in cookies.items():\n                    print(f\"   {name}: {value}\")\n            else:\n                print(f\"\ud83c\udf6a Cookie: \u672a\u83b7\u53d6\u5230\")\n            \n            user_id = status.get('user_id')\n            if user_id:\n                print(f\"\ud83d\udc64 \u7528\u6237ID: {user_id}\")\n            else:\n                print(f\"\ud83d\udc64 \u7528\u6237ID: \u672a\u83b7\u53d6\u5230\")\n                \n            # \u663e\u793a\u767b\u5f55\u72b6\u6001\n            if status.get('is_logged_in'):\n                print(f\"\u2705 \u767b\u5f55\u72b6\u6001: \u5df2\u767b\u5f55\")\n            else:\n                print(f\"\u274c \u767b\u5f55\u72b6\u6001: \u672a\u767b\u5f55\")\n                if status.get('login_error'):\n                    print(f\"   \u9519\u8bef: {status.get('login_error')}\")\n                    \n        except Exception as e:\n            print(f\"\ud83c\udf6a NagaPortal\u72b6\u6001\u83b7\u53d6\u5931\u8d25: {e}\")\n    \n    def _start_mqtt_status_check(self):\n        \"\"\"\u542f\u52a8\u7269\u8054\u7f51\u901a\u8baf\u8fde\u63a5\u5e76\u663e\u793a\u72b6\u6001\uff08\u5f02\u6b65\uff09\"\"\"\n        try:\n            # \u68c0\u67e5\u662f\u5426\u914d\u7f6e\u4e86\u7269\u8054\u7f51\u901a\u8baf\n            if not config.mqtt.enabled:\n                return  # \u9759\u9ed8\u8df3\u8fc7\uff0c\u4e0d\u8f93\u51fa\u65e5\u5fd7\n            \n            # \u5728\u65b0\u7ebf\u7a0b\u4e2d\u5f02\u6b65\u6267\u884c\u7269\u8054\u7f51\u901a\u8baf\u8fde\u63a5\n            def run_mqtt_connection():\n                try:\n                    import sys\n                    import os\n                    import time\n                    # \u6dfb\u52a0\u9879\u76ee\u6839\u76ee\u5f55\u5230Python\u8def\u5f84\n                    project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\n                    sys.path.insert(0, project_root)\n                    \n                    try:\n                        from mqtt_tool.device_switch import device_manager\n                        \n                        # \u5c1d\u8bd5\u8fde\u63a5\u7269\u8054\u7f51\u8bbe\u5907\n                        if hasattr(device_manager, 'connect'):\n                            success = device_manager.connect()\n                            if success:\n                                print(\"\ud83d\udd17 \u7269\u8054\u7f51\u901a\u8baf\u72b6\u6001: \u5df2\u8fde\u63a5\")\n                            else:\n                                print(\"\u26a0\ufe0f \u7269\u8054\u7f51\u901a\u8baf\u72b6\u6001: \u8fde\u63a5\u5931\u8d25\uff08\u5c06\u5728\u4f7f\u7528\u65f6\u91cd\u8bd5\uff09\")\n                        else:\n                            print(\"\u274c \u7269\u8054\u7f51\u901a\u8baf\u529f\u80fd\u4e0d\u53ef\u7528\")\n                            \n                    except Exception as e:\n                        print(f\"\u26a0\ufe0f \u7269\u8054\u7f51\u901a\u8baf\u8fde\u63a5\u5931\u8d25: {e}\")\n                        \n                except Exception as e:\n                    print(f\"\u274c \u7269\u8054\u7f51\u901a\u8baf\u8fde\u63a5\u5f02\u5e38: {e}\")\n            \n            # \u542f\u52a8\u540e\u53f0\u7ebf\u7a0b\n            import threading\n            mqtt_thread = threading.Thread(target=run_mqtt_connection, daemon=True)\n            mqtt_thread.start()\n            \n        except Exception as e:\n            print(f\"\u274c \u7269\u8054\u7f51\u901a\u8baf\u8fde\u63a5\u542f\u52a8\u5931\u8d25: {e}\")\n    \n    \n    def _init_voice_system(self):\n        \"\"\"\u521d\u59cb\u5316\u8bed\u97f3\u5904\u7406\u7cfb\u7edf\"\"\"\n        try:\n            if config.system.voice_enabled:\n                logger.info(\"\u8bed\u97f3\u529f\u80fd\u5df2\u542f\u7528\uff08\u8bed\u97f3\u8f93\u5165+\u8f93\u51fa\uff09\uff0c\u7531UI\u5c42\u7ba1\u7406\")\n            else:\n                logger.info(\"\u8bed\u97f3\u529f\u80fd\u5df2\u7981\u7528\")\n        except Exception as e:\n            logger.warning(f\"\u8bed\u97f3\u7cfb\u7edf\u521d\u59cb\u5316\u5931\u8d25: {e}\")\n    \n    def _init_memory_system(self):\n        \"\"\"\u521d\u59cb\u5316\u8bb0\u5fc6\u7cfb\u7edf\"\"\"\n        try:\n            if memory_manager and memory_manager.enabled:\n                logger.info(\"\u590f\u56ed\u8bb0\u5fc6\u7cfb\u7edf\u5df2\u521d\u59cb\u5316\")\n            else:\n                logger.info(\"\u590f\u56ed\u8bb0\u5fc6\u7cfb\u7edf\u5df2\u7981\u7528\")\n        except Exception as e:\n            logger.warning(f\"\u8bb0\u5fc6\u7cfb\u7edf\u521d\u59cb\u5316\u5931\u8d25: {e}\")\n    \n    def _init_mcp_services(self):\n        \"\"\"\u521d\u59cb\u5316MCP\u670d\u52a1\u7cfb\u7edf\"\"\"\n        try:\n            # MCP\u670d\u52a1\u73b0\u5728\u7531mcpserver\u72ec\u7acb\u7ba1\u7406\uff0c\u8fd9\u91cc\u53ea\u9700\u8981\u8bb0\u5f55\u65e5\u5fd7\n            logger.info(\"MCP\u670d\u52a1\u7cfb\u7edf\u7531mcpserver\u72ec\u7acb\u7ba1\u7406\")\n        except Exception as e:\n            logger.error(f\"MCP\u670d\u52a1\u7cfb\u7edf\u521d\u59cb\u5316\u5931\u8d25: {e}\")\n    \n    \n    def show_naga_portal_status(self):\n        \"\"\"\u663e\u793aNagaPortal\u914d\u7f6e\u72b6\u6001\uff08\u624b\u52a8\u8c03\u7528\uff09\"\"\"\n        try:\n            if config.naga_portal.username and config.naga_portal.password:\n                print(f\"\ud83c\udf10 NagaPortal: \u5df2\u914d\u7f6e\u8d26\u6237\u4fe1\u606f\")\n                print(f\"   \u5730\u5740: {config.naga_portal.portal_url}\")\n                print(f\"   \u7528\u6237: {config.naga_portal.username&#91;:3]}***{config.naga_portal.username&#91;-3:] if len(config.naga_portal.username) &gt; 6 else '***'}\")\n                \n                # \u83b7\u53d6\u5e76\u663e\u793aCookie\u4fe1\u606f\n                try:\n                    from mcpserver.agent_naga_portal.portal_login_manager import get_portal_login_manager\n                    login_manager = get_portal_login_manager()\n                    status = login_manager.get_status()\n                    cookies = login_manager.get_cookies()\n                    \n                    if cookies:\n                        print(f\"\ud83c\udf6a Cookie\u4fe1\u606f ({len(cookies)}\u4e2a):\")\n                        for name, value in cookies.items():\n                            # \u663e\u793a\u5b8c\u6574\u7684cookie\u540d\u79f0\u548c\u503c\n                            print(f\"   {name}: {value}\")\n                    else:\n                        print(f\"\ud83c\udf6a Cookie: \u672a\u83b7\u53d6\u5230\")\n                    \n                    user_id = status.get('user_id')\n                    if user_id:\n                        print(f\"\ud83d\udc64 \u7528\u6237ID: {user_id}\")\n                    else:\n                        print(f\"\ud83d\udc64 \u7528\u6237ID: \u672a\u83b7\u53d6\u5230\")\n                        \n                    # \u663e\u793a\u767b\u5f55\u72b6\u6001\n                    if status.get('is_logged_in'):\n                        print(f\"\u2705 \u767b\u5f55\u72b6\u6001: \u5df2\u767b\u5f55\")\n                    else:\n                        print(f\"\u274c \u767b\u5f55\u72b6\u6001: \u672a\u767b\u5f55\")\n                        if status.get('login_error'):\n                            print(f\"   \u9519\u8bef: {status.get('login_error')}\")\n                        \n                except Exception as e:\n                    print(f\"\ud83c\udf6a \u72b6\u6001\u83b7\u53d6\u5931\u8d25: {e}\")\n            else:\n                print(f\"\ud83c\udf10 NagaPortal: \u672a\u914d\u7f6e\u8d26\u6237\u4fe1\u606f\")\n                print(f\"   \u5982\u9700\u4f7f\u7528NagaPortal\u529f\u80fd\uff0c\u8bf7\u5728config.json\u4e2d\u914d\u7f6enaga_portal.username\u548cpassword\")\n        except Exception as e:\n            print(f\"\ud83c\udf10 NagaPortal: \u914d\u7f6e\u68c0\u67e5\u5931\u8d25 - {e}\")\n\n# \u5de5\u5177\u51fd\u6570\n#\u8fd9\u90e8\u5206\u5b9a\u4e49\u4e86\u4e09\u4e2a\u7b80\u5355\u4f46\u6709\u7528\u7684\u5c0f\u5de5\u5177\uff1a\n'''\u90fd\u5f88\u7b80\u5355\uff0c\u53ea\u6709\u4e00\u884c\u4ee3\u7801\n\u90fd\u662f\u7ed9\u7528\u6237\u63d0\u4f9b\u4fbf\u5229\u7684\u5de5\u5177,\u4e0d\u6d89\u53ca\u590d\u6742\u7684\u903b\u8f91\n'''\ndef show_help():\n    print('\u7cfb\u7edf\u547d\u4ee4: \u6e05\u5c4f, \u67e5\u770b\u7d22\u5f15, \u5e2e\u52a9, \u9000\u51fa')\n\ndef show_index():\n    print('\u4e3b\u9898\u5206\u7247\u7d22\u5f15\u5df2\u96c6\u6210\uff0c\u65e0\u9700\u5355\u72ec\u7d22\u5f15\u67e5\u770b')\n\ndef clear():  # \u6e05\u9664\u5c4f\u5e55\u4e0a\u7684\u5185\u5bb9\n    os.system('cls' if os.name == 'nt' else 'clear')\n'''\u5de5\u4f5c\u539f\u7406\uff1a\n os.name == 'nt'\uff1a\u68c0\u67e5\u5f53\u524d\u64cd\u4f5c\u7cfb\u7edf\u662f\u4e0d\u662fWindows\uff08'nt'\u8868\u793aWindows\uff09\n 'cls' if ... else 'clear'\uff1a\n    \u5982\u679c\u662fWindows \u2192 \u4f7f\u7528cls\u547d\u4ee4\n    \u5982\u679c\u662fLinux\/macOS \u2192 \u4f7f\u7528clear\u547d\u4ee4\n os.system()\uff1a\u6267\u884c\u7cfb\u7edf\u547d\u4ee4\n'''\n\n# \u5ef6\u8fdf\u521d\u59cb\u5316 - \u907f\u514d\u542f\u52a8\u65f6\u963b\u585e,\u8fd9\u662f\u4e00\u4e2a\u975e\u5e38\u91cd\u8981\u7684\u51fd\u6570\ndef _lazy_init_services():\n    #\u4e0b\u5212\u7ebf\u5f00\u5934\uff1a\u8868\u793a\u8fd9\u662f\u5185\u90e8\u51fd\u6570\uff0c\u5176\u4ed6\u4ee3\u7801\u4e0d\u5e94\u8be5\u76f4\u63a5\u8c03\u7528\n    #lazy\uff1a\u8868\u793a\"\u61d2\u60f0\u7684\"\uff0c\u610f\u601d\u662f\"\u7b49\u5230\u9700\u8981\u7684\u65f6\u5019\u518d\u505a\"\n    \"\"\"\u5ef6\u8fdf\u521d\u59cb\u5316\u670d\u52a1 - \u5728\u9700\u8981\u65f6\u624d\u521d\u59cb\u5316\"\"\"\n    global service_manager, n\n    '''global\u5173\u952e\u5b57\uff1a\n           global service_manager\uff1a\u544a\u8bc9Python\uff0c\u6211\u4eec\u8981\u4fee\u6539\u5168\u5c40\u53d8\u91cfservice_manager\n           global n\uff1a\u544a\u8bc9Python\uff0c\u6211\u4eec\u8981\u4fee\u6539\u5168\u5c40\u53d8\u91cfn\n           \u4e3a\u4ec0\u4e48\u9700\u8981global\uff1a\u5728\u51fd\u6570\u5185\u90e8\u4fee\u6539\u5168\u5c40\u53d8\u91cf\u65f6\u9700\u8981\u4f7f\u7528\n    '''\n    if not hasattr(_lazy_init_services, '_initialized'):\n        '''\u68c0\u67e5\u662f\u5426\u5df2\u521d\u59cb\u5316\n               hasattr(_lazy_init_services, '_initialized')\uff1a\u68c0\u67e5\u51fd\u6570\u672c\u8eab\u6709\u6ca1\u6709_initialized\u5c5e\u6027\n               \u8fd9\u662f\u4e00\u79cd\u6280\u5de7\uff1a\u5229\u7528\u51fd\u6570\u672c\u8eab\u7684\u5c5e\u6027\u6765\u8bb0\u5f55\u72b6\u6001\n               \u903b\u8f91\uff1a\u5982\u679c\u6ca1\u6709\u521d\u59cb\u5316\u8fc7\uff08_initialized\u5c5e\u6027\u4e0d\u5b58\u5728\uff09\uff0c\u5c31\u6267\u884c\u521d\u59cb\u5316\n        '''\n        # \u521d\u59cb\u5316\u670d\u52a1\u7ba1\u7406\u5668\n        service_manager = ServiceManager()  #\u521b\u5efaServiceManager\u5bf9\u8c61\n        service_manager.start_background_services()\n        # service_manager.start_background_services()\uff1a\u8c03\u7528\u5bf9\u8c61\u7684start_background_services\u65b9\u6cd5\n\n        # conversation_core\u5df2\u5220\u9664\uff0c\u76f8\u5173\u529f\u80fd\u5df2\u8fc1\u79fb\u5230apiserver\n        n = None #n = None\uff1a\u628a\u5168\u5c40\u53d8\u91cfn\u8bbe\u4e3aNone\uff08\u7a7a\uff09\n        \n        # \u521d\u59cb\u5316\u5404\u4e2a\u7cfb\u7edf\uff08conversation_core\u5df2\u5220\u9664\uff0c\u76f4\u63a5\u521d\u59cb\u5316\u670d\u52a1\uff09\n        #\u8c03\u7528\u4e86ServiceManager\u5bf9\u8c61\u7684\u4e09\u4e2a\u521d\u59cb\u5316\u65b9\u6cd5\uff1a\n        service_manager._init_mcp_services() #\u521d\u59cb\u5316MCP\u670d\u52a1\n        service_manager._init_voice_system()  #\u521d\u59cb\u5316\u8bed\u97f3\u7cfb\u7edf\n        service_manager._init_memory_system()   # \u521d\u59cb\u5316\u8bb0\u5fc6\u7cfb\u7edf\n        # service_manager._load_persistent_context()  # \u5220\u9664\u91cd\u590d\u52a0\u8f7d\uff0cUI\u6e32\u67d3\u65f6\u4f1a\u81ea\u52a8\u52a0\u8f7d\n        \n        # \u521d\u59cb\u5316\u8fdb\u5ea6\u6587\u4ef6\n        #with open('.\/ui\/styles\/progress.txt', 'w') as f:\n            #f.write('0')\n        #\u4f55\u610f\u5473\uff1f\u6ce8\u91ca\u4e86 by Null\n        #\u539f\u672c\u7684\u4f5c\u7528\uff1a\u521b\u5efa\u4e00\u4e2a\u8fdb\u5ea6\u6587\u4ef6\uff0c\u5199\u5165\u521d\u59cb\u503c0\n        \n        # \u663e\u793a\u7cfb\u7edf\u72b6\u6001\uff0c\u8fd9\u6bb5\u4ee3\u7801\u6253\u5370\u4e86\u4e00\u4e9b\u91cd\u8981\u7684\u7cfb\u7edf\u72b6\u6001\u4fe1\u606f\uff1a\n        print(\"=\" * 30)  #\u5206\u9694\u7ebf\uff1a\u6253\u537030\u4e2a\u7b49\u53f7\uff0c\u7528\u4f5c\u89c6\u89c9\u5206\u9694\n        print(f\"GRAG\u72b6\u6001: {'\u542f\u7528' if memory_manager.enabled else '\u7981\u7528'}\")\n        '''\n        \u6761\u4ef6\u8868\u8fbe\u5f0f\n           '\u542f\u7528' if memory_manager.enabled else '\u7981\u7528'\n            \u5982\u679cmemory_manager.enabled\u4e3aTrue \u2192 \u663e\u793a\"\u542f\u7528\"\n            \u5426\u5219 \u2192 \u663e\u793a\"\u7981\u7528\"\n        \u5426\u5219 \u2192 \u663e\u793a\"\u7981\u7528\"\n        '''\n        if memory_manager.enabled:  #\u6761\u4ef6\u5224\u65ad\uff1a\u53ea\u6709\u8bb0\u5fc6\u7cfb\u7edf\u542f\u7528\u65f6\u624d\u6267\u884c\n            stats = memory_manager.get_memory_stats()   #\u83b7\u53d6\u7edf\u8ba1\u4fe1\u606f\uff1amemory_manager.get_memory_stats()\n            from summer_memory.quintuple_graph import graph, GRAG_ENABLED\n            print(f\"Neo4j\u8fde\u63a5: {'\u6210\u529f' if graph and GRAG_ENABLED else '\u5931\u8d25'}\")\n            #\u4ecesummer_memory.quintuple_graph\u5bfc\u5165graph\u548cGRAG_ENABLED\n            #\u68c0\u67e5Neo4j\u56fe\u6570\u636e\u5e93\u662f\u5426\u8fde\u63a5\u6210\u529f\n        print(\"=\" * 30)\n        print(f'{AI_NAME}\u7cfb\u7edf\u5df2\u542f\u52a8')  #\u663e\u793aAI\u540d\u79f0\uff1a\u4f7f\u7528\u4e4b\u524d\u5bfc\u5165\u7684AI_NAME\u53d8\u91cf\n        print(\"=\" * 30)\n        \n        # \u542f\u52a8\u670d\u52a1\uff08\u5e76\u884c\u5f02\u6b65\uff09\n        service_manager.start_all_servers()\n        '''\u542f\u52a8\u6240\u6709\u670d\u52a1\n        \u8c03\u7528service_manager.start_all_servers()\u65b9\u6cd5\n        \u6ce8\u91ca\u8bf4\u660e\uff1a\u5e76\u884c\u5f02\u6b65\u542f\u52a8\n        '''\n        \n        # \u542f\u52a8NagaPortal\u81ea\u52a8\u767b\u5f55\n        service_manager._start_naga_portal_auto_login()   #\u8c03\u7528_start_naga_portal_auto_login()\u65b9\u6cd5\n        print(\"\u23f3 NagaPortal\u6b63\u5728\u540e\u53f0\u81ea\u52a8\u767b\u5f55...\")   #   \u6253\u5370\u63d0\u793a\u4fe1\u606f\uff1a\u23f3 NagaPortal\u6b63\u5728\u540e\u53f0\u81ea\u52a8\u767b\u5f55...\n        \n        # \u542f\u52a8\u7269\u8054\u7f51\u901a\u8baf\u8fde\u63a5\n        service_manager._start_mqtt_status_check()  #   \u8c03\u7528_start_mqtt_status_check()\u65b9\u6cd5\n        print(\"\u23f3 \u7269\u8054\u7f51\u901a\u8baf\u6b63\u5728\u540e\u53f0\u521d\u59cb\u5316\u8fde\u63a5...\")\n        \n        show_help()  #\u8c03\u7528\u4e4b\u524d\u5b9a\u4e49\u7684show_help()\u51fd\u6570\n        \n        _lazy_init_services._initialized = True\n        '''\u8bbe\u7f6e\u521d\u59cb\u5316\u6807\u8bb0\n        \u7ed9\u51fd\u6570\u672c\u8eab\u6dfb\u52a0_initialized\u5c5e\u6027\uff0c\u5e76\u8bbe\u4e3aTrue\n        \u4f5c\u7528\uff1a\u4e0b\u6b21\u8c03\u7528\u8fd9\u4e2a\u51fd\u6570\u65f6\uff0chasattr(_lazy_init_services, '_initialized')\u4f1a\u8fd4\u56deTrue\n        \u7ed3\u679c\uff1a\u4e0d\u4f1a\u91cd\u590d\u521d\u59cb\u5316\uff0c\u53ea\u521d\u59cb\u5316\u4e00\u6b21\n        '''\n\n# NagaAgent\u9002\u914d\u5668 - \u4f18\u5316\u91cd\u590d\u521d\u59cb\u5316\n# \u7c7b\u5b9a\u4e49,\u4f5c\u4e3a\u9002\u914d\u5668\uff0c\u5c01\u88c5\u4e86\u5bf9naga\u5bf9\u8c61\u7684\u8bbf\u95ee,\u786e\u4fdd\u5728\u4f7f\u7528\u524d\u670d\u52a1\u5df2\u7ecf\u521d\u59cb\u5316\nclass NagaAgentAdapter:\n    def __init__(s): #\u521d\u59cb\u5316\u65b9\u6cd5,\u53c2\u6570\uff1as\uff08\u5b9e\u9645\u4e0a\u662fself\uff0c\u53ea\u662f\u7528\u4e86\u4e0d\u540c\u7684\u540d\u5b57\uff09\n        # \u4f7f\u7528\u5168\u5c40\u5b9e\u4f8b\uff0c\u907f\u514d\u91cd\u590d\u521d\u59cb\u5316\n        _lazy_init_services()  #\u8c03\u7528_lazy_init_services(),\u786e\u4fdd\u670d\u52a1\u5df2\u521d\u59cb\u5316\n        s.naga = n  # \u4f7f\u7528\u5168\u5c40\u5b9e\u4f8b,\u628a\u5168\u5c40\u53d8\u91cfn\u8d4b\u503c\u7ed9s.naga\n\n   #respond_stream\u65b9\u6cd5,\u8fd9\u662f\u4e00\u4e2a\u5f02\u6b65\u751f\u6210\u5668\u65b9\u6cd5\n    #async def\uff1a\u5b9a\u4e49\u5f02\u6b65\u65b9\u6cd5\n    async def respond_stream(s, txt): #s\uff1a\u5bf9\u8c61\u81ea\u8eab\uff08\u76f8\u5f53\u4e8eself\uff09,txt\uff1a\u8f93\u5165\u7684\u6587\u672c\n        #\u5f02\u6b65\u8fed\u4ee3\uff1aasync for\u7528\u4e8e\u8fed\u4ee3\u5f02\u6b65\u751f\u6210\u5668\n        async for resp in s.naga.process(txt):  #s.naga.process(txt)\uff1a\u8c03\u7528naga\u5bf9\u8c61\u7684process\u65b9\u6cd5\u5904\u7406\u6587\u672c\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u8fd4\u56de\u4e00\u4e2a\u5f02\u6b65\u751f\u6210\u5668\uff0c\u6bcf\u6b21\u4ea7\u751f\u4e00\u4e2a\u54cd\u5e94\n            yield AI_NAME, resp, None, True, False #yield\uff1a\u4ea7\u751f\u4e00\u4e2a\u503c\uff0c\u4f46\u4e0d\u7ed3\u675f\u51fd\u6570\uff08\u751f\u6210\u5668\u7279\u6027\uff09\n            '''\u8fd4\u56de\u7684\u5143\u7ec4\uff1a\u5305\u542b5\u4e2a\u503c\uff1a\n            AI_NAME\uff1aAI\u7684\u540d\u5b57,resp\uff1a\u5904\u7406\u540e\u7684\u54cd\u5e94,None\uff1a\u7a7a\u503c\n            True\uff1a\u5e03\u5c14\u503c\u771f.False\uff1a\u5e03\u5c14\u503c\u5047\n            '''\n\n# \u4e3b\u7a0b\u5e8f\u5165\u53e3\nif __name__ == \"__main__\":\n    '''\n    __name__ \u662f\u4e00\u4e2a\u7279\u6b8a\u7684Python\u53d8\u91cf\n    \u5f53\u4e00\u4e2aPython\u6587\u4ef6\u88ab\u76f4\u63a5\u8fd0\u884c\u65f6\uff0c__name__ \u7684\u503c\u662f \"__main__\"\n    \u5f53\u4e00\u4e2aPython\u6587\u4ef6\u88ab\u5bfc\u5165\u4e3a\u6a21\u5757\u65f6\uff0c__name__ \u7684\u503c\u662f\u6587\u4ef6\u540d\uff08\u4e0d\u5e26.py\uff09\n    '''\n    import argparse # \u5bfc\u5165argparse\u6a21\u5757\n'''\nPython\u6807\u51c6\u5e93\u4e2d\u7684\u6a21\u5757\n\u7528\u6765\u89e3\u6790\u547d\u4ee4\u884c\u53c2\u6570\n\u53ef\u4ee5\u8ba9\u7a0b\u5e8f\u63a5\u53d7\u7528\u6237\u4ece\u547d\u4ee4\u884c\u8f93\u5165\u7684\u53c2\u6570\n'''\n\n    # \u89e3\u6790\u547d\u4ee4\u884c\u53c2\u6570\n    parser = argparse.ArgumentParser(description=\"NagaAgent - \u667a\u80fd\u5bf9\u8bdd\u52a9\u624b\") # \u521b\u5efa\u53c2\u6570\u89e3\u6790\u5668\n    #ArgumentParser\uff1a\u53c2\u6570\u89e3\u6790\u5668\u7684\u7c7b,description\uff1a\u7a0b\u5e8f\u63cf\u8ff0\uff0c\u663e\u793a\u5728\u5e2e\u52a9\u4fe1\u606f\u4e2d\n    #\u521b\u5efa\u7684parser\u5bf9\u8c61\uff1a\u53ef\u4ee5\u7406\u89e3\u4e3a\u4e00\u4e2a\"\u53c2\u6570\u63a5\u6536\u5668\",\u8d1f\u8d23\u5b9a\u4e49\u7a0b\u5e8f\u80fd\u63a5\u53d7\u54ea\u4e9b\u53c2\u6570\n    parser.add_argument(\"--check-env\", action=\"store_true\", help=\"\u8fd0\u884c\u7cfb\u7edf\u73af\u5883\u68c0\u6d4b\") # \u6dfb\u52a0\u547d\u4ee4\u884c\u53c2\u6570,--check-env\uff1a\u8fd0\u884c\u5b8c\u6574\u7684\u7cfb\u7edf\u73af\u5883\u68c0\u6d4b\n    #\u53c2\u6570\u8bf4\u660e\uff1a\"--check-env\"\uff1a\u53c2\u6570\u7684\u540d\u79f0\uff08\u524d\u9762\u6709\u4e24\u4e2a\u51cf\u53f7\uff09,action=\"store_true\"\uff1a\u5982\u679c\u7528\u6237\u8f93\u5165\u4e86\u8fd9\u4e2a\u53c2\u6570\uff0c\u5c31\u628a\u503c\u8bbe\u4e3aTrue,help=\"...\"\uff1a\u5e2e\u52a9\u4fe1\u606f\uff0c\u8bf4\u660e\u8fd9\u4e2a\u53c2\u6570\u7684\u4f5c\u7528\n    parser.add_argument(\"--quick-check\", action=\"store_true\", help=\"\u8fd0\u884c\u5feb\u901f\u73af\u5883\u68c0\u6d4b\") # --quick-check\uff1a\u8fd0\u884c\u5feb\u901f\u73af\u5883\u68c0\u6d4b\n    parser.add_argument(\"--force-check\", action=\"store_true\", help=\"\u5f3a\u5236\u8fd0\u884c\u73af\u5883\u68c0\u6d4b\uff08\u5ffd\u7565\u7f13\u5b58\uff09\") # --force-check\uff1a\u5f3a\u5236\u8fd0\u884c\u68c0\u6d4b\uff0c\u5ffd\u7565\u7f13\u5b58\n\n    args = parser.parse_args() #\u89e3\u6790\u547d\u4ee4\u884c\u53c2\u6570\n    '''\u8fd9\u4e00\u884c\u4ee3\u7801\u7684\u4f5c\u7528\uff1a\u8bfb\u53d6\u7528\u6237\u5728\u547d\u4ee4\u884c\u8f93\u5165\u7684\u53c2\u6570\n          \u6839\u636e\u524d\u9762\u5b9a\u4e49\u7684\u89c4\u5219\u89e3\u6790\u8fd9\u4e9b\u53c2\u6570\n          \u628a\u7ed3\u679c\u4fdd\u5b58\u5230args\u5bf9\u8c61\u4e2d\n    args\u5bf9\u8c61\uff1a\u5305\u542b\u4e86\u6240\u6709\u89e3\u6790\u540e\u7684\u53c2\u6570\u503c,\u4f8b\u5982\uff0c\u5982\u679c\u7528\u6237\u8f93\u5165\u4e86--check-env\uff0c\u90a3\u4e48args.check_env\u5c31\u662fTrue\n    '''\n\n'''\n\u7528\u6237\u8f93\u5165\u4e86--check-env\u6216--quick-check\u5417\uff1f\n    \u2193\n\u662f \u2192 \u9700\u8981\u8fd0\u884c\u73af\u5883\u68c0\u6d4b\n    \u2193\n\u7528\u6237\u8f93\u5165\u4e86--quick-check\u5417\uff1f\n    \u2193\n\u662f \u2192 \u8fd0\u884c\u5feb\u901f\u68c0\u6d4b(run_quick_check)\n\u5426 \u2192 \u8fd0\u884c\u5b8c\u6574\u68c0\u6d4b(run_system_check)\n    \u2193\n\u68c0\u6d4b\u6210\u529f\u5417\uff1f\n    \u2193\n\u662f \u2192 \u9000\u51fa\u7a0b\u5e8f\uff0c\u8fd4\u56de0\uff08\u8868\u793a\u6210\u529f\uff09\n\u5426 \u2192 \u9000\u51fa\u7a0b\u5e8f\uff0c\u8fd4\u56de1\uff08\u8868\u793a\u5931\u8d25\uff09\n'''\n\n    # \u5904\u7406\u68c0\u6d4b\u547d\u4ee4\n    if args.check_env or args.quick_check:  #\u6761\u4ef6\u5224\u65ad\uff1a\u5982\u679c\u7528\u6237\u8f93\u5165\u4e86--check-env\u6216--quick-check,or\u903b\u8f91\uff1a\u4e24\u4e2a\u6761\u4ef6\u6ee1\u8db3\u4e00\u4e2a\u5c31\u884c\n        if args.quick_check: #\u5982\u679c\u7528\u6237\u8f93\u5165\u4e86--quick-check \u2192 \u8fd0\u884c\u5feb\u901f\u68c0\u6d4b\n            success = run_quick_check()\n        else:  # \u5426\u5219 \u2192 \u8fd0\u884c\u5b8c\u6574\u68c0\u6d4b\n            success = run_system_check(force_check=args.force_check)  #  force_check=args.force_check\uff1a\u628a--force-check\u53c2\u6570\u4f20\u7ed9\u68c0\u6d4b\u51fd\u6570\n        sys.exit(0 if success else 1)\n        '''\u6761\u4ef6\u8868\u8fbe\u5f0f\uff1a0 if success else 1\n               \u5982\u679csuccess\u662fTrue \u2192 \u8fd4\u56de0\n               \u5982\u679csuccess\u662fFalse \u2192 \u8fd4\u56de1\n        sys.exit()\uff1a\u9000\u51fa\u7a0b\u5e8f\n        \u9000\u51fa\u7801\u7684\u610f\u4e49\uff1a0\uff1a\u6210\u529f,\u975e0\uff08\u59821\uff09\uff1a\u5931\u8d25\n        '''\n\n    # \u7cfb\u7edf\u73af\u5883\u68c0\u6d4b\n    print(\"\ud83d\ude80 \u6b63\u5728\u542f\u52a8NagaAgent...\")\n    print(\"=\" * 50)\n\n    # \u5982\u679c\u662f\u6253\u5305\u73af\u5883\uff0c\u8df3\u8fc7\u6240\u6709\u73af\u5883\u68c0\u6d4b\n    if IS_PACKAGED:\n        print(\"\ud83d\udce6 \u68c0\u6d4b\u5230\u6253\u5305\u73af\u5883\uff0c\u8df3\u8fc7\u7cfb\u7edf\u73af\u5883\u68c0\u6d4b...\")  #\u5982\u679c\u662f\u6253\u5305\u73af\u5883 \u2192 \u8df3\u8fc7\u68c0\u6d4b\n    else:\n        # \u6267\u884c\u7cfb\u7edf\u68c0\u6d4b\uff08\u53ea\u5728\u7b2c\u4e00\u6b21\u542f\u52a8\u65f6\u68c0\u6d4b\uff09\n        #\u975e\u6253\u5305\u73af\u5883\u7684\u68c0\u6d4b\uff1a\n        if not run_system_check(): #\u8fd0\u884c\u7cfb\u7edf\u68c0\u6d4b\uff1arun_system_check(),\u903b\u8f91\u53cd\u8f6c\uff1anot\u8868\u793a\"\u5982\u679c\u4e0d\u662f\",\u610f\u601d\uff1a\u5982\u679c\u68c0\u6d4b\u5931\u8d25\uff08\u8fd4\u56deFalse\uff09\n            print(\"\\n\u274c \u7cfb\u7edf\u73af\u5883\u68c0\u6d4b\u5931\u8d25\uff0c\u7a0b\u5e8f\u65e0\u6cd5\u542f\u52a8\")\n            print(\"\u8bf7\u6839\u636e\u4e0a\u8ff0\u5efa\u8bae\u4fee\u590d\u95ee\u9898\u540e\u91cd\u65b0\u542f\u52a8\")\n            i=input(\"\u662f\u5426\u65e0\u89c6\u68c0\u6d4b\u7ed3\u679c\u7ee7\u7eed\u542f\u52a8\uff1f\u662f\u5219\u6309y\uff0c\u5426\u5219\u6309\u5176\u4ed6\u4efb\u610f\u952e\u9000\u51fa...\")\n            if i != \"y\" and i != \"Y\":\n                sys.exit(1)\n\n    print(\"\\n\ud83c\udf89 \u7cfb\u7edf\u73af\u5883\u68c0\u6d4b\u901a\u8fc7\uff0c\u6b63\u5728\u542f\u52a8\u5e94\u7528...\")\n    print(\"=\" * 50)\n\n      #\u8bbe\u7f6e\u5f02\u6b65\u4e8b\u4ef6\u5faa\u73af\n      #asyncio.get_event_loop()\uff1a\u83b7\u53d6\u5f53\u524d\u7684\u4e8b\u4ef6\u5faa\u73af,is_running()\uff1a\u68c0\u67e5\u4e8b\u4ef6\u5faa\u73af\u662f\u5426\u5728\u8fd0\u884c\n     if not asyncio.get_event_loop().is_running():  # \u5982\u679c\u4e8b\u4ef6\u5faa\u73af\u4e0d\u5728\u8fd0\u884c\n        asyncio.set_event_loop(asyncio.new_event_loop())\n        #asyncio.new_event_loop()\uff1a\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u4e8b\u4ef6\u5faa\u73af\n       #asyncio.set_event_loop(...)\uff1a\u628a\u8fd9\u4e2a\u65b0\u7684\u4e8b\u4ef6\u5faa\u73af\u8bbe\u4e3a\u5f53\u524d\u5faa\u73af\n\n    \n    # \u5feb\u901f\u542f\u52a8UI\uff0c\u540e\u53f0\u670d\u52a1\u5ef6\u8fdf\u521d\u59cb\u5316\n    #QApplication\u5bf9\u8c61\uff1aPyQt5\u7a0b\u5e8f\u7684\"\u5fc3\u810f\",\u7ba1\u7406\u6574\u4e2aGUI\u5e94\u7528\u7a0b\u5e8f,sys.argv\uff1a\u4f20\u9012\u547d\u4ee4\u884c\u53c2\u6570\u7ed9Qt\n    app = QApplication(sys.argv)\n    icon_path = os.path.join(os.path.dirname(__file__), \"ui\", \"img\/window_icon.png\") #\u6700\u7ec8\u8def\u5f84\uff1a\u5f53\u524d\u76ee\u5f55\/ui\/img\/window_icon.png\n    #os.path.dirname(__file__)\uff1a\u83b7\u53d6\u5f53\u524d\u6587\u4ef6\u6240\u5728\u7684\u76ee\u5f55\n    #os.path.join(...)\uff1a\u62fc\u63a5\u8def\u5f84\n    app.setWindowIcon(QIcon(icon_path))\n    #QIcon(icon_path)\uff1a\u4ece\u8def\u5f84\u521b\u5efa\u56fe\u6807\u5bf9\u8c61\n    #app.setWindowIcon(...)\uff1a\u8bbe\u7f6e\u5e94\u7528\u7a0b\u5e8f\u7684\u56fe\u6807\n    \n    # \u96c6\u6210\u63a7\u5236\u53f0\u6258\u76d8\u529f\u80fd\n    console_tray = integrate_console_tray()\n    #\u8c03\u7528integrate_console_tray()\u51fd\u6570,\u521b\u5efa\u7cfb\u7edf\u6258\u76d8\u56fe\u6807,\u8fd4\u56de\u6258\u76d8\u5bf9\u8c61\uff0c\u4fdd\u5b58\u5230console_tray\u53d8\u91cf\n    \n    # \u521b\u5efa\u5e76\u663e\u793a\u4e3b\u7a97\u53e3,\u7acb\u5373\u663e\u793aUI\uff0c\u63d0\u5347\u7528\u6237\u4f53\u9a8c\n    win = ChatWindow()  #\u521b\u5efa\u7a97\u53e3\u5bf9\u8c61\uff1aChatWindow()\uff0c\u8c03\u7528\u4e4b\u524d\u5bfc\u5165\u7684ChatWindow\u7c7b\n    win.setWindowTitle(\"NagaAgent\")  # \u8bbe\u7f6e\u7a97\u53e3\u6807\u9898\uff1asetWindowTitle(\"NagaAgent\")\n    win.show()  # \u663e\u793a\u7a97\u53e3\uff1ashow()\u65b9\u6cd5\u8ba9\u7a97\u53e3\u53ef\u89c1\n    \n    # \u5728UI\u663e\u793a\u540e\u5f02\u6b65\u521d\u59cb\u5316\u540e\u53f0\u670d\u52a1,\u5f02\u6b65\u521d\u59cb\u5316\u540e\u53f0\u670d\u52a1\n    def init_services_async(): #\u5728\u51fd\u6570\u5185\u90e8\u8c03\u7528_lazy_init_services()\uff08\u6211\u4eec\u4e4b\u524d\u5206\u6790\u7684\u90a3\u4e2a\u51fd\u6570\uff09\n        \"\"\"\u5f02\u6b65\u521d\u59cb\u5316\u540e\u53f0\u670d\u52a1\"\"\"\\\n        #\u7528try...except\u6355\u83b7\u5f02\u5e38\uff0c\u9632\u6b62\u521d\u59cb\u5316\u5931\u8d25\u5bfc\u81f4\u7a0b\u5e8f\u5d29\u6e83\n        try:\n            _lazy_init_services()\n        except Exception as e:\n            print(f\"\u26a0\ufe0f \u540e\u53f0\u670d\u52a1\u521d\u59cb\u5316\u5f02\u5e38: {e}\")\n\n\n    # \u4f7f\u7528\u5b9a\u65f6\u5668\u5ef6\u8fdf\u521d\u59cb\u5316\uff0c\u907f\u514d\u963b\u585eUI,\u5bfc\u5165QTimer\uff1aQt\u7684\u5b9a\u65f6\u5668\u7c7b\n    from nagaagent_core.vendors.PyQt5.QtCore import QTimer\n    QTimer.singleShot(100, init_services_async)  # 100ms\u540e\u521d\u59cb\u5316\n    #singleShot\uff1a\u5355\u6b21\u5b9a\u65f6\u5668,init_services_async\uff1a\u8981\u6267\u884c\u7684\u51fd\u6570\n\n    #\u8fd9\u662f\u6700\u91cd\u8981\u7684\u4e00\u884c\u4ee3\u7801\uff1a\u5b83\u542f\u52a8\u4e86\u6574\u4e2aGUI\u7a0b\u5e8f\n    sys.exit(app.exec_())\n    #\u542f\u52a8\u4e8b\u4ef6\u5faa\u73af\uff1a\u5f00\u59cb\u5904\u7406\u7528\u6237\u7684\u6240\u6709\u64cd\u4f5c\uff08\u70b9\u51fb\u3001\u952e\u76d8\u8f93\u5165\u7b49\uff09\n    #\u8fd9\u4e2a\u65b9\u6cd5\u4f1a\u4e00\u76f4\u8fd0\u884c\uff0c\u76f4\u5230\u7a0b\u5e8f\u9000\u51fa\n\n\n#\u6574\u4e2a\u542f\u52a8\u6d41\u7a0b\u603b\u7ed3\n'''\n\u5f00\u59cb\n  \u2193\n\u68c0\u67e5\u662f\u5426\u76f4\u63a5\u8fd0\u884c(__name__ == \"__main__\")\n  \u2193\n\u89e3\u6790\u547d\u4ee4\u884c\u53c2\u6570\n  \u2193\n\u7528\u6237\u8f93\u5165\u4e86\u68c0\u6d4b\u53c2\u6570\u5417\uff1f\n  \u251c\u2500 \u662f \u2192 \u8fd0\u884c\u68c0\u6d4b \u2192 \u9000\u51fa\u7a0b\u5e8f\n  \u2193\n\u5426\uff08\u6b63\u5e38\u542f\u52a8\uff09\n  \u2193\n\u663e\u793a\u542f\u52a8\u4fe1\u606f\n  \u2193\n\u662f\u6253\u5305\u73af\u5883\u5417\uff1f\n  \u251c\u2500 \u662f \u2192 \u8df3\u8fc7\u73af\u5883\u68c0\u6d4b\n  \u2193\n\u5426 \u2192 \u8fd0\u884c\u7cfb\u7edf\u73af\u5883\u68c0\u6d4b\n  \u2193\n\u68c0\u6d4b\u901a\u8fc7\u5417\uff1f\n  \u251c\u2500 \u5426 \u2192 \u8be2\u95ee\u662f\u5426\u7ee7\u7eed \u2192 \u7528\u6237\u9009\u62e9\u7ee7\u7eed\u5417\uff1f\n  \u2502         \u251c\u2500 \u662f \u2192 \u7ee7\u7eed\u542f\u52a8\n  \u2502         \u2193\n  \u2502        \u5426 \u2192 \u9000\u51fa\u7a0b\u5e8f\n  \u2193\n\u662f \u2192 \u8bbe\u7f6e\u5f02\u6b65\u4e8b\u4ef6\u5faa\u73af\n  \u2193\n\u521b\u5efaQt\u5e94\u7528\u7a0b\u5e8f\u5bf9\u8c61\n  \u2193\n\u8bbe\u7f6e\u5e94\u7528\u7a0b\u5e8f\u56fe\u6807\n  \u2193\n\u521b\u5efa\u7cfb\u7edf\u6258\u76d8\u56fe\u6807\n  \u2193\n\u521b\u5efa\u5e76\u663e\u793a\u4e3b\u7a97\u53e3\uff08\u7528\u6237\u7acb\u5373\u770b\u5230\u754c\u9762\uff09\n  \u2193\n\u8bbe\u7f6e\u5b9a\u65f6\u5668\uff0c100\u6beb\u79d2\u540e\u521d\u59cb\u5316\u540e\u53f0\u670d\u52a1\n  \u2193\n\u542f\u52a8Qt\u4e8b\u4ef6\u5faa\u73af\uff08\u7a0b\u5e8f\u5f00\u59cb\u8fd0\u884c\uff0c\u7b49\u5f85\u7528\u6237\u64cd\u4f5c\uff09\n  \u2193\n\u7528\u6237\u64cd\u4f5c\u7a0b\u5e8f...\n  \u2193\n\u7528\u6237\u5173\u95ed\u7a0b\u5e8f \u2192 \u9000\u51fa\u4e8b\u4ef6\u5faa\u73af \u2192 \u9000\u51faPython\u7a0b\u5e8f\n'''<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">build.py<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>import os   # \u6587\u4ef6\u548c\u6587\u4ef6\u5939\u64cd\u4f5c\uff08\u5c31\u50cfWindows\u7684\u8d44\u6e90\u7ba1\u7406\u5668\uff09\nimport shutil   # \u590d\u5236\u3001\u79fb\u52a8\u6587\u4ef6\nimport subprocess   # \u8fd0\u884c\u5916\u90e8\u547d\u4ee4\uff08\u5c31\u50cf\u5728cmd\u91cc\u8f93\u5165\u547d\u4ee4\uff09\nimport sys       # \u7cfb\u7edf\u76f8\u5173\u529f\u80fd\uff0c\u6bd4\u5982\u9000\u51fa\u7a0b\u5e8f\nimport platform     # \u5224\u65ad\u662f\u4ec0\u4e48\u64cd\u4f5c\u7cfb\u7edf\uff08Windows\u3001Mac\u3001Linux\uff09\nimport glob        # \u67e5\u627e\u6587\u4ef6\u540d\uff08\u53ef\u4ee5\u7528*\u8fd9\u79cd\u901a\u914d\u7b26\uff09\nimport zipfile     # \u538b\u7f29\u548c\u89e3\u538bzip\u6587\u4ef6\nimport tarfile     # \u538b\u7f29\u548c\u89e3\u538btar\u6587\u4ef6\n\ndef user_confirmation():\n    \"\"\"\u63d0\u793a\u6e05\u7a7a\u914d\u7f6e\uff0c\u8ba9\u7528\u6237\u786e\u8ba4\u662f\u5426\u7ee7\u7eed\"\"\"\n    print(\"=========================================\")\n    print(\"  \u63d0\u793a\uff1a\u8bf7\u786e\u4fddconfig.json\u5185\u65e0\u9690\u79c1\u6570\u636e\u6216\u5df2\u5220\u9664\u3002\")\n    print(\"=========================================\")\n    response = input(\"\u8bf7\u786e\u8ba4\u662f\u5426\u7ee7\u7eed (\u8f93\u5165 'Y' \u7ee7\u7eed\uff0c\u6216\u6309 Enter\/n \u53d6\u6d88): \").strip().lower()\n    \n    if response != 'y':\n        print(\"\\n\u64cd\u4f5c\u5df2\u53d6\u6d88\u3002\")\n        sys.exit(0)\n\n#\u4ec0\u4e48\u662fuv\uff1f uv\u662f\u4e00\u4e2a\u5feb\u901f\u7684Python\u5305\u7ba1\u7406\u5668\uff0c\u5c31\u50cfpip\u4f46\u66f4\u5feb\u3002\ndef check_uv():\n    \"\"\"\u68c0\u67e5 uv \u662f\u5426\u5b58\u5728\uff0c\u4e0d\u5b58\u5728\u5c31\u63d0\u793a\u5b89\u88c5\uff0c\u7136\u540e\u9000\u51fa\"\"\"\n    print(\"\\n&#91;1\/7] \u68c0\u67e5 uv \u662f\u5426\u5df2\u5b89\u88c5...\")\n    try:\n        # \u8fd0\u884c uv --version \u6765\u68c0\u67e5\u662f\u5426\u5b58\u5728\n        # capture_output=True \u548c check=True \u786e\u4fdd\u5728\u5931\u8d25\u65f6\u80fd\u6355\u83b7\u8f93\u51fa\u6216\u629b\u51fa\u5f02\u5e38\n        subprocess.run(&#91;'uv', '--version'], \n                       capture_output=True, \n                       text=True, \n                       check=True) \n        print(\"    -&gt; uv \u68c0\u67e5\u901a\u8fc7\u3002\")\n    except FileNotFoundError:\n        print(\"\\n&#91;\u9519\u8bef] \u627e\u4e0d\u5230 'uv' \u547d\u4ee4\u3002\")\n        print(\"\u8bf7\u5148\u5b89\u88c5 uv (\u63a8\u8350\u4f7f\u7528 pipx install uv) \u6216\u786e\u4fdd\u5b83\u5728\u7cfb\u7edf PATH \u4e2d\u3002\")\n        sys.exit(1)\n    except subprocess.CalledProcessError as e:\n        print(f\"\\n&#91;\u9519\u8bef] \u6267\u884c 'uv --version' \u5931\u8d25\uff0c\u8fd4\u56de\u975e\u96f6\u72b6\u6001\u7801: {e.returncode}\")\n        print(\"\u8bf7\u68c0\u67e5 uv \u5b89\u88c5\u662f\u5426\u6b63\u786e\u3002\")\n        sys.exit(1)\n\ndef manage_config_files():\n    config_path = os.path.join('config.json')    # \u5f53\u524d\u6587\u4ef6\u5939\u7684config.json\n    example_path = os.path.join('config.json.example')    # \u793a\u4f8b\u914d\u7f6e\u6587\u4ef6\n\n    print(\"\\n&#91;2\/7] \u68c0\u67e5\u914d\u7f6e\u6587\u4ef6...\")\n    if os.path.exists(config_path):   # \u5982\u679c\u5df2\u7ecf\u6709config.json\n        print(f\"    -&gt; \u5df2\u68c0\u6d4b\u5230 {config_path}\uff0c\u8df3\u8fc7\u521b\u5efa\u3002\")\n    else:    # \u5982\u679c\u6ca1\u6709config.json\n        if os.path.exists(example_path):    # \u5982\u679c\u6709\u793a\u4f8b\u6587\u4ef6\n            try:\n                shutil.copy(example_path, config_path)   # \u590d\u5236\u793a\u4f8b\u6587\u4ef6\n                print(f\"    -&gt; \u672a\u68c0\u6d4b\u5230 {config_path}\uff0c\u5df2\u4ece {example_path} \u590d\u5236\u3002\")\n            except Exception as e:\n                print(f\"&#91;\u9519\u8bef] \u590d\u5236\u914d\u7f6e\u6587\u4ef6\u5931\u8d25: {e}\")\n                sys.exit(1)\n        else:\n            print(f\"&#91;\u9519\u8bef] \u672a\u627e\u5230 {example_path}\uff0c\u65e0\u6cd5\u521b\u5efa {config_path}\u3002\")\n            sys.exit(1)\n#\u7b80\u5355\u7406\u89e3\uff1a\u5c31\u50cf\u505a\u86cb\u7cd5\uff0c\u5982\u679c\u6ca1\u6709\u914d\u65b9\uff08config.json\uff09\uff0c\u5c31\u4ece\u793a\u4f8b\u914d\u65b9\uff08config.json.example\uff09\u6284\u4e00\u4efd\u3002\n\n#\u4e3b\u8981\u6784\u5efa\u8fc7\u7a0b,\u8fd9\u662f\u6700\u590d\u6742\u7684\u90e8\u5206\uff0c\u52064\u4e2a\u5c0f\u6b65\u9aa4\ndef run_build_commands():\n    \"\"\"\u6267\u884c uv sync \u548c pyinstaller \u547d\u4ee4\"\"\"\n    \n    print(\"\\n&#91;3\/7] \u5b89\u88c5\u6240\u9700\u4f9d\u8d56...\")\n    try:\n        subprocess.run(&#91;'uv', 'sync', '--group', 'build'], check=True) #\u5b89\u88c5\u4f9d\u8d56\n        print(\"    -&gt; uv sync \u5b8c\u6210\u3002\")\n    except subprocess.CalledProcessError:\n        print(\"&#91;\u9519\u8bef] 'uv sync' \u5931\u8d25\u3002\u8bf7\u68c0\u67e5 'pyproject.toml' \u548c\u7f51\u7edc\u8fde\u63a5\u3002\")\n        sys.exit(1)\n        # \u7ed9Linux\/Mac\u6587\u4ef6\u52a0\u6743\u9650\uff08\u53ea\u6709\u975eWindows\u9700\u8981\uff09\n    if platform.system() != \"Windows\":   # \u5982\u679c\u4e0d\u662fWindows\u7cfb\u7edf\n        print(\"\\n&#91;4\/7] \u6388\u4e88\u6267\u884c\u6743\u9650...\")  # \u627e\u5230\u6240\u6709.so\u6587\u4ef6\n        try:\n            # \u4f7f\u7528 glob \u9012\u5f52\u67e5\u627e .venv \u4e0b\u7684 .so* \u6587\u4ef6\uff0c\u5e76\u4e3a\u6bcf\u4e2a\u6587\u4ef6\u6dfb\u52a0\u53ef\u6267\u884c\u6743\u9650\n            so_files = glob.glob('.venv\/**\/*.so*', recursive=True) \n            if not so_files:\n                print(\"    -&gt; \u672a\u53d1\u73b0 .so* \u6587\u4ef6\uff0c\u8df3\u8fc7\u6388\u4e88\u6267\u884c\u6743\u9650\u3002\")\n            else:\n                for f in so_files:\n                    try:\n                        st = os.stat(f).st_mode\n                        os.chmod(f, st | 0o111)     # \u52a0\u4e0a\u53ef\u6267\u884c\u6743\u9650\n                    except Exception as e:\n                        print(f\"    -&gt; \u65e0\u6cd5\u4fee\u6539\u6743\u9650 {f}: {e}\")\n                print(\"    -&gt; \u6267\u884c\u6743\u9650\u6388\u4e88\u5b8c\u6210\u3002\")\n        except Exception:\n            print(\"&#91;\u9519\u8bef] \u6267\u884c\u6743\u9650\u6388\u4e88\u5931\u8d25\u3002\")\n            sys.exit(1)\n    else:\n        print(\"\\n&#91;4\/7] Windows\u65e0\u9700\u6388\u4e88\u6267\u884c\u6743\u9650\uff0c\u5df2\u8df3\u8fc7...\")\n\n    print(\"\\n&#91;5\/7] \u8fd0\u884c\u6784\u5efa\u547d\u4ee4\")\n    try:\n        # pyinstaller \u547d\u4ee4,\u7528PyInstaller\u6253\u5305\n        subprocess.run(&#91;'uv', 'run', 'pyinstaller', 'main.spec', '--clean', '--noconfirm'], check=True)\n        print(\"    -&gt; PyInstaller \u6784\u5efa\u5b8c\u6210\u3002\")\n    except subprocess.CalledProcessError:\n        print(\"&#91;\u9519\u8bef] 'pyinstaller' \u6784\u5efa\u5931\u8d25\u3002\u8bf7\u68c0\u67e5 PyInstaller \u914d\u7f6e\u3002\")\n        sys.exit(1)\n\ndef create_instructions_and_venv_placeholder():\n    \"\"\"\u521b\u5efa\u8bf4\u660e\u6587\u4ef6\u548c .venv \u5360\u4f4d\u7b26(\u8bf4\u660e\u6587\u4ef6)\"\"\"\n    \n    ## \u8def\u5f84\u5b9a\u4e49\n    dist_main_dir = os.path.join('dist', 'main')  # dist\/main\u6587\u4ef6\u5939\n    instructions_path = os.path.join(dist_main_dir, '\u4f7f\u7528\u8bf4\u660e.txt')  # \u8bf4\u660e\u6587\u4ef6\u8def\u5f84\n    #venv_path = os.path.join(dist_main_dir, '.venv')\n    #placeholder_path = os.path.join(venv_path, '\u8bf4\u660e.txt')\n\n    # \u4f7f\u7528\u8bf4\u660e\u5185\u5bb9\n    instructions_content = \"\"\"\\\nconfig.json\uff08\u914d\u7f6e\u6587\u4ef6\uff09\u4f4d\u7f6e\uff1a_internal\/config.json\uff0c\u4e5f\u53ef\u4ee5\u4f7f\u7528GUI\u8fdb\u884c\u914d\u7f6e\u586b\u5199\n\u9519\u8bef\u8bf7\u7fa4\u91cc\u53cd\u5e94\u6216\u524d\u5f80https:\/\/github.com\/69gg\/NagaAgent\/issues\uff0c\u4e0d\u8981\u524d\u5f80\u5b98\u65b9\u4ed3\u5e93\n\u53cc\u51fb\u8fd0\u884c\u53ef\u6267\u884c\u6587\u4ef6\u5373\u53ef\u542f\u52a8\u7a0b\u5e8f\n\u73af\u5883\u68c0\u6d4b\u9519\u8bef\u76f4\u63a5\u8f93\u5165y\u8df3\u8fc7\u5373\u53ef\uff0c\u4e0d\u5f71\u54cd\u4f7f\u7528\n\"\"\"\n    # .venv\/\u8bf4\u660e.txt \u5185\u5bb9\n    placeholder_content = \"\u5360\u4f4d\"\n\n    print(f\"\\n&#91;6\/7] \u521b\u5efa {instructions_path}...\")\n    \n    # \u786e\u4fdd\u76ee\u6807\u76ee\u5f55\u5b58\u5728,\u521b\u5efa\u6587\u4ef6\u5939\uff08\u5982\u679c\u4e0d\u5b58\u5728\uff09\n    os.makedirs(dist_main_dir, exist_ok=True)\n\n    # \u5199\u5165\u4f7f\u7528\u8bf4\u660e\n    try:\n        with open(instructions_path, 'w', encoding='utf-8') as f:\n            f.write(instructions_content)\n        print(f\"    -&gt; {os.path.basename(instructions_path)} \u5199\u5165\u5b8c\u6210\u3002\")\n    except Exception as e:\n        print(f\"&#91;\u8b66\u544a] \u5199\u5165\u4f7f\u7528\u8bf4\u660e\u5931\u8d25: {e}\")\n\n    ## \u5199\u5165 .venv \u5360\u4f4d\u6587\u4ef6\n    #try:\n    #    with open(placeholder_path, 'w', encoding='utf-8') as f:\n    #        f.write(placeholder_content)\n    #    print(\"    -&gt; .venv\/\u8bf4\u660e.txt \u5199\u5165\u5b8c\u6210\u3002\")\n    #except Exception as e:\n    #    print(f\"&#91;\u8b66\u544a] \u5199\u5165 .venv \u5360\u4f4d\u6587\u4ef6\u5931\u8d25: {e}\")\n\n#\u91cd\u547d\u540d\u548c\u6253\u5305,\u8fd9\u4e2a\u51fd\u6570\u662f\u6574\u4e2a\u6784\u5efa\u6d41\u7a0b\u7684\u6700\u540e\u4e00\u6b65\ndef rename_and_zip_output():\n    \"\"\"\u91cd\u547d\u540d dist\/main \u76ee\u5f55\u5e76\u5feb\u901f\u5f52\u6863\uff08\u4e0d\u538b\u7f29\uff09\"\"\"\n\n    # \u786e\u5b9a\u7cfb\u7edf\u540d\u79f0\n    sys_map = {\n        'Windows': 'Windows',\n        'Linux': 'Linux',\n        'Darwin': 'Darwin'  # Darwin is the core of macOS\n    }\n    current_system = sys_map.get(platform.system(), 'Unknown')\n    #platform.system() \u8fd4\u56de\uff1a'Windows'\u3001'Linux' \u6216 'Darwin'\uff08macOS\uff09\n\n    # \u786e\u5b9a\u7cfb\u7edf\u67b6\u6784\n    arch = platform.machine()  # \u76f4\u63a5\u4f7f\u7528\u539f\u59cb\u673a\u5668\u67b6\u6784\u540d\u79f0\n    #platform.machine() \u8fd4\u56de\uff1a'x86_64'\uff0864\u4f4d\uff09\u3001'AMD64'\u3001'arm64'\uff08\u82f9\u679cM\u82af\u7247\uff09\u7b49\n\n    source_dir = os.path.join('dist', 'main')  # \u6e90\u6587\u4ef6\u5939\uff1adist\/main\n    target_base_name = f'NagaAgent_{current_system}_{arch}'  # \u65b0\u540d\u79f0\n    target_dir_path = os.path.join('dist', target_base_name)  # \u65b0\u8def\u5f84\n    zip_file_path = f'{target_dir_path}.zip'   # \u538b\u7f29\u5305\u8def\u5f84\n    #\u8fd9\u6837\u5c31\u80fd\u751f\u6210\u50cf NagaAgent_Windows_x86_64 \u8fd9\u6837\u7684\u6587\u4ef6\u540d\n\n    if not os.path.isdir(source_dir):    # \u5982\u679cdist\/main\u4e0d\u5b58\u5728\n        print(f\"\\n&#91;\u9519\u8bef] \u627e\u4e0d\u5230\u6784\u5efa\u76ee\u5f55 {source_dir}\u3002\u8bf7\u68c0\u67e5 PyInstaller \u662f\u5426\u6210\u529f\u8fd0\u884c\u3002\")\n        sys.exit(1)\n'''\u627e\u5230\u6253\u5305\u597d\u7684\u7a0b\u5e8f\u6587\u4ef6\u5939\uff08dist\/main\uff09\n\u51c6\u5907\u7ed9\u5b83\u8d77\u4e2a\u65b0\u540d\u5b57\uff0c\u5305\u542b\u7cfb\u7edf\u4fe1\u606f\n\u68c0\u67e5\u8fd9\u4e2a\u6587\u4ef6\u5939\u662f\u5426\u5b58\u5728\uff08\u4e0d\u5b58\u5728\u8bf4\u660e\u524d\u9762\u6b65\u9aa4\u5931\u8d25\u4e86\uff09'''\n\n#\u91cd\u547d\u540d\u6587\u4ef6\u5939\n    print(f\"\\n&#91;7\/7] \u6253\u5305\u4e3a\u538b\u7f29\u5305...\")\n    try:\n        # \u5982\u679c\u76ee\u6807\u76ee\u5f55\u5df2\u5b58\u5728\uff0c\u5148\u5220\u9664\uff0c\u786e\u4fdd\u91cd\u547d\u540d\u6210\u529f\n        if os.path.exists(target_dir_path):\n            shutil.rmtree(target_dir_path)   # \u5220\u9664\u65e7\u7684\n            print(f\"    -&gt; \u5df2\u5220\u9664\u65e7\u76ee\u5f55 {target_dir_path}\u3002\")\n        \n        # \u91cd\u547d\u540d\n        os.rename(source_dir, target_dir_path)\n        print(f\"    -&gt; \u91cd\u547d\u540d {os.path.basename(source_dir)} \u4e3a {os.path.basename(target_dir_path)} \u5b8c\u6210\u3002\")\n    except Exception as e:\n        print(f\"&#91;\u9519\u8bef] \u91cd\u547d\u540d\u5931\u8d25: {e}\")\n        sys.exit(1)\n\n    #Windows\u7cfb\u7edf\u7684\u6253\u5305\u65b9\u5f0f\uff08\u6700\u590d\u6742\uff09\n    print(f\"\\n    -&gt; \u5f00\u59cb\u6253\u5305 {target_dir_path} ...\")\n    try:\n        # Windows: \u5c1d\u8bd5\u4f7f\u7528 7z\uff08\u652f\u6301\u591a\u7ebf\u7a0b\uff09\uff0c\u5426\u5219\u56de\u9000\u5230\u4f7f\u7528\u591a\u7ebf\u7a0b\u8bfb\u53d6\u5e76\u5199\u5165 zip\uff08\u538b\u7f29\u5728\u5199\u5165\u65f6\u4ecd\u4e3a\u5355\u7ebf\u7a0b\uff09\n        if platform.system() == \"Windows\":\n            zip_file_path = f'{target_dir_path}.zip'\n            sevenz = shutil.which('7z') or shutil.which('7za') or shutil.which('7zr')\n            if sevenz:  # \u5982\u679c\u67097z\u5de5\u5177\n                print(\"    -&gt; \u68c0\u6d4b\u5230 7z\uff0c\u4f7f\u7528 7z \u591a\u7ebf\u7a0b\u538b\u7f29\u4e3a zip ...\")\n                try:\n                    subprocess.run(&#91;sevenz, 'a', '-tzip', zip_file_path, target_dir_path, '-mx=9', '-mmt'], check=True)\n                    print(f\"    -&gt; \u591a\u7ebf\u7a0b\u538b\u7f29\u5b8c\u6210\u3002\u6587\u4ef6\u4f4d\u7f6e: {zip_file_path}\")\n                except subprocess.CalledProcessError as e:\n                    print(f\"&#91;\u9519\u8bef] \u4f7f\u7528 7z \u6253\u5305\u5931\u8d25: {e}\")\n                    sys.exit(1)\n            else: # \u5982\u679c\u6ca1\u67097z\uff0c\u7528Python\u81ea\u5df1\u7684\u65b9\u6cd5\n                print(\"    -&gt; \u672a\u68c0\u6d4b\u5230 7z\uff0c\u4f7f\u7528 Python \u591a\u7ebf\u7a0b\u8bfb\u53d6\u5e76\u5199\u5165 zip\uff08\u517c\u5bb9\u6a21\u5f0f\uff09...\")\n                import concurrent.futures # \u591a\u7ebf\u7a0b\u6a21\u5757\n                 # \u627e\u5230\u6240\u6709\u8981\u538b\u7f29\u7684\u6587\u4ef6\n                files = &#91;]\n                for root, _, fnames in os.walk(target_dir_path):\n                    for fname in fnames:\n                        full = os.path.join(root, fname)\n                        arcname = os.path.relpath(full, os.path.join(target_dir_path, '..'))\n                        # \u538b\u7f29\u5305\u5185\u8def\u5f84\n                        files.append((full, arcname))\n                try:   # \u4f7f\u7528\u591a\u7ebf\u7a0b\u8bfb\u53d6\u6587\u4ef6\n                    max_workers = os.cpu_count() or 4  # \u7528CPU\u6838\u5fc3\u6570\u505a\u7ebf\u7a0b\u6570\n                    with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as ex:\n                        # \u5e76\u884c\u8bfb\u53d6\u6587\u4ef6\u5230\u5185\u5b58\n                        future_map = {ex.submit(open, p, 'rb'): (p, a) for p, a in files}\n                        # \u4e3a\u4e86\u4fdd\u8bc1\u987a\u5e8f\u65e0\u5173\u7d27\u8981\uff0c\u6211\u4eec\u6309\u5b8c\u6210\u987a\u5e8f\u5199\u5165 zip\n                        with zipfile.ZipFile(zip_file_path, 'w', zipfile.ZIP_DEFLATED) as zipf:\n                            read_futures = &#91;]\n                            for p, a in files:\n                                read_futures.append(ex.submit(lambda p=p: open(p, 'rb').read()))\n                            # \u6309\u539f files \u987a\u5e8f\u5199\u5165\u4ee5\u4f7f archive \u7a33\u5b9a\n                            for (p, a), fut in zip(files, read_futures):\n                                data = fut.result()   # \u83b7\u53d6\u8bfb\u53d6\u7684\u6587\u4ef6\u5185\u5bb9\n                                zipf.writestr(a, data) # \u5199\u5165zip\n                    print(f\"    -&gt; \u5f52\u6863\u5b8c\u6210\u3002\u6587\u4ef6\u4f4d\u7f6e: {zip_file_path}\")\n                except Exception as e:\n                    print(f\"&#91;\u9519\u8bef] \u5f52\u6863\u5931\u8d25: {e}\")\n                    sys.exit(1)\n                    '''7z\u65b9\u5f0f\uff1a\u5982\u679c\u67097z\u5c31\u7528\u5b83\uff0c\u56e0\u4e3a\u5b83\u5feb\u4e14\u652f\u6301\u591a\u7ebf\u7a0b\n                    Python\u65b9\u5f0f\uff1a\u7528\u591a\u7ebf\u7a0b\u540c\u65f6\u8bfb\u53d6\u591a\u4e2a\u6587\u4ef6\uff0c\u4f46\u5199\u5165zip\u65f6\u8fd8\u662f\u5355\u7ebf\u7a0b\n                   \u4e3a\u4ec0\u4e48\u7528\u591a\u7ebf\u7a0b\u8bfb\u53d6\uff1f \u56e0\u4e3a\u8bfb\u53d6\u6587\u4ef6\u65f6CPU\u5728\u7b49\u786c\u76d8\uff0c\u53ef\u4ee5\u540c\u65f6\u8bfb\u591a\u4e2a '''\n                    \n\n        # Linux \/ Darwin: \u4f18\u5148\u4f7f\u7528 xz\uff08\u66f4\u9ad8\u538b\u7f29\u7387\uff09\uff0c\u56de\u9000\u4f7f\u7528 pigz + tar\uff0c\u6700\u540e\u56de\u9000\u5230 tarfile\n        else:\n            tar_xz_path = f'{target_dir_path}.tar.xz'  # .tar.xz \u6587\u4ef6\u8def\u5f84\n            tar_gz_path = f'{target_dir_path}.tar.gz'   # .tar.gz \u6587\u4ef6\u8def\u5f84\n            tar_cmd = shutil.which('tar')   # \u627etar\u547d\u4ee4\n            xz_cmd = shutil.which('xz')    # \u627exz\u547d\u4ee4\n            pigz_cmd = shutil.which('pigz')   # \u627epigz\u547d\u4ee4\uff08\u591a\u7ebf\u7a0bgzip\uff09\n\n            # \u9996\u5148\u5c1d\u8bd5\u4f7f\u7528 xz\uff08\u6700\u9ad8\u538b\u7f29\u7387\uff09\n            if tar_cmd and xz_cmd:\n                print(\"    -&gt; \u68c0\u6d4b\u5230 tar \u548c xz\uff0c\u4f7f\u7528 xz \u6700\u9ad8\u538b\u7f29\u7387\u538b\u7f29\u4e3a tar.xz ...\")\n                try:\n                    nproc = str(os.cpu_count() or 4)\n                    cwd = os.path.dirname(target_dir_path) or '.'\n                    base = os.path.basename(target_dir_path)\n                    with open(tar_xz_path, 'wb') as out_f:\n                        p1 = subprocess.Popen(&#91;tar_cmd, '-C', cwd, '-cf', '-', base], stdout=subprocess.PIPE)\n                        # xz -9: \u6700\u9ad8\u538b\u7f29\u7ea7\u522b, -T: \u591a\u7ebf\u7a0b\n                        p2 = subprocess.Popen(&#91;xz_cmd, '-9', '-T', nproc], stdin=p1.stdout, stdout=out_f)\n                        p1.stdout.close()\n                        ret2 = p2.wait()\n                        ret1 = p1.wait()\n                        if ret1 != 0 or ret2 != 0:\n                            raise subprocess.CalledProcessError(ret2 or ret1, 'tar|xz')\n                    print(f\"    -&gt; \u591a\u7ebf\u7a0b xz \u538b\u7f29\u5b8c\u6210\u3002\u6587\u4ef6\u4f4d\u7f6e: {tar_xz_path}\")\n                except Exception as e:\n                    print(f\"&#91;\u9519\u8bef] xz\/tar \u6253\u5305\u5931\u8d25: {e}\")\n                    sys.exit(1)\n            # \u56de\u9000\u4f7f\u7528 pigz\n            elif tar_cmd and pigz_cmd:\n                print(\"    -&gt; \u68c0\u6d4b\u5230 tar \u548c pigz\uff0c\u4f7f\u7528 pigz \u591a\u7ebf\u7a0b\u538b\u7f29\u4e3a tar.gz ...\")\n                try:\n                    nproc = str(os.cpu_count() or 4)\n                    cwd = os.path.dirname(target_dir_path) or '.'\n                    base = os.path.basename(target_dir_path)\n                    with open(tar_gz_path, 'wb') as out_f:\n                        p1 = subprocess.Popen(&#91;tar_cmd, '-C', cwd, '-cf', '-', base], stdout=subprocess.PIPE)\n                        p2 = subprocess.Popen(&#91;pigz_cmd, '-9', '-p', nproc], stdin=p1.stdout, stdout=out_f)\n                        p1.stdout.close()\n                        ret2 = p2.wait()\n                        ret1 = p1.wait()\n                        if ret1 != 0 or ret2 != 0:\n                            raise subprocess.CalledProcessError(ret2 or ret1, 'tar|pigz')\n                    print(f\"    -&gt; \u591a\u7ebf\u7a0b\u5f52\u6863\u5b8c\u6210\u3002\u6587\u4ef6\u4f4d\u7f6e: {tar_gz_path}\")\n                except Exception as e:\n                    print(f\"&#91;\u9519\u8bef] pigz\/tar \u6253\u5305\u5931\u8d25: {e}\")\n                    sys.exit(1)\n            else:\n                # \u6700\u540e\u56de\u9000\u5230 Python tarfile\uff0c\u4f18\u5148\u5c1d\u8bd5 xz \u683c\u5f0f\n                try:\n                    print(\"    -&gt; \u672a\u68c0\u6d4b\u5230\u5916\u90e8\u538b\u7f29\u5de5\u5177\uff0c\u4f7f\u7528 Python tarfile xz \u683c\u5f0f\u538b\u7f29...\")\n                    with tarfile.open(tar_xz_path, 'w:xz', preset=9) as tar:\n                        tar.add(target_dir_path, arcname=os.path.basename(target_dir_path))\n                    print(f\"    -&gt; tar.xz \u5f52\u6863\u5b8c\u6210\u3002\u6587\u4ef6\u4f4d\u7f6e: {tar_xz_path}\")\n                except Exception:\n                    # tarfile \u53ef\u80fd\u4e0d\u652f\u6301 xz\uff0c\u56de\u9000\u5230 gzip\n                    try:\n                        print(\"    -&gt; Python tarfile \u4e0d\u652f\u6301 xz\uff0c\u56de\u9000\u5230 gzip \u538b\u7f29...\")\n                        with tarfile.open(tar_gz_path, 'w:gz', compresslevel=9) as tar:\n                            tar.add(target_dir_path, arcname=os.path.basename(target_dir_path))\n                        print(f\"    -&gt; tar.gz \u5f52\u6863\u5b8c\u6210\u3002\u6587\u4ef6\u4f4d\u7f6e: {tar_gz_path}\")\n                    except Exception as e:\n                        print(f\"&#91;\u9519\u8bef] tarfile \u6253\u5305\u5931\u8d25: {e}\")\n                        sys.exit(1)\n\n    except Exception as e:\n        print(f\"&#91;\u9519\u8bef] \u6253\u5305\u8fc7\u7a0b\u51fa\u73b0\u5f02\u5e38: {e}\")\n        sys.exit(1)\n\ndef main():\n    user_confirmation()    # 1. \u786e\u8ba4\u63d0\u793a\n    check_uv()    # 2. \u68c0\u67e5uv\u5de5\u5177\n    manage_config_files()    # 3. \u5904\u7406\u914d\u7f6e\u6587\u4ef6\n    run_build_commands()    # 4. \u6784\u5efa\u547d\u4ee4\uff08\u5b89\u88c5\u4f9d\u8d56\u3001\u6253\u5305\uff09\n    create_instructions_and_venv_placeholder()   # 5. \u521b\u5efa\u8bf4\u660e\u6587\u4ef6\n    rename_and_zip_output()     # 6. \u91cd\u547d\u540d\u548c\u538b\u7f29\n    \n    print(\"\\n=========================================\")\n    print(\"      \u6784\u5efa\u548c\u6253\u5305\u6d41\u7a0b\u5df2\u5168\u90e8\u5b8c\u6210\uff01\")\n    print(\"=========================================\")\n\nif __name__ == \"__main__\":\n    main()\n\n'''\n\u5f00\u59cb\n  \u2193\n\u7528\u6237\u786e\u8ba4 (user_confirmation) \u2190 \u5982\u679c\u7528\u6237\u4e0d\u8f93\u5165'y'\u5c31\u9000\u51fa\n  \u2193\n\u68c0\u67e5uv\u5de5\u5177 (check_uv) \u2190 \u5982\u679c\u6ca1\u6709uv\u5c31\u9000\u51fa\n  \u2193\n\u5904\u7406\u914d\u7f6e\u6587\u4ef6 (manage_config_files) \u2190 \u590d\u5236\u793a\u4f8b\u914d\u7f6e\u6587\u4ef6\n  \u2193\n\u6784\u5efa\u547d\u4ee4 (run_build_commands)\n  \u251c\u2500 \u5b89\u88c5\u4f9d\u8d56 (uv sync)\n  \u251c\u2500 \u7ed9Linux\/Mac\u6587\u4ef6\u52a0\u6743\u9650 (\u5982\u679c\u4e0d\u662fWindows)\n  \u2514\u2500 \u6253\u5305\u6210exe (pyinstaller)\n  \u2193\n\u521b\u5efa\u8bf4\u660e\u6587\u4ef6 (create_instructions_and_venv_placeholder)\n  \u2193\n\u91cd\u547d\u540d\u548c\u538b\u7f29 (rename_and_zip_output)\n  \u251c\u2500 Windows: \u538b\u7f29\u4e3a.zip (\u4f18\u5148\u75287z)\n  \u251c\u2500 Linux: \u538b\u7f29\u4e3a.tar.xz (\u4f18\u5148\u7528tar+xz)\n  \u2514\u2500 macOS: \u538b\u7f29\u4e3a.tar.xz (\u4f18\u5148\u7528tar+xz)\n  \u2193\n\u663e\u793a\u5b8c\u6210\u4fe1\u606f\n  \u2193\n\u7ed3\u675f\n'''<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">setup.py<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>import os   # \u64cd\u4f5c\u7cfb\u7edf\u7684\u5de5\u5177\uff08\u6bd4\u5982\u6253\u5f00\u6587\u4ef6\uff09\nimport platform  #\u67e5\u770b\u7cfb\u7edf\u4fe1\u606f\u7684\u5de5\u5177\uff08\u6bd4\u5982\u77e5\u9053\u662fWindows\u8fd8\u662fMac\uff09\nimport subprocess  #  \u8fd0\u884c\u5176\u4ed6\u7a0b\u5e8f\u6216\u547d\u4ee4\u7684\u5de5\u5177\nimport shutil  #  \u6587\u4ef6\u64cd\u4f5c\u5de5\u5177\uff08\u590d\u5236\u3001\u5220\u9664\u6587\u4ef6\uff09\nimport sys   # Python\u7cfb\u7edf\u5de5\u5177\uff08\u9000\u51fa\u7a0b\u5e8f\u7b49\uff09\nfrom pathlib import Path  #\u5904\u7406\u6587\u4ef6\u8def\u5f84\u7684\u5de5\u5177\nimport re  # \u6b63\u5219\u8868\u8fbe\u5f0f\u5de5\u5177\uff08\u7528\u6765\u67e5\u627e\u7279\u5b9a\u683c\u5f0f\u7684\u6587\u5b57\uff09\n\n'''\u8fd9\u4e2a\u51fd\u6570\u7684\u5de5\u4f5c\u5c31\u50cf\u627e\u94a5\u5319\uff1a\n\u76ee\u6807\uff1a\u5728\u7535\u8111\u4e0a\u627e\u5230\u53ef\u4ee5\u4f7f\u7528\u7684Python\u7a0b\u5e8f\n\u5bfb\u627e\u987a\u5e8f\uff1a\u5148\u627epython3\uff0c\u518d\u627epython\uff0c\u518d\u627epy\uff0c\u6700\u540e\u627epython3.11\n\u68c0\u67e5\u65b9\u6cd5\uff1a\u7528python --version\u547d\u4ee4\u770b\u6bcf\u4e2a\u7a0b\u5e8f\u662f\u5426\u80fd\u8fd0\u884c\n\u7ed3\u679c\uff1a\u5982\u679c\u627e\u5230\u5c31\u8fd4\u56de\u7a0b\u5e8f\u540d\u548c\u7248\u672c\u53f7\uff0c\u627e\u4e0d\u5230\u5c31\u8fd4\u56de\u7a7a'''\ndef find_python_command(preferred_versions=None):\n    \"\"\"\n    \u5728 PATH \u4e2d\u67e5\u627e\u53ef\u7528\u7684 python \u53ef\u6267\u884c\u6587\u4ef6\uff0c\u5e76\u8fd4\u56de\u7b2c\u4e00\u4e2a\u5339\u914d\u7684\u547d\u4ee4\u53ca\u5176\u7248\u672c\u8f93\u51fa\u3002\n    preferred_versions: \u6309\u4f18\u5148\u7ea7\u6392\u5217\u7684\u547d\u4ee4\u5217\u8868\uff08\u4f8b\u5982 &#91;\"python3.11\", \"python3\", \"python\"]\uff09\n    \u8fd4\u56de (\u547d\u4ee4, \u7248\u672c\u8f93\u51fa\u5b57\u7b26\u4e32) \u6216 (None, None)\n    \"\"\"\n    if preferred_versions is None:\n        # &lt;&lt;&lt; \u53d8\u5316\u5f00\u59cb: \u8c03\u6574\u4e86\u68c0\u6d4b\u987a\u5e8f\uff0c\u4f18\u5148\u68c0\u6d4b\u66f4\u901a\u7528\u7684\u547d\u4ee4\n        preferred_versions = &#91;\"python3\", \"python\", \"py\", \"python3.11\"]\n        # &lt;&lt;&lt; \u53d8\u5316\u7ed3\u675f\n    for cmd in preferred_versions:\n        try:\n            # \u901a\u8fc7 `--version` \u83b7\u53d6\u7248\u672c\u4fe1\u606f\uff08\u90e8\u5206 Python \u5c06\u8f93\u51fa\u5230 stderr\uff09\n            proc = subprocess.run(&#91;cmd, \"--version\"], capture_output=True, text=True, check=True)\n            out = (proc.stdout or proc.stderr).strip()\n            if out:\n                return cmd, out\n        except (FileNotFoundError, subprocess.CalledProcessError):\n            # \u547d\u4ee4\u4e0d\u5b58\u5728\u6216\u6267\u884c\u5931\u8d25\uff0c\u7ee7\u7eed\u5c1d\u8bd5\u4e0b\u4e00\u4e2a\n            continue\n    return None, None\n\ndef parse_version(version_output: str):\n    \"\"\"\n    \u4ece\u7248\u672c\u8f93\u51fa\u5b57\u7b26\u4e32\u4e2d\u89e3\u6790\u51fa\u7248\u672c\u53f7\uff08\u5339\u914d X.Y \u6216 X.Y.Z\uff09\n    \u8fd4\u56de\u5339\u914d\u7684\u7248\u672c\u5b57\u7b26\u4e32\u6216 None\n    \"\"\"\n    m = re.search(r\"(\\d+\\.\\d+\\.\\d+|\\d+\\.\\d+)\", version_output)\n    return m.group(1) if m else None\n\ndef is_python_compatible() -&gt; tuple&#91;bool, str, str]:\n    \"\"\"\n    \u68c0\u67e5 Python \u7248\u672c\u3002\u4f18\u5148\u5bfb\u627e 3.11\uff0c\u4f46\u4e5f\u8fd4\u56de\u627e\u5230\u7684\u5176\u4ed6\u7248\u672c\u4fe1\u606f\u3002\n    \u8fd4\u56de (\u662f\u5426\u517c\u5bb93.11, \u4f7f\u7528\u7684 python \u547d\u4ee4, \u7248\u672c\u8f93\u51fa\u5b57\u7b26\u4e32)\n    \"\"\"\n    # &lt;&lt;&lt; \u53d8\u5316\u5f00\u59cb: \u51fd\u6570\u73b0\u5728\u8fd4\u56de\u4e09\u4e2a\u503c\uff0c\u5305\u62ec\u627e\u5230\u7684\u4efb\u4f55python\u7248\u672c\u4fe1\u606f\n    cmd, out = find_python_command()\n    if not cmd:\n        return False, \"\", \"\"\n    ver = parse_version(out) or \"\"\n    try:\n        parts = &#91;int(x) for x in ver.split(\".\")]\n    except Exception:\n        return False, cmd, out\n    # \u4ec5\u5141\u8bb8 3.11.x\n    if len(parts) &gt;= 2 and parts&#91;0] == 3 and parts&#91;1] == 11:\n        return True, cmd, out\n    return False, cmd, out\n    # &lt;&lt;&lt; \u53d8\u5316\u7ed3\u675f\n\ndef is_uv_available() -&gt; bool:\n    \"\"\"\n    \u68c0\u67e5\u662f\u5426\u5b89\u88c5\u5e76\u5728 PATH \u4e2d\u53ef\u7528\u7684 `uv` \u5de5\u5177\n    \"\"\"\n    return shutil.which(\"uv\") is not None\n\nif __name__ == \"__main__\":\n    print(\"\u5f00\u59cb\u8fdb\u884c\u521d\u59cb\u5316\")\n    \n    use_uv = is_uv_available()\n    python_cmd = \"\"\n\n    if use_uv:\n        print(\"   \u2705 \u68c0\u6d4b\u5230 uv\uff0c\u5c06\u7528\u4ee5\u540c\u6b65\u4f9d\u8d56\uff0c\u8df3\u8fc7python\u7248\u672c\u68c0\u6d4b\")\n    else:\n        print(\"   \u2139\ufe0f \u672a\u68c0\u6d4b\u5230 uv\uff0c\u6b63\u5728\u68c0\u67e5 Python \u73af\u5883...\")\n        is_compatible, found_cmd, version_output = is_python_compatible()\n        \n        if is_compatible:\n            python_cmd = found_cmd\n            print(f\"   \u2705 \u68c0\u6d4b\u5230\u517c\u5bb9\u7684 Python 3.11: {python_cmd} ({version_output})\")\n            print(\"   \u2139\ufe0f \u5c06\u4f7f\u7528 venv \u548c pip \u8fdb\u884c\u5b89\u88c5\")\n        elif found_cmd:\n            print(f\"   \u26a0\ufe0f \u672a\u68c0\u6d4b\u5230 Python 3.11\uff0c\u4f46\u627e\u5230\u4e86: {found_cmd} ({version_output})\")\n            prompt = \"   \ud83d\udc49 \u662f\u5426\u8981\u5c1d\u8bd5\u4f7f\u7528\u6b64 Python \u81ea\u52a8\u5b89\u88c5 'uv' \u4ee5\u7ee7\u7eed? (y\/n): \"\n            try:\n                answer = input(prompt).lower().strip()\n            except (EOFError, KeyboardInterrupt):\n                # \u7528\u6237\u6309 Ctrl+C \u6216 Ctrl+D \u4e2d\u65ad\n                print(\"\\n   \u274c \u64cd\u4f5c\u5df2\u53d6\u6d88\u3002\")\n                sys.exit(1)\n\n            if answer in &#91;'y', 'yes']:\n                try:\n                    print(f\"   \u23f3 \u6b63\u5728\u4f7f\u7528 {found_cmd} \u5b89\u88c5 uv...\")\n                    subprocess.run(&#91;found_cmd, \"-m\", \"pip\", \"install\", \"uv\"], check=True)\n                    print(\"   \u2705 uv \u5b89\u88c5\u6210\u529f!\")\n                    use_uv = True # \u6807\u8bb0\u5207\u6362\u5230 uv \u8def\u5f84\n                except subprocess.CalledProcessError as e:\n                    print(f\"   \u274c uv \u5b89\u88c5\u5931\u8d25: {e}\")\n                    print(\"   \u274c \u8bf7\u624b\u52a8\u5b89\u88c5 Python 3.11 \u6216\u8bbf\u95ee https:\/\/docs.astral.sh\/uv\/getting-started\/installation\/ \u624b\u52a8\u5b89\u88c5 uv\")\n                    sys.exit(1)\n            else:\n                print(\"   \u274c \u64cd\u4f5c\u5df2\u53d6\u6d88\u3002\u8bf7\u5b89\u88c5 Python 3.11 \u6216 uv \u540e\u91cd\u8bd5\u3002\")\n                sys.exit(1)\n        else:\n            print(\"   \u274c \u672a\u5728 PATH \u4e2d\u627e\u5230\u4efb\u4f55\u53ef\u7528\u7684 Python \u73af\u5883\u3002\")\n            print(\"   \u274c \u8bf7\u5b89\u88c5 Python 3.11 \u6216\u8bbf\u95ee https:\/\/docs.astral.sh\/uv\/getting-started\/installation\/ \u5b89\u88c5 uv\u3002\")\n            sys.exit(1)\n\n    repo_root = Path(__file__).parent.resolve()\n    \n    if use_uv:\n        # \u4f7f\u7528 uv \u6765\u540c\u6b65\u4f9d\u8d56\u5e76\u5b89\u88c5 playwright \u7684 chromium\n        print(\"   \u2699\ufe0f \u6b63\u5728\u4f7f\u7528 uv \u540c\u6b65\u4f9d\u8d56...\")\n        try:\n            subprocess.run(&#91;\"uv\", \"sync\"], check=True, cwd=repo_root)\n            print(\"   \u2699\ufe0f \u6b63\u5728\u4f7f\u7528 uv \u5b89\u88c5 Playwright browsers...\")\n            # uv run \u4f1a\u5728uv\u7ba1\u7406\u7684\u73af\u5883\u4e2d\u6267\u884c\u547d\u4ee4\n            subprocess.run(&#91;\"uv\", \"run\", \"playwright\", \"install\", \"chromium\"], check=True, cwd=repo_root)\n        except subprocess.CalledProcessError as e:\n            print(f\"   \u274c uv \u64cd\u4f5c\u5931\u8d25: {e}\")\n            sys.exit(1)\n    else:\n        # \u4f7f\u7528\u4f20\u7edf\u7684 venv\/pip \u6d41\u7a0b\n        venv_dir = repo_root \/ \".venv\"\n        print(f\"   \u2699\ufe0f \u6b63\u5728\u521b\u5efa\u865a\u62df\u73af\u5883\u5230: {venv_dir}\")\n        try:\n            subprocess.run(&#91;python_cmd, \"-m\", \"venv\", str(venv_dir)], check=True)\n        except subprocess.CalledProcessError as e:\n            print(f\"   \u274c \u521b\u5efa\u865a\u62df\u73af\u5883\u5931\u8d25: {e}\")\n            sys.exit(1)\n\n        # \u865a\u62df\u73af\u5883\u4e2d Python \u53ef\u6267\u884c\u6587\u4ef6\u7684\u8def\u5f84\uff08Windows \u548c\u7c7b Unix \u4e0d\u540c\uff09\n        if platform.system() == \"Windows\":\n            venv_python = venv_dir \/ \"Scripts\" \/ \"python.exe\"\n        else:\n            venv_python = venv_dir \/ \"bin\" \/ \"python\"\n\n        if not venv_python.exists():\n            print(\"   \u274c \u865a\u62df\u73af\u5883 Python \u672a\u627e\u5230\uff0c\u5b89\u88c5\u4e2d\u65ad\")\n            sys.exit(1)\n            \n        print(\"   \u2699\ufe0f \u6b63\u5728\u5b89\u88c5\u4f9d\u8d56...\")\n        try:\n            subprocess.run(&#91;str(venv_python), \"-m\", \"pip\", \"install\", \"--upgrade\", \"pip\"], check=True)\n            req_file = repo_root \/ \"requirements.txt\"\n            if req_file.exists():\n                subprocess.run(&#91;str(venv_python), \"-m\", \"pip\", \"install\", \"-r\", str(req_file)], check=True)\n            else:\n                print(\"   \u26a0\ufe0f requirements.txt \u672a\u627e\u5230\uff0c\u8df3\u8fc7 pip \u5b89\u88c5\")\n            \n            print(\"   \u2699\ufe0f \u6b63\u5728\u5b89\u88c5 Playwright browsers...\")\n            subprocess.run(&#91;str(venv_python), \"-m\", \"playwright\", \"install\", \"chromium\"], check=True)\n        except subprocess.CalledProcessError as e:\n            print(f\"   \u274c \u4f9d\u8d56\u5b89\u88c5\u5931\u8d25: {e}\")\n            sys.exit(1)\n\n    \n    # \u5904\u7406\u914d\u7f6e\u6587\u4ef6 config.json\uff1a\u5982\u679c\u4e0d\u5b58\u5728\u5219\u4ece config.json.example \u590d\u5236\u4e00\u4efd\n    cfg = repo_root \/ \"config.json\"\n    example = repo_root \/ \"config.json.example\"\n    if not cfg.exists():\n        if example.exists():\n            try:\n                shutil.copyfile(str(example), str(cfg))\n                print(\"   \u2705 \u5df2\u521b\u5efa config.json\")\n            except Exception as e:\n                print(f\"   \u274c \u590d\u5236 config.json.example \u5931\u8d25: {e}\")\n                sys.exit(1)\n        else:\n            print(\"   \u274c config.json.example \u4e0d\u5b58\u5728\uff0c\u65e0\u6cd5\u521b\u5efa config.json\")\n            sys.exit(1)\n    else:\n        print(\"   \u2705 config.json \u5df2\u5b58\u5728\")\n\n    # \u4f7f\u7528\u7cfb\u7edf\u9ed8\u8ba4\u7f16\u8f91\u5668\u6253\u5f00 config.json\uff0c\u4fbf\u4e8e\u7528\u6237\u7f16\u8f91\n    print(\"   \ud83d\udce5 \u4f7f\u7528\u7cfb\u7edf\u9ed8\u8ba4\u7f16\u8f91\u5668\u6253\u5f00 config.json\uff0c\u8bf7\u6839\u636e\u9700\u8981\u8fdb\u884c\u4fee\u6539\")\n    try:\n        if platform.system() == \"Windows\":\n            os.startfile(str(cfg))\n        elif platform.system() == \"Darwin\":\n            subprocess.run(&#91;\"open\", str(cfg)], check=True)\n        else:\n            subprocess.run(&#91;\"xdg-open\", str(cfg)], check=True)\n    except Exception as e:\n        print(f\"   \u26a0\ufe0f \u65e0\u6cd5\u81ea\u52a8\u6253\u5f00 config.json: {e}\")\n        \n    print(\"\\n\ud83c\udf89 \u521d\u59cb\u5316\u5b8c\u6210\uff0c\u53ef\u4ee5\u542f\u52a8\u7a0b\u5e8f\u4e86\uff08\u4f8b\u5982\u8fd0\u884c start.bat \/ start.sh\uff09\")\n<\/code><\/pre>\n\n\n\n<p>\u5176\u4ed6\u6587\u4ef6\u5939\u4f60\u6253\u5f00\u4e86\u4e4b\u540e\u53d1\u73b0\u4ed6\u4eec\u5c31\u662f\u57fa\u672c\u4e0a\u5c31\u662f\u53ea\u5305\u542b\u4e86\u4e00\u4e2a\u6587\u4ef6\u914d\u7f6e\u7684\u5c31\u662f\u544a\u8bc9\u4f60\u8981\u914d\u7f6e\u54ea\u4e9b\u6587\u4ef6\uff0c\u54ea\u4e9b\u6587\u4ef6\u662f\u9700\u8981\u8fdb\u884c\u5b89\u88c5\u7684\uff0c\u6240\u4ee5\u5462\uff0c\u8fd9\u4e9b\u4e1c\u897f\u4e0d\u662f\u6d89\u53ca\u6574\u4e2a\u6838\u5fc3\u529f\u80fd\u7684\u5b9e\u73b0\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u5148\u62ce\u4e3b\u6b21 \u8981\u5206\u6790\u8fd9\u4e2a\u9879\u76ee\u7684\u6587\u4ef6\u7ed3\u6784\uff0c\u6211\u4eec\u53ef\u4ee5\u4ece\u201c\u6838\u5fc3\u5165\u53e3\u201d\u5230\u201c\u8f85\u52a9\u914d\u7f6e\u201d\u7684\u987a\u5e8f\u62c6\u89e3\uff0c\u5148\u6293\u5173\u952e\u6587\u4ef6\uff0c\u518d\u770b\u8f85\u52a9\u7ec4\u4ef6 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[27,55],"tags":[],"class_list":["post-1249","post","type-post","status-publish","format-standard","hentry","category-open-source-analysis","category-technology"],"_links":{"self":[{"href":"http:\/\/www.preluna.xyz\/index.php\/wp-json\/wp\/v2\/posts\/1249","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.preluna.xyz\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.preluna.xyz\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.preluna.xyz\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.preluna.xyz\/index.php\/wp-json\/wp\/v2\/comments?post=1249"}],"version-history":[{"count":7,"href":"http:\/\/www.preluna.xyz\/index.php\/wp-json\/wp\/v2\/posts\/1249\/revisions"}],"predecessor-version":[{"id":1262,"href":"http:\/\/www.preluna.xyz\/index.php\/wp-json\/wp\/v2\/posts\/1249\/revisions\/1262"}],"wp:attachment":[{"href":"http:\/\/www.preluna.xyz\/index.php\/wp-json\/wp\/v2\/media?parent=1249"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.preluna.xyz\/index.php\/wp-json\/wp\/v2\/categories?post=1249"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.preluna.xyz\/index.php\/wp-json\/wp\/v2\/tags?post=1249"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}