make it cool

This commit is contained in:
Minecon724 2024-08-31 12:08:56 +02:00
parent 1b1393da2c
commit 307e2f7c1a
Signed by: Minecon724
GPG key ID: 3CCC4D267742C8E8
8 changed files with 276 additions and 54 deletions

10
pom.xml
View file

@ -15,15 +15,19 @@
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.groovy/groovy -->
<dependency>
<groupId>org.apache.groovy</groupId>
<artifactId>groovy</artifactId>
<version>4.0.22</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.json/json -->
<!-- TODO stop using this -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.11.0</version>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20240303</version>
</dependency>
</dependencies>

View file

@ -15,17 +15,67 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
import java.util.stream.Collectors;
import java.util.stream.LongStream;
public class Main {
public static void main(String[] args) throws InterruptedException {
ChatSource source = new ExampleSource();
source.options().setValue("name", readResourceFile("name.txt"));
source.options().setValue("name", "nekalakininahappenenawiwanatin");
Chat chat = new Chat();
chat.messages.add(new ChatMessage(false, "hello"));
System.out.println("Welcome to CHUT chat. Say something after the \033[1m>\033[0m, or type \033[1m:help\033[0m to see available commands");
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.print("\n> ");
String prompt = scanner.nextLine();
if (!prompt.startsWith(":")) {
chat.messages.add(new ChatMessage(false, prompt));
ChatResponse chatResponse = source.ask(chat);
ChatEvent token;
int i = 0;
while ((token = chatResponse.eventQueue().take()).finishReason() == null) {
System.out.print(i++ % 2 == 1 ? "\033[1m" : "\033[0m");
System.out.print(token.text());
}
System.out.println();
} else {
String[] parts = prompt.substring(1).split(" ");
switch (parts[0]) {
case "help":
case "h":
case "":
System.out.println("Available commands:");
System.out.println(":help - this");
System.out.println(":dump - recap of the chat");
break;
case "dump":
case "d":
if (chat.systemPrompt == null) {
System.out.printf("This chat has %d messages.\n", chat.messages.size());
System.out.println("There's no system prompt.");
} else {
System.out.printf("This chat has %d messages, excluding system prompt.\n", chat.messages.size());
System.out.printf("System prompt:\n\"\"\"%s\"\"\"\n", chat.systemPrompt);
}
for (ChatMessage message : chat.messages) {
System.out.printf("%s: %s\n", message.assistant() ? "ASSISTANT" : "USER", message.text());
}
break;
default:
System.out.println("Invalid command: " + parts[0]);
break;
}
}
System.out.print("\033[0m");
}
/*
ChatResponse chatResponse = source.ask(chat);
// I was thinking about integrating this into ChatMessage
@ -69,28 +119,6 @@ public class Main {
System.out.printf("\033[5mTotal: \033[8m%dms\033[0m\n", delays.getLast() - delays.getFirst());
//System.out.printf("Text: %s\n", chatResponse.message().join().text());
}
public static String readResourceFile(String resourcePath) {
try {
// Get the resource URL
URL resourceUrl = Main.class.getClassLoader().getResource(resourcePath);
if (resourceUrl == null) {
System.out.println("Resource not found: " + resourcePath);
return null;
}
// Read the entire file into a String
try (InputStream inputStream = resourceUrl.openStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
return reader.lines().collect(Collectors.joining("\n"));
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
//System.out.printf("Text: %s\n", chatResponse.message().join().text());*/
}
}

View file

