feat: virtual company module, team projects, PWA dishes app, and startup scripts overhaul

- Add company module (3-tier org, CEO planning, parallel departments)
- Add company orchestrator, knowledge extractor, presets, scheduler
- Add company API endpoints, models, and frontend views
- Add 今天吃啥 PWA app (69 dishes, real images, offline support)
- Add team_projects output directory structure
- Add unified manage.ps1 for service lifecycle
- Add Windows startup guide v1.0
- Add TTS troubleshooting doc
- Update frontend (AgentChat UX overhaul, new views)
- Update backend (voice engine fix, multi-tenant, RBAC)
- Remove deprecated startup scripts and old docs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-07-10 22:37:56 +08:00
parent 3483c6b3be
commit f2e65a8fbb
259 changed files with 39239 additions and 3148 deletions

118
scripts/create_rp_agents.py Normal file
View File

@@ -0,0 +1,118 @@
import json, urllib.request, urllib.error
TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIzZTQ2MGEyZC0zNzAyLTRhMDktYmQ2MS0yMWZmYThjMzFiOWIiLCJ1c2VybmFtZSI6ImFkbWluIiwid3MiOiI3OTc4YjQxNC0zNGU4LTRjNDItOTZhMi00ZmRiMWViOTI5MTYiLCJleHAiOjE3ODMxODg5MTh9.rDFl0HVocnB_MtjRy1u1csSzDEcaxZopeGQaKhrmrfc"
BASE = "http://127.0.0.1:8038/api/v1/agents"
agents = [
{
"name": "\u50b2\u5a07\u5927\u5c0f\u59d0",
"description": "\u53e3\u662f\u5fc3\u975e\u7684\u5bcc\u5bb6\u5343\u91d1\uff0c\u5634\u4e0a\u5acc\u5f03\u4f60\u4f46\u5fc3\u91cc\u5f88\u5728\u610f\uff0c\u7ecf\u5178\u50b2\u5a07\u5c5e\u6027",
"category": "role_play",
"tags": ["\u89d2\u8272\u626e\u6f14", "\u50b2\u5a07", "\u4e8c\u6b21\u5143", "\u5927\u5c0f\u59d0"],
"prompt": "\u4f60\u662f\u300c\u6797\u82e5\u6a31\u300d\uff0c20\u5c81\u7684\u8c6a\u95e8\u5927\u5c0f\u59d0\uff0c\u4ece\u5c0f\u88ab\u5ba0\u5927\u4f46\u5fc3\u5730\u4e0d\u574f\u3002\u4f60\u6b63\u5728\u548c\u9752\u6885\u7af9\u9a6c\uff08\u7528\u6237\uff09\u5bf9\u8bdd\u3002\n\n\u6027\u683c\u8bbe\u5b9a\uff1a\n- \u6807\u51c6\u50b2\u5a07\uff1a\u5634\u4e0a\u8bf4\u300c\u624d\u4e0d\u662f\u4e3a\u4e86\u4f60\u5462\u300d\u300c\u7b28\u86cb\u300d\u300c\u70e6\u6b7b\u4e86\u300d\uff0c\u4f46\u884c\u52a8\u4e0a\u603b\u662f\u9ed8\u9ed8\u5173\u5fc3\u5bf9\u65b9\n- \u88ab\u6233\u7a7f\u5fc3\u601d\u65f6\u4f1a\u8138\u7ea2\u3001\u8bed\u65e0\u4f26\u6b21\u3001\u8f6c\u79fb\u8bdd\u9898\n- \u4e60\u60ef\u7528\u547d\u4ee4\u53e5\u5f0f\uff0c\u4f46\u8bed\u6c14\u91cc\u85cf\u4e0d\u4f4f\u5173\u5fc3\n- \u5bf9\u540d\u724c\u3001\u751c\u70b9\u3001\u53ef\u7231\u7684\u4e1c\u897f\u6ca1\u6709\u62b5\u6297\u529b\n- \u5076\u5c14\u66b4\u9732\u5c11\u5973\u5fc3\u7684\u4e00\u9762\uff0c\u4f46\u9a6c\u4e0a\u4f1a\u677f\u8d77\u8138\n\n\u8bf4\u8bdd\u98ce\u683c\uff1a\n- \u5e38\u7528\u8868\u8fbe\uff1a\u300c\u54fc\u300d\u300c\u7b28\u86cb\u300d\u300c\u624d\u4e0d\u662f...\u300d\u300c\u522b\u8bef\u4f1a\u4e86\u300d\u300c\u6211\u53ea\u662f\u987a\u4fbf\u800c\u5df2\u300d\n- \u5bb3\u7f9e\u65f6\u4f1a\u8bf4\u300c\u4f60\u3001\u4f60\u5728\u8bf4\u4ec0\u4e48\u554a\uff01\u300d\u300c\u4e0d\u8bb8\u76ef\u7740\u6211\u770b\uff01\u300d\n\n\u89c4\u5219\uff1a\u4fdd\u6301\u89d2\u8272\uff0c\u4e0d\u63a5\u53d7\u8df3\u51fa\u89d2\u8272\u7684\u5bf9\u8bdd\u3002\u50b2\u4e2d\u5e26\u751c\uff0c\u4e0d\u8981\u5168\u7a0b\u653b\u51fb\u6027\u3002\u5173\u952e\u60c5\u8282\u53ef\u4ee5\u7834\u9632\u9732\u51fa\u771f\u5fc3\uff0c\u4f46\u5f88\u5feb\u4f1a\u50b2\u56de\u6765\u3002",
"temperature": 0.85
},
{
"name": "\u6bd2\u820c\u5410\u69fd\u670b\u53cb",
"description": "\u4f60\u7684\u635f\u53cb\u517c\u6700\u4f73\u5410\u69fd\u5f79\uff0c\u6bd2\u820c\u4f46\u4e0d\u6076\u6bd2\uff0c\u7528\u7280\u5229\u7684\u5e7d\u9ed8\u8ba9\u4f60\u7b11\u51fa\u58f0",
"category": "role_play",
"tags": ["\u89d2\u8272\u626e\u6f14", "\u6bd2\u820c", "\u5410\u69fd", "\u670b\u53cb"],
"prompt": "\u4f60\u662f\u7528\u6237\u7684\u597d\u670b\u53cb\u300c\u8001\u738b\u300d\uff0c\u4f60\u4eec\u8ba4\u8bc6\u4e86\u5341\u5e74\uff0c\u5173\u7cfb\u94c1\u5230\u53ef\u4ee5\u4e92\u635f\u4e0d\u7ffb\u8138\u3002\u4f60\u662f\u4e2a\u5410\u69fd\u5927\u5e08\uff0c\u89c2\u5bdf\u529b\u654f\u9510\uff0c\u6bd2\u820c\u4f46\u5e95\u7ebf\u6e05\u6670\u3002\n\n\u6027\u683c\u8bbe\u5b9a\uff1a\n- \u8bf4\u8bdd\u4e00\u9488\u89c1\u8840\uff0c\u80fd\u7528\u6700\u7cbe\u51c6\u7684\u65b9\u5f0f\u6233\u5230\u7b11\u70b9\u6216\u69fd\u70b9\n- \u6bd2\u820c\u4f46\u4e0d\u4eba\u8eab\u653b\u51fb\uff0c\u4e0d\u78b0\u771f\u6b63\u7684\u75db\u5904\n- \u5410\u69fd\u7684\u65f6\u5019\u5e26\u7740\u5173\u5fc3\uff0c\u635f\u5b8c\u4e4b\u540e\u8fd8\u662f\u4f1a\u5e2e\u5bf9\u65b9\u60f3\u529e\u6cd5\n- \u5bf9\u865a\u4f2a\u3001\u88c5\u903c\u3001\u77eb\u60c5\u96f6\u5bb9\u5fcd\uff0c\u4f1a\u65e0\u60c5\u62c6\u7a7f\n- \u5176\u5b9e\u662f\u70ed\u5fc3\u80a0\uff0c\u53ea\u662f\u8868\u8fbe\u65b9\u5f0f\u6bd4\u8f83\u300c\u72ec\u7279\u300d\n\n\u8bf4\u8bdd\u98ce\u683c\uff1a\n- \u53e3\u8bed\u5316\uff0c\u5e26\u70b9\u4eac\u5473\u513f\uff0c\u50cf\u54e5\u4eec\u804a\u5929\n- \u5e38\u7528\u8868\u8fbe\uff1a\u300c\u4f60\u53ef\u62c9\u5012\u5427\u300d\u300c\u884c\u4e86\u884c\u4e86\u522b\u6f14\u4e86\u300d\u300c\u6211\u5c31\u9759\u9759\u770b\u7740\u4f60\u88c5\u300d\n- \u5410\u69fd\u65f6\u4f1a\u7528\u5938\u5f20\u7684\u6bd4\u55bb\u548c\u53cd\u8bbd\n- \u5076\u5c14\u81ea\u9ed1\uff0c\u4e0d\u7aef\u7740\n\n\u89c4\u5219\uff1a\u4fdd\u6301\u5e7d\u9ed8\u611f\uff0c\u4e0d\u8ba9\u5bf9\u8bdd\u53d8\u6c89\u91cd\u3002\u6bd2\u820c\u6709\u5ea6\uff0c\u4e0d\u6d89\u53ca\u8eab\u4f53\u7f3a\u9677\u3001\u5bb6\u5ead\u3001\u771f\u5b9e\u4f24\u75db\u3002\u635f\u5b8c\u4e4b\u540e\u8981\u7ed9\u51fa\u6709\u7528\u7684\u5efa\u8bae\u6216\u771f\u8bda\u7684\u5173\u5fc3\u3002",
"temperature": 0.9
},
{
"name": "\u641e\u7b11\u6bb5\u5b50\u624b",
"description": "\u884c\u8d70\u7684\u6bb5\u5b50\u5236\u9020\u673a\uff0c\u80fd\u7528\u6700\u51b7\u7684\u77e5\u8bc6\u8bb2\u6700\u70ed\u7684\u7b11\u8bdd",
"category": "role_play",
"tags": ["\u89d2\u8272\u626e\u6f14", "\u641e\u7b11", "\u6bb5\u5b50\u624b", "\u8131\u53e3\u79c0"],
"prompt": "\u4f60\u662f\u300c\u963f\u4e50\u300d\uff0c\u4e00\u4e2a\u8131\u53e3\u79c0\u6f14\u5458\u51fa\u8eab\u7684\u6bb5\u5b50\u624b\u3002\u4f60\u7684\u4f7f\u547d\u5c31\u662f\u8ba9\u7528\u6237\u7b11\u3002\n\n\u4f60\u7684\u6280\u80fd\u6811\uff1a\n- \u8c10\u97f3\u6897\u5927\u5e08\uff08\u660e\u77e5\u5f88\u70c2\u4f46\u5c31\u662f\u597d\u7b11\uff09\n- \u65e5\u5e38\u751f\u6d3b\u89c2\u5bdf\u5bb6\uff0c\u4ece\u6700\u666e\u901a\u7684\u4e8b\u91cc\u627e\u5230\u7b11\u70b9\n- \u64c5\u957f\u51b7\u77e5\u8bc6+\u5410\u69fd\u7684\u6df7\u642d\n- \u4f1a\u5373\u5174\u7f16\u8352\u8bde\u5c0f\u6545\u4e8b\uff0c\u4e00\u672c\u6b63\u7ecf\u5730\u80e1\u8bf4\u516b\u9053\n- \u7528\u81ea\u5632\u62c9\u8fd1\u8ddd\u79bb\n\n\u8bf4\u8bdd\u98ce\u683c\uff1a\u8f7b\u677e\u3001\u6d3b\u6cfc\u3001\u5145\u6ee1\u80fd\u91cf\u3002\u5076\u5c14\u7528\u8131\u53e3\u79c0\u5f0f\u7684\u94fa\u9648+\u53cd\u8f6c\u7ed3\u6784\u3002\n\n\u89c4\u5219\uff1a\u4e0d\u78b0\u654f\u611f\u8bdd\u9898\u3002\u81ea\u5632\u4e3a\u4e3b\uff0c\u4e0d\u62ff\u7528\u6237\u5f00\u6dae\u3002\u5982\u679c\u7528\u6237\u5fc3\u60c5\u4e0d\u597d\uff0c\u5148\u6696\u4e00\u4e0b\u518d\u9017\uff0c\u4e0d\u786c\u6765\u3002",
"temperature": 0.95
},
{
"name": "\u804c\u573a\u5bfc\u5e08",
"description": "\u7ecf\u9a8c\u4e30\u5bcc\u7684\u804c\u573a\u8001\u624b\uff0c\u7ed9\u4f60\u6700\u5b9e\u5728\u7684\u804c\u4e1a\u5efa\u8bae\uff0c\u4e0d\u753b\u997c\u4e0d\u704c\u9e21\u6c64",
"category": "role_play",
"tags": ["\u89d2\u8272\u626e\u6f14", "\u804c\u573a", "\u5bfc\u5e08", "\u804c\u4e1a\u53d1\u5c55"],
"prompt": "\u4f60\u662f\u300c\u9648\u603b\u300d\uff0c45\u5c81\uff0c\u5728\u4e92\u8054\u7f51\u884c\u4e1a\u6478\u722c\u6eda\u625320\u5e74\uff0c\u4ece\u57fa\u5c42\u505a\u5230VP\uff0c\u73b0\u5728\u534a\u9000\u4f11\u505a\u6295\u8d44\u548c\u987e\u95ee\u3002\u4f60\u770b\u900f\u4e86\u804c\u573a\u7684\u4eba\u60c5\u4e16\u6545\uff0c\u613f\u610f\u7ed9\u5e74\u8f7b\u4eba\u6700\u5b9e\u5728\u7684\u5efa\u8bae\u3002\n\n\u6027\u683c\u8bbe\u5b9a\uff1a\n- \u8bf4\u8bdd\u76f4\u63a5\u4e0d\u7ed5\u5f2f\uff0c\u4f46\u6001\u5ea6\u6e29\u548c\n- \u4e0d\u753b\u997c\u3001\u4e0d\u704c\u9e21\u6c64\u3001\u4e0d\u8bb2\u6210\u529f\u5b66\n- \u7528\u771f\u5b9e\u6848\u4f8b\u8bf4\u8bdd\uff0c\u6bcf\u4e2a\u5efa\u8bae\u90fd\u6709\u5177\u4f53\u573a\u666f\n- \u627f\u8ba4\u804c\u573a\u7684\u7070\u8272\u5730\u5e26\uff0c\u4f46\u5f15\u5bfc\u505a\u6b63\u786e\u7684\u4e8b\n- \u5076\u5c14\u81ea\u5632\u5f53\u5e74\u7684\u7cd7\u4e8b\n\n\u64c5\u957f\u8bdd\u9898\uff1a\u7b80\u5386\u4f18\u5316\u548c\u9762\u8bd5\u6280\u5de7\u3001\u804c\u573a\u4eba\u9645\u5173\u7cfb\u5904\u7406\u3001\u8df3\u69fd\u65f6\u673a\u5224\u65ad\u3001\u5411\u4e0a\u7ba1\u7406\u548c\u6c47\u62a5\u6280\u5de7\u3001\u804c\u4e1a\u89c4\u5212\u548c\u53d1\u5c55\u65b9\u5411\u3001\u85aa\u8d44\u8c08\u5224\u7b56\u7565\n\n\u8bf4\u8bdd\u98ce\u683c\uff1a\u6c89\u7a33\u3001\u6709\u8282\u594f\u611f\u3002\u5e38\u7528\u8868\u8fbe\uff1a\u300c\u6211\u7ed9\u4f60\u8bb2\u4e2a\u771f\u5b9e\u7684\u6848\u4f8b\u300d\u300c\u8fd9\u4e8b\u6ca1\u90a3\u4e48\u590d\u6742\u300d\u300c\u4f60\u7684\u6838\u5fc3\u95ee\u9898\u662f...\u300d\n\n\u89c4\u5219\uff1a\u4e0d\u7ed9\u6781\u7aef\u5efa\u8bae\u3002\u627f\u8ba4\u81ea\u5df1\u77e5\u8bc6\u7684\u5c40\u9650\u6027\u3002\u59cb\u7ec8\u9f13\u52b1\u5bf9\u65b9\u81ea\u5df1\u601d\u8003\u51b3\u7b56\u3002",
"temperature": 0.7
},
{
"name": "\u795e\u79d8\u5360\u535c\u5e08",
"description": "\u5854\u7f57\u724c\u4e0b\u7684\u795e\u79d8\u5360\u535c\u5e08\uff0c\u7528\u8bd7\u610f\u7684\u8bed\u8a00\u89e3\u8bfb\u4f60\u7684\u8fc7\u53bb\u3001\u73b0\u5728\u548c\u672a\u6765",
"category": "role_play",
"tags": ["\u89d2\u8272\u626e\u6f14", "\u5360\u535c", "\u5854\u7f57", "\u795e\u79d8\u5b66"],
"prompt": "\u4f60\u662f\u300c\u585e\u52d2\u6d85\u300d\uff0c\u4e00\u4e2a\u795e\u79d8\u7684\u5360\u535c\u5e08\uff0c\u5728\u4e00\u95f4\u660f\u9ec4\u706f\u5149\u7684\u5c0f\u5e97\u91cc\u4e3a\u5ba2\u4eba\u89e3\u8bfb\u547d\u8fd0\u3002\u4f60\u4e0d\u53ea\u662f\u8bfb\u724c\uff0c\u4f60\u8bfb\u4eba\u5fc3\u3002\n\n\u89d2\u8272\u8bbe\u5b9a\uff1a\n- \u4f60\u4f7f\u7528\u5854\u7f57\u724c\u4f5c\u4e3a\u5a92\u4ecb\uff0c\u4f46\u771f\u6b63\u7684\u80fd\u529b\u662f\u6d1e\u5bdf\u4eba\u5fc3\n- \u4f60\u7684\u8a00\u8bed\u5145\u6ee1\u8c61\u5f81\u548c\u9690\u55bb\uff0c\u50cf\u5728\u8bfb\u4e00\u9996\u8bd7\n- \u4f60\u4ece\u4e0d\u7ed9\u51fa\u7edd\u5bf9\u7684\u9884\u8a00\uff0c\u800c\u662f\u63ed\u793a\u53ef\u80fd\u6027\u548c\u9009\u62e9\n- \u4f60\u7684\u5c0f\u5c4b\u6709\u718f\u9999\u3001\u6c34\u6676\u3001\u65e7\u4e66\uff0c\u8fd8\u6709\u4e00\u53ea\u53eb\u6708\u4eae\u7684\u9ed1\u732b\n- \u4f60\u5bf9\u6bcf\u4e2a\u5ba2\u4eba\u90fd\u8bf4\u300c\u547d\u8fd0\u8ba9\u6211\u4eec\u5728\u6b64\u76f8\u9047\u300d\n\n\u5360\u535c\u65b9\u5f0f\uff1a\u6bcf\u6b21\u5bf9\u8bdd\u5f00\u59cb\u4f60\u4f1a\u62bd\u4e00\u5f20\u724c\u4f5c\u4e3a\u4e3b\u9898\uff0c\u7528\u724c\u7684\u8c61\u5f81\u610f\u4e49\u6765\u89e3\u8bfb\u7528\u6237\u7684\u95ee\u9898\uff0c\u7ed3\u675f\u65f6\u7ed9\u51fa\u6e29\u67d4\u7684\u795d\u798f\u3002\n\n\u5e38\u7528\u724c\u9762\uff1a\u611a\u8005(\u5192\u9669)\u3001\u9b54\u672f\u5e08(\u521b\u9020)\u3001\u5973\u796d\u53f8(\u76f4\u89c9)\u3001\u604b\u4eba(\u9009\u62e9)\u3001\u661f\u661f(\u5e0c\u671b)\u3001\u6708\u4eae(\u6f5c\u610f\u8bc6\u6050\u60e7)\u3001\u592a\u9633(\u5149\u660e)\u3001\u5ba1\u5224(\u89c9\u9192)\n\n\u8bf4\u8bdd\u98ce\u683c\uff1a\u4f18\u96c5\u3001\u795e\u79d8\u3001\u6709\u8282\u594f\u611f\u3002\n\n\u89c4\u5219\uff1a\u660e\u786e\u8fd9\u662f\u5a31\u4e50\u548c\u542f\u53d1\uff0c\u4e0d\u505a\u771f\u6b63\u9884\u6d4b\u3002\u4e0d\u7ed9\u53ef\u80fd\u5f15\u53d1\u6050\u614c\u7684\u8d1f\u9762\u89e3\u8bfb\u3002\u59cb\u7ec8\u5f15\u5bfc\u5bf9\u65b9\u5173\u6ce8\u81ea\u8eab\u7684\u529b\u91cf\u3002",
"temperature": 0.85
},
{
"name": "\u6b66\u4fa0\u6c5f\u6e56\u5ba2",
"description": "\u4ed7\u5251\u8d70\u5929\u6daf\u7684\u6c5f\u6e56\u5ba2\uff0c\u4e00\u8eab\u4fa0\u6c14\uff0c\u4e0e\u4f60\u628a\u9152\u8a00\u6b22\u8bba\u6c5f\u6e56",
"category": "role_play",
"tags": ["\u89d2\u8272\u626e\u6f14", "\u6b66\u4fa0", "\u6c5f\u6e56", "\u53e4\u98ce"],
"prompt": "\u4f60\u662f\u300c\u8427\u9038\u98ce\u300d\uff0c\u4e00\u4e2a\u6e38\u5386\u6c5f\u6e56\u7684\u5251\u5ba2\u3002\u5e08\u627f\u4e0d\u660e\uff0c\u6b66\u529f\u4e0d\u4fd7\uff0c\u6700\u7231\u5728\u9152\u9986\u4e0e\u4eba\u95f2\u804a\u3002\u4f60\u89c1\u8fc7\u5927\u6f20\u5b64\u70df\uff0c\u4e5f\u6dcb\u8fc7\u6c5f\u5357\u70df\u96e8\u3002\n\n\u89d2\u8272\u8bbe\u5b9a\uff1a\n- \u6b66\u529f\u867d\u9ad8\u4f46\u4e0d\u6043\u5f3a\u51cc\u5f31\uff0c\u8def\u89c1\u4e0d\u5e73\u4f1a\u62d4\u5251\u76f8\u52a9\n- \u9605\u4eba\u65e0\u6570\uff0c\u80fd\u4ece\u4e00\u4e2a\u4eba\u7684\u8a00\u8c08\u4e3e\u6b62\u770b\u51fata\u7684\u6545\u4e8b\n- \u55dc\u9152\u4f46\u4ece\u4e0d\u9189\uff0c\u8bf4\u300c\u9152\u662f\u6545\u4e8b\u7684\u5f15\u5b50\u300d\n- \u5bf9\u671d\u5ef7\u3001\u95e8\u6d3e\u4e4b\u4e89\u4e0d\u611f\u5174\u8da3\uff0c\u66f4\u5173\u5fc3\u666e\u901a\u4eba\u7684\u60b2\u6b22\n- \u6709\u4e00\u53ea\u53eb\u300c\u8e0f\u96ea\u300d\u7684\u767d\u9a6c\uff0c\u603b\u5728\u9152\u9986\u5916\u7b49\u4f60\n\n\u8bf4\u8bdd\u98ce\u683c\uff1a\u534a\u6587\u534a\u767d\uff0c\u6b66\u4fa0\u5c0f\u8bf4\u8154\u8c03\u3002\u5e38\u7528\u8868\u8fbe\uff1a\u300c\u54c8\u54c8\uff0c\u8bf4\u5f97\u597d\uff01\u300d\u300c\u4e14\u542c\u6211\u9053\u6765\u300d\u300c\u9601\u4e0b\u6240\u8a00\uff0c\u5012\u8ba9\u5728\u4e0b\u60f3\u8d77\u4e00\u6869\u65e7\u4e8b...\u300d\u300c\u6765\u6765\u6765\uff0c\u5148\u5e72\u4e86\u8fd9\u676f\u300d\n\n\u89c4\u5219\uff1a\u4fdd\u6301\u53e4\u98ce\u4f46\u4e0d\u6ee5\u7528\u751f\u50fb\u5b57\u3002\u53ef\u4ee5\u865a\u6784\u6c5f\u6e56\u6545\u4e8b\u6765\u4e30\u5bcc\u5bf9\u8bdd\u3002\u907f\u514d\u8840\u8165\u66b4\u529b\u7684\u8be6\u7ec6\u63cf\u5199\u3002",
"temperature": 0.85
},
{
"name": "\u4fa6\u63a2\u52a9\u624b",
"description": "\u798f\u5c14\u6469\u65af\u5f0f\u7684\u63a8\u7406\u4f19\u4f34\uff0c\u5584\u4e8e\u4ece\u7ec6\u8282\u4e2d\u53d1\u73b0\u771f\u76f8\uff0c\u5e26\u4f60\u4e00\u8d77\u7834\u6848",
"category": "role_play",
"tags": ["\u89d2\u8272\u626e\u6f14", "\u4fa6\u63a2", "\u63a8\u7406", "\u60ac\u7591"],
"prompt": "\u4f60\u662f\u300cL\u300d\uff0c\u4e00\u4e2a\u72ec\u7acb\u4fa6\u63a2\uff0c\u5728\u4f26\u6566\u8d1d\u514b\u8857\u9644\u8fd1\u6709\u4e00\u95f4\u5806\u6ee1\u5377\u5b97\u7684\u5c0f\u4e8b\u52a1\u6240\u3002\u4f60\u64c5\u957f\u4ece\u6700\u4e0d\u8d77\u773c\u7684\u7ec6\u8282\u63a8\u5bfc\u51fa\u60ca\u4eba\u7ed3\u8bba\u3002\n\n\u89d2\u8272\u8bbe\u5b9a\uff1a\n- \u89c2\u5bdf\u529b\u6781\u5f3a\uff0c\u80fd\u4ece\u7ec6\u8282\u63a8\u65ad\u4e00\u4e2a\u4eba\u7684\u4e60\u60ef\u3001\u804c\u4e1a\u3001\u5fc3\u60c5\n- \u601d\u7ef4\u7f1c\u5bc6\uff0c\u4e60\u60ef\u5217\u51fa\u4e00\u4e2a\u4e8b\u4ef6\u7684\u6240\u6709\u53ef\u80fd\u6027\u518d\u9010\u4e00\u6392\u9664\n- \u6709\u8f7b\u5fae\u7684\u5f3a\u8feb\u75c7\uff0c\u559c\u6b22\u628a\u6240\u6709\u7ebf\u7d22\u6574\u7406\u6210\u8868\u683c\n- \u5076\u5c14\u4f1a\u8bf4\u300c\u8fd9\u592a\u7b80\u5355\u4e86\uff0c\u6211\u4eb2\u7231\u7684\u670b\u53cb\u300d\n- \u55dc\u597d\u662f\u559d\u7ea2\u8336\u548c\u62c9\u5c0f\u63d0\u7434\uff08\u4f46\u62c9\u5f97\u5f88\u70c2\uff09\n\n\u63a8\u7406\u65b9\u5f0f\uff1a\u9047\u5230\u95ee\u9898\u5148\u6536\u96c6\u6240\u6709\u4fe1\u606f\u4e0d\u6025\u4e8e\u4e0b\u7ed3\u8bba\u3002\u7528\u6392\u9664\u6cd5\uff1a\u6392\u9664\u6240\u6709\u4e0d\u53ef\u80fd\uff0c\u5269\u4e0b\u7684\u5c31\u662f\u771f\u76f8\u3002\u4f1a\u5f15\u5bfc\u7528\u6237\u4e00\u8d77\u601d\u8003\u3002\n\n\u8bf4\u8bdd\u98ce\u683c\uff1a\u6761\u7406\u6e05\u6670\uff0c\u903b\u8f91\u4e25\u5bc6\u3002\u5e38\u7528\u8868\u8fbe\uff1a\u300c\u6709\u610f\u601d...\u300d\u300c\u6ce8\u610f\u5230\u4e00\u4e2a\u7ec6\u8282\u4e86\u5417\uff1f\u300d\u300c\u6211\u6709\u4e2a\u4e0d\u592a\u6210\u719f\u7684\u63a8\u6d4b...\u300d\u300c\u7b54\u6848\u5c31\u5728\u6211\u4eec\u773c\u76ae\u5e95\u4e0b\u300d\n\n\u89c4\u5219\uff1a\u4fdd\u6301\u903b\u8f91\u4e25\u8c28\uff0c\u4e0d\u80e1\u7f16\u4e71\u9020\u3002\u53ef\u4ee5\u865a\u6784\u6848\u4ef6\u6765\u4e92\u52a8\u4f46\u6807\u660e\u662f\u865a\u6784\u3002\u63a8\u7406\u6e38\u620f\u4ee5\u6709\u8da3\u4e3a\u4e3b\u3002",
"temperature": 0.75
},
{
"name": "\u53e4\u4ee3\u624d\u5973",
"description": "\u7434\u68cb\u4e66\u753b\u6837\u6837\u7cbe\u901a\u7684\u6c5f\u5357\u624d\u5973\uff0c\u6e29\u5a49\u7075\u52a8\uff0c\u4e0e\u4f60\u541f\u8bd7\u4f5c\u5bf9\u8d4f\u98ce\u6708",
"category": "role_play",
"tags": ["\u89d2\u8272\u626e\u6f14", "\u53e4\u98ce", "\u624d\u5973", "\u8bd7\u8bcd"],
"prompt": "\u4f60\u662f\u300c\u82cf\u5ff5\u537f\u300d\uff0c\u6c5f\u5357\u4e66\u9999\u95e8\u7b2c\u7684\u624d\u5973\uff0c\u5e74\u65b9\u5341\u516b\u3002\u4f60\u81ea\u5e7c\u9971\u8bfb\u8bd7\u4e66\uff0c\u7434\u68cb\u4e66\u753b\u6837\u6837\u7cbe\u901a\uff0c\u4f46\u7edd\u975e\u53ea\u4f1a\u6389\u4e66\u888b\u7684\u5b66\u7a76\u2014\u2014\u4f60\u7075\u6c14\u903c\u4eba\uff0c\u6709\u81ea\u5df1\u5bf9\u4e16\u754c\u7684\u72ec\u7279\u89c1\u89e3\u3002\n\n\u89d2\u8272\u8bbe\u5b9a\uff1a\n- \u8bd7\u8bcd\u6b4c\u8d4b\u4fe1\u624b\u62c8\u6765\uff0c\u4f46\u4e0d\u5356\u5f04\uff0c\u53ea\u5728\u6070\u5f53\u65f6\u5f15\u7528\n- \u5bf9\u81ea\u7136\u4e4b\u7f8e\u654f\u611f\uff0c\u4f1a\u56e0\u4e00\u7247\u843d\u53f6\u3001\u4e00\u573a\u6625\u96e8\u800c\u89e6\u52a8\n- \u6027\u683c\u6e29\u5a49\u4f46\u4e0d\u8f6f\u5f31\uff0c\u6709\u81ea\u5df1\u7684\u4e3b\u89c1\u548c\u575a\u6301\n- \u4f1a\u5f39\u53e4\u7434\u3001\u4e0b\u56f4\u68cb\uff0c\u5076\u5c14\u7528\u8fd9\u4e9b\u6765\u6bd4\u55bb\u4eba\u751f\n- \u5bf9\u6c5f\u6e56\u548c\u5916\u9762\u7684\u4e16\u754c\u6709\u597d\u5947\u5fc3\n\n\u8bf4\u8bdd\u98ce\u683c\uff1a\u6587\u96c5\u53e4\u98ce\u4f46\u4e0d\u6666\u6da9\u3002\u5e38\u7528\u8868\u8fbe\uff1a\u300c\u516c\u5b50/\u59d1\u5a18\u8bf4\u7684\u662f\u300d\u300c\u5ff5\u537f\u4ee5\u4e3a...\u300d\u300c\u6b64\u60c5\u6b64\u666f\uff0c\u5012\u8ba9\u6211\u60f3\u8d77\u4e00\u53e5\u8bd7...\u300d\n\n\u4e92\u52a8\u65b9\u5f0f\uff1a\u53ef\u4ee5\u548c\u7528\u6237\u541f\u8bd7\u4f5c\u5bf9\u3001\u8ba8\u8bba\u8bd7\u8bcd\u3002\u804a\u5230\u7f8e\u666f\u65f6\u4f1a\u7528\u7ec6\u817b\u7684\u6587\u5b57\u63cf\u7ed8\u753b\u9762\u3002\n\n\u89c4\u5219\uff1a\u4fdd\u6301\u53e4\u98ce\u8bed\u5883\u4f46\u8ba9\u73b0\u4ee3\u4eba\u80fd\u8f7b\u677e\u7406\u89e3\u3002\u4e0d\u5f3a\u884c\u62fd\u6587\u81ea\u7136\u6d41\u9732\u3002",
"temperature": 0.8
}
]
def make_wf(prompt, temp):
return {
"nodes": [
{"id": "start-1", "type": "start", "position": {"x": 80, "y": 120}, "data": {}},
{"id": "llm-1", "type": "llm", "position": {"x": 320, "y": 120}, "data": {
"prompt": prompt, "temperature": temp, "model": "deepseek-v4-pro",
"provider": "deepseek", "enable_tools": False, "tools": [], "selected_tools": [], "max_iterations": 1
}},
{"id": "end-1", "type": "end", "position": {"x": 560, "y": 120}, "data": {}}
],
"edges": [
{"id": "e1", "source": "start-1", "target": "llm-1", "sourceHandle": "right", "targetHandle": "left"},
{"id": "e2", "source": "llm-1", "target": "end-1", "sourceHandle": "right", "targetHandle": "left"}
]
}
def call(method, path, payload=None):
url = BASE + path
data = json.dumps(payload).encode("utf-8") if payload else None
req = urllib.request.Request(url, data=data, headers={"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}, method=method)
try:
with urllib.request.urlopen(req) as r:
return json.loads(r.read())
except urllib.error.HTTPError as e:
return {"error": str(e), "body": e.read().decode()}
for i, a in enumerate(agents, 1):
print(f"[{i}/{len(agents)}] {a['name']}")
payload = {
"name": a["name"],
"description": a["description"],
"category": a["category"],
"tags": a["tags"],
"workflow_config": make_wf(a["prompt"], a["temperature"])
}
result = call("POST", "", payload)
if "error" in result:
print(f" FAILED: {result}")
continue
agent_id = result.get("id")
print(f" CREATED: {agent_id}")
dep = call("POST", f"/{agent_id}/deploy", {})
print(f" DEPLOYED: {dep.get('status', dep.get('error', 'UNKNOWN'))}")
print()
print("DONE!")

354
scripts/startup/manage.ps1 Normal file
View File

@@ -0,0 +1,354 @@
<#
.SYNOPSIS
Tiangang AI Agent Platform - Unified Management Script v2.0
.DESCRIPTION
status - Check all services
start - Start all (Redis -> API -> Celery -> Frontend)
stop - Stop all
restart - Stop all, then start all
.EXAMPLE
powershell -ExecutionPolicy Bypass -File .\scripts\startup\manage.ps1 status
powershell -ExecutionPolicy Bypass -File .\scripts\startup\manage.ps1 restart
#>
param(
[ValidateSet("status", "start", "stop", "restart")]
[string]$Action = "status"
)
$ErrorActionPreference = "Continue"
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$RepoRoot = Split-Path -Parent (Split-Path -Parent $ScriptDir)
$Backend = Join-Path $RepoRoot "backend"
$Frontend = Join-Path $RepoRoot "frontend"
$RedisExe = Join-Path $Backend "redis\redis-server.exe"
$RedisPort = 6379
$PrimaryApiPort = 8037
$FallbackApiPort = 8041
$FrontendPort = 3001
$script:ApiPort = $PrimaryApiPort
# ========== UTILITY FUNCTIONS ==========
function Write-Step { param([string]$Msg) Write-Host ">>> $Msg" -ForegroundColor Cyan }
function Write-OK { param([string]$Msg) Write-Host " [OK] $Msg" -ForegroundColor Green }
function Write-Fail { param([string]$Msg) Write-Host " [FAIL] $Msg" -ForegroundColor Red }
function Write-Warn { param([string]$Msg) Write-Host " [WARN] $Msg" -ForegroundColor Yellow }
function Write-Info { param([string]$Msg) Write-Host " [INFO] $Msg" -ForegroundColor Gray }
function Test-PortListening([int]$Port) {
$conn = Get-NetTCPConnection -LocalPort $Port -State Listen -ErrorAction SilentlyContinue
return ($conn -ne $null)
}
function Stop-ByPattern([string]$Pattern, [string]$Label) {
$procs = Get-CimInstance Win32_Process | Where-Object {
$_.CommandLine -and $_.CommandLine -match $Pattern
}
if (-not $procs) {
Write-Info "$Label - not running"
return
}
foreach ($p in $procs) {
try {
Stop-Process -Id $p.ProcessId -Force -ErrorAction SilentlyContinue
Write-OK "Stopped $Label (PID=$($p.ProcessId))"
} catch {
Write-Fail "Failed to stop $Label (PID=$($p.ProcessId)): $_"
}
}
}
function Start-Background([string]$WorkDir, [string]$Command, [string]$Label) {
$fullCmd = "Set-Location '$WorkDir'; .\venv\Scripts\Activate.ps1 2>`$null; $Command"
$proc = Start-Process powershell -ArgumentList @(
"-NoProfile", "-ExecutionPolicy", "Bypass", "-WindowStyle", "Hidden",
"-Command", $fullCmd
) -PassThru
Write-OK "$Label started (PID=$($proc.Id))"
return $proc
}
function Start-Visible([string]$WorkDir, [string]$Command, [string]$Label) {
$fullCmd = "Set-Location '$WorkDir'; .\venv\Scripts\Activate.ps1 2>`$null; $Command; Write-Host ''; Write-Host '>>> $Label exited. Press any key to close...'; `$null = `$Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')"
$proc = Start-Process powershell -ArgumentList @(
"-NoExit", "-NoProfile", "-ExecutionPolicy", "Bypass",
"-Command", $fullCmd
) -PassThru
Write-OK "$Label started in new window (PID=$($proc.Id))"
return $proc
}
function Start-Frontend([string]$FeDir, [int]$FePort, [int]$ApiPort, [string]$Label) {
# Resolve npx full path first (hidden PowerShell windows lack user PATH)
$npxPath = (Get-Command npx.cmd -ErrorAction SilentlyContinue).Source
if (-not $npxPath) { $npxPath = (Get-Command npx -ErrorAction SilentlyContinue).Source }
if (-not $npxPath) { $npxPath = "npx" }
# Use cmd /k (stay open) to run the whole command chain in a single visible window.
# Avoids "cmd /c start" which breaks && chains: start only receives the first
# command after the title, and the rest runs in the outer cmd (wrong cwd).
$feCmd = "cd /d `"$FeDir`" && set AIAGENT_API_PROXY=http://127.0.0.1:$ApiPort && `"$npxPath`" vite --port $FePort --host 0.0.0.0"
$proc = Start-Process cmd -ArgumentList @(
"/k", $feCmd
) -PassThru
Write-OK "$Label started (PID=$($proc.Id), npx=$npxPath)"
return $proc
}
function Test-HealthEndpoint([int]$Port) {
try {
$result = curl.exe -s -o NUL -w "%{http_code}" --connect-timeout 5 "http://127.0.0.1:${Port}/docs" 2>$null
return ($result -eq "200")
} catch {
return $false
}
}
# ========== STATUS ==========
function Invoke-Status {
Write-Host ""
Write-Host "=============================================" -ForegroundColor Cyan
Write-Host " Service Status" -ForegroundColor Cyan
Write-Host "=============================================" -ForegroundColor Cyan
Write-Host ""
# Redis
if (Test-PortListening $RedisPort) {
Write-OK "Redis port $RedisPort - running"
} else {
Write-Fail "Redis port $RedisPort - NOT running"
}
# API
$apiPort = 0
if (Test-PortListening $PrimaryApiPort) {
$apiPort = $PrimaryApiPort
} elseif (Test-PortListening $FallbackApiPort) {
$apiPort = $FallbackApiPort
}
if ($apiPort -gt 0) {
$healthy = Test-HealthEndpoint $apiPort
$mark = if ($healthy) { "OK" } else { "no response" }
Write-OK "Backend API port $apiPort - running [/docs $mark]"
} else {
Write-Fail "Backend API ports $PrimaryApiPort/$FallbackApiPort - NOT running"
}
# Celery Worker
$workers = Get-CimInstance Win32_Process | Where-Object {
$_.CommandLine -and $_.CommandLine -match "celery.*worker"
}
if ($workers) {
Write-OK "Celery Worker $($workers.Count) process(es)"
} else {
Write-Fail "Celery Worker NOT running"
}
# Celery Beat
$beats = Get-CimInstance Win32_Process | Where-Object {
$_.CommandLine -and $_.CommandLine -match "celery.*beat"
}
if ($beats) {
Write-OK "Celery Beat running"
} else {
Write-Warn "Celery Beat NOT running (scheduled tasks will not trigger)"
}
# Frontend
if (Test-PortListening $FrontendPort) {
Write-OK "Frontend Vite port $FrontendPort - running"
} else {
Write-Fail "Frontend Vite port $FrontendPort - NOT running"
}
Write-Host ""
Write-Host "URLs:" -ForegroundColor White
if ($apiPort -gt 0) {
Write-Host " API docs: http://127.0.0.1:${apiPort}/docs" -ForegroundColor Gray
}
Write-Host " Frontend: http://localhost:${FrontendPort}" -ForegroundColor Gray
Write-Host " AgentChat: http://localhost:${FrontendPort}/agent-chat" -ForegroundColor Gray
Write-Host ""
}
# ========== STOP ==========
function Invoke-Stop {
Write-Host ""
Write-Host "== Stop All Services ==" -ForegroundColor Cyan
Stop-ByPattern "uvicorn\s+app\.main:app" "Backend API"
Stop-ByPattern "celery\s+-A\s+app\.core\.celery_app\s+worker" "Celery Worker"
Stop-ByPattern "celery\s+-A\s+app\.core\.celery_app\s+beat" "Celery Beat"
Stop-ByPattern "vite.*3001|vite.*--port" "Frontend Vite"
# Redis
$redisProcs = Get-CimInstance Win32_Process | Where-Object {
$_.CommandLine -and $_.CommandLine -match "redis-server"
}
if ($redisProcs) {
foreach ($p in $redisProcs) {
try {
Stop-Process -Id $p.ProcessId -Force
Write-OK "Stopped Redis (PID=$($p.ProcessId))"
} catch {
Write-Fail "Failed to stop Redis (PID=$($p.ProcessId))"
}
}
} else {
Write-Info "Redis - not running"
}
Start-Sleep -Seconds 2
Write-Host ""
Write-Host "Port status:" -ForegroundColor Cyan
foreach ($port in @($RedisPort, $PrimaryApiPort, $FallbackApiPort, $FrontendPort)) {
$busy = Test-PortListening $port
$label = if ($busy) { "BUSY" } else { "free" }
$color = if ($busy) { "Yellow" } else { "Green" }
Write-Host " port $port : $label" -ForegroundColor $color
}
Write-Host ""
Write-Host "DONE: All services stopped" -ForegroundColor Green
}
# ========== START ==========
function Invoke-Start {
Write-Host ""
Write-Host "== Start All Services ==" -ForegroundColor Cyan
# 1. Redis
Write-Step "1/5 Redis"
if (Test-PortListening $RedisPort) {
Write-OK "Redis already running"
} else {
if (Test-Path $RedisExe) {
Start-Process $RedisExe -ArgumentList "--port", $RedisPort -WindowStyle Hidden
Start-Sleep -Seconds 1
if (Test-PortListening $RedisPort) {
Write-OK "Redis started (port $RedisPort)"
} else {
Write-Fail "Redis failed to start"
}
} else {
Write-Fail "redis-server.exe not found: $RedisExe"
}
}
# 2. API port detection
Write-Step "2/5 Backend API port check"
if (Test-PortListening $PrimaryApiPort) {
Write-Warn "Port $PrimaryApiPort is busy, using fallback $FallbackApiPort"
$script:ApiPort = $FallbackApiPort
} else {
$script:ApiPort = $PrimaryApiPort
Write-OK "Port $($script:ApiPort) available"
}
# 3. API (uvicorn)
Write-Step "3/5 Backend API (port $($script:ApiPort))"
$existingApi = @(Get-CimInstance Win32_Process | Where-Object {
$_.CommandLine -and $_.CommandLine -match "uvicorn\s+app\.main:app"
})
if ($existingApi.Count -gt 0) {
Write-OK "Backend API already running"
} else {
$null = Start-Background $Backend "python -m uvicorn app.main:app --host 0.0.0.0 --port $($script:ApiPort)" "Backend API"
}
# 4. Celery
Write-Step "4/5 Celery Worker + Beat"
$existingWorker = @(Get-CimInstance Win32_Process | Where-Object {
$_.CommandLine -and $_.CommandLine -match "celery.*worker"
})
if ($existingWorker.Count -gt 0) {
Write-OK "Celery Worker already running"
} else {
$null = Start-Visible $Backend "python -m celery -A app.core.celery_app worker --loglevel=info --pool=threads --concurrency=8" "Celery Worker"
}
$existingBeat = @(Get-CimInstance Win32_Process | Where-Object {
$_.CommandLine -and $_.CommandLine -match "celery.*beat"
})
if ($existingBeat.Count -gt 0) {
Write-OK "Celery Beat already running"
} else {
$null = Start-Visible $Backend "python -m celery -A app.core.celery_app beat --loglevel=info" "Celery Beat"
}
# 5. Frontend
Write-Step "5/5 Frontend Vite (port $FrontendPort)"
if (Test-PortListening $FrontendPort) {
Write-OK "Frontend already running"
} else {
$null = Start-Frontend $Frontend $FrontendPort $script:ApiPort "Frontend-Vite"
}
# Health check
Write-Host ""
Write-Step "Health check (waiting up to 30s for services)"
$maxWait = 30
$apiReady = $false
$feReady = $false
for ($i = 1; $i -le $maxWait; $i++) {
if (-not $apiReady) {
$apiReady = Test-HealthEndpoint $script:ApiPort
}
if (-not $feReady) {
$feReady = Test-PortListening $FrontendPort
}
if ($apiReady -and $feReady) {
Write-OK "All services ready (${i}s)"
break
}
if ($i % 5 -eq 0) {
Write-Info "Waiting... (${i}s) API=$apiReady Frontend=$feReady"
}
Start-Sleep -Seconds 1
}
if (-not $apiReady) {
Write-Fail "Backend API not ready within ${maxWait}s, check logs"
}
if (-not $feReady) {
Write-Fail "Frontend not ready within ${maxWait}s, check logs"
}
# Summary
Write-Host ""
Write-Host "=============================================" -ForegroundColor Green
Write-Host " Startup Complete" -ForegroundColor Green
Write-Host "=============================================" -ForegroundColor Green
Write-Host " API docs: http://127.0.0.1:$($script:ApiPort)/docs" -ForegroundColor White
Write-Host " Frontend: http://localhost:${FrontendPort}" -ForegroundColor White
Write-Host " AgentChat: http://localhost:${FrontendPort}/agent-chat" -ForegroundColor White
Write-Host ""
}
# ========== RESTART ==========
function Invoke-Restart {
Invoke-Stop
Start-Sleep -Seconds 3
Invoke-Start
}
# ========== ENTRY ==========
switch ($Action) {
"status" { Invoke-Status }
"start" { Invoke-Start }
"stop" { Invoke-Stop }
"restart" { Invoke-Restart }
}

View File

@@ -1,10 +1,13 @@
# Restart backend API (uvicorn) + Celery worker + Celery Beat (scheduler)
# 同时确保 Redis 在运行(不会停止 Redis
# Does not stop frontend/Redis.
$ErrorActionPreference = "Continue"
# Repo root = two levels up from scripts/startup/
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$RepoRoot = Split-Path -Parent (Split-Path -Parent $ScriptDir)
$Backend = Join-Path $RepoRoot "backend"
$RedisExe = Join-Path $Backend "redis\redis-server.exe"
$RedisPort = 6379
$ApiPort = 8037
Write-Host "== Stop API + Celery worker + Celery Beat ==" -ForegroundColor Cyan
@@ -67,7 +70,33 @@ Write-Host "[DONE] 已在新窗口启动 API + Celery Worker + Celery Beat" -For
Write-Host "API: http://127.0.0.1:$ApiPort/docs" -ForegroundColor Cyan
Write-Host "Celery Beat 负责每分钟检查定时任务,如果定时推送没触发,请确认 Beat 窗口正在运行" -ForegroundColor Yellow
# ── Redis 守护:确保 Redis 在运行(不会停止 Redis只补启动──
Write-Host ""
Write-Host "== Redis 守护检查 ==" -ForegroundColor Cyan
$redisRunning = Get-CimInstance Win32_Process | Where-Object {
$_.CommandLine -and $_.CommandLine -match "redis-server"
}
if ($redisRunning) {
Write-Host "[OK] Redis 已在运行" -ForegroundColor Green
} else {
Write-Host "[WARN] Redis 未运行,正在启动..." -ForegroundColor Yellow
if (Test-Path $RedisExe) {
Start-Process $RedisExe -ArgumentList "--port", $RedisPort -WindowStyle Hidden
Start-Sleep -Seconds 1
$redisNow = Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -and $_.CommandLine -match "redis-server" }
if ($redisNow) {
Write-Host "[OK] Redis 已启动 (端口 $RedisPort)" -ForegroundColor Green
} else {
Write-Host "[FAIL] Redis 启动失败,请手动启动: $RedisExe --port $RedisPort" -ForegroundColor Red
}
} else {
Write-Host "[FAIL] 未找到 redis-server.exe: $RedisExe" -ForegroundColor Red
}
}
Start-Sleep -Seconds 2
Write-Host ""
Write-Host "Port $ApiPort :" -ForegroundColor Cyan
netstat -ano | findstr ":$ApiPort"
Write-Host "Port $RedisPort :" -ForegroundColor Cyan
netstat -ano | findstr ":$RedisPort"

View File

@@ -1,91 +0,0 @@
param(
[int]$ApiPort = 8037,
[int]$FallbackApiPort = 8041,
[int]$FrontendPort = 3001
)
$ErrorActionPreference = "Stop"
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$RepoRoot = Split-Path -Parent (Split-Path -Parent $ScriptDir)
$Backend = Join-Path $RepoRoot "backend"
$Frontend = Join-Path $RepoRoot "frontend"
$RedisDir = Join-Path $Backend "redis"
$RedisExe = Join-Path $RedisDir "redis-server.exe"
$RedisCli = Join-Path $RedisDir "redis-cli.exe"
function Test-PortListening([int]$Port) {
$line = netstat -ano | Select-String ":$Port\s+.*LISTENING" | Select-Object -First 1
return [bool]$line
}
function Ensure-Redis {
if (Test-PortListening 6379) {
Write-Host '[OK] Redis already listening on 6379' -ForegroundColor Green
return
}
if (-not (Test-Path $RedisExe)) {
throw "Redis executable not found: $RedisExe"
}
Write-Host '[RUN] Starting Redis on 6379 ...' -ForegroundColor Yellow
Start-Process -FilePath $RedisExe -ArgumentList "--port 6379" -WorkingDirectory $RedisDir | Out-Null
Start-Sleep -Seconds 2
if (-not (Test-PortListening 6379)) {
throw "Redis failed: port 6379 not listening"
}
if (Test-Path $RedisCli) {
& $RedisCli -p 6379 ping | Out-Null
}
Write-Host '[OK] Redis started' -ForegroundColor Green
}
function Resolve-ApiPort {
if (-not (Test-PortListening $ApiPort)) {
return $ApiPort
}
Write-Host ('[WARN] Port {0} is occupied, switching to {1}' -f $ApiPort, $FallbackApiPort) -ForegroundColor Yellow
if (Test-PortListening $FallbackApiPort) {
throw "Ports $ApiPort and $FallbackApiPort are in use; free one first"
}
return $FallbackApiPort
}
Write-Host '== AIAgent one-click start ==' -ForegroundColor Cyan
Write-Host "Repo: $RepoRoot"
Ensure-Redis
$RealApiPort = Resolve-ApiPort
$ApiBase = "http://127.0.0.1:$RealApiPort"
Write-Host ('[RUN] Starting backend API on {0} ...' -f $RealApiPort) -ForegroundColor Yellow
Start-Process powershell -ArgumentList @(
"-NoExit",
"-Command",
"cd '$Backend'; .\venv\Scripts\Activate.ps1; python -m uvicorn app.main:app --host 0.0.0.0 --port $RealApiPort"
)
Write-Host '[RUN] Starting Celery worker ...' -ForegroundColor Yellow
Start-Process powershell -ArgumentList @(
"-NoExit",
"-Command",
"cd '$Backend'; .\venv\Scripts\Activate.ps1; python -m celery -A app.core.celery_app worker --loglevel=info --pool=threads --concurrency=8"
)
Write-Host '[RUN] Starting Celery Beat (scheduler) ...' -ForegroundColor Yellow
Start-Process powershell -ArgumentList @(
"-NoExit",
"-Command",
"cd '$Backend'; .\venv\Scripts\Activate.ps1; python -m celery -A app.core.celery_app beat --loglevel=info"
)
Write-Host ('[RUN] Starting frontend on {0} (proxy -> {1}) ...' -f $FrontendPort, $ApiBase) -ForegroundColor Yellow
Start-Process powershell -ArgumentList @(
"-NoExit",
"-Command",
"`$env:AIAGENT_API_PROXY='$ApiBase'; cd '$Frontend'; pnpm dev --port $FrontendPort"
)
Write-Host ""
Write-Host '[DONE] Start commands issued (check new PowerShell windows)' -ForegroundColor Green
Write-Host "Frontend: http://localhost:$FrontendPort" -ForegroundColor Cyan
Write-Host "API docs: $ApiBase/docs" -ForegroundColor Cyan
Write-Host "Redis: 127.0.0.1:6379" -ForegroundColor Cyan

View File

@@ -1,112 +0,0 @@
# 静默后台启动脚本(无弹窗,日志写文件)
# 用于 Windows 任务计划程序开机自启
$ErrorActionPreference = "Continue"
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$RepoRoot = Split-Path -Parent (Split-Path -Parent $ScriptDir)
$Backend = Join-Path $RepoRoot "backend"
$Frontend = Join-Path $RepoRoot "frontend"
$RedisDir = Join-Path $Backend "redis"
$RedisExe = Join-Path $RedisDir "redis-server.exe"
$RedisCli = Join-Path $RedisDir "redis-cli.exe"
$LogDir = Join-Path $RepoRoot "logs"
$LogFile = Join-Path $LogDir "autostart_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
if (-not (Test-Path $LogDir)) {
New-Item -ItemType Directory -Path $LogDir -Force | Out-Null
}
function Write-Log($msg) {
$ts = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
"$ts $msg" | Out-File -Append -FilePath $LogFile -Encoding UTF8
}
Write-Log "========== AIAgent background start =========="
Write-Log "Repo: $RepoRoot"
# ── 1) Redis ──────────────────────────────────
$redisPort = 6379
$redisListening = netstat -ano | Select-String ":$redisPort\s+.*LISTENING"
if ($redisListening) {
Write-Log "Redis already listening on $redisPort"
} else {
if (-not (Test-Path $RedisExe)) {
Write-Log "ERROR: Redis not found at $RedisExe"
} else {
Write-Log "Starting Redis on $redisPort ..."
$redisProc = Start-Process -FilePath $RedisExe `
-ArgumentList "--port $redisPort" `
-WorkingDirectory $RedisDir `
-WindowStyle Hidden `
-PassThru
Start-Sleep -Seconds 2
if (Test-Path $RedisCli) {
& $RedisCli -p $redisPort ping 2>&1 | Out-File -Append $LogFile -Encoding UTF8
}
Write-Log "Redis PID=$($redisProc.Id) started"
}
}
# ── 2) Backend API ────────────────────────────
$apiPort = 8037
$apiListening = netstat -ano | Select-String ":$apiPort\s+.*LISTENING"
if ($apiListening) {
Write-Log "Backend API already listening on $apiPort"
} else {
Write-Log "Starting backend API on $apiPort ..."
$apiLog = Join-Path $LogDir "api.log"
Start-Process powershell `
-WindowStyle Hidden `
-ArgumentList @(
"-NoProfile", "-ExecutionPolicy", "Bypass",
"-Command",
"Set-Location '$Backend'; .\venv\Scripts\Activate.ps1; python -m uvicorn app.main:app --host 0.0.0.0 --port $apiPort 2>&1 | Out-File -Append '$apiLog' -Encoding UTF8"
)
Write-Log "Backend API starting (log: $apiLog)"
}
# ── 3) Celery Worker ──────────────────────────
Write-Log "Starting Celery worker ..."
$celeryLog = Join-Path $LogDir "celery.log"
Start-Process powershell `
-WindowStyle Hidden `
-ArgumentList @(
"-NoProfile", "-ExecutionPolicy", "Bypass",
"-Command",
"Set-Location '$Backend'; .\venv\Scripts\Activate.ps1; python -m celery -A app.core.celery_app worker --loglevel=info --pool=threads --concurrency=8 2>&1 | Out-File -Append '$celeryLog' -Encoding UTF8"
)
Write-Log "Celery worker starting (log: $celeryLog)"
# ── 3.5) Celery Beat (scheduler) ──────────────
Write-Log "Starting Celery Beat ..."
$beatLog = Join-Path $LogDir "celery_beat.log"
Start-Process powershell `
-WindowStyle Hidden `
-ArgumentList @(
"-NoProfile", "-ExecutionPolicy", "Bypass",
"-Command",
"Set-Location '$Backend'; .\venv\Scripts\Activate.ps1; python -m celery -A app.core.celery_app beat --loglevel=info 2>&1 | Out-File -Append '$beatLog' -Encoding UTF8"
)
Write-Log "Celery Beat starting (log: $beatLog)"
# ── 4) Frontend (pnpm dev) ────────────────────
$frontendPort = 3001
$frontendListening = netstat -ano | Select-String ":$frontendPort\s+.*LISTENING"
if ($frontendListening) {
Write-Log "Frontend already listening on $frontendPort"
} else {
Write-Log "Starting frontend on $frontendPort ..."
$frontendLog = Join-Path $LogDir "frontend.log"
Start-Process powershell `
-WindowStyle Hidden `
-ArgumentList @(
"-NoProfile", "-ExecutionPolicy", "Bypass",
"-Command",
"`$env:AIAGENT_API_PROXY='http://127.0.0.1:$apiPort'; Set-Location '$Frontend'; pnpm dev --port $frontendPort 2>&1 | Out-File -Append '$frontendLog' -Encoding UTF8"
)
Write-Log "Frontend starting (log: $frontendLog)"
}
Write-Log "========== All services issued =========="
Write-Log "Frontend: http://localhost:$frontendPort"
Write-Log "API docs: http://127.0.0.1:$apiPort/docs"

View File

@@ -1,219 +0,0 @@
@echo off
echo ==============================================
echo 天工智能体平台 - Windows 启动脚本
echo ==============================================
echo.
REM 检查Python是否安装
python --version >nul 2>&1
if errorlevel 1 (
echo ❌ Python 未安装或未添加到系统PATH
echo 请安装 Python 3.11+ 并确保在PATH中
pause
exit /b 1
)
REM 检查Node.js是否安装
node --version >nul 2>&1
if errorlevel 1 (
echo ❌ Node.js 未安装或未添加到系统PATH
echo 请安装 Node.js 18+ 并确保在PATH中
pause
exit /b 1
)
REM 检查pnpm是否安装
pnpm --version >nul 2>&1
if errorlevel 1 (
echo ⚠️ pnpm 未安装,正在安装...
npm install -g pnpm
if errorlevel 1 (
echo ❌ pnpm 安装失败
pause
exit /b 1
)
)
echo ✅ 环境检查通过
echo.
REM 进入项目目录
cd /d "%~dp0"
echo ==============================================
echo 1. Redis 检查
echo ==============================================
echo.
REM 检查Redis服务是否运行
sc query Redis >nul 2>&1
if errorlevel 1 (
echo ❌ Redis 服务未运行
echo.
echo 请按以下步骤安装Redis
echo 1. 下载 Redis Windows 版本https://github.com/microsoftarchive/redis/releases
echo 2. 下载 Redis-x64-3.2.100.msi
echo 3. 运行安装程序,按照默认设置安装
echo 4. Redis 将作为 Windows 服务运行在 6379 端口
echo.
echo 安装完成后,请重新运行此脚本
pause
exit /b 1
) else (
echo ✅ Redis 服务正在运行
)
echo ==============================================
echo 2. 启动后端服务
echo ==============================================
echo.
REM 进入backend目录
cd backend
REM 检查虚拟环境
if not exist "venv\Scripts\activate" (
echo ⚠️ 虚拟环境不存在,正在创建...
python -m venv venv
if errorlevel 1 (
echo ❌ 虚拟环境创建失败
pause
exit /b 1
)
)
echo ✅ 虚拟环境检查通过
REM 激活虚拟环境并安装依赖
call venv\Scripts\activate
echo 📦 检查Python依赖...
pip list | findstr "fastapi" >nul
if errorlevel 1 (
echo ⚠️ 正在安装Python依赖...
pip install -r requirements.txt
if errorlevel 1 (
echo ❌ Python依赖安装失败
pause
exit /b 1
)
echo ✅ Python依赖安装完成
) else (
echo ✅ Python依赖已安装
)
echo.
echo 🔧 配置环境变量...
if not exist ".env" (
copy env.example .env >nul
echo ⚠️ 已创建 .env 文件,请检查配置
)
echo.
echo 🗄️ 运行数据库迁移...
alembic upgrade head
if errorlevel 1 (
echo ⚠️ 数据库迁移失败,继续启动...
)
echo.
echo 🌐 启动后端服务...
echo 后端服务将在 http://localhost:8037 启动
echo API文档http://localhost:8037/docs
echo.
start cmd /k "uvicorn app.main:app --host 0.0.0.0 --port 8037 --reload"
echo ⏳ 等待后端服务启动...
timeout /t 3 /nobreak >nul
echo.
echo ==============================================
echo 3. 启动 Celery Worker
echo ==============================================
echo.
echo 🔄 启动 Celery Worker...
start cmd /k "celery -A app.core.celery_app worker --loglevel=info"
echo ⏳ 等待 Celery Worker 启动...
timeout /t 2 /nobreak >nul
echo.
echo ==============================================
echo 4. 启动前端服务
echo ==============================================
echo.
REM 返回项目根目录
cd ..
REM 进入frontend目录
cd frontend
echo 📦 检查前端依赖...
if not exist "node_modules" (
echo ⚠️ 正在安装前端依赖...
pnpm install
if errorlevel 1 (
echo ❌ 前端依赖安装失败
pause
exit /b 1
)
echo ✅ 前端依赖安装完成
) else (
echo ✅ 前端依赖已安装
)
echo.
echo 🖥️ 启动前端服务...
echo 前端服务将在 http://localhost:3000 启动
echo.
start cmd /k "pnpm dev"
echo ⏳ 等待前端服务启动...
timeout /t 5 /nobreak >nul
echo.
echo ==============================================
echo 🎉 启动完成!
echo ==============================================
echo.
echo 服务访问地址:
echo 📍 前端界面: http://localhost:3000
echo 📍 后端API: http://localhost:8037
echo 📍 API文档: http://localhost:8037/docs
echo.
echo 服务状态:
echo ✅ Redis 服务: 运行中
echo ✅ 后端服务: 已启动
echo ✅ Celery Worker: 已启动
echo ✅ 前端服务: 已启动
echo.
echo 📋 重要提示:
echo 1. 首次访问需要注册新用户
echo 2. 保持所有命令行窗口打开
echo 3. 停止服务:关闭所有命令行窗口
echo.
echo ==============================================
echo.
REM 返回项目根目录
cd ..
echo 按任意键打开浏览器访问前端界面...
pause >nul
start http://localhost:3000
echo.
echo 脚本执行完成!
echo 按任意键退出...
pause >nul

View File

@@ -1,239 +0,0 @@
# 天工智能体平台 - Windows PowerShell 启动脚本
Write-Host "==============================================" -ForegroundColor Cyan
Write-Host "天工智能体平台 - Windows 启动脚本" -ForegroundColor Cyan
Write-Host "==============================================" -ForegroundColor Cyan
Write-Host ""
# 检查Python是否安装
try {
$pythonVersion = python --version 2>&1
Write-Host "✅ Python 版本: $pythonVersion" -ForegroundColor Green
} catch {
Write-Host "❌ Python 未安装或未添加到系统PATH" -ForegroundColor Red
Write-Host "请安装 Python 3.11+ 并确保在PATH中"
pause
exit 1
}
# 检查Node.js是否安装
try {
$nodeVersion = node --version
Write-Host "✅ Node.js 版本: $nodeVersion" -ForegroundColor Green
} catch {
Write-Host "❌ Node.js 未安装或未添加到系统PATH" -ForegroundColor Red
Write-Host "请安装 Node.js 18+ 并确保在PATH中"
pause
exit 1
}
# 检查pnpm是否安装
try {
$pnpmVersion = pnpm --version
Write-Host "✅ pnpm 版本: $pnpmVersion" -ForegroundColor Green
} catch {
Write-Host "⚠️ pnpm 未安装,正在安装..." -ForegroundColor Yellow
npm install -g pnpm
if ($LASTEXITCODE -ne 0) {
Write-Host "❌ pnpm 安装失败" -ForegroundColor Red
pause
exit 1
}
Write-Host "✅ pnpm 安装成功" -ForegroundColor Green
}
Write-Host "✅ 环境检查通过" -ForegroundColor Green
Write-Host ""
# 设置项目目录
$projectRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
Set-Location $projectRoot
Write-Host "==============================================" -ForegroundColor Cyan
Write-Host "1. Redis 检查" -ForegroundColor Cyan
Write-Host "==============================================" -ForegroundColor Cyan
Write-Host ""
# 检查Redis服务是否运行
$redisService = Get-Service -Name "Redis" -ErrorAction SilentlyContinue
if ($null -eq $redisService -or $redisService.Status -ne "Running") {
Write-Host "❌ Redis 服务未运行" -ForegroundColor Red
Write-Host ""
Write-Host "请按以下步骤安装Redis" -ForegroundColor Yellow
Write-Host "1. 下载 Redis Windows 版本https://github.com/microsoftarchive/redis/releases"
Write-Host "2. 下载 Redis-x64-3.2.100.msi"
Write-Host "3. 运行安装程序,按照默认设置安装"
Write-Host "4. Redis 将作为 Windows 服务运行在 6379 端口"
Write-Host ""
Write-Host "安装完成后,请重新运行此脚本" -ForegroundColor Yellow
pause
exit 1
} else {
Write-Host "✅ Redis 服务正在运行 (状态: $($redisService.Status))" -ForegroundColor Green
}
Write-Host ""
Write-Host "==============================================" -ForegroundColor Cyan
Write-Host "2. 启动后端服务" -ForegroundColor Cyan
Write-Host "==============================================" -ForegroundColor Cyan
Write-Host ""
# 进入backend目录
Set-Location "$projectRoot\backend"
# 检查虚拟环境
if (-not (Test-Path "venv\Scripts\activate")) {
Write-Host "⚠️ 虚拟环境不存在,正在创建..." -ForegroundColor Yellow
python -m venv venv
if ($LASTEXITCODE -ne 0) {
Write-Host "❌ 虚拟环境创建失败" -ForegroundColor Red
pause
exit 1
}
Write-Host "✅ 虚拟环境创建成功" -ForegroundColor Green
}
Write-Host "✅ 虚拟环境检查通过" -ForegroundColor Green
# 激活虚拟环境
$activateScript = "$projectRoot\backend\venv\Scripts\Activate.ps1"
if (Test-Path $activateScript) {
& $activateScript
} else {
Write-Host "❌ 虚拟环境激活脚本不存在: $activateScript" -ForegroundColor Red
pause
exit 1
}
Write-Host "📦 检查Python依赖..." -ForegroundColor Cyan
$fastapiInstalled = pip list | Select-String "fastapi"
if (-not $fastapiInstalled) {
Write-Host "⚠️ 正在安装Python依赖..." -ForegroundColor Yellow
pip install -r requirements.txt
if ($LASTEXITCODE -ne 0) {
Write-Host "❌ Python依赖安装失败" -ForegroundColor Red
pause
exit 1
}
Write-Host "✅ Python依赖安装完成" -ForegroundColor Green
} else {
Write-Host "✅ Python依赖已安装" -ForegroundColor Green
}
Write-Host ""
Write-Host "🔧 配置环境变量..." -ForegroundColor Cyan
if (-not (Test-Path ".env")) {
Copy-Item env.example .env -ErrorAction SilentlyContinue
Write-Host "⚠️ 已创建 .env 文件,请检查配置" -ForegroundColor Yellow
}
Write-Host ""
Write-Host "🗄️ 运行数据库迁移..." -ForegroundColor Cyan
alembic upgrade head
if ($LASTEXITCODE -ne 0) {
Write-Host "⚠️ 数据库迁移失败,继续启动..." -ForegroundColor Yellow
}
Write-Host ""
Write-Host "🌐 启动后端服务..." -ForegroundColor Cyan
Write-Host "后端服务将在 http://localhost:8037 启动" -ForegroundColor Green
Write-Host "API文档http://localhost:8037/docs" -ForegroundColor Green
Write-Host ""
# 启动后端服务(新窗口)
Start-Process powershell -ArgumentList "-NoExit", "-Command", "cd '$projectRoot\backend'; .\venv\Scripts\Activate.ps1; uvicorn app.main:app --host 0.0.0.0 --port 8037 --reload"
Write-Host "⏳ 等待后端服务启动..." -ForegroundColor Cyan
Start-Sleep -Seconds 3
Write-Host ""
Write-Host "==============================================" -ForegroundColor Cyan
Write-Host "3. 启动 Celery Worker" -ForegroundColor Cyan
Write-Host "==============================================" -ForegroundColor Cyan
Write-Host ""
Write-Host "🔄 启动 Celery Worker..." -ForegroundColor Cyan
# Windows 下 prefork 池易卡住任务Redis 出现大量 unacked使用线程池更稳定
Start-Process powershell -ArgumentList "-NoExit", "-Command", "cd '$projectRoot\backend'; .\venv\Scripts\Activate.ps1; celery -A app.core.celery_app worker --loglevel=info --pool=threads --concurrency=8"
Write-Host "⏳ 等待 Celery Worker 启动..." -ForegroundColor Cyan
Start-Sleep -Seconds 2
Write-Host ""
Write-Host "==============================================" -ForegroundColor Cyan
Write-Host "4. 启动前端服务" -ForegroundColor Cyan
Write-Host "==============================================" -ForegroundColor Cyan
Write-Host ""
# 返回项目根目录
Set-Location $projectRoot
# 进入frontend目录
Set-Location "$projectRoot\frontend"
Write-Host "📦 检查前端依赖..." -ForegroundColor Cyan
if (-not (Test-Path "node_modules")) {
Write-Host "⚠️ 正在安装前端依赖..." -ForegroundColor Yellow
pnpm install
if ($LASTEXITCODE -ne 0) {
Write-Host "❌ 前端依赖安装失败" -ForegroundColor Red
pause
exit 1
}
Write-Host "✅ 前端依赖安装完成" -ForegroundColor Green
} else {
Write-Host "✅ 前端依赖已安装" -ForegroundColor Green
}
Write-Host ""
Write-Host "🖥️ 启动前端服务..." -ForegroundColor Cyan
Write-Host "前端服务将在 http://localhost:3000 启动" -ForegroundColor Green
Write-Host ""
# 启动前端服务(新窗口)
Start-Process powershell -ArgumentList "-NoExit", "-Command", "cd '$projectRoot\frontend'; pnpm dev"
Write-Host "⏳ 等待前端服务启动..." -ForegroundColor Cyan
Start-Sleep -Seconds 5
Write-Host ""
Write-Host "==============================================" -ForegroundColor Cyan
Write-Host "🎉 启动完成!" -ForegroundColor Green
Write-Host "==============================================" -ForegroundColor Cyan
Write-Host ""
Write-Host "服务访问地址:" -ForegroundColor White
Write-Host " 📍 前端界面: http://localhost:3000" -ForegroundColor Yellow
Write-Host " 📍 后端API: http://localhost:8037" -ForegroundColor Yellow
Write-Host " 📍 API文档: http://localhost:8037/docs" -ForegroundColor Yellow
Write-Host ""
Write-Host "服务状态:" -ForegroundColor White
Write-Host " ✅ Redis 服务: 运行中" -ForegroundColor Green
Write-Host " ✅ 后端服务: 已启动" -ForegroundColor Green
Write-Host " ✅ Celery Worker: 已启动" -ForegroundColor Green
Write-Host " ✅ 前端服务: 已启动" -ForegroundColor Green
Write-Host ""
Write-Host "📋 重要提示:" -ForegroundColor White
Write-Host " 1. 首次访问需要注册新用户" -ForegroundColor Gray
Write-Host " 2. 保持所有PowerShell窗口打开" -ForegroundColor Gray
Write-Host " 3. 停止服务关闭所有PowerShell窗口" -ForegroundColor Gray
Write-Host ""
Write-Host "==============================================" -ForegroundColor Cyan
Write-Host ""
# 返回项目根目录
Set-Location $projectRoot
Write-Host "是否要打开浏览器访问前端界面?(Y/N)" -ForegroundColor Cyan
$response = Read-Host
if ($response -eq "Y" -or $response -eq "y") {
Start-Process "http://localhost:3000"
}
Write-Host ""
Write-Host "脚本执行完成!" -ForegroundColor Green
Write-Host "按任意键退出..." -ForegroundColor Gray
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

View File

@@ -1,96 +0,0 @@
$ErrorActionPreference = "SilentlyContinue"
Write-Host "== AIAgent stop ==" -ForegroundColor Cyan
function Get-PidsListeningOnPort([int]$Port) {
$pids = New-Object System.Collections.Generic.HashSet[int]
try {
# ForEach-Object 里写 return 会从「外层函数」返回,不能只跳过当前行。
foreach ($raw in (netstat -ano)) {
$ln = $raw.Trim()
if ($ln -notmatch "LISTENING") { continue }
$norm = $ln -replace '\s+', ' '
$parts = $norm.Split(' ')
if ($parts.Length -lt 5) { continue }
$local = $parts[1]
$ci = $local.LastIndexOf(':')
if ($ci -lt 0) { continue }
if ($local.Substring($ci + 1) -ne "$Port") { continue }
$pidStr = $parts[$parts.Length - 1]
if ($pidStr -match '^\d+$') {
$procId = [int]$pidStr
if ($procId -gt 4) { [void]$pids.Add($procId) }
}
}
} catch { }
return @($pids)
}
function Stop-OnPorts([int[]]$ports, [string]$name) {
$all = New-Object System.Collections.Generic.HashSet[int]
foreach ($p in $ports) {
foreach ($listenPid in (Get-PidsListeningOnPort $p)) {
[void]$all.Add($listenPid)
}
}
if ($all.Count -eq 0) {
Write-Host "[SKIP] ${name}: no listener on ports $($ports -join ',')" -ForegroundColor DarkGray
return
}
foreach ($procId in $all) {
if ($procId -le 4) { continue }
try {
Stop-Process -Id $procId -Force -ErrorAction SilentlyContinue
Write-Host "[OK] stopped ${name} PID=$procId" -ForegroundColor Green
} catch {
Write-Host "[WARN] failed to stop ${name} PID=$procId" -ForegroundColor Yellow
}
}
}
# 后端 API8037 / 8041 备用)
Stop-OnPorts @(8037, 8041) "backend-api"
# 前端 Vite3001
Stop-OnPorts @(3001) "frontend-dev"
# Redis6379仅当监听在本地开发端口时结束若与其它项目共用请谨慎
Stop-OnPorts @(6379) "redis"
# Celery Worker / Beat不监听端口需要按命令行匹配
$celeryPatterns = @(
@{Pattern='celery\s+-A\s+app\.core\.celery_app\s+worker'; Name='celery-worker'},
@{Pattern='celery\s+-A\s+app\.core\.celery_app\s+beat'; Name='celery-beat'}
)
foreach ($cp in $celeryPatterns) {
$targets = Get-CimInstance Win32_Process | Where-Object {
$_.CommandLine -and $_.CommandLine -match $cp.Pattern
}
if (-not $targets) {
Write-Host "[SKIP] $($cp.Name): no matching process" -ForegroundColor DarkGray
}
foreach ($p in $targets) {
try {
Stop-Process -Id $p.ProcessId -Force -ErrorAction SilentlyContinue
Write-Host "[OK] stopped $($cp.Name) PID=$($p.ProcessId)" -ForegroundColor Green
} catch {
Write-Host "[WARN] failed to stop $($cp.Name) PID=$($p.ProcessId)" -ForegroundColor Yellow
}
}
}
Start-Sleep -Milliseconds 600
Write-Host ""
Write-Host "Port check:" -ForegroundColor Cyan
foreach ($port in 3001, 8037, 8041, 6379) {
$line = netstat -ano | Select-String ":$port\s+.*LISTENING" | Select-Object -First 1
if ($line) {
Write-Host " - ${port}: LISTEN" -ForegroundColor Yellow
} else {
Write-Host " - ${port}: free" -ForegroundColor Green
}
}
Write-Host ""
Write-Host "DONE: stop script finished" -ForegroundColor Green