Skill: tom859174-sketch/tesseract-ocr-skill (version 1.0.1)

--- name: tesseract-ocr-skill description: 基于Tesseract引擎的OCR文字识别技能，支持中文、英文、中英混合三种模式，输出text/structured/question_answer三种格式。 --- # Tesseract OCR Skill 使用 Tesseract 引擎从图像中提取文字内容。 ## 功能 - 支持中文（简体）、英文、中英混合三种语言模式 - 支持三种输出格式： - `text`: 纯文本输出 - `structured`: 结构化输出（识别题目、选项、答案） - `question_answer`: 问答对格式 ## 使用方式 ```bash python <skill-path>/tesseract_ocr_skill.py <image_path> --lang chi_sim+eng --format text ``` ## 参数 | 参数 | 说明 | 默认值 | |------|------|--------| | `image_path` | 图片文件路径 | 必填 | | `--lang` | 识别语言 | `chi_sim+eng` | | `--format` | 输出格式 | `text` | | `--output` | 输出文件路径 | 控制台输出 | ## 依赖 - Python 3.x - pytesseract - Pillow - Tesseract OCR 引擎（需单独安装） ## 安装 Tesseract Windows: 下载安装包 https://github.com/UB-Mannheim/tesseract/wiki

path: scripts/tesseract_ocr.py
content: import pytesseract
from PIL import Image
import re
from typing import Dict, Any

def extract_text_with_tesseract(image_path: str, language: str = "chi_sim+eng", output_format: str = "text") -> Dict[str, Any]:
    """
    使用Tesseract从图像中提取文字
    """
    try:
        # 打开图片
        img = Image.open(image_path)
        
        # 使用Tesseract进行OCR
        extracted_text = pytesseract.image_to_string(img, lang=language)
        
        result = {
            "original_text": extracted_text.strip(),
            "processed_text": "",
            "structure": None
        }
        
        if output_format == "text":
            result["processed_text"] = extracted_text.strip()
        elif output_format == "structured":
            # 尝试识别结构化信息
            structured = identify_structure(extracted_text)
            result["processed_text"] = structured["formatted_text"]
            result["structure"] = structured["structure"]
        elif output_format == "question_answer":
            # 专门识别问答题
            qa_result = identify_questions_and_answers(extracted_text)
            result["processed_text"] = qa_result["formatted_text"]
            result["structure"] = qa_result["qa_pairs"]
        
        return {
            "status": "success",
            "data": result
        }
    except Exception as e:
        return {
            "status": "error",
            "message": str(e)
        }

def identify_structure(text: str) -> Dict[str, Any]:
    """
    识别文本结构（题目、选项、答案等）
    """
    lines = text.split('\n')
    structure = {
        "sections": [],
        "questions": [],
        "answers": [],
        "options": []
    }
    
    current_section = ""
    current_question = ""
    current_options = []
    current_answer = ""
    
    for line in lines:
        line = line.strip()
        if not line:
            continue
            
        # 检查是否是章节标题（如"哮病"、"咳嗽"等）
        if re.search(r'(病|证|症|综合征)$', line):
            if current_section:
                structure["sections"].append(current_section)
            current_section = line
        # 检查是否是问题（数字+. 或者中文数字+、）
        elif re.match(r'^\d+[\.．、]', line) or re.match(r'^[一二三四五六七八九十\d]+[\.．、]', line):
            if current_question:
                # 保存上一个问题
                structure["questions"].append(current_question)
                if current_options:
                    structure["options"].append(current_options)
                if current_answer:
                    structure["answers"].append(current_answer)
                    
            current_question = line
            current_options = []
            current_answer = ""
        elif re.match(r'^[A-Z][\.．:：]', line) or re.match(r'^[（\(][A-Z][）\)]', line):
            # 检查是否是选项
            current_options.append(line)
        elif '答案' in line or '答：' in line or ('【' in line and '】' in line):
            # 检查是否是答案
            current_answer = line
        else:
            if current_question and not any(opt in line for opt in ['A.', 'B.', 'C.', 'D.', 'E.', 'F.']):
                # 添加到当前问题中
                current_question += '\n' + line
    
    # 添加最后一个
    if current_question:
        structure["questions"].append(current_question)
        if current_options:
            structure["options"].append(current_options)
        if current_answer:
            structure["answers"].append(current_answer)
    
    # 如果没有找到特定结构，返回原始文本
    if not structure["questions"] and not structure["sections"]:
        return {
            "formatted_text": text,
            "structure": {"raw_text": text}
        }
    
    # 格式化输出
    formatted_text = ""
    if structure["sections"]:
        for section in structure["sections"]:
            formatted_text += f"【{section}】\n"
    if structure["questions"]:
        for i, q in enumerate(structure["questions"]):
            formatted_text += f"题目{i+1}: {q}\n"
            if i < len(structure["options"]):
                for opt in structure["options"][i]:
                    formatted_text += f"  {opt}\n"
            if i < len(structure["answers"]):
                formatted_text += f"  答案: {structure['answers'][i]}\n"
            formatted_text += "\n"
    
    return {
        "formatted_text": formatted_text.strip(),
        "structure": structure
    }

