Skip to content

Commit fb0efe0

Browse files
authored
Feat/2.2.0 beta2 (#1667)
2 parents 4bea644 + 7fb56ce commit fb0efe0

File tree

100 files changed

+4353
-1163
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+4353
-1163
lines changed

docker/docker-compose.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ services:
4040

4141
backend:
4242
container_name: bisheng-backend
43-
image: dataelement/bisheng-backend:v2.2.0-beta1
43+
image: dataelement/bisheng-backend:v2.2.0-beta2
4444
ports:
4545
- "7860:7860"
4646
environment:
@@ -78,7 +78,7 @@ services:
7878

7979
backend_worker:
8080
container_name: bisheng-backend-worker
81-
image: dataelement/bisheng-backend:v2.2.0-beta1
81+
image: dataelement/bisheng-backend:v2.2.0-beta2
8282
environment:
8383
TZ: Asia/Shanghai
8484
BS_MILVUS_CONNECTION_ARGS: '{"host":"milvus","port":"19530","user":"","password":"","secure":false}'
@@ -109,7 +109,7 @@ services:
109109

110110
frontend:
111111
container_name: bisheng-frontend
112-
image: dataelement/bisheng-frontend:v2.2.0-beta1
112+
image: dataelement/bisheng-frontend:v2.2.0-beta2
113113
ports:
114114
- "3001:3001"
115115
environment:

src/backend/bisheng/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
try:
99
# 通过ci去自动修改
10-
__version__ = '2.2.0-beta1'
10+
__version__ = '2.2.0-beta2'
1111
except metadata.PackageNotFoundError:
1212
# Case where package metadata is not available.
1313
__version__ = ''

src/backend/bisheng/api/errcode/base.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,15 @@ def to_sse_event_instance(self, event: str = "error", data: any = None) -> dict:
5959
})
6060
}
6161

