diff --git a/test_accuracy_batch_full.py b/test_accuracy_batch_full.py
index 080ef30..ffb35d1 100644
--- a/test_accuracy_batch_full.py
+++ b/test_accuracy_batch_full.py
@@ -127,6 +127,7 @@ RESULTS_JSON = Path(r"src/test/resources/data/results.json")
OUTPUT_DIR = Path("test_reports_full")
BATCH_SIZE = 20
SIMILARITY_THRESHOLD = 85.0
+ACCEPTABLE_THRESHOLD = 60.0 # 相似度阈值,用于判断"acceptable"级别的匹配
# OCR Model Configuration
# Options: "ppocr_v5" (default), "paddleocr_vl"
@@ -1594,6 +1595,8 @@ def classify_match(extracted: Optional[str], expected: str, field_type: str = 'd
match_type = 'exact'
elif similarity >= SIMILARITY_THRESHOLD:
match_type = 'partial'
+ elif similarity >= ACCEPTABLE_THRESHOLD:
+ match_type = 'acceptable'
else:
match_type = 'no_match'
@@ -1883,8 +1886,8 @@ def generate_individual_report(result: Dict[str, Any], output_dir: Path):
total_time = result['performance']['total_time']
# Colors
- cma_color = '#4caf50' if cma_match == 'exact' else '#ff9800' if cma_match == 'partial' else '#f44336'
- inst_color = '#4caf50' if inst_match == 'exact' else '#ff9800' if inst_match == 'partial' else '#f44336'
+ cma_color = '#4caf50' if cma_match == 'exact' else '#ff9800' if cma_match == 'partial' else '#2196f3' if cma_match == 'acceptable' else '#f44336'
+ inst_color = '#4caf50' if inst_match == 'exact' else '#ff9800' if inst_match == 'partial' else '#2196f3' if inst_match == 'acceptable' else '#f44336'
# Build seals HTML
seals_html = ""
@@ -2025,11 +2028,13 @@ def generate_summary_report(all_results: List[Dict[str, Any]], output_dir: Path)
cma_exact = sum(1 for r in valid_cma if r['comparison']['cma'].get('match_type') == 'exact')
cma_partial = sum(1 for r in valid_cma if r['comparison']['cma'].get('match_type') == 'partial')
- cma_no = len(valid_cma) - cma_exact - cma_partial
+ cma_acceptable = sum(1 for r in valid_cma if r['comparison']['cma'].get('match_type') == 'acceptable')
+ cma_no = len(valid_cma) - cma_exact - cma_partial - cma_acceptable
inst_exact = sum(1 for r in valid_inst if r['comparison']['institution'].get('match_type') == 'exact')
inst_partial = sum(1 for r in valid_inst if r['comparison']['institution'].get('match_type') == 'partial')
- inst_no = len(valid_inst) - inst_exact - inst_partial
+ inst_acceptable = sum(1 for r in valid_inst if r['comparison']['institution'].get('match_type') == 'acceptable')
+ inst_no = len(valid_inst) - inst_exact - inst_partial - inst_acceptable
cma_acc = (cma_exact / len(valid_cma) * 100) if valid_cma else 0
inst_acc = (inst_exact / len(valid_inst) * 100) if valid_inst else 0
@@ -2045,7 +2050,7 @@ def generate_summary_report(all_results: List[Dict[str, Any]], output_dir: Path)
body {{ font-family: 'Segoe UI', sans-serif; margin: 0; padding: 20px; background: #f5f5f5; }}
.container {{ max-width: 1400px; margin: 0 auto; background: white; padding: 30px; border-radius: 8px; }}
h1 {{ color: #333; }}
- .summary {{ display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; margin: 20px 0; }}
+ .summary {{ display: grid; grid-template-columns: repeat(5, 1fr); gap: 15px; margin: 20px 0; }}
.summary-card {{ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 20px; border-radius: 8px; color: white; text-align: center; }}
.summary-card .label {{ font-size: 14px; opacity: 0.9; }}
.summary-card .value {{ font-size: 32px; font-weight: bold; }}
@@ -2069,11 +2074,15 @@ def generate_summary_report(all_results: List[Dict[str, Any]], output_dir: Path)
Partial Match
{cma_partial}/{len(valid_cma)}
+
+
Acceptable
+
{cma_acceptable}/{len(valid_cma)}
+
No Match
{cma_no}/{len(valid_cma)}
-
+
@@ -2089,11 +2098,15 @@ def generate_summary_report(all_results: List[Dict[str, Any]], output_dir: Path)
Partial Match
{inst_partial}/{len(valid_inst)}
+
+
Acceptable
+
{inst_acceptable}/{len(valid_inst)}
+
No Match
{inst_no}/{len(valid_inst)}
-
+
@@ -2120,8 +2133,8 @@ def generate_summary_report(all_results: List[Dict[str, Any]], output_dir: Path)
"""
for r in all_results:
- cma_symbol = {'exact': '[OK]', 'partial': '[PARTIAL]', 'no_match': '[FAIL]'}.get(r['comparison'].get('cma', {}).get('match_type', 'no_match'), '[?]')
- inst_symbol = {'exact': '[OK]', 'partial': '[PARTIAL]', 'no_match': '[FAIL]'}.get(r['comparison'].get('institution', {}).get('match_type', 'no_match'), '[?]')
+ cma_symbol = {'exact': '[OK]', 'partial': '[PARTIAL]', 'acceptable': '[ACCEPTABLE]', 'no_match': '[FAIL]'}.get(r['comparison'].get('cma', {}).get('match_type', 'no_match'), '[?]')
+ inst_symbol = {'exact': '[OK]', 'partial': '[PARTIAL]', 'acceptable': '[ACCEPTABLE]', 'no_match': '[FAIL]'}.get(r['comparison'].get('institution', {}).get('match_type', 'no_match'), '[?]')
seals_count = len(r['seal_results'])
html += f"""
@@ -2360,13 +2373,15 @@ def main():
valid_cma = [r for r in all_results if r['expected']['cma'] not in ['无', None]]
cma_exact = sum(1 for r in valid_cma if r['comparison']['cma'].get('match_type') == 'exact')
cma_partial = sum(1 for r in valid_cma if r['comparison']['cma'].get('match_type') == 'partial')
- cma_no = len(valid_cma) - cma_exact - cma_partial
+ cma_acceptable = sum(1 for r in valid_cma if r['comparison']['cma'].get('match_type') == 'acceptable')
+ cma_no = len(valid_cma) - cma_exact - cma_partial - cma_acceptable
cma_acc = (cma_exact / len(valid_cma) * 100) if valid_cma else 0
valid_inst = [r for r in all_results if r['expected']['institution'] not in ['无', None] and r['extracted']['institution']]
inst_exact = sum(1 for r in valid_inst if r['comparison']['institution'].get('match_type') == 'exact')
inst_partial = sum(1 for r in valid_inst if r['comparison']['institution'].get('match_type') == 'partial')
- inst_no = len(valid_inst) - inst_exact - inst_partial
+ inst_acceptable = sum(1 for r in valid_inst if r['comparison']['institution'].get('match_type') == 'acceptable')
+ inst_no = len(valid_inst) - inst_exact - inst_partial - inst_acceptable
inst_acc = (inst_exact / len(valid_inst) * 100) if valid_inst else 0
# Generate summary report
@@ -2380,12 +2395,14 @@ def main():
'cma': {
'exact': cma_exact,
'partial': cma_partial,
+ 'acceptable': cma_acceptable,
'no_match': cma_no,
'accuracy': cma_acc / 100
},
'institution': {
'exact': inst_exact,
'partial': inst_partial,
+ 'acceptable': inst_acceptable,
'no_match': inst_no,
'accuracy': inst_acc / 100
},
@@ -2406,12 +2423,14 @@ def main():
print("CMA Code Results:")
print(f" Exact Match: {cma_exact}/{len(valid_cma)} ({cma_exact/len(valid_cma)*100:.1f}%)")
print(f" Partial Match: {cma_partial}/{len(valid_cma)} ({cma_partial/len(valid_cma)*100:.1f}%)")
+ print(f" Acceptable Match: {cma_acceptable}/{len(valid_cma)} ({cma_acceptable/len(valid_cma)*100:.1f}%)")
print(f" No Match: {cma_no}/{len(valid_cma)} ({cma_no/len(valid_cma)*100:.1f}%)")
print(f" ** CMA Accuracy: {cma_acc:.1f}% **")
print()
print("Institution Name Results:")
print(f" Exact Match: {inst_exact}/{len(valid_inst)} ({inst_exact/len(valid_inst)*100:.1f}%)")
print(f" Partial Match: {inst_partial}/{len(valid_inst)} ({inst_partial/len(valid_inst)*100:.1f}%)")
+ print(f" Acceptable Match: {inst_acceptable}/{len(valid_inst)} ({inst_acceptable/len(valid_inst)*100:.1f}%)")
print(f" No Match: {inst_no}/{len(valid_inst)} ({inst_no/len(valid_inst)*100:.1f}%)")
print(f" ** Institution Accuracy: {inst_acc:.1f}% **")
print()