import gradio as gr
from evaluate import eval, install
from datetime import datetime
import os, shutil, spaces
import warnings, tempfile
from audio import gen_audio
warnings.filterwarnings("ignore")
warnings.simplefilter("ignore")
videos = {
"教學視頻1": "teach/00.mp4",
"教學視頻2": "teach/01.mp4",
"教學視頻3": "teach/02.mp4",
"教學視頻4": "teach/03.mp4",
"(病症)高峰期": "teach/(病症)高峰期.mp4",
"公園": "teach/公園.mp4",
"健康": "teach/健康.mp4",
"刷牙": "teach/刷牙.mp4",
"圖書館": "teach/圖書館.mp4",
"下午": "teach/下午.mp4",
"中風": "teach/中風.mp4",
"中暑": "teach/中暑.mp4",
"主題": "teach/主題.mp4",
"住院證明": "teach/住院證明.mp4"
}
jsons = {
"教學視頻1": "teach/00.json",
"教學視頻2": "teach/01.json",
"教學視頻3": "teach/02.json",
"教學視頻4": "teach/03.json",
"(病症)高峰期": "teach/(病症)高峰期.json",
"公園": "teach/公園.json",
"健康": "teach/健康.json",
"刷牙": "teach/刷牙.json",
"圖書館": "teach/圖書館.json",
"下午": "teach/下午.json",
"中風": "teach/中風.json",
"中暑": "teach/中暑.json",
"主題": "teach/主題.json",
"住院證明": "teach/住院證明.json"
}
def get_video_url(option):
return videos[option]
@spaces.GPU()
def evaluate_sign_language(user_video, standard_video_option):
tmp = tempfile.TemporaryDirectory()
tmpdir = tmp.name
new_path = tmpdir + "/user.mp4"
shutil.copy(user_video, new_path)
shutil.copy(videos[standard_video_option], tmpdir + "/standard.mp4")
test, standard = user_video, videos[standard_video_option]
score, final_merged_intervals, comments = eval(test, standard, tmpdir)
if score < 95:
score = 0
elif score < 98:
score = 50 * (score - 95) / 3
elif 98 <= score <= 100:
score = 50 * (score - 98) / 2 + 50
current_date = datetime.now().strftime("%Y年%m月%d日")
# 初始化反馈报告
qualification = "不合格" if score < 60 else "合格"
advice = f"""
\n手語表現反饋報告
日期: {current_date}
整體評估: {qualification}。在您的手語練習中,我們註意到一些動作可以改進以提升流暢性,感謝您的努力,繼續加油。
改進建議(供參考):
"""
part_translation = {
'Right Hand': '右手細節、',
'Left Hand': '左手細節、',
'Right Arm': '右臂、',
'Left Arm': '左臂、'
}
# 为每个问题区间生成具体观察结果
f = 0
subtitles = []
for interval, errors in final_merged_intervals:
advice += f" - 時間區間:{interval[0]}-{interval[1]}秒
"
parts = ""
for error in errors:
part = part_translation[error]
parts += part
advice += f" 觀察結果:您的{parts[:-1]}動作與標準手語手勢不太一致。
"
f = 1
subtitles.append([[interval[0], interval[1]], parts[:-1]])
if not f:
advice = advice[:-4]
advice += "無"
advice += "
建議:請參考標準視頻,模仿正確的動作,保持速度一致。
"
advice += f"綜合評分: 您本次的總評分為 {score:.2f}/100分。
"
ret_video = gen_audio(subtitles, tmpdir)
return advice, ret_video, tmp
def cleanup_temp_dir(tmp_dir):
if tmp_dir:
time.sleep(0.5)
print(f"Cleaning up temporary directory: {tmp_dir.name}")
tmp_dir.cleanup()
return "临时目录已清理"
return "没有临时目录需要清理"
install()
font = ["Heiti SC", "FangSong"]
title = """
手語教學與評估系統
"""
with gr.Blocks(
css="""
.contain { display: flex; flex-direction: column; }
.gradio-container { height: 200vh !important;
overflow-y: auto; /* 添加垂直滚动条 */
}
#col_container { height: 100%; }
pre {
white-space: pre-wrap; /* Since CSS 2.1 */
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
}""",
js="""
function refresh() {
const url = new URL(window.location);
if (url.searchParams.get('__theme') !== 'light') {
url.searchParams.set('__theme', 'light');
window.location.href = url.href;
}
}""",
title="手語教學與評估系統",
theme=gr.themes.Soft(),
) as app:
gr.HTML(title)
with gr.Row():
with gr.Column():
video_selector = gr.Dropdown(list(videos.keys()), label="請選擇教學視頻")
video_player = gr.Video(label="請觀看教學視頻演示")
video_selector.change(get_video_url, inputs=video_selector, outputs=video_player)
with gr.Column():
upload_video = gr.Video(label="請錄製/上傳您的視頻,點擊\'開始評估\'")
evaluate_button = gr.Button("開始評估")
with gr.Row():
with gr.Column():
advice_output = gr.HTML(label="反饋報告")
with gr.Column():
compare_video_player = gr.Video(label="評估結果")
tmp_dir_state = gr.State()
evaluate_button.click(
evaluate_sign_language,
inputs=[upload_video, video_selector],
outputs=[advice_output, compare_video_player, tmp_dir_state],
)
compare_video_player.change(
fn=cleanup_temp_dir,
inputs=tmp_dir_state,
outputs=None
)
app.launch(share=True)