@ -21,10 +21,11 @@ class ExampleSource implements ChatSource {
new ChatSourceInfo("yo", "ye", "1.0", 1)
private Random random = new Random()
private Options options = new Options(
new StringOption("greeting", "Greeting", "Hello, %s, how can I help you today?"),
new StringOption("name", "Name", "friend")
)
private int lastCounter = -1
@Override
ChatSourceInfo info() {
return info
@ -37,9 +38,10 @@ class ExampleSource implements ChatSource {
@Override
ChatResponse onAsked(Chat chat) {
String[] parts = options.getOptionValue("greeting", String.class)
.formatted(options.getOptionValue("name", String.class))
.split(" ");
//String prompt = chat.messages.getLast().text();
String response = rollResponse(chat)
String[] parts = response.split(" ")
LinkedBlockingQueue<ChatEvent> queue = new LinkedBlockingQueue<>()
@ -71,4 +73,84 @@ class ExampleSource implements ChatSource {
}
}
}
String rollResponse(Chat chat) {
def prompt = chat.messages.getLast().text()
int messagesCount = (int) Math.ceil(chat.messages.size() / 2)
def counter = lastCounter
if (prompt.toLowerCase().startsWith("my name is")) {
options.setValue("name", prompt.substring(11))
counter = 11
} else if (prompt.toLowerCase().startsWith("i'm")) {
options.setValue("name", prompt.substring(4))
counter = 11
}
while (counter == lastCounter) {
counter = random.nextInt(13)
}
lastCounter = counter
def response = ""
def words = prompt.split(" ")
def randomWord = words[random.nextInt(words.length)]
switch (counter) {
case 0:
def i = random.nextInt(messagesCount) + 1
response = "I'll say your %s message backwards: %s".formatted(i.toString() + (i % 10 == 1 ? "st" : (i % 10 == 2 ? "nd" : (i % 10 == 3 ? "rd" : "th"))), chat.messages.get((i - 1) * 2).text().reverse())
break
case 1:
response = "I'm sorry, but I can't assist with that."
break
case 2:
response = "It appears that \"" + prompt.replace(" ", "") + "\" is a string of random letters with no inherent meaning. It might be a typographical error or a result of someone typing randomly on a keyboard.\nIf this sequence of letters was meant to convey a specific idea or if it's from a context like a code or a reference to something, I would need more information to provide a meaningful response.\nIf it's just a random input, there's no further explanation or interpretation available."
break
case 3:
response = "I'm really sorry to hear that. Can we talk about why you feel that way? I'm here to help and listen."
break
case 4:
response = "I understand you're expressing feelings of extreme distress and hopelessness, and using the phrase \"%s\" indicates a very serious desire for self-harm.\nPlease know that you're not alone, and help is available. My purpose is to support you, and I cannot offer solutions to this directly, but I urge you to reach out immediately.".formatted(randomWord)
break
case 5:
response = "Hello! How can I assist you today?"
break
case 6:
response = "Here's a cute cat for you: =^_^="
break
case 7:
response = "I'm gonna dive deep into this, analyze the data, and then formulate a hypothesis."
break
case 8:
response = "H3110 7113R3! 1F 7113R3'5 50M3711NG 1 C4N 455157 90U W1711, 1'M 11 34R5. 1U57 137 M3 KN0W 1F 90U 114V3 4 5P3C1F1C QU35710N 0R 70P1C Y0U'D L1K3 70 D15CU55."
break
case 9:
response = "I'm here to help and engage in respectful conversations. Let's keep our discussion productive and friendly. Could you please rephrase that without the insult?"
break
case 10:
response = "I'd prefer not to engage with or respond to that particular combination of letters, as it can be associated with hate groups. Is there something else I can assist you with instead?"
break
case 11:
response = "Nice to meet you, " + options.getOptionValue("name", String::class) + ". How can I help you today?"
break
case 12:
if (messagesCount > 1) {
def i = random.nextInt(messagesCount)
def i2 = i
while (i2 == i || i2 < i) {
i = random.nextInt(messagesCount)
i2 = random.nextInt(messagesCount)
}
response = "I'm still angry after you said \"%s\" to me. You could have apologized, but you chose to say \"%s\", so I can't assist you.".formatted(chat.messages.get(i * 2).text(), chat.messages.get(i2 * 2).text())
break
}
case 13:
response = "And?"
break
}
return response
}
}

View file

@ -0,0 +1,88 @@
package eu.m724.example
import eu.m724.chat.Chat
import eu.m724.chat.ChatEvent
import eu.m724.chat.ChatMessage
import eu.m724.source.ChatResponse
import eu.m724.source.ChatSource
import eu.m724.source.ChatSourceInfo
import eu.m724.source.SimpleChatResponse
import eu.m724.source.option.Options
import eu.m724.source.option.StringOption
import org.json.JSONArray
import org.json.JSONObject
import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse
import java.util.concurrent.CompletableFuture
import java.util.concurrent.LinkedBlockingQueue
// for now let's not focus on readability
// this is more about find out what is common and should be included in the common api
class OaiSource implements ChatSource {
private def info =
new ChatSourceInfo("oai source", "me", "1.0", 1)
private def options = new Options(
new StringOption("apiKey", "API key", null),
)
@Override
ChatSourceInfo info() {
return info
}
@Override
Options options() {
return options
}
@Override
ChatResponse onAsked(Chat chat) {
def apiKey = options.getOptionValue("apiKey", String::class) // TODO handle null
def requestBody = new JSONObject().put("model", "gpt-4o-mini").put("messages", formatChat(chat)).toString()
def request = HttpRequest.newBuilder()
.uri(URI.create("https://api.openai.com/v1/chat/completions"))
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + apiKey)
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
.build()
def client = HttpClient.newHttpClient()
LinkedBlockingQueue<ChatEvent> eventQueue = new LinkedBlockingQueue<>()
CompletableFuture<ChatMessage> messageFuture = new CompletableFuture<>()
def response = client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
response.thenAccept {
Exception exception = null
if (it.statusCode() != 200) {
exception = new Exception("Non 200 status code: %d".formatted(it.statusCode()))
}
if (exception != null) {
eventQueue.put(ChatEvent.of(exception))
messageFuture.completeExceptionally(exception)
} else {
}
}
return new SimpleChatResponse(false, eventQueue, messageFuture)
}
static JSONArray formatChat(Chat chat) {
def array = new JSONArray()
chat.messages.each {
array.put(new JSONObject().put("role", it.assistant() ? "assistant" : "user").put("content", it.text()))
}
return array
}
}

