VietCat commited on
Commit
35f4ffd
·
1 Parent(s): 55d95bd

add data viewer

Browse files
Files changed (2) hide show
  1. app/law_document_chunker.py +36 -14
  2. app/main.py +75 -8
app/law_document_chunker.py CHANGED
@@ -183,12 +183,27 @@ class LawDocumentChunker:
183
  """Xử lý văn bản theo cấu trúc phân cấp."""
184
  lines = content.split('\n')
185
  chunks = []
186
- parent_stack = [] # Stack để theo dõi parent IDs
187
- current_parent = None
 
 
188
 
189
  current_chunk_content = ""
190
  current_level = "CONTENT"
191
  current_level_value = None
 
 
 
 
 
 
 
 
 
 
 
 
 
192
 
193
  for line in lines:
194
  level, level_value, level_content = self._detect_structure_level(line)
@@ -207,18 +222,11 @@ class LawDocumentChunker:
207
  )
208
  chunks.append(metadata)
209
 
210
- # Cập nhật parent stack
211
- if level in ["PHAN", "PHU_LUC", "CHUONG", "MUC"]:
212
- # Cấp độ cao, reset stack
213
- parent_stack = [metadata.id]
214
- current_parent = metadata.id
215
- elif level == "DIEU":
216
- # Điều thuộc về cấp độ cao nhất hiện tại
217
- current_parent = parent_stack[-1] if parent_stack else None
218
- parent_stack.append(metadata.id)
219
- elif level in ["KHOAN", "DIEM"]:
220
- # Khoản/Điểm thuộc về Điều hiện tại
221
- current_parent = parent_stack[-1] if parent_stack else None
222
 
223
  # Bắt đầu chunk mới
224
  current_chunk_content = line + "\n"
@@ -260,6 +268,20 @@ class LawDocumentChunker:
260
 
261
  logger.info(f"[CHUNKER] Created {len(chunks)} chunks from document")
262
  return chunks
 
 
 
 
 
 
 
 
 
 
 
 
 
 
263
 
264
  async def _create_embeddings_for_chunks(self, chunks: List[ChunkMetadata]) -> int:
265
  """Tạo embeddings cho các chunks và lưu ngay lập tức vào Supabase."""
 
183
  """Xử lý văn bản theo cấu trúc phân cấp."""
184
  lines = content.split('\n')
185
  chunks = []
186
+
187
+ # Stack để theo dõi các chunks theo thứ tự xuất hiện
188
+ # Mỗi item là (chunk_id, level, level_value)
189
+ chunk_stack = []
190
 
191
  current_chunk_content = ""
192
  current_level = "CONTENT"
193
  current_level_value = None
194
+ current_parent = None
195
+
196
+ # Định nghĩa thứ tự ưu tiên của các level (số càng nhỏ càng cao)
197
+ level_priority = {
198
+ "PHAN": 1,
199
+ "PHU_LUC": 1,
200
+ "CHUONG": 2,
201
+ "MUC": 3,
202
+ "DIEU": 4,
203
+ "KHOAN": 5,
204
+ "DIEM": 6,
205
+ "CONTENT": 7
206
+ }
207
 
208
  for line in lines:
209
  level, level_value, level_content = self._detect_structure_level(line)
 
222
  )
223
  chunks.append(metadata)
224
 
225
+ # Thêm vào stack
226
+ chunk_stack.append((metadata.id, current_level, current_level_value))
227
+
228
+ # Tìm parent cho level mới
229
+ current_parent = self._find_parent_for_level(chunk_stack, level, level_priority)
 
 
 
 
 
 
 
230
 
231
  # Bắt đầu chunk mới
232
  current_chunk_content = line + "\n"
 
268
 
269
  logger.info(f"[CHUNKER] Created {len(chunks)} chunks from document")
270
  return chunks
