Fix/interface home (#182)

* [fix]Fix the interface for statistics of recent activities and applications

* [changes]Modify the code based on the AI review
1.Use the boolean auxiliary methods provided by SQLAlchemy instead of using == True in the is_active filter.
2.The calculation of the "PROJECT_ROOT" has now been hardcoded with five levels of nested os.path.dirname calls.

* [fix]Fix the interface for statistics of recent activities and applications

* [changes]Modify the code based on the AI review
1.Use the boolean auxiliary methods provided by SQLAlchemy instead of using == True in the is_active filter.
2.The calculation of the "PROJECT_ROOT" has now been hardcoded with five levels of nested os.path.dirname calls.
This commit is contained in:
乐力齐
2026-01-23 10:50:24 +08:00
committed by GitHub
parent 45adb9627a
commit 7870c6c33f
26 changed files with 148 additions and 129 deletions

View File

@@ -317,9 +317,12 @@ async def chat(
appid = share.app_id appid = share.app_id
"""获取存储类型和工作空间的ID""" """获取存储类型和工作空间的ID"""
# 直接通过 SQLAlchemy 查询 app # 直接通过 SQLAlchemy 查询 app(仅查询未删除的应用)
from app.models.app_model import App from app.models.app_model import App
app = db.query(App).filter(App.id == appid).first() app = db.query(App).filter(
App.id == appid,
App.is_active.is_(True)
).first()
if not app: if not app:
raise BusinessException("应用不存在", BizCode.APP_NOT_FOUND) raise BusinessException("应用不存在", BizCode.APP_NOT_FOUND)

View File

@@ -54,7 +54,7 @@ async def create_workflow_config(
app = db.query(App).filter( app = db.query(App).filter(
App.id == app_id, App.id == app_id,
App.workspace_id == current_user.current_workspace_id, App.workspace_id == current_user.current_workspace_id,
App.is_active == True App.is_active.is_(True)
).first() ).first()
if not app: if not app:
@@ -214,7 +214,7 @@ async def delete_workflow_config(
app = db.query(App).filter( app = db.query(App).filter(
App.id == app_id, App.id == app_id,
App.workspace_id == current_user.current_workspace_id, App.workspace_id == current_user.current_workspace_id,
App.is_active == True App.is_active.is_(True)
).first() ).first()
if not app: if not app:
@@ -259,7 +259,7 @@ async def validate_workflow_config(
app = db.query(App).filter( app = db.query(App).filter(
App.id == app_id, App.id == app_id,
App.workspace_id == current_user.current_workspace_id, App.workspace_id == current_user.current_workspace_id,
App.is_active == True App.is_active.is_(True)
).first() ).first()
if not app: if not app:
@@ -329,7 +329,7 @@ async def get_workflow_executions(
app = db.query(App).filter( app = db.query(App).filter(
App.id == app_id, App.id == app_id,
App.workspace_id == current_user.current_workspace_id, App.workspace_id == current_user.current_workspace_id,
App.is_active == True App.is_active.is_(True)
).first() ).first()
if not app: if not app:
@@ -389,7 +389,7 @@ async def get_workflow_execution(
app = db.query(App).filter( app = db.query(App).filter(
App.id == execution.app_id, App.id == execution.app_id,
App.workspace_id == current_user.current_workspace_id, App.workspace_id == current_user.current_workspace_id,
App.is_active == True App.is_active.is_(True)
).first() ).first()
if not app: if not app:
@@ -440,7 +440,7 @@ async def run_workflow(
app = db.query(App).filter( app = db.query(App).filter(
App.id == app_id, App.id == app_id,
App.workspace_id == current_user.current_workspace_id, App.workspace_id == current_user.current_workspace_id,
App.is_active == True App.is_active.is_(True)
).first() ).first()
if not app: if not app:
@@ -578,7 +578,7 @@ async def cancel_workflow_execution(
app = db.query(App).filter( app = db.query(App).filter(
App.id == execution.app_id, App.id == execution.app_id,
App.workspace_id == current_user.current_workspace_id, App.workspace_id == current_user.current_workspace_id,
App.is_active == True App.is_active.is_(True)
).first() ).first()
if not app: if not app:

View File

@@ -1,11 +1,12 @@
import os import os
from collections import defaultdict from collections import defaultdict
from pathlib import Path
from typing import Annotated, TypedDict from typing import Annotated, TypedDict
from langchain_core.messages import AnyMessage from langchain_core.messages import AnyMessage
from langgraph.graph import add_messages from langgraph.graph import add_messages
PROJECT_ROOT_ = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) PROJECT_ROOT_ = str(Path(__file__).resolve().parents[3])
class WriteState(TypedDict): class WriteState(TypedDict):
''' '''

View File

@@ -139,7 +139,8 @@ def parse_api_docs(file_path: str) -> Dict[str, Any]:
def get_default_docs_path() -> str: def get_default_docs_path() -> str:
project_root = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) from pathlib import Path
project_root = str(Path(__file__).resolve().parents[2])
return os.path.join(project_root, "src", "analytics", "API接口.md") return os.path.join(project_root, "src", "analytics", "API接口.md")

View File

@@ -2,13 +2,16 @@ import os
import re import re
import glob import glob
import json import json
from pathlib import Path
from typing import Tuple from typing import Tuple
try: try:
from app.core.memory.utils.config.definitions import PROJECT_ROOT from app.core.memory.utils.config.definitions import PROJECT_ROOT
except Exception: except Exception:
# Fallback: derive project root from this file location # Fallback: derive project root from this file location
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) # 当前文件在 api/app/core/memory/analytics/recent_activity_stats.py
# 需要向上 5 级到达 api/ 目录
PROJECT_ROOT = str(Path(__file__).resolve().parents[4])
def _get_latest_prompt_log_path() -> str | None: def _get_latest_prompt_log_path() -> str | None:
@@ -67,44 +70,43 @@ def parse_stats_from_log(log_path: str) -> dict:
triplet_relations_count = 0 triplet_relations_count = 0
temporal_count = 0 temporal_count = 0
# Patterns # 正则表达式模式 - 匹配当前日志格式
pat_chunk_render = re.compile(r"===\s*RENDERED\s*STATEMENT\s*EXTRACTION\s*PROMPT\s*===") pat_chunk_render = re.compile(r"===\s*RENDERED\s*STATEMENT\s*EXTRACTION\s*PROMPT\s*===")
pat_triplet_start = re.compile(r"\[Triplet\].*statements_to_process\s*=\s*(\d+)") pat_triplet_started = re.compile(r"\[Triplet\]\s+Started\s+-\s+statement_id=")
pat_triplet_done = re.compile( pat_triplet_completed = re.compile(
r"\[Triplet\].*completed,\s*total_triplets\s*=\s*(\d+),\s*total_entities\s*=\s*(\d+)" r"\[Triplet\]\s+Completed\s+-\s+statement_id=[^,]+,\s+triplets=(\d+),\s+entities=(\d+)"
) )
pat_temporal_done = re.compile( pat_temporal_completed = re.compile(
r"\[Temporal\].*completed,\s*extracted_valid_ranges\s*=\s*(\d+)" r"\[Temporal\]\s+Completed\s+-\s+statement_id=[^,]+,\s+valid_ranges=(\d+)"
) )
with open(log_path, "r", encoding="utf-8", errors="ignore") as f: with open(log_path, "r", encoding="utf-8", errors="ignore") as f:
for line in f: for line in f:
# Chunk prompts count (each chunk triggers one statement-extraction prompt render) # 文本块数量(每个块触发一次陈述提取提示)
if pat_chunk_render.search(line): if pat_chunk_render.search(line):
chunk_count += 1 chunk_count += 1
continue continue
m1 = pat_triplet_start.search(line) # 陈述数量(每个 Triplet Started 代表一个陈述被处理)
if m1: if pat_triplet_started.search(line):
statements_count += 1
continue
# 三元组完成:[Triplet] Completed - statement_id=xxx, triplets=X, entities=Y
m_triplet = pat_triplet_completed.search(line)
if m_triplet:
try: try:
statements_count += int(m1.group(1)) triplet_relations_count += int(m_triplet.group(1))
triplet_entities_count += int(m_triplet.group(2))
except Exception: except Exception:
pass pass
continue continue
m2 = pat_triplet_done.search(line) # 时间信息完成:[Temporal] Completed - statement_id=xxx, valid_ranges=X
if m2: m_temporal = pat_temporal_completed.search(line)
if m_temporal:
try: try:
triplet_relations_count += int(m2.group(1)) temporal_count += int(m_temporal.group(1))
triplet_entities_count += int(m2.group(2))
except Exception:
pass
continue
m3 = pat_temporal_done.search(line)
if m3:
try:
temporal_count += int(m3.group(1))
except Exception: except Exception:
pass pass
continue continue
@@ -120,15 +122,20 @@ def parse_stats_from_log(log_path: str) -> dict:
def get_recent_activity_stats() -> Tuple[dict, str]: def get_recent_activity_stats() -> Tuple[dict, str]:
"""Get aggregated stats from all prompt logs in logs/. """Get stats from the latest prompt log file only.
Returns (stats_dict, message). Returns (stats_dict, message).
""" """
all_logs = _get_all_prompt_logs() # 获取最新的日志文件
# Fallback to recursive search if none found in logs/ latest_log = _get_latest_prompt_log_path()
if not all_logs:
# 如果没有找到,尝试递归搜索
if not latest_log:
all_logs = _get_any_logs_recursive() all_logs = _get_any_logs_recursive()
if not all_logs: if all_logs:
latest_log = all_logs[-1] # 取最新的
if not latest_log:
return ( return (
{ {
"chunk_count": 0, "chunk_count": 0,
@@ -141,24 +148,13 @@ def get_recent_activity_stats() -> Tuple[dict, str]:
"未找到日志文件,请确认已运行过提取流程。", "未找到日志文件,请确认已运行过提取流程。",
) )
agg = { # 只解析最新的日志文件
"chunk_count": 0, stats = parse_stats_from_log(latest_log)
"statements_count": 0,
"triplet_entities_count": 0, # 添加日志文件路径信息
"triplet_relations_count": 0, stats["log_path"] = f"最新:{latest_log}"
"temporal_count": 0,
} return stats, "成功读取最近一次记忆活动统计。"
for path in all_logs:
s = parse_stats_from_log(path)
agg["chunk_count"] += s.get("chunk_count", 0)
agg["statements_count"] += s.get("statements_count", 0)
agg["triplet_entities_count"] += s.get("triplet_entities_count", 0)
agg["triplet_relations_count"] += s.get("triplet_relations_count", 0)
agg["temporal_count"] += s.get("temporal_count", 0)
# Attach a summary of files combined
agg["log_path"] = f"{len(all_logs)} 个日志文件,最新:{all_logs[-1]}"
return agg, "成功汇总 logs 目录中所有提示日志。"
def _format_summary(stats: dict) -> str: def _format_summary(stats: dict) -> str:

View File

@@ -8,13 +8,14 @@ import sys
import time import time
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Any, Dict, List from typing import Any, Dict, List
from pathlib import Path
from dotenv import load_dotenv from dotenv import load_dotenv
# 1 # 1
# 添加项目根目录到路径 # 添加项目根目录到路径
current_dir = os.path.dirname(os.path.abspath(__file__)) current_dir = Path(__file__).resolve().parent
project_root = os.path.dirname(current_dir) project_root = str(current_dir.parent)
if project_root not in sys.path: if project_root not in sys.path:
sys.path.insert(0, project_root) sys.path.insert(0, project_root)
# 关键:将 src 目录置于最前,确保从当前仓库加载模块 # 关键:将 src 目录置于最前,确保从当前仓库加载模块

View File

@@ -16,9 +16,10 @@ except Exception:
# 确保可以找到 src 及项目根路径 # 确保可以找到 src 及项目根路径
import sys import sys
from pathlib import Path
_THIS_DIR = os.path.dirname(os.path.abspath(__file__)) _THIS_DIR = Path(__file__).resolve().parent
_PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(_THIS_DIR))) _PROJECT_ROOT = str(_THIS_DIR.parents[2])
_SRC_DIR = os.path.join(_PROJECT_ROOT, "src") _SRC_DIR = os.path.join(_PROJECT_ROOT, "src")
for _p in (_SRC_DIR, _PROJECT_ROOT): for _p in (_SRC_DIR, _PROJECT_ROOT):
if _p not in sys.path: if _p not in sys.path:

View File

@@ -15,9 +15,10 @@ except Exception:
# 路径与模块导入保持与现有评估脚本一致 # 路径与模块导入保持与现有评估脚本一致
import sys import sys
from pathlib import Path
_THIS_DIR = os.path.dirname(os.path.abspath(__file__)) _THIS_DIR = Path(__file__).resolve().parent
_PROJECT_ROOT = os.path.dirname(os.path.dirname(_THIS_DIR)) _PROJECT_ROOT = str(_THIS_DIR.parents[1])
_SRC_DIR = os.path.join(_PROJECT_ROOT, "src") _SRC_DIR = os.path.join(_PROJECT_ROOT, "src")
for _p in (_SRC_DIR, _PROJECT_ROOT): for _p in (_SRC_DIR, _PROJECT_ROOT):
if _p not in sys.path: if _p not in sys.path:

View File

@@ -15,9 +15,13 @@ class AppRepository:
self.db = db self.db = db
def get_apps_by_workspace_id(self, workspace_id: uuid.UUID) -> list[App]: def get_apps_by_workspace_id(self, workspace_id: uuid.UUID) -> list[App]:
"""根据工作空间ID查询应用""" """根据工作空间ID查询应用(仅返回未删除的应用)"""
try: try:
apps = self.db.query(App).filter(App.workspace_id == workspace_id).all() apps = (
self.db.query(App)
.filter(App.workspace_id == workspace_id, App.is_active.is_(True))
.all()
)
db_logger.info(f"成功查询工作空间 {workspace_id} 下的 {len(apps)} 个应用") db_logger.info(f"成功查询工作空间 {workspace_id} 下的 {len(apps)} 个应用")
return apps return apps
except Exception as e: except Exception as e:
@@ -26,7 +30,7 @@ class AppRepository:
def get_apps_by_id(self, app_id: uuid.UUID) -> App: def get_apps_by_id(self, app_id: uuid.UUID) -> App:
try: try:
app = self.db.query(App).filter(App.id == app_id, App.is_active == True).first() app = self.db.query(App).filter(App.id == app_id, App.is_active.is_(True)).first()
return app return app
except Exception as e: except Exception as e:
raise raise

View File

@@ -17,24 +17,24 @@ class HomePageRepository:
"""获取模型统计数据""" """获取模型统计数据"""
total_models = db.query(ModelConfig).filter( total_models = db.query(ModelConfig).filter(
ModelConfig.tenant_id == tenant_id, ModelConfig.tenant_id == tenant_id,
ModelConfig.is_active == True ModelConfig.is_active.is_(True)
).count() ).count()
total_llm = db.query(ModelConfig).filter( total_llm = db.query(ModelConfig).filter(
ModelConfig.tenant_id == tenant_id, ModelConfig.tenant_id == tenant_id,
ModelConfig.is_active == True, ModelConfig.is_active.is_(True),
ModelConfig.type == "llm" ModelConfig.type == "llm"
).count() ).count()
total_embedding = db.query(ModelConfig).filter( total_embedding = db.query(ModelConfig).filter(
ModelConfig.tenant_id == tenant_id, ModelConfig.tenant_id == tenant_id,
ModelConfig.is_active == True, ModelConfig.is_active.is_(True),
ModelConfig.type == "embedding" ModelConfig.type == "embedding"
).count() ).count()
new_models_this_week = db.query(ModelConfig).filter( new_models_this_week = db.query(ModelConfig).filter(
ModelConfig.tenant_id == tenant_id, ModelConfig.tenant_id == tenant_id,
ModelConfig.is_active == True, ModelConfig.is_active.is_(True),
ModelConfig.created_at >= week_start ModelConfig.created_at >= week_start
).count() ).count()
@@ -56,12 +56,12 @@ class HomePageRepository:
"""获取工作空间统计数据""" """获取工作空间统计数据"""
active_workspaces = db.query(Workspace).filter( active_workspaces = db.query(Workspace).filter(
Workspace.tenant_id == tenant_id, Workspace.tenant_id == tenant_id,
Workspace.is_active == True Workspace.is_active.is_(True)
).count() ).count()
new_workspaces_this_week = db.query(Workspace).filter( new_workspaces_this_week = db.query(Workspace).filter(
Workspace.tenant_id == tenant_id, Workspace.tenant_id == tenant_id,
Workspace.is_active == True, Workspace.is_active.is_(True),
Workspace.created_at >= week_start Workspace.created_at >= week_start
).count() ).count()
@@ -83,7 +83,7 @@ class HomePageRepository:
"""获取用户统计数据""" """获取用户统计数据"""
workspace_ids = db.query(Workspace.id).filter( workspace_ids = db.query(Workspace.id).filter(
Workspace.tenant_id == tenant_id, Workspace.tenant_id == tenant_id,
Workspace.is_active == True Workspace.is_active.is_(True)
).subquery() ).subquery()
total_users = db.query(EndUser).join( total_users = db.query(EndUser).join(
@@ -91,7 +91,7 @@ class HomePageRepository:
EndUser.app_id == App.id EndUser.app_id == App.id
).filter( ).filter(
App.workspace_id.in_(workspace_ids), App.workspace_id.in_(workspace_ids),
App.is_active == True, App.is_active.is_(True),
App.status == "active" App.status == "active"
).count() ).count()
@@ -100,7 +100,7 @@ class HomePageRepository:
EndUser.app_id == App.id EndUser.app_id == App.id
).filter( ).filter(
App.workspace_id.in_(workspace_ids), App.workspace_id.in_(workspace_ids),
App.is_active == True, App.is_active.is_(True),
App.status == "active", App.status == "active",
EndUser.created_at >= week_start EndUser.created_at >= week_start
).count() ).count()
@@ -123,18 +123,18 @@ class HomePageRepository:
"""获取应用统计数据""" """获取应用统计数据"""
workspace_ids = db.query(Workspace.id).filter( workspace_ids = db.query(Workspace.id).filter(
Workspace.tenant_id == tenant_id, Workspace.tenant_id == tenant_id,
Workspace.is_active == True Workspace.is_active.is_(True)
).subquery() ).subquery()
running_apps = db.query(App).filter( running_apps = db.query(App).filter(
App.workspace_id.in_(workspace_ids), App.workspace_id.in_(workspace_ids),
App.is_active == True, App.is_active.is_(True),
App.status == "active" App.status == "active"
).count() ).count()
new_apps_this_week = db.query(App).filter( new_apps_this_week = db.query(App).filter(
App.workspace_id.in_(workspace_ids), App.workspace_id.in_(workspace_ids),
App.is_active == True, App.is_active.is_(True),
App.status == "active", App.status == "active",
App.created_at >= week_start App.created_at >= week_start
).count() ).count()
@@ -158,7 +158,7 @@ class HomePageRepository:
# 获取工作空间列表 # 获取工作空间列表
workspaces = db.query(Workspace).filter( workspaces = db.query(Workspace).filter(
Workspace.tenant_id == tenant_id, Workspace.tenant_id == tenant_id,
Workspace.is_active == True Workspace.is_active.is_(True)
).all() ).all()
workspace_ids = [ws.id for ws in workspaces] workspace_ids = [ws.id for ws in workspaces]
@@ -169,7 +169,7 @@ class HomePageRepository:
func.count(App.id).label('count') func.count(App.id).label('count')
).filter( ).filter(
App.workspace_id.in_(workspace_ids), App.workspace_id.in_(workspace_ids),
App.is_active, App.is_active.is_(True),
App.status == "active" App.status == "active"
).group_by(App.workspace_id).all() ).group_by(App.workspace_id).all()
@@ -184,7 +184,7 @@ class HomePageRepository:
EndUser.app_id == App.id EndUser.app_id == App.id
).filter( ).filter(
App.workspace_id.in_(workspace_ids), App.workspace_id.in_(workspace_ids),
App.is_active, App.is_active.is_(True),
App.status == "active" App.status == "active"
).group_by(App.workspace_id).all() ).group_by(App.workspace_id).all()

