npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

astro-chatty-gpt

v0.0.3

Published

A chatbot for your astro site powered by Upstash search and gpt-5

Readme

astro-chatty-gpt (WIP)

An Astro integration that adds AI-powered search and chat functionality to your Astro website using Upstash Search and OpenAI.

Features

  • 🤖 AI-Powered Search: Intelligent search across your website content (GPT-5)
  • 💬 Chat Interface: Interactive chat with your website content
  • 🔍 Search: Powered by Upstash Search for semantic search
  • 🌐 Multi-language Support: Search and chat in multiple languages
  • 📱 Streaming Responses: Real-time streaming chat responses
  • Auto-indexing: Automatically crawls and indexes your website content on every build
  • 🎯 Flexible Configuration: Customizable search behavior and content filtering

Usage

Prerequisites

Before using this integration, you'll need:

  1. Upstash Account: Sign up at upstash.com and create a Search Database
  2. OpenAI API Key: Get your API key from platform.openai.com

Installation (WIP)

Install the integration automatically using the Astro CLI:

pnpm astro add astro-chatty-gpt
npx astro add astro-chatty-gpt
yarn astro add astro-chatty-gpt

Or install it manually:

  1. Install the required dependencies
pnpm add astro-chatty-gpt
npm install astro-chatty-gpt
yarn add astro-chatty-gpt
  1. Add the integration to your astro config
+import AstroChattyGpt from "astro-chatty-gpt";
+import { loadEnv } from "vite";
+const env = loadEnv("", process.cwd(), "");

export default defineConfig({
  integrations: [
+    AstroChattyGpt({
+      upstashUrl: env.UPSTASH_SEARCH_REST_URL!,
+      upstashToken: env.UPSTASH_SEARCH_REST_TOKEN!,
+      openAiKey: env.OPENAI_API_KEY!,
+      maxOutputTokens: 500,
+      excludeRoutes: ['admin/', 'private/'],
+      maxContextDocs: 10,
+      maxContentLength: 2000,
+      contentTag: 'main',
+      searchLimit: 10,
+      excludeTags: ['.sidebar', '.ads', '.navigation'],
+      botName: 'AstroChattyGpt',
+      systemPrompt: 'You are a helpful assistant for my website.',
+    }),
  ],
});

Configuration

Required Environment Variables

Create a .env file in your project root:

UPSTASH_SEARCH_REST_URL=your_upstash_rest_url
UPSTASH_SEARCH_REST_TOKEN=your_upstash_rest_token
OPENAI_API_KEY=your_openai_api_key

Integration Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | upstashUrl | string | - | Upstash Search REST URL | | upstashToken | string | - | Upstash Search REST Token | | openAiKey | string | - | OpenAI API Key | | maxOutputTokens | number | 500 | Maximum tokens to use for AI responses | | excludeRoutes | string[] | [] | Routes to exclude from indexing | | maxContextDocs | number | 10 | Maximum number of context documents | | maxContentLength | number | 2000 | Maximum content length to index | | contentTag | string | - | CSS selector for main content (class, id, or tag) | | searchLimit | number | 10 | Maximum number of search results | | excludeTags | string[] | [] | CSS selectors for content to exclude (id, class, or tag) | | botName | string | "ChattyGpt" | Name of the chatbot | | systemPrompt | string | Default prompt | Custom system prompt for AI responses |

API Endpoint

The integration automatically creates a /api/chatbot endpoint that accepts POST requests:

// Basic usage
const response = await fetch('/api/chatbot', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    query: 'What is this website about?',
    language: 'en',
    stream: false
  })
});

const data = await response.json();
console.log(data.answer); // AI response
console.log(data.sources); // Source documents

Request Format

interface ChatRequest {
  query: string;           // User's question
  language?: string;       // Language code (default: 'en')
  stream?: boolean;       // Enable streaming (default: false)
  messages?: Array<{      // For chat history
    role: 'user' | 'assistant';
    content: string;
  }>;
}

Response Format

interface ChatResponse {
  answer: string;         // AI-generated answer
  sources: Array<{       // Source documents
    url: string;
    title: string;
    thumbnail: string;
    snippet: string;
  }>;
}

Frontend Integration

React/Preact Example

import { useState } from 'react';

export default function ChatBot() {
  const [query, setQuery] = useState('');
  const [response, setResponse] = useState(null);
  const [loading, setLoading] = useState(false);

  const handleSubmit = async (e) => {
    e.preventDefault();
    setLoading(true);
    
    try {
      const res = await fetch('/api/chatbot', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ query, stream: false })
      });
      
      const data = await res.json();
      setResponse(data);
    } catch (error) {
      console.error('Chat error:', error);
    } finally {
      setLoading(false);
    }
  };

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          placeholder="Ask about this website..."
        />
        <button type="submit" disabled={loading}>
          {loading ? 'Searching...' : 'Ask'}
        </button>
      </form>
      
      {response && (
        <div>
          <h3>Answer:</h3>
          <p>{response.answer}</p>
          
          <h4>Sources:</h4>
          <ul>
            {response.sources.map((source, i) => (
              <li key={i}>
                <a href={source.url}>{source.title}</a>
                <p>{source.snippet}</p>
              </li>
            ))}
          </ul>
        </div>
      )}
    </div>
  );
}

Streaming Example

async function streamChat(query) {
  const response = await fetch('/api/chatbot', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ query, stream: true })
  });

  const reader = response.body.getReader();
  const decoder = new TextDecoder();

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    
    const chunk = decoder.decode(value);
    const lines = chunk.split('\n');
    
    for (const line of lines) {
      if (line.startsWith('DATA:')) {
        try {
          const data = JSON.parse(line.slice(5));
          
          if (data.type === 'text') {
            // Text content
            console.log(data.data);
          } else if (data.type === 'sources') {
            // Sources
            console.log('Sources:', data.data);
          }
        } catch (e) {
          console.error('Error parsing stream data:', e);
        }
      }
    }
  }
}

Development

This package is structured as a monorepo:

  • playground contains code for testing the package
  • packages/astro-chatty-gpt contains the actual package

Install dependencies using pnpm:

pnpm i --frozen-lockfile

Start the playground and package watcher:

pnpm dev

You can now edit files in packages/astro-chatty-gpt. Please note that making changes to those files may require restarting the playground dev server.

Troubleshooting

Common Issues

  1. "Search service unavailable" error

    • Check your Upstash credentials are correct
    • Ensure your Upstash Search Database is active
    • Verify the REST URL and token are properly set
  2. "AI service unavailable" error

    • Verify your OpenAI API key is valid
    • Check you have sufficient OpenAI credits
    • Ensure the API key has the correct permissions
  3. No search results found

    • Make sure your website has been built and indexed
    • Check the include and exclude patterns in your configuration
    • Verify your content selectors are targeting the right elements
  4. Build-time indexing fails

    • Ensure your site option is set in astro.config.mjs
    • Check that your website URLs are accessible
    • Verify your content selectors match your HTML structure

License

MIT Licensed. Made with ❤️ by unfolding.

Acknowledgements