271
+
272
+ def _find_parent_for_level(self, chunk_stack: List[Tuple[str, str, Optional[str]]],
273
+ current_level: str, level_priority: Dict[str, int]) -> Optional[str]:
274
+ """
275
+ Tìm parent gần nhất có level cao hơn (priority thấp hơn) cho level hiện tại.
276
+ """
277
+ current_priority = level_priority.get(current_level, 999)
278
+
279
+ # Tìm từ cuối stack (gần nhất) đến đầu stack
280
+ for chunk_id, level, level_value in reversed(chunk_stack):
281
+ if level_priority.get(level, 999) < current_priority:
282
+ return chunk_id
283
+
284
+ return None
285
 
286
  async def _create_embeddings_for_chunks(self, chunks: List[ChunkMetadata]) -> int:
287
  """Tạo embeddings cho các chunks và lưu ngay lập tức vào Supabase."""
app/main.py CHANGED
@@ -2,7 +2,7 @@ from fastapi import FastAPI, Request, HTTPException, Depends
2
  from fastapi.middleware.cors import CORSMiddleware
3
  from loguru import logger
4
  import json
5
- from typing import Dict, Any, List
6
  import asyncio
7
  from concurrent.futures import ThreadPoolExecutor
8
  import os
@@ -698,7 +698,7 @@ async def update_all_documents():
698
  @timing_decorator_async
699
  async def view_all_document_chunks():
700
  """
701
- API xem toàn bộ dữ liệu trong bảng document_chunks.
702
  """
703
  try:
704
  logger.info("[API] Starting view all document chunks")
@@ -710,7 +710,7 @@ async def view_all_document_chunks():
710
  total_chunks = len(chunks_data)
711
  unique_documents = len(set(chunk.get('vanbanid') for chunk in chunks_data if chunk.get('vanbanid')))
712
 
713
- # Nhóm theo vanbanid để thống kê và tổ chức data
714
  chunks_by_document = {}
715
  for chunk in chunks_data:
716
  vanbanid = chunk.get('vanbanid')
@@ -720,7 +720,7 @@ async def view_all_document_chunks():
720
 
721
  # Thống kê chi tiết
722
  document_stats = []
723
- grouped_data = []
724
 
725
  for vanbanid, chunks in chunks_by_document.items():
726
  # Thống kê
@@ -730,12 +730,14 @@ async def view_all_document_chunks():
730
  "document_title": chunks[0].get('document_title', 'Unknown') if chunks else 'Unknown'
731
  })
732
 
733
- # Nhóm data theo vanbanid
734
- grouped_data.append({
 
 
735
  "vanbanid": vanbanid,
736
  "document_title": chunks[0].get('document_title', 'Unknown') if chunks else 'Unknown',
737
  "chunk_count": len(chunks),
738
- "chunks": chunks
739
  })
740
 
741
  return {
@@ -746,13 +748,78 @@ async def view_all_document_chunks():
746
  "unique_documents": unique_documents,
747
  "document_stats": document_stats
748
  },
749
- "data": grouped_data
750
  }
751
 
752
  except Exception as e:
753
  logger.error(f"[API] Error in view_all_document_chunks: {e}")
754
  raise HTTPException(status_code=500, detail=f"Lỗi: {str(e)}")
755
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
756
  @app.get("/api/document-chunks/status")
757
  @timing_decorator_async
758
  async def get_document_chunks_status():
 
2
  from fastapi.middleware.cors import CORSMiddleware
3
  from loguru import logger
4
  import json
5
+ from typing import Dict, Any, List, Optional
6
  import asyncio
7
  from concurrent.futures import ThreadPoolExecutor
8
  import os
 
698
  @timing_decorator_async
699
  async def view_all_document_chunks():
700
  """
701
+ API xem toàn bộ dữ liệu trong bảng document_chunks theo cấu trúc cây.
702
  """
703
  try:
704
  logger.info("[API] Starting view all document chunks")
 
710
  total_chunks = len(chunks_data)
711
  unique_documents = len(set(chunk.get('vanbanid') for chunk in chunks_data if chunk.get('vanbanid')))
712
 
