diff --git a/src/main/java/GeminiAI.java b/src/main/java/GeminiAI.java new file mode 100644 index 0000000..432f60c --- /dev/null +++ b/src/main/java/GeminiAI.java @@ -0,0 +1,74 @@ +import okhttp3.*; +import org.json.JSONArray; +import org.json.JSONObject; +import java.net.URL; +import java.util.concurrent.TimeUnit; + +public class GeminiAI { + private static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); + public static String send(String dialog, String untranslatedNames, String translatedNames) { + OkHttpClient client = new OkHttpClient.Builder().connectTimeout(60, TimeUnit.SECONDS).readTimeout(120, TimeUnit.SECONDS).build(); + JSONObject payload = new JSONObject(); //holds the whole object of JSON sent to google + JSONArray contents = new JSONArray(); //holds the text content sent to the AI + //how gemini works is that the turns HAVE to be user -> model -> user -> model -> user and ALWAYS start and end with user + //its really stupid, and making the JSON for this is a pain in the ass. + + /* + //this would have been for a "system" prompt but apparently gemini doesnt have that. + //not going to delete this but instead i shall comment it out. + JSONObject modelPrompt = new JSONObject(); + modelPrompt.put("role", "model"); + JSONArray parts = new JSONArray(); + JSONObject text = new JSONObject(); + text.put("text","Answer the request."); + parts.put(text); + modelPrompt.put("parts", parts); + contents.put(modelPrompt); + */ + + JSONObject userPrompt = new JSONObject(); + userPrompt.put("role", "user"); + JSONArray userParts = new JSONArray(); + JSONObject userText = new JSONObject(); + userText.put("text", "Create a complete summary for the following story: \n" + + "- Respond only in English.\n" + + "- The summary should be 2-3 paragraphs in length, and include all major events.\n" + + "- Be thorough describing the events.\n" + + "- Specify which characters are involved in each event.\n" + + "- Use the characters' Japanese names when they are referred to.\n" + + "- This story happens in the main story of Kemono Friends 3, where human girls with animal features go on adventures, and fight against Celliens.\n" + + "\n\n" + dialog + "\n\nSummarize the story, and respond in English."); + + /*"This story happens in the Kemono Friends 3 mobile game, where human girls with animal features go on adventures, and fight against Celliens. " + + "Respond in english. The characters involved are " + names + ". " + + "Be specific about actions and events that occurred. Create a complete summary for the following story. ---\n\n" + dialog + + "\n\n---\n\nSummarize the story, and respond in English."); */ + + userParts.put(userText); + userPrompt.put("parts", userParts); + contents.put(userPrompt); + //this hunk of shit puts the text into googles special little array with an object inside or something + //i hate google's stupid fucking API formatting + + payload.put("contents",contents); + + RequestBody requestBody = RequestBody.create(JSON, payload.toString()); + String output; + try { + //to change model, change the gemini-1.0-pro-latest thing to whichever model you want. + URL url = new URL("https://generativelanguage.googleapis.com/v1beta/models/gemini-1.0-pro-latest:generateContent?key=" + ReadKey.read("APIKey")); + Request request = new Request.Builder().url(url).post(requestBody).build(); + String responseContent; + try (Response resp = client.newCall(request).execute()) { + responseContent = resp.body().string(); + } + //you know what i hate more than googles INPUT json?????? OUTPUT JSON!!!! + JSONObject response = new JSONObject(responseContent); + //System.out.println(responseContent); + output = response.getJSONArray("candidates").getJSONObject(0).getJSONObject("content").getJSONArray("parts").getJSONObject(0).getString("text"); + } catch (Exception e) { + throw new RuntimeException(e); + } + return output; + } +} diff --git a/src/main/java/ReadKey.java b/src/main/java/ReadKey.java new file mode 100644 index 0000000..3626c74 --- /dev/null +++ b/src/main/java/ReadKey.java @@ -0,0 +1,17 @@ +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; + +public class ReadKey { + public static String read(String filepath) { + String line = null; + try { + BufferedReader reader = new BufferedReader(new FileReader(filepath)); + line = reader.readLine(); + reader.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return line; + } +} diff --git a/src/main/java/SummaryMain.java b/src/main/java/SummaryMain.java new file mode 100644 index 0000000..7dc3553 --- /dev/null +++ b/src/main/java/SummaryMain.java @@ -0,0 +1,130 @@ +import org.json.JSONArray; +import org.json.JSONObject; + +import java.io.*; +import java.util.*; + +public class SummaryMain { + public static void main(String[] args) { + + String folderPath = "char/"; //the folder to look for the scenario files in + + Scanner sc = new Scanner(System.in); + System.out.println("Input the ID of the chapter you want summarized. (format \"3\" or \"179\")"); + String idUnformatted = sc.nextLine(); + int idUnformattedInt = Integer.parseInt(idUnformatted); + String id = String.format("%04d",idUnformattedInt); + + + //for (int loopOverEveryChapter = 0; loopOverEveryChapter < 10; loopOverEveryChapter++) { + //String id = String.format("%02d",loopOverEveryChapter); + //this is used when iterating over story chapters + + //Essentially this reads all of the scenario files in order for the correct character ID. Edit the character ID. + File folder = new File(folderPath); + File[] files = folder.listFiles((dir, name) -> name.startsWith("scenario_c_" + id + "_") && name.endsWith(".prefab.json")); + Arrays.sort(files, Comparator.naturalOrder()); //this is what puts them in the right order, lol + + int half = files.length / 2; + int stoppingPoint = half; + for (int iter = 0; iter < 2; iter++) { + String dialog = null; + StringBuilder fullScene = new StringBuilder(); //holds all of the scenarios put together and formatted + JSONArray allScenarios = new JSONArray(); //holds all of the JSONs for the scenarios + JSONArray charaNames = new JSONArray(); //holds all of the character names used + duplicates + int startingPoint = 0; + if (iter > 0) { + //if we have already iterated once, start from the old stopping point + startingPoint = stoppingPoint; + stoppingPoint = stoppingPoint + half; + } + for (int f = startingPoint; f < stoppingPoint; f++) { + File file = files[f]; + String fileContents = ""; + try (BufferedReader br = new BufferedReader(new FileReader(folderPath + file.getName()))) { + String line; + while ((line = br.readLine()) != null) { + fileContents += line; + } + } catch (IOException e) { + throw new RuntimeException(e); + } + //for the scenario we just got, save the character names and then add this scenario to all of the other scenarios + JSONObject scenario = new JSONObject(fileContents); + for (int i = 0; i < scenario.getJSONArray("charaDatas").length(); i++) { + charaNames.put(scenario.getJSONArray("charaDatas").getJSONObject(i).getString("name")); + } + allScenarios.put(scenario); + } + + JSONArray uniqueNames = removeDuplicates(charaNames); //remove duplicate names to not confuse the AI + String names = uniqueNames.toString().replaceAll("[\\[\\]]", ""); //remove the brackets + + //this hunk of shit parses the dialog down to only the spoken words and formats it like "name: text." it works. + for (int i = 0; i < allScenarios.length(); i++) { + JSONObject scenarioData = allScenarios.getJSONObject(i); + JSONArray rowDatas = scenarioData.getJSONArray("rowDatas"); + for (Object rowData : rowDatas) { + JSONObject jsonObject = (JSONObject) rowData; + if (jsonObject.has("mSerifCharaName")) { + String charName = jsonObject.getString("mSerifCharaName"); + if (!charName.isEmpty()) { + JSONArray dialogArray = jsonObject.getJSONArray("mStrParams"); + for (Object sentence : dialogArray) { + if (!sentence.toString().equals("none")) { + if (!sentence.toString().isBlank()) { + String cleanedSentence = sentence.toString().replaceAll("<.*?>", ""); + dialog = charName + ": " + cleanedSentence + "\n"; + } + } + } + fullScene.append(dialog).append("\n"); + } + } + } + } + try (FileWriter tfw = new FileWriter("summary/untranslated/" + id + "(" + (iter + 1) + ").txt")) { + BufferedWriter bw = new BufferedWriter(tfw); + bw.write(fullScene.toString()); + bw.flush(); + bw.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + //System.out.println(fullScene); //mostly here for debug + System.out.println("---"); + System.out.println("Summarizing half " + (iter + 1) + "..."); + //String translatedScene = TactAI.translate(fullScene.toString()); + String translatedNames = Translate.translator(names); //translate the names with google translate first + String summarizedScene = GeminiAI.send(fullScene.toString(), names, translatedNames); //send the scenarios to the AI + System.out.println(summarizedScene); + + //now write the summary into a file + String filename = "summary/" + id + "(" + (iter + 1) + ").txt"; + try (FileWriter fw = new FileWriter(filename)) { + BufferedWriter bw = new BufferedWriter(fw); + bw.write(summarizedScene); + bw.flush(); + bw.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + //} + } + } + + public static JSONArray removeDuplicates(JSONArray jsonArray) { + //some nice code that claude 3 generated that works well. basically uses something that already has an + //"add only if it doesnt exist yet" function then puts it back in a JSONArray. pretty thrifty nifty. + Set uniqueElements = new HashSet<>(); + JSONArray uniqueArray = new JSONArray(); + + for (int i = 0; i < jsonArray.length(); i++) { + String element = jsonArray.getString(i); + if (uniqueElements.add(element)) { // add returns true if element is not already present + uniqueArray.put(element); + } + } + return uniqueArray; + } +} diff --git a/src/main/java/TactAI.java b/src/main/java/TactAI.java new file mode 100644 index 0000000..c9bfd09 --- /dev/null +++ b/src/main/java/TactAI.java @@ -0,0 +1,88 @@ +import okhttp3.*; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.net.URL; +import java.util.concurrent.TimeUnit; + +public class TactAI { + private static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); + public static String translate(String dialog) { + String kfInfo = "Friends are human girls with animal-like features. They are animals that have transformed into human girls through a substance called Sandstar. While retaining influences from their animal form, such as ears, tail, wings (for bird friends), and personality traits, friends do not have paws, claws, or fur and are fully human. There are friends representing both extant and extinct animal species. Sandstar, a mineral, interacts with animals to create friends in their human form. Japari Park is an island safari that encompasses various biomes and ecosystems, housing the corresponding animal and plant life. At the center of the park is a large mountain, which generates Sandstar at its peak with crystalline structures extending beyond it. Celliens are cell-like alien creatures with the sole goal of consuming friends, causing them to revert to their animal form."; + + OkHttpClient client = new OkHttpClient.Builder().connectTimeout(60, TimeUnit.SECONDS).readTimeout(120, TimeUnit.SECONDS).build(); + String prompt = "Translate the following story into English. Do not add additional information, keep the story intact. \"セルリアン\" is \"Cellien\". -\n\n"; + JSONArray messages = new JSONArray(); + + JSONObject systemPrompt = new JSONObject(); + systemPrompt.put("role", "user"); + systemPrompt.put("content", prompt + dialog); + messages.put(systemPrompt); //put the system prompt first + + /*JSONObject dialogMessage = new JSONObject(); + dialogMessage.put("role", "user"); + dialogMessage.put("content", "Additional context for the story is as follows -\n" + kfInfo); + messages.put(dialogMessage); //put the dialog to be summarize second */ + + JSONObject parameters = new JSONObject(); + parameters.put("max_tokens", 550); + parameters.put("messages", messages); + + RequestBody requestBody = RequestBody.create(JSON, parameters.toString()); + String output; + try { + URL url = new URL("http://localhost:8080/v1/chat/completions"); + Request request = new Request.Builder().url(url).post(requestBody).build(); + String responseContent; + try (Response resp = client.newCall(request).execute()) { + responseContent = resp.body().string(); + } + JSONObject jsonObject = new JSONObject(responseContent); + output = jsonObject.getJSONArray("choices").getJSONObject(0).getJSONObject("message").getString("content"); + } catch (Exception e) { + throw new RuntimeException(e); + } + + return output; + } + + public static String summarize(String dialog) { + String kfInfo = "Friends are human girls with animal-like features. They are animals that have transformed into human girls through a substance called Sandstar. While retaining influences from their animal form, such as ears, tail, wings (for bird friends), and personality traits, friends do not have paws, claws, or fur and are fully human. There are friends representing both extant and extinct animal species. Sandstar, a mineral, interacts with animals to create friends in their human form. Japari Park is an island safari that encompasses various biomes and ecosystems, housing the corresponding animal and plant life. At the center of the park is a large mountain, which generates Sandstar at its peak with crystalline structures extending beyond it. Celliens are cell-like alien creatures with the sole goal of consuming friends, causing them to revert to their animal form."; + + OkHttpClient client = new OkHttpClient.Builder().connectTimeout(60, TimeUnit.SECONDS).readTimeout(120, TimeUnit.SECONDS).build(); + String prompt = "Create a complete summary for the following story. " + + "Explain what happens, and tell what events occurred within one paragraph -\n\n"; + JSONArray messages = new JSONArray(); + + JSONObject systemPrompt = new JSONObject(); + systemPrompt.put("role", "user"); + systemPrompt.put("content", prompt + dialog); + messages.put(systemPrompt); //put the system prompt first + + /*JSONObject dialogMessage = new JSONObject(); + dialogMessage.put("role", "user"); + dialogMessage.put("content", "Translate the dialog into English."); + messages.put(dialogMessage); //put the dialog to be summarize second */ + + JSONObject parameters = new JSONObject(); + parameters.put("max_tokens", 550); + parameters.put("messages", messages); + + RequestBody requestBody = RequestBody.create(JSON, parameters.toString()); + String output; + try { + URL url = new URL("http://localhost:8080/v1/chat/completions"); + Request request = new Request.Builder().url(url).post(requestBody).build(); + String responseContent; + try (Response resp = client.newCall(request).execute()) { + responseContent = resp.body().string(); + } + JSONObject jsonObject = new JSONObject(responseContent); + output = jsonObject.getJSONArray("choices").getJSONObject(0).getJSONObject("message").getString("content"); + } catch (Exception e) { + throw new RuntimeException(e); + } + + return output; + } +} diff --git a/src/main/java/Translate.java b/src/main/java/Translate.java new file mode 100644 index 0000000..8042a86 --- /dev/null +++ b/src/main/java/Translate.java @@ -0,0 +1,12 @@ +import me.bush.translator.Language; +import me.bush.translator.Translation; +import me.bush.translator.Translator; + +public class Translate { + public static String translator(String input) { + Translator translator = new Translator(); + //input text, target language, source language + Translation tr = translator.translateBlocking(input, Language.ENGLISH, Language.AUTO); + return tr.getTranslatedText(); + } +}