Merge branch 'develop' of codeup.aliyun.com:redbearai/python/redbear-mem-open into develop
This commit is contained in:
@@ -1,26 +1,28 @@
|
|||||||
from typing import Optional
|
|
||||||
import datetime
|
import datetime
|
||||||
import json
|
import json
|
||||||
|
from typing import Optional
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, status, Query
|
from fastapi import APIRouter, Depends, HTTPException, status, Query
|
||||||
from sqlalchemy import or_
|
from sqlalchemy import or_
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
from app.celery_app import celery_app
|
||||||
|
from app.core.logging_config import get_api_logger
|
||||||
|
from app.core.rag.common import settings
|
||||||
|
from app.core.rag.llm.chat_model import Base
|
||||||
|
from app.core.rag.nlp import rag_tokenizer, search
|
||||||
|
from app.core.rag.prompts.generator import graph_entity_types
|
||||||
|
from app.core.rag.vdb.elasticsearch.elasticsearch_vector import ElasticSearchVectorFactory
|
||||||
|
from app.core.response_utils import success
|
||||||
from app.db import get_db
|
from app.db import get_db
|
||||||
from app.dependencies import get_current_user
|
from app.dependencies import get_current_user
|
||||||
from app.models.user_model import User
|
from app.models.user_model import User
|
||||||
from app.models import knowledge_model, document_model, file_model
|
from app.models import knowledge_model, document_model, file_model
|
||||||
from app.schemas import knowledge_schema
|
from app.schemas import knowledge_schema
|
||||||
from app.schemas.response_schema import ApiResponse
|
from app.schemas.response_schema import ApiResponse
|
||||||
from app.core.response_utils import success
|
|
||||||
from app.services import knowledge_service, document_service
|
from app.services import knowledge_service, document_service
|
||||||
from app.core.rag.llm.chat_model import Base
|
from app.services.model_service import ModelConfigService
|
||||||
from app.core.rag.prompts.generator import graph_entity_types
|
|
||||||
from app.core.rag.vdb.elasticsearch.elasticsearch_vector import ElasticSearchVectorFactory
|
|
||||||
from app.core.logging_config import get_api_logger
|
|
||||||
from app.core.rag.nlp import rag_tokenizer, search
|
|
||||||
from app.core.rag.common import settings
|
|
||||||
from app.celery_app import celery_app
|
|
||||||
|
|
||||||
# Obtain a dedicated API logger
|
# Obtain a dedicated API logger
|
||||||
api_logger = get_api_logger()
|
api_logger = get_api_logger()
|
||||||
@@ -47,6 +49,45 @@ def get_parser_types():
|
|||||||
return success(msg="Successfully obtained the knowledge parser type", data=list(knowledge_model.ParserType))
|
return success(msg="Successfully obtained the knowledge parser type", data=list(knowledge_model.ParserType))
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/knowledge_graph_entity_types", response_model=ApiResponse)
|
||||||
|
async def get_knowledge_graph_entity_types(
|
||||||
|
llm_id: uuid.UUID,
|
||||||
|
scenario: str,
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
current_user: User = Depends(get_current_user)
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
get knowledge graph entity types based on llm_id
|
||||||
|
"""
|
||||||
|
api_logger.info(f"Obtain details of the knowledge graph: llm_id={llm_id}, username: {current_user.username}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 1. Check whether the model exists
|
||||||
|
api_logger.debug(f"Check whether the model exists: {llm_id}")
|
||||||
|
config = ModelConfigService.get_model_by_id(db=db, model_id=llm_id)
|
||||||
|
|
||||||
|
if not config:
|
||||||
|
api_logger.warning(
|
||||||
|
f"The model does not exist or you do not have permission to access it: llm_id={llm_id}")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
|
detail="The model does not exist or you do not have permission to access it"
|
||||||
|
)
|
||||||
|
# 2. Prepare to configure chat_mdl information
|
||||||
|
chat_model = Base(
|
||||||
|
key=config.api_keys[0].api_key,
|
||||||
|
model_name=config.api_keys[0].model_name,
|
||||||
|
base_url=config.api_keys[0].api_base
|
||||||
|
)
|
||||||
|
response = graph_entity_types(chat_model, scenario)
|
||||||
|
return success(data=response, msg="Successfully obtained knowledge graph entity types")
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
api_logger.error(f"get knowledge graph entity types failed: llm_id={llm_id} - {str(e)}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
@router.get("/knowledges", response_model=ApiResponse)
|
@router.get("/knowledges", response_model=ApiResponse)
|
||||||
async def get_knowledges(
|
async def get_knowledges(
|
||||||
parent_id: Optional[uuid.UUID] = Query(None, description="parent folder id"),
|
parent_id: Optional[uuid.UUID] = Query(None, description="parent folder id"),
|
||||||
@@ -379,7 +420,7 @@ async def delete_knowledge_graph(
|
|||||||
current_user: User = Depends(get_current_user)
|
current_user: User = Depends(get_current_user)
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Soft-delete knowledge graph
|
delete knowledge graph
|
||||||
"""
|
"""
|
||||||
api_logger.info(f"Request to delete knowledge graph: knowledge_id={knowledge_id}, username: {current_user.username}")
|
api_logger.info(f"Request to delete knowledge graph: knowledge_id={knowledge_id}, username: {current_user.username}")
|
||||||
|
|
||||||
@@ -442,42 +483,3 @@ async def rebuild_knowledge_graph(
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
api_logger.error(f"Failed to rebuild knowledge graph: knowledge_id={knowledge_id} - {str(e)}")
|
api_logger.error(f"Failed to rebuild knowledge graph: knowledge_id={knowledge_id} - {str(e)}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
@router.get("/{knowledge_id}/knowledge_graph_entity_types", response_model=ApiResponse)
|
|
||||||
async def get_knowledge_graph_entity_types(
|
|
||||||
knowledge_id: uuid.UUID,
|
|
||||||
scenario: str,
|
|
||||||
db: Session = Depends(get_db),
|
|
||||||
current_user: User = Depends(get_current_user)
|
|
||||||
):
|
|
||||||
"""
|
|
||||||
get knowledge graph entity types based on knowledge_id
|
|
||||||
"""
|
|
||||||
api_logger.info(f"Obtain details of the knowledge graph: knowledge_id={knowledge_id}, username: {current_user.username}")
|
|
||||||
|
|
||||||
try:
|
|
||||||
# 1. Check whether the knowledge base exists
|
|
||||||
api_logger.debug(f"Check whether the knowledge base exists: {knowledge_id}")
|
|
||||||
db_knowledge = knowledge_service.get_knowledge_by_id(db, knowledge_id=knowledge_id, current_user=current_user)
|
|
||||||
|
|
||||||
if not db_knowledge:
|
|
||||||
api_logger.warning(
|
|
||||||
f"The knowledge base does not exist or you do not have permission to access it: knowledge_id={knowledge_id}")
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_404_NOT_FOUND,
|
|
||||||
detail="The knowledge base does not exist or you do not have permission to access it"
|
|
||||||
)
|
|
||||||
# 2. Prepare to configure chat_mdl information
|
|
||||||
chat_model = Base(
|
|
||||||
key=db_knowledge.llm.api_keys[0].api_key,
|
|
||||||
model_name=db_knowledge.llm.api_keys[0].model_name,
|
|
||||||
base_url=db_knowledge.llm.api_keys[0].api_base
|
|
||||||
)
|
|
||||||
response = graph_entity_types(chat_model, scenario)
|
|
||||||
return success(data=response, msg="Successfully obtained knowledge graph entity types")
|
|
||||||
except HTTPException:
|
|
||||||
raise
|
|
||||||
except Exception as e:
|
|
||||||
api_logger.error(f"get knowledge graph entity types failed: knowledge_id={knowledge_id} - {str(e)}")
|
|
||||||
raise
|
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ class RAGExcelParser:
|
|||||||
logging.info(f"pandas with default engine load error: {ex}, try calamine instead")
|
logging.info(f"pandas with default engine load error: {ex}, try calamine instead")
|
||||||
file_like_object.seek(0)
|
file_like_object.seek(0)
|
||||||
df = pd.read_excel(file_like_object, engine="calamine")
|
df = pd.read_excel(file_like_object, engine="calamine")
|
||||||
print("lxc1")
|
|
||||||
return RAGExcelParser._dataframe_to_workbook(df)
|
return RAGExcelParser._dataframe_to_workbook(df)
|
||||||
except Exception as e_pandas:
|
except Exception as e_pandas:
|
||||||
raise Exception(f"pandas.read_excel error: {e_pandas}, original openpyxl error: {e}")
|
raise Exception(f"pandas.read_excel error: {e_pandas}, original openpyxl error: {e}")
|
||||||
@@ -215,19 +214,35 @@ class RAGExcelParser:
|
|||||||
continue
|
continue
|
||||||
if not rows:
|
if not rows:
|
||||||
continue
|
continue
|
||||||
|
# 获取表头
|
||||||
ti = list(rows[0])
|
ti = list(rows[0])
|
||||||
for r in list(rows[1:]):
|
header_fields = []
|
||||||
fields = []
|
for cell in ti:
|
||||||
for i, c in enumerate(r):
|
if cell.value: # 只添加有值的表头
|
||||||
if not c.value:
|
header_fields.append(str(cell.value))
|
||||||
continue
|
|
||||||
t = str(ti[i].value) if i < len(ti) else ""
|
# 如果有数据行,处理数据行;否则只处理表头
|
||||||
t += (":" if t else "") + str(c.value)
|
data_rows = rows[1:]
|
||||||
fields.append(t)
|
if data_rows:
|
||||||
line = "; ".join(fields)
|
for r in data_rows:
|
||||||
if sheetname.lower().find("sheet") < 0:
|
fields = []
|
||||||
line += " ——" + sheetname
|
for i, c in enumerate(r):
|
||||||
res.append(line)
|
if not c.value:
|
||||||
|
continue
|
||||||
|
t = str(ti[i].value) if i < len(ti) else ""
|
||||||
|
t += (":" if t else "") + str(c.value)
|
||||||
|
fields.append(t)
|
||||||
|
line = "; ".join(fields)
|
||||||
|
if sheetname.lower().find("sheet") < 0:
|
||||||
|
line += " ——" + sheetname
|
||||||
|
res.append(line)
|
||||||
|
else:
|
||||||
|
# 只有表头的情况
|
||||||
|
if header_fields:
|
||||||
|
line = "; ".join(header_fields)
|
||||||
|
if sheetname.lower().find("sheet") < 0:
|
||||||
|
line += " ——" + sheetname
|
||||||
|
res.append(line)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ class EndNode(BaseNode):
|
|||||||
引用的节点 ID 列表
|
引用的节点 ID 列表
|
||||||
"""
|
"""
|
||||||
# 匹配 {{node_id.xxx}} 格式
|
# 匹配 {{node_id.xxx}} 格式
|
||||||
pattern = r'\{\{([a-zA-Z0-9_]+)\.[a-zA-Z0-9_]+\}\}'
|
pattern = r'\{\{([a-zA-Z0-9_-]+)\.[a-zA-Z0-9_]+\}\}'
|
||||||
matches = re.findall(pattern, template)
|
matches = re.findall(pattern, template)
|
||||||
return list(set(matches)) # 去重
|
return list(set(matches)) # 去重
|
||||||
|
|
||||||
|
|||||||
@@ -51,8 +51,8 @@ class DataConfig(Base):
|
|||||||
# 自我反思配置
|
# 自我反思配置
|
||||||
enable_self_reflexion = Column(Boolean, default=False, comment="是否启用自我反思")
|
enable_self_reflexion = Column(Boolean, default=False, comment="是否启用自我反思")
|
||||||
iteration_period = Column(String, default="3", comment="反思迭代周期")
|
iteration_period = Column(String, default="3", comment="反思迭代周期")
|
||||||
reflexion_range = Column(String, default="retrieval", comment="反思范围:部分/全部")
|
reflexion_range = Column(String, default="partial", comment="反思范围:部分/全部")
|
||||||
baseline = Column(String, default="time", comment="基线:时间/事实/时间和事实")
|
baseline = Column(String, default="TIME", comment="基线:时间/事实/时间和事实")
|
||||||
reflection_model_id = Column(String, nullable=True, comment="反思模型ID")
|
reflection_model_id = Column(String, nullable=True, comment="反思模型ID")
|
||||||
memory_verify = Column(Boolean, default=True, comment="记忆验证")
|
memory_verify = Column(Boolean, default=True, comment="记忆验证")
|
||||||
quality_assessment = Column(Boolean, default=True, comment="质量评估")
|
quality_assessment = Column(Boolean, default=True, comment="质量评估")
|
||||||
|
|||||||
@@ -41,8 +41,6 @@ nodes:
|
|||||||
- 使用友好、礼貌的语气
|
- 使用友好、礼貌的语气
|
||||||
- 适当使用格式化(如列表、段落)提高可读性
|
- 适当使用格式化(如列表、段落)提高可读性
|
||||||
|
|
||||||
- role: user
|
|
||||||
content: "{{sys.message}}"
|
|
||||||
|
|
||||||
model_id: null
|
model_id: null
|
||||||
temperature: 0.7
|
temperature: 0.7
|
||||||
|
|||||||
Reference in New Issue
Block a user