def identify_questions_and_answers(text: str) -> Dict[str, Any]:
    """
    专门识别问题和答案
    """
    # 按段落分割文本
    paragraphs = [p.strip() for p in text.split('\n') if p.strip()]
    
    qa_pairs = []
    current_qa = {"question": "", "answer": ""}
    
    for para in paragraphs:
        # 检查是否是问题（以数字开头）
        if re.match(r'^\d+[\.．、]', para) or re.match(r'^[一二三四五六七八九十\d]+[\.．、]', para):
            if current_qa["question"]:
                # 保存上一个QA对
                qa_pairs.append(current_qa.copy())
            
            # 开始新问题
            current_qa = {"question": para, "answer": ""}
        elif '答案' in para or '答：' in para or ('【' in para and '】' in para):
            # 答案行
            current_qa["answer"] = para
        else:
            # 可能是问题的延续
            if current_qa["question"] and not current_qa["answer"]:
                current_qa["question"] += '\n' + para
            elif current_qa["answer"]:
                current_qa["answer"] += '\n' + para
    
    # 添加最后一个
    if current_qa["question"]:
        qa_pairs.append(current_qa)
    
    formatted_text = ""
    for i, pair in enumerate(qa_pairs):
        formatted_text += f"Q{i+1}: {pair['question']}\n"
        formatted_text += f"A{i+1}: {pair['answer']}\n\n"
    
    return {
        "formatted_text": formatted_text.strip(),
        "qa_pairs": qa_pairs
    }

def main(params: Dict[str, Any]) -> Dict[str, Any]:
    image_path = params.get("image_path")
    language = params.get("language", "chi_sim+eng")
    output_format = params.get("output_format", "text")
    
    return extract_text_with_tesseract(image_path, language, output_format)

def extract_text_with_tesseract(image_path: str, language: str = "chi_sim+eng", output_format: str = "text") -> Dict[str, Any]:
    """
    使用Tesseract从图像中提取文字
    """
    try:
        # 检查文件是否存在
        if not os.path.exists(image_path):
            return {
                "status": "error",
                "message": f"Image file does not exist: {image_path}"
            }
        
        # 打开图片
        img = Image.open(image_path)
        
        # 使用Tesseract进行OCR
        extracted_text = pytesseract.image_to_string(img, lang=language)
        
        result = {
            "original_text": extracted_text.strip(),
            "processed_text": "",
            "structure": None
        }
        
        if output_format == "text":
            result["processed_text"] = extracted_text.strip()
        elif output_format == "structured":
            # 尝试识别结构化信息
            structured = identify_structure(extracted_text)
            result["processed_text"] = structured["formatted_text"]
            result["structure"] = structured["structure"]
        elif output_format == "question_answer":
            # 专门识别问答题
            qa_result = identify_questions_and_answers(extracted_text)
            result["processed_text"] = qa_result["formatted_text"]
            result["structure"] = qa_result["qa_pairs"]
        
        return {
            "status": "success",
            "data": result
        }
    except Exception as e:
        return {
            "status": "error",
            "message": str(e)
        }

path: SKILL.json
content: {
  "name": "tesseract-ocr-skill",
  "version": "1.0.0",
  "description": "基于Tesseract引擎的OCR技能，专门用于处理中医教材截图",
  "author": "仁风助手",
  "skills": [
    {
      "id": "tesseract_ocr_extraction",
      "name": "Tesseract OCR Extraction",
      "description": "使用Tesseract引擎从图像中提取文字内容",
      "parameters": {
        "type": "object",
        "properties": {
          "image_path": {
            "type": "string",
            "description": "图像文件路径"
          },
          "language": {
            "type": "string",
            "enum": ["chi_sim", "eng", "chi_sim+eng"],
            "default": "chi_sim+eng",
            "description": "识别语言：简体中文、英文、中英混合"
          },
          "output_format": {
            "type": "string",
            "enum": ["text", "structured", "question_answer"],
            "default": "text",
            "description": "输出格式"
          }
        },
        "required": ["image_path"]
      },
      "implementation": {
        "type": "script",
        "engine": "python",
        "path": "./scripts/tesseract_ocr.py"
      }
    }
  ]
}

path: tesseract_ocr_skill.py
content: #!/usr/bin/env python3
"""
Tesseract OCR Skill for OpenClaw
专门用于处理中医教材截图的OCR技能
"""

import argparse
import json
import sys
from pathlib import Path

# 添加脚本路径到系统路径
script_dir = Path(__file__).parent
sys.path.insert(0, str(script_dir))

from .scripts.tesseract_ocr import main as tesseract_main

def cli_main():
    parser = argparse.ArgumentParser(description='Tesseract OCR Skill for TCM Materials')
    parser.add_argument('image_path', help='Path to the image file')
    parser.add_argument('--lang', choices=['chi_sim', 'eng', 'chi_sim+eng'], 
                       default='chi_sim+eng', help='Recognition language')
    parser.add_argument('--format', choices=['text', 'structured', 'question_answer'], 
                       default='text', help='Output format')
    parser.add_argument('--output', '-o', help='Output file path')
    
    args = parser.parse_args()
    
    params = {
        "image_path": args.image_path,
        "language": args.lang,
        "output_format": args.format
    }
    
    result = tesseract_main(params)
    
    if args.output:
        with open(args.output, 'w', encoding='utf-8') as f:
            json.dump(result, f, ensure_ascii=False, indent=2)
        print(f"Result saved to {args.output}")
    else:
        print(json.dumps(result, ensure_ascii=False, indent=2))

if __name__ == "__main__":
    cli_main()

Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (MEDIUM)