diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..d6ccb4c
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+ChatGpt
\ No newline at end of file
diff --git a/app/README.md b/app/README.md
new file mode 100644
index 0000000..fcc074c
--- /dev/null
+++ b/app/README.md
@@ -0,0 +1,31 @@
+# Einleitung (ImageToText)
+Die letzte Aktualisierung hat der App eine wichtige Neuerung hinzugefügt. Jetzt können Nutzer direkt **Bilder** von ihren Handys auswählen. Die App kann dann den **Text aus den ausgewählten Bildern** extrahieren und ihn problemlos an **ChatGPT** weitergeben. Diese Erweiterung macht die App viel besser, da Nutzer nun beispielsweise mathematische Aufgaben von einem Blatt abfotografieren können und sofort die Lösung bekommen.
+# Anforderungen
+Die neueste Erweiterung, die eingeführt wurde, ermöglicht es nun, **Bilder auszuwählen** und ChatGPT den enthaltenen Text zu senden. Die Benutzer können mit dieser Funktion Textinformationen aus Bildern extrahieren und eine Antwort von ChatGPT erhalten.
+
+# Umsetzung
+Mithilfe von **Firebase ML Vision** kann die Erweiterung Bilder aus dem Handy auswählen und den darin enthaltenen Text auslesen. Die Methode **getScanButton().setOnClickListener** startet die Bildauswahl-Intent.
+
+Nachdem das Bild ausgewählt wurde, wird die Methode **processImage(Uri imageUri)** verwendet. In diesem Fall wird das ausgewählte Bild in eine **Bitmap** umgewandelt und der Text wird mit **Firebase ML Vision extrahiert**. Der extrahierte Text wird dann in der Chat-Ansicht als Benutzernachricht angezeigt.
+
+Um eine Antwort zu erhalten, wird der extrahierte Text dann a ChatGPT weitergeleitet. Die Kommunikation mit ChatGPT wird durch eine API-Anfrage mit einem API ermöglicht. ChatGPT-Nachrichten mit den Antworten werden dann angezeigt und vorgelesen.
+
+Zusätzlich zur genannten Funktionalität habe ich im **XML-Layout** des **MainFragment** einen **Button** erstellt. Dieser Button dient dazu, den Auswahlprozess für das Bild zu starten und somit die oben beschriebene Prozedur auszulösen. Darüber hinaus wurde ein **ImageView** hinzugefügt, um das ausgewählte Bild anzuzeigen. Dies bietet den Benutzern eine visuelle Rückmeldung über das ausgewählte Bild, bevor der Text extrahiert und verarbeitet wird. In Kombination mit dem Button ermöglicht dies eine benutzerfreundliche Interaktion mit der Bildverarbeitungsfunktion der App.
+
+### Firebase
+Um die App nutzen zu können, muss zunächst Firebase in der Anwendung aktiviert werden. Die Bilder werden in der Datenbank gespeichert.
+
+#### Aktivierung von Firebase
+1. Öffnen Sie die **Toolbar**, die sich oben befindet.
+2. Wählen Sie **Tools**.
+3. Unter **Tools** wählen Sie **Firebase** aus.
+4. Es erscheint eine umfangreiche Liste.
+5. Suchen Sie nach **Firebase ML** und wählen Sie es aus.
+6. Innerhalb von **Firebase ML** wählen Sie **Use Firebase ML to recognize text in image [Java]**.
+7. Aktivieren Sie die Schritte **1. Connect your app to Firebase** und **3. Add Firebase ML to your app**.
+8. Fertig!
+
+
+# Probleme
+
+Da das geplante Ziel erfolgreich erreicht wurde, gab es keine Probleme. Die gewünschten Funktionen wurden reibungslos eingeführt, und alle notwendigen Aspekte, wie die Auswahl von Bildern, die Extrahierung von Texten und die Kommunikation mit ChatGPT, wurden erfolgreich integriert. Daher verlief das Projekt ohne große Schwierigkeiten und die gewünschten Features wurden erfolgreich umgesetzt.
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index dde8da9..86f1b88 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,5 +1,6 @@
plugins {
id 'com.android.application'
+ id 'com.google.gms.google-services'
}
android {
@@ -29,7 +30,7 @@ android {
}
dependencies {
-
+ implementation 'com.google.firebase:firebase-ml-vision:24.0.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
diff --git a/app/google-services.json b/app/google-services.json
new file mode 100644
index 0000000..f5d215d
--- /dev/null
+++ b/app/google-services.json
@@ -0,0 +1,29 @@
+{
+ "project_info": {
+ "project_number": "1093072293771",
+ "project_id": "chatgpt-242c2",
+ "storage_bucket": "chatgpt-242c2.appspot.com"
+ },
+ "client": [
+ {
+ "client_info": {
+ "mobilesdk_app_id": "1:1093072293771:android:6d84ae93db15a4973f298e",
+ "android_client_info": {
+ "package_name": "de.fhdw.app_entwicklung.chatgpt"
+ }
+ },
+ "oauth_client": [],
+ "api_key": [
+ {
+ "current_key": "AIzaSyDE7-w8OA55sVON8E54muDETdl4KBh9ulM"
+ }
+ ],
+ "services": {
+ "appinvite_service": {
+ "other_platform_oauth_client": []
+ }
+ }
+ }
+ ],
+ "configuration_version": "1"
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 45fda6c..5c304a6 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -4,6 +4,8 @@
+
+
getTextFromSpeech = registerForActivityResult(
new LaunchSpeechRecognition(),
query -> {
- Message userMessage = new Message(Author.User, query);
+ Message userMessage = new Message(Author.User,"Text: \n"+ query);
chat.addMessage(userMessage);
if (chat.getMessages().size() > 1) {
getTextView().append(CHAT_SEPARATOR);
@@ -46,10 +60,10 @@ public class MainFragment extends Fragment {
MainActivity.backgroundExecutorService.execute(() -> {
String apiToken = prefs.getApiToken();
- IChatGpt chatGpt = new MockChatGpt(apiToken);
+ ChatGpt chatGpt = new ChatGpt(apiToken);
String answer = chatGpt.getChatCompletion(chat);
- Message answerMessage = new Message(Author.Assistant, answer);
+ Message answerMessage = new Message(Author.Assistant,"ChatGPT: \n"+ answer);
chat.addMessage(answerMessage);
MainActivity.uiThreadHandler.post(() -> {
@@ -61,12 +75,18 @@ public class MainFragment extends Fragment {
});
});
- public MainFragment() {
- }
+ private final ActivityResultLauncher pickImageLauncher = registerForActivityResult(
+ new ActivityResultContracts.StartActivityForResult(),
+ result -> {
+ if (result.getResultCode() == RESULT_OK && result.getData() != null) {
+ Uri imageUri = result.getData().getData();
+ getImageView().setImageURI(imageUri);
+ processImage(imageUri);
+ }
+ });
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_main, container, false);
}
@@ -83,37 +103,76 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
getAskButton().setOnClickListener(v ->
getTextFromSpeech.launch(new LaunchSpeechRecognition.SpeechRecognitionArgs(Locale.GERMAN)));
+
getResetButton().setOnClickListener(v -> {
chat = new Chat();
updateTextView();
+
+ });
+
+ getScanButton().setOnClickListener(v -> {
+ Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
+ pickImageLauncher.launch(intent);
+
});
+
updateTextView();
}
- @Override
- public void onPause() {
- super.onPause();
- textToSpeech.stop();
- }
+ private void processImage(Uri imageUri) {
+ try {
+ Bitmap bitmap = MediaStore.Images.Media.getBitmap(requireActivity().getContentResolver(), imageUri);
- @Override
- public void onSaveInstanceState(@NonNull Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putParcelable(EXTRA_DATA_CHAT, chat);
- }
+ FirebaseVisionImage firebaseVisionImage = FirebaseVisionImage.fromBitmap(bitmap);
- @Override
- public void onDestroy() {
- textToSpeech.destroy();
- textToSpeech = null;
+ FirebaseVisionTextRecognizer textRecognizer = FirebaseVision.getInstance().getOnDeviceTextRecognizer();
+
+
+ Task result = textRecognizer.processImage(firebaseVisionImage);
- super.onDestroy();
+ result.addOnSuccessListener(firebaseVisionText -> {
+ String extractedText = firebaseVisionText.getText();
+ Message imageMessage = new Message(Author.User, "Text: \n" + extractedText);
+ chat.addMessage(imageMessage);
+
+ if (chat.getMessages().size() > 1) {
+ getTextView().append(CHAT_SEPARATOR);
+ }
+
+ getTextView().append(toString(imageMessage));
+ scrollToEnd();
+
+ MainActivity.backgroundExecutorService.execute(() -> {
+ String apiToken = prefs.getApiToken();
+ ChatGpt chatGpt = new ChatGpt(apiToken);
+
+ String answer = chatGpt.getChatCompletion(chat);
+ Message answerMessage = new Message(Author.Assistant, "ChatGPT: \n" + answer);
+ chat.addMessage(answerMessage);
+
+ MainActivity.uiThreadHandler.post(() -> {
+ getTextView().append(CHAT_SEPARATOR);
+ getTextView().append(toString(answerMessage));
+ scrollToEnd();
+ textToSpeech.speak(answer);
+ });
+ });
+ });
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
}
+
+
private void updateTextView() {
getTextView().setText("");
- List messages = chat.getMessages();
+ getImageView().setImageURI(null);
+ List messages = chat.getMessages().stream()
+ .filter(message -> message.author == Author.User || message.author == Author.Assistant)
+ .collect(Collectors.toList());
if (!messages.isEmpty()) {
getTextView().append(toString(messages.get(0)));
for (int i = 1; i < messages.size(); i++) {
@@ -124,6 +183,7 @@ private void updateTextView() {
scrollToEnd();
}
+
private void scrollToEnd() {
getScrollView().postDelayed(() -> getScrollView().fullScroll(ScrollView.FOCUS_DOWN), 300);
}
@@ -133,23 +193,26 @@ private CharSequence toString(Message message) {
}
private TextView getTextView() {
- //noinspection ConstantConditions
return getView().findViewById(R.id.textView);
}
private Button getAskButton() {
- //noinspection ConstantConditions
return getView().findViewById(R.id.button_ask);
}
private Button getResetButton() {
- //noinspection ConstantConditions
return getView().findViewById(R.id.button_reset);
}
+ private Button getScanButton() {
+ return getView().findViewById(R.id.camera);
+ }
+
private ScrollView getScrollView() {
- //noinspection ConstantConditions
return getView().findViewById(R.id.scrollview);
}
+ private ImageView getImageView() {
+ return getView().findViewById(R.id.image);
+ }
}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/baseline_app_shortcut_24.xml b/app/src/main/res/drawable/baseline_app_shortcut_24.xml
new file mode 100644
index 0000000..c1037c5
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_app_shortcut_24.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/document_scanner_black_24dp.xml b/app/src/main/res/drawable/document_scanner_black_24dp.xml
new file mode 100644
index 0000000..46f5ebc
--- /dev/null
+++ b/app/src/main/res/drawable/document_scanner_black_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/mic_none_black_24dp.xml b/app/src/main/res/drawable/mic_none_black_24dp.xml
new file mode 100644
index 0000000..918f53f
--- /dev/null
+++ b/app/src/main/res/drawable/mic_none_black_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/radius_btn.xml b/app/src/main/res/drawable/radius_btn.xml
new file mode 100644
index 0000000..a5304fc
--- /dev/null
+++ b/app/src/main/res/drawable/radius_btn.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/restart_alt_black_24dp.xml b/app/src/main/res/drawable/restart_alt_black_24dp.xml
new file mode 100644
index 0000000..dc34f75
--- /dev/null
+++ b/app/src/main/res/drawable/restart_alt_black_24dp.xml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_main.xml b/app/src/main/res/layout/fragment_main.xml
index e6e3bda..e8b13c1 100644
--- a/app/src/main/res/layout/fragment_main.xml
+++ b/app/src/main/res/layout/fragment_main.xml
@@ -6,6 +6,7 @@
android:layout_height="match_parent"
tools:context=".MainFragment">
+
+
+ app:layout_constraintTop_toTopOf="parent">
+ android:layout_marginBottom="15dp"
+ android:paddingRight="5dp"
+ android:textColor="@color/black"
+ android:textSize="24sp"
+ android:visibility="visible" />
+
+
+
+
+ app:layout_constraintEnd_toStartOf="@+id/button_reset"
+ app:layout_constraintStart_toEndOf="@+id/button_ask"
+ app:layout_constraintTop_toBottomOf="@+id/scrollview"
+ app:layout_constraintVertical_bias="0.0" />
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 0ebef73..07df78b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,4 +1,8 @@
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
+buildscript {
+ dependencies {
+ classpath 'com.google.gms:google-services:4.4.0'
+ }
+}// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '8.1.0' apply false
id 'com.android.library' version '8.1.0' apply false