Merge branch 'develop' of codeup.aliyun.com:redbearai/python/redbear-mem-open into develop

This commit is contained in:
Mark
2026-01-04 18:05:15 +08:00
5 changed files with 82 additions and 67 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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)) # 去重

View File

@@ -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="质量评估")

View File

@@ -41,8 +41,6 @@ nodes:
- 使用友好、礼貌的语气 - 使用友好、礼貌的语气
- 适当使用格式化(如列表、段落)提高可读性 - 适当使用格式化(如列表、段落)提高可读性
- role: user
content: "{{sys.message}}"
model_id: null model_id: null
temperature: 0.7 temperature: 0.7