Skip to content
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
4f2598f
Add JavaFX dependencies and set up main class.
svntax Jun 21, 2025
e00486e
Set up MVCI framework for the GUI chatbox.
svntax Jun 23, 2025
f65a1f6
Implement run inference button.
svntax Jun 24, 2025
44c9750
Implement Browse button for Llama3 path.
svntax Jun 24, 2025
a0ce181
Implement Reload button for scanning for model files.
svntax Jun 24, 2025
f21cec1
Change output text area to autoscroll to the bottom.
svntax Jun 24, 2025
a281461
Change buttons to be disabled while inference is running.
svntax Jun 24, 2025
ad22925
Adjust buttons, labels, and container nodes for GUI chatbox.
svntax Jun 25, 2025
7c29d68
Add AtlantaFX for new theme styles.
svntax Jun 25, 2025
c43f7a9
Decrease padding between left and right panels.
svntax Jun 25, 2025
bed9b66
Remove unused import
svntax Jun 25, 2025
eb454a7
Remove the need for setting Llama3 path.
svntax Jun 26, 2025
f1b565f
Modify LlamaApp and llama-tornado to support GUI mode.
svntax Jun 26, 2025
03ee28c
Refactor chatbox interactor to run models directly.
svntax Jun 27, 2025
bc43b28
Fix width for engine dropdown menu and remove unused import.
svntax Jun 27, 2025
d381457
Add dropdown menu for chat mode selection.
svntax Jun 28, 2025
6937602
Change USE_TORNADOVM flag into a regular member variable.
svntax Jul 4, 2025
2e2408f
Implement interactive mode for GUI chatbox.
svntax Jul 7, 2025
480336e
Disable GUI controls while an interactive chat is running.
svntax Jul 7, 2025
b898006
Merge branch 'main' of https://github.com/svntax/GPULlama3.java into …
svntax Jul 7, 2025
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
21 changes: 21 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,18 @@
<artifactId>tornado-runtime</artifactId>
<version>1.1.1-dev</version>
</dependency>

<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>21</version>
</dependency>

<dependency>
<groupId>io.github.mkpaz</groupId>
<artifactId>atlantafx-base</artifactId>
<version>2.0.1</version>
</dependency>
</dependencies>

<build>
Expand Down Expand Up @@ -68,6 +80,15 @@
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.8</version>
<configuration>
<mainClass>com.example.gui.LlamaChatbox</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
36 changes: 36 additions & 0 deletions src/main/java/com/example/gui/ChatboxController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.example.gui;

import javafx.concurrent.Task;
import javafx.scene.layout.Region;