View File

@@ -68,7 +68,7 @@ class UserRepository:
db_logger.debug("查询超级用户") db_logger.debug("查询超级用户")
try: try:
user = self.db.query(User).options(joinedload(User.tenant)).filter(User.is_active == True).filter(User.is_superuser == True).first() user = self.db.query(User).options(joinedload(User.tenant)).filter(User.is_active.is_(True)).filter(User.is_superuser.is_(True)).first()
if user: if user:
db_logger.debug(f"超级用户查询成功: {user.username}") db_logger.debug(f"超级用户查询成功: {user.username}")
else: else:
@@ -82,7 +82,7 @@ class UserRepository:
db_logger.debug("检查是否只有一个超级用户") db_logger.debug("检查是否只有一个超级用户")
try: try:
count = self.db.query(User).options(joinedload(User.tenant)).filter(User.is_active == True).filter(User.is_superuser == True).count() count = self.db.query(User).options(joinedload(User.tenant)).filter(User.is_active.is_(True)).filter(User.is_superuser.is_(True)).count()
return count == 1 return count == 1
except Exception as e: except Exception as e:
db_logger.error(f"检查超级用户数量失败: {str(e)}") db_logger.error(f"检查超级用户数量失败: {str(e)}")

View File

@@ -33,7 +33,7 @@ class WorkflowConfigRepository:
""" """
return self.db.query(WorkflowConfig).filter( return self.db.query(WorkflowConfig).filter(
WorkflowConfig.app_id == app_id, WorkflowConfig.app_id == app_id,
WorkflowConfig.is_active == True WorkflowConfig.is_active.is_(True)
).first() ).first()
def create_or_update( def create_or_update(

View File

@@ -103,7 +103,7 @@ class WorkspaceRepository:
workspaces = ( workspaces = (
self.db.query(Workspace) self.db.query(Workspace)
.filter(Workspace.tenant_id == user.tenant_id) .filter(Workspace.tenant_id == user.tenant_id)
.filter(Workspace.is_active == True) .filter(Workspace.is_active.is_(True))
.order_by(Workspace.updated_at.desc()) .order_by(Workspace.updated_at.desc())
.all() .all()
) )
@@ -115,7 +115,7 @@ class WorkspaceRepository:
self.db.query(Workspace) self.db.query(Workspace)
.join(WorkspaceMember, Workspace.id == WorkspaceMember.workspace_id) .join(WorkspaceMember, Workspace.id == WorkspaceMember.workspace_id)
.filter(WorkspaceMember.user_id == user_id) .filter(WorkspaceMember.user_id == user_id)
.filter(Workspace.is_active == True) .filter(Workspace.is_active.is_(True))
.order_by(Workspace.updated_at.desc()) .order_by(Workspace.updated_at.desc())
.all() .all()
) )
@@ -134,7 +134,7 @@ class WorkspaceRepository:
workspaces = ( workspaces = (
self.db.query(Workspace) self.db.query(Workspace)
.filter(Workspace.tenant_id == tenant_id) .filter(Workspace.tenant_id == tenant_id)
.filter(Workspace.is_active == True) .filter(Workspace.is_active.is_(True))
.all() .all()
) )
db_logger.debug(f"租户工作空间查询成功: tenant_id={tenant_id}, 数量={len(workspaces)}") db_logger.debug(f"租户工作空间查询成功: tenant_id={tenant_id}, 数量={len(workspaces)}")
@@ -169,7 +169,7 @@ class WorkspaceRepository:
member = self.db.query(WorkspaceMember).filter( member = self.db.query(WorkspaceMember).filter(
WorkspaceMember.user_id == user_id, WorkspaceMember.user_id == user_id,
WorkspaceMember.workspace_id == workspace_id, WorkspaceMember.workspace_id == workspace_id,
WorkspaceMember.is_active == True, WorkspaceMember.is_active.is_(True),
).first() ).first()
if member: if member:
db_logger.debug(f"工作空间成员查询成功: user_id={user_id}, workspace_id={workspace_id}, role={member.role}") db_logger.debug(f"工作空间成员查询成功: user_id={user_id}, workspace_id={workspace_id}, role={member.role}")
@@ -189,8 +189,8 @@ class WorkspaceRepository:
.join(User, WorkspaceMember.user_id == User.id) .join(User, WorkspaceMember.user_id == User.id)
.options(joinedload(WorkspaceMember.user), joinedload(WorkspaceMember.workspace)) .options(joinedload(WorkspaceMember.user), joinedload(WorkspaceMember.workspace))
.filter(WorkspaceMember.workspace_id == workspace_id) .filter(WorkspaceMember.workspace_id == workspace_id)
.filter(WorkspaceMember.is_active == True) .filter(WorkspaceMember.is_active.is_(True))
.filter(User.is_active == True) .filter(User.is_active.is_(True))
.all() .all()
) )
db_logger.debug(f"成员列表查询成功: workspace_id={workspace_id}, 数量={len(members)}") db_logger.debug(f"成员列表查询成功: workspace_id={workspace_id}, 数量={len(members)}")
@@ -208,8 +208,8 @@ class WorkspaceRepository:
.join(User, WorkspaceMember.user_id == User.id) .join(User, WorkspaceMember.user_id == User.id)
.options(joinedload(WorkspaceMember.user), joinedload(WorkspaceMember.workspace)) .options(joinedload(WorkspaceMember.user), joinedload(WorkspaceMember.workspace))
.filter(WorkspaceMember.id == member_id) .filter(WorkspaceMember.id == member_id)
.filter(WorkspaceMember.is_active == True) .filter(WorkspaceMember.is_active.is_(True))
.filter(User.is_active == True) .filter(User.is_active.is_(True))
.first() .first()
) )
if member: if member:
@@ -226,7 +226,7 @@ class WorkspaceRepository:
member = self.db.query(WorkspaceMember).filter( member = self.db.query(WorkspaceMember).filter(
WorkspaceMember.workspace_id == workspace_id, WorkspaceMember.workspace_id == workspace_id,
WorkspaceMember.user_id == user_id, WorkspaceMember.user_id == user_id,
WorkspaceMember.is_active == True, WorkspaceMember.is_active.is_(True),
).first() ).first()
if not member: if not member:
return None return None
@@ -243,7 +243,7 @@ class WorkspaceRepository:
member = self.db.query(WorkspaceMember).filter( member = self.db.query(WorkspaceMember).filter(
WorkspaceMember.workspace_id == workspace_id, WorkspaceMember.workspace_id == workspace_id,
WorkspaceMember.user_id == user_id, WorkspaceMember.user_id == user_id,
WorkspaceMember.is_active == True, WorkspaceMember.is_active.is_(True),
).first() ).first()
if not member: if not member:
return None return None
@@ -259,7 +259,7 @@ class WorkspaceRepository:
try: try:
member = self.db.query(WorkspaceMember).filter( member = self.db.query(WorkspaceMember).filter(
WorkspaceMember.id == member_id, WorkspaceMember.id == member_id,
WorkspaceMember.is_active == True, WorkspaceMember.is_active.is_(True),
).first() ).first()
if not member: if not member:
return None return None
@@ -275,7 +275,7 @@ class WorkspaceRepository:
try: try:
member = self.db.query(WorkspaceMember).filter( member = self.db.query(WorkspaceMember).filter(
WorkspaceMember.id == id, WorkspaceMember.id == id,
WorkspaceMember.is_active == True, WorkspaceMember.is_active.is_(True),
).first() ).first()
if not member: if not member:
return None return None

