SBTI打不开?手把手教你部署自己的人格测试(附源码链接)
网站打不开?部署自己的SBTI人格测试(附源码链接)
最近在B站刷到了一个很火的SBTI人格测试,觉得挺有意思的。作为一名开发者,我决定自己动手实现一个可以本地部署的版本。本文将带你从零开始,用Flask框架搭建一个完整的人格测试网站。
技术栈: Flask + 原生HTML/CSS/JavaScript
项目地址: 部署自己的SBTI
一、SBTI测试原理解析
1.1 什么是SBTI?
SBTI人格测试采用"量表打分 + 向量匹配"的混合机制,通过30道常规题目从5个模型的15个维度分析用户的人格特征。
1.2 五大模型与15个维度
| 模型 | 维度 | 说明 |
|---|---|---|
| 自我模型(S) | S1-自尊自信 S2-自我清晰度 S3-核心价值 |
评估自我认知和价值观 |
| 情感模型(E) | E1-依恋安全感 E2-情感投入度 E3-边界与依赖 |
评估情感模式和亲密关系 |
| 态度模型(A) | A1-世界观倾向 A2-规则与灵活度 A3-人生意义感 |
评估对世界的态度 |
| 行动驱力(Ac) | Ac1-动机导向 Ac2-决策风格 Ac3-执行模式 |
评估行动力和决策方式 |
| 社交模型(So) | So1-社交主动性 So2-人际边界感 So3-表达与真实度 |
评估社交风格 |
1.3 赋分机制
选项分值:
- A选项 = 1分(低分)
- B选项 = 2分(中分)
- C选项 = 3分(高分)
维度等级转换:
每个维度由2道题组成,总分转换为等级:
- 2-3分 → L(低)
- 4分 → M(中)
- 5-6分 → H(高)
人格匹配:
将用户的15维度等级向量与25种预定义人格模式进行匹配,选出最接近的类型。
二、项目架构设计
2.1 项目结构
sbti/
├── app.py # Flask后端主文件
├── templates/
│ └── index.html # 前端页面
├── requirements.txt # Python依赖
└── README.md # 项目文档
2.2 技术选型
- 后端框架: Flask 3.0.0(轻量、简单、易上手)
- 前端技术: 原生HTML/CSS/JavaScript(无需打包,开箱即用)
- 数据存储: 内存存储(无需数据库,适合小型项目)
三、后端实现详解
3.1 Flask应用初始化
from flask import Flask, render_template, request, jsonify
import random
app = Flask(__name__)
3.2 数据结构设计
人格类型定义
PERSONALITIES = {
"HHHH": {"name": "HHHH", "emoji": "🌟", "desc": "全维度高分,罕见的全能型人格"},
"SEALH": {"name": "SEALH", "emoji": "🦭", "desc": "自信稳定,情感投入,乐观行动派"},
"SEAHH": {"name": "SEAHH", "emoji": "🌊", "desc": "自信独立,情感充沛,高执行力"},
"DRUNK": {"name": "DRUNK", "emoji": "🍺", "desc": "保温杯里泡枸杞的养生朋克"},
# ... 共25种人格类型
}
题目数据结构
QUESTIONS = [
{
"id": 1,
"dim": "S1", # 对应维度
"text": "别人夸你的时候,你的第一反应是?",
"options": [
"A. 先怀疑是不是在讽刺",
"B. 表面谦虚,心里还挺受用",
"C. 坦然接受,觉得理所当然"
]
},
# ... 共30道题
]
特殊题(彩蛋)
SPECIAL_QUESTIONS = [
{
"id": 31,
"type": "drunk",
"text": "保温杯里泡枸杞,你觉得?",
"options": ["A. 养生达人", "B. 朋克养生", "C. 保温杯里泡白酒"],
"trigger": "C" # 触发条件
}
]
3.3 核心API实现
API 1:获取题目列表
@app.route('/api/questions', methods=['GET'])
def get_questions():
"""获取随机打乱的题目"""
questions = QUESTIONS.copy()
random.shuffle(questions) # 随机打乱顺序
# 随机插入1道特殊题
special_q = random.choice(SPECIAL_QUESTIONS)
insert_pos = random.randint(10, 25)
questions.insert(insert_pos, special_q)
return jsonify(questions)
API 2:计算测试结果
@app.route('/api/calculate', methods=['POST'])
def calculate_result():
"""计算测试结果"""
data = request.json
answers = data.get('answers', {})
# 1. 检查是否触发DRUNK彩蛋
for qid, answer in answers.items():
q = next((q for q in SPECIAL_QUESTIONS if str(q['id']) == qid), None)
if q and q.get('type') == 'drunk' and answer == q.get('trigger'):
return jsonify({
'personality': 'DRUNK',
'emoji': '🍺',
'name': 'DRUNK',
'desc': '保温杯里泡枸杞的养生朋克',
'match_rate': 100
})
# 2. 计算15个维度的分数
dim_scores = {}
for q in QUESTIONS:
qid = str(q['id'])
if qid in answers:
answer = answers[qid]
# 计算分数(A=1, B=2, C=3)
if answer == 'A':
score = 3 if q.get('reverse') else 1
elif answer == 'B':
score = 2
else: # C
score = 1 if q.get('reverse') else 3
dim = q['dim']
if dim not in dim_scores:
dim_scores[dim] = []
dim_scores[dim].append(score)
# 3. 转换为L/M/H等级
dim_levels = {}
for dim, scores in dim_scores.items():
total = sum(scores)
if total <= 3:
level = 'L'
elif total == 4:
level = 'M'
else:
level = 'H'
dim_levels[dim] = level
# 4. 匹配最佳人格类型
best_match = find_best_personality(dim_levels)
personality_info = PERSONALITIES.get(best_match)
return jsonify({
'personality': best_match,
'emoji': personality_info['emoji'],
'name': personality_info['name'],
'desc': personality_info['desc'],
'match_rate': 85,
'dimensions': dim_levels
})
人格匹配算法
def find_best_personality(dim_levels):
"""根据维度等级匹配最佳人格"""
# 计算各模型的平均等级
s_avg = get_avg_level([dim_levels.get('S1'), dim_levels.get('S2'), dim_levels.get('S3')])
e_avg = get_avg_level([dim_levels.get('E1'), dim_levels.get('E2'), dim_levels.get('E3')])
a_avg = get_avg_level([dim_levels.get('A1'), dim_levels.get('A2'), dim_levels.get('A3')])
ac_avg = get_avg_level([dim_levels.get('Ac1'), dim_levels.get('Ac2'), dim_levels.get('Ac3')])
# 组合成人格模式
pattern = s_avg + e_avg + a_avg + ac_avg
if pattern in PERSONALITIES:
return pattern
return 'HHHH' # 默认返回
def get_avg_level(levels):
"""计算平均等级"""
level_map = {'L': 1, 'M': 2, 'H': 3}
scores = [level_map.get(l, 2) for l in levels if l]
if not scores:
return 'M'
avg = sum(scores) / len(scores)
if avg <= 1.5:
return 'L'
elif avg <= 2.5:
return 'M'
else:
return 'H'
四、前端实现详解
4.1 UI设计思路
参考原版网站,采用清新的绿色主题:
:root {
--bg: #f6faf6; /* 背景色 */
--panel: #ffffff; /* 卡片背景 */
--text: #1e2a22; /* 文字颜色 */
--accent: #6c8d71; /* 主题色 */
--accent-strong: #4d6a53; /* 深色主题 */
--shadow: 0 16px 40px rgba(47, 73, 55, 0.08); /* 阴影 */
--radius: 22px; /* 圆角 */
}
4.2 页面结构
采用三屏切换设计:
<!-- 首页 -->
<div id="home-screen" class="screen active">
<div class="card hero">
<h1>SBTI 人格测试</h1>
<button onclick="startTest()">开始测试</button>
</div>
</div>
<!-- 测试页面 -->
<div id="test-screen" class="screen">
<div class="progress">
<span id="progress-bar"></span>
</div>
<div id="question-container"></div>
<button onclick="nextQuestion()">下一题</button>
</div>
<!-- 结果页面 -->
<div id="result-screen" class="screen">
<div class="result-emoji">🦭</div>
<div class="result-name">SEALH</div>
<div class="result-desc">自信稳定,情感投入,乐观行动派</div>
</div>
4.3 核心JavaScript逻辑
开始测试
async function startTest() {
const response = await fetch('/api/questions');
questions = await response.json();
showScreen('test-screen');
renderQuestion();
}
渲染题目
function renderQuestion() {
const q = questions[currentIndex];
const container = document.getElementById('question-container');
container.innerHTML = `
<div class="question-card">
<div class="question-text">${currentIndex + 1}. ${q.text}</div>
<div class="options">
${q.options.map((opt, i) => `
<div class="option ${answers[q.id] === opt[0] ? 'selected' : ''}"
onclick="selectOption(${q.id}, '${opt[0]}')">
${opt}
</div>
`).join('')}
</div>
</div>
`;
updateProgress();
}
提交测试
async function submitTest() {
const response = await fetch('/api/calculate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ answers })
});
const result = await response.json();
showResult(result);
}
显示结果
function showResult(result) {
document.getElementById('result-emoji').textContent = result.emoji;
document.getElementById('result-name').textContent = result.name;
document.getElementById('result-desc').textContent = result.desc;
document.getElementById('result-match').textContent = `匹配度: ${result.match_rate}%`;
// 显示维度分析
const dimLabels = {
'S1': '自尊自信', 'S2': '自我清晰度', 'S3': '核心价值',
'E1': '依恋安全感', 'E2': '情感投入度', 'E3': '边界与依赖',
// ... 其他维度
};
// 渲染维度网格
// ...
showScreen('result-screen');
}
五、项目亮点与优化
5.1 题目随机化
每次测试时,题目顺序都会随机打乱,避免记忆答案:
questions = QUESTIONS.copy()
random.shuffle(questions)
5.2 隐藏彩蛋机制
在题目中随机插入特殊题,选择特定答案触发彩蛋:
# 检查是否触发DRUNK彩蛋
if answer == "C": # 选择"保温杯里泡白酒"
return DRUNK人格
5.3 反转题处理
部分题目(Q14、Q27)的选项分值顺序相反:
if answer == 'A':
score = 3 if q.get('reverse') else 1 # 反转题A=3分
5.4 响应式设计
使用CSS媒体查询适配移动端:
@media (max-width: 640px) {
.hero h1 { font-size: 32px; }
.result-emoji { font-size: 60px; }
}
5.5 进度条动画
实时显示测试进度,提升用户体验:
function updateProgress() {
const progress = ((currentIndex + 1) / questions.length) * 100;
document.getElementById('progress-bar').style.width = progress + '%';
}
六、部署与运行
6.1 本地运行
# 1. 克隆项目
git clone https://github.com/yourusername/sbti-test.git
cd sbti-test
# 2. 安装依赖
pip install Flask==3.0.0
# 3. 运行项目
python app.py
# 4. 访问网站
# 打开浏览器访问 http://localhost:5000
6.2 生产环境部署
使用Gunicorn部署:
pip install gunicorn
gunicorn -w 4 -b 0.0.0.0:5000 app:app
6.3 Docker部署
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "app.py"]
七、效果展示
首页

