Skip to main content

Local OpenAI-compatible proxy with Firefox/Selenium search + Ollama backend for Avante.nvim by @yetone

Project description

Moonshot-Local

Local OpenAI-compatible API proxy that combines Firefox/Selenium web search with Ollama LLM backend for Avante by @yetone.

What is this?

A local service that gives Avante.nvim web search capabilities while keeping everything private and self-hosted. It replicates Moonshot/Kimi's built-in web search feature using:

  • Firefox + Selenium for Google search
  • Ollama for local LLM generation
  • FastAPI for OpenAI-compatible endpoints

Architecture

Avante.nvim (by yetone)
  ↓
local-moonie API (FastAPI)
  ↓
Search Decision Engine
  ↓
Selenium + Firefox (Google search)
  ↓
Prompt Augmentation
  ↓
Ollama (llama3.2:3b)
  ↓
OpenAI-compatible SSE stream

Features

  • ✅ OpenAI-compatible /v1/models and /v1/chat/completions endpoints
  • ✅ Streaming and non-streaming responses
  • ✅ Automatic web search detection based on keywords
  • ✅ Firefox/Selenium Google search scraping
  • ✅ Search result injection into prompt context
  • ✅ Ollama backend integration
  • ✅ Graceful degradation if search fails
  • ✅ Single-user stability with browser session management

Quick Start

1. Install System Dependencies

Arch Linux:

sudo pacman -S firefox geckodriver python python-pip

Other systems:

2. Verify Ollama

# Check Ollama is running
curl http://127.0.0.1:11434/api/tags

# Should show your models (e.g., llama3.2:3b)

If not running:

ollama serve

3. Install local-moonie

Option A: Install from AUR (Arch Linux):

yay -S python-local_moonie

Option B: Install from PyPI:

pip install local_moonie

Option C: Install from source:

git clone https://github.com/gub-7/local_moonie.git
cd local-moonie
pip install -e .

4. Configure

For AUR installation:

# Edit the system-wide config
sudo nano /etc/local-moonie/config.env

For PyPI/source installation:

# Copy example config
cp .env.example .env

# Edit configuration
nano .env

Important settings:

# Ollama backend (adjust to your setup)
OLLAMA_HOST=http://127.0.0.1:11434
OLLAMA_MODEL=llama3.2:3b

# Set a secure API key (optional - leave empty for no auth)
API_KEY=

# Browser visibility
HEADLESS_BROWSER=false  # false = visible, true = headless

Note: The service will log the configuration file path on startup, so you always know which file it's reading from.

5. Start Server

Quick start:

./start.sh

Or manually:

python -m local_moonie.app.main

Or with uvicorn:

uvicorn local_moonie.app.main:app --host 127.0.0.1 --port 8080

6. Test

# Set API key
export MOONSHOT_LOCAL_API_KEY=your-secret-key-here

# Run tests
./test_api.sh

# Or use Python example
python example_client.py

Avante.nvim Integration

Avante.nvim by @yetone is a Neovim plugin that brings Cursor-like AI features to Neovim.

Configure Avante

Add to your Neovim config (e.g., ~/.config/nvim/lua/plugins/avante.lua):

return {
  "yetone/avante.nvim",
  event = "VeryLazy",
  opts = {
    -- Use local_moonie as provider
    provider = "local_moonie",

    behaviour = {
      -- Fast Apply requires separate Morph service
      enable_fastapply = false,
    },

    providers = {
      local_moonie = {
        -- Inherit OpenAI-compatible behavior
        __inherited_from = "openai",

        -- Point to local proxy
        endpoint = "http://127.0.0.1:8080/v1",

        -- API key from environment
        api_key_name = "MOONSHOT_LOCAL_API_KEY",

        -- Model name
        model = "local-moonie",

        -- Optional settings
        temperature = 0.2,
        max_tokens = 4096,
      },
    },
  },

  dependencies = {
    "stevearc/dressing.nvim",
    "nvim-lua/plenary.nvim",
    "MunifTanjim/nui.nvim",
    "nvim-tree/nvim-web-devicons",
  },
}

Set API Key

# Add to your shell rc file (~/.bashrc, ~/.zshrc, etc.)
export MOONSHOT_LOCAL_API_KEY=your-secret-key-here

# Or set for current session
export MOONSHOT_LOCAL_API_KEY=your-secret-key-here

