Files
claude-code-skills-reference/transcript-fixer/scripts/core/ai_processor.py
daymade bd0aa12004 Release v1.8.0: Add transcript-fixer skill
## New Skill: transcript-fixer v1.0.0

Correct speech-to-text (ASR/STT) transcription errors through dictionary-based rules and AI-powered corrections with automatic pattern learning.

**Features:**
- Two-stage correction pipeline (dictionary + AI)
- Automatic pattern detection and learning
- Domain-specific dictionaries (general, embodied_ai, finance, medical)
- SQLite-based correction repository
- Team collaboration with import/export
- GLM API integration for AI corrections
- Cost optimization through dictionary promotion

**Use cases:**
- Correcting meeting notes, lecture recordings, or interview transcripts
- Fixing Chinese/English homophone errors and technical terminology
- Building domain-specific correction dictionaries
- Improving transcript accuracy through iterative learning

**Documentation:**
- Complete workflow guides in references/
- SQL query templates
- Troubleshooting guide
- Team collaboration patterns
- API setup instructions

**Marketplace updates:**
- Updated marketplace to v1.8.0
- Added transcript-fixer plugin (category: productivity)
- Updated README.md with skill description and use cases
- Updated CLAUDE.md with skill listing and counts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-28 13:16:37 +08:00

215 lines
6.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
AI Processor - Stage 2: AI-powered Text Corrections
SINGLE RESPONSIBILITY: Process text using GLM API for intelligent corrections
Features:
- Split text into chunks for API processing
- Call GLM-4.6 for context-aware corrections
- Track AI-suggested changes
- Handle API errors gracefully
"""
from __future__ import annotations
import os
import re
from typing import List, Tuple
from dataclasses import dataclass
import httpx
@dataclass
class AIChange:
"""Represents an AI-suggested change"""
chunk_index: int
from_text: str
to_text: str
confidence: float # 0.0 to 1.0
class AIProcessor:
"""
Stage 2 Processor: AI-powered corrections using GLM-4.6
Process:
1. Split text into chunks (respecting API limits)
2. Send each chunk to GLM API
3. Track changes for learning engine
4. Preserve formatting and structure
"""
def __init__(self, api_key: str, model: str = "GLM-4.6",
base_url: str = "https://open.bigmodel.cn/api/anthropic",
fallback_model: str = "GLM-4.5-Air"):
"""
Initialize AI processor
Args:
api_key: GLM API key
model: Model name (default: GLM-4.6)
base_url: API base URL
fallback_model: Fallback model on primary failure
"""
self.api_key = api_key
self.model = model
self.fallback_model = fallback_model
self.base_url = base_url
self.max_chunk_size = 6000 # Characters per chunk
def process(self, text: str, context: str = "") -> Tuple[str, List[AIChange]]:
"""
Process text with AI corrections
Args:
text: Text to correct
context: Optional domain/meeting context
Returns:
(corrected_text, list_of_changes)
"""
chunks = self._split_into_chunks(text)
corrected_chunks = []
all_changes = []
print(f"📝 Processing {len(chunks)} chunks with {self.model}...")
for i, chunk in enumerate(chunks, 1):
print(f" Chunk {i}/{len(chunks)}... ", end="", flush=True)
try:
corrected_chunk = self._process_chunk(chunk, context, self.model)
corrected_chunks.append(corrected_chunk)
# TODO: Extract actual changes for learning
# For now, we assume the whole chunk changed
if corrected_chunk != chunk:
all_changes.append(AIChange(
chunk_index=i,
from_text=chunk[:50] + "...",
to_text=corrected_chunk[:50] + "...",
confidence=0.9 # Placeholder
))
print("")
except Exception as e:
print(f"{str(e)[:50]}")
# Retry with fallback model
if self.fallback_model and self.fallback_model != self.model:
print(f" Retrying with {self.fallback_model}... ", end="", flush=True)
try:
corrected_chunk = self._process_chunk(chunk, context, self.fallback_model)
corrected_chunks.append(corrected_chunk)
print("")
continue
except Exception as e2:
print(f"{str(e2)[:50]}")
print(" Using original text...")
corrected_chunks.append(chunk)
return "\n\n".join(corrected_chunks), all_changes
def _split_into_chunks(self, text: str) -> List[str]:
"""
Split text into processable chunks
Strategy:
- Split by double newlines (paragraphs)
- Keep chunks under max_chunk_size
- Don't split mid-paragraph if possible
"""
paragraphs = text.split('\n\n')
chunks = []
current_chunk = []
current_length = 0
for para in paragraphs:
para_length = len(para)
# If single paragraph exceeds limit, force split
if para_length > self.max_chunk_size:
if current_chunk:
chunks.append('\n\n'.join(current_chunk))
current_chunk = []
current_length = 0
# Split long paragraph by sentences
sentences = re.split(r'([。!?\n])', para)
temp_para = ""
for i in range(0, len(sentences), 2):
sentence = sentences[i] + (sentences[i+1] if i+1 < len(sentences) else "")
if len(temp_para) + len(sentence) > self.max_chunk_size:
if temp_para:
chunks.append(temp_para)
temp_para = sentence
else:
temp_para += sentence
if temp_para:
chunks.append(temp_para)
# Normal case: accumulate paragraphs
elif current_length + para_length > self.max_chunk_size and current_chunk:
chunks.append('\n\n'.join(current_chunk))
current_chunk = [para]
current_length = para_length
else:
current_chunk.append(para)
current_length += para_length + 2 # +2 for \n\n
if current_chunk:
chunks.append('\n\n'.join(current_chunk))
return chunks
def _process_chunk(self, chunk: str, context: str, model: str) -> str:
"""Process a single chunk with GLM API"""
prompt = self._build_prompt(chunk, context)
url = f"{self.base_url}/v1/messages"
headers = {
"anthropic-version": "2023-06-01",
"Authorization": f"Bearer {self.api_key}",
"content-type": "application/json"
}
data = {
"model": model,
"max_tokens": 8000,
"temperature": 0.3,
"messages": [{"role": "user", "content": prompt}]
}
with httpx.Client(timeout=60.0) as client:
response = client.post(url, headers=headers, json=data)
response.raise_for_status()
result = response.json()
return result["content"][0]["text"]
def _build_prompt(self, chunk: str, context: str) -> str:
"""Build correction prompt for GLM"""
base_prompt = """你是专业的会议记录校对专家。请修复以下会议转录中的语音识别错误。
**修复原则**
1. 严格保留原有格式时间戳、发言人标识、Markdown标记等
2. 修复明显的同音字错误
3. 修复专业术语错误
4. 修复语法错误,但保持口语化特征
5. 不确定的地方保持原样,不要过度修改
"""
if context:
base_prompt += f"\n**会议背景**\n{context}\n"
base_prompt += f"""
**需要修复的内容**
{chunk}
**请直接输出修复后的文本,不要添加任何解释或标注**"""
return base_prompt