30 | {/* 头部 */}
31 |
32 |
33 |
Person Data
34 |
35 | 个人数据管理
36 |
37 |
38 |
39 | {/* 标签切换 */}
40 |
41 |
42 |
53 |
64 |
65 |
66 |
67 | {/* 内容区域 */}
68 |
69 | {activeTab === 'notes' && }
70 | {activeTab === 'todos' && }
71 |
72 |
73 | );
74 | }
--------------------------------------------------------------------------------
/ui/src/components/guardrails.tsx:
--------------------------------------------------------------------------------
1 | import { Shield, CheckCircle, XCircle } from "lucide-react";
2 | import type { GuardrailCheck } from "../lib/types";
3 |
4 | interface GuardrailsProps {
5 | guardrails: GuardrailCheck[];
6 | inputGuardrails: string[];
7 | }
8 |
9 | export function Guardrails({ guardrails, inputGuardrails }: GuardrailsProps) {
10 | const activeGuardrails = guardrails.filter(g =>
11 | inputGuardrails.includes(g.name) || inputGuardrails.includes(g.id)
12 | );
13 |
14 | return (
15 |
16 |
17 |
18 |
19 | 安全护栏检查
20 |
21 |
22 |
23 | {activeGuardrails.length === 0 && (
24 |
25 | 当前代理没有激活的护栏检查
26 |
27 | )}
28 |
29 | {activeGuardrails.map((check) => (
30 |
38 |
39 | {check.passed ? (
40 |
41 | ) : (
42 |
43 | )}
44 |
45 |
46 | {check.name}
47 |
48 |
49 | {check.reasoning}
50 |
51 |
52 | 输入: {check.input}
53 |
54 |
55 |
56 |
57 | 检查时间: {check.timestamp.toLocaleTimeString()}
58 |
59 |
60 | ))}
61 |
62 | {guardrails.length > activeGuardrails.length && (
63 |
64 |
65 | 所有护栏检查历史:
66 |
67 |
68 | {guardrails.map((check) => (
69 |
73 |
74 | {check.passed ? (
75 |
76 | ) : (
77 |
78 | )}
79 | {check.name}
80 |
81 | {check.timestamp.toLocaleTimeString()}
82 |
83 |
84 |
85 | ))}
86 |
87 |
88 | )}
89 |
90 | );
91 | }
--------------------------------------------------------------------------------
/nginx.conf:
--------------------------------------------------------------------------------
1 | events {
2 | worker_connections 1024;
3 | }
4 |
5 | http {
6 | include /etc/nginx/mime.types;
7 | default_type application/octet-stream;
8 |
9 | # 日志格式
10 | log_format main '$remote_addr - $remote_user [$time_local] "$request" '
11 | '$status $body_bytes_sent "$http_referer" '
12 | '"$http_user_agent" "$http_x_forwarded_for"';
13 |
14 | access_log /var/log/nginx/access.log main;
15 | error_log /var/log/nginx/error.log;
16 |
17 | # 基本设置
18 | sendfile on;
19 | tcp_nopush on;
20 | tcp_nodelay on;
21 | keepalive_timeout 65;
22 | types_hash_max_size 2048;
23 |
24 | # 压缩设置
25 | gzip on;
26 | gzip_vary on;
27 | gzip_min_length 10240;
28 | gzip_proxied any;
29 | gzip_comp_level 6;
30 | gzip_types
31 | text/plain
32 | text/css
33 | text/xml
34 | text/javascript
35 | application/json
36 | application/javascript
37 | application/xml+rss
38 | application/atom+xml
39 | image/svg+xml;
40 |
41 | # WebSocket 升级设置
42 | map $http_upgrade $connection_upgrade {
43 | default upgrade;
44 | '' close;
45 | }
46 |
47 | # 上游服务器
48 | upstream app_backend {
49 | server app:8000;
50 | }
51 |
52 | server {
53 | listen 80;
54 | server_name _;
55 |
56 | # 设置最大文件上传大小
57 | client_max_body_size 50M;
58 |
59 | # 根路径处理
60 | location / {
61 | proxy_pass http://app_backend;
62 | proxy_set_header Host $host;
63 | proxy_set_header X-Real-IP $remote_addr;
64 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
65 | proxy_set_header X-Forwarded-Proto $scheme;
66 |
67 | # 超时设置
68 | proxy_connect_timeout 60s;
69 | proxy_send_timeout 60s;
70 | proxy_read_timeout 60s;
71 | }
72 |
73 | # API 路由
74 | location /api/ {
75 | proxy_pass http://app_backend;
76 | proxy_set_header Host $host;
77 | proxy_set_header X-Real-IP $remote_addr;
78 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
79 | proxy_set_header X-Forwarded-Proto $scheme;
80 | }
81 |
82 | # WebSocket 路由
83 | location /ws {
84 | proxy_pass http://app_backend;
85 | proxy_http_version 1.1;
86 | proxy_set_header Upgrade $http_upgrade;
87 | proxy_set_header Connection $connection_upgrade;
88 | proxy_set_header Host $host;
89 | proxy_set_header X-Real-IP $remote_addr;
90 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
91 | proxy_set_header X-Forwarded-Proto $scheme;
92 |
93 | # WebSocket 特殊设置
94 | proxy_cache_bypass $http_upgrade;
95 | proxy_read_timeout 86400;
96 | }
97 |
98 | # 静态文件缓存
99 | location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
100 | proxy_pass http://app_backend;
101 | proxy_set_header Host $host;
102 | expires 1y;
103 | add_header Cache-Control "public, immutable";
104 | }
105 |
106 | # 健康检查
107 | location /health {
108 | proxy_pass http://app_backend/api/health;
109 | access_log off;
110 | }
111 | }
112 | }
--------------------------------------------------------------------------------
/backend/service/models/note.py:
--------------------------------------------------------------------------------
1 | """
2 | 笔记数据模型
3 | """
4 |
5 | from sqlalchemy import Column, Integer, String, Text, DateTime, Index
6 | from sqlalchemy.sql import func
7 | from core.database_core import BaseModel
8 |
9 |
10 | class InvalidTagError(Exception):
11 | """标签验证异常"""
12 | pass
13 |
14 |
15 | class Note(BaseModel):
16 | """
17 | 笔记模型
18 |
19 | 存储用户的笔记内容,用户信息来自JSONPlaceholder API
20 | """
21 | __tablename__ = 'notes'
22 |
23 | # 允许的标签选项
24 | ALLOWED_TAGS = [
25 | 'lifestyle tips',
26 | 'cooking advice',
27 | 'weather interpretation',
28 | 'news context'
29 | ]
30 |
31 | # 用户ID(来自JSONPlaceholder API)
32 | user_id = Column(Integer, nullable=False, comment='用户ID(来自JSONPlaceholder)')
33 |
34 | # 笔记标题
35 | title = Column(String(200), nullable=False, comment='笔记标题')
36 |
37 | # 笔记内容
38 | content = Column(Text, comment='笔记内容')
39 |
40 | # 笔记标签(单个标签,只允许指定选项)
41 | tag = Column(String(50), comment='笔记标签')
42 |
43 | # 笔记状态(草稿、已发布、已归档等)
44 | status = Column(String(20), default='draft', comment='笔记状态')
45 |
46 | # 最后更新时间
47 | last_updated = Column(DateTime, default=func.now(), onupdate=func.now(), comment='最后更新时间')
48 |
49 | # 创建索引优化查询
50 | __table_args__ = (
51 | Index('idx_notes_user_id', 'user_id'),
52 | Index('idx_notes_title', 'title'),
53 | Index('idx_notes_status', 'status'),
54 | Index('idx_notes_tag', 'tag'),
55 | Index('idx_notes_last_updated', 'last_updated'),
56 | Index('idx_notes_user_status', 'user_id', 'status'),
57 | )
58 |
59 | def __repr__(self):
60 | return f"