mirror of
https://github.com/Team4388/RidgeScout.git
synced 2026-06-08 16:28:00 -06:00
AI intigration
This commit is contained in:
@@ -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")
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
"type": "SINGLE",
|
||||
"filters": [],
|
||||
"attributes": [],
|
||||
"versionCode": 2,
|
||||
"versionName": "0.2",
|
||||
"versionCode": 3,
|
||||
"versionName": "0.3",
|
||||
"outputFile": "app-release.apk"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -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">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
package com.ridgebotics.ridgescout.ui.data;
|
||||
|
||||
import static com.ridgebotics.ridgescout.SettingsVersionStack.latestSettings.settings;
|
||||
import static com.ridgebotics.ridgescout.types.input.inputType.dropdownType;
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.evcode;
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.event;
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.match_latest_values;
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.pit_latest_values;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -15,9 +20,15 @@ import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentDataReportBinding;
|
||||
import com.ridgebotics.ridgescout.scoutingData.ScoutingDataWriter;
|
||||
import com.ridgebotics.ridgescout.types.data.dataType;
|
||||
import com.ridgebotics.ridgescout.types.frcMatch;
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.types.input.dropdownType;
|
||||
import com.ridgebotics.ridgescout.types.input.inputType;
|
||||
import com.ridgebotics.ridgescout.types.input.sliderType;
|
||||
import com.ridgebotics.ridgescout.utility.DataManager;
|
||||
import com.ridgebotics.ridgescout.utility.fileEditor;
|
||||
import com.ridgebotics.ridgescout.utility.ollama.OllamaTest;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -31,13 +42,17 @@ public class ReportFragment extends Fragment {
|
||||
|
||||
binding = FragmentDataReportBinding.inflate(inflater, container, false);
|
||||
|
||||
DataManager.reload_event();
|
||||
DataManager.reload_pit_fields();
|
||||
DataManager.reload_match_fields();
|
||||
|
||||
getReportMatches();
|
||||
AIDataOverview();
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
public frcMatch[] getTeamMatches(int teamNum){
|
||||
DataManager.reload_event();
|
||||
List<frcMatch> 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());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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.Message> messages;
|
||||
public boolean stream;
|
||||
public ChatRequest(String model, ArrayList<Messages.Message> 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" +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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<Message> 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;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<OllamaModel> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
<TableLayout
|
||||
android:id="@+id/teamMatchesTable"
|
||||
android:layout_width="409dp"
|
||||
android:layout_height="729dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="1dp"
|
||||
android:layout_marginEnd="1dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
@@ -20,6 +20,17 @@
|
||||
android:layout_height="match_parent" />
|
||||
</TableLayout>
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/AyEyeBox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text=""
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/teamMatchesTable"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView4"
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<network-security-config>
|
||||
<base-config cleartextTrafficPermitted="true">
|
||||
<trust-anchors>
|
||||
<certificates src="system" />
|
||||
</trust-anchors>
|
||||
</base-config>
|
||||
</network-security-config>
|
||||
Reference in New Issue
Block a user