Use in Avante

  1. Start local-moonie: ./start.sh
  2. Open Neovim
  3. Use Avante commands as normal

Search triggers when you ask about:

  • "latest", "current", "recent" info
  • Documentation, release notes
  • "How to" questions
  • Version-specific queries

How It Works

Normal Coding Prompt

User in Avante: "Write quicksort in Python"
  ↓
local-moonie: No search keywords detected
  ↓
Ollama (llama3.2:3b): Generate code
  ↓
Stream back to Avante

Search-Enabled Prompt

User in Avante: "What are the latest features in FastAPI?"
  ↓
local-moonie: Detected "latest" keyword
  ↓
Firefox + Selenium: Search Google
  ↓
Scrape top 5 results (title, URL, snippet)
  ↓
Inject into prompt:
  "WEB_RESULTS:
   [1] FastAPI 0.109.0 Release
   URL: https://...
   Snippet: New features include..."
  ↓
Ollama: Generate answer with web context
  ↓
Stream back to Avante with citations

Search Trigger Keywords

Search activates when prompt contains:

  • latest, current, today, recent, search
  • docs, documentation, release notes
  • version, pricing, news
  • what is, how to, tutorial

API Endpoints

GET /v1/models

Returns available models (OpenAI-compatible).

curl http://127.0.0.1:8080/v1/models \
  -H "Authorization: Bearer your-secret-key-here"

POST /v1/chat/completions

Main endpoint for chat completions.

Request:

{
  "model": "local-moonie",
  "messages": [
    {"role": "user", "content": "Your prompt here"}
  ],
  "stream": true,
  "temperature": 0.2
}

Non-streaming example:

curl http://127.0.0.1:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-secret-key-here" \
  -d '{
    "model": "local-moonie",
    "messages": [{"role": "user", "content": "Hello"}],
    "stream": false
  }'

Streaming example:

curl http://127.0.0.1:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-secret-key-here" \
  -d '{
    "model": "local-moonie",
    "messages": [{"role": "user", "content": "latest Python features"}],
    "stream": true
  }'

GET /health

Health check endpoint.

curl http://127.0.0.1:8080/health

Configuration Reference

All settings in .env:

# Ollama backend
OLLAMA_HOST=http://127.0.0.1:11434
OLLAMA_MODEL=llama3.2:3b
OLLAMA_EMBED_MODEL=mxbai-embed-large:latest

# Server
HOST=127.0.0.1
PORT=8080
API_KEY=your-secret-key-here

# Search
MAX_SEARCH_RESULTS=5
SEARCH_TIMEOUT=10
HEADLESS_BROWSER=false

Project Structure

local_moonie/
├── app/
│   ├── main.py              # FastAPI routes
│   ├── schemas.py           # Pydantic models (OpenAI-compatible)
│   ├── config.py            # Configuration from .env
│   ├── browser.py           # Selenium Firefox manager
│   ├── search.py            # Google search scraper
│   ├── search_decider.py    # Search trigger logic
│   ├── prompting.py         # Prompt augmentation
│   ├── llm.py               # Ollama adapter
│   └── sse.py               # SSE streaming formatter
└── __init__.py

pyproject.toml               # Dependencies
.env.example                 # Configuration template
README.md                    # This file
start.sh                     # Quick start script
test_api.sh                  # Test script
example_client.py            # Python example client
avante_config.lua            # Avante config example
local-moonie.service       # systemd service file

Upgrading the Model

llama3.2:3b is fast but weak for complex coding. Upgrade for better quality:

# Pull a better model
ollama pull qwen2.5-coder:14b

# Or for 32B if you have VRAM
ollama pull qwen2.5-coder:32b

# Update .env
nano .env
# Change: OLLAMA_MODEL=qwen2.5-coder:14b

# Restart server

Model recommendations:

  • qwen2.5-coder:14b - Great for coding (~8GB VRAM)
  • qwen2.5-coder:32b - Best for coding (~20GB VRAM)
  • deepseek-coder-v2:16b - Alternative for code
  • llama3.3:70b - If you have 48GB+ VRAM

Troubleshooting

Server won't start

Error: Address already in use

# Check what's using port 8080
sudo lsof -i :8080

# Kill it or change PORT in .env

Error: ModuleNotFoundError

# Reinstall
pip install -e .

