Commit dce41c59 by ccran

feat: add full text segment id support;

parent e047146d
......@@ -35,6 +35,7 @@ MAX_SINGLE_CHUNK_SIZE = 5000
MERGE_RULE_PROMPT = False
META_KEY = "META"
DEFAULT_RULESET_ID = "通用"
FULL_TEXT_SEGMENT_ID = -1
## 规则集ID列表,需与rules.xlsx中的sheet名称保持一致!!!
ALL_RULESET_IDS = [
"通用",
......
......@@ -18,6 +18,7 @@ from core.config import (
doc_support_formats,
pdf_support_formats,
MERGE_RULE_PROMPT,
FULL_TEXT_SEGMENT_ID,
use_lufa,
max_model_len,
debug_mode,
......@@ -266,11 +267,18 @@ def summarize_facts(payload: SegmentSummaryRequest) -> SegmentSummaryResponse:
class SegmentReviewRequest(BaseModel):
conversation_id: str
segment_id: int
segment_id: int = Field(
default=FULL_TEXT_SEGMENT_ID,
description="分段ID;为 FULL_TEXT_SEGMENT_ID 时使用 segment_text 审查全文",
)
segment_text: Optional[str] = Field(
default=None,
description="segment_id 为 FULL_TEXT_SEGMENT_ID 时用于审查的全文文本",
)
party_role: Optional[str] = ""
ruleset_id: Optional[str] = "通用"
routed_rule_titles: Optional[List[str]] = None
file_ext: str
file_ext: Optional[str] = None
context_memories: Optional[List[Dict]] = None
route_by: Literal["rule", "summary"] = Field(
default="rule", description="路由依据:rule=审查规则项,summary=摘要项"
......@@ -294,9 +302,27 @@ class SegmentRuleRouterResponse(BaseModel):
routed_rules: List[Dict]
@app.post("/segments/review/findings", response_model=SegmentReviewResponse)
def review_segment(payload: SegmentReviewRequest) -> SegmentReviewResponse:
store = get_cached_memory(payload.conversation_id)
def _resolve_review_segment(payload: SegmentReviewRequest):
if payload.segment_id == FULL_TEXT_SEGMENT_ID:
segment_text = (payload.segment_text or "").strip()
if not segment_text:
raise HTTPException(
status_code=400,
detail=f"segment_text cannot be empty when segment_id is {FULL_TEXT_SEGMENT_ID}",
)
return FULL_TEXT_SEGMENT_ID, segment_text, None
if payload.segment_id < FULL_TEXT_SEGMENT_ID:
raise HTTPException(
status_code=400,
detail=f"segment_id must be {FULL_TEXT_SEGMENT_ID} or greater",
)
if not payload.file_ext:
raise HTTPException(
status_code=400,
detail=f"file_ext is required when segment_id is not {FULL_TEXT_SEGMENT_ID}",
)
try:
doc_obj, _ = get_cached_doc_tool(payload.conversation_id, payload.file_ext)
except Exception as exc:
......@@ -312,6 +338,13 @@ def review_segment(payload: SegmentReviewRequest) -> SegmentReviewResponse:
status_code=404,
detail=f"Segment text not found for id {payload.segment_id}: {exc}. Please parse document first.",
)
return segment_idx, segment_text, doc_obj
@app.post("/segments/review/findings", response_model=SegmentReviewResponse)
def review_segment(payload: SegmentReviewRequest) -> SegmentReviewResponse:
store = get_cached_memory(payload.conversation_id)
segment_idx, segment_text, _ = _resolve_review_segment(payload)
ruleset_id = payload.ruleset_id or rules_reference_tool.default_ruleset_id
rules = rules_reference_tool.run(
......@@ -366,21 +399,7 @@ def review_segment(payload: SegmentReviewRequest) -> SegmentReviewResponse:
@app.post("/segments/review/rule-router", response_model=SegmentRuleRouterResponse)
def route_segment_rules(payload: SegmentReviewRequest) -> SegmentRuleRouterResponse:
try:
doc_obj, _ = get_cached_doc_tool(payload.conversation_id, payload.file_ext)
except Exception as exc:
raise HTTPException(
status_code=400, detail=f"Document tool not available: {exc}"
)
segment_idx = payload.segment_id - 1
try:
segment_text = doc_obj.get_chunk_item(segment_idx)
except Exception as exc:
raise HTTPException(
status_code=404,
detail=f"Segment text not found for id {payload.segment_id}: {exc}. Please parse document first.",
)
segment_idx, segment_text, doc_obj = _resolve_review_segment(payload)
ruleset_id = payload.ruleset_id or rules_reference_tool.default_ruleset_id
rules = rules_reference_tool.run(ruleset_id=ruleset_id).get("rules", [])
......
......@@ -4,7 +4,7 @@ import re
from thefuzz import fuzz
from utils.doc_util import DocBase
from utils.common_util import adjust_single_chunk_size
from core.config import use_lufa
from core.config import FULL_TEXT_SEGMENT_ID, use_lufa
import os
......@@ -553,6 +553,22 @@ class SpireWordDoc(DocBase):
for loc in chunk_locations
]
def get_all_sub_chunks(self):
self._ensure_loaded()
sub_chunks = []
for chunk_id in range(len(self._chunk_list)):
sub_chunks.extend(self.get_sub_chunks(chunk_id))
return sub_chunks
def _get_comment_sub_chunks(self, chunk_id):
self._ensure_loaded()
if chunk_id == FULL_TEXT_SEGMENT_ID:
return self.get_all_sub_chunks()
if isinstance(chunk_id, int) and 0 <= chunk_id < self.get_chunk_num():
return self.get_sub_chunks(chunk_id)
logger.error(f"invalid chunk_id for comment: {chunk_id}")
return []
def format_comment_author(self, comment):
return "{}|{}".format(str(comment["id"]), comment["key_points"])
......@@ -820,14 +836,15 @@ class SpireWordDoc(DocBase):
for comment in comments:
if comment.get("result") != "不合格":
continue
# update chunk_id
comment_chunk_id = comment.get("chunk_id", -1)
# 优先使用comments里提供的chunk_id,如果没有或无效则使用外部传入的chunk_id,如果都没有则异常处理
sub_chunks = (
self.get_sub_chunks(comment_chunk_id)
if comment_chunk_id != -1 and comment_chunk_id < self.get_chunk_num()
else self.get_sub_chunks(chunk_id)
)
comment_chunk_id = comment.get("chunk_id")
# 优先使用 comment 中的 chunk_id;-1 表示全文;缺失或无效时回退到入参 chunk_id。
if isinstance(comment_chunk_id, int) and (
comment_chunk_id == FULL_TEXT_SEGMENT_ID
or 0 <= comment_chunk_id < self.get_chunk_num()
):
sub_chunks = self._get_comment_sub_chunks(comment_chunk_id)
else:
sub_chunks = self._get_comment_sub_chunks(chunk_id)
author = self.format_comment_author(comment)
suggest = comment.get("suggest", "")
original_text = (comment.get("original_text") or "").strip()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment