Fix time zone problem of doc status
Browse files
lightrag/api/routers/document_routes.py
CHANGED
@@ -9,7 +9,7 @@ import aiofiles
|
|
9 |
import shutil
|
10 |
import traceback
|
11 |
import pipmaster as pm
|
12 |
-
from datetime import datetime
|
13 |
from pathlib import Path
|
14 |
from typing import Dict, List, Optional, Any, Literal
|
15 |
from fastapi import APIRouter, BackgroundTasks, Depends, File, HTTPException, UploadFile
|
@@ -20,6 +20,30 @@ from lightrag.base import DocProcessingStatus, DocStatus
|
|
20 |
from lightrag.api.utils_api import get_combined_auth_dependency
|
21 |
from ..config import global_args
|
22 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
router = APIRouter(
|
24 |
prefix="/documents",
|
25 |
tags=["documents"],
|
@@ -207,14 +231,6 @@ Attributes:
|
|
207 |
|
208 |
|
209 |
class DocStatusResponse(BaseModel):
|
210 |
-
@staticmethod
|
211 |
-
def format_datetime(dt: Any) -> Optional[str]:
|
212 |
-
if dt is None:
|
213 |
-
return None
|
214 |
-
if isinstance(dt, str):
|
215 |
-
return dt
|
216 |
-
return dt.isoformat()
|
217 |
-
|
218 |
id: str = Field(description="Document identifier")
|
219 |
content_summary: str = Field(description="Summary of document content")
|
220 |
content_length: int = Field(description="Length of document content in characters")
|
@@ -300,7 +316,7 @@ class PipelineStatusResponse(BaseModel):
|
|
300 |
autoscanned: Whether auto-scan has started
|
301 |
busy: Whether the pipeline is currently busy
|
302 |
job_name: Current job name (e.g., indexing files/indexing texts)
|
303 |
-
job_start: Job start time as ISO format string (optional)
|
304 |
docs: Total number of documents to be indexed
|
305 |
batchs: Number of batches for processing documents
|
306 |
cur_batch: Current processing batch
|
@@ -322,6 +338,12 @@ class PipelineStatusResponse(BaseModel):
|
|
322 |
history_messages: Optional[List[str]] = None
|
323 |
update_status: Optional[dict] = None
|
324 |
|
|
|
|
|
|
|
|
|
|
|
|
|
325 |
class Config:
|
326 |
extra = "allow" # Allow additional fields from the pipeline status
|
327 |
|
@@ -1188,9 +1210,10 @@ def create_document_routes(
|
|
1188 |
if "history_messages" in status_dict:
|
1189 |
status_dict["history_messages"] = list(status_dict["history_messages"])
|
1190 |
|
1191 |
-
#
|
1192 |
-
if status_dict
|
1193 |
-
|
|
|
1194 |
|
1195 |
return PipelineStatusResponse(**status_dict)
|
1196 |
except Exception as e:
|
@@ -1240,10 +1263,10 @@ def create_document_routes(
|
|
1240 |
content_summary=doc_status.content_summary,
|
1241 |
content_length=doc_status.content_length,
|
1242 |
status=doc_status.status,
|
1243 |
-
created_at=
|
1244 |
doc_status.created_at
|
1245 |
),
|
1246 |
-
updated_at=
|
1247 |
doc_status.updated_at
|
1248 |
),
|
1249 |
chunks_count=doc_status.chunks_count,
|
|
|
9 |
import shutil
|
10 |
import traceback
|
11 |
import pipmaster as pm
|
12 |
+
from datetime import datetime, timezone
|
13 |
from pathlib import Path
|
14 |
from typing import Dict, List, Optional, Any, Literal
|
15 |
from fastapi import APIRouter, BackgroundTasks, Depends, File, HTTPException, UploadFile
|
|
|
20 |
from lightrag.api.utils_api import get_combined_auth_dependency
|
21 |
from ..config import global_args
|
22 |
|
23 |
+
# Function to format datetime to ISO format string with timezone information
|
24 |
+
def format_datetime(dt: Any) -> Optional[str]:
|
25 |
+
"""Format datetime to ISO format string with timezone information
|
26 |
+
|
27 |
+
Args:
|
28 |
+
dt: Datetime object, string, or None
|
29 |
+
|
30 |
+
Returns:
|
31 |
+
ISO format string with timezone information, or None if input is None
|
32 |
+
"""
|
33 |
+
if dt is None:
|
34 |
+
return None
|
35 |
+
if isinstance(dt, str):
|
36 |
+
return dt
|
37 |
+
|
38 |
+
# Check if datetime object has timezone information
|
39 |
+
if isinstance(dt, datetime):
|
40 |
+
# If datetime object has no timezone info (naive datetime), add UTC timezone
|
41 |
+
if dt.tzinfo is None:
|
42 |
+
dt = dt.replace(tzinfo=timezone.utc)
|
43 |
+
|
44 |
+
# Return ISO format string with timezone information
|
45 |
+
return dt.isoformat()
|
46 |
+
|
47 |
router = APIRouter(
|
48 |
prefix="/documents",
|
49 |
tags=["documents"],
|
|
|
231 |
|
232 |
|
233 |
class DocStatusResponse(BaseModel):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
234 |
id: str = Field(description="Document identifier")
|
235 |
content_summary: str = Field(description="Summary of document content")
|
236 |
content_length: int = Field(description="Length of document content in characters")
|
|
|
316 |
autoscanned: Whether auto-scan has started
|
317 |
busy: Whether the pipeline is currently busy
|
318 |
job_name: Current job name (e.g., indexing files/indexing texts)
|
319 |
+
job_start: Job start time as ISO format string with timezone (optional)
|
320 |
docs: Total number of documents to be indexed
|
321 |
batchs: Number of batches for processing documents
|
322 |
cur_batch: Current processing batch
|
|
|
338 |
history_messages: Optional[List[str]] = None
|
339 |
update_status: Optional[dict] = None
|
340 |
|
341 |
+
@field_validator('job_start', mode='before')
|
342 |
+
@classmethod
|
343 |
+
def parse_job_start(cls, value):
|
344 |
+
"""Process datetime and return as ISO format string with timezone"""
|
345 |
+
return format_datetime(value)
|
346 |
+
|
347 |
class Config:
|
348 |
extra = "allow" # Allow additional fields from the pipeline status
|
349 |
|
|
|
1210 |
if "history_messages" in status_dict:
|
1211 |
status_dict["history_messages"] = list(status_dict["history_messages"])
|
1212 |
|
1213 |
+
# Ensure job_start is properly formatted as a string with timezone information
|
1214 |
+
if "job_start" in status_dict and status_dict["job_start"]:
|
1215 |
+
# Use format_datetime to ensure consistent formatting
|
1216 |
+
status_dict["job_start"] = format_datetime(status_dict["job_start"])
|
1217 |
|
1218 |
return PipelineStatusResponse(**status_dict)
|
1219 |
except Exception as e:
|
|
|
1263 |
content_summary=doc_status.content_summary,
|
1264 |
content_length=doc_status.content_length,
|
1265 |
status=doc_status.status,
|
1266 |
+
created_at=format_datetime(
|
1267 |
doc_status.created_at
|
1268 |
),
|
1269 |
+
updated_at=format_datetime(
|
1270 |
doc_status.updated_at
|
1271 |
),
|
1272 |
chunks_count=doc_status.chunks_count,
|
lightrag/lightrag.py
CHANGED
@@ -6,7 +6,7 @@ import configparser
|
|
6 |
import os
|
7 |
import warnings
|
8 |
from dataclasses import asdict, dataclass, field
|
9 |
-
from datetime import datetime
|
10 |
from functools import partial
|
11 |
from typing import (
|
12 |
Any,
|
@@ -756,8 +756,8 @@ class LightRAG:
|
|
756 |
"content": content_data["content"],
|
757 |
"content_summary": get_content_summary(content_data["content"]),
|
758 |
"content_length": len(content_data["content"]),
|
759 |
-
"created_at": datetime.now().isoformat(),
|
760 |
-
"updated_at": datetime.now().isoformat(),
|
761 |
"file_path": content_data[
|
762 |
"file_path"
|
763 |
], # Store file path in document status
|
@@ -840,7 +840,7 @@ class LightRAG:
|
|
840 |
{
|
841 |
"busy": True,
|
842 |
"job_name": "Default Job",
|
843 |
-
"job_start": datetime.now().isoformat(),
|
844 |
"docs": 0,
|
845 |
"batchs": 0, # Total number of files to be processed
|
846 |
"cur_batch": 0, # Number of files already processed
|
@@ -958,7 +958,7 @@ class LightRAG:
|
|
958 |
"content_summary": status_doc.content_summary,
|
959 |
"content_length": status_doc.content_length,
|
960 |
"created_at": status_doc.created_at,
|
961 |
-
"updated_at": datetime.now().isoformat(),
|
962 |
"file_path": file_path,
|
963 |
}
|
964 |
}
|
@@ -1018,7 +1018,7 @@ class LightRAG:
|
|
1018 |
"content_summary": status_doc.content_summary,
|
1019 |
"content_length": status_doc.content_length,
|
1020 |
"created_at": status_doc.created_at,
|
1021 |
-
"updated_at": datetime.now().isoformat(),
|
1022 |
"file_path": file_path,
|
1023 |
}
|
1024 |
}
|
@@ -1053,7 +1053,7 @@ class LightRAG:
|
|
1053 |
"content_summary": status_doc.content_summary,
|
1054 |
"content_length": status_doc.content_length,
|
1055 |
"created_at": status_doc.created_at,
|
1056 |
-
"updated_at": datetime.now().isoformat(),
|
1057 |
"file_path": file_path,
|
1058 |
}
|
1059 |
}
|
|
|
6 |
import os
|
7 |
import warnings
|
8 |
from dataclasses import asdict, dataclass, field
|
9 |
+
from datetime import datetime, timezone
|
10 |
from functools import partial
|
11 |
from typing import (
|
12 |
Any,
|
|
|
756 |
"content": content_data["content"],
|
757 |
"content_summary": get_content_summary(content_data["content"]),
|
758 |
"content_length": len(content_data["content"]),
|
759 |
+
"created_at": datetime.now(timezone.utc).isoformat(),
|
760 |
+
"updated_at": datetime.now(timezone.utc).isoformat(),
|
761 |
"file_path": content_data[
|
762 |
"file_path"
|
763 |
], # Store file path in document status
|
|
|
840 |
{
|
841 |
"busy": True,
|
842 |
"job_name": "Default Job",
|
843 |
+
"job_start": datetime.now(timezone.utc).isoformat(),
|
844 |
"docs": 0,
|
845 |
"batchs": 0, # Total number of files to be processed
|
846 |
"cur_batch": 0, # Number of files already processed
|
|
|
958 |
"content_summary": status_doc.content_summary,
|
959 |
"content_length": status_doc.content_length,
|
960 |
"created_at": status_doc.created_at,
|
961 |
+
"updated_at": datetime.now(timezone.utc).isoformat(),
|
962 |
"file_path": file_path,
|
963 |
}
|
964 |
}
|
|
|
1018 |
"content_summary": status_doc.content_summary,
|
1019 |
"content_length": status_doc.content_length,
|
1020 |
"created_at": status_doc.created_at,
|
1021 |
+
"updated_at": datetime.now(timezone.utc).isoformat(),
|
1022 |
"file_path": file_path,
|
1023 |
}
|
1024 |
}
|
|
|
1053 |
"content_summary": status_doc.content_summary,
|
1054 |
"content_length": status_doc.content_length,
|
1055 |
"created_at": status_doc.created_at,
|
1056 |
+
"updated_at": datetime.now(timezone.utc).isoformat(),
|
1057 |
"file_path": file_path,
|
1058 |
}
|
1059 |
}
|
lightrag_webui/src/components/documents/PipelineStatusDialog.tsx
CHANGED
@@ -158,7 +158,16 @@ export default function PipelineStatusDialog({
|
|
158 |
<div className="rounded-md border p-3 space-y-2">
|
159 |
<div>{t('documentPanel.pipelineStatus.jobName')}: {status?.job_name || '-'}</div>
|
160 |
<div className="flex justify-between">
|
161 |
-
<span>{t('documentPanel.pipelineStatus.startTime')}: {status?.job_start
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
162 |
<span>{t('documentPanel.pipelineStatus.progress')}: {status ? `${status.cur_batch}/${status.batchs} ${t('documentPanel.pipelineStatus.unit')}` : '-'}</span>
|
163 |
</div>
|
164 |
</div>
|
|
|
158 |
<div className="rounded-md border p-3 space-y-2">
|
159 |
<div>{t('documentPanel.pipelineStatus.jobName')}: {status?.job_name || '-'}</div>
|
160 |
<div className="flex justify-between">
|
161 |
+
<span>{t('documentPanel.pipelineStatus.startTime')}: {status?.job_start
|
162 |
+
? new Date(status.job_start).toLocaleString(undefined, {
|
163 |
+
year: 'numeric',
|
164 |
+
month: 'numeric',
|
165 |
+
day: 'numeric',
|
166 |
+
hour: 'numeric',
|
167 |
+
minute: 'numeric',
|
168 |
+
second: 'numeric'
|
169 |
+
})
|
170 |
+
: '-'}</span>
|
171 |
<span>{t('documentPanel.pipelineStatus.progress')}: {status ? `${status.cur_batch}/${status.batchs} ${t('documentPanel.pipelineStatus.unit')}` : '-'}</span>
|
172 |
</div>
|
173 |
</div>
|