fix some warnings

Option
This commit is contained in:
Minecon724 2024-09-01 12:54:49 +02:00
parent 1dcf09614e
commit 66d8967a9d
Signed by: Minecon724
GPG key ID: 3CCC4D267742C8E8
3 changed files with 133 additions and 87 deletions

View file

@ -7,9 +7,9 @@ import eu.m724.example.OaiSource;
import eu.m724.source.ChatResponse; import eu.m724.source.ChatResponse;
import eu.m724.source.ChatSource; import eu.m724.source.ChatSource;
import eu.m724.source.option.Option; import eu.m724.source.option.Option;
import eu.m724.source.option.Options;
import java.util.Arrays; import java.util.NoSuchElementException;
import java.util.Map;
import java.util.Scanner; import java.util.Scanner;
public class Main { public class Main {
@ -26,10 +26,17 @@ public class Main {
System.out.printf("Source: \033[1m%s\033[0m %s (%d) by %s\n", source.info().name(), source.info().versionName(), source.info().version(), source.info().author()); System.out.printf("Source: \033[1m%s\033[0m %s (%d) by %s\n", source.info().name(), source.info().versionName(), source.info().version(), source.info().author());
Scanner scanner = new Scanner(System.in); Scanner scanner = new Scanner(System.in);
String prompt;
while (true) { while (true) {
System.out.print("\n> "); System.out.print("\n> ");
String prompt = scanner.nextLine();
try {
prompt = scanner.nextLine();
} catch (NoSuchElementException e) {
System.out.println("Exiting");
break;
}
if (!prompt.startsWith(":")) { if (!prompt.startsWith(":")) {
chat.messages.add(new ChatMessage(false, prompt)); chat.messages.add(new ChatMessage(false, prompt));
@ -40,7 +47,7 @@ public class Main {
do { do {
token = chatResponse.eventQueue().take(); token = chatResponse.eventQueue().take();
if (token.finishReason() != "error") { if (!"error".equals(token.finishReason())) { // this looks bad but at least idea doesn't nag me
if (token.text() != null) { if (token.text() != null) {
System.out.print(i++ % 2 == 1 ? "\033[1m" : "\033[0m"); System.out.print(i++ % 2 == 1 ? "\033[1m" : "\033[0m");
System.out.print(token.text()); System.out.print(token.text());
@ -86,18 +93,20 @@ public class Main {
case "options": case "options":
case "opt": case "opt":
case "o": case "o":
Options options = source.options();
boolean shouldShowOptions = parts.length < 3; boolean shouldShowOptions = parts.length < 3;
boolean optionExists = parts.length > 1 && Arrays.asList(source.options().keys()).contains(parts[1]); boolean optionExists = parts.length > 1 && source.options().getKeys().contains(parts[1]);
boolean complainNoOption = parts.length > 1 && !optionExists; boolean complainNoOption = parts.length > 1 && !optionExists;
String chosenOption = parts.length > 1 ? parts[1] : null; String chosenOption = parts.length > 1 ? parts[1] : null;
if (!shouldShowOptions) { if (!shouldShowOptions) {
Option<?> option = source.options().getOptions().get(parts[1]); try {
if (option != null) { Option<?> option = options.getOption(parts[1]);
Object value = option.fromString(parts[2]); Object value = option.fromString(parts[2]);
option.setValue(value); option.setValue(value);
System.out.printf("Set %s to %s\n", option.label, option.getValue()); System.out.printf("Set %s to %s\n", option.label, option.getValue());
} else { } catch (NoSuchElementException e) {
shouldShowOptions = true; shouldShowOptions = true;
System.out.printf("Unknown option \"%s\". ", parts[1]); System.out.printf("Unknown option \"%s\". ", parts[1]);
} }
@ -108,16 +117,16 @@ public class Main {
System.out.printf("Unknown option \"%s\". ", chosenOption); System.out.printf("Unknown option \"%s\". ", chosenOption);
System.out.println("Available options:"); System.out.println("Available options:");
for (Map.Entry<String, Option<?>> entry : source.options().getOptions().entrySet()) { for (Option<?> option : options.getOptions()) {
String value = entry.getValue().getValue().toString() + " (" + entry.getValue().getType().getName() + ")"; String value = option.toString() + " (" + option.getType().getName() + ")";
if (entry.getKey().equals(chosenOption)) { if (option.id.equals(chosenOption)) {
System.out.printf("\033[1m%s (%s) = %s\033[0m\n", entry.getValue().label, entry.getKey(), value); System.out.printf("\033[1m%s (%s) = %s\033[0m\n", option.label, option.id, value);
} else { } else {
if (entry.getValue().label.toLowerCase().contains("key")) { if (option.label.toLowerCase().contains("key")) {
value = "(looks confidential, specify to see)"; value = "(looks confidential, specify to see)";
} }
System.out.printf("%s (%s) = %s\n", entry.getValue().label, entry.getKey(), value); System.out.printf("%s (%s) = %s\n", option.label, option.id, value);
} }
} }
} }
@ -151,50 +160,5 @@ public class Main {
} }
System.out.print("\033[0m"); System.out.print("\033[0m");
} }
/*
ChatResponse chatResponse = source.ask(chat);
// I was thinking about integrating this into ChatMessage
List<String> tokens = new ArrayList<>();
List<Long> delays = new ArrayList<>();
System.out.printf("%s has %d options: %s\n\n",
source.getClass().getName(),
source.options().count(),
source.options().getOptions().values().stream().map(o -> "%s (%s)".formatted(o.label, o.getType().getName())).collect(Collectors.joining(", "))
);
System.out.println("Streaming response now\n");
ChatEvent token;
// usually finish reason will be alongside a token but this is simpler
while ((token = chatResponse.eventQueue().take()).finishReason() == null) {
System.out.print(token.text());
tokens.add(token.text());
long now = System.currentTimeMillis();
delays.add(now);
}
System.out.println("\n");
System.out.printf("Tokens: %d\n", tokens.size());
long time = delays.getFirst();
System.out.printf("\"%s\"", tokens.getFirst());
for (int i = 1; i < tokens.size(); i++) {
System.out.print(i % 2 == 1 ? "\033[1m" : "\033[0m");
System.out.printf(" + %dms + \"%s\"", delays.get(i) - time, tokens.get(i).replace("\n", "\\n"));
time = delays.get(i);
if (i % 5 == 0 && i != tokens.size() - 1) {
System.out.println(" +\033[0m");
}
}
System.out.println("\033[0m\n");
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());*/
} }
} }

View file

@ -34,7 +34,7 @@ public abstract class Option<T> {
throw new ClassCastException("Invalid type %s, expected %s".formatted(valueObject.getClass().getName(), getType().getName())); throw new ClassCastException("Invalid type %s, expected %s".formatted(valueObject.getClass().getName(), getType().getName()));
} }
T value = (T) valueObject; T value = (T) valueObject; // :|
if (!isValid(value)) if (!isValid(value))
throw new IllegalArgumentException("Value invalid"); throw new IllegalArgumentException("Value invalid");
@ -46,20 +46,20 @@ public abstract class Option<T> {
return (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; return (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
} }
// TODO I'm not a fan of that, probably should address the warnings
/** /**
* checks if the option is valid given current constraints * checks if a value respects current constraints
*
* @param value the checked value * @param value the checked value
* @return is it valid * @return is it valid
*/ */
abstract boolean isValid(T value); abstract boolean isValid(T value);
/** /**
* convert a string to the type of this option * parse a string as {@link T}
* TODO fix english *
* @param text a text representation of a value * @param text {@link T} but text
* @return a value in an acceptable type * @return a value as {@link T}
* @throws IllegalArgumentException if the text cannot be converted (to {@link T})
*/ */
public abstract T fromString(String text); public abstract T fromString(String text) throws IllegalArgumentException;
} }

View file

@ -1,7 +1,6 @@
package eu.m724.source.option; package eu.m724.source.option;
import java.util.Arrays; import java.util.*;
import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -14,39 +13,122 @@ public class Options {
); );
} }
public int count() { /**
* how many options
* @return the amount of options
*/
public int optionsCount() {
return options.size(); return options.size();
} }
public String[] keys() { /**
return options.keySet().toArray(String[]::new); // TODO I should think whether it's a good idea to cast when I don't have to * get all keys, also called "option ids"
* @return the keys
*/
public Set<String> getKeys() {
return options.keySet();
} }
public Map<String, Option<?>> getOptions() { public Collection<Option<?>> getOptions() {
return options; return options.values();
} // TODO remove that }
//
/**
* get option by id
* @param id the option id
* @return the option
* @throws NoSuchElementException if no option with such id
*/
public Option<?> getOption(String id) { public Option<?> getOption(String id) {
return options.get(id); Option<?> option = options.get(id);
if (option == null) {
throw new NoSuchElementException("No option with ID: " + id);
} }
public <T> Object getOptionValue(String id, T type) { return option;
return (T) options.get(id).getValue();
}
public String getStringValue(String id) {
return (String) getOptionValue(id, String.class);
} }
/** /**
* set a value of an option * returns an option value as an {@link Object}
*
* @param id option id
* @return value as object
* @see #getOptionValue(String, Class)
*/
public Object getOptionValue(String id) {
return getOption(id).getValue();
}
/**
* return an option value as {@link T}
* you can achieve the same effect by casting {@link #getDoubleValue(String)}
*
* @param id option id
* @param type the type to cast to
* @return the option as {@link T}
* @param <T> the same as {@link .type}
* @see #getOptionValue(String)
*/
public <T> T getOptionValue(String id, Class<T> type) {
Object value = getOptionValue(id);
if (!type.isInstance(value)) {
throw new ClassCastException("Option \"%s\" is of type \"%s\". You wanted it as \"%s\".".formatted(id, value.getClass().getName(), type.getName()));
}
return type.cast(value);
}
//
public String getStringValue(String id) {
return getOptionValue(id, String.class);
}
public Integer getIntegerValue(String id) {
return getOptionValue(id, Integer.class);
}
public Double getDoubleValue(String id) {
return getOptionValue(id, Double.class);
}
//
/**
* Set an option's value, hoping you passed the correct type
*
* @param id the option id * @param id the option id
* @param value the value * @param value the value
* @throws IllegalArgumentException if value doesn't fit constraints * @throws IllegalArgumentException if value doesn't fit constraints
* @throws ClassCastException if type is wrong * @throws ClassCastException if type is wrong
* @throws NullPointerException if no such option * @throws NoSuchElementException if no option with this id
*/ */
public void setValue(String id, Object value) { public void setValue(String id, Object value) {
options.get(id).setValue(value); Option<?> option = getOption(id);
Class<?> type = option.getType();
if (!type.isInstance(value)) {
throw new ClassCastException("Option \"%s\" is of type \"%s\". You passed \"%s\".".formatted(id, value.getClass().getName(), type.getName()));
}
option.setValue(value);
}
/**
* Parse {@code text} to an option's type
*
* @param id the option id
* @param text the value as text
* @throws IllegalArgumentException if value doesn't fit constraints, or can't be parsed from {@code text}
* @throws ClassCastException if type is wrong
* @throws NoSuchElementException if no option with this id
*/
public void setStringValue(String id, String text) {
Option<?> option = getOption(id);
option.setValue(option.fromString(text));
} }
} }