Coding Assistant (POC)

This example demonstrates how to use Vapi assistant to generate code and update the state of code in sandpack to make a live coding assistant.

Preview

Coding Assistant

Conversation

Code

Copy the following code to your component file for example ai-coder.tsx.

import React, { useEffect, useState } from "react";
import {
  SandpackProvider,
  SandpackPreview,
  useSandpack,
  SandpackLayout,
  SandpackStack,
  FileTabs,
} from "@codesandbox/sandpack-react";
import Editor from "@monaco-editor/react";
import useVapi from "@/hooks/code-assistant";
 
interface LayoutProps {
  children: React.ReactNode;
}
 
const Layout: React.FC<LayoutProps> = ({ children }) => (
  <div className="flex flex-col items-center p-4 min-h-full w-full">
    <div className="w-full">{children}</div>
  </div>
);
 
interface TranscriberProps {
  conversation: Array<{ role: string; text: string; timestamp: string }>;
}
 
const Transcriber: React.FC<TranscriberProps> = ({ conversation }) => (
  <div className="p-4 border-t-2 mt-4">
    <h2 className="text-lg font-semibold">Conversation</h2>
    <div className="max-h-64 overflow-y-auto">
      {conversation.map((msg, index) => (
        <div key={index} className="mt-2">
          <strong>{msg.role}:</strong> {msg.text}{" "}
          <span className="text-gray-500 text-xs">{msg.timestamp}</span>
        </div>
      ))}
    </div>
  </div>
);
 
interface MonacoEditorProps {
  code: string;
}
 
const getLanguageOfFile = (filePath: string) => {
  const ext = filePath.split('.').pop();
  switch (ext) {
    case 'js':
    case 'jsx':
      return 'javascript';
    case 'ts':
    case 'tsx':
      return 'typescript';
    case 'vue':
      return 'vue';
    case 'html':
      return 'html';
    case 'css':
      return 'css';
    case 'json':
      return 'json';
    default:
      return 'plaintext';
  }
};
 
const MonacoEditor: React.FC<MonacoEditorProps> = ({ code }) => {
  const { sandpack } = useSandpack();
  const language = getLanguageOfFile(sandpack.activeFile);
 
  return (
    <SandpackStack style={{ height: "50vh", margin: 0 }}>
      <FileTabs />
      <div style={{ flex: 1, paddingTop: 8 }}>
        <Editor
          width="100%"
          height="100%"
          language={language}
          theme="vs-dark"
          value={code}
        />
      </div>
    </SandpackStack>
  );
};
 
const VapiDemoComponent: React.FC = () => {
  const { isSessionActive, conversation, toggleCall, code } = useVapi();
  const [showSandpack, setShowSandpack] = useState(false);
 
  useEffect(() => {
    if (code && code.length > 5) {
      setShowSandpack(true);
    }
  }, [code]);
 
  const files = {
    "/pages/index.js": code,
  };
 
  return (
    <Layout>
      <div className="flex justify-between items-center p-4 w-full">
        <h1 className="text-xl font-bold">Coding Assistant</h1>
        <button
          className={`px-4 py-2 rounded ${isSessionActive ? "bg-red-500" : "bg-green-500"} text-white`}
          onClick={toggleCall}
        >
          {isSessionActive ? "Stop Call" : "Start Call"}
        </button>
      </div>
 
      {showSandpack && code && (
        <div className="mt-4 min-h-5xl w-full">
          <SandpackProvider template="nextjs" files={files}>
            <SandpackLayout>
              <MonacoEditor code={code} />
              <SandpackPreview style={{ height: "50vh" }} />
            </SandpackLayout>
          </SandpackProvider>
        </div>
      )}
      <Transcriber conversation={conversation} />
    </Layout>
  );
};
 
export default VapiDemoComponent;