public class ChatboxController {

private final ChatboxViewBuilder viewBuilder;
private final ChatboxInteractor interactor;

public ChatboxController() {
ChatboxModel model = new ChatboxModel();
interactor = new ChatboxInteractor(model);
viewBuilder = new ChatboxViewBuilder(model, this::runInference);
}

private void runInference(Runnable postRunAction) {
Task<Void> inferenceTask = new Task<>() {
@Override
protected Void call() {
interactor.runLlamaTornado();
return null;
}
};
inferenceTask.setOnSucceeded(evt -> {
postRunAction.run();
});
Thread inferenceThread = new Thread(inferenceTask);
inferenceThread.start();
}

public Region getView() {
return viewBuilder.build();
}

}
89 changes: 89 additions & 0 deletions src/main/java/com/example/gui/ChatboxInteractor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package com.example.gui;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ChatboxInteractor {

private final ChatboxModel model;

public ChatboxInteractor(ChatboxModel viewModel) {
this.model = viewModel;
}

// Run the 'llama-tornado' script in the given Llama3 path, and stream its output to the GUI's output area.
public void runLlamaTornado() {
List<String> commands = new ArrayList<>();

String llama3Path = model.getLlama3Path();
if (llama3Path == null || llama3Path.isEmpty()) {
model.setOutputText("Please set the Llama3 path:");
return;
}

// Format for running 'llama-tornado' depends on the operating system.
if (System.getProperty("os.name").startsWith("Windows")) {
commands.add(String.format("%s\\external\\tornadovm\\.venv\\Scripts\\python", llama3Path));
commands.add("llama-tornado");
} else {
commands.add(String.format("%s/.llama-tornado", llama3Path));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
commands.add(String.format("%s/.llama-tornado", llama3Path));
commands.add(String.format("%s/llama-tornado", llama3Path));

.llama-tornado does not work on Linux

}

ChatboxModel.Engine engine = model.getSelectedEngine();
if (engine == ChatboxModel.Engine.TORNADO_VM) {
commands.add("--gpu");
}

// Assume that models are found in a /models directory.
String selectedModel = model.getSelectedModel();
if (selectedModel == null || selectedModel.isEmpty()) {
model.setOutputText("Please select a model.");
return;
}
String modelPath = String.format("%s/models/%s", llama3Path, selectedModel);
String prompt = String.format("\"%s\"", model.getPromptText());

commands.addAll(Arrays.asList(
"--model", modelPath,
"--prompt", prompt
));

ProcessBuilder processBuilder = new ProcessBuilder(commands);
processBuilder.redirectErrorStream(true);
BufferedReader bufferedReader = null;
Process process;
try {
process = processBuilder.start();
bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder builder = new StringBuilder();

// Make sure to output the raw command.
builder.append("Running command: ");
builder.append(String.join(" ", processBuilder.command().toArray(new String[0])));
builder.append(System.getProperty("line.separator"));

String line;
while ((line = bufferedReader.readLine()) != null) {
builder.append(line);
builder.append(System.getProperty("line.separator"));
final String currentOutput = builder.toString();
javafx.application.Platform.runLater(() -> model.setOutputText(currentOutput));
}
Copy link
Preview

Copilot AI Jun 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updating the UI on every line read from the process may cause performance issues for high-volume output. Consider batching updates to reduce the overhead on the JavaFX application thread.

Suggested change
while ((line = bufferedReader.readLine()) != null) {
builder.append(line);
builder.append(System.getProperty("line.separator"));
final String currentOutput = builder.toString();
javafx.application.Platform.runLater(() -> model.setOutputText(currentOutput));
}
int lineCounter = 0; // Counter to track the number of lines read.
while ((line = bufferedReader.readLine()) != null) {
builder.append(line);
builder.append(System.getProperty("line.separator"));
lineCounter++;
// Update the UI every 100 lines or when the process finishes.
if (lineCounter >= 100) {
final String currentOutput = builder.toString();
javafx.application.Platform.runLater(() -> model.setOutputText(currentOutput));
lineCounter = 0; // Reset the counter after updating the UI.
}
}
// Ensure any remaining output is flushed to the UI.
final String remainingOutput = builder.toString();
javafx.application.Platform.runLater(() -> model.setOutputText(remainingOutput));

Copilot uses AI. Check for mistakes.

} catch (IOException e) {
e.printStackTrace();
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

}
78 changes: 78 additions & 0 deletions src/main/java/com/example/gui/ChatboxModel.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package com.example.gui;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class ChatboxModel {

public enum Engine { TORNADO_VM, JVM }

private final ObjectProperty<Engine> selectedEngine = new SimpleObjectProperty<>(Engine.TORNADO_VM);
private final StringProperty llama3Path = new SimpleStringProperty("");
private final StringProperty selectedModel = new SimpleStringProperty("");
private final StringProperty promptText = new SimpleStringProperty("");
private final StringProperty outputText = new SimpleStringProperty("");

public Engine getSelectedEngine() {
return selectedEngine.get();
}

public ObjectProperty<Engine> selectedEngineProperty() {
return selectedEngine;
}

public void setSelectedEngine(Engine engine) {
this.selectedEngine.set(engine);
}

public String getLlama3Path() {
return llama3Path.get();
}

public StringProperty llama3PathProperty() {
return llama3Path;
}

public void setLlama3Path(String path) {
this.llama3Path.set(path);
}

public String getSelectedModel() {
return selectedModel.get();
}

public StringProperty selectedModelProperty() {
return selectedModel;
}

public void setSelectedModel(String selectedModel) {
this.selectedModel.set(selectedModel);
}

public String getPromptText() {
return promptText.get();
}

public StringProperty promptTextProperty() {
return promptText;
}

public void setPromptText(String text) {
this.promptText.set(text);
}

public String getOutputText() {
return outputText.get();
}

public StringProperty outputTextProperty() {
return outputText;
}

public void setOutputText(String text) {
this.outputText.set(text);
}

}
Loading