diff --git a/app/src/main/java/eu/faircode/email/FragmentCompose.java b/app/src/main/java/eu/faircode/email/FragmentCompose.java index 688a294c0a..7f788f3a2c 100644 --- a/app/src/main/java/eu/faircode/email/FragmentCompose.java +++ b/app/src/main/java/eu/faircode/email/FragmentCompose.java @@ -2790,8 +2790,9 @@ public class FragmentCompose extends FragmentBase { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); String model = prefs.getString("gemini_model", "gemini-pro"); + float temperature = prefs.getFloat("gemini_temperature", 0.5f); - return Gemini.generate(context, model, new String[]{Gemini.truncateParagraphs(body)}); + return Gemini.generate(context, model, new String[]{Gemini.truncateParagraphs(body)}, temperature); } @Override diff --git a/app/src/main/java/eu/faircode/email/FragmentDialogSummarize.java b/app/src/main/java/eu/faircode/email/FragmentDialogSummarize.java index 4aa3ef593a..b4e57f40c8 100644 --- a/app/src/main/java/eu/faircode/email/FragmentDialogSummarize.java +++ b/app/src/main/java/eu/faircode/email/FragmentDialogSummarize.java @@ -106,9 +106,10 @@ public class FragmentDialogSummarize extends FragmentDialogBase { return sb.toString(); } else if (Gemini.isAvailable(context)) { String model = prefs.getString("gemini_model", "gemini-pro"); + float temperature = prefs.getFloat("gemini_temperature", 0.5f); String prompt = prefs.getString("gemini_summarize", Gemini.SUMMARY_PROMPT); - String[] result = Gemini.generate(context, model, new String[]{prompt, text}); + String[] result = Gemini.generate(context, model, new String[]{prompt, text}, temperature); return TextUtils.join("\n", result); } diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsIntegrations.java b/app/src/main/java/eu/faircode/email/FragmentOptionsIntegrations.java index 2638be48fc..0bbeb647c6 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptionsIntegrations.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptionsIntegrations.java @@ -90,6 +90,8 @@ public class FragmentOptionsIntegrations extends FragmentBase implements SharedP private EditText etGemini; private TextInputLayout tilGemini; private EditText etGeminiModel; + private TextView tvGeminiTemperature; + private SeekBar sbGeminiTemperature; private EditText etGeminiSummarize; private ImageButton ibGemini; @@ -106,7 +108,7 @@ public class FragmentOptionsIntegrations extends FragmentBase implements SharedP "vt_enabled", "vt_apikey", "send_enabled", "send_host", "send_dlimit", "send_tlimit", "openai_enabled", "openai_uri", "openai_apikey", "openai_model", "openai_temperature", "openai_moderation", "openai_summarize", - "gemini_enabled", "gemini_uri", "gemini_apikey", "gemini_model", "gemini_summarize" + "gemini_enabled", "gemini_uri", "gemini_apikey", "gemini_model", "gemini_temperature", "gemini_summarize" )); @Override @@ -162,6 +164,8 @@ public class FragmentOptionsIntegrations extends FragmentBase implements SharedP etGemini = view.findViewById(R.id.etGemini); tilGemini = view.findViewById(R.id.tilGemini); etGeminiModel = view.findViewById(R.id.etGeminiModel); + tvGeminiTemperature = view.findViewById(R.id.tvGeminiTemperature); + sbGeminiTemperature = view.findViewById(R.id.sbGeminiTemperature); etGeminiSummarize = view.findViewById(R.id.etGeminiSummarize); ibGemini = view.findViewById(R.id.ibGemini); @@ -556,6 +560,7 @@ public class FragmentOptionsIntegrations extends FragmentBase implements SharedP public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { prefs.edit().putBoolean("gemini_enabled", checked).apply(); etGeminiModel.setEnabled(checked); + sbGeminiTemperature.setEnabled(checked); etGeminiSummarize.setEnabled(checked); if (checked) swOpenAi.setChecked(false); @@ -634,6 +639,24 @@ public class FragmentOptionsIntegrations extends FragmentBase implements SharedP } }); + sbGeminiTemperature.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + float temp = progress / 20f; + prefs.edit().putFloat("gemini_temperature", temp).apply(); + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + // Do nothing + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + // Do nothing + } + }); + etGeminiSummarize.setHint(Gemini.SUMMARY_PROMPT); etGeminiSummarize.addTextChangedListener(new TextWatcher() { @Override @@ -780,6 +803,12 @@ public class FragmentOptionsIntegrations extends FragmentBase implements SharedP tilGemini.getEditText().setText(prefs.getString("gemini_apikey", null)); etGeminiModel.setText(prefs.getString("gemini_model", null)); etGeminiModel.setEnabled(swGemini.isChecked()); + + temperature = prefs.getFloat("gemini_temperature", 0.5f); + tvGeminiTemperature.setText(getString(R.string.title_advanced_openai_temperature, NF.format(temperature))); + sbGeminiTemperature.setProgress(Math.round(temperature * 20)); + sbGeminiTemperature.setEnabled(swGemini.isChecked()); + etGeminiSummarize.setText(prefs.getString("gemini_summarize", null)); etGeminiSummarize.setEnabled(swGemini.isChecked()); } catch (Throwable ex) { diff --git a/app/src/main/java/eu/faircode/email/Gemini.java b/app/src/main/java/eu/faircode/email/Gemini.java index ea731db039..784bd6cce7 100644 --- a/app/src/main/java/eu/faircode/email/Gemini.java +++ b/app/src/main/java/eu/faircode/email/Gemini.java @@ -40,6 +40,8 @@ import java.util.Objects; public class Gemini { // https://ai.google.dev/models/gemini + static final String MODEL = "model"; + static final String USER = "user"; static final String SUMMARY_PROMPT = "Summarize the following text:"; private static final int MAX_GEMINI_LEN = 4000; // characters @@ -57,7 +59,7 @@ public class Gemini { (!TextUtils.isEmpty(apikey) || !Objects.equals(getUri(context), BuildConfig.GEMINI_ENDPOINT))); } - static String[] generate(Context context, String model, String[] texts) throws JSONException, IOException { + static String[] generate(Context context, String model, String[] texts, float temperature) throws JSONException, IOException { JSONArray jpart = new JSONArray(); for (String text : texts) { JSONObject jtext = new JSONObject(); @@ -67,10 +69,17 @@ public class Gemini { JSONObject jcontent0 = new JSONObject(); jcontent0.put("parts", jpart); + jcontent0.put("role", USER); JSONArray jcontents = new JSONArray(); jcontents.put(jcontent0); + + // https://ai.google.dev/api/python/google/generativeai/GenerationConfig + JSONObject jconfig = new JSONObject(); + jconfig.put("temperature", temperature); + JSONObject jrequest = new JSONObject(); jrequest.put("contents", jcontents); + jrequest.put("generationConfig", jconfig); String path = "models/" + Uri.encode(model) + ":generateContent"; diff --git a/app/src/main/res/layout/fragment_options_integrations.xml b/app/src/main/res/layout/fragment_options_integrations.xml index 8869a0b4a4..402d8669ed 100644 --- a/app/src/main/res/layout/fragment_options_integrations.xml +++ b/app/src/main/res/layout/fragment_options_integrations.xml @@ -750,6 +750,31 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/tvGeminiModel" /> + + + + + app:layout_constraintTop_toBottomOf="@id/sbGeminiTemperature" />