View File

@@ -55,8 +55,8 @@ class AgentRegistry:
""" """
# 构建查询 # 构建查询
stmt = select(AgentConfig).join(App).where( stmt = select(AgentConfig).join(App).where(
AgentConfig.is_active == True, AgentConfig.is_active.is_(True),
App.is_active == True App.is_active.is_(True)
) )
# 工作空间过滤(同工作空间或公开) # 工作空间过滤(同工作空间或公开)

View File

@@ -758,7 +758,7 @@ class AppService:
) )
# 构建查询条件 # 构建查询条件
filters = [App.is_active == True] filters = [App.is_active.is_(True)]
if type: if type:
filters.append(App.type == type) filters.append(App.type == type)
if visibility: if visibility:
@@ -873,7 +873,7 @@ class AppService:
self._validate_workspace_access(app, workspace_id) self._validate_workspace_access(app, workspace_id)
stmt = select(AgentConfig).where(AgentConfig.app_id == app_id, AgentConfig.is_active == True).order_by( stmt = select(AgentConfig).where(AgentConfig.app_id == app_id, AgentConfig.is_active.is_(True)).order_by(
AgentConfig.updated_at.desc()) AgentConfig.updated_at.desc())
agent_cfg: Optional[AgentConfig] = self.db.scalars(stmt).first() agent_cfg: Optional[AgentConfig] = self.db.scalars(stmt).first()
now = datetime.datetime.now() now = datetime.datetime.now()
@@ -1204,7 +1204,7 @@ class AppService:
default_model_config_id = None default_model_config_id = None
if app.type == AppType.AGENT: if app.type == AppType.AGENT:
stmt = select(AgentConfig).where(AgentConfig.app_id == app_id, AgentConfig.is_active == True).order_by( stmt = select(AgentConfig).where(AgentConfig.app_id == app_id, AgentConfig.is_active.is_(True)).order_by(
AgentConfig.updated_at.desc()) AgentConfig.updated_at.desc())
agent_cfg = self.db.scalars(stmt).first() agent_cfg = self.db.scalars(stmt).first()
if not agent_cfg: if not agent_cfg:
@@ -1226,7 +1226,7 @@ class AppService:
select(MultiAgentConfig) select(MultiAgentConfig)
.where( .where(
MultiAgentConfig.app_id == app_id, MultiAgentConfig.app_id == app_id,
MultiAgentConfig.is_active == True MultiAgentConfig.is_active.is_(True)
) )
.order_by(MultiAgentConfig.updated_at.desc()) .order_by(MultiAgentConfig.updated_at.desc())
) )
@@ -1380,7 +1380,7 @@ class AppService:
stmt = ( stmt = (
select(AppRelease) select(AppRelease)
.where(AppRelease.app_id == app_id, AppRelease.is_active == True) .where(AppRelease.app_id == app_id, AppRelease.is_active.is_(True))
.order_by(AppRelease.version.desc()) .order_by(AppRelease.version.desc())
) )
return list(self.db.scalars(stmt).all()) return list(self.db.scalars(stmt).all())

