97e91a83f3
Ruff / Ruff (push) Waiting to run
Test / Core Tests (push) Waiting to run
Test / Offline Coverage Tests (Python 3.10) (push) Waiting to run
Test / Offline Coverage Tests (Python 3.11) (push) Waiting to run
Test / Offline Coverage Tests (Python 3.12) (push) Waiting to run
Test / Offline Coverage Tests (Python 3.13) (push) Waiting to run
Test / Offline Coverage Tests (Python 3.9) (push) Waiting to run
Test / Full Coverage (Python 3.11) (push) Waiting to run
Test / Core Provider Tests (OpenAI) (push) Blocked by required conditions
Test / Core Provider Tests (Anthropic) (push) Blocked by required conditions
Test / Core Provider Tests (Google) (push) Blocked by required conditions
Test / Core Provider Tests (Other) (push) Blocked by required conditions
Test / Anthropic Tests (push) Blocked by required conditions
Test / Gemini Tests (push) Blocked by required conditions
Test / Google GenAI Tests (push) Blocked by required conditions
Test / Vertex AI Tests (push) Blocked by required conditions
Test / OpenAI Tests (push) Blocked by required conditions
Test / Writer Tests (push) Blocked by required conditions
Test / Auto Client Tests (push) Blocked by required conditions
ty / type-check (push) Waiting to run
272 lines
8.0 KiB
Python
Executable File
272 lines
8.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Fix old client initialization patterns in documentation files.
|
|
|
|
Replaces old initialization patterns with from_provider:
|
|
- instructor.from_openai(OpenAI()) → instructor.from_provider("openai/model-name")
|
|
- instructor.from_anthropic(Anthropic()) → instructor.from_provider("anthropic/model-name")
|
|
- instructor.patch(OpenAI()) → instructor.from_provider("openai/model-name")
|
|
- Similar patterns for all other providers
|
|
"""
|
|
|
|
import argparse
|
|
import re
|
|
from pathlib import Path
|
|
from typing import List, Tuple
|
|
|
|
|
|
# Mapping of provider names to their from_provider identifiers
|
|
PROVIDER_MAPPING = {
|
|
"openai": "openai",
|
|
"anthropic": "anthropic",
|
|
"google": "google",
|
|
"cohere": "cohere",
|
|
"mistral": "mistral",
|
|
"groq": "groq",
|
|
"litellm": "litellm",
|
|
"ollama": "ollama",
|
|
"azure": "azure",
|
|
"bedrock": "bedrock",
|
|
"vertex": "vertex",
|
|
"genai": "google", # Google GenAI
|
|
"deepseek": "deepseek",
|
|
"fireworks": "fireworks",
|
|
"cerebras": "cerebras",
|
|
"together": "together",
|
|
"anyscale": "anyscale",
|
|
"perplexity": "perplexity",
|
|
"writer": "writer",
|
|
"openrouter": "openrouter",
|
|
"sambanova": "sambanova",
|
|
"truefoundry": "truefoundry",
|
|
"cortex": "cortex",
|
|
"databricks": "databricks",
|
|
"xai": "xai",
|
|
}
|
|
|
|
|
|
def find_markdown_files(docs_dir: Path) -> List[Path]:
|
|
"""Find all markdown files in the docs directory."""
|
|
return list(docs_dir.rglob("*.md")) + list(docs_dir.rglob("*.ipynb"))
|
|
|
|
|
|
def extract_model_name(content: str, match_start: int, match_end: int) -> str:
|
|
"""
|
|
Try to extract model name from context around the match.
|
|
Looks for common patterns like model="...", model='...', or model_name=...
|
|
"""
|
|
# Look backwards and forwards for model parameter
|
|
context_start = max(0, match_start - 200)
|
|
context_end = min(len(content), match_end + 200)
|
|
context = content[context_start:context_end]
|
|
|
|
# Try to find model parameter
|
|
model_match = re.search(
|
|
r'model\s*[=:]\s*["\']([^"\']+)["\']', context, re.IGNORECASE
|
|
)
|
|
if model_match:
|
|
return model_match.group(1)
|
|
|
|
# Default model names by provider
|
|
return "gpt-4o" # Will need manual review for accuracy
|
|
|
|
|
|
def replace_from_pattern(
|
|
content: str, provider: str, dry_run: bool = False
|
|
) -> Tuple[str, int]:
|
|
"""
|
|
Replace instructor.from_PROVIDER(Provider()) patterns.
|
|
|
|
Pattern: instructor.from_openai(OpenAI(model="..."))
|
|
→ instructor.from_provider("openai/model-name")
|
|
"""
|
|
replacements = 0
|
|
|
|
# Pattern: instructor.from_PROVIDER(ProviderClass(...))
|
|
pattern = rf"instructor\.from_{provider}\((\w+)(\([^)]*\))?\)"
|
|
|
|
def replacer(match):
|
|
nonlocal replacements
|
|
provider_class = match.group(1)
|
|
args = match.group(2) or ""
|
|
|
|
# Try to extract model name from args
|
|
model_match = re.search(r'model\s*=\s*["\']([^"\']+)["\']', args)
|
|
if model_match:
|
|
model_name = model_match.group(1)
|
|
else:
|
|
# Default model - may need manual review
|
|
model_name = (
|
|
"gpt-4o" if provider == "openai" else "claude-3-5-sonnet-20241022"
|
|
)
|
|
|
|
replacements += 1
|
|
return f'instructor.from_provider("{provider}/{model_name}")'
|
|
|
|
new_content = re.sub(pattern, replacer, content, flags=re.IGNORECASE)
|
|
return new_content, replacements
|
|
|
|
|
|
def replace_patch_pattern(content: str, dry_run: bool = False) -> Tuple[str, int]:
|
|
"""
|
|
Replace instructor.patch(Provider()) patterns.
|
|
|
|
Pattern: instructor.patch(OpenAI(model="..."))
|
|
→ instructor.from_provider("openai/model-name")
|
|
"""
|
|
replacements = 0
|
|
|
|
# Pattern: instructor.patch(ProviderClass(...))
|
|
# Match common provider classes
|
|
provider_classes = "|".join(
|
|
[
|
|
"OpenAI",
|
|
"Anthropic",
|
|
"GoogleGenerativeAI",
|
|
"Cohere",
|
|
"Mistral",
|
|
"Groq",
|
|
"LiteLLM",
|
|
"Ollama",
|
|
"Bedrock",
|
|
"VertexAI",
|
|
]
|
|
)
|
|
|
|
pattern = rf"instructor\.patch\(({provider_classes})(\([^)]*\))?\)"
|
|
|
|
def replacer(match):
|
|
nonlocal replacements
|
|
provider_class = match.group(1)
|
|
args = match.group(2) or ""
|
|
|
|
# Map class name to provider identifier
|
|
class_to_provider = {
|
|
"OpenAI": "openai",
|
|
"Anthropic": "anthropic",
|
|
"GoogleGenerativeAI": "google",
|
|
"Cohere": "cohere",
|
|
"Mistral": "mistral",
|
|
"Groq": "groq",
|
|
"LiteLLM": "litellm",
|
|
"Ollama": "ollama",
|
|
"Bedrock": "bedrock",
|
|
"VertexAI": "vertex",
|
|
}
|
|
|
|
provider = class_to_provider.get(provider_class, "openai")
|
|
|
|
# Try to extract model name from args
|
|
model_match = re.search(r'model\s*=\s*["\']([^"\']+)["\']', args)
|
|
if model_match:
|
|
model_name = model_match.group(1)
|
|
else:
|
|
# Default models
|
|
defaults = {
|
|
"openai": "gpt-4o",
|
|
"anthropic": "claude-3-5-sonnet-20241022",
|
|
"google": "gemini-1.5-pro",
|
|
}
|
|
model_name = defaults.get(provider, "gpt-4o")
|
|
|
|
replacements += 1
|
|
return f'instructor.from_provider("{provider}/{model_name}")'
|
|
|
|
new_content = re.sub(pattern, replacer, content)
|
|
return new_content, replacements
|
|
|
|
|
|
def replace_old_patterns(content: str, dry_run: bool = False) -> Tuple[str, int]:
|
|
"""
|
|
Replace all old initialization patterns.
|
|
|
|
Returns:
|
|
Tuple of (new_content, total_replacements)
|
|
"""
|
|
total_replacements = 0
|
|
new_content = content
|
|
|
|
# Replace instructor.patch() patterns first
|
|
new_content, patch_replacements = replace_patch_pattern(new_content, dry_run)
|
|
total_replacements += patch_replacements
|
|
|
|
# Replace instructor.from_* patterns for each provider
|
|
for provider in PROVIDER_MAPPING.keys():
|
|
new_content, from_replacements = replace_from_pattern(
|
|
new_content, provider, dry_run
|
|
)
|
|
total_replacements += from_replacements
|
|
|
|
return new_content, total_replacements
|
|
|
|
|
|
def process_file(file_path: Path, dry_run: bool = False) -> int:
|
|
"""Process a single file and return number of replacements."""
|
|
try:
|
|
content = file_path.read_text(encoding="utf-8")
|
|
new_content, replacements = replace_old_patterns(content, dry_run)
|
|
|
|
if replacements > 0:
|
|
if dry_run:
|
|
print(f"Would fix {replacements} instances in {file_path}")
|
|
else:
|
|
file_path.write_text(new_content, encoding="utf-8")
|
|
print(f"Fixed {replacements} instances in {file_path}")
|
|
|
|
return replacements
|
|
except Exception as e:
|
|
print(f"Error processing {file_path}: {e}")
|
|
return 0
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="Replace old client initialization patterns with from_provider"
|
|
)
|
|
parser.add_argument(
|
|
"--docs-dir",
|
|
type=Path,
|
|
default=Path("docs"),
|
|
help="Directory containing documentation files (default: docs)",
|
|
)
|
|
parser.add_argument(
|
|
"--dry-run",
|
|
action="store_true",
|
|
help="Show what would be changed without making changes",
|
|
)
|
|
parser.add_argument(
|
|
"--file",
|
|
type=Path,
|
|
help="Process a single file instead of all files",
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
if args.file:
|
|
files = [args.file]
|
|
else:
|
|
files = find_markdown_files(args.docs_dir)
|
|
|
|
total_replacements = 0
|
|
files_modified = 0
|
|
|
|
for file_path in files:
|
|
replacements = process_file(file_path, args.dry_run)
|
|
if replacements > 0:
|
|
total_replacements += replacements
|
|
files_modified += 1
|
|
|
|
print(f"\nSummary:")
|
|
print(f" Files processed: {len(files)}")
|
|
print(f" Files modified: {files_modified}")
|
|
print(f" Total replacements: {total_replacements}")
|
|
|
|
if args.dry_run:
|
|
print("\nRun without --dry-run to apply changes")
|
|
else:
|
|
print("\n⚠️ Note: Please review model names - defaults may need adjustment")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|