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:
118
scripts/create_rp_agents.py
Normal file
118
scripts/create_rp_agents.py
Normal 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
354
scripts/startup/manage.ps1
Normal 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 }
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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")
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 后端 API(8037 / 8041 备用)
|
||||
Stop-OnPorts @(8037, 8041) "backend-api"
|
||||
|
||||
# 前端 Vite(3001)
|
||||
Stop-OnPorts @(3001) "frontend-dev"
|
||||
|
||||
# Redis(6379,仅当监听在本地开发端口时结束;若与其它项目共用请谨慎)
|
||||
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
|
||||
Reference in New Issue
Block a user