diff --git a/apps/entities/collection.py b/apps/entities/collection.py index 3f727790bad7424619dff82394c0df41c340a3f0..00c32404a22b1fbd4230c571c741e8043f57347b 100644 --- a/apps/entities/collection.py +++ b/apps/entities/collection.py @@ -23,7 +23,8 @@ class Blacklist(BaseModel): is_audited: bool = False reason_type: list[str] = [] reason: Optional[str] = None - updated_at: float = Field(default_factory=lambda: round(datetime.now(tz=timezone.utc).timestamp(), 3)) + updated_at: float = Field(default_factory=lambda: round( + datetime.now(tz=timezone.utc).timestamp(), 3)) class UserDomainData(BaseModel): @@ -41,7 +42,8 @@ class User(BaseModel): """ id: str = Field(alias="_id") - last_login: float = Field(default_factory=lambda: round(datetime.now(tz=timezone.utc).timestamp(), 3)) + last_login: float = Field(default_factory=lambda: round( + datetime.now(tz=timezone.utc).timestamp(), 3)) is_active: bool = False is_whitelisted: bool = False credit: int = 100 @@ -80,7 +82,8 @@ class Document(BaseModel): name: str type: str size: float - created_at: float = Field(default_factory=lambda: round(datetime.now(tz=timezone.utc).timestamp(), 3)) + created_at: float = Field(default_factory=lambda: round( + datetime.now(tz=timezone.utc).timestamp(), 3)) conversation_id: str @@ -93,7 +96,8 @@ class Audit(BaseModel): id: str = Field(default_factory=lambda: str(uuid.uuid4()), alias="_id") user_sub: Optional[str] = None http_method: str - created_at: float = Field(default_factory=lambda: round(datetime.now(tz=timezone.utc).timestamp(), 3)) + created_at: float = Field(default_factory=lambda: round( + datetime.now(tz=timezone.utc).timestamp(), 3)) module: str client_ip: Optional[str] = None message: str @@ -123,7 +127,8 @@ class RecordComment(BaseModel): feedback_type: list[str] feedback_link: str feedback_content: str - feedback_time: float = Field(default_factory=lambda: round(datetime.now(tz=timezone.utc).timestamp(), 3)) + feedback_time: float = Field(default_factory=lambda: round( + datetime.now(tz=timezone.utc).timestamp(), 3)) class Record(BaseModel): @@ -133,11 +138,13 @@ class Record(BaseModel): user_sub: str data: str key: dict[str, Any] = {} - flow: list[str] = Field(description="[运行后修改]与Record关联的FlowHistory的ID", default=[]) + flow: list[str] = Field( + description="[运行后修改]与Record关联的FlowHistory的ID", default=[]) facts: list[str] = Field(description="[运行后修改]与Record关联的事实信息", default=[]) comment: Optional[RecordComment] = None metadata: Optional[RecordMetadata] = None - created_at: float = Field(default_factory=lambda: round(datetime.now(tz=timezone.utc).timestamp(), 3)) + created_at: float = Field(default_factory=lambda: round( + datetime.now(tz=timezone.utc).timestamp(), 3)) class RecordGroupDocument(BaseModel): @@ -161,7 +168,8 @@ class RecordGroup(BaseModel): docs: list[RecordGroupDocument] = [] # 问题不变,所用到的文档不变 conversation_id: str task_id: str - created_at: float = Field(default_factory=lambda: round(datetime.now(tz=timezone.utc).timestamp(), 3)) + created_at: float = Field(default_factory=lambda: round( + datetime.now(tz=timezone.utc).timestamp(), 3)) class Domain(BaseModel): @@ -173,28 +181,5 @@ class Domain(BaseModel): id: str = Field(default_factory=lambda: str(uuid.uuid4()), alias="_id") name: str definition: str - updated_at: float = Field(default_factory=lambda: round(datetime.now(tz=timezone.utc).timestamp(), 3)) -class NodeMetaData(BaseModel): - """节点元数据""" - pass -class ServiceNodeMetaDatas(BaseModel): - """节点原数据""" - pass -class Position(BaseModel): - """前端相对位置""" - pass -class Flow(BaseModel): - """流的拓扑数据""" - pass -class Branch(BaseModel): - """节点分支信息""" - pass -class Dependency(BaseModel): - """节点伴生关系""" - pass -class Node(BaseModel): - """流拓扑中的节点数据""" - pass -class Edge(BaseModel): - """流拓扑中的边信息""" - pass + updated_at: float = Field(default_factory=lambda: round( + datetime.now(tz=timezone.utc).timestamp(), 3)) diff --git a/apps/entities/flow.py b/apps/entities/flow.py index bf7ab7533cb441288ddb500c36a3caa3c648f7de..4b91d2ad45f5f9cd20b3bac5d41b5a7983a0372a 100644 --- a/apps/entities/flow.py +++ b/apps/entities/flow.py @@ -93,10 +93,14 @@ class ServiceApiAuthKeyVal(BaseModel): class ServiceApiAuth(BaseModel): """Service的API鉴权方式""" - header: list[ServiceApiAuthKeyVal] = Field(description="HTTP头鉴权配置", default=[]) - cookie: list[ServiceApiAuthKeyVal] = Field(description="HTTP Cookie鉴权配置", default=[]) - query: list[ServiceApiAuthKeyVal] = Field(description="HTTP URL参数鉴权配置", default=[]) - oidc: Optional[ServiceApiAuthOidc] = Field(description="OIDC鉴权配置", default=None) + header: list[ServiceApiAuthKeyVal] = Field( + description="HTTP头鉴权配置", default=[]) + cookie: list[ServiceApiAuthKeyVal] = Field( + description="HTTP Cookie鉴权配置", default=[]) + query: list[ServiceApiAuthKeyVal] = Field( + description="HTTP URL参数鉴权配置", default=[]) + oidc: Optional[ServiceApiAuthOidc] = Field( + description="OIDC鉴权配置", default=None) class ServiceApiConfig(BaseModel): @@ -123,7 +127,8 @@ class AppLink(BaseModel): class AppPermission(BaseModel): """App的权限配置""" - type: AppPermissionType = Field(description="权限类型", default=AppPermissionType.PRIVATE) + type: AppPermissionType = Field( + description="权限类型", default=AppPermissionType.PRIVATE) users: list[str] = Field(description="可访问的用户列表", default=[]) @@ -134,7 +139,8 @@ class AppMetadata(MetadataBase): links: list[AppLink] = Field(description="相关链接", default=[]) first_questions: list[str] = Field(description="首次提问", default=[]) history_len: int = Field(description="对话轮次", default=3, le=10) - permissions: Optional[AppPermission] = Field(description="应用权限配置", default=None) + permissions: Optional[AppPermission] = Field( + description="应用权限配置", default=None) class ServiceApiSpec(BaseModel): @@ -145,45 +151,3 @@ class ServiceApiSpec(BaseModel): size: int = Field(description="OpenAPI文件大小(单位:KB)") path: str = Field(description="OpenAPI文件路径") hash: str = Field(description="OpenAPI文件的hash值") - -class PositionItem(BaseModel): - """请求/响应中的前端相对位置变量类""" - x:float - y:float -class FlowItem(BaseModel): - """请求/响应中的流变量类""" - flow_id:str=Optional[Field](alias="flowId") - name:str - description:str - enable:bool - created_at: str= Field(alias="createdAt") -class BranchItem(BaseModel): - """请求/响应中的节点分支变量类""" - branch_id:str=Field(alias="branchId") - type:str - description:str -class DependencyItem(BaseModel): - """请求/响应中的节点依赖变量类""" - node_id:str=Field(alias="nodeId") - type:str -class NodeItem(BaseModel): - """请求/响应中的节点变量类""" - node_id:str=Field(alias="nodeId") - api_id:str=Field(alias="apiId") - name:str - type:str - description:str - enable:str - branches:list[BranchItem] - depedency:DependencyItem - position:PositionItem - editable:bool - created_at: str= Field(alias="createdAt") -class EdgeItem(BaseModel): - """请求/响应中的边变量类""" - egde_id:str=Field(alias="edgeId") - source_node:str=Field(alias="sourceNode") - target_node:str=Field(alias="targetNode") - type:str - branch_id:str=Field(alias="branchId") - created_at: str= Field(alias="createdAt") \ No newline at end of file diff --git a/apps/entities/flow_topology.py b/apps/entities/flow_topology.py new file mode 100644 index 0000000000000000000000000000000000000000..2e9c6849fb262b78ec6a24f137a2fef87ed3d383 --- /dev/null +++ b/apps/entities/flow_topology.py @@ -0,0 +1,77 @@ +import uuid +from typing import Optional + +from pydantic import BaseModel, Field + + +class ServiceItem(BaseModel): + """元数据归属的服务类""" + service_id: str = Field(alias="serviceId") + name: str + type: str + created_at: str = Field(alias="createdAt") + + +class NodeMetaDataItem(BaseModel): + """节点元数据类""" + api_id: str = Field(alias="apiId") + name: str + type: str + parametersTemplate: str + editable: str + created_at: str = Field(alias="createdAt") + + +class PositionItem(BaseModel): + """请求/响应中的前端相对位置变量类""" + x: float + y: float + + +class FlowItem(BaseModel): + """请求/响应中的流变量类""" + flow_id: Optional[str] = Field(alias="flowId") + name: str + description: str + enable: bool + editable: bool + created_at: str = Field(alias="createdAt") + + +class BranchItem(BaseModel): + """请求/响应中的节点分支变量类""" + branch_id: str = Field(alias="branchId") + type: str + description: str + + +class DependencyItem(BaseModel): + """请求/响应中的节点依赖变量类""" + node_id: str = Field(alias="nodeId") + type: str + + +class NodeItem(BaseModel): + """请求/响应中的节点变量类""" + node_id: str = Field(alias="nodeId") + api_id: str = Field(alias="apiId") + name: str + type: str + description: str + enable: str + parameters: str + branches: list[BranchItem] + depedency: DependencyItem + position: PositionItem + editable: bool + created_at: str = Field(alias="createdAt") + + +class EdgeItem(BaseModel): + """请求/响应中的边变量类""" + edge_id: str = Field(alias="edgeId") + source_node: str = Field(alias="sourceNode") + target_node: str = Field(alias="targetNode") + type: str + branch_id: str = Field(alias="branchId") + created_at: str = Field(alias="createdAt") diff --git a/apps/entities/request_data.py b/apps/entities/request_data.py index 10bc63d6c2cf3e747ecab770da7f8d2166201c1e..7c113c449e0ed18daf753be676dfc34a53ea4681 100644 --- a/apps/entities/request_data.py +++ b/apps/entities/request_data.py @@ -7,7 +7,8 @@ from typing import Optional from pydantic import BaseModel, Field from apps.entities.task import RequestDataPlugin -from apps.entities.flow import PositionItem,FlowItem,NodeItem,EdgeItem +from apps.entities.flow_topology import PositionItem, FlowItem, NodeItem, EdgeItem + class RequestDataFeatures(BaseModel): """POST /api/chat的features字段数据""" @@ -100,13 +101,16 @@ class PostKnowledgeIDData(BaseModel): kb_id: str + class PutFlowReq(BaseModel): """创建/修改流拓扑结构""" - flow_id:Optional[str]=Field(alias="flowId") - flow:FlowItem - nodes:list[NodeItem] - edges:list[EdgeItem] - focus_point:PositionItem=Field(alias="focusPoint") + flow_id: Optional[str] = Field(alias="flowId") + flow: FlowItem + nodes: list[NodeItem] + edges: list[EdgeItem] + focus_point: PositionItem = Field(alias="focusPoint") + + class PutNodeParameterReq: """修改节点的参数""" - content:str \ No newline at end of file + content: str diff --git a/apps/entities/response_data.py b/apps/entities/response_data.py index 50926e73d4b44079be07fe9e851bc8496bdbdf47..f392eccffcbbf4fa2f774af6a25c81acb0ac19ad 100644 --- a/apps/entities/response_data.py +++ b/apps/entities/response_data.py @@ -6,11 +6,12 @@ from typing import Any, Optional from pydantic import BaseModel, Field -from apps.entities.collection import Blacklist, Document,NodeMetaData +from apps.entities.collection import Blacklist, Document from apps.entities.enum_var import DocumentStatus from apps.entities.plugin import PluginData from apps.entities.record import RecordData -from apps.entities.flow import PositionItem,FlowItem,NodeItem,EdgeItem +from apps.entities.flow_topology import ServiceItem, NodeMetaDataItem, PositionItem, FlowItem, NodeItem, EdgeItem + class ResponseData(BaseModel): """基础返回数据结构""" @@ -56,6 +57,7 @@ class PostClientSessionRsp(ResponseData): result: PostClientSessionMsg + class AuthUserMsg(BaseModel): """GET /api/auth/user Result数据结构""" @@ -74,11 +76,13 @@ class HealthCheckRsp(BaseModel): status: str + class GetPluginListMsg(BaseModel): """GET /api/plugin Result数据结构""" plugins: list[PluginData] + class GetPluginListRsp(ResponseData): """GET /api/plugin 返回数据结构""" @@ -117,6 +121,7 @@ class ConversationListItem(BaseModel): doc_count: int created_time: str + class ConversationListMsg(BaseModel): """GET /api/conversation Result数据结构""" @@ -140,6 +145,7 @@ class AddConversationRsp(ResponseData): result: AddConversationMsg + class UpdateConversationRsp(ResponseData): """POST /api/conversation 返回数据结构""" @@ -151,6 +157,7 @@ class RecordListMsg(BaseModel): records: list[RecordData] + class RecordListRsp(ResponseData): """GET /api/record/{conversation_id} 返回数据结构""" @@ -202,6 +209,7 @@ class UploadDocumentMsg(BaseModel): documents: list[UploadDocumentMsgItem] + class UploadDocumentRsp(ResponseData): """POST /api/document/{conversation_id} 返回数据结构""" @@ -225,79 +233,62 @@ class GetKnowledgeIDMsg(BaseModel): kb_id: str + class GetKnowledgeIDRsp(ResponseData): """GET /api/knowledge 返回数据结构""" result: GetKnowledgeIDMsg -class NodeMetaDataItem(BaseModel): - """GET /api/flow/node/metadata 单个节点元数据结构""" - api_id: str = Field(alias="apiId") - name:str - type:str - created_at: str= Field(alias="createdAt") -class ServiceNodeMetaDatasItem(BaseModel): - """GET /api/flow/node/metadata 服务与服务下节点元数据结构""" - service_id:str=Field(alias="serviceId") - name:str - type:str - node_meta_datas:list[NodeMetaDataItem]=Field(alias="nodeMetaData",default=[]) - created_at: str= Field(alias="createdAt") -class NodeMetaDataListMsg(ResponseData): - services:list[ServiceNodeMetaDatasItem] +class NodeServiceListMsg(BaseModel): + """GET /api/flow/service result""" + total: int + services: list[ServiceItem] + + +class NodeServiceListRsp(ResponseData): + """GET /api/flow/service 返回数据结构""" + result: NodeServiceListMsg + + +class NodeMetaDataListMsg(BaseModel): + """GET /api/flow/service/node result""" + node_meta_datas: list[NodeMetaDataItem] + + class NodeMetaDataListRsp(ResponseData): - """GET /api/flow/node/metadata 返回数据结构""" - result:NodeMetaDataListMsg + """GET /api/flow/service/node 返回数据结构""" + result: NodeMetaDataListMsg class FlowStructureGetMsg(BaseModel): - """GET /api/flow/{flowId} result""" - flow:FlowItem - nodes:list[NodeItem] - edges:list[EdgeItem] - focus_point:PositionItem=Field(alias="focusPoint") - -class FlowStructureGetRsp(BaseModel): - """GET /api/flow/{flowId} 返回数据结构""" - result:FlowStructureGetMsg + """GET /api/flow result""" + flow: FlowItem + edges: list[EdgeItem] + nodes: list[NodeItem] + focus_point: PositionItem + + +class FlowStructureGetRsp(ResponseData): + """GET /api/flow 返回数据结构""" + result: FlowStructureGetMsg + + class FlowStructurePutMsg(BaseModel): """PUT /api/flow result""" - flow_id:str=Field(alias="flowId") + flow_id: str = Field(alias="flowId") + + class FlowStructurePutRsp(ResponseData): """PUT /api/flow 返回数据结构""" - flow_id:str=Field(alias="flowId") + result: FlowStructurePutMsg + class FlowStructureDeleteMsg(BaseModel): """DELETE /api/flow/{flowId} result""" - flow_id:str=Field(alias="flowId") + flow_id: str = Field(alias="flowId") + + class FlowStructureDeleteRsp(ResponseData): """DELETE /api/flow/{flowId} 返回数据结构""" - flow_id:str=Field(alias="flowId") - -class NodeParameterItem(BaseModel): - parameter_id:str=Field(alias="parameterId") - content:str - updated_at: str= Field(alias="updatedAt") -class NodeParameterGetMsg(BaseModel): - """GET /api/flow/node/parameter result""" - node_id:str=Field(alias="nodeId") - parameter:NodeParameterItem -class NodeParameterGetRsp(ResponseData): - """GET /api/flow/node/parameter 返回数据结构""" - result:NodeParameterGetMsg -class NodeParameterListMsg(BaseModel): - """GET /api/flow/node/parameter/history result""" - node_id:str=Field(alias="nodeId") - parameter_history:list[NodeParameterItem]=Field(alias="parameterHistory") -class NodeParameterListRsp(ResponseData): - """GET /api/flow/node/parameter/history 返回数据结构""" - result:NodeParameterListMsg - -class NodeParameterPutMsg(BaseModel): - """PUT /api/flow/node/parameter result""" - node_id:str=Field(alias="nodeId") - parameter_id:str=Field(alias="parameterId") -class NodeParameterPutRsp(ResponseData): - """PUT /api/flow/node/parameter 返回数据结构""" - result:NodeParameterPutMsg + result: FlowStructureDeleteMsg diff --git a/apps/manager/flow.py b/apps/manager/flow.py new file mode 100644 index 0000000000000000000000000000000000000000..4c29832dae667b6a8eb2f14585bcaca9875b9880 --- /dev/null +++ b/apps/manager/flow.py @@ -0,0 +1,29 @@ +"""评论 Manager + +Copyright (c) Huawei Technologies Co., Ltd. 2023-2024. All rights reserved. +""" +from typing import Optional, Tuple, List + +from apps.constants import LOGGER +from apps.entities.flow_topology import ServiceItem, NodeMetaDataItem, FlowItem, NodeItem, EdgeItem, PositionItem +from apps.models.mongo import MongoDB + + +class FlowManager: + async def validate_user_workflow_access(user_sub: str, app_id: str, editable: bool) -> bool: + return True + + async def get_service_by_user_id(user_sub: str) -> Tuple[int, List[ServiceItem]]: + pass + + async def get_node_meta_datas_by_user_id(user_sub: str) -> List[NodeMetaDataItem]: + pass + + async def get_flow_by_app_and_flow_id(app_id: str, flow_id: str) -> Tuple[FlowItem, List[NodeItem], List[EdgeItem], PositionItem]: + pass + + async def put_flow_by_app_and_flow_id(app_id: str, flow_id: str, flow: Tuple[FlowItem, List[NodeItem], List[EdgeItem], PositionItem]) -> str: + pass + + async def delete_flow_by_app_and_flow_id(flow_id: str) -> str: + pass diff --git a/apps/routers/flow.py b/apps/routers/flow.py index 592b550ca7859605b280daf3e684b929889efcd7..a1c1cc3c7dbe39eaf0b0a5f839c02ad052d98e6c 100644 --- a/apps/routers/flow.py +++ b/apps/routers/flow.py @@ -2,14 +2,16 @@ Copyright (c) Huawei Technologies Co., Ltd. 2023-2024. All rights reserved. """ -from fastapi import APIRouter, Depends, status,Path,Query,Body +from fastapi import APIRouter, Depends, status, Path, Query, Body from fastapi.responses import JSONResponse +from typing import Annotated from apps.dependency.csrf import verify_csrf_token from apps.dependency.user import verify_user -from apps.entities.request_data import PutFlowReq,PutNodeParameterReq -from apps.entities.response_data import NodeMetaDataListRsp,FlowStructureGetRsp,FlowStructurePutRsp,\ - FlowStructureDeleteRsp,NodeParameterGetRsp,NodeParameterListRsp,NodeParameterPutRsp +from apps.dependency import get_user +from apps.entities.request_data import PutFlowReq, PutNodeParameterReq +from apps.entities.response_data import NodeServiceListRsp, NodeMetaDataListRsp, FlowStructureGetRsp, \ + FlowStructurePutRsp, FlowStructureDeleteRsp from apps.manager.domain import DomainManager router = APIRouter( @@ -22,43 +24,47 @@ router = APIRouter( ) -@router.get("/node/metadata",response_model=NodeMetaDataListRsp) -async def get_node_metadatas(page:int =Query(...), - page_size:int =Query(...,alias="pageSize")): # noqa: ANN201 - """获取节点元数据""" +@router.get("/service", response_model=NodeMetaDataListRsp) +async def get_node_metadatas( + user_sub: Annotated[str, Depends(get_user)], + page: int = Query(...), + page_size: int = Query(..., alias="pageSize"), +): + """获取节点数据所在服务的信息""" pass -@router.get("/{flowId}", response_model=FlowStructureGetRsp) -async def get_flow(flowId: str = Path(..., title="流的id")): - flow_id=flowId - pass -@router.put("", response_model=FlowStructurePutRsp) -async def put_flow(flow_id:str = Query(..., alias="flowId"), - put_body: PutFlowReq=Body(...)): +@router.get("/service/node", response_model=NodeMetaDataListRsp) +async def get_flow( + user_sub: Annotated[str, Depends(get_user)], + service_id: int = Query(..., alias="serviceId") +): pass -@router.delete("/{flowId}", response_model=FlowStructureDeleteRsp) -async def delte_flow(flowId: str = Path(..., title="流的id")): - flow_id=flowId - pass -@router.get("/node/parameter", response_model=NodeParameterGetRsp) -async def get_node_parameter(flow_id:str = Query(..., alias="flowId"), - node_id:str = Query(..., alias="nodeId")): +@router.get("", response_model=FlowStructureGetRsp) +async def put_flow( + user_sub: Annotated[str, Depends(get_user)], + app_id: str = Query(..., alias="appId"), + flow_id: str = Query(..., alias="flowId") +): pass -@router.get("/node/parameter/history", response_model=NodeParameterListRsp) -async def get_node_parameter_history(flow_id:str = Query(..., alias="flowId"), - node_id:str = Query(..., alias="nodeId"), - start_time:str = Query(..., alias="startTime"), - end_time:str = Query(..., alias="endTime"), - page:int =Query(...), - page_size:int =Query(...,alias="pageSize"), - ): - pass -@router.put("/node/parameter", response_model=NodeParameterPutRsp) -async def put_node_parameter(flow_id:str = Query(..., alias="flowId"), - node_id:str = Query(..., alias="nodeId"), - put_body:PutNodeParameterReq=Body(...)): + + +@router.put("", response_model=FlowStructurePutRsp) +async def delte_flow( + user_sub: Annotated[str, Depends(get_user)], + app_id: str = Query(..., alias="appId"), + flow_id: str = Query(..., alias="flowId"), + put_body: PutFlowReq = Body(...) +): pass + +@router.delete("", response_model=FlowStructureDeleteRsp) +async def delte_flow( + user_sub: Annotated[str, Depends(get_user)], + app_id: str = Query(..., alias="appId"), + flow_id: str = Query(..., alias="flowId") +): + pass diff --git a/apps/service/flow.py b/apps/service/flow.py new file mode 100644 index 0000000000000000000000000000000000000000..0c7e39e2410eab0643b506b1e74a7102a947be7e --- /dev/null +++ b/apps/service/flow.py @@ -0,0 +1,3 @@ + +class FlowService: + pass \ No newline at end of file