diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 25b36a7..870c88e 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -78,7 +78,7 @@ dependencies { implementation("org.tensorflow:tensorflow-lite-task-text:0.3.0") - implementation("io.github.ollama4j:ollama4j:1.0.79") + implementation("com.squareup.okhttp3:okhttp:4.9.0") diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json index 4a9a6c1..e1fb618 100644 --- a/app/release/output-metadata.json +++ b/app/release/output-metadata.json @@ -11,8 +11,8 @@ "type": "SINGLE", "filters": [], "attributes": [], - "versionCode": 2, - "versionName": "0.2", + "versionCode": 3, + "versionName": "0.3", "outputFile": "app-release.apk" } ], diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cf41b67..a92caf9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -31,6 +31,10 @@ android:supportsRtl="true" android:theme="@style/Theme.RidgeScout" android:hardwareAccelerated="true" + + android:networkSecurityConfig="@xml/network_security_config" + android:usesCleartextTraffic="true" + tools:targetApi="31"> teamMatches = new ArrayList<>(); for(int i = 0; i < event.matches.size(); i++){ frcMatch match = event.matches.get(i); @@ -118,4 +133,143 @@ public class ReportFragment extends Fragment { } // AlertManager.error(out); } + + private String fieldSummary(inputType field){ + String summary = field.name + ": "; + switch (field.getInputType()){ + case DROPDOWN: + summary += "A the index of a dropdown with the possible options: [" +String.join(", ", ((dropdownType) field).text_options) + "]"; + break; + case SLIDER: + sliderType slider = (sliderType) field; + summary += "A slider with the range ["+slider.min+","+slider.max+"]"; + break; + case TALLY: + summary += "A tally counter"; + break; + case NOTES_INPUT: + summary += "Raw text input"; + break; + } + return summary; + } + + private void AIDataOverview(){ + String prompt = "Below is a list of data collected from an FRC match. Generate a qualitative and concise summary of the teams listed in the data collected.\n\n"; + + frcMatch curmatch = event.matches.get(0); + + prompt += "## Pit scouting\n"; + prompt += "This is a list of the different fields that are present in the pit scouting data:\n"; + + + prompt += "1) Team number\n"; + for(int i = 0; i < pit_latest_values.length; i++){ + prompt += (i+2) + ") " + fieldSummary(pit_latest_values[i]) + "\n"; + } + prompt += ("\nData:\n"); + + for(int a = 0; a < 6; a++){ + int teamNum = 0; + if(a < 3) + teamNum = curmatch.redAlliance[a]; + else + teamNum = curmatch.blueAlliance[a-3]; + + prompt += teamNum + ","; + + String filename = evcode+"-"+teamNum+".pitscoutdata"; + if(!fileEditor.fileExist(filename)){ + prompt += ("null,".repeat(pit_latest_values.length)); + }else{ + ScoutingDataWriter.ParsedScoutingDataResult psdr = ScoutingDataWriter.load(filename, DataManager.pit_values, DataManager.pit_transferValues); + dataType[] types = psdr.data.array; + for(int i = 0; i < types.length; i++) { + prompt += (types[i].get() + ","); + } + } + prompt += "\n"; + } + + + prompt += "\n## Match scouting\n"; + prompt += "This is a list of the different fields that are present in the match scouting data:\n"; + + prompt += "1) Match number\n"; + for(int i = 0; i < match_latest_values.length; i++){ + prompt += (i+2) + ") " + fieldSummary(match_latest_values[i]) + "\n"; + } + + prompt += ("\nData:\n"); + + for(int a = 0; a < 6; a++){ + int teamNum = 0; + if(a < 3) + teamNum = curmatch.redAlliance[a]; + else + teamNum = curmatch.blueAlliance[a-3]; + + prompt += "Team " + teamNum + " Match scout data:\n"; + + frcMatch[] matchNums = getTeamMatches(teamNum); + + for(int b = 0; b < matchNums.length; b++) { + frcMatch match = matchNums[b]; + + String alliance = ""; + int alliancePos = 0; + + for(int c = 0; c < 6; c++) { + if(c<3){ + if(match.redAlliance[c] != teamNum) continue; + alliance = "red"; + alliancePos = c+1; + break; + }else{ + if(match.blueAlliance[c-3] != teamNum) continue; + alliance = "blue"; + alliancePos = c-2; + break; + } + + } + + + String filename = evcode + "-" + match.matchIndex + "-" + alliance + "-" + alliancePos + "-" + teamNum + ".matchscoutdata"; + + if (!fileEditor.fileExist(filename)) continue; + + ScoutingDataWriter.ParsedScoutingDataResult psdr = ScoutingDataWriter.load(filename, DataManager.match_values, DataManager.match_transferValues); + dataType[] types = psdr.data.array; + prompt += match.matchIndex + ","; + for (int i = 0; i < types.length; i++) { + prompt += (types[i].get() + ","); + } + prompt += "\n"; + + } + } + + System.out.println(prompt); +// binding.AyEyeBox.setText(prompt); + + + OllamaTest.run(prompt, new OllamaTest.ollamaListener() { + @Override + public void onResponse(String response) { +// System.out.println(response); + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + binding.AyEyeBox.setText(binding.AyEyeBox.getText()+response); + } + }); + } + + @Override + public void onComplete() { + System.out.println(binding.AyEyeBox.getText()); + } + }); + } } diff --git a/app/src/main/java/com/ridgebotics/ridgescout/utility/ollama/OllamaTest.java b/app/src/main/java/com/ridgebotics/ridgescout/utility/ollama/OllamaTest.java new file mode 100644 index 0000000..12f382f --- /dev/null +++ b/app/src/main/java/com/ridgebotics/ridgescout/utility/ollama/OllamaTest.java @@ -0,0 +1,95 @@ +package com.ridgebotics.ridgescout.utility.ollama; + +import androidx.annotation.NonNull; + +import com.ridgebotics.ridgescout.utility.AlertManager; +import com.ridgebotics.ridgescout.utility.ollama.types.ChatMessage; +import com.ridgebotics.ridgescout.utility.ollama.types.ChatRequest; +import com.ridgebotics.ridgescout.utility.ollama.types.ChatResponse; +import com.ridgebotics.ridgescout.utility.ollama.types.Messages; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.util.List; + +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; +import okhttp3.OkHttpClient; + +public class OllamaTest { + private static final String MODEL_KEY = "llama3"; + private static final String OLLAMA_URL_KEY = "http://199.204.135.71:11434"; + + private static final String GENERATE_PATH = "/api/generate"; + + public interface ollamaListener { + void onResponse(String response); + void onComplete(); + } + + private static String promptToJson(String prompt){ + + try { + JSONObject jobj = new JSONObject(); + jobj.put("model", "llama3"); + jobj.put("prompt", prompt); + return jobj.toString(); + } catch (JSONException e){ + AlertManager.error(e); + } + return "{}"; + } + + public static void run(String prompt, ollamaListener listener){ + final Messages llamaMessages = new Messages(); + llamaMessages.messages.add(new Messages.Message("user", "Test!")); +// ChatRequest chatRequest = new ChatRequest(MODEL_KEY, llamaMessages.messages,true); + + RequestBody body = RequestBody.create(promptToJson(prompt), MediaType.parse("application/json")); + + Request request = new Request.Builder() + .url(OLLAMA_URL_KEY+GENERATE_PATH) + .post(body) + .build(); + + new OkHttpClient().newCall(request).enqueue(new Callback() { + @Override + public void onFailure(@NonNull Call call, @NonNull IOException e) { + AlertManager.error(e); + } + + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { + responseStreamer(response, listener); + } + }); + } + + + private static void responseStreamer(Response r, ollamaListener listener){ + String line; + ResponseBody body = r.body(); + if(body == null) + return; + try { + while ((line = body.source().readUtf8Line()) != null) { +// System.out.println(line); + JSONObject json = new JSONObject(line); + + listener.onResponse(json.getString("response")); + if(json.getBoolean("done")) + listener.onComplete(); + } + } catch (IOException | NumberFormatException | IllegalStateException | JSONException e) { +// addMessage(chatResponse,fullResponse.toString(),stopButton,sendButton); + AlertManager.error(e); + } + } +} diff --git a/app/src/main/java/com/ridgebotics/ridgescout/utility/ollama/types/ChatMessage.java b/app/src/main/java/com/ridgebotics/ridgescout/utility/ollama/types/ChatMessage.java new file mode 100644 index 0000000..d0cbd44 --- /dev/null +++ b/app/src/main/java/com/ridgebotics/ridgescout/utility/ollama/types/ChatMessage.java @@ -0,0 +1,26 @@ +package com.ridgebotics.ridgescout.utility.ollama.types; +// Credit to https://github.com/DataDropp/OllamaDroid + +public class ChatMessage { + private final int profileImage; + private final String profileName; + private final String messageContent; + + public ChatMessage(int profileImage, String profileName, String messageContent) { + this.profileImage = profileImage; + this.profileName = profileName; + this.messageContent = messageContent; + } + + public int getProfileImage() { + return profileImage; + } + + public String getProfileName() { + return profileName; + } + + public String getMessageContent() { + return messageContent; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ridgebotics/ridgescout/utility/ollama/types/ChatRequest.java b/app/src/main/java/com/ridgebotics/ridgescout/utility/ollama/types/ChatRequest.java new file mode 100644 index 0000000..ff533d1 --- /dev/null +++ b/app/src/main/java/com/ridgebotics/ridgescout/utility/ollama/types/ChatRequest.java @@ -0,0 +1,23 @@ +package com.ridgebotics.ridgescout.utility.ollama.types; +// Credit to https://github.com/DataDropp/OllamaDroid + + + +import java.util.ArrayList; + +public class ChatRequest { + public String model; + public ArrayList messages; + public boolean stream; + public ChatRequest(String model, ArrayList message, boolean stream){ + this.model = model; + this.messages = message; + this.stream = stream; + } + public String toJson(){ + return "{\n" + + " \"model\": \"llama3\",\n" + + " \"prompt\": \"Why is the sky blue?\"\n" + + "}"; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ridgebotics/ridgescout/utility/ollama/types/ChatResponse.java b/app/src/main/java/com/ridgebotics/ridgescout/utility/ollama/types/ChatResponse.java new file mode 100644 index 0000000..0b1226e --- /dev/null +++ b/app/src/main/java/com/ridgebotics/ridgescout/utility/ollama/types/ChatResponse.java @@ -0,0 +1,17 @@ +package com.ridgebotics.ridgescout.utility.ollama.types; +// Credit to https://github.com/DataDropp/OllamaDroid + +import java.util.Date; + +public class ChatResponse { + public String model; + public Date created_at; + public Messages.Message message; + public boolean done; + public long total_duration; + public int load_duration; + public int prompt_eval_count; + public int prompt_eval_duration; + public int eval_count; + public long eval_duration; +} \ No newline at end of file diff --git a/app/src/main/java/com/ridgebotics/ridgescout/utility/ollama/types/Messages.java b/app/src/main/java/com/ridgebotics/ridgescout/utility/ollama/types/Messages.java new file mode 100644 index 0000000..fb4a7ea --- /dev/null +++ b/app/src/main/java/com/ridgebotics/ridgescout/utility/ollama/types/Messages.java @@ -0,0 +1,17 @@ +package com.ridgebotics.ridgescout.utility.ollama.types; +// Credit to https://github.com/DataDropp/OllamaDroid + +import java.util.ArrayList; + +public class Messages { + public ArrayList messages = new ArrayList<>(); + public static class Message { + public String role; + public String content; + public Message(String role, String string) { + this.role = role; + this.content = string; + + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ridgebotics/ridgescout/utility/ollama/types/OllamaModels.java b/app/src/main/java/com/ridgebotics/ridgescout/utility/ollama/types/OllamaModels.java new file mode 100644 index 0000000..e23ad70 --- /dev/null +++ b/app/src/main/java/com/ridgebotics/ridgescout/utility/ollama/types/OllamaModels.java @@ -0,0 +1,24 @@ +package com.ridgebotics.ridgescout.utility.ollama.types; +// Credit to https://github.com/DataDropp/OllamaDroid + +import java.util.ArrayList; + +public class OllamaModels { + public ArrayList models; + public class OllamaModel { + + public String name; + public String modified_at; + public Object size; + public String digest; + public Details details; + + private class Details { + public String format; + public String family; + public Object families; + public String parameter_size; + public String quantization_level; + } + } +} diff --git a/app/src/main/res/layout/fragment_data_report.xml b/app/src/main/res/layout/fragment_data_report.xml index 5db837d..8d22a96 100644 --- a/app/src/main/res/layout/fragment_data_report.xml +++ b/app/src/main/res/layout/fragment_data_report.xml @@ -8,7 +8,7 @@ + + + + + + + + + +