View File

@@ -728,7 +728,7 @@ class DraftRunService:
select(ModelApiKey) select(ModelApiKey)
.where( .where(
ModelApiKey.model_config_id == model_config_id, ModelApiKey.model_config_id == model_config_id,
ModelApiKey.is_active == True ModelApiKey.is_active.is_(True)
) )
.order_by(ModelApiKey.priority.desc()) .order_by(ModelApiKey.priority.desc())
.limit(1) .limit(1)

View File

@@ -173,10 +173,9 @@ class MemoryAgentService:
""" """
logger.info("Reading log file") logger.info("Reading log file")
# Get log file path - use project root directory
current_file = os.path.abspath(__file__) # app/services/memory_agent_service.py from pathlib import Path
app_dir = os.path.dirname(os.path.dirname(current_file)) # app directory project_root = str(Path(__file__).resolve().parents[2]) # api directory
project_root = os.path.dirname(app_dir) # redbear-mem directory
log_path = os.path.join(project_root, "logs", "agent_service.log") log_path = os.path.join(project_root, "logs", "agent_service.log")
summer = '' summer = ''
@@ -215,9 +214,8 @@ class MemoryAgentService:
logger.info("Starting log content streaming") logger.info("Starting log content streaming")
# Get log file path - use project root directory # Get log file path - use project root directory
current_file = os.path.abspath(__file__) # app/services/memory_agent_service.py from pathlib import Path
app_dir = os.path.dirname(os.path.dirname(current_file)) # app directory project_root = str(Path(__file__).resolve().parents[2]) # api directory
project_root = os.path.dirname(app_dir) # redbear-mem directory
log_path = os.path.join(project_root, "logs", "agent_service.log") log_path = os.path.join(project_root, "logs", "agent_service.log")
# Check if file exists before starting stream # Check if file exists before starting stream
@@ -1079,9 +1077,8 @@ class MemoryAgentService:
logger.info("Starting log content streaming") logger.info("Starting log content streaming")
# Get log file path - use project root directory # Get log file path - use project root directory
current_file = os.path.abspath(__file__) # app/services/memory_agent_service.py from pathlib import Path
app_dir = os.path.dirname(os.path.dirname(current_file)) # app directory project_root = str(Path(__file__).resolve().parents[2]) # api directory
project_root = os.path.dirname(app_dir) # redbear-mem directory
log_path = os.path.join(project_root, "logs", "agent_service.log") log_path = os.path.join(project_root, "logs", "agent_service.log")
# Check if file exists before starting stream # Check if file exists before starting stream

