revert: reset to 32bee87 for clean text_bbox baseline

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
DocAuditAI Dev
2026-03-23 18:13:59 +08:00
parent 6563686bb3
commit ebcaf05625
10 changed files with 100 additions and 228 deletions
@@ -93,32 +93,6 @@ export interface CharPosition {
score: number; // OCR识别置信度
}
/**
* text_bbox -> CharPosition[] 转换
* GraphRAG 抽取结果只有 text_bbox (段落级坐标), 没有 char_positions (字符级坐标)。
* 将 text_bbox 转为单个 CharPosition 矩形框, 让 PdfPreview 的高亮逻辑复用。
*/
function resolveCharPositions(data: any): CharPosition[] | undefined {
// 优先用 char_positions
if (data?.char_positions && data.char_positions.length > 0) {
return data.char_positions;
}
// fallback: text_bbox -> CharPosition[]
if (data?.text_bbox) {
const b = data.text_bbox;
if (b.x_min != null && b.y_min != null && b.x_max != null && b.y_max != null
&& (b.x_max - b.x_min) > 0 && (b.y_max - b.y_min) > 0) {
return [{
box: [[b.x_min, b.y_min], [b.x_max, b.y_min], [b.x_max, b.y_max], [b.x_min, b.y_max]],
char: '',
score: 1
}];
}
}
return undefined;
}
/**
* 评查点类型定义
* 用于展示单个评查结果
@@ -1538,7 +1512,7 @@ export function ReviewPointsList({
for (const item of chain) {
if (item.data.page && typeof onReviewPointSelect === 'function') {
hasPage = true;
onReviewPointSelect(reviewPoint.id, Number(item.data.page), resolveCharPositions(item.data), item.data.value);
onReviewPointSelect(reviewPoint.id, Number(item.data.page), item.data.char_positions, item.data.value);
break;
}
}
@@ -1552,7 +1526,7 @@ export function ReviewPointsList({
// 遍历chain找到第一个有效的page
for (const item of chain) {
if (item.data.page && typeof onReviewPointSelect === 'function') {
onReviewPointSelect(reviewPoint.id, Number(item.data.page), resolveCharPositions(item.data), item.data.value);
onReviewPointSelect(reviewPoint.id, Number(item.data.page), item.data.char_positions, item.data.value);
break;
}
}
@@ -1592,11 +1566,11 @@ export function ReviewPointsList({
// 假设onReviewPointSelect在作用域内可用
const reviewPointId = reviewPoint.id as string;
if (reviewPointId && typeof onReviewPointSelect === 'function') {
onReviewPointSelect(reviewPointId, Number(item.data.page), resolveCharPositions(item.data), item.data.value);
onReviewPointSelect(reviewPointId, Number(item.data.page), item.data.char_positions, item.data.value);
}
}
else if(reviewPoint.contentPage && reviewPoint.contentPage[item.field]){
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[item.field]), resolveCharPositions(item.data), item.data.value);
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[item.field]), item.data.char_positions, item.data.value);
}
else{
toastService.error(`没有找到${item.field}对应的索引内容`);
@@ -1675,11 +1649,11 @@ export function ReviewPointsList({
if (chain[0].data.page) {
const reviewPointId = reviewPoint.id as string;
if (reviewPointId && typeof onReviewPointSelect === 'function') {
onReviewPointSelect(reviewPointId, chain[0].data.page, resolveCharPositions(chain[0].data), chain[0].data.value);
onReviewPointSelect(reviewPointId, chain[0].data.page, chain[0].data.char_positions, chain[0].data.value);
}
}
else if(reviewPoint.contentPage && reviewPoint.contentPage[chain[0].field]){
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[chain[0].field]), resolveCharPositions(chain[0].data), chain[0].data.value);
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[chain[0].field]), chain[0].data.char_positions, chain[0].data.value);
}
else{
toastService.error(`没有找到${chain[0].field}对应的索引内容`);
@@ -1701,11 +1675,11 @@ export function ReviewPointsList({
if (chain[1].data.page) {
const reviewPointId = reviewPoint.id as string;
if (reviewPointId && typeof onReviewPointSelect === 'function') {
onReviewPointSelect(reviewPointId, chain[1].data.page, resolveCharPositions(chain[1].data), chain[1].data.value);
onReviewPointSelect(reviewPointId, chain[1].data.page, chain[1].data.char_positions, chain[1].data.value);
}
}
else if(reviewPoint.contentPage && reviewPoint.contentPage[chain[1].field]){
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[chain[1].field]), resolveCharPositions(chain[1].data), chain[1].data.value);
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[chain[1].field]), chain[1].data.char_positions, chain[1].data.value);
}
else{
toastService.error(`没有找到${chain[1].field}对应的索引内容`);
@@ -1841,9 +1815,9 @@ export function ReviewPointsList({
onClick={(e) => {
e.stopPropagation();
if (mainTypeValue.page && typeof onReviewPointSelect === 'function') {
onReviewPointSelect(reviewPoint.id, Number(mainTypeValue.page), resolveCharPositions(mainTypeValue), mainTypeValue.value);
onReviewPointSelect(reviewPoint.id, Number(mainTypeValue.page), mainTypeValue.char_positions, mainTypeValue.value);
}else if(reviewPoint.contentPage && reviewPoint.contentPage[fieldKey]){
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[fieldKey]), resolveCharPositions(mainTypeValue), mainTypeValue.value);
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[fieldKey]), mainTypeValue.char_positions, mainTypeValue.value);
}else{
toastService.error(`没有找到${fieldKey}对应的索引内容`);
}
@@ -1852,9 +1826,9 @@ export function ReviewPointsList({
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
if (mainTypeValue.page && typeof onReviewPointSelect === 'function') {
onReviewPointSelect(reviewPoint.id, Number(mainTypeValue.page), resolveCharPositions(mainTypeValue), mainTypeValue.value);
onReviewPointSelect(reviewPoint.id, Number(mainTypeValue.page), mainTypeValue.char_positions, mainTypeValue.value);
}else if(reviewPoint.contentPage && reviewPoint.contentPage[fieldKey]){
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[fieldKey]), resolveCharPositions(mainTypeValue), mainTypeValue.value);
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[fieldKey]), mainTypeValue.char_positions, mainTypeValue.value);
}else{
toastService.error(`没有找到${fieldKey}对应的索引内容`);
}
@@ -1922,7 +1896,6 @@ export function ReviewPointsList({
fields?: Record<string, {
page: number | string;
value: string;
res: boolean;
char_positions?: CharPosition[];
}>;
ai_suggestion?: {
@@ -1981,14 +1954,14 @@ export function ReviewPointsList({
<button
key={`field-${index}`}
className={`border border-gray w-full
rounded-md overflow-hidden mb-2 ${value.res ? 'bg-[rgba(246,255,237,1)]' : 'bg-[rgba(255,251,230,1)]'} flex
hover:shadow-[0_0_10px_rgba(0,0,0,0.1)] ${value.res ? 'hover:bg-[rgba(0,128,0,0.1)]' : 'hover:bg-[rgba(255,255,0,0.1)]'}`}
rounded-md overflow-hidden mb-2 ${res ? 'bg-[rgba(246,255,237,1)]' : 'bg-[rgba(255,251,230,1)]'} flex
hover:shadow-[0_0_10px_rgba(0,0,0,0.1)] ${res ? 'hover:bg-[rgba(0,128,0,0.1)]' : 'hover:bg-[rgba(255,255,0,0.1)]'}`}
onClick={(e) => {
e.stopPropagation();
if (value.page && typeof onReviewPointSelect === 'function') {
onReviewPointSelect(reviewPoint.id, Number(value.page), resolveCharPositions(value), value.value);
onReviewPointSelect(reviewPoint.id, Number(value.page), value.char_positions, value.value);
}else if(reviewPoint.contentPage && reviewPoint.contentPage[key]){
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[key]), resolveCharPositions(value), value.value);
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[key]), value.char_positions, value.value);
}else{
toastService.error(`没有找到${key}对应的索引内容`);
}
@@ -1998,9 +1971,9 @@ export function ReviewPointsList({
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
if (value.page && typeof onReviewPointSelect === 'function') {
onReviewPointSelect(reviewPoint.id, Number(value.page), resolveCharPositions(value), value.value);
onReviewPointSelect(reviewPoint.id, Number(value.page), value.char_positions, value.value);
}else if(reviewPoint.contentPage && reviewPoint.contentPage[key]){
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[key]), resolveCharPositions(value), value.value);
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[key]), value.char_positions, value.value);
}else{
toastService.error(`没有找到${key}对应的索引内容`);
}
@@ -2031,7 +2004,7 @@ export function ReviewPointsList({
)}
</div>
<div className={`w-8 flex items-center justify-center rounded-r-md group relative`}>
{value.res ? (
{res ? (
<i className="ri-check-line text-success text-base hover:text-green-800" ></i>
) : (
<i className="ri-alert-line text-warning text-base hover:text-yellow-800" ></i>
@@ -2048,7 +2021,7 @@ export function ReviewPointsList({
<div className={`rounded-md flex flex-row items-center`}>
<div className="text-xs text-gray-600 pl-1 whitespace-nowrap">:</div>
<div className={`p-1 text-xs rounded-full min-w-[50px] text-center`}>
{ value.res ? '通过' : '不通过'}
{res ? '通过' : '不通过'}
</div>
</div>
</div>
@@ -2717,10 +2690,7 @@ export function ReviewPointsList({
{/* <div className='flex flex-col'> */}
<div className="flex items-center gap-2 max-w-[75%]">
<div className="review-point-title text-left text-blue-500 break-all">{reviewPoint.pointName}</div>
{ reviewPoint.pointName === '签署乙方详细信息校验' && (() => {
const firstContentKey = reviewPoint.content ? Object.keys(reviewPoint.content)[0] : undefined;
const firstContentValue = firstContentKey ? reviewPoint.content![firstContentKey]?.value : undefined;
return (
{ reviewPoint.pointName === '签署乙方详细信息校验' && (
<button
className="enterprise-info-btn"
style={{
@@ -2733,25 +2703,27 @@ export function ReviewPointsList({
flexShrink: 0,
transition: 'all 0.2s',
border: 'none',
cursor: firstContentValue ? 'pointer' : 'not-allowed',
backgroundColor: firstContentValue ? '#00684a' : '#e5e7eb',
color: firstContentValue ? '#ffffff' : '#9ca3af',
cursor: reviewPoint.content?.['合同主体信息-乙方名称']?.value ? 'pointer' : 'not-allowed',
backgroundColor: reviewPoint.content?.['合同主体信息-乙方名称']?.value ? '#00684a' : '#e5e7eb',
color: reviewPoint.content?.['合同主体信息-乙方名称']?.value ? '#ffffff' : '#9ca3af',
}}
disabled={!firstContentValue}
disabled={!reviewPoint.content?.['合同主体信息-乙方名称']?.value}
onClick={(e) => {
e.stopPropagation();
const companyName = typeof firstContentValue === 'string' ? firstContentValue : String(firstContentValue || '');
const companyNameValue = reviewPoint.content?.['合同主体信息-乙方名称']?.value;
// console.log('companyNameValue', companyNameValue);
const companyName = typeof companyNameValue === 'string' ? companyNameValue : String(companyNameValue || '');
if (companyName) {
handleCorporateInfoClick(companyName);
}
}}
onMouseEnter={(e) => {
if (firstContentValue) {
if (reviewPoint.content?.['合同主体信息-乙方名称']?.value) {
e.currentTarget.style.backgroundColor = '#005a3f';
}
}}
onMouseLeave={(e) => {
if (firstContentValue) {
if (reviewPoint.content?.['合同主体信息-乙方名称']?.value) {
e.currentTarget.style.backgroundColor = '#00684a';
}
}}
@@ -2759,12 +2731,8 @@ export function ReviewPointsList({
<i className="ri-eye-line"></i>
</button>
);
})()}
{ reviewPoint.pointName === '签署甲方详细信息校验' && (() => {
const firstContentKey = reviewPoint.content ? Object.keys(reviewPoint.content)[0] : undefined;
const firstContentValue = firstContentKey ? reviewPoint.content![firstContentKey]?.value : undefined;
return (
)}
{ reviewPoint.pointName === '签署甲方详细信息校验' && (
<button
className="enterprise-info-btn"
style={{
@@ -2777,25 +2745,26 @@ export function ReviewPointsList({
flexShrink: 0,
transition: 'all 0.2s',
border: 'none',
cursor: firstContentValue ? 'pointer' : 'not-allowed',
backgroundColor: firstContentValue ? '#00684a' : '#e5e7eb',
color: firstContentValue ? '#ffffff' : '#9ca3af',
cursor: reviewPoint.content?.['合同主体信息-甲方名称']?.value ? 'pointer' : 'not-allowed',
backgroundColor: reviewPoint.content?.['合同主体信息-甲方名称']?.value ? '#00684a' : '#e5e7eb',
color: reviewPoint.content?.['合同主体信息-甲方名称']?.value ? '#ffffff' : '#9ca3af',
}}
disabled={!firstContentValue}
disabled={!reviewPoint.content?.['合同主体信息-甲方名称']?.value}
onClick={(e) => {
e.stopPropagation();
const companyName = typeof firstContentValue === 'string' ? firstContentValue : String(firstContentValue || '');
const companyNameValue = reviewPoint.content?.['合同主体信息-甲方名称']?.value;
const companyName = typeof companyNameValue === 'string' ? companyNameValue : String(companyNameValue || '');
if (companyName) {
handleCorporateInfoClick(companyName);
}
}}
onMouseEnter={(e) => {
if (firstContentValue) {
if (reviewPoint.content?.['合同主体信息-甲方名称']?.value) {
e.currentTarget.style.backgroundColor = '#005a3f';
}
}}
onMouseLeave={(e) => {
if (firstContentValue) {
if (reviewPoint.content?.['合同主体信息-甲方名称']?.value) {
e.currentTarget.style.backgroundColor = '#00684a';
}
}}
@@ -2803,8 +2772,7 @@ export function ReviewPointsList({
<i className="ri-eye-line"></i>
</button>
);
})()}
)}
</div>
{/* <div className="review-point-header flex justify-between items-start">
<div className="flex-1 text-left min-w-[25%] font-medium text-[13px]">{reviewPoint.title}</div>