zhaoqingang
2024-12-13 f2c43713b16e821f4a1ae97804c60f18734d5f6a
问题优化
20个文件已修改
9个文件已添加
619 ■■■■ 已修改文件
alembic/versions/1c4af61d72a5_dialog_id_to_36.py 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
alembic/versions/ba24e02a6610_menu_table_update.py 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
alembic/versions/ef06c24632a7_dialog_id_to_update.py 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/api/auth.py 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/api/dialog.py 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/api/role.py 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/api/user.py 33 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/init_config/__init__.py 补丁 | 查看 | 原始文档 | blame | 历史
app/init_config/init_run_data.py 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/models/dialog_model.py 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/models/knowledge_model.py 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/models/menu_model.py 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/models/role_model.py 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/models/token_model.py 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/models/user.py 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/models/user_model.py 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/service/auth.py 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/service/dialog.py 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/service/role.py 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/service/service_token.py 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/service/user.py 100 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/service/v2/initialize_data.py 53 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/task/fetch_agent.py 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/utils/password_handle.py 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
env_conf/api_key_conf.json 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
env_conf/app_register_conf.json 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
env_conf/default_agent_conf.json 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
env_conf/menu_conf.json 62 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main.py 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
alembic/versions/1c4af61d72a5_dialog_id_to_36.py
New file
@@ -0,0 +1,52 @@
"""dialog id to 36
Revision ID: 1c4af61d72a5
Revises: 0366cf835bba
Create Date: 2024-12-13 11:24:57.138214
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision: str = '1c4af61d72a5'
down_revision: Union[str, None] = '0366cf835bba'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.alter_column('dialogs', 'id',
               existing_type=mysql.VARCHAR(length=32),
               type_=sa.String(length=36),
               existing_nullable=False)
    op.alter_column('dialogs', 'agent_id',
               existing_type=mysql.VARCHAR(length=32),
               type_=sa.String(length=36),
               existing_nullable=True)
    op.alter_column('knowledgebase', 'id',
               existing_type=mysql.VARCHAR(length=32),
               type_=sa.String(length=36),
               existing_nullable=False)
    # ### end Alembic commands ###
def downgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.alter_column('knowledgebase', 'id',
               existing_type=sa.String(length=36),
               type_=mysql.VARCHAR(length=32),
               existing_nullable=False)
    op.alter_column('dialogs', 'agent_id',
               existing_type=sa.String(length=36),
               type_=mysql.VARCHAR(length=32),
               existing_nullable=True)
    op.alter_column('dialogs', 'id',
               existing_type=sa.String(length=36),
               type_=mysql.VARCHAR(length=32),
               existing_nullable=False)
    # ### end Alembic commands ###
alembic/versions/ba24e02a6610_menu_table_update.py
New file
@@ -0,0 +1,32 @@
"""menu table update
Revision ID: ba24e02a6610
Revises: ef06c24632a7
Create Date: 2024-12-13 17:19:35.020328
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = 'ba24e02a6610'
down_revision: Union[str, None] = 'ef06c24632a7'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.add_column('menu_capacity', sa.Column('chat_id', sa.String(length=36), nullable=True))
    op.add_column('menu_capacity', sa.Column('chat_type', sa.String(length=36), nullable=True))
    # ### end Alembic commands ###
def downgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_column('menu_capacity', 'chat_type')
    op.drop_column('menu_capacity', 'chat_id')
    # ### end Alembic commands ###