713
+ # Nhóm theo vanbanid
714
  chunks_by_document = {}
715
  for chunk in chunks_data:
716
  vanbanid = chunk.get('vanbanid')
 
720
 
721
  # Thống kê chi tiết
722
  document_stats = []
723
+ hierarchical_data = []
724
 
725
  for vanbanid, chunks in chunks_by_document.items():
726
  # Thống kê
 
730
  "document_title": chunks[0].get('document_title', 'Unknown') if chunks else 'Unknown'
731
  })
732
 
733
+ # Tạo cấu trúc cây cho từng văn bản
734
+ tree_structure = build_chunk_tree(chunks)
735
+
736
+ hierarchical_data.append({
737
  "vanbanid": vanbanid,
738
  "document_title": chunks[0].get('document_title', 'Unknown') if chunks else 'Unknown',
739
  "chunk_count": len(chunks),
740
+ "chunks": tree_structure
741
  })
742
 
743
  return {
 
748
  "unique_documents": unique_documents,
749
  "document_stats": document_stats
750
  },
751
+ "data": hierarchical_data
752
  }
753
 
754
  except Exception as e:
755
  logger.error(f"[API] Error in view_all_document_chunks: {e}")
756
  raise HTTPException(status_code=500, detail=f"Lỗi: {str(e)}")
757
 
758
+ def build_chunk_tree(chunks: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
759
+ """
760
+ Xây dựng cấu trúc cây từ danh sách chunks phẳng.
761
+ """
762
+ # Tạo dictionary để truy cập nhanh
763
+ chunks_dict = {chunk['id']: chunk for chunk in chunks}
764
+
765
+ # Tạo cấu trúc cây
766
+ root_chunks = []
767
+
768
+ for chunk in chunks:
769
+ chunk_id = chunk['id']
770
+ parent_id = chunk.get('cha')
771
+
772
+ # Tạo node mới với cấu trúc cây
773
+ tree_node = {
774
+ "id": chunk_id,
775
+ "content": chunk.get('content', ''),
776
+ "vanbanid": chunk.get('vanbanid'),
777
+ "cha": parent_id,
778
+ "document_title": chunk.get('document_title', ''),
779
+ "article_number": chunk.get('article_number'),
780
+ "article_title": chunk.get('article_title', ''),
781
+ "clause_number": chunk.get('clause_number', ''),
782
+ "sub_clause_letter": chunk.get('sub_clause_letter', ''),
783
+ "context_summary": chunk.get('context_summary', ''),
784
+ "data": chunk, # Toàn bộ dữ liệu gốc
785
+ "children": []
786
+ }
787
+
788
+ if parent_id is None:
789
+ # Đây là root node
790
+ root_chunks.append(tree_node)
791
+ else:
792
+ # Tìm parent và thêm vào children
793
+ parent = chunks_dict.get(parent_id)
794
+ if parent:
795
+ # Tìm node parent trong cây
796
+ parent_node = find_node_in_tree(root_chunks, parent_id)
797
+ if parent_node:
798
+ parent_node["children"].append(tree_node)
799
+ else:
800
+ # Nếu không tìm thấy parent, coi như root
801
+ root_chunks.append(tree_node)
802
+ else:
803
+ # Parent không tồn tại, coi như root
804
+ root_chunks.append(tree_node)
805
+
806
+ return root_chunks
807
+
808
+ def find_node_in_tree(nodes: List[Dict[str, Any]], target_id: str) -> Optional[Dict[str, Any]]:
809
+ """
810
+ Tìm node trong cây theo ID.
811
+ """
812
+ for node in nodes:
813
+ if node["id"] == target_id:
814
+ return node
815
+
816
+ # Tìm trong children
817
+ found = find_node_in_tree(node.get("children", []), target_id)
818
+ if found:
819
+ return found
820
+
821
+ return None
822
+
823
  @app.get("/api/document-chunks/status")
824
  @timing_decorator_async
825
  async def get_document_chunks_status():