Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Misc. fixes #120

Merged
merged 16 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@
| ----------------------------------- | ----------------------------------- | ----------------------------------- |
| [<img src="doc/Screenshots/WASM_C64_LastNinja.png" title="Blazor WebAssembly app, C64 Last Ninja"/>](https://highbyte.se/dotnet-6502/app) | [<img src="doc/Screenshots/SilkNetNative_C64_BubbleBobble.png" title="SilkNet native app, C64 Bubble Bobble" />](#highbytedotnet6502appsilknetnative) | [<img src="doc/Screenshots/SadConsole_C64_Basic.png" title="SadConsole native app, C64 Basic" />](#highbytedotnet6502appsadconsole) |

| Run 6502 machine code in your own .NET apps | Machine code monitor |
| ----------------------------------- | ----------------------------------- |
| ![Code integration](doc/Screenshots/Code_integration.png 'Code integration') | ![SilkNet native app, C64 monitor](doc/Screenshots/SilkNetNative_Monitor.png 'SilkNet native app, C64 monitor') |
| C64 Basic AI code completion | Run 6502 machine code in your own .NET apps | Machine code monitor |
| ----------------------------------- | ----------------------------------- | ----------------------------------- |
| ![C64 Basic AI code completion](doc/Screenshots/WASM_C64_Basic_AI.png 'C64 Basic AI code completion') | ![Code integration](doc/Screenshots/Code_integration.png 'Code integration') | ![SilkNet native app, C64 monitor](doc/Screenshots/SilkNetNative_Monitor.png 'SilkNet native app, C64 monitor') |

## Common libraries
- [`Highbyte.DotNet6502`](doc/CPU_LIBRARY.md)
Expand Down Expand Up @@ -108,6 +108,9 @@ A console application with a only UI being a machine code monitor.

<img align="top" src="doc/Screenshots/ConsoleMonitor.png" width="25%" height="25%" title="Console monitor app" />

## C64 Basic AI code completion
See [here](doc/SYSTEMS_C64_AI_CODE_COMPLETION.md)

# Limitations
> [!IMPORTANT]
> - Correct emulation of all aspects of computers such as Commodore 64 is not likely.
Expand Down
6 changes: 5 additions & 1 deletion doc/SYSTEMS_C64.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,16 @@ Current capabilities
- Timers
- IRQ
- Limited SID 6581 audio chip support
- WASM and native app UI
- WASM and native (SilkNet and SadConsole) app UI:s

# C64 programs that works and how to run them

See [`SYSTEMS_C64_COMPATIBLE_PRG.md`](SYSTEMS_C64_COMPATIBLE_PRG.md)

## C64 Basic AI code completion

See [SYSTEMS_C64_AI_CODE_COMPLETION.md`](SYSTEMS_C64_AI_CODE_COMPLETION.md)

# Implementations

- System logic [`Highbyte.DotNet6502.Systems.Commodore64`](../src/libraries/Highbyte.DotNet6502.Systems.Commodore64)
Expand Down
103 changes: 103 additions & 0 deletions doc/SYSTEMS_C64_AI_CODE_COMPLETION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<h1 align="center">Commodore64 Basic AI Code Completion</h1>

# Overview

There is an experimental AI-powered Basic coding assistant available in the [C64 emulator ](SYSTEMS_C64.md) that can be turned on. This a work in progress.

## Background

> [!NOTE]
> If AI capabilities like GitHub CoPilot were available in the 80s, how could a similar experience be had in the then existing Commodore 64 Basic editor? That was the thought experiment that lead to the idea of trying to integrate a AI coding assistant inside the C64 Basic (with existing 80s UI limitations).

## Use
> [!IMPORTANT]
> Assuming the coding assistant is [configured](#configure) correctly, the assistant can be used when writing Commodore 64 Basic programs inside the emulator.

### Turn on/off
Use the `AI Basic` checkbox or F9 to toggle assistant on/off.

### Code suggestions
- After a Basic line number has been entered, and then stopped typing for a short while, a suggestion for the rest of the line will be displayed in grey text.
- Accept the suggestion by pressing `Tab`.
- Ignore the suggestion by pressing any other key.

> [!INFORMATION]
> - Suggestions only appear after you've entered a line number (that is not followed by `REM` comment statement).
> - If no suggestion appears, it's either because the AI backend could not give any suggestion, or that the request to the AI backend failed for some reason (verify that the connection works via Config UI, see [here](#configure)).

> [!TIP]
> You can enter a Basic line with a comment (`REM` statement) and explain what you want the program to do. Then when you start typing the next several lines it will continuously suggest new code that will build up your program based on the comment.

![C64 Basic AI code completion](Screenshots/WASM_C64_Basic_AI.png 'C64 Basic AI code completion')


## Configure
> [!IMPORTANT]
> The AI coding assistant is currently available in the `WebAssembly` and `SadConsole` versions of the emulator.

### WebAssembly version
The configuration is done in the `Configuration` section -> `C64 Config` button -> `Basic AI coding assistant` section.

#### AI backend type: `CustomEndpoint` (temporarily available)
There is a _temporarily available_ AI backend that won't require your own OpenAI API key. This is currently the default setting.
- Select `AI backend type` to `CustomEndpoint`.
- Press `Test` to verify that custom endpoint is available.
- It will be a bit slower than using OpenAI directly.

> [!NOTE]
> The field `Custom endpoint API key` is currently pre-populated with a public available key for the custom endpoint (_it's not an OpenAI key_). This is for future use.

#### AI backend type: `OpenAI`
If you have your own OpenAI API key, you can connect to OpenAI directly.

> [!CAUTION]
> - Use this at your own risk. Using your own OpenAI API key will use your own credit grants. It's a good idea to set a limit in OpenAI for how much can be used.
> - You can inspect the network traffic from browser (F12 devtool) to see which (and how many) requests are done to OpenAI.
> - The OpenAI API key is only stored in your browser local storage, it's not stored on any server. This can be verified in the browser with the F12 devtool.

- Set `AI backend type` to `OpenAI`.
- Set `OpenAI API key` to the OpenAI API key.
- Press `Test` to verify that OpenAI API key works against OpenAI API.

#### AI backend type: `OpenAISelfHostedCodeLlama`
If you host your own AI model with [Ollama](https://ollama.com/), you can use a local `CodeLlama-code` model as source for the C64 Basic AI assistant.

> [!IMPORTANT]
> - With Ollama installed, download a CodeLlama-code model for example `codellama:13b-code` or `codellama:7b-code`. The larger the model the better, as long as your machine can handle it. Other types of models (non CodeLlama-code) may not work.
> - Ex. download model: `ollama pull codellama:13b-code`
> - Make sure Ollama (or any proxy in front of it) has configured [CORS Settings](https://medium.com/dcoderai/how-to-handle-cors-settings-in-ollama-a-comprehensive-guide-ee2a5a1beef0) to allow requests from the site running the WebAssembly version of the Emulator (or all *).

- Set `AI backend type` to `OpenAISelfHostedCodeLlama`.
- Set `Self-hosted OpenAI compatible endpoint (Ollama)` to the self-hosted endpoint. The default is `http://localhost:11434/api`
- Set `Model name` to a locally installed CodeLlama-code model, for example `codellama:13b-code` or `codellama:7b-code`. Other non CodeLlama-code models may not work.
- Optionally set `Self-hosted API key (optional)` if a API key is required to access the self-hosted endpoint (for example if Open WebUI is used as a proxy in front of Ollama endpoint).
- Press `Test` to verify that OpenAI API key works against OpenAI API.


#### AI backend type: `None`
If you want to disable the coding assistant.
- Set `AI backend type` to `None`.

![C64 Basic AI code completion](Screenshots/WASM_C64_Basic_AI_Config.png 'C64 Basic AI code completion')

### SadConsole version
Configure `CodingAssistant` section in `appsettings.json`.

Using OpenAI:
- `CodingAssistantType:OpenAI:CodingAssistantType`: `OpenAI`
- `CodingAssistantType:OpenAI:ApiKey`: Your own OpenAI API key
- `CodingAssistantType:OpenAI:DeploymentName`: The OpenAI model (default: `gpt-4o`)

Using self-hosted OpenAI API compatible LLM (Ollama with CodeLlama-code model):
- `CodingAssistantType:OpenAISelfHostedCodeLlama:CodingAssistantType`: `OpenAI`
- `CodingAssistantType:OpenAISelfHostedCodeLlama:EndPoint`: The local Ollama HTTP endpoint (ex: `http://localhost:11434/api`)
- `CodingAssistantType:OpenAISelfHostedCodeLlama:DeploymentName`: A local CodeLlama-code model (ex: `codellama:13b-code` or `codellama:7b-code`.)
- `CodingAssistantType:OpenAISelfHostedCodeLlama:ApiKey`: Optional. May be required if Open WebUI proxy is in front of Ollama.

Using custom AI backend:
TODO

Using no assistant:
- `CodingAssistantType:OpenAI:CodingAssistantType`: `None`

In the emulator UI, use the `C64 Config` -> Basic AI assistant -> `Test` button to verify the connection.
2 changes: 1 addition & 1 deletion doc/SYSTEMS_C64_COMPATIBLE_PRG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<h1 align="center">Compatible C64 programs</h1>

A list of applications that seem to work decently with the C64 emulator.
A list of applications that seem to work decently with the [C64 emulator](SYSTEMS_C64.md).

> **Limitations:**<br>
> - The C64 emulator currently lacks support for the C64 disk and tape drives. Therefore programs must be loaded from the emulator menu (or monitor) as **.prg** files from the host OS file system. Also, any loaded .prg file that tries to access the C64 disk or tape drive most likely will not work (hang).
Expand Down
Binary file modified doc/Screenshots/SadConsole_C64_Basic.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/Screenshots/WASM_C64_Basic.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/Screenshots/WASM_C64_Basic_AI.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/Screenshots/WASM_C64_Basic_AI_Config.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/Screenshots/WASM_C64_LastNinja.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/Screenshots/WASM_C64_Monitor.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,15 @@ private void DrawUIItems()
// AI coding assistant selection
var codingAssistantLabel = CreateLabel("Basic AI assistant: ", 1, romDownloadLinkTextBox.Bounds.MaxExtentY + 3);
var codingAssistantValue = CreateLabel($"{C64HostConfig.CodeSuggestionBackendType}", codingAssistantLabel.Bounds.MaxExtentX + 1, codingAssistantLabel.Position.Y);
codingAssistantValue.TextColor = Controls.GetThemeColors().White;

var codingAssistantInfoLabel = new Label(Width - 10)
{
Name = "codingAssistantInfoLabel",
Position = (1, codingAssistantValue.Bounds.MaxExtentY + 1),
IsEnabled = false,
DisplayText = "Set AI assistant in appsetting.json",
DisplayText = "Set AI assistant in appsetting.json.",
TextColor = Controls.GetThemeColors().Appearance_ControlDisabled.Foreground
};
Controls.Add(codingAssistantInfoLabel);

Expand All @@ -159,7 +161,10 @@ private void DrawUIItems()
{
try
{
var codeSuggestionBackend = CodeSuggestionConfigurator.CreateCodeSuggestion(C64HostConfig.CodeSuggestionBackendType, _configuration, C64BasicCodingAssistant.CODE_COMPLETION_LANGUAGE_DESCRIPTION);
var codeSuggestionBackend = CodeSuggestionConfigurator.CreateCodeSuggestion(C64HostConfig.CodeSuggestionBackendType, _configuration, C64BasicCodingAssistant.CODE_COMPLETION_LANGUAGE_DESCRIPTION, C64BasicCodingAssistant.CODE_COMPLETION_ADDITIONAL_SYSTEM_INSTRUCTION);
codingAssistantInfoLabel.DisplayText = "Testing...";
codingAssistantInfoLabel.TextColor = Color.White;

await codeSuggestionBackend.CheckAvailability();
if (codeSuggestionBackend.IsAvailable)
{
Expand All @@ -180,6 +185,14 @@ private void DrawUIItems()
};
Controls.Add(codingAssistantTestButton);

var openBasicAIHelpURLButton = new Button("Help")
{
Name = "openBasicAIHelpURLButton",
Position = (codingAssistantTestButton.Bounds.MaxExtentX, codingAssistantInfoLabel.Position.Y),
};
openBasicAIHelpURLButton.Click += (s, e) => OpenURL("https://github.com/highbyte/dotnet-6502/blob/master/doc/SYSTEMS_C64_AI_CODE_COMPLETION.md");
Controls.Add(openBasicAIHelpURLButton);


//ComboBox codingAssistantComboBox = new ComboBox(codingAssistantLabel.Bounds.MaxExtentX + 1, codingAssistantLabel.Position.Y, 6, Enum.GetNames<CodeSuggestionBackendTypeEnum>().ToArray())
//{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ private void SetControlStates()
public async Task ToggleBasicAIAssistant()
{
var c64aiBasicAssistantCheckbox = Controls["c64aiBasicAssistantCheckbox"] as CheckBox;
await SetBasicAIAssistant(!c64aiBasicAssistantCheckbox.IsSelected);
c64aiBasicAssistantCheckbox.IsSelected = !c64aiBasicAssistantCheckbox.IsSelected;
}

private async Task SetBasicAIAssistant(bool enabled)
Expand Down
8 changes: 8 additions & 0 deletions src/apps/Highbyte.DotNet6502.App.SadConsole/InfoConsole.cs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,14 @@ Label CreateLabel(string text, int col, int row, string? name = null)
CreateLabel("Change text color 9-16", colTab1, row, Controls.ThemeColors.ControlHostForeground);
CreateLabel("C= + numbers 1-8", colTab2, row, Controls.ThemeColors.ControlHostForeground);
CreateLabel("LeftCtrl + numbers 1-8", colTab3, row, Controls.ThemeColors.ControlHostForeground);
row++;
CreateLabel("AI Basic: accept suggestion", colTab1, row, Controls.ThemeColors.ControlHostForeground);
CreateLabel("CTRL", colTab2, row, Controls.ThemeColors.ControlHostForeground);
CreateLabel("Tab", colTab3, row, Controls.ThemeColors.ControlHostForeground);
row++;
CreateLabel("AI Basic: ignore suggestion", colTab1, row, Controls.ThemeColors.ControlHostForeground);
CreateLabel("Any other key than CTRL", colTab2, row, Controls.ThemeColors.ControlHostForeground);
CreateLabel("Any other key than Tab", colTab3, row, Controls.ThemeColors.ControlHostForeground);

Label CreateLabel(string text, int col, int row, Color? textColor = null, string? name = null)
{
Expand Down
12 changes: 10 additions & 2 deletions src/apps/Highbyte.DotNet6502.App.SadConsole/SadConsoleHostApp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,7 @@ public void DisableMonitor()
_monitorStatusConsole.Disable();
OnMonitorStateChange(monitorEnabled: false);
}

public void EnableMonitor(ExecEvaluatorTriggerResult? execEvaluatorTriggerResult = null)
{
_monitorConsole.Enable(execEvaluatorTriggerResult);
Expand Down Expand Up @@ -589,17 +590,24 @@ private async Task HandleUIKeyboardInput()
// ToggleLogs();

if (keyboard.IsKeyPressed(Keys.F11))
{
keyboard.Clear();
ToggleInfo();
}

if (keyboard.IsKeyPressed(Keys.F12) && (EmulatorState == EmulatorState.Running || EmulatorState == EmulatorState.Paused))
if (keyboard.IsKeyReleased(Keys.F12) && (EmulatorState == EmulatorState.Running || EmulatorState == EmulatorState.Paused))
{
keyboard.Clear();
ToggleMonitor();
}

if (keyboard.IsKeyPressed(Keys.F9) && EmulatorState == EmulatorState.Running)
if (keyboard.IsKeyReleased(Keys.F9) && EmulatorState == EmulatorState.Running)
{
keyboard.Clear();
if (_systemMenuConsole is C64MenuConsole c64MenuConsole)
{
await c64MenuConsole.ToggleBasicAIAssistant();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ NAudioAudioHandlerContext audioHandlerContext

var renderer = new C64SadConsoleRenderer(c64, renderContext);

ICodeSuggestion codeSuggestion = CodeSuggestionConfigurator.CreateCodeSuggestion(c64HostConfig.CodeSuggestionBackendType, _configuration, C64BasicCodingAssistant.CODE_COMPLETION_LANGUAGE_DESCRIPTION, defaultToNoneIdConfigError: true);
ICodeSuggestion codeSuggestion = CodeSuggestionConfigurator.CreateCodeSuggestion(c64HostConfig.CodeSuggestionBackendType, _configuration, C64BasicCodingAssistant.CODE_COMPLETION_LANGUAGE_DESCRIPTION, C64BasicCodingAssistant.CODE_COMPLETION_ADDITIONAL_SYSTEM_INSTRUCTION , defaultToNoneIdConfigError: true);
var c64BasicCodingAssistant = new C64BasicCodingAssistant(c64, codeSuggestion, _loggerFactory);
var inputHandler = new C64SadConsoleInputHandler(c64, inputHandlerContext, _loggerFactory, c64BasicCodingAssistant, c64HostConfig.BasicAIAssistantDefaultEnabled);

Expand Down
9 changes: 8 additions & 1 deletion src/apps/Highbyte.DotNet6502.App.SadConsole/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,15 @@
//"Endpoint": "https://YOUR_ACCOUNT.openai.azure.com/"
},

"OpenAISelfHostedCodeLlama": {
"Endpoint": "http://localhost:11434/api",
//"DeploymentName": "codellama:7b-code", // Works sometimes (must be a CodeLlama:xxx-code model to work).
"DeploymentName": "codellama:13b-code" // Works ok (must be a CodeLlama:xxx-code model to work)
//"ApiKey": "[SET IN DOTNET USER SECRETS]" // API key may not be required for self-hosted
},

"CustomEndpoint": {
// Set to true to use special endpoint that encapsulates code completion requests and forwards to OpenAI API (no OpenAI key is required on client, instead a API key for the custom endpoint)
// A custom endpoint that encapsulates code completion requests and forwards to OpenAI API (no OpenAI key is required on client, instead a API key for the custom endpoint)
"Endpoint": "",

// dotnet user-secrets set "CodingAssistant:CustomEndpoint:ApiKey" "[MY API KEY]"
Expand Down
Loading
Loading