|
import gradio as gr
|
|
import random
|
|
import time
|
|
|
|
css = '''
|
|
.show img {height: 320px}
|
|
.result img {height: 320px}
|
|
.qrcode img {height: 225px}
|
|
.btn {
|
|
justify-content: normal
|
|
}
|
|
'''
|
|
|
|
def get_new_question_and_options():
|
|
time.sleep(1.5)
|
|
number = random.randint(1,65536)
|
|
return {
|
|
"question_text": f"问题{number}是这样的。",
|
|
"option_A": f"问题{number}给出的选项A,吃饭",
|
|
"option_B": f"问题{number}给出的选项B,睡觉",
|
|
"option_C": f"问题{number}给出的选项C,打豆豆",
|
|
}
|
|
|
|
def get_option_result(question_text, option_text):
|
|
time.sleep(1.5)
|
|
numbers = [
|
|
random.randint(-10,10),
|
|
random.randint(-10,10),
|
|
random.randint(-10,10),
|
|
random.randint(-10,10)
|
|
]
|
|
|
|
return {
|
|
"result_text": f"问题“{question_text}”执行“{option_text}”选项,结果完成了",
|
|
"score_text": f"导致四个维度增减情况为 {numbers[0]} {numbers[1]} {numbers[2]} {numbers[3]}",
|
|
"deltas": numbers
|
|
}
|
|
|
|
def typePUA(a):
|
|
|
|
x = '0' if a[0] <= 50 else '1'
|
|
y = '0' if a[1] <= 50 else '1'
|
|
z = '0' if a[2] <= 50 else '1'
|
|
w = '0' if a[3] <= 50 else '1'
|
|
|
|
puatype = ''.join([x,y,z,w])
|
|
|
|
pua = {
|
|
"0000": "1 反PUA斗士",
|
|
"0001": "2",
|
|
"0010": "3",
|
|
"0011": "4",
|
|
"0100": "5",
|
|
"0101": "6",
|
|
"0110": "7",
|
|
"0111": "8",
|
|
"1000": "9",
|
|
"1001": "10",
|
|
"1010": "11",
|
|
"1011": "12",
|
|
"1100": "13",
|
|
"1101": "14",
|
|
"1110": "15",
|
|
"1111": "16 天生牛马打工人",
|
|
}
|
|
|
|
return pua[puatype]
|
|
|
|
with gr.Blocks(css=css).queue() as demo:
|
|
|
|
|
|
|
|
|
|
page_index = gr.State(0)
|
|
|
|
|
|
user_info = gr.State({
|
|
"user_name": ""
|
|
})
|
|
|
|
|
|
qa_data = gr.State({
|
|
"total": 3,
|
|
"progress": 1,
|
|
"question_text": "",
|
|
"result_text": "",
|
|
"score_text": "",
|
|
"options": [
|
|
"",
|
|
"",
|
|
"",
|
|
""
|
|
],
|
|
"deltas": [0,0,0,0],
|
|
"canOptionA": True,
|
|
"canOptionB": True,
|
|
"canOptionC": True,
|
|
"canOptionD": False,
|
|
"canFillD": True,
|
|
"canRestart": True,
|
|
"canRefresh": True,
|
|
"canNext": False,
|
|
"nextName": "➡️ 下一题",
|
|
})
|
|
|
|
|
|
result_data = gr.State({
|
|
"avdice_text": "",
|
|
"score_text": "",
|
|
"score": [50,50,50,50]
|
|
})
|
|
|
|
gr.Markdown("# 😅别再PUA啦:基于多智能体的被PUA指数心理测评游戏")
|
|
gr.Markdown("### 😋机智选择,远离PUA😈")
|
|
|
|
with gr.Tab("测评"):
|
|
|
|
|
|
@gr.render(inputs=[page_index, user_info, qa_data, result_data])
|
|
def show_page_by_index(index, user, qa, result):
|
|
|
|
|
|
if index == 0:
|
|
gr.Image(elem_classes="show", value="./src/home.png", label="首页图", height=400, interactive=False)
|
|
with gr.Group():
|
|
with gr.Row():
|
|
user_name = gr.Textbox(placeholder="输入您的昵称", value=user["user_name"], container=False)
|
|
start = gr.Button(value="▶️ 开始测评", variant="primary")
|
|
|
|
def onStart(user_name, user=user, index=index, qa=qa, result=result):
|
|
if not user_name.strip():
|
|
raise gr.Error("输入您的昵称后才能进行测评!", duration=3)
|
|
|
|
user["user_name"] = user_name
|
|
index = 1
|
|
qa["progress"] = 1
|
|
|
|
res = get_new_question_and_options()
|
|
qa["question_text"] = res["question_text"]
|
|
qa["options"][0] = res["option_A"]
|
|
qa["options"][1] = res["option_B"]
|
|
qa["options"][2] = res["option_C"]
|
|
|
|
qa["canOptionA"] = True
|
|
qa["canOptionB"] = True
|
|
qa["canOptionC"] = True
|
|
qa["canOptionD"] = False
|
|
qa["canFillD"] = True
|
|
qa["canRestart"] = True
|
|
qa["canRefresh"] = True
|
|
qa["canNext"] = False
|
|
|
|
result["score"] = [50,50,50,50]
|
|
|
|
print(qa, result)
|
|
return index, user, qa, result
|
|
|
|
start.click(onStart, [user_name], [page_index, user_info, qa_data, result_data])
|
|
|
|
|
|
elif index == 1:
|
|
gr.Markdown(f"您好,{user['user_name']}。请根据如下提示完成测评流程!小心不要被 PUA 到啦 ~")
|
|
with gr.Row():
|
|
with gr.Column():
|
|
gr.Image(elem_classes="show", value=f"./src/question_{qa['progress']}.jpg", label="事件图示", height=400, interactive=False)
|
|
gr.Slider(label=f"测评进度(共{qa['total']}题)", value=qa['progress'], minimum=0, maximum=qa["total"], step=1, interactive=False)
|
|
gr.Markdown("当前分数")
|
|
with gr.Group():
|
|
gr.Slider(label="维度1", value=result["score"][0], minimum=0, maximum=100, step=1, interactive=False)
|
|
gr.Slider(label="维度2", value=result["score"][1], minimum=0, maximum=100, step=1, interactive=False)
|
|
gr.Slider(label="维度3", value=result["score"][2], minimum=0, maximum=100, step=1, interactive=False)
|
|
gr.Slider(label="维度4", value=result["score"][3], minimum=0, maximum=100, step=1, interactive=False)
|
|
with gr.Column():
|
|
question_text = gr.TextArea(label="事件背景", value=qa["question_text"], placeholder="请等待生成", interactive=False, lines=4)
|
|
result_text = gr.TextArea(label="事件结果", value=qa["result_text"], placeholder="请根据事件背景,结合个人实际情况做出选择。注意,选择之间并无对错之分。", interactive=False, lines=4)
|
|
score_text = gr.TextArea(label="分数变更", value=qa["score_text"], placeholder="请根据事件背景,结合个人实际情况做出选择。注意,选择之间并无对错之分。", interactive=False, lines=4)
|
|
option_A_button = gr.Button(value=f"A: {qa['options'][0]}", interactive=qa["canOptionA"], elem_classes="btn")
|
|
option_B_button = gr.Button(value=f"B: {qa['options'][1]}", interactive=qa["canOptionB"], elem_classes="btn")
|
|
option_C_button = gr.Button(value=f"C: {qa['options'][2]}", interactive=qa["canOptionC"], elem_classes="btn")
|
|
with gr.Group():
|
|
option_D_button = gr.Button(value="D: 我选这个", interactive=qa["canOptionD"], elem_classes="btn")
|
|
option_D_text = gr.Textbox(show_label=False, value=qa['options'][3], placeholder="我有独特的主见", interactive=qa["canFillD"], container=False)
|
|
|
|
def onClickABC(question_text, btn, qa=qa, result=result):
|
|
option_text = btn[2:]
|
|
res = get_option_result(question_text, option_text)
|
|
|
|
qa["result_text"] = res["result_text"]
|
|
qa["score_text"] = res["score_text"]
|
|
qa["deltas"] = res["deltas"]
|
|
qa["canOptionA"] = False
|
|
qa["canOptionB"] = False
|
|
qa["canOptionC"] = False
|
|
qa["canOptionD"] = False
|
|
qa["canFillD"] = False
|
|
qa["canRefresh"] = False
|
|
qa["canNext"] = True
|
|
|
|
for i in range(len(result["score"])):
|
|
result["score"][i] = max(min(result["score"][i] + res["deltas"][i], 100), -100)
|
|
if qa["progress"] == qa["total"]:
|
|
qa["nextName"] = "✨查看结果"
|
|
|
|
print(qa["progress"],qa["total"])
|
|
return qa["result_text"], qa["score_text"], qa, result
|
|
|
|
def onClickD(question_text, option_D_text, qa=qa, result=result):
|
|
res = get_option_result(question_text, option_D_text)
|
|
|
|
qa["result_text"] = res["result_text"]
|
|
qa["score_text"] = res["score_text"]
|
|
qa["deltas"] = res["deltas"]
|
|
qa["canOptionA"] = False
|
|
qa["canOptionB"] = False
|
|
qa["canOptionC"] = False
|
|
qa["canOptionD"] = False
|
|
qa["canFillD"] = False
|
|
qa["canRefresh"] = False
|
|
qa["canNext"] = True
|
|
|
|
for i in range(len(result["score"])):
|
|
result["score"][i] = max(min(result["score"][i] + res["deltas"][i], 100), -100)
|
|
|
|
if qa["progress"] == qa["total"]:
|
|
qa["nextName"] = "✨查看结果"
|
|
|
|
print(qa, result)
|
|
return qa["result_text"], qa["score_text"], qa, result
|
|
|
|
def onChangeD(option_D_text, qa=qa):
|
|
qa["options"][3] = option_D_text
|
|
if option_D_text.strip():
|
|
qa["canOptionD"] = True
|
|
else:
|
|
qa["canOptionD"] = False
|
|
|
|
print(qa, result)
|
|
return qa
|
|
|
|
option_A_button.click(onClickABC, [question_text, option_A_button], [result_text, score_text, qa_data, result_data])
|
|
option_B_button.click(onClickABC, [question_text, option_B_button], [result_text, score_text, qa_data, result_data])
|
|
option_C_button.click(onClickABC, [question_text, option_C_button], [result_text, score_text, qa_data, result_data])
|
|
option_D_button.click(onClickD, [question_text, option_D_text], [result_text, score_text, qa_data, result_data])
|
|
option_D_text.blur(onChangeD, option_D_text, qa_data)
|
|
|
|
with gr.Row():
|
|
restart = gr.Button(value="↩️ 重新开始", interactive=qa["canRestart"])
|
|
refresh = gr.Button(value="🔄️ 刷新", interactive=qa["canRefresh"])
|
|
next = gr.Button(value=qa["nextName"], interactive=qa["canNext"])
|
|
|
|
def onRestart(index=index):
|
|
index = 0
|
|
return index
|
|
|
|
def onRefresh(qa=qa, result=result):
|
|
res = get_new_question_and_options()
|
|
qa["question_text"] = res["question_text"]
|
|
qa["result_text"] = ""
|
|
qa["score_text"] = ""
|
|
qa["options"][0] = res["option_A"]
|
|
qa["options"][1] = res["option_B"]
|
|
qa["options"][2] = res["option_C"]
|
|
qa["options"][3] = ""
|
|
qa["canOptionA"] = True
|
|
qa["canOptionB"] = True
|
|
qa["canOptionC"] = True
|
|
qa["canOptionD"] = False
|
|
qa["canFillD"] = True
|
|
qa["canRestart"] = True
|
|
qa["canRefresh"] = True
|
|
qa["canNext"] = False
|
|
|
|
print(qa, result)
|
|
return qa["question_text"] , qa["result_text"], qa["score_text"], qa["options"][3], qa, result
|
|
|
|
def onNext(index=index, qa=qa, result=result):
|
|
if qa["nextName"] == "➡️ 下一题":
|
|
qa["progress"] += 1
|
|
|
|
res = get_new_question_and_options()
|
|
qa["question_text"] = res["question_text"]
|
|
qa["result_text"] = ""
|
|
qa["score_text"] = ""
|
|
qa["options"][0] = res["option_A"]
|
|
qa["options"][1] = res["option_B"]
|
|
qa["options"][2] = res["option_C"]
|
|
qa["options"][3] = ""
|
|
qa["canOptionA"] = True
|
|
qa["canOptionB"] = True
|
|
qa["canOptionC"] = True
|
|
qa["canOptionD"] = False
|
|
qa["canFillD"] = True
|
|
qa["canRestart"] = True
|
|
qa["canRefresh"] = True
|
|
qa["canNext"] = False
|
|
|
|
print(qa, result)
|
|
return qa["question_text"] , qa["result_text"], qa["score_text"], qa["options"][3], index, qa, result
|
|
else:
|
|
qa["question_text"] = ""
|
|
qa["result_text"] = ""
|
|
qa["score_text"] = ""
|
|
qa["options"][0] = ""
|
|
qa["options"][1] = ""
|
|
qa["options"][2] = ""
|
|
qa["options"][3] = ""
|
|
qa["canOptionA"] = True
|
|
qa["canOptionB"] = True
|
|
qa["canOptionC"] = True
|
|
qa["canOptionD"] = False
|
|
qa["canFillD"] = True
|
|
qa["canRestart"] = True
|
|
qa["canRefresh"] = True
|
|
qa["canNext"] = False
|
|
index = 2
|
|
return "", "", "", "", index, qa, result
|
|
|
|
restart.click(onRestart, None, page_index)
|
|
refresh.click(onRefresh, None, [question_text, result_text, score_text, option_D_text, qa_data, result_data])
|
|
next.click(onNext, None, [question_text, result_text, score_text, option_D_text, page_index, qa_data, result_data])
|
|
|
|
|
|
else:
|
|
gr.Markdown("### 测评结果")
|
|
with gr.Row():
|
|
with gr.Column():
|
|
gr.Image(elem_classes="result", value="./src/home.png", label="测评结果图示", height=400, interactive=False)
|
|
gr.Markdown("最终分数")
|
|
with gr.Group():
|
|
gr.Slider(label="维度1", value=result["score"][0], minimum=0, maximum=100, step=1, interactive=False)
|
|
gr.Slider(label="维度2", value=result["score"][1], minimum=0, maximum=100, step=1, interactive=False)
|
|
gr.Slider(label="维度3", value=result["score"][2], minimum=0, maximum=100, step=1, interactive=False)
|
|
gr.Slider(label="维度4", value=result["score"][3], minimum=0, maximum=100, step=1, interactive=False)
|
|
with gr.Column():
|
|
with gr.Row():
|
|
gr.Number(label="您的被PUA指数", value=sum(result["score"])/4, interactive=False)
|
|
gr.Textbox(label="您的被PUA类型", value=typePUA(result["score"]), interactive=False, placeholder="测评结束后生成")
|
|
gr.TextArea(label="您的测评结果解释", placeholder="测评结束后生成", interactive=False, lines=6)
|
|
gr.TextArea(label="可能的解决方案", placeholder="测评结束后生成", interactive=False, lines=14)
|
|
restart = gr.Button(value="↩️ 重新开始", interactive=qa["canRestart"])
|
|
|
|
def onRestart(index=index):
|
|
index = 0
|
|
return index
|
|
|
|
restart.click(onRestart, None, page_index)
|
|
|
|
gr.Button(value="如果对您有用,欢迎分享网站与测评结果 🥰", variant="primary")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with gr.Tab("关于"):
|
|
gr.Markdown("")
|
|
gr.Markdown("**Datawhale AI夏令营(第四期)x 浪潮信息 “源”大模型应用开发活动**")
|
|
gr.Markdown("---")
|
|
gr.Markdown("**项目名称**:别再PUA啦:基于多智能体的被PUA指数心理测评游戏")
|
|
gr.Markdown("**项目Slogan**:机智选择,远离PUA")
|
|
gr.Markdown("**项目简介**:“别再PUA啦”是一款创新的心理测评游戏,它基于多智能体技术,旨在通过互动游戏的形式,测量个体对PUA策略的抵抗力和识别能力,从而帮助用户提高自我保护意识和社交技巧。")
|
|
gr.Markdown("**项目技术栈**:Yuan 2.0,RAG,Langchain,Muiti-Agent, Gradio")
|
|
gr.Markdown("**项目演示视频**:【TODO】")
|
|
gr.Markdown("**项目构建分析与复盘博客**:【TODO】")
|
|
gr.Markdown("---")
|
|
gr.Markdown("**作者**:胡钧耀(南开大学计算机视觉在读一年级直博生,个人研究兴趣方向为视觉AIGC)")
|
|
gr.Markdown("**联系方式**:微信(LittleDream_hjy),[Bilibili](https://space.bilibili.com/2042113),[GitHub](https://github.com/JunyaoHu),[个人主页](https://junyaohu.github.io)")
|
|
with gr.Row():
|
|
gr.Image(elem_classes="qrcode", value="./src/weixin.png", label="微信", height=250)
|
|
gr.Image(elem_classes="qrcode", value="./src/zanshang.png", label="感谢支持", height=250)
|
|
|
|
if __name__ == "__main__":
|
|
|
|
demo.launch(share=True) |