Introducing AI-Powered HTML to Markdown Conversion in get-md
We're excited to announce an upcoming feature for @nanocollective/get-md: optional AI-powered HTML to Markdown conversion using locally-run language models. This enhancement will give developers the choice between lightning-fast conversion and AI-enhanced quality, all while maintaining complete offline functionality.
The Challenge
While our current Turndown-based conversion is fast and reliable (sub-100ms for most pages), complex HTML structures like nested tables, intricate layouts, and heavily formatted content can sometimes result in less-than-perfect Markdown output. We wanted to offer a solution that could handle these edge cases better without forcing all users to adopt a slower, more resource-intensive approach.
The Solution: Optional Local LLM
We're adding support for ReaderLM-v2, a 1.5 billion parameter language model specifically designed for HTML-to-Markdown conversion. The key aspects of our approach:
- Completely optional: Turndown remains the default. Users opt-in via a simple flag.
- Runs locally: No API keys, no cloud services, no internet required (after model download).
- Full control: Developers using get-md in their applications can let their end-users decide whether to enable AI conversion.
- Smart fallback: If the LLM fails for any reason, the system automatically falls back to Turndown.
How It Works
For CLI Users
# Check if the model is available
getmd --model-info
# Download the AI model (986MB, one-time)
getmd --download-model
# Convert using AI
getmd https://example.com --use-llm
The CLI provides interactive prompts and progress bars to guide users through the model download process.
For SDK/Package Users
import {
convertToMarkdown,
checkLLMModel,
downloadLLMModel
} from '@nanocollective/get-md';
// Check if model is available
const status = await checkLLMModel();
if (!status.available) {
// Download with progress callbacks
await downloadLLMModel({
onProgress: (downloaded, total, percentage) => {
console.log(`Downloading: ${percentage.toFixed(1)}%`);
}
});
}
// Convert with AI
const result = await convertToMarkdown('https://example.com', {
useLLM: true,
onLLMEvent: (event) => {
// React to conversion events
if (event.type === 'conversion-complete') {
console.log(`Done in ${event.duration}ms`);
}
}
});
Perfect for Application Developers
One of the most powerful aspects of this feature is how it works for developers building applications with get-md. Whether you're creating an Obsidian plugin, VS Code extension, Electron app, or web service, you can give your users the choice to enable AI conversion.
Example: Obsidian Plugin
// In your plugin settings
new Setting(containerEl)
.setName('AI-powered conversion')
.setDesc('Better quality, slower (986MB model)')
.addToggle(toggle => toggle
.setValue(this.settings.useAI)
.onChange(async (value) => {
this.settings.useAI = value;
await this.saveSettings();
}));
// Add a download button if model isn't installed
if (!modelAvailable) {
new Setting(containerEl)
.addButton(button => button
.setButtonText('Download AI Model')
.onClick(async () => {
await downloadLLMModel({
onProgress: (_, __, percentage) => {
button.setButtonText(`Downloading... ${percentage}%`);
}
});
}));
}
Your users get a seamless experience with progress feedback, and the model downloads directly to their machine—no server-side infrastructure needed on your end.
Performance Trade-offs
We believe in transparency, so here's what you need to know:
| Metric | Turndown (Default) | LLM (Optional) |
|---|---|---|
| Speed | <100ms | 5-10 seconds |
| RAM | ~100MB | 2-4GB |
| Disk | 0MB | 986MB (model) |
| Quality | Good | Excellent |
| Complex layouts | Good | Excellent |
| Consistency | 100% deterministic | ~95% consistent |
When to Use Each
Use Turndown (default) for:
- Batch processing thousands of pages
- CI/CD pipelines
- Real-time conversion
- Low-resource environments
- Simple blog posts and articles
Use LLM (opt-in) for:
- High-quality single conversions
- Complex documentation sites
- Pages with intricate tables and nested structures
- When visual fidelity matters most
Technical Architecture
The LLM integration is designed to enhance, not replace, the existing pipeline:
- Content extraction (Readability) - removes ads, nav, etc.
- HTML cleaning - removes scripts, normalizes structure
- Structure enhancement - fixes heading hierarchy
- Conversion - Either Turndown OR LLM (user's choice)
- Post-processing - adds frontmatter, calculates stats
By running the LLM on pre-cleaned HTML, we get better results while reducing token usage and processing time.
Callback System for Rich UIs
We've designed a comprehensive callback system so developers can build rich user interfaces around the conversion process:
await convertToMarkdown(url, {
useLLM: true,
onLLMEvent: (event) => {
switch (event.type) {
case 'model-loading':
showSpinner('Loading AI model...');
break;
case 'download-progress':
updateProgressBar(event.percentage);
break;
case 'conversion-complete':
hideSpinner();
showSuccess(`Converted in ${event.duration}ms`);
break;
case 'fallback-start':
showWarning('Using fallback method');
break;
}
}
});
This means whether you're building a CLI tool, desktop app, or web service, you can provide users with real-time feedback on what's happening.
Why ReaderLM-v2?
We chose ReaderLM-v2 for several reasons:
- Purpose-built: Specifically designed for HTML-to-Markdown conversion
- Efficient: 1.5B parameters with GGUF quantization (Q4_K_M) runs on consumer hardware
- Multilingual: Supports 29 languages out of the box
- Proven: Outperforms much larger models on conversion tasks
- Open source: Available on Hugging Face, MIT-compatible licensing
The Q4_K_M quantized version strikes the perfect balance—high quality at 986MB, running comfortably on systems with 8GB+ RAM.
Open Questions & Future Enhancements
We're considering several enhancements for future versions:
- Hybrid mode: Use LLM only for complex sections (tables, nested structures), Turndown for simple content
- GPU acceleration: Faster inference on compatible hardware
- Caching layer: Store conversions to avoid re-processing identical content
- Alternative models: Support for other models based on user preference
- Smart detection: Automatically choose method based on HTML complexity
We'd love to hear your feedback on which features would be most valuable to you.
No Breaking Changes
This is a purely additive feature. All existing code continues to work exactly as before. The default behavior remains unchanged—fast, deterministic Turndown conversion. LLM conversion is opt-in only.
Try It Out
The implementation is currently in planning stages. We're working through the architecture and will be rolling this out in phases:
- Phase 1: Core infrastructure and LLM integration
- Phase 2: CLI and SDK integration with callbacks
- Phase 3: Enhanced features (model management, config files)
- Phase 4: Comprehensive testing and documentation
Follow our GitHub repository for updates, or check out Issue #3 to join the discussion.
We Want Your Feedback
This feature is being designed with the community in mind. We'd love to hear:
- What use cases would benefit most from AI-powered conversion?
- What should the user experience look like in your application?
- Are there specific models or configurations you'd like to see supported?
- What concerns do you have about the implementation?
Join the conversation on GitHub or reach out to us directly. Let's build something amazing together.
get-md is an open-source HTML to Markdown converter optimized for LLM consumption, built by the Nano Collective. Fast, reliable, and now with optional AI enhancement.
Want to join the discussion? Head over to GitHub to share your thoughts!
View Discussion on GitHub