Ollama connection fails

Error: Connection refused

# Start Ollama
ollama serve

# Verify
curl http://127.0.0.1:11434/api/tags

Firefox/geckodriver issues

Error: geckodriver not found

# Arch Linux
sudo pacman -S geckodriver

# Verify
geckodriver --version

Firefox opens but search fails:

  1. Set HEADLESS_BROWSER=false in .env
  2. Watch Firefox window
  3. If Google consent page appears, accept it manually once
  4. Profile persists, won't ask again

Search returns no results:

  • Google may have changed DOM structure
  • Check logs for scraping errors
  • System still works - degrades gracefully to LLM without web context

Avante integration issues

Avante can't connect:

# Verify server is running
curl http://127.0.0.1:8080/health

# Check API key matches
echo $MOONSHOT_LOCAL_API_KEY

# In Neovim, check env var is visible:
:lua print(vim.fn.getenv('MOONSHOT_LOCAL_API_KEY'))

Streaming doesn't work:

  • Ensure Avante provider inherits from "openai"
  • Check stream = true is supported in your Avante version

Running as systemd Service

# Copy service file
sudo cp local-moonie.service /etc/systemd/system/

# Edit paths if needed
sudo nano /etc/systemd/system/local-moonie.service

# Enable and start
sudo systemctl enable local-moonie
sudo systemctl start local-moonie

# Check status
sudo systemctl status local-moonie

# View logs
sudo journalctl -u local-moonie -f

Advanced Usage

Custom Search Keywords

Edit local_moonie/app/search_decider.py:

SEARCH_KEYWORDS = {
    "latest", "current", "today", "recent", "search",
    "your", "custom", "keywords", "here",
}

Multiple Search Queries

Edit local_moonie/app/search_decider.py:

def generate_queries(messages: list[Message], max_queries: int = 3):  # Changed from 1
    # Add query expansion logic

Adjust Search Results

In .env:

MAX_SEARCH_RESULTS=10  # Default is 5
SEARCH_TIMEOUT=15      # Default is 10

Performance

  • Normal prompts: ~Same as direct Ollama
  • Search prompts: +2-5 seconds for Firefox/scraping
  • Model quality: Depends on your Ollama model

Limitations

  • v1 scope: Single-user, serialized browser access
  • Search fragility: Google DOM changes can break scraping
  • No Fast Apply: Avante Fast Apply requires separate Morph service
  • Model quality: Depends on your Ollama model choice

Roadmap

Future improvements:

  • Result caching (Redis/SQLite)
  • Multiple search providers (DuckDuckGo, Brave API)
  • Full page content extraction
  • Local reranker for results
  • Multi-browser pool
  • Tool-call emulation for Moonshot-like behavior
  • Morph-compatible Fast Apply service
  • Embeddings endpoint for RAG

Security Notes

  • API key required by default (set in .env)
  • Binds to localhost by default (not exposed to network)
  • For production: use HTTPS reverse proxy, stronger auth

Credits

Built for Avante.nvim by @yetone with:

  • FastAPI (web framework)
  • Selenium (browser automation)
  • Ollama (local LLM)
  • Firefox (web search)

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

local_moonie-0.1.2.tar.gz (22.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

local_moonie-0.1.2-py3-none-any.whl (18.1 kB view details)

Uploaded Python 3

File details

Details for the file local_moonie-0.1.2.tar.gz.

File metadata

  • Download URL: local_moonie-0.1.2.tar.gz
  • Upload date:
  • Size: 22.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for local_moonie-0.1.2.tar.gz
Algorithm Hash digest
SHA256 03f8cf1a642dab655081a544cd415833de4450ae829c4e261b490bea38645303
MD5 626d3b3412362e71cb2678f1751a26a5
BLAKE2b-256 00e2e7b792a4ae624b83aa878bdd98069a3ebde82b7d6fd89ae79aa6dfab7e39

See more details on using hashes here.

File details

Details for the file local_moonie-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: local_moonie-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 18.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for local_moonie-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 dd7b978d8b6b4566d0743f5b7c2e67e4cd8576fbd83c59dc3e992b6f8efdda08
MD5 ace0304c8a38b3b534a03630f3cd99a4
BLAKE2b-256 decf1798c8d80065c2affe239948c60215584d32c302113e9d8ecde7bfb3932a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page