model-optimizer / feedback_util.py
wangyiyi666's picture
feat: 添加用户反馈系统 + 模块化拆分(config/repo_util/feedback_util)
6de26b7 verified
Raw
History Blame Contribute Delete
3.9 kB
"""用户建议反馈 - HF 仓库读写"""
import json
import os
import tempfile
import uuid
from datetime import datetime
from config import FEEDBACK_REPO_PREFIX
from repo_util import download_repo_file, list_repo_files_safe, load_repo_json, upload_repo_file
def _parse_created(value):
if not value:
return datetime.min
try:
return datetime.fromisoformat(str(value).replace("Z", "+00:00"))
except ValueError:
try:
return datetime.strptime(str(value)[:19], "%Y-%m-%d %H:%M:%S")
except ValueError:
return datetime.min
def _normalize_feedback(meta):
meta = dict(meta or {})
meta.setdefault("feedback_id", "")
meta.setdefault("username", "匿名")
meta.setdefault("text", "")
meta.setdefault("is_public", False)
meta.setdefault("created", "")
meta.setdefault("images", [])
meta["image_count"] = len(meta.get("images") or [])
meta["public_label"] = "公开" if meta.get("is_public") else "仅管理员可见"
text = meta.get("text") or ""
meta["text_preview"] = text if len(text) <= 80 else text[:80] + "..."
return meta
def fetch_all_feedback():
"""获取全部用户反馈(本地管理端)"""
files = list_repo_files_safe()
prefix = FEEDBACK_REPO_PREFIX.rstrip("/") + "/"
json_files = [f for f in files if f.startswith(prefix) and f.endswith(".json")]
feedbacks = []
for json_path in json_files:
try:
meta = _normalize_feedback(load_repo_json(json_path))
feedbacks.append(meta)
except Exception:
continue
feedbacks.sort(key=lambda item: _parse_created(item.get("created")), reverse=True)
return feedbacks
def fetch_public_feedback():
"""获取允许公开展示的反馈(web 端)"""
return [item for item in fetch_all_feedback() if item.get("is_public")]
def submit_feedback(username, text, image_files=None, is_public=False):
"""提交用户反馈到 HF 仓库"""
text = (text or "").strip()
if not text:
raise ValueError("请填写反馈内容")
feedback_id = uuid.uuid4().hex
image_paths = []
image_files = image_files or []
for index, image_path in enumerate(image_files):
if not image_path or not os.path.exists(image_path):
continue
ext = os.path.splitext(image_path)[1].lower() or ".png"
remote_path = f"{FEEDBACK_REPO_PREFIX}/{feedback_id}_{index}{ext}"
upload_repo_file(image_path, remote_path)
image_paths.append(remote_path)
meta = {
"feedback_id": feedback_id,
"username": (username or "").strip() or "匿名",
"text": text,
"is_public": bool(is_public),
"created": datetime.now().isoformat(),
"images": image_paths,
}
with tempfile.NamedTemporaryFile("w", encoding="utf-8", suffix=".json", delete=False) as fp:
json.dump(meta, fp, ensure_ascii=False, indent=2)
tmp_json = fp.name
try:
upload_repo_file(tmp_json, f"{FEEDBACK_REPO_PREFIX}/{feedback_id}.json")
finally:
os.remove(tmp_json)
return meta
def get_feedback(feedback_id):
"""按 ID 获取单条反馈"""
json_path = f"{FEEDBACK_REPO_PREFIX}/{feedback_id}.json"
return _normalize_feedback(load_repo_json(json_path))
def ensure_feedback_image_cached(feedback_id, image_index, cache_dir):
"""下载反馈图片到本地缓存并返回路径"""
meta = get_feedback(feedback_id)
images = meta.get("images") or []
if image_index < 0 or image_index >= len(images):
raise FileNotFoundError("图片不存在")
remote_path = images[image_index]
filename = os.path.basename(remote_path)
local_path = os.path.join(cache_dir, f"{feedback_id}_{filename}")
if os.path.exists(local_path):
return local_path
return download_repo_file(remote_path, local_path)