62+
def to_sse_event_instance_str(self, event: str = "error", data: any = None) -> str:
63+
data = data if data is not None else {"exception": str(self), **self.kwargs}
64+
msg = json.dumps({
65+
"status_code": self.code,
66+
"status_message": self.message,
67+
"data": data
68+
}, ensure_ascii=False)
69+
return f'event: {event}\ndata: {msg}\n\n'
70+
6271
def to_dict(self, data: any = None) -> dict:
6372
data = data if data is not None else {"exception": str(self), **self.kwargs}
6473
return {

src/backend/bisheng/api/errcode/flow.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,8 @@ class WorkFlowVersionUpdateError(BaseErrorCode):
7575
class WorkFlowTaskBusyError(BaseErrorCode):
7676
Code: int = 10540
7777
Msg: str = '服务器线程数已满,请稍候再试'
78+
79+
# 工作流任务其它错误
80+
class WorkFlowTaskOtherError(BaseErrorCode):
81+
Code: int = 10541
82+
Msg: str = '工作流任务执行失败'

src/backend/bisheng/api/errcode/linsight.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1-
from .base import BaseErrorCode
1+
from bisheng.api.errcode.base import BaseErrorCode
22

33

44
class SopFileError(BaseErrorCode):
55
Code: int = 11010
66
Msg: str = 'SOP文件格式不符合要求'
77

88

9+
class SopShowcaseError(BaseErrorCode):
10+
Code: int = 11011
11+
Msg: str = 'SOP设置精选案例失败'
12+
13+
914
class FileUploadError(BaseErrorCode):
1015
__doc__ = 'Linsight上传文件失败'
1116
Code: int = 11020
@@ -53,6 +58,7 @@ class LinsightBishengLLMError(BaseErrorCode):
5358
Code: int = 11090
5459
Msg: str = '灵思Bisheng LLM相关错误'
5560

61+
5662
# 生成SOP内容失败
5763
class LinsightGenerateSopError(BaseErrorCode):
5864
Code: int = 11100
@@ -70,27 +76,32 @@ class LinsightSessionVersionRunningError(BaseErrorCode):
7076
Code: int = 11120
7177
Msg: str = '灵思会话版本已完成或正在执行,无法再次执行'
7278

79+
7380
# 开始执行灵思任务失败
7481
class LinsightStartTaskError(BaseErrorCode):
7582
Code: int = 11130
7683
Msg: str = '开始执行灵思任务失败'
7784

85+
7886
# 获取灵思队列排队状态失败
7987
class LinsightQueueStatusError(BaseErrorCode):
8088
Code: int = 11140
8189
Msg: str = '获取灵思队列排队状态失败'
8290

91+
8392
# 添加指导手册失败,向量存储添加数据失败
8493
class LinsightAddSopError(BaseErrorCode):
8594
Code: int = 11150
8695
Msg: str = '添加指导手册失败,向量存储添加数据失败'
8796

97+
8898
# 更新指导手册失败,向量存储更新数据失败
8999
class LinsightUpdateSopError(BaseErrorCode):
90100
Code: int = 11160
91101
Msg: str = '更新指导手册失败,向量存储更新数据失败'
92102

103+
93104
# 删除指导手册失败,向量存储删除数据失败
94105
class LinsightDeleteSopError(BaseErrorCode):
95106
Code: int = 11170
96-
Msg: str = '删除指导手册失败,向量存储删除数据失败'
107+
Msg: str = '删除指导手册失败,向量存储删除数据失败'

src/backend/bisheng/api/services/chat_imp.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
from collections import defaultdict
66
from datetime import datetime, timedelta
77

8+
from pydantic import BaseModel
9+
from websockets import connect
10+
811
from bisheng.api.errcode.http_error import ServerError
9-
from bisheng.api.v1.schemas import resp_500
1012
from bisheng.database.base import session_getter
1113
from bisheng.database.models.message import ChatMessage
12-
from pydantic import BaseModel
13-
from websockets import connect
1414

1515
# 维护一个连接池
1616
connection_pool = defaultdict(asyncio.Queue)
@@ -54,6 +54,8 @@ async def clean_inactive_queues(queue: defaultdict, timeout_threshold: timedelta
5454

5555
# 维护一个连接池
5656
connection_pool = defaultdict(TimedQueue)
57+
58+
5759
# clean_inactive_queues(connection_pool, timedelta(minutes=5))
5860

5961

@@ -106,25 +108,24 @@ def __str__(self) -> str:
106108

107109

108110
async def event_stream(
109-
webosocket: connect,
110-
message: str,
111-
session_id: str,
112-
model: str,
113-
streaming: bool,
111+
webosocket: connect,
112+
message: str,
113+
session_id: str,
114+
model: str,
115+
streaming: bool,
114116
):
115-
116117
payload = {'inputs': message, 'flow_id': model, 'chat_id': session_id}
117118
try:
118119
await webosocket.send(json.dumps(payload, ensure_ascii=False))
119120
except Exception as e:
120-
yield ServerError(exception=e).to_sse_event_instance()
121+
yield ServerError(exception=e).to_sse_event_instance_str()
121122
return
122123
sync = ''
123124
while True:
124125
try:
125126
msg = await webosocket.recv()
126127
except Exception as e:
127-
yield ServerError(exception=e).to_sse_event_instance()
128+
yield ServerError(exception=e).to_sse_event_instance_str()
128129
break
129130
if msg is None:
130131
continue

src/backend/bisheng/api/services/linsight/sop_manage.py

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import io
22
import json
33
import uuid
4-
from typing import List, Dict
4+
from typing import List, Dict, Literal
55

66
import openpyxl
77
from fastapi import UploadFile
@@ -176,6 +176,9 @@ async def _sync_sop_record(sop_records: list[LinsightSOPRecord], override: bool
176176
description=one_record.description,
177177
content=one_record.content,
178178
rating=one_record.rating,
179+
linsight_version_id=one_record.linsight_version_id,
180+
showcase=False,
181+
user_id=one_record.user_id,
179182
))
180183
override_name_dict[one.name] = True
181184
# 再新增剩下的sop记录
@@ -187,6 +190,7 @@ async def _sync_sop_record(sop_records: list[LinsightSOPRecord], override: bool
187190
description=one.description,
188191
content=one.content,
189192
rating=one.rating,
193+
linsight_version_id=one.linsight_version_id,
190194
), one.user_id)
191195
elif save_new:
192196
for one in sop_records:
@@ -199,6 +203,7 @@ async def _sync_sop_record(sop_records: list[LinsightSOPRecord], override: bool
199203
description=one.description,
200204
content=one.content,
201205
rating=one.rating,
206+
linsight_version_id=one.linsight_version_id,
202207
), one.user_id)
203208
else:
204209
# 说明有重复的记录,需要用户确认
@@ -211,6 +216,7 @@ async def _sync_sop_record(sop_records: list[LinsightSOPRecord], override: bool
211216
description=one.description,
212217
content=one.content,
213218
rating=one.rating,
219+
linsight_version_id=one.linsight_version_id,
214220
), one.user_id)
215221
if oversize_records:
216222
raise ValueError(f"{'、'.join(oversize_records)}内容超长")
@@ -285,6 +291,28 @@ async def upload_sop_file(cls, login_user: UserPayload, file: UploadFile, ignore
285291
records = [LinsightSOPRecord(**one, user_id=login_user.user_id) for one in success_rows]
286292
return await cls._sync_sop_record(records, override=override, save_new=save_new)
287293

294+
@classmethod
295+
async def get_sop_list(cls, keywords: str = None, sort: Literal["asc", "desc"] = "desc", showcase: bool = False,
296+
page: int = 1, page_size: int = 10) -> dict:
297+
"""
298+
获取SOP列表
299+
:param keywords: 关键词
300+
:param sort: 排序方式
301+
:param page: 页码
302+
:param page_size: 每页数量
303+
:param showcase: 是否仅展示精选案例的SOP
304+
:return: SOP列表和总数
305+
"""
306+
sop_pages = await LinsightSOPDao.get_sop_page(keywords=keywords, showcase=showcase, page=page,
307+
page_size=page_size,
308+
sort=sort)
309+
user_ids = list(set([one["user_id"] for one in sop_pages["items"]]))
310+
user_map = UserDao.aget_user_by_ids(user_ids=user_ids)
311+
user_map = {one.user_id: one.user_name for one in await user_map}
312+
for one in sop_pages["items"]:
313+
one["user_name"] = user_map.get(one["user_id"], str(one["user_id"]))
314+
return sop_pages
315+
288316
@staticmethod
289317
async def add_sop(sop_obj: SOPManagementSchema, user_id) -> UnifiedResponseModel | None:
290318
"""
@@ -336,16 +364,20 @@ async def add_sop(sop_obj: SOPManagementSchema, user_id) -> UnifiedResponseModel
336364
return resp_200(data=sop_model)
337365

338366
@staticmethod
339-
async def update_sop(sop_obj: SOPManagementUpdateSchema) -> UnifiedResponseModel | None:
367+
async def update_sop(sop_obj: SOPManagementUpdateSchema,
368+
update_version_id: bool = True) -> UnifiedResponseModel | None:
340369
"""
341370
更新SOP
342371
:param sop_obj:
372+
:param update_version_id: 是否更新版本ID
343373
:return: 更新后的SOP对象
344374
"""
345375
# 校验SOP是否存在
346376
existing_sop = await LinsightSOPDao.get_sops_by_ids([sop_obj.id])
347377
if not existing_sop:
348378
return NotFoundError.return_resp()
379+
if not update_version_id:
380+
sop_obj.linsight_version_id = existing_sop[0].linsight_version_id
349381

350382
if sop_obj.content != existing_sop[0].content:
351383

@@ -419,6 +451,18 @@ async def remove_sop(sop_ids: list[int], login_user: UserPayload) -> UnifiedResp
419451

420452
return resp_200(data=True)
421453

454+
@classmethod
455+
async def get_sop_by_id(cls, sop_id: int) -> LinsightSOP | None:
456+
"""
457+
根据ID获取SOP
458+
:param sop_id: SOP唯一ID
459+
:return: SOP对象
460+
"""
461+
sop_models = await LinsightSOPDao.get_sops_by_ids([sop_id])
462+
if not sop_models:
463+
return None
464+
return sop_models[0]
465+
422466
# sop 库检索
423467
@classmethod
424468
async def search_sop(cls, query: str, k: int = 3) -> (List[Document], BaseErrorCode | None):

src/backend/bisheng/api/services/linsight/workbench_impl.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,8 @@ async def generate_sop(cls, linsight_session_version_id: str,
317317
feedback_content: Optional[str] = None,
318318
reexecute: bool = False,
319319
login_user: Optional[UserPayload] = None,
320-
knowledge_list: List[KnowledgeRead] = None) -> AsyncGenerator[Dict, None]:
320+
knowledge_list: List[KnowledgeRead] = None,
321+
sop_id: Optional[int] = None) -> AsyncGenerator[Dict, None]:
321322
"""
322323
生成SOP内容
323324
@@ -359,9 +360,14 @@ async def generate_sop(cls, linsight_session_version_id: str,
359360
if previous_session_version_id:
360361
session_version = await LinsightSessionVersionDao.get_by_id(previous_session_version_id)
361362

363+
example_sop = None
364+
if sop_id:
365+
sop_db = await SOPManageService.get_sop_by_id(sop_id)
366+
example_sop = sop_db.content if sop_db else None
367+
362368
content = ""
363369
async for res in cls._generate_sop_content(
364-
agent, session_version, feedback_content, history_summary, knowledge_list
370+
agent, session_version, feedback_content, history_summary, knowledge_list, example_sop=example_sop
365371
):
366372
if isinstance(res, cls.SearchSOPError):
367373
yield res.error_class.to_sse_event(event="search_sop_error")
@@ -497,12 +503,15 @@ async def _create_linsight_agent(cls, session_version: LinsightSessionVersion,
497503
async def _generate_sop_content(cls, agent, session_version: LinsightSessionVersion,
498504
feedback_content: Optional[str],
499505
history_summary: List[str],
500-
knowledge_list: List[KnowledgeRead] = None) -> AsyncGenerator:
506+
knowledge_list: List[KnowledgeRead] = None,
507+
example_sop: str = None) -> AsyncGenerator:
501508
"""生成SOP内容"""
502509
file_list = await cls.prepare_file_list(session_version)
503510
knowledge_list = await cls.prepare_knowledge_list(knowledge_list)
504-
505-
if feedback_content is None:
511+
if example_sop:
512+
async for res in agent.generate_sop(sop=example_sop, file_list=file_list, knowledge_list=knowledge_list):
513+
yield res
514+
elif feedback_content is None:
506515
# 检索SOP模板
507516
sop_template, search_sop_error = await SOPManageService.search_sop(
508517
query=session_version.question, k=3

src/backend/bisheng/api/v1/flows.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,24 @@
22
from typing import Any
33

44
from fastapi import APIRouter, Depends, HTTPException, Query, Request
5-
from fastapi_jwt_auth import AuthJWT
65
from sqlmodel import select
76
from starlette.responses import StreamingResponse
87

9-
from bisheng.api.errcode.http_error import UnAuthorizedError, ServerError, NotFoundError
108
from bisheng.api.errcode.flow import FlowOnlineEditError, FlowNameExistsError
9+
from bisheng.api.errcode.http_error import UnAuthorizedError, ServerError, NotFoundError
1110
from bisheng.api.services.flow import FlowService
1211
from bisheng.api.services.user_service import UserPayload, get_login_user
13-
from bisheng.api.utils import build_flow_no_yield, get_L2_param_from_flow, remove_api_keys
12+
from bisheng.api.utils import build_flow_no_yield, remove_api_keys
1413
from bisheng.api.v1.schemas import (FlowCompareReq, FlowListRead, FlowVersionCreate, StreamData,
15-
UnifiedResponseModel, resp_200)
14+
resp_200)
1615
from bisheng.database.base import session_getter
17-
from bisheng.database.models.flow import (Flow, FlowCreate, FlowDao, FlowRead, FlowReadWithStyle, FlowType,
16+
from bisheng.database.models.flow import (Flow, FlowCreate, FlowDao, FlowRead, FlowType,
1817
FlowUpdate)
1918
from bisheng.database.models.flow_version import FlowVersionDao
2019
from bisheng.database.models.role_access import AccessType
2120
from bisheng.settings import settings
2221
from bisheng.utils.logger import logger
22+
from fastapi_jwt_auth import AuthJWT
2323

2424
# build router
2525
router = APIRouter(prefix='/flows', tags=['Flows'], dependencies=[Depends(get_login_user)])
@@ -238,7 +238,7 @@ async def event_stream(req: FlowCompareReq):
238238
yield str(StreamData(event='message', data={'type': 'end', 'data': ''}))
239239
except Exception as e:
240240
logger.exception('compare flow stream error')
241-
yield ServerError(exception=e).to_sse_event_instance()
241+
yield ServerError(exception=e).to_sse_event_instance_str()
242242

243243
try:
244244
return StreamingResponse(event_stream(item), media_type='text/event-stream')

0 commit comments

Comments
 (0)