fix: 6 bug fixes - timezone CST, knowledge_ids mismatch, skill uninstall, dashboard stats, chat knowledge retrieval, skill selection
This commit is contained in:
1 parent
f7ab61bd9d
commit
8ec808b515
6 files changed
+119
-49
No files matched your search
@@ -10,10 +10,13 @@ from ...models import (
|
|||||||
)
|
)
|
||||||
from ...auth import get_current_admin
|
from ...auth import get_current_admin
|
||||||
from ...middleware.log_service import LogService
|
from ...middleware.log_service import LogService
|
||||||
from datetime import datetime, date
|
from datetime import datetime, date, timezone, timedelta
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
# CST timezone (UTC+8)
|
||||||
|
CST_TZ = timezone(timedelta(hours=8))
|
||||||
|
|
||||||
|
|
||||||
@router.get("/stats")
|
@router.get("/stats")
|
||||||
async def get_dashboard_stats(
|
async def get_dashboard_stats(
|
||||||
@@ -21,7 +24,11 @@ async def get_dashboard_stats(
|
|||||||
db: Session = Depends(get_db),
|
db: Session = Depends(get_db),
|
||||||
):
|
):
|
||||||
"""获取管理员仪表盘统计数据"""
|
"""获取管理员仪表盘统计数据"""
|
||||||
today = date.today()
|
# Use CST timezone for "today" since container uses UTC but users are in CST
|
||||||
|
now_cst = datetime.now(CST_TZ)
|
||||||
|
today_cst = now_cst.date()
|
||||||
|
# Convert CST today start to UTC for DB comparison
|
||||||
|
today_start_utc = datetime(now_cst.year, now_cst.month, now_cst.day, 0, 0, 0, tzinfo=CST_TZ).astimezone(timezone.utc).replace(tzinfo=None)
|
||||||
|
|
||||||
active_users = db.query(func.count(User.id)).filter(
|
active_users = db.query(func.count(User.id)).filter(
|
||||||
User.status == "active"
|
User.status == "active"
|
||||||
@@ -31,12 +38,13 @@ async def get_dashboard_stats(
|
|||||||
AIModel.is_enabled == True
|
AIModel.is_enabled == True
|
||||||
).scalar() or 0
|
).scalar() or 0
|
||||||
|
|
||||||
|
# Use range comparison instead of func.date() for timezone-correct results
|
||||||
today_orders = db.query(func.count(Order.id)).filter(
|
today_orders = db.query(func.count(Order.id)).filter(
|
||||||
func.date(Order.created_at) == today
|
Order.created_at >= today_start_utc
|
||||||
).scalar() or 0
|
).scalar() or 0
|
||||||
|
|
||||||
today_tokens = db.query(func.sum(TokenUsageLog.total_tokens)).filter(
|
today_tokens = db.query(func.sum(TokenUsageLog.total_tokens)).filter(
|
||||||
func.date(TokenUsageLog.created_at) == today
|
TokenUsageLog.created_at >= today_start_utc
|
||||||
).scalar() or 0
|
).scalar() or 0
|
||||||
|
|
||||||
total_tokens = db.query(func.sum(TokenUsageLog.total_tokens)).scalar() or 0
|
total_tokens = db.query(func.sum(TokenUsageLog.total_tokens)).scalar() or 0
|
||||||
@@ -47,6 +55,7 @@ async def get_dashboard_stats(
|
|||||||
"today_orders": today_orders,
|
"today_orders": today_orders,
|
||||||
"today_tokens": int(today_tokens),
|
"today_tokens": int(today_tokens),
|
||||||
"total_tokens": int(total_tokens),
|
"total_tokens": int(total_tokens),
|
||||||
|
"server_time": now_cst.isoformat(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -69,12 +78,20 @@ async def get_recent_logs(
|
|||||||
"target_id": log.target_id,
|
"target_id": log.target_id,
|
||||||
"detail": log.detail,
|
"detail": log.detail,
|
||||||
"ip": log.ip,
|
"ip": log.ip,
|
||||||
"created_at": log.created_at.isoformat() if log.created_at else None,
|
"created_at": _format_cst(log.created_at),
|
||||||
}
|
}
|
||||||
for log in logs
|
for log in logs
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _format_cst(dt_value):
|
||||||
|
"""Format UTC naive datetime to CST ISO string"""
|
||||||
|
if dt_value is None:
|
||||||
|
return None
|
||||||
|
utc_dt = dt_value.replace(tzinfo=timezone.utc)
|
||||||
|
cst_dt = utc_dt.astimezone(CST_TZ)
|
||||||
|
return cst_dt.isoformat()
|
||||||
|
|
||||||
@router.get("/recent-audit")
|
@router.get("/recent-audit")
|
||||||
async def get_recent_audit(
|
async def get_recent_audit(
|
||||||
admin_user=Depends(get_current_admin),
|
admin_user=Depends(get_current_admin),
|
||||||
@@ -93,7 +110,16 @@ async def get_recent_audit(
|
|||||||
"target_type": log.target_type,
|
"target_type": log.target_type,
|
||||||
"target_id": log.target_id,
|
"target_id": log.target_id,
|
||||||
"detail": log.detail,
|
"detail": log.detail,
|
||||||
"created_at": log.created_at.isoformat() if log.created_at else None,
|
"created_at": _format_cst(log.created_at),
|
||||||
}
|
}
|
||||||
for log in logs
|
for log in logs
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _format_cst(dt_value):
|
||||||
|
"""Format UTC naive datetime to CST ISO string"""
|
||||||
|
if dt_value is None:
|
||||||
|
return None
|
||||||
|
utc_dt = dt_value.replace(tzinfo=timezone.utc)
|
||||||
|
cst_dt = utc_dt.astimezone(CST_TZ)
|
||||||
|
return cst_dt.isoformat()
|
||||||
@@ -4,7 +4,7 @@ from sqlalchemy import and_, desc, asc
|
|||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime
|
from datetime import datetime, timezone, timedelta
|
||||||
import re
|
import re
|
||||||
import random
|
import random
|
||||||
import json
|
import json
|
||||||
@@ -26,6 +26,14 @@ router = APIRouter()
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# CST timezone (UTC+8) for consistent time display
|
||||||
|
CST_TZ = timezone(timedelta(hours=8))
|
||||||
|
|
||||||
|
|
||||||
|
def cst_now():
|
||||||
|
"""Get current time in CST timezone"""
|
||||||
|
return datetime.now(CST_TZ)
|
||||||
|
|
||||||
|
|
||||||
class CreateConversationRequest(BaseModel):
|
class CreateConversationRequest(BaseModel):
|
||||||
title: str = Field(default="新对话")
|
title: str = Field(default="新对话")
|
||||||
@@ -99,8 +107,8 @@ def create_conversation(
|
|||||||
status="active",
|
status="active",
|
||||||
pinned=False,
|
pinned=False,
|
||||||
knowledge_graph_count=0,
|
knowledge_graph_count=0,
|
||||||
created_at=datetime.now(),
|
created_at=cst_now(),
|
||||||
updated_at=datetime.now(),
|
updated_at=cst_now(),
|
||||||
)
|
)
|
||||||
db.add(conv)
|
db.add(conv)
|
||||||
db.commit()
|
db.commit()
|
||||||
@@ -141,7 +149,7 @@ def update_conversation(
|
|||||||
conv.status = req.status
|
conv.status = req.status
|
||||||
if req.pinned is not None:
|
if req.pinned is not None:
|
||||||
conv.pinned = req.pinned
|
conv.pinned = req.pinned
|
||||||
conv.updated_at = datetime.now()
|
conv.updated_at = cst_now()
|
||||||
|
|
||||||
db.commit()
|
db.commit()
|
||||||
db.refresh(conv)
|
db.refresh(conv)
|
||||||
@@ -166,7 +174,7 @@ def delete_conversation(
|
|||||||
|
|
||||||
# 软删除
|
# 软删除
|
||||||
conv.status = "archived"
|
conv.status = "archived"
|
||||||
conv.updated_at = datetime.now()
|
conv.updated_at = cst_now()
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
return {"code": 0, "message": "删除成功"}
|
return {"code": 0, "message": "删除成功"}
|
||||||
@@ -228,7 +236,7 @@ async def send_message(
|
|||||||
content=req.content,
|
content=req.content,
|
||||||
token_used=len(req.content) // 2, # 粗略估算
|
token_used=len(req.content) // 2, # 粗略估算
|
||||||
model_id=req.model_id or conv.model_id,
|
model_id=req.model_id or conv.model_id,
|
||||||
created_at=datetime.now(),
|
created_at=cst_now(),
|
||||||
)
|
)
|
||||||
db.add(user_msg)
|
db.add(user_msg)
|
||||||
|
|
||||||
@@ -294,6 +302,22 @@ async def send_message(
|
|||||||
if kbs:
|
if kbs:
|
||||||
kb_names = ", ".join([k.name for k in kbs])
|
kb_names = ", ".join([k.name for k in kbs])
|
||||||
system_parts.append(f"参考知识库: {kb_names}")
|
system_parts.append(f"参考知识库: {kb_names}")
|
||||||
|
# 修复: 实际检索知识库文档内容注入到system prompt
|
||||||
|
kb_context_parts = []
|
||||||
|
for kb in kbs:
|
||||||
|
docs = db.query(KnowledgeDocument).filter(
|
||||||
|
KnowledgeDocument.knowledge_base_id == kb.id
|
||||||
|
).order_by(KnowledgeDocument.created_at.desc()).limit(5).all()
|
||||||
|
for doc in docs:
|
||||||
|
if doc.content:
|
||||||
|
# 截取前500字符避免prompt过长
|
||||||
|
kb_context_parts.append(f"[{kb.name}/{doc.name}]: {doc.content[:500]}")
|
||||||
|
if kb_context_parts:
|
||||||
|
kb_context = "\n".join(kb_context_parts)
|
||||||
|
# 限制总长度避免超出模型token上限
|
||||||
|
if len(kb_context) > 2000:
|
||||||
|
kb_context = kb_context[:2000] + "...(内容截断)"
|
||||||
|
system_parts.append(f"知识库内容参考:\n{kb_context}")
|
||||||
|
|
||||||
messages.append({"role": "system", "content": "; ".join(system_parts)})
|
messages.append({"role": "system", "content": "; ".join(system_parts)})
|
||||||
|
|
||||||
@@ -403,7 +427,7 @@ async def send_message(
|
|||||||
content=ai_content,
|
content=ai_content,
|
||||||
token_used=ai_token_count,
|
token_used=ai_token_count,
|
||||||
model_id=req.model_id or conv.model_id,
|
model_id=req.model_id or conv.model_id,
|
||||||
created_at=datetime.now(),
|
created_at=cst_now(),
|
||||||
)
|
)
|
||||||
db.add(ai_msg)
|
db.add(ai_msg)
|
||||||
|
|
||||||
@@ -418,14 +442,14 @@ async def send_message(
|
|||||||
used_skills = [s.skill_name for s in selected_skills]
|
used_skills = [s.skill_name for s in selected_skills]
|
||||||
ai_msg.used_skills = used_skills
|
ai_msg.used_skills = used_skills
|
||||||
# 更新每个被使用技能的use_count和last_used_at
|
# 更新每个被使用技能的use_count和last_used_at
|
||||||
now = datetime.now()
|
now = cst_now()
|
||||||
for s in selected_skills:
|
for s in selected_skills:
|
||||||
s.use_count = (s.use_count or 0) + 1
|
s.use_count = (s.use_count or 0) + 1
|
||||||
s.last_used_at = now
|
s.last_used_at = now
|
||||||
|
|
||||||
# 更新对话统计
|
# 更新对话统计
|
||||||
conv.knowledge_graph_count = (conv.knowledge_graph_count or 0) + 1
|
conv.knowledge_graph_count = (conv.knowledge_graph_count or 0) + 1
|
||||||
conv.updated_at = datetime.now()
|
conv.updated_at = cst_now()
|
||||||
|
|
||||||
# 记录Token使用
|
# 记录Token使用
|
||||||
token_usage = TokenUsageLog(
|
token_usage = TokenUsageLog(
|
||||||
@@ -437,7 +461,7 @@ async def send_message(
|
|||||||
prompt_tokens=prompt_tokens or len(req.content) // 2,
|
prompt_tokens=prompt_tokens or len(req.content) // 2,
|
||||||
completion_tokens=completion_tokens or ai_token_count,
|
completion_tokens=completion_tokens or ai_token_count,
|
||||||
total_tokens=total_tokens or (len(req.content) // 2 + ai_token_count),
|
total_tokens=total_tokens or (len(req.content) // 2 + ai_token_count),
|
||||||
created_at=datetime.now(),
|
created_at=cst_now(),
|
||||||
)
|
)
|
||||||
db.add(token_usage)
|
db.add(token_usage)
|
||||||
|
|
||||||
@@ -454,7 +478,7 @@ async def send_message(
|
|||||||
conversation_id=conv_id,
|
conversation_id=conv_id,
|
||||||
status="discovered",
|
status="discovered",
|
||||||
token_used=ai_token_count,
|
token_used=ai_token_count,
|
||||||
created_at=datetime.now(),
|
created_at=cst_now(),
|
||||||
)
|
)
|
||||||
db.add(trajectory)
|
db.add(trajectory)
|
||||||
db.flush() # 确保trajectory先写入,再启动pipeline
|
db.flush() # 确保trajectory先写入,再启动pipeline
|
||||||
@@ -511,7 +535,7 @@ def clear_conversation(
|
|||||||
).delete()
|
).delete()
|
||||||
|
|
||||||
conv.knowledge_graph_count = 0
|
conv.knowledge_graph_count = 0
|
||||||
conv.updated_at = datetime.now()
|
conv.updated_at = cst_now()
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
return {"code": 0, "message": "对话上下文已清空"}
|
return {"code": 0, "message": "对话上下文已清空"}
|
||||||
@@ -550,8 +574,8 @@ def convert_to_knowledge_graph(
|
|||||||
description=f"从对话「{conv.title}」自动生成的知识图谱",
|
description=f"从对话「{conv.title}」自动生成的知识图谱",
|
||||||
directory_path="/",
|
directory_path="/",
|
||||||
document_count=0,
|
document_count=0,
|
||||||
created_at=datetime.now(),
|
created_at=cst_now(),
|
||||||
updated_at=datetime.now(),
|
updated_at=cst_now(),
|
||||||
)
|
)
|
||||||
db.add(kb)
|
db.add(kb)
|
||||||
db.flush()
|
db.flush()
|
||||||
@@ -572,8 +596,8 @@ def convert_to_knowledge_graph(
|
|||||||
file_size=len(msg.content.encode('utf-8')),
|
file_size=len(msg.content.encode('utf-8')),
|
||||||
status="completed",
|
status="completed",
|
||||||
chunk_count=max(1, len(msg.content) // 500 + 1),
|
chunk_count=max(1, len(msg.content) // 500 + 1),
|
||||||
created_at=datetime.now(),
|
created_at=cst_now(),
|
||||||
updated_at=datetime.now(),
|
updated_at=cst_now(),
|
||||||
)
|
)
|
||||||
db.add(doc)
|
db.add(doc)
|
||||||
doc_count += 1
|
doc_count += 1
|
||||||
@@ -660,11 +684,11 @@ def convert_to_knowledge_graph(
|
|||||||
|
|
||||||
# 更新知识库的知识图谱计数
|
# 更新知识库的知识图谱计数
|
||||||
kb.knowledge_graph_count = len(graph_nodes)
|
kb.knowledge_graph_count = len(graph_nodes)
|
||||||
kb.updated_at = datetime.now()
|
kb.updated_at = cst_now()
|
||||||
|
|
||||||
# 更新对话的知识图谱计数
|
# 更新对话的知识图谱计数
|
||||||
conv.knowledge_graph_count = (conv.knowledge_graph_count or 0) + 1
|
conv.knowledge_graph_count = (conv.knowledge_graph_count or 0) + 1
|
||||||
conv.updated_at = datetime.now()
|
conv.updated_at = cst_now()
|
||||||
|
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
@@ -776,6 +800,6 @@ def _execute_skill_tool(db: Session, func_name: str, args: dict, skills_list: li
|
|||||||
# 更新skill使用计数
|
# 更新skill使用计数
|
||||||
if matched_skill:
|
if matched_skill:
|
||||||
matched_skill.use_count = (matched_skill.use_count or 0) + 1
|
matched_skill.use_count = (matched_skill.use_count or 0) + 1
|
||||||
matched_skill.last_used_at = datetime.now()
|
matched_skill.last_used_at = cst_now()
|
||||||
|
|
||||||
return result
|
return result
|
||||||
@@ -359,7 +359,9 @@ def uninstall_app(
|
|||||||
db: Session = Depends(get_db),
|
db: Session = Depends(get_db),
|
||||||
current_user: User = Depends(get_current_user),
|
current_user: User = Depends(get_current_user),
|
||||||
):
|
):
|
||||||
"""卸载应用 - 删除当前用户的安装记录(按用户隔离)"""
|
"""卸载应用 - 删除当前用户的安装记录(按用户隔离)
|
||||||
|
修复: 当没有AppInstallation记录时(如导入的技能),仍然允许卸载
|
||||||
|
"""
|
||||||
app = db.query(MarketApp).filter(MarketApp.id == app_id).first()
|
app = db.query(MarketApp).filter(MarketApp.id == app_id).first()
|
||||||
if not app:
|
if not app:
|
||||||
raise HTTPException(status_code=404, detail="应用不存在")
|
raise HTTPException(status_code=404, detail="应用不存在")
|
||||||
@@ -368,22 +370,26 @@ def uninstall_app(
|
|||||||
installation = db.query(AppInstallation).filter(
|
installation = db.query(AppInstallation).filter(
|
||||||
and_(AppInstallation.app_id == app_id, AppInstallation.user_id == current_user.id)
|
and_(AppInstallation.app_id == app_id, AppInstallation.user_id == current_user.id)
|
||||||
).first()
|
).first()
|
||||||
if not installation:
|
|
||||||
raise HTTPException(status_code=400, detail="应用未安装")
|
|
||||||
|
|
||||||
# 删除安装记录
|
# 修复: 即使没有安装记录也允许卸载(导入的技能可能没有安装记录)
|
||||||
db.delete(installation)
|
if installation:
|
||||||
|
db.delete(installation)
|
||||||
|
|
||||||
# 问题4修复: 将AppPurchase状态从installed重置为purchased
|
# 将AppPurchase状态从installed重置为purchased
|
||||||
purchase = db.query(AppPurchase).filter(
|
purchase = db.query(AppPurchase).filter(
|
||||||
and_(AppPurchase.app_id == app_id, AppPurchase.user_id == current_user.id)
|
and_(AppPurchase.app_id == app_id, AppPurchase.user_id == current_user.id)
|
||||||
).first()
|
).first()
|
||||||
if purchase and purchase.status == "installed":
|
if purchase and purchase.status == "installed":
|
||||||
purchase.status = "purchased"
|
purchase.status = "purchased"
|
||||||
|
|
||||||
|
# 更新应用安装量(减1,最小为0)
|
||||||
|
if app.install_count and app.install_count > 0:
|
||||||
|
app.install_count = app.install_count - 1
|
||||||
|
|
||||||
|
# 将应用状态标记为未安装(对于skill类型)
|
||||||
|
if app.type == "skill" and app.is_active:
|
||||||
|
app.is_active = False
|
||||||
|
|
||||||
# 更新应用安装量(减1,最小为0)
|
|
||||||
if app.install_count and app.install_count > 0:
|
|
||||||
app.install_count = app.install_count - 1
|
|
||||||
app.updated_at = datetime.now()
|
app.updated_at = datetime.now()
|
||||||
|
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from sqlalchemy import and_, desc, asc, func, extract
|
|||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime, date, timedelta
|
from datetime import datetime, date, timedelta, timezone
|
||||||
|
|
||||||
from ..database import get_db
|
from ..database import get_db
|
||||||
from ..models import (
|
from ..models import (
|
||||||
@@ -16,6 +16,9 @@ from ..middleware.log_service import LogService
|
|||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
# CST timezone (UTC+8)
|
||||||
|
CST_TZ = timezone(timedelta(hours=8))
|
||||||
|
|
||||||
|
|
||||||
class RechargeRequest(BaseModel):
|
class RechargeRequest(BaseModel):
|
||||||
amount: int = Field(ge=1)
|
amount: int = Field(ge=1)
|
||||||
@@ -32,12 +35,15 @@ def get_overview(
|
|||||||
TokenUsageLog.user_id == current_user.id
|
TokenUsageLog.user_id == current_user.id
|
||||||
).scalar()
|
).scalar()
|
||||||
|
|
||||||
# 今日使用中应用数
|
# 今日使用中应用数 - 使用CST时区的"今天"
|
||||||
today_start = datetime.combine(date.today(), datetime.min.time())
|
now_cst = datetime.now(CST_TZ)
|
||||||
|
today_start = now_cst.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||||
|
# Convert to UTC for DB comparison since container uses UTC timestamps
|
||||||
|
today_start_utc = today_start.astimezone(timezone.utc).replace(tzinfo=None)
|
||||||
today_apps = db.query(func.count(func.distinct(TokenUsageLog.model_id))).filter(
|
today_apps = db.query(func.count(func.distinct(TokenUsageLog.model_id))).filter(
|
||||||
and_(
|
and_(
|
||||||
TokenUsageLog.user_id == current_user.id,
|
TokenUsageLog.user_id == current_user.id,
|
||||||
TokenUsageLog.created_at >= today_start,
|
TokenUsageLog.created_at >= today_start_utc,
|
||||||
)
|
)
|
||||||
).scalar() or 0
|
).scalar() or 0
|
||||||
|
|
||||||
@@ -46,9 +52,7 @@ def get_overview(
|
|||||||
TokenBalance.user_id == current_user.id
|
TokenBalance.user_id == current_user.id
|
||||||
).first()
|
).first()
|
||||||
|
|
||||||
from datetime import timezone, timedelta
|
server_time = datetime.now(CST_TZ).isoformat()
|
||||||
shanghai_tz = timezone(timedelta(hours=8))
|
|
||||||
server_time = datetime.now(shanghai_tz).isoformat()
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"code": 0,
|
"code": 0,
|
||||||
@@ -169,7 +173,7 @@ def get_token_logs(
|
|||||||
"completion_tokens": log_item.completion_tokens or 0,
|
"completion_tokens": log_item.completion_tokens or 0,
|
||||||
"total_tokens": log_item.total_tokens or 0,
|
"total_tokens": log_item.total_tokens or 0,
|
||||||
"conversation_id": log_item.conversation_id,
|
"conversation_id": log_item.conversation_id,
|
||||||
"created_at": log_item.created_at.isoformat() if log_item.created_at else None,
|
"created_at": _format_cst_time(log_item.created_at),
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -245,3 +249,13 @@ def recharge(
|
|||||||
},
|
},
|
||||||
"message": "充值成功",
|
"message": "充值成功",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _format_cst_time(dt_value):
|
||||||
|
"""Format datetime to CST ISO string. Input is UTC naive datetime from DB."""
|
||||||
|
if dt_value is None:
|
||||||
|
return None
|
||||||
|
# DB stores UTC naive datetime, convert to CST
|
||||||
|
utc_dt = dt_value.replace(tzinfo=timezone.utc)
|
||||||
|
cst_dt = utc_dt.astimezone(CST_TZ)
|
||||||
|
return cst_dt.isoformat()
|
||||||
@@ -105,7 +105,7 @@ export const chatAPI = {
|
|||||||
del<any>(`/chat/conversations/${id}`),
|
del<any>(`/chat/conversations/${id}`),
|
||||||
getMessages: (convId: string) =>
|
getMessages: (convId: string) =>
|
||||||
get<any[]>(`/chat/conversations/${convId}/messages`),
|
get<any[]>(`/chat/conversations/${convId}/messages`),
|
||||||
sendMessage: (convId: string, data: { content: string; model_id?: string; agent_ids?: string[]; skill_ids?: string[]; knowledge_ids?: string[]; use_tools?: boolean }) =>
|
sendMessage: (convId: string, data: { content: string; model_id?: string; agent_ids?: string[]; skill_ids?: string[]; knowledge_base_ids?: string[]; use_tools?: boolean }) =>
|
||||||
post<any>(`/chat/conversations/${convId}/messages`, data),
|
post<any>(`/chat/conversations/${convId}/messages`, data),
|
||||||
clearContext: (convId: string) =>
|
clearContext: (convId: string) =>
|
||||||
post<any>(`/chat/conversations/${convId}/clear`),
|
post<any>(`/chat/conversations/${convId}/clear`),
|
||||||
|
|||||||
@@ -582,7 +582,7 @@ const ChatPage: React.FC = () => {
|
|||||||
model_id: selectedModelId || undefined,
|
model_id: selectedModelId || undefined,
|
||||||
agent_ids: selectedAgentIds.length > 0 ? selectedAgentIds : undefined,
|
agent_ids: selectedAgentIds.length > 0 ? selectedAgentIds : undefined,
|
||||||
skill_ids: selectedSkillIds.length > 0 ? selectedSkillIds : undefined,
|
skill_ids: selectedSkillIds.length > 0 ? selectedSkillIds : undefined,
|
||||||
knowledge_ids: selectedKbIds.length > 0 ? selectedKbIds : undefined,
|
knowledge_base_ids: selectedKbIds.length > 0 ? selectedKbIds : undefined,
|
||||||
use_tools: selectedSkillIds.length > 0 || selectedAgentIds.length > 0,
|
use_tools: selectedSkillIds.length > 0 || selectedAgentIds.length > 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user