Skip to content

Web

Get information about a website.

src/skills/web.ts
import { Context } from "@xmtp/message-kit";
import type { Skill } from "@xmtp/message-kit";
import OpenAI from "openai";
 
const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});
 
export const web: Skill[] = [
  {
    skill: "web",
    examples: ["/web https://message-kit.org"],
    handler: handler,
    description: "Get information about a website.",
    params: {
      url: {
        type: "url",
      },
    },
  },
];
 
export async function handler(context: Context) {
  const {
    message: {
      content: {
        params: { url },
      },
    },
  } = context;
 
  try {
    const response = await fetch(url);
    if (!response.ok) {
      return {
        code: response.status,
        message: `Unable to access website: ${response.statusText}`,
      };
    }
 
    const html = await response.text();
    const content = extractContent(html);
    const summary = await getAISummary(content, url);
 
    return {
      code: 200,
      message: summary,
    };
  } catch (error: any) {
    return {
      code: 500,
      message: `Could not analyze website: ${error.message}`,
    };
  }
}
 
function extractContent(html: string): string {
  // Remove scripts and style elements
  html = html
    .replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "")
    .replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, "");
 
  // Get text content
  const text = html
    .replace(/<[^>]+>/g, " ")
    .replace(/\s+/g, " ")
    .trim()
    .slice(0, 1000);
 
  return text;
}
 
async function getAISummary(content: string, url: string): Promise<string> {
  const completion = await openai.chat.completions.create({
    messages: [
      {
        role: "user",
        content: `What is ${url} about? Summarize it in 2-3 sentences based on the following content: \n${content}\n\nDon't include any pretext but include the url in the summary.`,
      },
    ],
    model: "gpt-4o-mini",
  });
 
  return (
    completion.choices[0].message.content ||
    "Could not generate summary. Please visit the website directly."
  );
}