测试页面


结果页面

八、常见问题
Q1: 为什么选择Flask而不是Django?
A: Flask更轻量,适合小型项目。本项目只需要几个API接口,不需要Django的复杂功能。
Q2: 为什么不使用数据库?
A: 题目和人格类型数据是固定的,不需要动态修改,使用内存存储即可。如果需要保存用户测试记录,可以后续添加数据库。
Q3: 匹配算法准确吗?
A: 本项目采用简化的匹配算法,主要用于学习和娱乐。如需更精确的匹配,可以使用曼哈顿距离或欧氏距离计算相似度。
Q4: 可以商用吗?
A: 本项目仅供学习交流使用,原始测试设计版权归原作者所有。
九、总结
这是一个非常适合初学者的Flask实战项目,代码简洁易懂,功能完整。你可以在此基础上进行扩展,添加更多有趣的功能。
项目源码:
SBTI
如果觉得有帮助,欢迎Star⭐和Fork!
在这里插入图片描述
需要注意:
仅供娱乐:SBTI不是专业心理测评,结果不具备心理学依据
半随机性:多次测试可能得到不同结果,这很正常
勿当真:不要将测试结果用于诊断、面试、相亲等严肃场合
作者初衷:B站UP主@蛆肉儿串儿最初是为了劝朋友戒酒而设计
参考资料
- Flask官方文档:https://flask.palletsprojects.com/
- 原版SBTI测试:https://sbti.unun.dev/
💡 提示: 本文所有代码均已在GitHub开源,欢迎下载学习!如有问题,欢迎在评论区讨论。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)