| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452 |
- # 程序的主入口
- # 承担服务器容器+程序作用
- # 服务器容器:提供http容器服务,程序放置于该容器中运行
- # 程序:本体-智能瞭望与智能问数系统 B/s架构
- import os
- import sys
- import tornado.ioloop
- import tornado.web
- from tornado.httpserver import HTTPServer
- # from app.controllers.base import BaseHandler
- # 引入auth - controller层
- from app.controllers.auth import LoginHandler,LogoutHandler
- from app.controllers.home import IndexHandler, DashboardHandler, DashboardApiHandler
- from app.controllers.user import UserPageHandler, UserApiHandler
- from app.controllers.menu import MenuPageHandler, MenuApiHandler
- from app.controllers.role import RolePageHandler, RoleApiHandler
- from app.controllers.model_engine import ModelEnginePageHandler, ModelEngineApiHandler, ModelTestApiHandler
- from app.controllers.spy_source import SpySourcePageHandler, SpySourceApiHandler
- from app.controllers.data_warehouse import DataWarehousePageHandler, DataWarehouseApiHandler, DataWarehouseDeepCrawlSseHandler
- from app.controllers.spy import SpyPageHandler, SpyRunApiHandler, SpyCommitApiHandler
- from app.controllers.api_manage import ApiManagePageHandler, ApiManageApiHandler, ApiInterfaceProxyHandler
- from app.controllers.digital_employee import DigitalEmployeePageHandler, DigitalEmployeeApiHandler, DigitalEmployeeChatApiHandler
- from app.controllers.chat_admin import ChatSessionsAdminPageHandler, ChatSessionsAdminApiHandler, ChatMessagesAdminPageHandler, ChatMessagesAdminApiHandler
- from app.controllers.skill_manage import SkillManagePageHandler, SkillManageApiHandler
- from app.controllers.portal import PortalRootHandler, PortalLoginHandler, PortalRegisterHandler, PortalChatPageHandler, PortalLogoutHandler, PortalModelsApiHandler, PortalEmployeesApiHandler, PortalSessionsApiHandler, PortalMessagesApiHandler, PortalChatStreamApiHandler, PortalAudioProxyHandler
- # 引入db - model层
- from app.models.db import init_db, get_connection
- from app.models.user import UserRepository
- from app.models.role import RoleRepository
- from app.models.menu import MenuRepository
- try:
- if hasattr(sys.stdout, "reconfigure"):
- sys.stdout.reconfigure(encoding="utf-8", errors="replace")
- if hasattr(sys.stderr, "reconfigure"):
- sys.stderr.reconfigure(encoding="utf-8", errors="replace")
- except Exception:
- pass
- # class HealthHandler(tornado.web.RequestHandler):
- # def get(self):
- # self.write({"status":"ok"})
- # class LoginHandler(tornado.web.RequestHandler):
- # def get(self):
- # self.write(f"""<h3>模拟登录验证测试BaesHandler</h3>
- # <form method="post">
-
- # <button type="submit">登录admin</button>
- # """
- # + self.xsrf_form_html() +
- # """
- # </form>
- # """)
- # def post(self):
- # next_url = self.get_argument("next","/private")
- # self.set_secure_cookie("username","admin")
- # # 写完安全的cookie以后,跳转到目标地址
- # self.redirect(next_url)
- # class PrivateHandler(BaseHandler):
- # @tornado.web.authenticated
- # def get(self):
- # self.write(self.current_user)
- def make_app():
- # return tornado.web.Application([
- # ("/abc",HealthHandler),
- # ("/login.jsp",HealthHandler),
- # ("/",HealthHandler),
- # ("/login.php",HealthHandler)
- # ],debug=True)
- # return tornado.web.Application([
- # (r"/",LoginHandler),
- # (r"/login",LoginHandler),
- # (r"/abc",HealthHandler),
- # (r"/private",PrivateHandler)
- # ],
- # cookie_secret="demo-cookie-secret-change-me",
- # login_url="/",
- # xsrf_cookies=True,
- # debug=True
- # )
- base_url = os.path.dirname(os.path.abspath(__file__))
- settings = dict(
- # 预留view 层的内容配置
- template_path=os.path.join(base_url,"app","templates"),
- static_path=os.path.join(base_url,"app","static"),
- cookie_secret="demo-cookie-secret-change-me",
- login_url="/admin/login",
- xsrf_cookies=True,
- debug=True,
- autoreload=True
- )
- return tornado.web.Application([
- (r"/", PortalRootHandler),
- (r"/login", PortalLoginHandler),
- (r"/register", PortalRegisterHandler),
- (r"/chat", PortalChatPageHandler),
- (r"/logout", PortalLogoutHandler),
- (r"/api/models", PortalModelsApiHandler),
- (r"/api/employees", PortalEmployeesApiHandler),
- (r"/api/sessions", PortalSessionsApiHandler),
- (r"/api/messages", PortalMessagesApiHandler),
- (r"/api/chat/stream", PortalChatStreamApiHandler),
- (r"/api/audio_proxy", PortalAudioProxyHandler),
- (r"/u/?", tornado.web.RedirectHandler, {"url": "/"}),
- (r"/u/login", tornado.web.RedirectHandler, {"url": "/login"}),
- (r"/u/register", tornado.web.RedirectHandler, {"url": "/register"}),
- (r"/u/chat", tornado.web.RedirectHandler, {"url": "/chat"}),
- (r"/u/logout", tornado.web.RedirectHandler, {"url": "/logout"}),
- (r"/api/u/models", tornado.web.RedirectHandler, {"url": "/api/models"}),
- (r"/api/u/employees", tornado.web.RedirectHandler, {"url": "/api/employees"}),
- (r"/api/u/sessions", tornado.web.RedirectHandler, {"url": "/api/sessions"}),
- (r"/api/u/messages", tornado.web.RedirectHandler, {"url": "/api/messages"}),
- (r"/api/u/chat/stream", tornado.web.RedirectHandler, {"url": "/api/chat/stream"}),
- (r"/admin/?", IndexHandler),
- (r"/admin/login", LoginHandler),
- (r"/admin/logout", LogoutHandler),
- (r"/admin/dashboard", DashboardHandler),
- (r"/dashboard", DashboardHandler),
- (r"/api/dashboard", DashboardApiHandler),
- (r"/auth/login", LoginHandler),
- (r"/auth/logout", LogoutHandler),
- (r"/user/list", UserPageHandler),
- (r"/api/user", UserApiHandler),
- (r"/menu/list", MenuPageHandler),
- (r"/api/menu", MenuApiHandler),
- (r"/role/list", RolePageHandler),
- (r"/api/role", RoleApiHandler),
- (r"/model_engine/list", ModelEnginePageHandler),
- (r"/api/model_engine", ModelEngineApiHandler),
- (r"/api/model_engine/test", ModelTestApiHandler),
- # 瞭望数据源管理路由
- (r"/spy_source/list", SpySourcePageHandler),
- (r"/api/spy_source", SpySourceApiHandler),
- # 数据仓库路由
- (r"/data_warehouse/list", DataWarehousePageHandler),
- (r"/api/data_warehouse", DataWarehouseApiHandler),
- (r"/api/data_warehouse/deep_sse", DataWarehouseDeepCrawlSseHandler),
- # 独立瞭望采集界面路由
- (r"/spy", SpyPageHandler),
- (r"/api/spy/run", SpyRunApiHandler),
- (r"/api/spy/commit", SpyCommitApiHandler),
- # 接口管理
- (r"/api_manage/list", ApiManagePageHandler),
- (r"/api/api_manage", ApiManageApiHandler),
- (r"/api/interface_proxy", ApiInterfaceProxyHandler),
- # 数字员工
- (r"/digital_employee/list", DigitalEmployeePageHandler),
- (r"/api/digital_employee", DigitalEmployeeApiHandler),
- (r"/api/digital_employee/chat", DigitalEmployeeChatApiHandler),
- # 技能管理
- (r"/skill_manage/list", SkillManagePageHandler),
- (r"/api/skill_manage", SkillManageApiHandler),
- # 用户侧会话/对话管理(后台)
- (r"/chat_admin/sessions", ChatSessionsAdminPageHandler),
- (r"/api/chat_admin/sessions", ChatSessionsAdminApiHandler),
- (r"/chat_admin/messages", ChatMessagesAdminPageHandler),
- (r"/api/chat_admin/messages", ChatMessagesAdminApiHandler),
- ],
- **settings
- )
- if __name__ == "__main__":
- # 启动服务之前,检查并初始化数据库表
- init_db()
-
- # 注入默认超管角色
- roles = RoleRepository.get_all_roles()
- super_role_id = None
- for r in roles:
- if r['code'] == 'super_admin':
- super_role_id = r['id']
- break
- if not super_role_id:
- super_role_id = RoleRepository.create_role("超级管理员", "super_admin", is_system=1)
- user_role = RoleRepository.get_by_code("user")
- user_role_id = user_role["id"] if user_role else RoleRepository.create_role("普通用户", "user", is_system=1)
- member_role = RoleRepository.get_by_code("member")
- if not member_role:
- RoleRepository.create_role("会员用户", "member", is_system=1)
-
- # 注入默认菜单
- menus = MenuRepository.get_all_menus()
- if not menus:
- sys_id = MenuRepository.create_menu("系统管理", "", "layui-icon-set", 0, 1)
- MenuRepository.create_menu("用户管理", "/user/list", "layui-icon-user", sys_id, 1)
- MenuRepository.create_menu("角色管理", "/role/list", "layui-icon-group", sys_id, 2)
- MenuRepository.create_menu("功能管理", "/menu/list", "layui-icon-app", sys_id, 3)
- # 给超管赋权
- all_menus = MenuRepository.get_all_menus()
- RoleRepository.assign_role_menus(super_role_id, [m['id'] for m in all_menus])
- # 注入默认管理员
- admin_user = UserRepository.get_user_by_username("admin")
- if not admin_user:
- UserRepository.create_user("admin", "admin888", super_role_id)
- else:
- # 确保已存在的 admin 绑定了超管角色
- with get_connection() as conn:
- conn.execute("INSERT OR IGNORE INTO user_roles (user_id, role_id) VALUES (?, ?)", (admin_user['id'], super_role_id))
-
- with get_connection() as conn:
- # 插入默认菜单
- conn.execute("INSERT OR IGNORE INTO menus (id, parent_id, name, icon, url, order_num) VALUES (?, ?, ?, ?, ?, ?)", (5, 0, '模型引擎', 'layui-icon-engine', '/model_engine/list', 5))
- conn.execute("INSERT OR IGNORE INTO menus (id, parent_id, name, icon, url, order_num) VALUES (?, ?, ?, ?, ?, ?)", (6, 0, '瞭望管理', 'layui-icon-find-fill', '', 6))
- conn.execute("INSERT OR IGNORE INTO menus (id, parent_id, name, icon, url, order_num) VALUES (?, ?, ?, ?, ?, ?)", (7, 6, '数据源管理', '', '/spy_source/list', 1))
- conn.execute("INSERT OR IGNORE INTO menus (id, parent_id, name, icon, url, order_num) VALUES (?, ?, ?, ?, ?, ?)", (8, 6, '瞭望采集', '', '/spy', 2))
- conn.execute("INSERT OR IGNORE INTO menus (id, parent_id, name, icon, url, order_num) VALUES (?, ?, ?, ?, ?, ?)", (9, 0, '数据仓库', 'layui-icon-table', '/data_warehouse/list', 7))
- api_parent_row = conn.execute("SELECT id FROM menus WHERE parent_id=0 AND name=?", ("接口服务",)).fetchone()
- if not api_parent_row:
- api_parent_row = conn.execute("SELECT id FROM menus WHERE parent_id=0 AND name=?", ("系统管理",)).fetchone()
- api_parent_id = api_parent_row["id"] if api_parent_row else 0
- api_row = conn.execute("SELECT id FROM menus WHERE url=?", ("/api_manage/list",)).fetchone()
- if not api_row:
- conn.execute(
- "INSERT OR IGNORE INTO menus (id, parent_id, name, icon, url, order_num) VALUES (?, ?, ?, ?, ?, ?)",
- (10, api_parent_id, '接口管理', 'layui-icon-link', '/api_manage/list', 8)
- )
- api_row = conn.execute("SELECT id FROM menus WHERE url=?", ("/api_manage/list",)).fetchone()
- if not api_row:
- cursor = conn.execute(
- "INSERT INTO menus (parent_id, name, icon, url, order_num) VALUES (?, ?, ?, ?, ?)",
- (api_parent_id, '接口管理', 'layui-icon-link', '/api_manage/list', 8)
- )
- api_menu_id = cursor.lastrowid
- else:
- api_menu_id = api_row["id"]
- api_current = conn.execute("SELECT name, icon FROM menus WHERE id=?", (api_menu_id,)).fetchone()
- if api_current:
- if not (api_current["name"] or "").strip():
- conn.execute("UPDATE menus SET name=? WHERE id=?", ('接口管理', api_menu_id))
- if not (api_current["icon"] or "").strip():
- conn.execute("UPDATE menus SET icon=? WHERE id=?", ('layui-icon-link', api_menu_id))
-
- # 确保超级管理员拥有上述菜单权限
- for mid in [5, 6, 7, 8, 9, api_menu_id]:
- conn.execute("INSERT OR IGNORE INTO role_menus (role_id, menu_id) VALUES (?, ?)", (super_role_id, mid))
- conn.execute(
- """
- INSERT OR IGNORE INTO api_endpoints
- (name, url, method, response_format, sample_request, qps_window, qps_max, bypass_token, remark, is_active, update_at)
- VALUES
- (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, current_timestamp)
- """,
- (
- "网易云随机音乐",
- "https://api.52vmy.cn/api/music/wy/rand",
- "GET",
- "JSON",
- "https://api.52vmy.cn/api/music/wy/rand",
- 2,
- 4,
- "",
- "",
- 1,
- ),
- )
- conn.execute(
- """
- INSERT OR IGNORE INTO api_endpoints
- (name, url, method, response_format, sample_request, qps_window, qps_max, bypass_token, remark, is_active, update_at)
- VALUES
- (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, current_timestamp)
- """,
- (
- "三日天气查询",
- "https://api.52vmy.cn/api/query/tian",
- "GET",
- "JSON",
- "https://api.52vmy.cn/api/query/tian?city=北京市",
- 2,
- 4,
- "",
- "点击前往三日天气API",
- 1,
- ),
- )
- service_row = conn.execute("SELECT id FROM menus WHERE parent_id=0 AND name=?", ("智能服务",)).fetchone()
- if not service_row:
- cursor = conn.execute(
- "INSERT INTO menus (parent_id, name, icon, url, order_num) VALUES (?, ?, ?, ?, ?)",
- (0, "智能服务", "layui-icon-component", "", 4)
- )
- service_menu_id = cursor.lastrowid
- else:
- service_menu_id = service_row["id"]
- de_row = conn.execute("SELECT id FROM menus WHERE url=?", ("/digital_employee/list",)).fetchone()
- if not de_row:
- cursor = conn.execute(
- "INSERT INTO menus (parent_id, name, icon, url, order_num) VALUES (?, ?, ?, ?, ?)",
- (service_menu_id, "数字员工", "layui-icon-username", "/digital_employee/list", 1)
- )
- de_menu_id = cursor.lastrowid
- else:
- de_menu_id = de_row["id"]
- conn.execute(
- "UPDATE menus SET name=?, icon=?, parent_id=?, order_num=? WHERE id=?",
- ("数字员工", "layui-icon-username", service_menu_id, 1, de_menu_id)
- )
- sess_row = conn.execute("SELECT id FROM menus WHERE url=?", ("/chat_admin/sessions",)).fetchone()
- if not sess_row:
- cursor = conn.execute(
- "INSERT INTO menus (parent_id, name, icon, url, order_num) VALUES (?, ?, ?, ?, ?)",
- (service_menu_id, "会话管理", "layui-icon-dialogue", "/chat_admin/sessions", 2)
- )
- sess_menu_id = cursor.lastrowid
- else:
- sess_menu_id = sess_row["id"]
- conn.execute(
- "UPDATE menus SET name=?, icon=?, parent_id=?, order_num=? WHERE id=?",
- ("会话管理", "layui-icon-dialogue", service_menu_id, 2, sess_menu_id)
- )
- msg_row = conn.execute("SELECT id FROM menus WHERE url=?", ("/chat_admin/messages",)).fetchone()
- if not msg_row:
- cursor = conn.execute(
- "INSERT INTO menus (parent_id, name, icon, url, order_num) VALUES (?, ?, ?, ?, ?)",
- (service_menu_id, "对话管理", "layui-icon-chat", "/chat_admin/messages", 3)
- )
- msg_menu_id = cursor.lastrowid
- else:
- msg_menu_id = msg_row["id"]
- conn.execute(
- "UPDATE menus SET name=?, icon=?, parent_id=?, order_num=? WHERE id=?",
- ("对话管理", "layui-icon-chat", service_menu_id, 3, msg_menu_id)
- )
- skill_row = conn.execute("SELECT id FROM menus WHERE url=?", ("/skill_manage/list",)).fetchone()
- if not skill_row:
- cursor = conn.execute(
- "INSERT INTO menus (parent_id, name, icon, url, order_num) VALUES (?, ?, ?, ?, ?)",
- (service_menu_id, "技能管理", "layui-icon-template-1", "/skill_manage/list", 4)
- )
- skill_menu_id = cursor.lastrowid
- else:
- skill_menu_id = skill_row["id"]
- conn.execute(
- "UPDATE menus SET name=?, icon=?, parent_id=?, order_num=? WHERE id=?",
- ("技能管理", "layui-icon-template-1", service_menu_id, 4, skill_menu_id)
- )
- conn.execute("INSERT OR IGNORE INTO role_menus (role_id, menu_id) VALUES (?, ?)", (super_role_id, service_menu_id))
- conn.execute("INSERT OR IGNORE INTO role_menus (role_id, menu_id) VALUES (?, ?)", (super_role_id, de_menu_id))
- conn.execute("INSERT OR IGNORE INTO role_menus (role_id, menu_id) VALUES (?, ?)", (super_role_id, sess_menu_id))
- conn.execute("INSERT OR IGNORE INTO role_menus (role_id, menu_id) VALUES (?, ?)", (super_role_id, msg_menu_id))
- conn.execute("INSERT OR IGNORE INTO role_menus (role_id, menu_id) VALUES (?, ?)", (super_role_id, skill_menu_id))
- music_api = conn.execute("SELECT id FROM api_endpoints WHERE url=? AND method='GET'", ("https://api.52vmy.cn/api/music/wy/rand",)).fetchone()
- weather_api = conn.execute("SELECT id FROM api_endpoints WHERE url=? AND method='GET'", ("https://api.52vmy.cn/api/query/tian",)).fetchone()
- conn.execute(
- """
- INSERT OR IGNORE INTO digital_employees
- (name, alias, category, description, ai_prompt, api_endpoint_id, api_param_name, is_active, update_at)
- VALUES
- (?, ?, ?, ?, ?, ?, ?, ?, current_timestamp)
- """,
- (
- "川小农",
- "川小农",
- "AI",
- "基于默认模型与 Prompt 的智能对话数字员工",
- "你是数字员工“川小农”。你以专业、克制、可执行的方式回答用户问题。你必须用中文输出。你会先给出结论,再给出清晰步骤与注意事项。遇到信息不足时,先提出最少的澄清点,然后给出可行的默认方案。",
- None,
- "",
- 1,
- ),
- )
- if weather_api:
- conn.execute(
- """
- INSERT OR IGNORE INTO digital_employees
- (name, alias, category, description, ai_prompt, api_endpoint_id, api_param_name, is_active, update_at)
- VALUES
- (?, ?, ?, ?, ?, ?, ?, ?, current_timestamp)
- """,
- (
- "天气",
- "天气",
- "NORMAL",
- "通过接口服务查询天气:@天气 北京市",
- "",
- int(weather_api["id"]),
- "city",
- 1,
- ),
- )
- if music_api:
- conn.execute(
- """
- INSERT OR IGNORE INTO digital_employees
- (name, alias, category, description, ai_prompt, api_endpoint_id, api_param_name, is_active, update_at)
- VALUES
- (?, ?, ?, ?, ?, ?, ?, ?, current_timestamp)
- """,
- (
- "音乐",
- "音乐",
- "NORMAL",
- "随机音乐卡片:@音乐",
- "",
- int(music_api["id"]),
- "",
- 1,
- ),
- )
- # 注入默认的百度新闻采集源
- baidu_source = conn.execute("SELECT id FROM spy_sources WHERE name='百度新闻'").fetchone()
- if not baidu_source:
- headers_str = """Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
- Accept-Encoding: gzip, deflate, br, zstd
- Accept-Language: zh-CN,zh;q=0.9
- Cache-Control: no-cache
- Connection: keep-alive
- Cookie: BIDUPSID=5CFCC8D701BF7571598CE9F66EE8E6B5; PSTM=1775407070; BD_UPN=1a314753; BAIDUID=5CFCC8D701BF75717E6B8B51D00D380F:SL=0:NR=10:FG=1;
- Host: www.baidu.com
- Pragma: no-cache
- Referer: https://news.baidu.com/
- Upgrade-Insecure-Requests: 1
- User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 QQBrowser/21.1.8743.400"""
-
- conn.execute(
- "INSERT INTO spy_sources (name, entry_url, request_headers, is_active) VALUES (?, ?, ?, ?)",
- ("百度新闻", "https://www.baidu.com/s?rtt=1&bsst=1&cl=2&tn=news&rsv_dl=ns_pc&word={关键字}&pn={分页步进}", headers_str, 1)
- )
-
- app = make_app()
- server = HTTPServer(app)
- server.bind(10088)
- # 自动CPU核心数
- server.start()
- try:
- print("====== Server 启动成功 ======== 端口:10088 ======", flush=True)
- except OSError:
- pass
- tornado.ioloop.IOLoop.current().start()
|