import os import json from datetime import datetime, timedelta import gradio as gr import spaces DATA_FILE = "messages.json" UPLOAD_DIR = "uploads" os.makedirs(UPLOAD_DIR, exist_ok=True) # 保留留言的天數(設為 30 天) RETENTION_DAYS = 30 def cleanup_old_messages(messages): """清理超過 Retention Days 的舊留言與對應圖片檔""" now = datetime.now() valid_messages = [] for msg in messages: try: # 解析留言時間 (格式: YYYY-MM-DD HH:MM) msg_time = datetime.strptime(msg["time"], "%Y-%m-%d %H:%M") # 判斷是否在 30 天內 if now - msg_time <= timedelta(days=RETENTION_DAYS): valid_messages.append(msg) else: # 已過期,刪除相關圖片實體檔案以釋放空間 if msg.get("image") and os.path.exists(msg["image"]): try: os.remove(msg["image"]) except Exception as e: print(f"刪除舊圖片失敗: {e}") except Exception: # 若時間解析失敗,預設留存 valid_messages.append(msg) return valid_messages def load_messages(): if os.path.exists(DATA_FILE): with open(DATA_FILE, "r", encoding="utf-8") as f: try: messages = json.load(f) # 載入時自動執行一次清理 cleaned_messages = cleanup_old_messages(messages) if len(cleaned_messages) != len(messages): save_messages(cleaned_messages) return cleaned_messages except Exception: return [] return [] def save_messages(messages): with open(DATA_FILE, "w", encoding="utf-8") as f: json.dump(messages, f, ensure_ascii=False, indent=2) @spaces.GPU(duration=1) def dummy_gpu_task(): return True def add_post(author, text, image): author = author.strip() if author and author.strip() else "匿名成員" img_path = None if image is not None: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") img_path = os.path.join(UPLOAD_DIR, f"{timestamp}.png") image.save(img_path) # 讀取並自動清理舊資料 messages = load_messages() messages.insert(0, { "author": author, "text": text, "image": img_path, "time": datetime.now().strftime("%Y-%m-%d %H:%M") }) # 儲存前再次確保只留 30 天內的資料 messages = cleanup_old_messages(messages) save_messages(messages) return "", "", None, *get_board_data() def get_board_data(): messages = load_messages() text_logs = [] gallery_images = [] for msg in messages: text_logs.append(f"📌 {msg['author']}({msg['time']})\n{msg['text']}\n" + "—"*25) if msg.get('image') and os.path.exists(msg['image']): gallery_images.append((msg['image'], f"{msg['author']} 的分享 ({msg['time']})")) full_text = "\n\n".join(text_logs) if text_logs else "目前尚無留言(近 30 天)。" return full_text, gallery_images with gr.Blocks(title="家庭佈告欄") as demo: gr.Markdown("# 🏡 家庭成員佈告欄") gr.Markdown("💡 *系統將自動保留最近 30 天內的留言與照片,過期內容會自動清除以清理空間。*") with gr.Row(): with gr.Column(): author_input = gr.Textbox(label="你的稱呼", placeholder="例如:媽媽、小明") text_input = gr.Textbox(label="留言內容", lines=3, placeholder="想跟大家說什麼?") image_input = gr.Image(label="上傳照片(可選)", type="pil") submit_btn = gr.Button("發布動態", variant="primary") with gr.Column(): init_text, init_gallery = get_board_data() board_text = gr.Textbox(value=init_text, label="留言記錄(近30天)", lines=8, interactive=False) board_gallery = gr.Gallery(value=init_gallery, label="照片牆") refresh_btn = gr.Button("🔄 重新整理") submit_btn.click( fn=add_post, inputs=[author_input, text_input, image_input], outputs=[author_input, text_input, image_input, board_text, board_gallery] ) refresh_btn.click( fn=get_board_data, outputs=[board_text, board_gallery] ) demo.launch()