View File

@@ -77,7 +77,10 @@ class MemoryAPIService:
) )
# Verify end_user belongs to the workspace via App relationship # Verify end_user belongs to the workspace via App relationship
app = self.db.query(App).filter(App.id == end_user.app_id).first() app = self.db.query(App).filter(
App.id == end_user.app_id,
App.is_active.is_(True)
).first()
if not app: if not app:
logger.warning(f"App not found for end_user: {end_user_id}") logger.warning(f"App not found for end_user: {end_user_id}")

View File

@@ -38,7 +38,10 @@ class WorkspaceAppService:
Returns: Returns:
Dictionary containing detailed application information Dictionary containing detailed application information
""" """
apps = self.db.query(App).filter(App.workspace_id == workspace_id).all() apps = self.db.query(App).filter(
App.workspace_id == workspace_id,
App.is_active.is_(True)
).all()
app_ids = [str(app.id) for app in apps] app_ids = [str(app.id) for app in apps]
apps_detailed_info = [] apps_detailed_info = []

View File

@@ -237,7 +237,8 @@ class DataConfigService: # 数据配置服务类PostgreSQL
ValueError: 当配置无效或参数缺失时 ValueError: 当配置无效或参数缺失时
RuntimeError: 当管线执行失败时 RuntimeError: 当管线执行失败时
""" """
project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from pathlib import Path
project_root = str(Path(__file__).resolve().parents[2])
try: try:
# 发出初始进度事件 # 发出初始进度事件

