diff --git a/.github/workflows/blog-to-basehub.yml b/.github/workflows/blog-to-basehub.yml new file mode 100644 index 0000000..d0dbd35 --- /dev/null +++ b/.github/workflows/blog-to-basehub.yml @@ -0,0 +1,241 @@ +# Blog to Basehub CMS Automation +# +# This workflow automatically creates draft blog posts in Basehub CMS +# when new blog posts are added to the repository. +# +# Triggers: +# - Push to main with changes in blog/ directory +# - Manual dispatch with optional blog file path +# +# Required secrets: +# - BASEHUB_TOKEN: Admin API token from Basehub (Settings → API Tokens) +# - BASEHUB_REPO: Your Basehub repository ID (e.g., "your-org/your-repo") +# +# Setup: +# 1. Get your Basehub admin token from basehub.com → Your Repo → Settings → API Tokens +# 2. Add BASEHUB_TOKEN and BASEHUB_REPO as repository secrets +# 3. Ensure your Basehub repo has a "posts" or "blog" collection with compatible schema + +name: Blog to Basehub CMS + +on: + push: + branches: [main] + paths: + - 'blog/**/*.mdx' + - 'blog/**/*.md' + workflow_dispatch: + inputs: + blog_file: + description: 'Specific blog file to sync (e.g., blog/my-post.mdx)' + required: false + type: string + force_update: + description: 'Force update even if post exists' + required: false + type: boolean + default: false + +jobs: + sync-to-basehub: + runs-on: ubuntu-24.04 + permissions: + contents: read + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 2 # Need previous commit to detect changes + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + + - name: Install dependencies + run: npm install gray-matter slugify + + - name: Detect changed blog files + id: detect-files + run: | + if [ -n "${{ github.event.inputs.blog_file }}" ]; then + # Manual dispatch with specific file + echo "files=${{ github.event.inputs.blog_file }}" >> $GITHUB_OUTPUT + else + # Auto-detect changed files + CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD -- 'blog/*.mdx' 'blog/*.md' 2>/dev/null | tr '\n' ' ' || echo "") + + # If no previous commit (first push), get all blog files + if [ -z "$CHANGED_FILES" ]; then + CHANGED_FILES=$(find blog -name "*.mdx" -o -name "*.md" 2>/dev/null | tr '\n' ' ' || echo "") + fi + + echo "files=$CHANGED_FILES" >> $GITHUB_OUTPUT + fi + + - name: Sync blog posts to Basehub + if: steps.detect-files.outputs.files != '' + env: + BASEHUB_TOKEN: ${{ secrets.BASEHUB_TOKEN }} + BASEHUB_REPO: ${{ secrets.BASEHUB_REPO }} + FORCE_UPDATE: ${{ github.event.inputs.force_update || 'false' }} + BLOG_FILES: ${{ steps.detect-files.outputs.files }} + run: | + node << 'EOF' + const fs = require('fs'); + const path = require('path'); + const matter = require('gray-matter'); + + const BASEHUB_API = 'https://api.basehub.com/graphql'; + const token = process.env.BASEHUB_TOKEN; + const repo = process.env.BASEHUB_REPO; + const forceUpdate = process.env.FORCE_UPDATE === 'true'; + const blogFiles = process.env.BLOG_FILES.trim().split(/\s+/).filter(Boolean); + + if (!token || !repo) { + console.log('⚠️ BASEHUB_TOKEN or BASEHUB_REPO not configured. Skipping sync.'); + console.log(' To enable Basehub sync:'); + console.log(' 1. Get your admin token from basehub.com → Settings → API Tokens'); + console.log(' 2. Add BASEHUB_TOKEN secret to this repository'); + console.log(' 3. Add BASEHUB_REPO secret (format: "org/repo")'); + process.exit(0); + } + + async function graphqlRequest(query, variables = {}) { + const response = await fetch(BASEHUB_API, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token}`, + 'X-Basehub-Repo': repo + }, + body: JSON.stringify({ query, variables }) + }); + + const result = await response.json(); + if (result.errors) { + throw new Error(JSON.stringify(result.errors, null, 2)); + } + return result.data; + } + + async function createDraftPost(frontmatter, content, filePath) { + const slug = path.basename(filePath, path.extname(filePath)); + + // Basehub mutation to create a draft blog post + // Adjust the mutation based on your Basehub schema + const mutation = ` + mutation CreateBlogPost($input: CreatePostInput!) { + createPost(input: $input) { + _id + _slug + _title + } + } + `; + + // Alternative: Use transactionAsync for complex operations + const transactionMutation = ` + mutation CreateDraftBlog($operations: [TransactionOperation!]!) { + transactionAsync(operations: $operations) { + id + status + } + } + `; + + const input = { + _title: frontmatter.title || slug, + _slug: slug, + description: frontmatter.description || '', + date: frontmatter.date || new Date().toISOString().split('T')[0], + author: frontmatter.author || 'Venice Team', + tags: frontmatter.tags || [], + featured: frontmatter.featured || false, + body: content, + _status: 'draft' // Create as draft + }; + + console.log(`📝 Creating draft: "${input._title}"`); + console.log(` Slug: ${slug}`); + console.log(` Tags: ${input.tags.join(', ') || 'none'}`); + + try { + // Try using the transaction API for more control + const operations = [{ + type: 'create', + collection: 'posts', // Adjust to your collection name (posts, blog, articles, etc.) + data: input + }]; + + const result = await graphqlRequest(transactionMutation, { operations }); + console.log(`✅ Draft created successfully!`); + console.log(` Transaction ID: ${result.transactionAsync?.id || 'N/A'}`); + return result; + } catch (error) { + // If transaction fails, try simpler approach + console.log(`⚠️ Transaction API not available, trying direct creation...`); + + try { + const result = await graphqlRequest(mutation, { input }); + console.log(`✅ Draft created: ${result.createPost?._id || 'success'}`); + return result; + } catch (innerError) { + console.error(`❌ Failed to create draft: ${innerError.message}`); + throw innerError; + } + } + } + + async function processFile(filePath) { + if (!fs.existsSync(filePath)) { + console.log(`⚠️ File not found: ${filePath}`); + return; + } + + const fileContent = fs.readFileSync(filePath, 'utf-8'); + const { data: frontmatter, content } = matter(fileContent); + + console.log(`\n📄 Processing: ${filePath}`); + + await createDraftPost(frontmatter, content, filePath); + } + + async function main() { + console.log('🚀 Basehub Blog Sync'); + console.log(` Repository: ${repo}`); + console.log(` Files to process: ${blogFiles.length}`); + console.log(` Force update: ${forceUpdate}`); + console.log(''); + + for (const file of blogFiles) { + try { + await processFile(file); + } catch (error) { + console.error(`\n❌ Error processing ${file}:`); + console.error(error.message); + // Continue with other files + } + } + + console.log('\n✨ Sync complete!'); + console.log(' View drafts at: https://basehub.com/' + repo); + } + + main().catch(error => { + console.error('Fatal error:', error); + process.exit(1); + }); + EOF + + - name: Summary + run: | + echo "## Blog to Basehub Sync Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Files processed:** ${{ steps.detect-files.outputs.files || 'None' }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### Next Steps" >> $GITHUB_STEP_SUMMARY + echo "1. Go to [Basehub CMS](https://basehub.com) to review the draft" >> $GITHUB_STEP_SUMMARY + echo "2. Edit and polish the content if needed" >> $GITHUB_STEP_SUMMARY + echo "3. Publish when ready" >> $GITHUB_STEP_SUMMARY diff --git a/blog/README.md b/blog/README.md new file mode 100644 index 0000000..94b2788 --- /dev/null +++ b/blog/README.md @@ -0,0 +1,77 @@ +# Blog Posts + +This directory contains blog posts that can be automatically synced to Basehub CMS as drafts. + +## File Format + +Blog posts should be MDX files with YAML frontmatter: + +```mdx +--- +title: "Your Blog Post Title" +description: "A brief description for SEO and previews" +date: "2026-01-25" +author: "Venice Team" +tags: + - tutorial + - privacy + - api +image: null +featured: false +--- + +# Your Blog Post Title + +Content goes here... +``` + +### Frontmatter Fields + +| Field | Required | Description | +|-------|----------|-------------| +| `title` | Yes | The blog post title | +| `description` | Yes | Short description for SEO/previews | +| `date` | Yes | Publication date (YYYY-MM-DD format) | +| `author` | No | Author name (defaults to "Venice Team") | +| `tags` | No | Array of tags for categorization | +| `image` | No | Cover image URL | +| `featured` | No | Whether to feature this post (default: false) | + +## Automatic Sync to Basehub + +When blog posts are pushed to the `main` branch, the GitHub Actions workflow automatically: + +1. Detects new or changed `.mdx` files in this directory +2. Parses the frontmatter and content +3. Creates a **draft** post in Basehub CMS +4. Notifies you in the workflow summary + +### Setup Requirements + +To enable Basehub sync, add these secrets to your repository: + +1. **`BASEHUB_TOKEN`**: Your Basehub admin API token + - Get it from: basehub.com → Your Repo → Settings → API Tokens + +2. **`BASEHUB_REPO`**: Your Basehub repository identifier + - Format: `your-org/your-repo` + +### Manual Sync + +You can also manually trigger a sync from the Actions tab: + +1. Go to Actions → "Blog to Basehub CMS" +2. Click "Run workflow" +3. Optionally specify a specific file path +4. Check "Force update" to overwrite existing drafts + +## Workflow + +1. **Write**: Create your `.mdx` file in this directory +2. **Commit**: Push to main (or open a PR) +3. **Review**: Check the draft in Basehub CMS +4. **Publish**: Edit and publish from Basehub when ready + +## Current Posts + +- `venice-api-clawdbot-tutorial.mdx` - How to use Venice API with Clawdbot diff --git a/blog/venice-api-clawdbot-tutorial.mdx b/blog/venice-api-clawdbot-tutorial.mdx new file mode 100644 index 0000000..5c6d606 --- /dev/null +++ b/blog/venice-api-clawdbot-tutorial.mdx @@ -0,0 +1,417 @@ +--- +title: "How to Use Venice API with Clawdbot: A Complete Privacy-Focused AI Tutorial" +description: "Learn how to set up Venice AI as your privacy-focused provider in Clawdbot using the new onboarding flow, with access to 25+ models including Claude, GPT-5.2, and fully private open-source options." +date: "2026-01-25" +author: "Venice Team" +tags: + - tutorial + - clawdbot + - privacy + - api + - integration + - open-source +image: null +featured: false +--- + +# How to Use Venice API with Clawdbot: A Complete Privacy-Focused AI Tutorial + +*If you're looking for a way to use powerful AI models while maintaining your privacy, the combination of Venice AI and Clawdbot is exactly what you need.* + +--- + +## What You'll Learn + +- What Venice AI offers and why privacy matters +- How to get your Venice API key +- Setting up Clawdbot with Venice using the new onboarding wizard +- Choosing the right model for your use case +- Practical examples and tips + +--- + +## Why Venice AI? + +Venice AI stands out in the crowded AI provider space for three key reasons: + +### 1. True Privacy-First Inference + +Unlike most AI providers, Venice offers **fully private inference** for open-source models. Your prompts and responses are never stored or logged—they're completely ephemeral. For privacy-conscious users, this is a game-changer. + +### 2. Uncensored Models + +Need AI without content restrictions? Venice provides access to uncensored models like **Venice Uncensored**, giving you complete control over what your AI can discuss. + +### 3. Anonymized Access to Premium Models + +Want to use Claude, GPT-5.2, or Gemini without linking your identity? Venice's anonymized proxy strips metadata from requests to proprietary models, letting you access premium AI capabilities with enhanced privacy. + +--- + +## Prerequisites + +Before we begin, make sure you have: + +- **Node.js 22 or higher** installed +- **Clawdbot** installed globally: + +```bash +npm install -g clawdbot@latest +``` + +- A **Venice AI account** (we'll create one together) + +--- + +## Step 1: Get Your Venice API Key + +First, let's get your Venice API credentials: + +1. **Create an account** at [venice.ai](https://venice.ai) +2. Navigate to **Settings → API Keys** +3. Click **Create new key** +4. Copy your API key—it starts with `vapi_` + +> **Tip:** Store your API key securely. You'll need it in the next step. + +--- + +## Step 2: Set Up Venice in Clawdbot + +Clawdbot's new onboarding flow makes Venice setup incredibly smooth. You have three options: + +### Option A: Interactive Onboarding (Recommended) + +This is the easiest way to get started. The wizard guides you through everything: + +```bash +clawdbot onboard --auth-choice venice-api-key +``` + +Here's what happens: + +1. **API Key Prompt**: Enter your Venice API key (or it uses `VENICE_API_KEY` if already set) +2. **Model Discovery**: Clawdbot fetches all 25+ available Venice models +3. **Model Selection**: Pick your default model from the list +4. **Auto-Configuration**: The provider is configured automatically + +That's it! You're ready to use Venice with Clawdbot. + +### Option B: Environment Variable + Onboarding + +If you prefer to set the API key first: + +```bash +# Set the environment variable +export VENICE_API_KEY="vapi_xxxxxxxxxxxx" + +# Run onboarding +clawdbot onboard --auth-choice venice-api-key +``` + +This method is useful if you want the API key available across terminal sessions (add it to your `.bashrc` or `.zshrc`). + +### Option C: Non-Interactive Setup + +For scripting or automation: + +```bash +clawdbot onboard --non-interactive \ + --auth-choice venice-api-key \ + --venice-api-key "vapi_xxxxxxxxxxxx" +``` + +--- + +## Step 3: Verify Your Setup + +Let's make sure everything is working: + +```bash +# List available Venice models +clawdbot models list | grep venice + +# Test with a simple message +clawdbot chat --model venice/llama-3.3-70b "Hello! Can you confirm you're working?" +``` + +You should see a response from the Llama 3.3 70B model. Congratulations—Venice is now powering your Clawdbot! + +--- + +## Understanding Venice Privacy Modes + +Venice offers two distinct privacy modes. Understanding these helps you choose the right model: + +### Private Mode (Open-Source Models) + +| Feature | Description | +|---------|-------------| +| **Logging** | None—completely ephemeral | +| **Data Storage** | Prompts/responses never stored | +| **Models** | Llama, Qwen, DeepSeek, Venice Uncensored | +| **Best For** | Maximum privacy, sensitive conversations | + +### Anonymized Mode (Proprietary Models) + +| Feature | Description | +|---------|-------------| +| **Proxy** | Requests routed through Venice | +| **Metadata** | Stripped before reaching provider | +| **Models** | Claude, GPT-5.2, Gemini, Grok | +| **Best For** | Premium model access with enhanced privacy | + +--- + +## Available Models: Your Complete Guide + +Venice provides 25 models across both privacy modes. Here's how to choose: + +### Private Models (15 Total) + +#### For General Use +- **`llama-3.3-70b`** — Best all-around private model (our default pick) +- **`qwen3-235b-a22b-instruct-2507`** — Strong general-purpose + +#### For Coding +- **`qwen3-coder-480b-a35b-instruct`** — 262k context, code-optimized +- **`grok-code-fast-1`** (anonymized) — Fast code generation + +#### For Complex Reasoning +- **`deepseek-v3.2`** — Excellent reasoning, 163k context +- **`qwen3-235b-a22b-thinking-2507`** — Thinking mode enabled +- **`zai-org-glm-4.7`** — Strong multilingual reasoning + +#### For Vision Tasks +- **`qwen3-vl-235b-a22b`** — Best private vision model +- **`google-gemma-3-27b-it`** — Lightweight vision capability + +#### For Uncensored Output +- **`venice-uncensored`** — No content restrictions + +#### For Speed +- **`qwen3-4b`** — Fast, lightweight, still capable +- **`llama-3.2-3b`** — Quick responses + +### Anonymized Models (10 Total) + +| Model | Original | Best For | +|-------|----------|----------| +| `claude-opus-45` | Claude Opus 4.5 | Complex reasoning, best overall quality | +| `claude-sonnet-45` | Claude Sonnet 4.5 | Balanced quality/speed | +| `openai-gpt-52` | GPT-5.2 | General excellence | +| `openai-gpt-52-codex` | GPT-5.2 Codex | Code generation | +| `gemini-3-pro-preview` | Gemini 3 Pro | Multimodal tasks | +| `gemini-3-flash-preview` | Gemini 3 Flash | Fast multimodal | +| `grok-41-fast` | Grok 4.1 Fast | Quick responses | +| `grok-code-fast-1` | Grok Code Fast 1 | Code assistance | +| `kimi-k2-thinking` | Kimi K2 Thinking | Extended reasoning | +| `minimax-m21` | MiniMax M2.1 | General reasoning | + +--- + +## Practical Usage Examples + +### Basic Chat + +```bash +# Use the default private model +clawdbot chat --model venice/llama-3.3-70b "Explain quantum computing in simple terms" + +# Use Claude via Venice for complex analysis +clawdbot chat --model venice/claude-opus-45 "Analyze this business strategy..." +``` + +### Coding Assistance + +```bash +# Get help with code +clawdbot chat --model venice/qwen3-coder-480b-a35b-instruct "Write a Python function to parse JSON files recursively" +``` + +### Using with Channels + +Once configured, you can use Venice-powered AI across all your Clawdbot channels: + +```bash +# Start the gateway with Venice as your provider +clawdbot gateway --port 18789 --verbose + +# Messages from WhatsApp, Telegram, Discord, etc. will use your Venice model +``` + +### Agent Mode with Deep Thinking + +```bash +# Use agent mode with high thinking for complex tasks +clawdbot agent --message "Create a complete project plan for a mobile app" --thinking high +``` + +### Changing Your Default Model + +```bash +# Switch to Claude for complex work +clawdbot models set venice/claude-opus-45 + +# Switch back to Llama for privacy +clawdbot models set venice/llama-3.3-70b +``` + +--- + +## Configuration File Setup + +For advanced users, you can configure Venice directly in your Clawdbot config: + +```json5 +{ + env: { + VENICE_API_KEY: "vapi_xxxxxxxxxxxx" + }, + agents: { + defaults: { + model: { + primary: "venice/llama-3.3-70b" + } + } + }, + models: { + mode: "merge", + providers: { + venice: { + baseUrl: "https://api.venice.ai/api/v1", + apiKey: "${VENICE_API_KEY}", + api: "openai-completions", + models: [ + { + id: "llama-3.3-70b", + name: "Llama 3.3 70B", + reasoning: false, + input: ["text"], + contextWindow: 131072, + maxTokens: 8192 + } + ] + } + } + } +} +``` + +--- + +## Model Selection Cheat Sheet + +| Your Need | Recommended Model | Why | +|-----------|-------------------|-----| +| **Maximum privacy** | `llama-3.3-70b` | Private mode, no logging | +| **Best overall quality** | `claude-opus-45` | Opus remains the strongest | +| **Fast responses** | `qwen3-4b` | Lightweight but capable | +| **Coding tasks** | `qwen3-coder-480b-a35b-instruct` | 262k context, code-optimized | +| **Vision/images** | `qwen3-vl-235b-a22b` | Best private vision model | +| **No restrictions** | `venice-uncensored` | Uncensored output | +| **Complex reasoning** | `deepseek-v3.2` | Strong reasoning, private | +| **Long context** | `qwen3-next-80b` | 262k token context | + +--- + +## Troubleshooting + +### API Key Not Recognized + +```bash +# Verify your key is set +echo $VENICE_API_KEY + +# Check if Venice models appear +clawdbot models list | grep venice +``` + +Make sure your key starts with `vapi_`. + +### Model Not Available + +Venice's model catalog updates dynamically. Some models may temporarily go offline: + +```bash +# See currently available models +clawdbot models list | grep venice +``` + +### Connection Issues + +Venice API endpoint is `https://api.venice.ai/api/v1`. Ensure: +- Your network allows HTTPS connections +- No firewall is blocking the Venice domain +- Check [status.venice.ai](https://status.venice.ai) for outages + +### Run Doctor + +Clawdbot includes a diagnostic tool: + +```bash +clawdbot doctor +``` + +This checks your configuration, API connections, and highlights any issues. + +--- + +## Venice vs Direct API Access + +Why use Venice instead of direct API access? Here's the comparison: + +| Aspect | Venice (Anonymized) | Direct API | +|--------|---------------------|------------| +| **Privacy** | Metadata stripped, anonymized | Your account linked | +| **Latency** | +10-50ms (proxy overhead) | Direct connection | +| **Features** | Most features supported | Full feature access | +| **Billing** | Venice credits | Provider billing | +| **Account linking** | None | Full tracking | + +--- + +## Tips for Success + +1. **Start with `llama-3.3-70b`** — It's the default for good reason: private, capable, and fast +2. **Use Claude for hard problems** — When you need the best reasoning, `claude-opus-45` via Venice gives you Opus quality with privacy +3. **Match context to model** — Use 262k-context models like `qwen3-coder-480b` for large codebases +4. **Run the gateway** — For the full Clawdbot experience across WhatsApp, Telegram, etc.: + +```bash +clawdbot onboard --install-daemon +clawdbot gateway --port 18789 --verbose +``` + +--- + +## What's Next? + +Now that you have Venice running with Clawdbot, explore these features: + +- **[Channels](https://docs.clawd.bot/channels)** — Connect WhatsApp, Telegram, Discord, Slack, and more +- **[Voice Wake](https://docs.clawd.bot/nodes/voicewake)** — Always-on voice activation +- **[Skills](https://docs.clawd.bot/tools/skills)** — Extend your AI with custom capabilities +- **[Canvas](https://docs.clawd.bot/platforms/mac/canvas)** — Visual AI workspace (macOS) + +--- + +## Conclusion + +Venice AI and Clawdbot together create a powerful, privacy-respecting AI assistant. Whether you need fully private inference with open-source models or anonymized access to premium models like Claude and GPT-5.2, this combination delivers. + +The new onboarding flow makes setup effortless—just run `clawdbot onboard --auth-choice venice-api-key` and you're ready to go. + +Happy chatting, privately! + +--- + +## Resources + +- **Clawdbot**: [GitHub](https://github.com/clawdbot/clawdbot) | [Docs](https://docs.clawd.bot) | [Discord](https://discord.gg/clawd) +- **Venice AI**: [Website](https://venice.ai) | [API Docs](https://docs.venice.ai) | [Pricing](https://venice.ai/pricing) +- **Getting Started**: [Clawdbot Quickstart](https://docs.clawd.bot/start/getting-started) + +--- + +*This tutorial covers the Venice AI integration added in [PR #1666](https://github.com/clawdbot/clawdbot/pull/1666). Special thanks to the Clawdbot community for making privacy-focused AI accessible to everyone.*