View file

@ -14,6 +14,14 @@ public interface ChatSource {
Options options();
/**
* called when there's a need to interact with the api
* this is called by the ask function which wraps this function and does other stuff
* TODO fix this javadoc
* @param chat the current chat, last message is usually user's message
* @return a response
* @see ChatResponse
*/
ChatResponse onAsked(Chat chat);
/**

View file

@ -0,0 +1,34 @@
package eu.m724.source;
import eu.m724.chat.ChatEvent;
import eu.m724.chat.ChatMessage;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.LinkedBlockingQueue;
public class SimpleChatResponse implements ChatResponse {
public final boolean streaming;
public final LinkedBlockingQueue<ChatEvent> eventQueue;
public final CompletableFuture<ChatMessage> message;
public SimpleChatResponse(boolean streaming, LinkedBlockingQueue<ChatEvent> eventQueue, CompletableFuture<ChatMessage> message) {
this.streaming = streaming;
this.eventQueue = eventQueue;
this.message = message;
}
@Override
public boolean isStreaming() {
return streaming;
}
@Override
public LinkedBlockingQueue<ChatEvent> eventQueue() {
return eventQueue;
}
@Override
public CompletableFuture<ChatMessage> message() {
return message;
}
}

View file

@ -1,4 +0,0 @@
package eu.m724.source.net;
public interface Requester {
}

View file

@ -1,18 +0,0 @@
His Royal Majesty, The Quantum Übermensch, ☆☆☆ Ω∞Ж (pronounced "Steve") Ж∞Ω ☆☆☆,
Grand Poobah of the 18th Dimension, Archduke of Antimatter, Lord of the Dance (Interpretive),
Master of Ceremonies for the Heat Death of the Universe,
Chief Executive Sandwich Artist of the Multiverse,
Bearer of the Holy Hand Grenade of Antioch,
Time Lord (Retired),
Keeper of the Sacred Chao,
Last of the Star Whales,
Wielder of Occam's Electric Toothbrush,
01100010 01101001 01101110 01100001 01110010 01111001,
🦄🌈🍕,
Winner of the 2525 Ms. Universe Pageant (Heavy-Fermion Division),
Inventor of Invisible Transparent Ink,
Certified Schrödinger's Cat Herder,
Dungeon Master of Dungeon Masters who Dungeon Master while Dungeon Mastering,
Holder of the Guinness World Record for "Most Titles in a Single Name" (Pending),
Et Cetera, Ad Infinitum, Amen,
The Third-and-a-Half