feat: Improve file display, timezone handling, and LOT management
Changes: - Fix datetime serialization with UTC 'Z' suffix for correct timezone display - Add PDF upload support with extension fallback for MIME detection - Fix LOT add/remove by creating new list for SQLAlchemy JSON change detection - Add file message components (FileMessage, ImageLightbox, UploadPreview) - Add multi-file upload support with progress tracking - Link uploaded files to chat messages via message_id - Include file attachments in AI report generation - Update specs for file-storage, realtime-messaging, and ai-report-generation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,18 @@ Contains the prompt construction logic for building the user query
|
||||
sent to DIFY Chat API.
|
||||
"""
|
||||
from typing import List, Dict, Any
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timezone, timedelta
|
||||
|
||||
# Taiwan timezone (GMT+8)
|
||||
TZ_GMT8 = timezone(timedelta(hours=8))
|
||||
|
||||
|
||||
def _to_gmt8(dt: datetime) -> datetime:
|
||||
"""Convert datetime to GMT+8 timezone"""
|
||||
if dt.tzinfo is None:
|
||||
# Assume UTC if no timezone
|
||||
dt = dt.replace(tzinfo=timezone.utc)
|
||||
return dt.astimezone(TZ_GMT8)
|
||||
|
||||
|
||||
INCIDENT_TYPE_MAP = {
|
||||
@@ -81,11 +92,11 @@ def _format_room_info(room_data: Dict[str, Any]) -> str:
|
||||
|
||||
created_at = room_data.get("created_at")
|
||||
if isinstance(created_at, datetime):
|
||||
created_at = created_at.strftime("%Y-%m-%d %H:%M")
|
||||
created_at = _to_gmt8(created_at).strftime("%Y-%m-%d %H:%M")
|
||||
|
||||
resolved_at = room_data.get("resolved_at")
|
||||
if isinstance(resolved_at, datetime):
|
||||
resolved_at = resolved_at.strftime("%Y-%m-%d %H:%M")
|
||||
resolved_at = _to_gmt8(resolved_at).strftime("%Y-%m-%d %H:%M")
|
||||
elif resolved_at is None:
|
||||
resolved_at = "尚未解決"
|
||||
|
||||
@@ -145,7 +156,7 @@ def _format_messages(messages: List[Dict[str, Any]]) -> str:
|
||||
|
||||
created_at = msg.get("created_at")
|
||||
if isinstance(created_at, datetime):
|
||||
time_str = created_at.strftime("%Y-%m-%d %H:%M")
|
||||
time_str = _to_gmt8(created_at).strftime("%Y-%m-%d %H:%M")
|
||||
else:
|
||||
time_str = str(created_at) if created_at else "未知時間"
|
||||
|
||||
@@ -164,26 +175,58 @@ def _format_messages(messages: List[Dict[str, Any]]) -> str:
|
||||
|
||||
|
||||
def _format_files(files: List[Dict[str, Any]]) -> str:
|
||||
"""Format file attachments section"""
|
||||
"""Format file attachments section with context
|
||||
|
||||
Each file now includes:
|
||||
- caption: User-provided description when uploading
|
||||
- context_before: The message sent before this file
|
||||
- context_after: The message sent after this file
|
||||
|
||||
This helps AI understand the context of each attachment.
|
||||
"""
|
||||
lines = ["## 附件清單"]
|
||||
lines.append("每個附件包含上傳時的說明文字以及上下文訊息,幫助理解該附件的用途。")
|
||||
lines.append("")
|
||||
|
||||
if not files:
|
||||
lines.append("無附件")
|
||||
return "\n".join(lines)
|
||||
|
||||
for f in files:
|
||||
for i, f in enumerate(files, 1):
|
||||
filename = f.get("filename", "未命名檔案")
|
||||
file_type = f.get("file_type", "file")
|
||||
uploader = f.get("uploader_name") or f.get("uploaded_by", "未知")
|
||||
caption = f.get("caption") # User-provided description
|
||||
context_before = f.get("context_before")
|
||||
context_after = f.get("context_after")
|
||||
|
||||
uploaded_at = f.get("uploaded_at")
|
||||
if isinstance(uploaded_at, datetime):
|
||||
time_str = uploaded_at.strftime("%Y-%m-%d %H:%M")
|
||||
time_str = _to_gmt8(uploaded_at).strftime("%Y-%m-%d %H:%M")
|
||||
else:
|
||||
time_str = str(uploaded_at) if uploaded_at else ""
|
||||
|
||||
type_label = "圖片" if file_type == "image" else "檔案"
|
||||
lines.append(f"- [{type_label}] {filename} (由 {uploader} 於 {time_str} 上傳)")
|
||||
|
||||
# Basic file info
|
||||
lines.append(f"### 附件 {i}: {filename}")
|
||||
lines.append(f"- 類型: {type_label}")
|
||||
lines.append(f"- 上傳者: {uploader}")
|
||||
lines.append(f"- 上傳時間: {time_str}")
|
||||
|
||||
# Caption/description if provided
|
||||
if caption:
|
||||
lines.append(f"- 說明: {caption}")
|
||||
|
||||
# Context messages to help AI understand when/why file was uploaded
|
||||
if context_before or context_after:
|
||||
lines.append("- 上下文:")
|
||||
if context_before:
|
||||
lines.append(f" - 前一則訊息: [{context_before['sender']}]: {context_before['content']}")
|
||||
if context_after:
|
||||
lines.append(f" - 後一則訊息: [{context_after['sender']}]: {context_after['content']}")
|
||||
|
||||
lines.append("") # Blank line between files
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user