View File

@@ -2548,7 +2548,7 @@ class MultiAgentOrchestrator:
# 获取 API Key 配置 # 获取 API Key 配置
api_key_config = self.db.query(ModelApiKey).filter( api_key_config = self.db.query(ModelApiKey).filter(
ModelApiKey.model_config_id == default_model_config_id, ModelApiKey.model_config_id == default_model_config_id,
ModelApiKey.is_active == True ModelApiKey.is_active.is_(True)
).first() ).first()
if not api_key_config: if not api_key_config:
@@ -2705,7 +2705,7 @@ class MultiAgentOrchestrator:
# 获取 API Key 配置 # 获取 API Key 配置
api_key_config = self.db.query(ModelApiKey).filter( api_key_config = self.db.query(ModelApiKey).filter(
ModelApiKey.model_config_id == default_model_config_id, ModelApiKey.model_config_id == default_model_config_id,
ModelApiKey.is_active == True ModelApiKey.is_active.is_(True)
).first() ).first()
if not api_key_config: if not api_key_config:

View File

@@ -74,7 +74,7 @@ class MultiAgentService:
select(MultiAgentConfig) select(MultiAgentConfig)
.where( .where(
MultiAgentConfig.app_id == app_id, MultiAgentConfig.app_id == app_id,
MultiAgentConfig.is_active == True MultiAgentConfig.is_active.is_(True)
) )
.order_by(MultiAgentConfig.updated_at.desc()) .order_by(MultiAgentConfig.updated_at.desc())
).first() ).first()
@@ -144,7 +144,7 @@ class MultiAgentService:
select(MultiAgentConfig) select(MultiAgentConfig)
.where( .where(
MultiAgentConfig.app_id == app_id, MultiAgentConfig.app_id == app_id,
MultiAgentConfig.is_active == True MultiAgentConfig.is_active.is_(True)
) )
.order_by(MultiAgentConfig.updated_at.desc()) .order_by(MultiAgentConfig.updated_at.desc())
).first() ).first()

