Skip to content

Commit

Permalink
Add GPT 4 support
Browse files Browse the repository at this point in the history
  • Loading branch information
Jan Scheffler committed Mar 18, 2023
1 parent 7ed6071 commit f8a12b4
Show file tree
Hide file tree
Showing 11 changed files with 249 additions and 184 deletions.
1 change: 0 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
"@typescript-eslint"
],
"rules": {
"@typescript-eslint/naming-convention": "warn",
"@typescript-eslint/semi": "warn",
"curly": "warn",
"eqeqeq": "warn",
Expand Down
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how

## [Unreleased]

- Initial release
## [0.0.5]

### Added

- Support for GPT 4
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
# AI Code Assistant

This extension provides developers with an easy way to interact with OpenAI's ChatGPT model directly from within Visual Studio Code.
This extension provides developers with an easy way to interact with OpenAI's ChatGPT models directly from within Visual Studio Code. You can select between GPT 3 and GPT 4.

## Features

Currently, this extension only provides a user interface to ChatGPT within VS Code.

![Preview](./images/video.gif)

You can open it by typing `Code Assistant` into the command box.

## Requirements

You need to signup for an [OpenAI Account](https://platform.openai.com/signup) and get a new [API Key](https://platform.openai.com/account/api-keys).
Expand All @@ -17,13 +19,14 @@ You need to signup for an [OpenAI Account](https://platform.openai.com/signup) a
This extension contributes the following settings:

* `codeAssistantAi.openaiApiKey`: The OpenAI API Key to use
* `codeAssistantAi.openaiModel`: The OpenAI Model to use (either GPT 3 or GPT 4)

## Known Issues

None yet.

## Release Notes

### 1.0.0
### 0.0.5

Initial release of the extension.
Added support for GPT 4.
10 changes: 8 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"name": "ai-code-assistant",
"displayName": "AI Code Assistant",
"description": "Access OpenAI's ChatGPT directly from within VS Code for better productivity",
"version": "0.0.4",
"description": "Access OpenAI's ChatGPT with GPT 3 or GPT 4 directly from within VS Code for better productivity",
"version": "0.0.5",
"engines": {
"vscode": "^1.76.0"
},
Expand Down Expand Up @@ -36,6 +36,12 @@
"type": "string",
"default": "",
"markdownDescription": "API Key for OpenAI. You can find your key in your [OpenAI account](https://platform.openai.com/account/api-keys). If you don't have an account already, you can use the link to sign up.\n\n_It is considered best practice to create a new key for this extension instead of using one that you also use elsewhere._"
},
"codeAssistantAi.openaiModel": {
"type": "string",
"default": "gpt-3.5-turbo",
"enum": ["gpt-3.5-turbo", "gpt-4"],
"markdownDescription": "The model version to use. See OpenAI's [Model Overview](https://platform.openai.com/docs/models/overview) for details.\n\n _GPT 4 is in limited beta and only accessible to those who have been granted access. Please join the [waitlist](https://openai.com/waitlist/gpt-4) to get access when capacity is available._"
}
}
}
Expand Down
27 changes: 19 additions & 8 deletions src/panels/CodeAssistantPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,42 @@ import * as vscode from "vscode";
import { getUri } from "../utilities/getUri";
import { getNonce } from "../utilities/getNonce";

interface Config {
openaiApiKey: string;
openaiModel: string;
}


export class CodeAssistantPanel {
public static currentPanel: CodeAssistantPanel | undefined;
private readonly _panel: vscode.WebviewPanel;
private _disposables: vscode.Disposable[] = [];
private apiKey?: string;
private config?: Config;

private constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) {
this._panel = panel;
this._panel.onDidDispose(() => this.dispose(), null, this._disposables);
this._setWebviewMessageListener(this._panel.webview);

const config = vscode.workspace.getConfiguration('codeAssistantAi');
const apiKey = config.get<string>('openaiApiKey');
this.apiKey = apiKey;
this.loadConfig();

vscode.workspace.onDidChangeConfiguration((e: vscode.ConfigurationChangeEvent) => {
if (!e.affectsConfiguration('codeAssistantAi')) {return;}
const config = vscode.workspace.getConfiguration('codeAssistantAi');
this.apiKey = config.get<string>('openaiApiKey');
if (!e.affectsConfiguration('codeAssistantAi')) { return; }
this.loadConfig();
this._panel.webview.html = this._getWebviewContent(this._panel.webview, extensionUri);
});

this._panel.webview.html = this._getWebviewContent(this._panel.webview, extensionUri);
}

