quero meter o gemini na app

This commit is contained in:
2026-02-10 16:58:11 +00:00
parent 1d5470b8a4
commit 325255e43a
77 changed files with 3466 additions and 4508 deletions

View File

@@ -40,22 +40,53 @@ public class RegisterActivity extends AppCompatActivity {
int age = Integer.parseInt(ageStr);
AppDatabase db = AppDatabase.getDatabase(getApplicationContext());
UserDao userDao = db.userDao();
binding.registerButton.setEnabled(false);
binding.registerButton.setText("A registar...");
AppDatabase.databaseWriteExecutor.execute(() -> {
User existing = userDao.checkUser(email);
if (existing != null) {
runOnUiThread(() -> Toast.makeText(this, "Email já registado", Toast.LENGTH_SHORT).show());
} else {
User newUser = new User(name, email, password, age, utenteStr);
userDao.insert(newUser);
runOnUiThread(() -> {
Toast.makeText(this, "Conta criada com sucesso!", Toast.LENGTH_SHORT).show();
startActivity(new Intent(this, LoginActivity.class));
finish();
com.google.firebase.auth.FirebaseAuth mAuth = com.google.firebase.auth.FirebaseAuth.getInstance();
com.google.firebase.firestore.FirebaseFirestore db = com.google.firebase.firestore.FirebaseFirestore
.getInstance();
mAuth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(this, task -> {
if (task.isSuccessful()) {
// Registration success, save additional info to Firestore
com.google.firebase.auth.FirebaseUser firebaseUser = mAuth.getCurrentUser();
if (firebaseUser != null) {
String userId = firebaseUser.getUid();
java.util.Map<String, Object> userMap = new java.util.HashMap<>();
userMap.put("uid", userId);
userMap.put("name", name);
userMap.put("email", email);
userMap.put("age", age);
userMap.put("utenteNumber", utenteStr);
userMap.put("profilePictureUri", ""); // Init empty
db.collection("users").document(userId)
.set(userMap)
.addOnSuccessListener(aVoid -> {
// Optional: Also save to local Room DB for offline cache if desired,
// but for now we focus on Firebase as requested.
Toast.makeText(RegisterActivity.this, "Conta criada com sucesso!",
Toast.LENGTH_SHORT).show();
startActivity(new Intent(RegisterActivity.this, LoginActivity.class));
finish();
})
.addOnFailureListener(e -> {
binding.registerButton.setEnabled(true);
binding.registerButton.setText("Registar");
Toast.makeText(RegisterActivity.this, "Erro ao salvar dados: " + e.getMessage(),
Toast.LENGTH_SHORT).show();
});
}
} else {
binding.registerButton.setEnabled(true);
binding.registerButton.setText("Registar");
Toast.makeText(RegisterActivity.this, "Falha no registo: " + task.getException().getMessage(),
Toast.LENGTH_SHORT).show();
}
});
}
});
}
}

View File

@@ -1,21 +1,17 @@
package com.example.cuida.ui.sns24;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.example.cuida.databinding.FragmentSns24Binding;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationServices;
import com.google.ai.client.generativeai.GenerativeModel;
import com.google.ai.client.generativeai.java.GenerativeModelFutures;
import com.google.ai.client.generativeai.type.Content;
@@ -23,110 +19,95 @@ import com.google.ai.client.generativeai.type.GenerateContentResponse;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import com.example.cuida.databinding.FragmentSns24Binding;
public class Sns24Fragment extends Fragment {
private FragmentSns24Binding binding;
private FusedLocationProviderClient fusedLocationClient;
private GenerativeModelFutures ai; // Equivalent to 'const ai = genkit(...)'
// API Key configurada
private GenerativeModelFutures model;
private static final String API_KEY = "AIzaSyBmLgn-SHaTDvAeDWsw2iTZRR9gahhOu7k";
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
binding = FragmentSns24Binding.inflate(inflater, container, false);
fusedLocationClient = LocationServices.getFusedLocationProviderClient(requireActivity());
// Initialize Gemini (Android equivalent of Genkit gemini15Flash configuration)
try {
GenerativeModel gm = new GenerativeModel("gemini-1.5-flash", API_KEY);
ai = GenerativeModelFutures.from(gm);
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(getContext(), "Erro ao iniciar IA: " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
binding.buttonCallSns.setOnClickListener(v -> {
try {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:808242424"));
startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(getContext(), "Não foi possível realizar a chamada.", Toast.LENGTH_SHORT).show();
}
});
binding.buttonAiTriage.setOnClickListener(v -> performTriage());
return binding.getRoot();
}
private void performTriage() {
if (API_KEY.equals("YOUR_API_KEY")) {
Toast.makeText(getContext(), "Configure a API Key no ficheiro Sns24Fragment.java!", Toast.LENGTH_LONG)
.show();
return;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (ai == null) {
Toast.makeText(getContext(), "IA não inicializada. Verifique s Logs.", Toast.LENGTH_SHORT).show();
return;
}
// 1. Inicializar o Modelo Gemini
// NOTA: Substitua "SUA_API_KEY" pela sua chave do Google AI Studio
GenerativeModel gm = new GenerativeModel("gemini-1.5-flash", API_KEY);
model = GenerativeModelFutures.from(gm);
String symptoms = binding.inputSymptoms.getText().toString();
if (symptoms.isEmpty()) {
binding.inputSymptoms.setError("Por favor descreva o que sente");
return;
}
// 2. Botão Ligar SNS 24
binding.buttonCallSns.setOnClickListener(v -> {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:808242424"));
startActivity(intent);
});
// 3. Botão Triagem IA
binding.buttonAiTriage.setOnClickListener(v -> {
String symptoms = binding.inputSymptoms.getText().toString().trim();
if (!symptoms.isEmpty()) {
analyzeSymptomsWithGemini(symptoms);
} else {
Toast.makeText(getContext(), "Por favor, descreva os seus sintomas.", Toast.LENGTH_SHORT).show();
}
});
}
private void analyzeSymptomsWithGemini(String symptoms) {
// Feedback visual de carregamento
binding.buttonAiTriage.setEnabled(false);
binding.buttonAiTriage.setText("A analisar...");
binding.textAiResult.setVisibility(View.GONE);
binding.textAiResult.setVisibility(View.VISIBLE);
binding.textAiResult.setText("A analisar sintomas com IA...");
// This prompt structure is equivalent to the flow in Genkit
String prompt = "O utilizador está a sentir o seguinte: " + symptoms + ". " +
"Analisa a gravidade como 'gemini-1.5-flash'. Deves recomendar uma de duas opções: 'Ir ao Hospital' ou 'Ir ao Posto Médico'. "
+
"Explica brevemente o porquê. Responde em Português de Portugal.";
// Criar o prompt
Content content = new Content.Builder()
.addText("Atua como um assistente de triagem de saúde. O utilizador diz: \"" + symptoms + "\". " +
"Dá uma resposta curta (máximo 4 linhas) sobre a urgência e se deve ligar para o SNS 24 (808242424). "
+
"Aviso: Isto não substitui aconselhamento médico.")
.build();
Content content = new Content.Builder().addText(prompt).build();
Executor executor = Executors.newSingleThreadExecutor();
// Executar chamada assíncrona (usando Guava Futures para Java)
ListenableFuture<GenerateContentResponse> response = model.generateContent(content);
// Equivalent to: const { text } = await ai.generate(...)
ListenableFuture<GenerateContentResponse> response = ai.generateContent(content);
// Executor para rodar a resposta na UI Thread
// Creating a new single thread executor for the background work if needed,
// but the callback needs to run on main thread or handle UI updates on main
// thread.
// We use ContextCompat.getMainExecutor to be safe on API < 28 (minSdk is 24)
Futures.addCallback(response, new FutureCallback<GenerateContentResponse>() {
@Override
public void onSuccess(GenerateContentResponse result) {
String resultText = result.getText();
requireActivity().runOnUiThread(() -> {
if (getActivity() != null) {
binding.textAiResult.setText(result.getText());
binding.buttonAiTriage.setEnabled(true);
binding.buttonAiTriage.setText("Analisar Sintomas");
binding.textAiResult.setText(resultText);
binding.textAiResult.setVisibility(View.VISIBLE);
});
}
}
@Override
public void onFailure(Throwable t) {
t.printStackTrace();
requireActivity().runOnUiThread(() -> {
if (getActivity() != null) {
binding.textAiResult.setText("Erro ao contactar a IA: " + t.getMessage());
binding.buttonAiTriage.setEnabled(true);
binding.buttonAiTriage.setText("Analisar Sintomas");
Toast.makeText(getContext(), "Erro na análise: " + t.getMessage(), Toast.LENGTH_LONG).show();
});
}
}
}, executor);
}, androidx.core.content.ContextCompat.getMainExecutor(requireContext()));
}
// AI Triage methods removed
// Nearest Hospital feature removed with AI Triage
@Override
public void onDestroyView() {
super.onDestroyView();