View File

@@ -168,7 +168,7 @@ class SharedChatService:
select(ModelApiKey) select(ModelApiKey)
.where( .where(
ModelApiKey.model_config_id == model_config_id, ModelApiKey.model_config_id == model_config_id,
ModelApiKey.is_active == True ModelApiKey.is_active.is_(True)
) )
.order_by(ModelApiKey.priority.desc()) .order_by(ModelApiKey.priority.desc())
.limit(1) .limit(1)
@@ -362,7 +362,7 @@ class SharedChatService:
select(ModelApiKey) select(ModelApiKey)
.where( .where(
ModelApiKey.model_config_id == model_config_id, ModelApiKey.model_config_id == model_config_id,
ModelApiKey.is_active == True ModelApiKey.is_active.is_(True)
) )
.order_by(ModelApiKey.priority.desc()) .order_by(ModelApiKey.priority.desc())
.limit(1) .limit(1)
@@ -598,7 +598,7 @@ class SharedChatService:
# 获取多 Agent 配置 # 获取多 Agent 配置
multi_agent_config = self.db.query(MultiAgentConfig).filter( multi_agent_config = self.db.query(MultiAgentConfig).filter(
MultiAgentConfig.app_id == release.app_id, MultiAgentConfig.app_id == release.app_id,
MultiAgentConfig.is_active == True MultiAgentConfig.is_active.is_(True)
).first() ).first()
if not multi_agent_config: if not multi_agent_config:
@@ -695,7 +695,7 @@ class SharedChatService:
# 获取多 Agent 配置 # 获取多 Agent 配置
multi_agent_config = self.db.query(MultiAgentConfig).filter( multi_agent_config = self.db.query(MultiAgentConfig).filter(
MultiAgentConfig.app_id == release.app_id, MultiAgentConfig.app_id == release.app_id,
MultiAgentConfig.is_active == True MultiAgentConfig.is_active.is_(True)
).first() ).first()
if not multi_agent_config: if not multi_agent_config:

