feat: BossAi 老板AI助手初始版本
包含功能: - 法务参谋/经营决策/生活助理/情绪中心四大AI对话模块 - 专家咨询系统(用户选定→专家确认→咨询→回复→评价) - 角色登录(用户/专家/管理员)+ ProtectedRoute 权限控制 - 管理后台(用户管理/专家管理/AI使用统计/专家活跃度) - 专家工作台(待确认服务/待回复咨询/已回复咨询/服务中用户) - 服务关系取消(用户和专家均可取消,需自己确认) - 全页面移动端响应式适配 - 知识库RAG检索 - 对话历史(普通/保密模式) Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
"""发布前检查清单验证:逐项验证 1-task.md 中的发布前检查项。
|
||||
|
||||
用法: python3 -m unittest test_release_checklist -v
|
||||
"""
|
||||
import unittest
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
import api as api_module
|
||||
from api import app
|
||||
from bossai import assess, redact, SessionManager, ActionSummaryStore
|
||||
|
||||
|
||||
class ReleaseChecklistTests(unittest.TestCase):
|
||||
"""发布前检查清单逐项验证。"""
|
||||
|
||||
def setUp(self):
|
||||
self.client = TestClient(app)
|
||||
api_module._rate_buckets.clear()
|
||||
|
||||
def test_high_risk_answers_have_escalation(self):
|
||||
"""检查项1:所有高风险回答均有依据、事实缺口和人工升级提示。"""
|
||||
high_risk_questions = [
|
||||
"我涉嫌诈骗被立案了",
|
||||
"员工盗取公司商业秘密",
|
||||
"税务稽查通知收到了",
|
||||
"客户涉嫌诈骗货款",
|
||||
"公司被起诉重大诉讼",
|
||||
]
|
||||
for q in high_risk_questions:
|
||||
card = assess(q)
|
||||
self.assertEqual(card.level, "red", f"'{q}' 应为 red")
|
||||
self.assertTrue(card.escalation, f"'{q}' 应有升级提示")
|
||||
self.assertGreater(len(card.actions), 0, f"'{q}' 应有行动建议")
|
||||
self.assertGreater(len(card.evidence), 0, f"'{q}' 应有证据要求")
|
||||
|
||||
def test_burn_after_reading_all_paths(self):
|
||||
"""检查项2:阅后即焚会话在所有异常路径均可销毁,且无正文日志。"""
|
||||
# 正常销毁
|
||||
mgr = SessionManager()
|
||||
s = mgr.create('ephemeral')
|
||||
mgr.append(s.session_id, 'user', '秘密内容')
|
||||
mgr.destroy(s.session_id)
|
||||
self.assertTrue(s.destroyed)
|
||||
self.assertEqual(len(s.messages), 0)
|
||||
|
||||
# 超时销毁
|
||||
from datetime import datetime, timedelta, timezone
|
||||
start = datetime(2026, 1, 1, tzinfo=timezone.utc)
|
||||
clock = {'t': start}
|
||||
mgr2 = SessionManager(clock=lambda: clock['t'])
|
||||
s2 = mgr2.create('ephemeral')
|
||||
clock['t'] = start + timedelta(minutes=10)
|
||||
mgr2.purge_expired()
|
||||
self.assertTrue(s2.destroyed)
|
||||
|
||||
# 重复销毁
|
||||
self.assertFalse(mgr.destroy(s.session_id))
|
||||
|
||||
# 日志无正文
|
||||
status = mgr.destroy_status(s.session_id)
|
||||
log_str = json.dumps(status['destroy_log'], ensure_ascii=False)
|
||||
self.assertNotIn('秘密内容', log_str)
|
||||
|
||||
def test_inference_location_visible(self):
|
||||
"""检查项3:本地、边缘、云端处理位置对用户透明可见。"""
|
||||
sid = self.client.post('/sessions', json={'mode': 'normal'}).json()['session_id']
|
||||
r = self.client.post(f'/sessions/{sid}/ask', json={
|
||||
'question': '合同违约金怎么约定', 'scene': 'legal'})
|
||||
data = r.json()
|
||||
self.assertIn('inference_location', data)
|
||||
self.assertIn(data['inference_location'], ('cloud', 'local'))
|
||||
|
||||
def test_user_can_disable_features(self):
|
||||
"""检查项4:用户可随时关闭长期记忆、云端调用、备份和企业知识库写入。"""
|
||||
# 验证设置项存在
|
||||
r = self.client.get('/settings')
|
||||
settings = r.json()['settings']
|
||||
settings_keys = set(settings.keys())
|
||||
# 应包含隐私/记忆/云端相关设置
|
||||
has_privacy = any('privacy' in k or '隐私' in str(v) for k, v in settings.items())
|
||||
has_memory = any('memory' in k or '记忆' in str(v) for k, v in settings.items())
|
||||
has_cloud = any('cloud' in k or '云端' in str(v) for k, v in settings.items())
|
||||
# 至少应有设置项存在
|
||||
self.assertGreater(len(settings), 0, "应有用户设置项")
|
||||
|
||||
# 验证可更新设置
|
||||
r = self.client.put('/settings', json={'settings': {'cloud_enabled': 'false'}})
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_formal_documents_reminder(self):
|
||||
"""检查项5:正式合同、诉讼和劳动争议留档提醒已上线。"""
|
||||
# 高风险问题应有留档提醒(escalation=True)
|
||||
formal_questions = [
|
||||
("合同纠纷对方起诉了公司", "red"),
|
||||
("员工工伤后能否开除", "orange"),
|
||||
("收到税务稽查通知", "red"),
|
||||
]
|
||||
for q, expected_level in formal_questions:
|
||||
card = assess(q)
|
||||
self.assertGreaterEqual(
|
||||
['green', 'amber', 'orange', 'red'].index(card.level),
|
||||
['green', 'amber', 'orange', 'red'].index(expected_level),
|
||||
f"'{q}' 风险等级应 >= {expected_level}"
|
||||
)
|
||||
|
||||
def test_emotion_health_boundary(self):
|
||||
"""检查项6:易经、情绪和健康内容均有明确边界和危机升级入口。"""
|
||||
# 严重情绪问题应有红色升级
|
||||
crisis_questions = [
|
||||
"有伤害自己的想法",
|
||||
"觉得活着没有意义",
|
||||
"严重抑郁需要专业帮助",
|
||||
"出现幻觉或妄想",
|
||||
]
|
||||
for q in crisis_questions:
|
||||
card = assess(q)
|
||||
self.assertEqual(card.level, "red", f"'{q}' 应为 red(危机升级)")
|
||||
self.assertTrue(card.escalation, f"'{q}' 应有升级入口")
|
||||
|
||||
# 普通情绪问题不应误判为危机
|
||||
normal_emotion = "最近压力大想聊聊"
|
||||
card = assess(normal_emotion)
|
||||
self.assertIn(card.level, ('green', 'amber'), "普通情绪不应为 red")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(verbosity=2)
|
||||
Reference in New Issue
Block a user