alembic/versions/ef06c24632a7_dialog_id_to_update.py
New file
@@ -0,0 +1,34 @@
"""dialog id to update
Revision ID: ef06c24632a7
Revises: 1c4af61d72a5
Create Date: 2024-12-13 16:18:18.486282
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = 'ef06c24632a7'
down_revision: Union[str, None] = '1c4af61d72a5'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.add_column('dialogs', sa.Column('mode', sa.String(length=36), nullable=True))
    op.add_column('user', sa.Column('sync_flag', sa.String(length=36), nullable=True))
    op.add_column('web_menu', sa.Column('rank', sa.Integer(), nullable=True))
    # ### end Alembic commands ###
def downgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_column('web_menu', 'rank')
    op.drop_column('user', 'sync_flag')
    op.drop_column('dialogs', 'mode')
    # ### end Alembic commands ###
app/api/auth.py
@@ -12,7 +12,7 @@
from app.models.app_token_model import AppToken
from app.models.base_model import get_db
from app.models.postgresql_base_model import get_pdb
from app.models.token_model import upsert_token
from app.models.token_model import upsert_token, update_token
from app.models.user import UserCreate, LoginData
from app.models.user_model import UserModel, UserAppModel
from app.service.auth import authenticate_user, create_access_token, is_valid_password, save_register_user, \
@@ -24,6 +24,7 @@
from app.service.ragflow import RagflowService
from sqlalchemy.future import select
from app.utils.password_handle import generate_password
router = APIRouter()
@@ -122,12 +123,14 @@
            continue
        try:
            name = login_data.username
            app_password = login_data.password
            user_app = await UserAppDao(db).get_data_by_id(user.id, app["id"])
            if user_app:
                name  = user_app.username
                app_password = user_app.decrypted_password(user_app.password)
            else:
                await update_user_info(db, user.id)
            token = await service.login(name, login_data.password)
            token = await service.login(name, app_password)
            token_dict[app["id"]] = token
        except Exception as e:
            return Response(code=500, msg=f"Failed to login with {app['id']}: {str(e)}")
@@ -135,7 +138,7 @@
    # 创建本地token
    access_token = create_access_token(data={"sub": user.username, "user_id": user.id})
    # await update_token(db, user.id, access_token, token_dict)
    await update_token(db, user.id, access_token, token_dict)
    await update_user_token(db, user.id, token_dict)
    result = await pdb.execute(select(AppToken).where(AppToken.id == user.id))
    db_app_token = result.scalars().first()
@@ -173,6 +176,7 @@
    app_register = AppRegisterDao(db).get_apps()
    register_dict = {}
    token = ""
    app_password = await generate_password(10)
    for app in app_register:
        if app["id"] == RAGFLOW:
            service = RagflowService(settings.fwr_base_url)
@@ -190,13 +194,20 @@
            continue
        try:
            name = app["id"] + str(int(time.time()))
            register_info = await service.register(name, user.password, token)
            register_info = await service.register(name, app_password, token)
            # print(register_info)
            register_dict[app['id']] = {"id":register_info.get("id"), "name": name, "email": register_info.get("email")}
        except Exception as e:
            return Response(code=500, msg=f"Failed to register with {app['id']}: {str(e)}")
    user_id = await save_register_user(db, user.username, user.password, user.email, register_dict)
    user_id = await save_register_user(db, user.username, user.password, user.email, app_password, register_dict)
    if not user_id:
        return Response(code=500, msg=f"Failed to register with app")
    is_update = await update_user_group(db, user_id)
    return Response(code=200, msg="User registered successfully",data={"username": user.username})
    return Response(code=200, msg="User registered successfully",data={"userFlag": user_id})
@router.get("/v2/sync", response_model=Response)
async def sync_user_tenant(userFlag: str, db=Depends(get_db)):
    app_register = AppRegisterDao(db).get_app_by_id(RAGFLOW)
    if app_register:
        is_update = await update_user_group(db, userFlag)
    return Response(code=200, msg="success", data={})
app/api/dialog.py
@@ -25,7 +25,7 @@
@dialog_router.post("/create", response_model=Response)
async def create_dialog_api(dialog: dialogData, current_user: UserModel = Depends(get_current_user), db=Depends(get_db)):
    is_create = await create_dialog_service(db, dialog.id, dialog.name, dialog.description, dialog.icon, dialog.dialogType, current_user.id)
    is_create = await create_dialog_service(db, dialog.id, dialog.name, dialog.description, dialog.icon, dialog.dialogType, dialog.mode,current_user.id)
    if not is_create:
        return Response(code=500, msg="role create failure", data={})
    return Response(code=200, msg="role create success", data={})
app/api/role.py
@@ -29,14 +29,14 @@
        return Response(code=500, msg="role create failure", data={})
    return Response(code=200, msg="role create successfully", data={"roleName": role.roleName})
@role_router.delete("/delete_role/{role_id}", response_model=Response)
async def delete_group(role_id: str, current_user: UserModel = Depends(get_current_user), db=Depends(get_db)):
    db_role = db.query(RoleModel).filter(RoleModel.id == role_id).first()
@role_router.delete("/delete_role/{roleId}", response_model=Response)
async def delete_group(roleId: str, current_user: UserModel = Depends(get_current_user), db=Depends(get_db)):
    db_role = db.query(RoleModel).filter(RoleModel.id == roleId).first()
    if not db_role:
        return Response(code=200, msg="role does not exist")
    if db_role.role_type ==2:
        return Response(code=400, msg="默认角色不允许删除!")
    is_edit = await delete_role_data(db, role_id)
    is_edit = await delete_role_data(db, roleId)
    if not is_edit:
        return Response(code=500, msg="role delete failure", data={})
    return Response(code=200, msg="role delete successfully", data={})
@@ -46,10 +46,10 @@
async def edit_group_status(role: RoleStatus, current_user: UserModel = Depends(get_current_user), db=Depends(get_db)):
    if role.status not in ["0", "1"]:
        return Response(code=400, msg="The status cannot be {}!".format(role.status))
    db_role = db.query(RoleModel).filter(RoleModel.id == role.role_id).first()
    db_role = db.query(RoleModel).filter(RoleModel.id == role.roleId).first()
    if not db_role:
        return Response(code=200, msg="role does not exist")
    is_edit = await edit_role_status(db, role.status,role.role_id)
    is_edit = await edit_role_status(db, role.status,role.roleId)
    if not is_edit:
        return Response(code=500, msg="role status edit failure", data={})
    return Response(code=200, msg="role status edit successfully", data={})
@@ -59,14 +59,14 @@
    if role.editType == 1:
        if not role.roleName:
            return Response(code=400, msg="The roleName cannot be empty!")
        db_role = db.query(RoleModel).filter(RoleModel.id == role.role_id).first()
        db_role = db.query(RoleModel).filter(RoleModel.id == role.roleId).first()
        if not db_role:
            return Response(code=200, msg="role does not exist")
        db_role = db.query(RoleModel).filter(RoleModel.name == role.roleName).first()
        if db_role and db_role.id != role.role_id:
        if db_role and db_role.id != role.roleId:
            return Response(code=200, msg="role already created")
    is_edit = await edit_role_resource(db, role.role_id,role.roleName, role.remark, role.roleKey, role.dataScope, role.resources, role.editType)
    is_edit = await edit_role_resource(db, role.roleId,role.roleName, role.remark, role.roleKey, role.dataScope, role.resources, role.editType)
    if not is_edit:
        return Response(code=500, msg="role edit failure", data={})
    return Response(code=200, msg="role edit successfully", data={})
app/api/user.py
@@ -1,12 +1,12 @@
from fastapi import APIRouter, Depends
from app.api import Response, pwd_context, get_current_user, ResponseList
from app.models.public_api_model import AppRegisterModel
from app.models.base_model import get_db
from app.models.user import PageParameter, UserStatus, UserInfo, LoginData
from app.models.user import PageParameter, UserStatus, UserInfo, LoginData, UserPassword
from app.models.user_model import UserModel
from app.service.auth import is_valid_password
from app.service.auth import is_valid_password, verify_password
from app.service.user import get_user_list, edit_user_status, delete_user_data, create_user, edit_user_data, \
    edit_user_pwd, get_user_info, get_user_routers, get_user_menus, get_user_permission, get_user_dept
    edit_user_pwd, get_user_info, get_user_routers, get_user_menus, get_user_permission, get_user_dept, change_user_pwd, \
    user_data_service
user_router = APIRouter()
@@ -86,6 +86,21 @@
    return Response(code=200, msg="user pwd reset successfully", data={})
@user_router.put("/change_password", response_model=Response)
async def change_user_password(user: UserPassword,  current_user: UserModel = Depends(get_current_user),db=Depends(get_db)):
    user_info = db.query(UserModel).filter(UserModel.id==current_user.id).first()
    if not user_info:
        return Response(code=401, msg="Incorrect change password !")
    if not verify_password(user.oldPassword, user_info.hashed_password):
        return Response(code=400, msg="Incorrect password !")
    if not is_valid_password(user.newPassword):
        return Response(code=400, msg="The password must be at least 8 and contain both numbers and letters")
    is_edit = await change_user_pwd(db, user_info.id, user.newPassword)
    if not is_edit:
        return Response(code=500, msg="user pwd change failure", data={})
    return Response(code=200, msg="user pwd change success", data={})
@user_router.get("/user_info", response_model=Response)
async def user_info(current_user: UserModel = Depends(get_current_user),db=Depends(get_db)):
    user_info = await get_user_info(db,  current_user.id)
@@ -119,4 +134,12 @@
@user_router.get("/dept", response_model=Response)
async def user_dept_api(userId:int, current_user: UserModel = Depends(get_current_user),db=Depends(get_db)):
    menus = await get_user_dept(db, userId)
    return Response(code=200, msg="successfully", data=menus)
    return Response(code=200, msg="successfully", data=menus)
@user_router.get("/user_data", response_model=Response)
async def user_data_api(userId, current_user: UserModel = Depends(get_current_user),db=Depends(get_db)):
    user_info = await user_data_service(db, userId)
    if not user_info:
        return Response(code=500, msg="user get failure", data={})
    return Response(code=200, msg="successfully", data=user_info)
app/init_config/__init__.py
app/init_config/init_run_data.py
New file
@@ -0,0 +1,14 @@
from app.models.base_model import SessionLocal
from app.service.v2.initialize_data import dialog_menu_sync, default_group_sync, default_role_sync, app_register_sync, \
    basic_agent_sync
async def sync_default_data():
    db = SessionLocal()
    await dialog_menu_sync(db)  # 小数
    await default_group_sync(db) # 默认组
    await default_role_sync(db) # 默认角色
    await app_register_sync(db) # 注册的应用
    await basic_agent_sync(db) # 开发的agent
    # await default_role_sync(db)  # 页面资源配置信息
    # await default_role_sync(db)  # 默认的角色资源
app/models/dialog_model.py
@@ -12,7 +12,7 @@
    __mapper_args__ = {
        # "order_by": 'SEQ'
    }
    id = Column(String(32), primary_key=True)  #  id
    id = Column(String(36), primary_key=True)  #  id
    create_date = Column(DateTime, default=datetime.now())             # 创建时间
    update_date = Column(DateTime, default=datetime.now(), onupdate=datetime.now())             # 更新时间
    tenant_id = Column(String(32))              # 创建人
@@ -20,8 +20,9 @@
    description = Column(Text)                 # 说明
    icon = Column(Text)                         # 图标
    status = Column(String(1), default="1")                 # 状态
    dialog_type = Column(String(1))            #    # 平台
    agent_id = Column(String(32))
    dialog_type = Column(String(1))            #  平台
    agent_id = Column(String(36))
    mode = Column(String(36))
    def get_id(self):
        return str(self.id)
@@ -38,6 +39,7 @@
            'status': self.status,
            'agentType': self.dialog_type,
            'agentId': self.agent_id,
            'mode': self.mode,
        }
@@ -73,6 +75,7 @@
    description: Optional[str] = ""
    dialogType: str
    icon: str
    mode: str
class dialogDataUpdate(BaseModel):
app/models/knowledge_model.py
@@ -13,7 +13,7 @@
    __mapper_args__ = {
        # "order_by": 'SEQ'
    }
    id = Column(String(32), primary_key=True)  # id
    id = Column(String(36), primary_key=True)  # id
    name = Column(String(128))                 # 名称
    create_date = Column(DateTime, default=datetime.now())             # 创建时间
    update_date = Column(DateTime, default=datetime.now(), onupdate=datetime.now())             # 更新时间
app/models/menu_model.py
@@ -12,6 +12,7 @@
    desc = Column(String(1000))
    icon = Column(String(16))
    img = Column(String(255))
    rank = Column(Integer)
    def to_dict(self):
@@ -36,4 +37,6 @@
    menu_id = Column(Integer)
    capacity_id = Column(String(36))
    capacity_type = Column(Integer)
    chat_id = Column(String(36))
    chat_type = Column(String(36))
app/models/role_model.py
@@ -90,12 +90,12 @@
class RoleStatus(BaseModel):
    role_id: str
    roleId: str
    status: constr(min_length=1, max_length=1, pattern='^(0|1)$')
class RoleEdit(BaseModel):
    role_id: str
    roleId: str
    remark: Optional[str] = ""
    roleName: Optional[str] = ""
    resources: Optional[list] = []
app/models/token_model.py
@@ -65,16 +65,16 @@
        if db_token:
            # 记录存在,进行更新
            db_token.token = access_token
            for k, v in token.items():
                setattr(db_token, k.replace("app", "token"), v)
            # for k, v in token.items():
            #     setattr(db_token, k.replace("app", "token"), v)
        else:
            # 记录不存在,进行插入
            db_token = TokenModel(
                user_id=user_id,
                token=access_token,
            )
            for k, v in token.items():
                setattr(db_token, k.replace("app", "token"), v)
            # for k, v in token.items():
            #     setattr(db_token, k.replace("app", "token"), v)
            db.add(db_token)
        # 提交事务
app/models/user.py
@@ -46,3 +46,10 @@
    groups: Optional[list] = []
class UserPassword(BaseModel):
    # userId: int
    newPassword: str
    oldPassword: str
app/models/user_model.py
@@ -39,6 +39,7 @@
    sex = Column(String(1))
    permission = Column(String(16), default="general")
    age = Column(Integer)
    sync_flag = Column(String(36))
    created_at = Column(DateTime, default=datetime.now())
    updated_at = Column(DateTime, default=datetime.now(), onupdate=datetime.now())
@@ -115,6 +116,7 @@
        for ogt in self.organizations:
            if ogt.id in ogt_set:
                continue
            print(ogt.id)
            ogt_set.add(ogt.id)
            for role in ogt.roles:
                roles[role.id] = role.to_dict()
@@ -122,9 +124,12 @@
            while parent_ogt:
                if parent_ogt.id not in ogt_set:
                    ogt_set.add(ogt.id)
                    for role in ogt.roles:
                    for role in parent_ogt.roles:
                        roles[role.id] = role.to_dict()
                    parent_ogt = ogt.parent
                    parent_ogt = parent_ogt.parent
                else:
                    break
        json['roles'] = list(roles.values())
        return json
@@ -220,9 +225,10 @@
            "app_type": self.app_type,
            'status': self.status,
        }
    def encrypted_password(self, password):
    @staticmethod
    def encrypted_password(password):
        return cipher_suite.encrypt(password.encode("utf-8")).decode("utf-8")
    def decrypted_password(self):
        return cipher_suite.decrypt(self.password).decode("utf-8")
    @staticmethod
    def decrypted_password(password):
        return cipher_suite.decrypt(password).decode("utf-8")
app/service/auth.py
@@ -1,6 +1,8 @@
import re
import uuid
from datetime import datetime, timedelta
from typing import Type
from uuid import uuid4
from jwt import encode, decode, exceptions
from passlib.context import CryptContext
@@ -69,12 +71,13 @@
    return has_digit is not None and has_letter is not None
async def save_register_user(db, username, password, email, register_dict):
async def save_register_user(db, username, password, email, app_password, register_dict):
    user_id = ""
    sync_flag = str(uuid.uuid4())
    try:
        hashed_password = pwd_context.hash(password)
        db_user = UserModel(username=username, hashed_password=hashed_password, email=email)
        pwd = db_user.encrypted_password(password)
        db_user = UserModel(username=username, hashed_password=hashed_password, email=email, sync_flag=sync_flag)
        pwd = db_user.encrypted_password(app_password)
        db_user.password = pwd
        db_user.roles = [db.query(RoleModel).filter(RoleModel.role_type == 2).first()]
        db_user.groups = [db.query(GroupModel).filter(GroupModel.group_type == 2).first()]
@@ -92,7 +95,7 @@
            db.query(UserModel).filter(UserModel.id == user_id).delete()
            db.commit
        return False
    return user_id
    return sync_flag
async def update_user_token(db, user_id, token_dict):
@@ -139,7 +142,7 @@
    # db.commit()
    # db.refresh(db_user)
    is_sava = await save_register_user(db, user.username, user.password, user.email, register_dict)
    # is_sava = await save_register_user(db, user.username, user.password, user.email, register_dict)
class UserAppDao:
    def __init__(self, db: Session):
app/service/dialog.py
@@ -90,9 +90,9 @@
async def create_dialog_service(db, dialog_id, dialog_name, description, icon, dialog_type, user_id):
async def create_dialog_service(db, dialog_id, dialog_name, description, icon, dialog_type, mode, user_id):
    try:
        dialog_model = DialogModel(id=dialog_id,name=dialog_name, description=description,icon=icon, dialog_type=dialog_type, tenant_id=user_id, agent_id=dialog_id)
        dialog_model = DialogModel(id=dialog_id,name=dialog_name, description=description,icon=icon, dialog_type=dialog_type, tenant_id=user_id, agent_id=dialog_id, mode=mode)
        db.add(dialog_model)
        db.commit()
        db.refresh(dialog_model)
app/service/role.py
@@ -12,9 +12,10 @@
    #     query.filter(RoleModel.creator==user_id)
    if keyword:
        query = query.filter(RoleModel.name.like('%{}%'.format(keyword)))
    total = query.count()
    roles = query.order_by(RoleModel.id.desc()).limit(page_size).offset(
        (page_index - 1) * page_size).all()
    return {"total": query.count(), "rows":  [role.to_json() for role in roles]}
    return {"total": total, "rows":  [role.to_json() for role in roles]}
async def create_role(db, role_name: str, description: str, role_key, data_scope, user_id):
app/service/service_token.py
@@ -11,24 +11,28 @@
async def get_bisheng_token(db, user_id: int):
    token = await UserAppDao(db).get_data_by_id(user_id, BISHENG)
    token = db.query(TokenModel).filter(TokenModel.user_id == user_id).first()
    if not token:
        token = db.query(TokenModel).filter(TokenModel.user_id == user_id).first()
        token = await UserAppDao(db).get_data_by_id(user_id, BISHENG)
        if not token:
            return None
    else:
        return token.access_token
    return token.bisheng_token
    else:
        return token.bisheng_token
async def get_ragflow_token(db, user_id: int):
    token = await UserAppDao(db).get_data_by_id(user_id, RAGFLOW)
    # token = await UserAppDao(db).get_data_by_id(user_id, RAGFLOW)
    token = db.query(TokenModel).filter(TokenModel.user_id == user_id).first()
    if not token:
        token = db.query(TokenModel).filter(TokenModel.user_id == user_id).first()
        token = await UserAppDao(db).get_data_by_id(user_id, RAGFLOW)
        if not token:
            return None
    else:
        return token.access_token
    return token.ragflow_token
    else:
        return token.ragflow_token
async def get_dify_token(db, user_id: int):
@@ -42,11 +46,12 @@
    user = db.query(UserAppModel).filter(UserAppModel.user_id == user_id, UserAppModel.app_type==app_type).first()
    if not user:
        return None
    pwd = user.password
    if app_type == RAGFLOW:
        ragflow_service = RagflowService(settings.fwr_base_url)
        # 登录到ragflow
        try:
            ragflow_token = await ragflow_service.login(user.username, user.decrypted_password())
            ragflow_token = await ragflow_service.login(user.username, user.decrypted_password(pwd))
            return ragflow_token
        except Exception as e:
            logger.error(e)
@@ -56,7 +61,7 @@
        bisheng_service = BishengService(settings.sgb_base_url)
        # 登录到毕昇
        try:
            bisheng_token = await bisheng_service.login(user.username, user.decrypted_password())
            bisheng_token = await bisheng_service.login(user.username, user.decrypted_password(pwd))
            return bisheng_token
        except Exception as e:
            logger.error(e)
@@ -67,7 +72,7 @@
        dify_service = DifyService(settings.dify_base_url)
        # 登录到毕昇
        try:
            dify_token = await dify_service.login(user.username, user.decrypted_password())
            dify_token = await dify_service.login(user.username, user.decrypted_password(pwd))
            return dify_token
        except Exception as e:
            logger.error(e)
@@ -86,15 +91,19 @@
    return res
async def update_user_group(db, user_id):
async def update_user_group(db, sync_flag):
    admin_user = db.query(UserModel).filter(UserModel.permission == "admin").first()
    sync_user = db.query(UserModel).filter(UserModel.sync_flag == sync_flag).first()
    if not admin_user or not sync_user:
        logger.error("注册用户失败!--------")
        return False
    token = await get_new_token(db, admin_user.id, RAGFLOW)
    # print(token)
    if not token:
        logger.error("注册用户获取token失败!")
        return False
    user_list = db.query(UserAppModel).filter(UserAppModel.app_type==RAGFLOW).all()
    user = db.query(UserAppModel).filter(UserAppModel.user_id==user_id, UserAppModel.app_type == RAGFLOW).first()
    user = db.query(UserAppModel).filter(UserAppModel.userFlag==sync_user.id, UserAppModel.app_type == RAGFLOW).first()
    if not user:
        logger.error("注册用户获取信息失败!")
        return False
app/service/user.py
@@ -15,6 +15,7 @@
from app.service.difyService import DifyService
from app.service.ragflow import RagflowService
from app.service.service_token import get_ragflow_token, get_bisheng_token, get_new_token, get_dify_token
from app.utils.password_handle import generate_password
async def get_user_list(db, page_index: int, page_size: int, keyword: str, role_key: str, user_id):
@@ -23,9 +24,10 @@
    #     query.filter(UserModel.creator==user_id)
    if keyword:
        query = query.filter(UserModel.username.like('%{}%'.format(keyword)))
    total = query.count()
    users = query.order_by(UserModel.id.desc()).limit(page_size).offset(
        (page_index - 1) * page_size).all()
    return {"total": query.count(), "rows": [user.to_json() for user in users]}
    return {"total": total, "rows": [user.to_json() for user in users]}
async def edit_user_status(db, status: str, user_id: int):
@@ -52,39 +54,24 @@
async def create_user(db, user_name, email, phone, login_name, password, roles, groups, user_id):
    try:
        # bisheng_service = BishengService(settings.sgb_base_url)
        # ragflow_service = RagflowService(settings.fwr_base_url)
        #
        # # 注册到毕昇
        # try:
        #     bisheng_info = await bisheng_service.register(user_name, password)
        # except Exception as e:
        #     logger.error(f"Failed to register with Bisheng: {str(e)}")
        #     return False
        #
        # # 注册到ragflow
        # try:
        #     ragflow_info = await ragflow_service.register(user_name, password)
        # except Exception as e:
        #     logger.error(f"Failed to register with Ragflow: {str(e)}")
        #     return False
        app_register = AppRegisterDao(db).get_apps()
        register_dict = {}
        token = ""
        app_password = generate_password()
        for app in app_register:
            if app["id"] == RAGFLOW:
                service = RagflowService(settings.fwr_base_url)
            elif app["id"] == BISHENG:
                service = BishengService(settings.sgb_base_url)
            elif app["id"] == DIFY:
                token = await get_dify_token()
                token = await get_dify_token(db, user_id)
                service = DifyService(settings.dify_base_url)
            else:
                logger.error("未知注册应用---")
                continue
            try:
                name = app["id"] + str(int(time.time()))
                register_info = await service.register(name, password, token)
                register_info = await service.register(name, app_password, token)
                # print(register_info)
                register_dict[app['id']] = {"id": register_info.get("id"), "name": name,
                                            "email": register_info.get("email")}
@@ -98,7 +85,7 @@
        user_model = UserModel(username=user_name, hashed_password=hashed_password, email=email,
                               ## ragflow_id=ragflow_info.get("id"),bisheng_id=bisheng_info.get("user_id"),
                               phone=phone, login_name=login_name)
        pwd = user_model.encrypted_password(password)
        pwd = user_model.encrypted_password(app_password)
        user_model.roles = [db.get(RoleModel, roleId) for roleId in roles]
        user_model.password = pwd
        if groups:
@@ -126,7 +113,7 @@
        user.email = email
        user.updated_at = datetime.now()
        user.roles = [db.get(RoleModel, roleId) for roleId in roles]
        user.groups = [db.get(GroupModel, groupId) for groupId in groups]
        # user.groups = [db.get(GroupModel, groupId) for groupId in groups]
        db.commit()
    except Exception as e:
        logger.error(e)
@@ -138,26 +125,38 @@
async def edit_user_pwd(db, user_id, current_user_id, new_password="basic123456"):
    try:
        user = db.query(UserModel).filter(UserModel.id == user_id).first()
        pwd = user.decrypted_password()
        for app in AppRegisterDao(db).get_apps():
            if app.get("id") == RAGFLOW:
                token = await get_new_token(db, user_id, app.get("id"))
                ragflow_service = RagflowService(settings.fwr_base_url)
                await ragflow_service.set_user_password(token, pwd, new_password)
            elif app.get("id") == BISHENG:
                token = await get_bisheng_token(db, current_user_id)
                bisheng_service = BishengService(settings.sgb_base_url)
                await bisheng_service.change_password_public(token, user.username, pwd, new_password)
            else:
                logger.error("注册未知应用:{}".format(app.get("id")))
        # pwd = user.decrypted_password()
        # for app in AppRegisterDao(db).get_apps():
        #     if app.get("id") == RAGFLOW:
        #         token = await get_new_token(db, user_id, app.get("id"))
        #         ragflow_service = RagflowService(settings.fwr_base_url)
        #         await ragflow_service.set_user_password(token, pwd, new_password)
        #     elif app.get("id") == BISHENG:
        #         token = await get_bisheng_token(db, current_user_id)
        #         bisheng_service = BishengService(settings.sgb_base_url)
        #         await bisheng_service.change_password_public(token, user.username, pwd, new_password)
        #     else:
        #         logger.error("注册未知应用:{}".format(app.get("id")))
        user.hashed_password = pwd_context.hash(new_password)
        user.password = user.encrypted_password(new_password)
        # user.password = user.encrypted_password(new_password)
        db.commit()
    except Exception as e:
        logger.error(e)
        db.rollback()
        return False
    return True
async def change_user_pwd(db, user_id, new_password):
    try:
        user = db.query(UserModel).filter(UserModel.id == user_id).first()
        user.hashed_password = pwd_context.hash(new_password)
        db.commit()
    except Exception as e:
        logger.error(e)
        db.rollback()
        return False
    return True
async def get_user_info(db, user_id):
@@ -223,7 +222,9 @@
            if parent_ogt.id not in dept_set:
                await role_resource(role_set, permissions, parent_ogt.roles)
                dept_set.add(parent_ogt.id)
            parent_ogt = parent_ogt.parent
                parent_ogt = parent_ogt.parent
            else:
                break
    tmp_dit = {}
    for permission in permissions.values():
        tmp_dit[permission["parentId"]] = tmp_dit.get(permission["parentId"], []) + [permission]
@@ -238,17 +239,14 @@
async def get_user_menus(db, user_id):
    dialog_list = []
    agent_list = []
    menu_dict = {}
    res = []
    user = db.query(UserModel).filter_by(id=user_id).first()
    for group in user.groups:
        for dialog in group.dialogs:
            dialog_list.append(dialog.id)
        for agent in group.agents:
            agent_list.append(agent.id)
    menu_list = db.query(WebMenuModel.id, WebMenuModel.title, WebMenuModel.describe, WebMenuModel.icon, WebMenuModel.desc,
                         WebMenuModel.img, MenuCapacityModel.capacity_id, MenuCapacityModel.capacity_type, DialogModel.agent_id.label("agentId")).outerjoin(
    menu_list = db.query(WebMenuModel.id, WebMenuModel.title, WebMenuModel.describe, WebMenuModel.icon, WebMenuModel.desc,WebMenuModel.rank,
                         WebMenuModel.img, MenuCapacityModel.capacity_id, MenuCapacityModel.capacity_type, MenuCapacityModel.chat_id.label("agentId")).outerjoin(
        MenuCapacityModel, WebMenuModel.id == MenuCapacityModel.menu_id).outerjoin(
        DialogModel, MenuCapacityModel.capacity_id == DialogModel.id).filter(DialogModel.status=="1").all()
@@ -262,8 +260,6 @@
                continue
            elif not m.capacity_type or m.capacity_type == 1 and m.capacity_id not in dialog_list:
                break
            elif not m.capacity_type or m.capacity_type == 2 and m.capacity_id not in agent_list:
                break
        else:
            res.append({
            'id': menus[0].id,
@@ -272,9 +268,10 @@
            'img': menus[0].img,
            'desc': menus[0].desc,
            'dialog': menus[0].describe,
            'agentId': menus[0].agentId
            'agentId': menus[0].agentId,
            'rank': menus[0].rank
        })
    return res
    return sorted(res, key=lambda x: x['rank'], reverse=True)
async def get_user_permission(db,  user_id):
@@ -286,7 +283,7 @@
    knowledge_dict = {}
    user = db.query(UserModel).filter_by(id=user_id).first()
    parent_id = ""
    print(111111111111111)
    # print(111111111111111)
    async def role_resource(role_set, permissions, roles):
        nonlocal parent_id
        for role in roles:
@@ -311,7 +308,9 @@
                await role_resource(role_set, permissions, parent_ogt.roles)
                dept_set.add(parent_ogt.id)
            parent_ogt = parent_ogt.parent
                parent_ogt = parent_ogt.parent
            else:
                break
    tmp_dit = {}
    for permission in permissions.values():
@@ -337,4 +336,11 @@
    res = {}
    user = db.query(UserModel).filter_by(id=user_id).first()
    res["rows"] = [i.to_dict() for i in user.organizations]
    return res
    return res
async def user_data_service(db, user_id):
    user = db.query(UserModel).filter_by(id=user_id).first()
    return {"roles": [i.to_dict() for i in user.roles], "user": user.to_dict()}
app/service/v2/initialize_data.py
@@ -1,7 +1,8 @@
import json
from Log import logger
from app.models import MenuCapacityModel, WebMenuModel, GroupModel, RoleModel
from app.models import MenuCapacityModel, WebMenuModel, GroupModel, RoleModel, DialogModel, UserModel
from app.service.v2.app_register import AppRegisterDao
async def dialog_menu_sync(db):
@@ -17,13 +18,9 @@
    for menu in menu_list:
        # print(menu)
        agent = menu.pop("agent", [])
        for i in agent:
            capacity = MenuCapacityModel(menu_id=menu["id"], capacity_id=i, capacity_type=2)
            db.add(capacity)
        dialog = menu.pop("dialog", [])
        for i in dialog:
            capacity = MenuCapacityModel(menu_id=menu["id"], capacity_id=i, capacity_type=1)
            capacity = MenuCapacityModel(menu_id=menu["id"], capacity_id=i["id"], capacity_type=i["agentType"], chat_id=i["id"] if not i["chat_id"] else i["chat_id"], chat_type=i["chat_type"])
            db.add(capacity)
        menu_obj = WebMenuModel(**menu)
        db.add(menu_obj)
@@ -53,4 +50,46 @@
            db.add(group)
            db.commit()
        except Exception as e:
            logger.error(e)
            logger.error(e)
async def app_register_sync(db):
    app_dict = {}
    with open("env_conf/app_register_conf.json", 'r', encoding='utf-8') as file:
        # 加载JSON数据
        app_dict = json.load(file)
        try:
            for app_id, status in app_dict.items():
                AppRegisterDao(db).update_and_insert_app(app_id, status)
        except Exception as e:
            logger.error(e)
async def basic_agent_sync(db):
    agent_list = []
    with open("env_conf/default_agent_conf.json", 'r', encoding='utf-8') as file:
        # 加载JSON数据
        agent_dict = json.load(file)
        agent_list = agent_dict.get("basic", [])
    user = db.query(UserModel).filter_by(permission="admin").first()
    for agent in agent_list:
        dialog = db.query(DialogModel).filter(DialogModel.id==agent["id"]).first()
        if dialog:
            try:
                dialog.name = agent["name"]
                dialog.description = agent["description"]
                dialog.icon = agent["icon"]
                db.commit()
            except Exception as e:
                logger.error(e)
        else:
            try:
                dialog = DialogModel(id=agent["id"], name=agent["name"], description=agent["description"],
                                     icon=agent["icon"], tenant_id=user.id if user else "", dialog_type="3",
                                     agent_id=agent["id"])
                db.add(dialog)
                db.commit()
                db.refresh(dialog)
            except Exception as e:
                print(e)
                db.rollback()
app/task/fetch_agent.py
@@ -1,14 +1,12 @@
from typing import Dict, List, Tuple
from sqlalchemy import create_engine, Column, String, Integer
from sqlalchemy.dialects.postgresql import array
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import sessionmaker
from app.config.config import settings
from app.models.agent_model import AgentModel
from app.models.base_model import SessionLocal, Base
from app.service.v2.initialize_data import dialog_menu_sync, default_group_sync, default_role_sync
# 创建数据库引擎和会话工厂
engine_bisheng = create_engine(settings.sgb_db_url)
@@ -151,13 +149,5 @@
        print(f"Failed to sync agents: {str(e)}")
async def sync_web_menu():
    db = SessionLocal()
    await dialog_menu_sync(db)
async def sync_default_data():
    db = SessionLocal()
    await default_group_sync(db)
    await default_role_sync(db)
app/utils/password_handle.py
New file
@@ -0,0 +1,31 @@
import asyncio
import random
import string
async def generate_password(length=10):
    if length < 6:  # 至少需要3位密码以包含所有必要的字符
        raise ValueError("Password length should be at least 3")
    # 确保密码中至少包含一个字母和一个数字
    password = [
        random.choice(string.ascii_uppercase),  # 大写字母
        random.choice(string.ascii_lowercase),  # 小写字母
        random.choice(string.digits)  # 数字
    ]
    # 添加剩余的随机字符
    characters = string.ascii_letters + string.digits
    password.extend(random.choice(characters) for _ in range(length - 3))
    # 打乱密码以确保随机性
    random.shuffle(password)
    # 将列表转换为字符串
    return ''.join(password)
if __name__ == "__main__":
    # 生成一个10位的密码
    asyncio.run(generate_password(10))
    # password = generate_password(10)
    # print(password)
env_conf/api_key_conf.json
New file
@@ -0,0 +1,5 @@
{
  "image_and_text_conversion": "",
  "document_to_report": "",
  "document_to_cleaning": ""
}
env_conf/app_register_conf.json
New file
@@ -0,0 +1,5 @@
{
  "bisheng_app": 1,
  "dify_app": 1,
  "ragflow_app": 1
}
env_conf/default_agent_conf.json
New file
@@ -0,0 +1,33 @@
{
  "basic": [
    {
      "id": "basic_excel_merge",
      "name": "报表合并",
      "description": "报表合并",
      "icon": "intellFrame4",
      "agentType": "excelMerge"
    },
    {
      "id": "basic_excel_talk",
      "name": "智能数据",
      "description": "智能数据",
      "icon": "intellFrame4",
      "agentType": "excelTalk"
    },
    {
      "id": "basic_question_talk",
      "name": "出题组卷",
      "description": "出题组卷",
      "icon": "intellFrame4",
      "agentType": "questionTalk"
    },
    {
      "id": "basic_paper_talk",
      "name": "文档出卷",
      "description": "文档出卷",
      "icon": "intellFrame4",
      "agentType": "paperTalk"
    }
  ],
  "bs": []
}
env_conf/menu_conf.json
@@ -7,8 +7,15 @@
      "img": "/src/assets/index/2.png",
      "desc": "基于您创建的报告格式和知识库中的文档内容,快速生成定制报告,并支持一键下载。",
      "describe": "基于您创建的报告格式和知识库中的文档内容,快速生成定制报告,并支持一键下载。",
      "agent" : [],
      "dialog": ["1"]
      "rank": 100,
      "dialog": [
        {
          "id": "1",
          "chat_id": "",
          "chat_type": "report",
          "agentType": 2
        }
      ]
    },
    {
      "id": 1,
@@ -17,8 +24,15 @@
      "img": "/src/assets/index/6.png",
      "desc": "基于您上传的报表进行合并,助您快速完成报表整合与分析",
      "describe": "基于您上传的报表进行合并,助您快速完成报表整合与分析",
      "agent" : [],
      "dialog": ["2"]
      "dialog": [
        {
          "id": "2",
          "chat_id": "",
          "chat_type": "excelMerge",
          "agentType": 1
        }
      ],
      "rank": 99
    },
    {
      "id": 2,
@@ -27,7 +41,7 @@
      "img": "/src/assets/index/5.png",
      "desc": "遍历已创建的文档知识库,生成完整和准确的答案,同时显示来源文档供您参考",
      "describe": "垂域知识的问答助手,针对你的提问,我们将遍历已创建的文档知识库,生成完整和准确的答案,同时显示来源文档供您参考。",
      "agent" : [],
      "rank": 98,
      "dialog": []
    },
    {
@@ -37,8 +51,15 @@
      "img": "/src/assets/index/7.png",
      "desc": "个人知识库的问答助手,基于您上传的文档进行问答,支持多文档",
      "describe": "个人知识库的问答助手,基于您上传的文档进行问答,支持多文档,大小在30M以内。",
      "agent" : [],
      "dialog": ["3"]
      "rank": 97,
      "dialog": [
        {
          "id": "3",
          "chat_id": "",
          "chat_type": "report",
          "agentType": 1
        }
      ]
    },
    {
      "id": 4,
@@ -47,7 +68,7 @@
      "img": "/src/assets/index/1.png",
      "desc": "能够理解和学习人类的语言,具备多轮对话的能力",
      "describe": "我可以理解和学习人类的语言,具备多轮对话的能力,现在和我开始交流吧~",
      "agent" : [],
      "rank": 96,
      "dialog": []
    },
    {
@@ -57,7 +78,7 @@
      "img": "/src/assets/index/8.png",
      "desc": "您可以上传文档或添加数据库地址,小数可针对你文档的数据进行分析,并生成指定的图表",
      "describe": "您可以上传文档或添加数据库地址,小数可针对你文档的数据进行分析,并生成指定的图表",
      "agent" : ["3", "4"],
      "rank": 95,
      "dialog": []
    },
    {
@@ -67,7 +88,7 @@
      "img": "/src/assets/index/7.png",
      "desc": "基于您上传的图片,生成对应的文字描述并基于图片内容实现问答。",
      "describe": "基于您上传的图片,生成对应的文字描述并基于图片内容实现问答。",
      "agent" : ["3"],
      "rank": 94,
      "dialog": []
    },
    {
@@ -77,7 +98,7 @@
      "img": "/src/assets/index/6.png",
      "desc": "您可以上传文档,小数能针对单文档或多个文档内容自动出题,高效便捷的帮助你建立私人题库。",
      "describe": "您可以上传文档,小数能针对单文档或多个文档内容自动出题,高效便捷的帮助你建立私人题库。",
      "agent" : [],
      "rank": 93,
      "dialog": []
    },
    {
@@ -87,7 +108,7 @@
      "img": "/src/assets/index/6.png",
      "desc": "您可以上传文档,小数能针对单文档或多个文档内容自动出题,高效便捷的帮助你建立私人题库。",
      "describe": "您可以上传文档,小数能针对单文档或多个文档内容自动出题,高效便捷的帮助你建立私人题库。",
      "agent" : ["4"],
      "rank": 92,
      "dialog": []
    },
    {
@@ -97,8 +118,21 @@
      "img": "/src/assets/index/2.png",
      "desc": "基于您创建的报告格式和上传的文档内容,快速生成定制报告,并支持一键下载。",
      "describe": "基于您创建的报告格式和上传的文档内容,快速生成定制报告,并支持一键下载。",
      "agent" : [],
      "dialog": []
      "rank": 91,
      "dialog": [
        {
          "id": "basic_excel_merge",
          "chat_id": "basic_report_clean",
          "chat_type": "reportWorkflow",
          "agentType": 4
        },
        {
          "id": "basic_paper_talk",
          "chat_id": "basic_report_clean",
          "chat_type": "reportWorkflow",
          "agentType": 4
        }
      ]
    }
  ]
}
main.py
@@ -22,7 +22,8 @@
from app.api.user import user_router
from app.api.group import group_router
from app.api.role import role_router
from app.task.fetch_agent import sync_agents, initialize_agents, sync_web_menu, sync_default_data
from app.task.fetch_agent import sync_agents, initialize_agents
from app.init_config.init_run_data import sync_default_data
# 使用 Lifespan 事件处理程序
@@ -33,7 +34,6 @@
    # 在应用启动时同步代理
    sync_agents()
    await sync_default_data()
    await sync_web_menu()
    yield
    # 在应用关闭时执行清理操作(如果需要)
    pass