View File

@@ -761,7 +761,10 @@ class WorkflowService:
# 4. 获取工作空间 ID从 app 获取) # 4. 获取工作空间 ID从 app 获取)
from app.models import App from app.models import App
app = self.db.query(App).filter(App.id == app_id).first() app = self.db.query(App).filter(
App.id == app_id,
App.is_active.is_(True)
).first()
if not app: if not app:
raise BusinessException( raise BusinessException(
code=BizCode.NOT_FOUND, code=BizCode.NOT_FOUND,

View File

@@ -635,8 +635,11 @@ def write_total_memory_task(workspace_id: str) -> Dict[str, Any]:
try: try:
workspace_uuid = uuid.UUID(workspace_id) workspace_uuid = uuid.UUID(workspace_id)
# 1. 查询当前workspace下的所有app # 1. 查询当前workspace下的所有app(仅未删除的)
apps = db.query(App).filter(App.workspace_id == workspace_uuid).all() apps = db.query(App).filter(
App.workspace_id == workspace_uuid,
App.is_active.is_(True)
).all()
if not apps: if not apps:
# 如果没有app总量为0 # 如果没有app总量为0

View File

@@ -46,7 +46,8 @@ def import_all_models_from_package(package_name: str):
# Add the project root to sys.path if not already there # Add the project root to sys.path if not already there
# This is crucial for relative imports like 'app.db' to work # This is crucial for relative imports like 'app.db' to work
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) from pathlib import Path
project_root = str(Path(__file__).resolve().parent.parent)
if project_root not in sys.path: if project_root not in sys.path:
sys.path.insert(0, project_root) sys.path.insert(0, project_root)