feat: 增加公共文件访问功能并添加favicon和robots.txt

- 新增公共文件访问接口,允许从public目录获取文件
- 添加favicon.ico以改善网站标识
- 新增robots.txt以指导搜索引擎爬虫行为
This commit is contained in:
Miu Li 2025-06-16 03:50:28 +08:00
parent 73f419f1aa
commit 345c571dda
4 changed files with 121 additions and 108 deletions

224
app.py
View File

@ -1,109 +1,117 @@
from fastapi import FastAPI, Request, HTTPException from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import HTMLResponse from fastapi.responses import HTMLResponse, FileResponse
import markdown import markdown
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
import json, yaml import json, yaml
import os import os
import uvicorn import uvicorn
app = FastAPI() app = FastAPI()
templates = Jinja2Templates(directory="templates") templates = Jinja2Templates(directory="templates")
app.mount("/static", StaticFiles(directory="static"), name="static") app.mount("/static", StaticFiles(directory="static"), name="static")
# 加载所有问卷数据 # Mount all files from public directory to root
def load_all_scales(): @app.get("/{filename}")
scales = {} async def get_public_file(filename: str):
tags = [] public_path = os.path.join("public", filename)
for root, dirs, files in os.walk(os.path.realpath('scales')): if os.path.isfile(public_path):
for filename in files: return FileResponse(public_path)
if filename.endswith(('.yaml', '.yml')): raise HTTPException(status_code=404, detail="File not found")
try:
with open(os.path.join(root, filename), 'r', encoding='utf-8') as f: # 加载所有问卷数据
scale = yaml.safe_load(f) def load_all_scales():
scale['instructions']=markdown.markdown(scale['instructions'], extensions=['fenced_code','tables','mdx_math']) scales = {}
scale['descriptions']=markdown.markdown(scale['descriptions'], extensions=['fenced_code','tables','mdx_math']) tags = []
scale['abstract']=markdown.markdown(scale['abstract'], extensions=['fenced_code','tables','mdx_math']) for root, dirs, files in os.walk(os.path.realpath('scales')):
if 'tag' not in scale: for filename in files:
scale['tag']='其他' if filename.endswith(('.yaml', '.yml')):
if scale['tag'] not in tags: try:
tags.append(scale['tag']) with open(os.path.join(root, filename), 'r', encoding='utf-8') as f:
scale_id = os.path.splitext(filename)[0] # 使用文件名作为标识 scale = yaml.safe_load(f)
scales[scale_id] = scale scale['instructions']=markdown.markdown(scale['instructions'], extensions=['fenced_code','tables','mdx_math'])
except Exception as e: scale['descriptions']=markdown.markdown(scale['descriptions'], extensions=['fenced_code','tables','mdx_math'])
print(f"Error loading scale {filename}: {e}") scale['abstract']=markdown.markdown(scale['abstract'], extensions=['fenced_code','tables','mdx_math'])
return tags, scales if 'tag' not in scale:
scale['tag']='其他'
@app.get("/", response_class=HTMLResponse) if scale['tag'] not in tags:
async def index(request: Request): tags.append(scale['tag'])
tags, _ = load_all_scales() scale_id = os.path.splitext(filename)[0] # 使用文件名作为标识
# 新增读取README.md的逻辑 scales[scale_id] = scale
readme_content = "" except Exception as e:
try: print(f"Error loading scale {filename}: {e}")
with open("README.md", "r", encoding="utf-8") as f: return tags, scales
readme_content = markdown.markdown(f.read())
except FileNotFoundError: @app.get("/", response_class=HTMLResponse)
pass # 如果README不存在则静默失败 async def index(request: Request):
return templates.TemplateResponse("index.html", { tags, _ = load_all_scales()
"request": request, # 新增读取README.md的逻辑
"tags": tags, readme_content = ""
"readme_content": readme_content # 新增模板变量 try:
}) with open("README.md", "r", encoding="utf-8") as f:
readme_content = markdown.markdown(f.read())
@app.get("/tag/{tag}", response_class=HTMLResponse) except FileNotFoundError:
async def list(request: Request, tag: str): pass # 如果README不存在则静默失败
tags, scales = load_all_scales() return templates.TemplateResponse("index.html", {
return templates.TemplateResponse("list.html", { "request": request,
"request": request, "tags": tags,
"tags": tags, "readme_content": readme_content # 新增模板变量
"scales": scales, })
"tag": tag
}) @app.get("/tag/{tag}", response_class=HTMLResponse)
async def list(request: Request, tag: str):
@app.get("/scales/{scale_id}", response_class=HTMLResponse) tags, scales = load_all_scales()
async def scale(request: Request, scale_id: str): return templates.TemplateResponse("list.html", {
tags, scales = load_all_scales() "request": request,
scale = scales.get(scale_id) "tags": tags,
if scale: "scales": scales,
return templates.TemplateResponse("scale.html", { "tag": tag
"request": request, })
"scale_id": scale_id,
"scale": scale, @app.get("/scales/{scale_id}", response_class=HTMLResponse)
"tags":tags async def scale(request: Request, scale_id: str):
}) tags, scales = load_all_scales()
raise HTTPException(status_code=404, detail="问卷未找到") scale = scales.get(scale_id)
if scale:
@app.post("/scales/{scale_id}", response_class=HTMLResponse) return templates.TemplateResponse("scale.html", {
async def result(request: Request, scale_id: str): "request": request,
form_data = await request.form() "scale_id": scale_id,
tags, scales = load_all_scales() "scale": scale,
scale = scales.get(scale_id) "tags":tags
if scale: })
# 这里可以添加保存数据到数据库等逻辑 raise HTTPException(status_code=404, detail="问卷未找到")
responses = {}
average = {} @app.post("/scales/{scale_id}", response_class=HTMLResponse)
options = {} async def result(request: Request, scale_id: str):
for subscale, qids in scale['subscales'].items(): form_data = await request.form()
responses[subscale] = 0 tags, scales = load_all_scales()
min_val = min(scale['options'].keys()) scale = scales.get(scale_id)
max_val = max(scale['options'].keys()) if scale:
options[subscale] = [min_val*len(qids),max_val*len(qids)] # 这里可以添加保存数据到数据库等逻辑
for qid in qids: responses = {}
if qid<0: average = {}
responses[subscale] += min_val + max_val - int(form_data[str(-qid)]) options = {}
else: for subscale, qids in scale['subscales'].items():
responses[subscale] += int(form_data[str(qid)]) responses[subscale] = 0
average[subscale] = round(responses[subscale]/len(qids),2) min_val = min(scale['options'].keys())
return templates.TemplateResponse("result.html", { max_val = max(scale['options'].keys())
"request": request, options[subscale] = [min_val*len(qids),max_val*len(qids)]
"responses": responses, for qid in qids:
"average": average, if qid<0:
"options": options, responses[subscale] += min_val + max_val - int(form_data[str(-qid)])
"scale": scale, else:
"tags":tags responses[subscale] += int(form_data[str(qid)])
}) average[subscale] = round(responses[subscale]/len(qids),2)
raise HTTPException(status_code=404, detail="问卷未找到") return templates.TemplateResponse("result.html", {
"request": request,
"responses": responses,
if __name__ == '__main__': "average": average,
"options": options,
"scale": scale,
"tags":tags
})
raise HTTPException(status_code=404, detail="问卷未找到")
if __name__ == '__main__':
uvicorn.run(app,host='0.0.0.0',port=8000) uvicorn.run(app,host='0.0.0.0',port=8000)

4
public/robots.txt Normal file
View File

@ -0,0 +1,4 @@
User-agent: *
Allow: /
# Sitemap: /sitemap.xml

BIN
static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

View File

@ -8,6 +8,7 @@
<meta name="keywords" content="心尺, PsychoScales, 心理学量表,专业心理测评,抑郁症测试,焦虑症自评,在线心理测评系统,心理咨询师工具, 心理测验, 报告解读, 测试题"> <meta name="keywords" content="心尺, PsychoScales, 心理学量表,专业心理测评,抑郁症测试,焦虑症自评,在线心理测评系统,心理咨询师工具, 心理测验, 报告解读, 测试题">
<meta name="baidu-site-verification" content="codeva-mPOBUr0rLS" /> <meta name="baidu-site-verification" content="codeva-mPOBUr0rLS" />
<link rel="stylesheet" href="/static/styles.css"> <link rel="stylesheet" href="/static/styles.css">
<link rel="icon" type="image/x-icon" href="/static/favicon.ico">
{% block head_extra %}{% endblock %} {% block head_extra %}{% endblock %}
</head> </head>