private loadConfig() {
const config = vscode.workspace.getConfiguration('codeAssistantAi');
this.config = {
openaiApiKey: config.get<string>('openaiApiKey') as string,
openaiModel: config.get<string>('openaiModel') as string,
};
}

public dispose() {
CodeAssistantPanel.currentPanel = undefined;

Expand Down Expand Up @@ -56,7 +67,7 @@ export class CodeAssistantPanel {
<link rel="stylesheet" nonce="${nonce}" href="${webviewCSSUri}" />
</head>
<body>
<script type="application/json" id="openai-api-key">${JSON.stringify(this.apiKey)}</script>
<script type="application/json" id="config">${JSON.stringify(this.config)}</script>
<div id="root"></div>
<script type="module" nonce="${nonce}" src="${webviewJSUri}"></script>
</body>
Expand Down
24 changes: 14 additions & 10 deletions src/webview/CodeAssistant.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import { VSCodeTextArea } from "@vscode/webview-ui-toolkit/react";
import ReactMarkdown from "react-markdown";
import rehypeHighlight from "rehype-highlight";
import 'highlight.js/styles/github-dark.css';
import { Message, useChatGPTCompletion } from "./chatgpt";
import { Message, useOpenAI } from "./OpenAIContext";

const CodeAssistant = () => {
const [messages, setMessages] = useState<Message[]>([]);
const [loading, setIsLoading] = useState(false);
const messagesRef = useRef<HTMLDivElement>(null);
const promptRef = useRef<HTMLElement>(null);
const chatGPTCompletion = useChatGPTCompletion();
const { complete } = useOpenAI();

useLayoutEffect(() => {
if (messagesRef.current) {
Expand All @@ -19,16 +19,20 @@ const CodeAssistant = () => {
}, [messages]);

useLayoutEffect(() => {
if (!promptRef.current) return;
if (!promptRef.current) {
return;
}
const shadowRoot = promptRef.current.shadowRoot;
if (!shadowRoot) return;
if (!shadowRoot) {
return;
}
window.setTimeout(() => {
shadowRoot.querySelector('textarea')?.focus();
}, 100);
}, [promptRef.current, loading]);

function handlePromptKeydown(e: KeyboardEvent) {
if (e.key === 'Enter') {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
const element = e.target as HTMLTextAreaElement;
sendPrompt(element.value);
Expand All @@ -40,7 +44,7 @@ const CodeAssistant = () => {
const next = [
...(previousMessages || messages),
message,
]
];
setMessages(next);
return next;
}
Expand All @@ -52,7 +56,7 @@ const CodeAssistant = () => {
content: prompt
});
let response = '';
for await (const chunk of chatGPTCompletion(messagesWithPrompt)) {
for await (const chunk of complete(messagesWithPrompt)) {
response += chunk;
setMessages([
...messagesWithPrompt,
Expand All @@ -70,10 +74,10 @@ const CodeAssistant = () => {
<div className="messages" ref={messagesRef}>
{messages.map((message, i) => (
<div
className={["message", message.role, loading && i == messages.length - 1 ? 'loading' : ''].join(' ')}
className={["message", message.role, loading && i === messages.length - 1 ? 'loading' : ''].join(' ')}
key={message.content}
>
<div className="role">{message.role == 'user' ? 'You' : 'Code Assistant'}</div>
<div className="role">{message.role === 'user' ? 'You' : 'Code Assistant'}</div>
<div className="content">
<ReactMarkdown
rehypePlugins={[[rehypeHighlight, { detect: true }]]}
Expand Down Expand Up @@ -148,6 +152,6 @@ const CodeAssistant = () => {
`}</style>
</div>
);
}
};

export default CodeAssistant;
39 changes: 39 additions & 0 deletions src/webview/ConfigContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { createContext, useContext, useEffect, useState, ReactNode } from 'react';

interface Config {
openaiApiKey: string;
openaiModel: string;
}

const ConfigContext = createContext<Config>({
openaiApiKey: '',
openaiModel: '',
});

export const ConfigProvider = ({ children }: { children: ReactNode }) => {
const [config, setConfig] = useState<Config>({
openaiApiKey: '',
openaiModel: '',
});

useEffect(() => {
const script = document.getElementById('config');

if (script && script.textContent) {
try {
const configData = JSON.parse(script.textContent);
setConfig(configData);
} catch (error) {
console.error('Failed to parse config', error);
}
}
}, []);

return (
<ConfigContext.Provider value={config}>
{children}
</ConfigContext.Provider>
);
};

export const useConfig = () => useContext(ConfigContext);
84 changes: 0 additions & 84 deletions src/webview/OpenAIApiKeyContext.tsx

This file was deleted.

0 comments on commit f8a12b4

Please sign in to comment.