Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
ccran
/
lufa-contract
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
dce41c59
authored
Jun 24, 2026
by
ccran
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: add full text segment id support;
parent
e047146d
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
66 additions
and
29 deletions
+66
-29
core/config.py
+1
-0
main.py
+39
-20
utils/spire_word_util.py
+26
-9
No files found.
core/config.py
View file @
dce41c59
...
@@ -35,6 +35,7 @@ MAX_SINGLE_CHUNK_SIZE = 5000
...
@@ -35,6 +35,7 @@ MAX_SINGLE_CHUNK_SIZE = 5000
MERGE_RULE_PROMPT
=
False
MERGE_RULE_PROMPT
=
False
META_KEY
=
"META"
META_KEY
=
"META"
DEFAULT_RULESET_ID
=
"通用"
DEFAULT_RULESET_ID
=
"通用"
FULL_TEXT_SEGMENT_ID
=
-
1
## 规则集ID列表,需与rules.xlsx中的sheet名称保持一致!!!
## 规则集ID列表,需与rules.xlsx中的sheet名称保持一致!!!
ALL_RULESET_IDS
=
[
ALL_RULESET_IDS
=
[
"通用"
,
"通用"
,
...
...
main.py
View file @
dce41c59
...
@@ -18,6 +18,7 @@ from core.config import (
...
@@ -18,6 +18,7 @@ from core.config import (
doc_support_formats
,
doc_support_formats
,
pdf_support_formats
,
pdf_support_formats
,
MERGE_RULE_PROMPT
,
MERGE_RULE_PROMPT
,
FULL_TEXT_SEGMENT_ID
,
use_lufa
,
use_lufa
,
max_model_len
,
max_model_len
,
debug_mode
,
debug_mode
,
...
@@ -266,11 +267,18 @@ def summarize_facts(payload: SegmentSummaryRequest) -> SegmentSummaryResponse:
...
@@ -266,11 +267,18 @@ def summarize_facts(payload: SegmentSummaryRequest) -> SegmentSummaryResponse:
class
SegmentReviewRequest
(
BaseModel
):
class
SegmentReviewRequest
(
BaseModel
):
conversation_id
:
str
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
]
=
""
party_role
:
Optional
[
str
]
=
""
ruleset_id
:
Optional
[
str
]
=
"通用"
ruleset_id
:
Optional
[
str
]
=
"通用"
routed_rule_titles
:
Optional
[
List
[
str
]]
=
None
routed_rule_titles
:
Optional
[
List
[
str
]]
=
None
file_ext
:
str
file_ext
:
Optional
[
str
]
=
None
context_memories
:
Optional
[
List
[
Dict
]]
=
None
context_memories
:
Optional
[
List
[
Dict
]]
=
None
route_by
:
Literal
[
"rule"
,
"summary"
]
=
Field
(
route_by
:
Literal
[
"rule"
,
"summary"
]
=
Field
(
default
=
"rule"
,
description
=
"路由依据:rule=审查规则项,summary=摘要项"
default
=
"rule"
,
description
=
"路由依据:rule=审查规则项,summary=摘要项"
...
@@ -294,9 +302,27 @@ class SegmentRuleRouterResponse(BaseModel):
...
@@ -294,9 +302,27 @@ class SegmentRuleRouterResponse(BaseModel):
routed_rules
:
List
[
Dict
]
routed_rules
:
List
[
Dict
]
@app.post
(
"/segments/review/findings"
,
response_model
=
SegmentReviewResponse
)
def
_resolve_review_segment
(
payload
:
SegmentReviewRequest
):
def
review_segment
(
payload
:
SegmentReviewRequest
)
->
SegmentReviewResponse
:
if
payload
.
segment_id
==
FULL_TEXT_SEGMENT_ID
:
store
=
get_cached_memory
(
payload
.
conversation_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
:
try
:
doc_obj
,
_
=
get_cached_doc_tool
(
payload
.
conversation_id
,
payload
.
file_ext
)
doc_obj
,
_
=
get_cached_doc_tool
(
payload
.
conversation_id
,
payload
.
file_ext
)
except
Exception
as
exc
:
except
Exception
as
exc
:
...
@@ -312,6 +338,13 @@ def review_segment(payload: SegmentReviewRequest) -> SegmentReviewResponse:
...
@@ -312,6 +338,13 @@ def review_segment(payload: SegmentReviewRequest) -> SegmentReviewResponse:
status_code
=
404
,
status_code
=
404
,
detail
=
f
"Segment text not found for id {payload.segment_id}: {exc}. Please parse document first."
,
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
ruleset_id
=
payload
.
ruleset_id
or
rules_reference_tool
.
default_ruleset_id
rules
=
rules_reference_tool
.
run
(
rules
=
rules_reference_tool
.
run
(
...
@@ -366,21 +399,7 @@ def review_segment(payload: SegmentReviewRequest) -> SegmentReviewResponse:
...
@@ -366,21 +399,7 @@ def review_segment(payload: SegmentReviewRequest) -> SegmentReviewResponse:
@app.post
(
"/segments/review/rule-router"
,
response_model
=
SegmentRuleRouterResponse
)
@app.post
(
"/segments/review/rule-router"
,
response_model
=
SegmentRuleRouterResponse
)
def
route_segment_rules
(
payload
:
SegmentReviewRequest
)
->
SegmentRuleRouterResponse
:
def
route_segment_rules
(
payload
:
SegmentReviewRequest
)
->
SegmentRuleRouterResponse
:
try
:
segment_idx
,
segment_text
,
doc_obj
=
_resolve_review_segment
(
payload
)
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."
,
)
ruleset_id
=
payload
.
ruleset_id
or
rules_reference_tool
.
default_ruleset_id
ruleset_id
=
payload
.
ruleset_id
or
rules_reference_tool
.
default_ruleset_id
rules
=
rules_reference_tool
.
run
(
ruleset_id
=
ruleset_id
)
.
get
(
"rules"
,
[])
rules
=
rules_reference_tool
.
run
(
ruleset_id
=
ruleset_id
)
.
get
(
"rules"
,
[])
...
...
utils/spire_word_util.py
View file @
dce41c59
...
@@ -4,7 +4,7 @@ import re
...
@@ -4,7 +4,7 @@ import re
from
thefuzz
import
fuzz
from
thefuzz
import
fuzz
from
utils.doc_util
import
DocBase
from
utils.doc_util
import
DocBase
from
utils.common_util
import
adjust_single_chunk_size
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
import
os
...
@@ -553,6 +553,22 @@ class SpireWordDoc(DocBase):
...
@@ -553,6 +553,22 @@ class SpireWordDoc(DocBase):
for
loc
in
chunk_locations
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
):
def
format_comment_author
(
self
,
comment
):
return
"{}|{}"
.
format
(
str
(
comment
[
"id"
]),
comment
[
"key_points"
])
return
"{}|{}"
.
format
(
str
(
comment
[
"id"
]),
comment
[
"key_points"
])
...
@@ -820,14 +836,15 @@ class SpireWordDoc(DocBase):
...
@@ -820,14 +836,15 @@ class SpireWordDoc(DocBase):
for
comment
in
comments
:
for
comment
in
comments
:
if
comment
.
get
(
"result"
)
!=
"不合格"
:
if
comment
.
get
(
"result"
)
!=
"不合格"
:
continue
continue
# update chunk_id
comment_chunk_id
=
comment
.
get
(
"chunk_id"
)
comment_chunk_id
=
comment
.
get
(
"chunk_id"
,
-
1
)
# 优先使用 comment 中的 chunk_id;-1 表示全文;缺失或无效时回退到入参 chunk_id。
# 优先使用comments里提供的chunk_id,如果没有或无效则使用外部传入的chunk_id,如果都没有则异常处理
if
isinstance
(
comment_chunk_id
,
int
)
and
(
sub_chunks
=
(
comment_chunk_id
==
FULL_TEXT_SEGMENT_ID
self
.
get_sub_chunks
(
comment_chunk_id
)
or
0
<=
comment_chunk_id
<
self
.
get_chunk_num
()
if
comment_chunk_id
!=
-
1
and
comment_chunk_id
<
self
.
get_chunk_num
()
):
else
self
.
get_sub_chunks
(
chunk_id
)
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
)
author
=
self
.
format_comment_author
(
comment
)
suggest
=
comment
.
get
(
"suggest"
,
""
)
suggest
=
comment
.
get
(
"suggest"
,
""
)
original_text
=
(
comment
.
get
(
"original_text"
)
or
""
)
.
strip
()
original_text
=
(
comment
.
get
(
"original_text"
)
or
""
)
.
strip
()
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment