Skip to content

LLM API Reference

This page documents the LLM enhancement modules of Medium Converter.

Configuration

medium_converter.llm.config.LLMConfig

Configuration for LLM integration.

from_env() classmethod

Create LLM config from environment variables.

RETURNS DESCRIPTION
LLMConfig

LLMConfig instance with values from environment

Source code in medium_converter/llm/config.py
@classmethod
def from_env(cls) -> "LLMConfig":
    """Create LLM config from environment variables.

    Returns:
        LLMConfig instance with values from environment
    """
    import os

    # Default to OpenAI if OPENAI_API_KEY is set
    if os.environ.get("OPENAI_API_KEY"):
        return cls(
            provider=LLMProvider.OPENAI,
            api_key=os.environ.get("OPENAI_API_KEY"),
            model=os.environ.get("OPENAI_MODEL", "gpt-3.5-turbo"),
        )

    # Check for Anthropic
    if os.environ.get("ANTHROPIC_API_KEY"):
        return cls(
            provider=LLMProvider.ANTHROPIC,
            api_key=os.environ.get("ANTHROPIC_API_KEY"),
            model=os.environ.get("ANTHROPIC_MODEL", "claude-3-sonnet-20240229"),
        )

    # Check for Google
    if os.environ.get("GOOGLE_API_KEY"):
        return cls(
            provider=LLMProvider.GOOGLE,
            api_key=os.environ.get("GOOGLE_API_KEY"),
            model=os.environ.get("GOOGLE_MODEL", "gemini-pro"),
        )

    # Check for Mistral
    if os.environ.get("MISTRAL_API_KEY"):
        return cls(
            provider=LLMProvider.MISTRAL,
            api_key=os.environ.get("MISTRAL_API_KEY"),
            model=os.environ.get("MISTRAL_MODEL", "mistral-medium"),
        )

    # Fallback to default
    return cls()

LLM Provider

medium_converter.llm.config.LLMProvider

Supported LLM providers.

Enhancer

medium_converter.llm.enhancer.enhance_article(article, config=None) async

Enhance an article using LLM.

PARAMETER DESCRIPTION
article

The article to enhance

TYPE: Article

config

Optional LLM configuration

TYPE: LLMConfig | None DEFAULT: None

RETURNS DESCRIPTION
Article

Enhanced article

Source code in medium_converter/llm/enhancer.py
async def enhance_article(article: Article, config: LLMConfig | None = None) -> Article:
    """Enhance an article using LLM.

    Args:
        article: The article to enhance
        config: Optional LLM configuration

    Returns:
        Enhanced article
    """
    if config is None:
        config = LLMConfig.from_env()

    llm = get_llm_client(config)

    # Create a copy of the article to avoid modifying the original
    enhanced_article = article.model_copy(deep=True)

    # Process each content block through the LLM
    for item_index, item in enumerate(enhanced_article.content):
        if isinstance(item, Section):
            for block_index, block in enumerate(item.blocks):
                if block.type.value == "text":
                    # Enhance text blocks only
                    prompt = get_enhancement_prompt(
                        text=block.content,
                        article_title=article.title,
                        context="section text",
                    )

                    try:
                        enhanced_text = await llm.generate(prompt)
                        # Use a type check to satisfy mypy
                        content_item = enhanced_article.content[item_index]
                        if isinstance(content_item, Section):
                            content_item.blocks[block_index].content = enhanced_text
                    except Exception as e:
                        # Log error but continue with original content
                        print(f"Error enhancing content: {e}")

        elif isinstance(item, ContentBlock) and item.type.value == "text":
            prompt = get_enhancement_prompt(
                text=item.content, article_title=article.title, context="article text"
            )

            try:
                enhanced_text = await llm.generate(prompt)
                # Use a type check to satisfy mypy
                content_item = enhanced_article.content[item_index]
                if isinstance(content_item, ContentBlock):
                    content_item.content = enhanced_text
            except Exception as e:
                # Log error but continue with original content
                print(f"Error enhancing content: {e}")

    return enhanced_article

Providers

medium_converter.llm.providers.LLMClient(config)

Base class for LLM clients.

Initialize the LLM client.

PARAMETER DESCRIPTION
config

LLM configuration

TYPE: LLMConfig

Source code in medium_converter/llm/providers.py
def __init__(self, config: LLMConfig):
    """Initialize the LLM client.

    Args:
        config: LLM configuration
    """
    self.config = config

generate(prompt) abstractmethod async

Generate text from a prompt.

PARAMETER DESCRIPTION
prompt

The prompt to generate from

TYPE: str

RETURNS DESCRIPTION
str

Generated text

Source code in medium_converter/llm/providers.py
@abstractmethod
async def generate(self, prompt: str) -> str:
    """Generate text from a prompt.

    Args:
        prompt: The prompt to generate from

    Returns:
        Generated text
    """
    pass

medium_converter.llm.providers.get_llm_client(config)

Get an LLM client based on the provider.

PARAMETER DESCRIPTION
config

LLM configuration

TYPE: LLMConfig

RETURNS DESCRIPTION
LLMClient

LLM client

Source code in medium_converter/llm/providers.py
def get_llm_client(config: LLMConfig) -> LLMClient:
    """Get an LLM client based on the provider.

    Args:
        config: LLM configuration

    Returns:
        LLM client
    """
    # Always use LiteLLM if available
    try:
        # We only need to check if litellm is importable
        __import__("litellm")
        return LiteLLMClient(config)
    except ImportError:
        pass

    # Fallback to specific providers
    if config.provider == LLMProvider.OPENAI:
        return OpenAIClient(config)
    elif config.provider == LLMProvider.ANTHROPIC:
        return AnthropicClient(config)
    elif config.provider == LLMProvider.GOOGLE:
        return GoogleClient(config)
    elif config.provider == LLMProvider.MISTRAL:
        # Placeholder for Mistral client
        return OpenAIClient(config)  # Temporary use OpenAI client
    elif config.provider == LLMProvider.LOCAL:
        # Placeholder for local client
        return OpenAIClient(config)  # Temporary use OpenAI client
    else:
        # Fallback to OpenAI
        return OpenAIClient(config)