From 7d6db315d530ea6cb9511abfa493b4b8b9de46b9 Mon Sep 17 00:00:00 2001 From: arshad Date: Tue, 20 Aug 2024 00:06:18 +0530 Subject: [PATCH] Update docs --- docs/components/footer.tsx | 6 +----- docs/constants.ts | 1 - docs/pages/docs/copilot-cost-overview.mdx | 12 ++++++------ docs/pages/docs/copilot-options.mdx | 16 +++++++++++----- docs/pages/docs/faq.mdx | 6 +----- docs/pages/docs/index.mdx | 4 ---- docs/pages/docs/nextjs.mdx | 4 +++- src/classes/completion-formatter.ts | 11 +++++++++++ src/classes/copilot.ts | 22 ++++++++++++++-------- src/constants/completion.ts | 14 +++++++------- src/core/handler.ts | 12 +++++------- src/core/register.ts | 3 --- src/error.ts | 11 ++++++++--- src/helpers/completion.ts | 4 +--- src/helpers/prompt.ts | 2 +- src/types/completion.ts | 10 +++++----- src/utils/completion.ts | 1 + test/src/app/api/copilot/route.ts | 6 +++--- 18 files changed, 78 insertions(+), 67 deletions(-) diff --git a/docs/components/footer.tsx b/docs/components/footer.tsx index a0fb2e5a..aaa2d27b 100644 --- a/docs/components/footer.tsx +++ b/docs/components/footer.tsx @@ -4,11 +4,7 @@ import React from 'react'; import Link from 'next/link'; import ThemeToggle from '@/components/theme-toggle'; -import { - CREATOR_NAME, - CREATOR_TWITTER_URL, - GROQ_HOMEPAGE_URL, -} from '@/constants'; +import {CREATOR_NAME, CREATOR_TWITTER_URL} from '@/constants'; const Footer = () => { return ( diff --git a/docs/constants.ts b/docs/constants.ts index 6480bc33..399a6a57 100644 --- a/docs/constants.ts +++ b/docs/constants.ts @@ -8,4 +8,3 @@ export const WEBSITE_URL = 'https://monacopilot.vercel.app'; export const WEBSITE_DOMAIN = 'monacopilot.vercel.app'; export const CREATOR_NAME = 'Arshad Yaseen'; export const CREATOR_TWITTER_URL = 'https://twitter.com/arshadyaseeen'; -export const GROQ_HOMEPAGE_URL = 'https://groq.com'; diff --git a/docs/pages/docs/copilot-cost-overview.mdx b/docs/pages/docs/copilot-cost-overview.mdx index 4d9d06de..2c1bb5da 100644 --- a/docs/pages/docs/copilot-cost-overview.mdx +++ b/docs/pages/docs/copilot-cost-overview.mdx @@ -6,13 +6,13 @@ import { Callout } from 'nextra/components' # Copilot Cost Overview -Monacopilot utilizes the Groq API for AI auto-completion. The cost of completions is very affordable. See the table below for an estimate of the costs you will need to pay Groq for completions. +The cost of completions is very affordable. See the table below for an estimate of the costs you will need to pay for completions. -| Model Name | Average cost per 1000 Code Completions | Completion Speed | -|-----------------|-----------------------------------------| -----------------| -| llama | $0.345 | normal | -| llama | $0.789 | little-faster | +| Provider | Model | Average cost per 1000 Code Completions | +|------------|-------------|----------------------------------------| +| Groq | llama-3-70b | $0.939 | +| OpenAI | gpt-4o | $3.46 | - The cost is calculated based on the [Groq pricing](https://wow.groq.com/). + Currently, Groq does not implement billing, allowing free usage of their API. During this free period, you will experience minimal rate limiting and some latency in completions. You can opt for Groq's enterprise plan to benefit from increased rate limits and get quick completions without visible latency. If you choose not to take the enterprise plan, you will need to wait for Groq to implement billing, which they plan to do soon. \ No newline at end of file diff --git a/docs/pages/docs/copilot-options.mdx b/docs/pages/docs/copilot-options.mdx index 332d8ae6..ca08dec4 100644 --- a/docs/pages/docs/copilot-options.mdx +++ b/docs/pages/docs/copilot-options.mdx @@ -35,17 +35,23 @@ By providing external context, Copilot can offer more intelligent suggestions. F Note: Including more external context may slightly increase completion costs. -### Changing the Default Model +### Changing the Provider and Model -You can specify a different model for completions by setting the `model` parameter in the `Copilot` constructor. +You can specify a different provider and model for completions by setting the `provider` and `model` parameters in the `Copilot` constructor. ```javascript -const copilot = new Copilot(process.env.GROQ_API_KEY, { - model: 'falcon' +const copilot = new Copilot(process.env.OPENAI_API_KEY, { + provider: 'openai', + model: 'gpt-4o' }); ``` -The default model is `llama` if not specified. +The default provider is `groq` and the default model is `llama-3-70b` if not specified. + +| Provider | Model | Description | Average Response Time | +|----------|-------------|----------------------------------------------------|------------------------| +| Groq | llama-3-70b | Fast and efficient, suitable for most tasks | < 0.5 second | +| OpenAI | gpt-4o | Highly intelligent, ideal for complex completions | 1-2 seconds | ### Filename diff --git a/docs/pages/docs/faq.mdx b/docs/pages/docs/faq.mdx index 01d85da7..24fc0ece 100644 --- a/docs/pages/docs/faq.mdx +++ b/docs/pages/docs/faq.mdx @@ -17,10 +17,6 @@ export function FAQBox({ title, children }) { ) } - - AI Auto Completion utilizes the Llama 3 70b model by default, supplemented by other open source LLMs from Groq. We chose Groq for its speed, crucial for rapid code completion. The system also leverages the current state and context of the editor, employing contextual filtering and various techniques. This approach ensures that completions are not only fast but also contextually relevant and responsive. - - - You use your own Groq API key for AI auto-completion. You can obtain an API key from [Groq console](https://console.groq.com). The cost of completions is very affordable, and we implement various methods to minimize these costs as much as possible. Costs vary depending on the model you use; see this [copilot cost overview table](/docs/copilot-cost-overview) for an idea of the cost. + You use your own Groq or OpenAI API key for AI auto-completion. The cost of completions is very affordable, and we implement various methods to minimize these costs as much as possible. Costs vary depending on the model you use; see this [copilot cost overview table](/docs/copilot-cost-overview) for an idea of the cost. \ No newline at end of file diff --git a/docs/pages/docs/index.mdx b/docs/pages/docs/index.mdx index 9d7460b5..3554527e 100644 --- a/docs/pages/docs/index.mdx +++ b/docs/pages/docs/index.mdx @@ -5,10 +5,6 @@ import { MagicWandIcon } from "@radix-ui/react-icons"; **Monacopilot** integrates AI auto-completion into the Monaco Editor, inspired by GitHub Copilot. - - Currently, Groq does not implement billing, allowing free usage of their API. During this free period, you will experience minimal rate limiting and some latency in completions. You can opt for Groq's enterprise plan to benefit from increased rate limits and get quick completions without visible latency. If you choose not to take the enterprise plan, you will need to wait for Groq to implement billing, which they plan to do soon. - - ### Installation First, install Monacopilot using your preferred package manager. diff --git a/docs/pages/docs/nextjs.mdx b/docs/pages/docs/nextjs.mdx index d093165b..79e434eb 100644 --- a/docs/pages/docs/nextjs.mdx +++ b/docs/pages/docs/nextjs.mdx @@ -12,6 +12,8 @@ This guide walks you through integrating AI auto-completion into your Next.js pr ### Setting Up the API Key +In this example, we use Groq as the provider. + Start by obtaining an API key from the [Groq console](https://console.groq.com/keys). Once you have your API key, define it as an environment variable in your project: ```bash filename=".env.local" @@ -53,7 +55,7 @@ Set up an API handler to manage auto-completion requests. -Monacopilot use this API endpoint to fetch completions for the editor. +The default provider is `Groq` and the default model is `llama-3-70b`. See the [Changing the Provider and Model](/docs/copilot-options#changing-the-provider-and-model) guide for more details. ### Install Monaco Editor diff --git a/src/classes/completion-formatter.ts b/src/classes/completion-formatter.ts index f28085ef..78bee59e 100644 --- a/src/classes/completion-formatter.ts +++ b/src/classes/completion-formatter.ts @@ -91,6 +91,17 @@ export class CompletionFormatter { return this; } + public removeMarkdownCodeSyntax(): CompletionFormatter { + const markdownCodeRegex = /^```[\s\S]*?\n([\s\S]*?)\n```$/; + const match = this.formattedCompletion.match(markdownCodeRegex); + + if (match) { + this.formattedCompletion = match[1].trim(); + } + + return this; + } + public trimStart(): CompletionFormatter { const firstNonSpaceIndex = this.formattedCompletion.search(/\S/); if (firstNonSpaceIndex > this.cursorPosition.column - 1) { diff --git a/src/classes/copilot.ts b/src/classes/copilot.ts index cb9756ed..5cc36792 100644 --- a/src/classes/copilot.ts +++ b/src/classes/copilot.ts @@ -22,7 +22,7 @@ import { import {HTTP, joinWithAnd} from '../utils'; /** - * Copilot class for handling completions using the Groq API. + * Copilot class for handling completions using the API. */ export class Copilot { private readonly apiKey: string; @@ -31,22 +31,25 @@ export class Copilot { /** * Initializes the Copilot with an API key and optional configuration. - * @param {string} apiKey - The Groq API key. + * @param {string} apiKey - The API key. * @param {CopilotOptions} [options] - Optional parameters to configure the completion model. * @throws {Error} If the API key is not provided. */ constructor(apiKey: string, options?: CopilotOptions) { + const model = options?.model || DEFAULT_COMPLETION_MODEL; + const provider = options?.provider || DEFAULT_COMPLETION_PROVIDER; + if (!apiKey) { - throw new Error('Groq API key is required to initialize Copilot.'); + throw new Error(`Please provide ${provider} API key.`); } this.apiKey = apiKey; - this.model = options?.model || DEFAULT_COMPLETION_MODEL; - this.provider = options?.provider || DEFAULT_COMPLETION_PROVIDER; + this.model = model; + this.provider = provider; } /** - * Sends a completion request to Groq API and returns the completion. + * Sends a completion request to API and returns the completion. * @param {CompletionRequest} params - The metadata required to generate the completion. * @returns {Promise} The completed text snippet or an error. */ @@ -70,8 +73,11 @@ export class Copilot { return {completion: completion.choices[0].message.content}; } catch (_err) { - handleError(_err, ErrorContext.COPILOT_COMPLETION_FETCH); - return {error: 'Failed to fetch completion', completion: null}; + const errorDetails = handleError( + _err, + ErrorContext.COPILOT_COMPLETION_FETCH, + ); + return {error: errorDetails.message, completion: null}; } } diff --git a/src/constants/completion.ts b/src/constants/completion.ts index b1a549a6..64c85a56 100644 --- a/src/constants/completion.ts +++ b/src/constants/completion.ts @@ -1,23 +1,23 @@ import { + CompletionCreateParamsExcludingModelAndMessages, CompletionModel, CompletionProvider, - GroqCompletionCreateParamsExcludingModelAndMessages, } from '../types'; export const COMPLETION_MODEL_IDS: Record = { - llama: 'llama3-70b-8192', - 'gpt-4o-mini': 'gpt-4o-mini', + 'llama-3-70b': 'llama3-70b-8192', + 'gpt-4o': 'gpt-4o-2024-08-06', }; export const COMPLETION_PROVIDER_MODEL_MAP: Record< CompletionProvider, CompletionModel[] > = { - groq: ['llama'], - openai: ['gpt-4o-mini'], + groq: ['llama-3-70b'], + openai: ['gpt-4o'], }; -export const DEFAULT_COMPLETION_MODEL: CompletionModel = 'llama'; +export const DEFAULT_COMPLETION_MODEL: CompletionModel = 'llama-3-70b'; export const DEFAULT_COMPLETION_PROVIDER: CompletionProvider = 'groq'; export const COMPLETION_API_ENDPOINT: Record = { @@ -25,7 +25,7 @@ export const COMPLETION_API_ENDPOINT: Record = { openai: 'https://api.openai.com/v1/chat/completions', }; -export const DEFAULT_COMPLETION_CREATE_PARAMS: GroqCompletionCreateParamsExcludingModelAndMessages = +export const DEFAULT_COMPLETION_CREATE_PARAMS: CompletionCreateParamsExcludingModelAndMessages = { temperature: 0.3, }; diff --git a/src/core/handler.ts b/src/core/handler.ts index ad287cd5..c924c506 100644 --- a/src/core/handler.ts +++ b/src/core/handler.ts @@ -13,7 +13,7 @@ import { formatCompletion, } from '../utils/completion'; -const DEBOUNCE_DELAY = 350; +const DEBOUNCE_DELAY = 300; const debouncedFetchCompletionItem = debounce( fetchCompletionItem, @@ -57,17 +57,15 @@ const handleInlineCompletions = async ({ } try { - const abortController = new AbortController(); - token.onCancellationRequested(() => { - abortController.abort(); - }); - const completionPromise = debouncedFetchCompletionItem({ ...options, text: model.getValue(), model, position, - abortSignal: abortController.signal, + }); + + token.onCancellationRequested(() => { + debouncedFetchCompletionItem.cancel(); }); const completion = await completionPromise; diff --git a/src/core/register.ts b/src/core/register.ts index 4bc286d5..6db74a50 100644 --- a/src/core/register.ts +++ b/src/core/register.ts @@ -73,9 +73,6 @@ export const registerCopilot = ( return { deregister: () => { disposables.forEach(disposable => disposable.dispose()); - console.warn( - 'Copilot deregistered due to an error during registration.', - ); }, }; } diff --git a/src/error.ts b/src/error.ts index 0a325cf3..847456a0 100644 --- a/src/error.ts +++ b/src/error.ts @@ -5,10 +5,12 @@ export class ErrorHandler { return ErrorHandler.instance; } - public handleError(error: unknown, context: ErrorContext): void { + public handleError(error: unknown, context: ErrorContext): ErrorDetails { const errorDetails = this.getErrorDetails(error); this.logError(context, errorDetails); + + return errorDetails; } private getErrorDetails(error: unknown): ErrorDetails { @@ -89,6 +91,9 @@ interface ErrorDetails { context?: any; } -export const handleError = (error: unknown, context: ErrorContext): void => { - ErrorHandler.getInstance().handleError(error, context); +export const handleError = ( + error: unknown, + context: ErrorContext, +): ErrorDetails => { + return ErrorHandler.getInstance().handleError(error, context); }; diff --git a/src/helpers/completion.ts b/src/helpers/completion.ts index 39fc5c9e..662a252a 100644 --- a/src/helpers/completion.ts +++ b/src/helpers/completion.ts @@ -13,7 +13,7 @@ import {getTextAfterCursor, getTextBeforeCursor, HTTP} from '../utils'; const CONTENT_TYPE_JSON = 'application/json'; /** - * Fetches a completion item from the groq API. + * Fetches a completion item from the API. * @param {FetchCompletionItemParams} params - The parameters for fetching the completion item. * @returns {Promise} The completion item or null if an error occurs or the request is aborted. */ @@ -25,7 +25,6 @@ export const fetchCompletionItem = async ({ externalContext, model, position, - abortSignal, }: FetchCompletionItemParams): Promise => { try { const {completion} = await HTTP.POST( @@ -43,7 +42,6 @@ export const fetchCompletionItem = async ({ { headers: {'Content-Type': CONTENT_TYPE_JSON}, error: 'Error while fetching completion item', - signal: abortSignal, }, ); diff --git a/src/helpers/prompt.ts b/src/helpers/prompt.ts index f79cc5b0..2e159058 100644 --- a/src/helpers/prompt.ts +++ b/src/helpers/prompt.ts @@ -86,7 +86,7 @@ export const generateUserPrompt = (metadata: CompletionMetadata): string => { prompt += ` - Optimize for readability and performance where possible. - Remember, output only the necessary completion code without any additional explanations or content. + Remember to output only the completion code without any additional explanation, and do not wrap it in markdown code syntax, such as three backticks (\`\`\`). Here's the code snippet for completion: diff --git a/src/types/completion.ts b/src/types/completion.ts index 437fb075..9307c487 100644 --- a/src/types/completion.ts +++ b/src/types/completion.ts @@ -10,12 +10,13 @@ import { import {Endpoint, ExternalContext, Filename, Technologies} from './copilot'; import {EditorModel, EditorPosition, EditorRange} from './monaco'; -export type CompletionModel = 'llama' | 'gpt-4o-mini'; +export type CompletionModel = 'llama-3-70b' | 'gpt-4o'; export type CompletionProvider = 'openai' | 'groq'; -export type CompletionCreateParams = - | OpenAIChatCompletionCreateParamsBase - | GroqChatCompletionCreateParamsBase; +export type CompletionCreateParams = Omit< + OpenAIChatCompletionCreateParamsBase | GroqChatCompletionCreateParamsBase, + 'frequence_penalty' +>; export type Completion = OpenAIChatCompletion | GroqChatCompletion; export type CompletionCreateParamsExcludingModelAndMessages = Omit< @@ -60,7 +61,6 @@ export interface FetchCompletionItemParams { externalContext?: ExternalContext; model: EditorModel; position: EditorPosition; - abortSignal: AbortSignal; } export type CompletionCacheItem = { diff --git a/src/utils/completion.ts b/src/utils/completion.ts index e57bfe25..e978c34b 100644 --- a/src/utils/completion.ts +++ b/src/utils/completion.ts @@ -44,6 +44,7 @@ export function formatCompletion( .removeDuplicatesFromStartOfCompletion() .preventDuplicateLines() .removeInvalidLineBreaks() + .removeMarkdownCodeSyntax() .trimStart() .build(); } diff --git a/test/src/app/api/copilot/route.ts b/test/src/app/api/copilot/route.ts index 51716891..1da7ebdc 100644 --- a/test/src/app/api/copilot/route.ts +++ b/test/src/app/api/copilot/route.ts @@ -1,8 +1,8 @@ import {Copilot} from 'monacopilot'; -const copilot = new Copilot(process.env.GROQ_API_KEY!, { - provider: 'groq', - model: 'gpt-4o-mini', +const copilot = new Copilot(process.env.OPENAI_API_KEY, { + provider: 'openai', + model: 'gpt-4o', }); export async function POST(req: Request) {