From 8b3da8ff6eea3266700052308c55e7ac7a46cf4b Mon Sep 17 00:00:00 2001 From: LilleBRG Date: Thu, 12 Sep 2024 13:40:14 +0200 Subject: [PATCH 1/6] init --- Mobile/lib/main.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/Mobile/lib/main.dart b/Mobile/lib/main.dart index 3784ba8..e593790 100644 --- a/Mobile/lib/main.dart +++ b/Mobile/lib/main.dart @@ -282,7 +282,6 @@ class _MyHomePageState extends State { LatLngBounds bounds = _mapController.camera.visibleBounds; _getOpenStreetMapData(LatLng(bounds.southWest.latitude, bounds.southWest.longitude),LatLng(bounds.northEast.latitude, bounds.northEast.longitude)); - } Future _getOpenStreetMapData(LatLng southWest, LatLng northEast) async { From 4100a5119451ca15d355c2036b603fea0c738c9f Mon Sep 17 00:00:00 2001 From: LilleBRG Date: Fri, 13 Sep 2024 09:59:21 +0200 Subject: [PATCH 2/6] tourist partly done --- .gitignore | 1 + Mobile/.gitignore | 3 +- Mobile/lib/base/sidemenu.dart | 12 +++- Mobile/lib/createreview.dart | 2 +- Mobile/lib/editprofile.dart | 2 +- Mobile/lib/favorites.dart | 2 +- Mobile/lib/login.dart | 2 +- Mobile/lib/main.dart | 4 +- Mobile/lib/profile.dart | 2 +- Mobile/lib/register.dart | 2 +- Mobile/lib/reviewlist.dart | 2 +- Mobile/lib/{ => services}/api.dart | 2 - Mobile/lib/services/openaiservice.dart | 49 +++++++++++++++ Mobile/lib/touristguidebook.dart | 86 ++++++++++++++++++++++++++ Mobile/pubspec.lock | 16 +++++ Mobile/pubspec.yaml | 2 + rust-backend/.env.example | 7 --- 17 files changed, 176 insertions(+), 20 deletions(-) rename Mobile/lib/{ => services}/api.dart (98%) create mode 100644 Mobile/lib/services/openaiservice.dart create mode 100644 Mobile/lib/touristguidebook.dart delete mode 100644 rust-backend/.env.example diff --git a/.gitignore b/.gitignore index 546f686..d797cd2 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ API/bin API/obj .idea +/rust-backend/.env.example diff --git a/Mobile/.gitignore b/Mobile/.gitignore index d90f52b..6b4559a 100644 --- a/Mobile/.gitignore +++ b/Mobile/.gitignore @@ -43,4 +43,5 @@ app.*.map.json /android/app/release environment.json -node_modules \ No newline at end of file +node_modules +.env \ No newline at end of file diff --git a/Mobile/lib/base/sidemenu.dart b/Mobile/lib/base/sidemenu.dart index 0208d7d..95032a5 100644 --- a/Mobile/lib/base/sidemenu.dart +++ b/Mobile/lib/base/sidemenu.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:mobile/api.dart' as api; +import 'package:mobile/services/api.dart' as api; import 'package:shared_preferences/shared_preferences.dart'; import 'package:google_fonts/google_fonts.dart'; import 'variables.dart'; @@ -96,7 +96,7 @@ class _SideMenuState extends State { Navigator.pushReplacementNamed(context, '/favorites'); }, ), - ListTile( + ListTile( title: const Text('Profile'), leading: const Icon(Icons.person), selected: _selectedIndex == 2, @@ -104,6 +104,14 @@ class _SideMenuState extends State { Navigator.pushReplacementNamed(context, '/profile'); }, ), + ListTile( + title: const Text('GuideBook'), + leading: const Icon(Icons.person), + selected: _selectedIndex == 5, + onTap: () { + Navigator.pushReplacementNamed(context, '/tourist-guide-book'); + }, + ), const Divider( color: Colors.grey, thickness: 2, diff --git a/Mobile/lib/createreview.dart b/Mobile/lib/createreview.dart index 4b7060b..86d9d7f 100644 --- a/Mobile/lib/createreview.dart +++ b/Mobile/lib/createreview.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import 'package:mobile/base/sidemenu.dart'; import 'models.dart' as models; -import 'api.dart' as api; +import 'services/api.dart' as api; import 'package:path/path.dart' as path; class CreateReviewPage extends StatefulWidget { diff --git a/Mobile/lib/editprofile.dart b/Mobile/lib/editprofile.dart index bc230b7..ff4b456 100644 --- a/Mobile/lib/editprofile.dart +++ b/Mobile/lib/editprofile.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import 'package:mobile/models.dart' as models; import 'package:shared_preferences/shared_preferences.dart'; -import 'api.dart' as api; +import 'services/api.dart' as api; import 'base/variables.dart'; class EditProfilePage extends StatefulWidget { diff --git a/Mobile/lib/favorites.dart b/Mobile/lib/favorites.dart index 8ac10bf..667abb5 100644 --- a/Mobile/lib/favorites.dart +++ b/Mobile/lib/favorites.dart @@ -1,5 +1,5 @@ import 'dart:convert'; -import 'api.dart' as api; +import 'services/api.dart' as api; import 'package:flutter/material.dart'; import 'base/sidemenu.dart'; // Import the base layout widget import 'models.dart'; diff --git a/Mobile/lib/login.dart b/Mobile/lib/login.dart index 6c21619..084e553 100644 --- a/Mobile/lib/login.dart +++ b/Mobile/lib/login.dart @@ -4,7 +4,7 @@ import 'package:mobile/models.dart' as models; import 'package:shared_preferences/shared_preferences.dart'; import 'package:google_fonts/google_fonts.dart'; import 'dart:convert'; -import 'api.dart' as api; +import 'services/api.dart' as api; import 'base/variables.dart'; class LoginPage extends StatefulWidget { diff --git a/Mobile/lib/main.dart b/Mobile/lib/main.dart index e593790..2214f47 100644 --- a/Mobile/lib/main.dart +++ b/Mobile/lib/main.dart @@ -8,13 +8,14 @@ import 'package:mobile/createreview.dart'; import 'package:mobile/favorites.dart'; import 'package:mobile/register.dart'; import 'package:mobile/reviewlist.dart'; +import 'package:mobile/touristguidebook.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'login.dart'; import 'base/sidemenu.dart'; import 'profile.dart'; import 'models.dart'; import 'package:geolocator/geolocator.dart'; -import 'api.dart' as api; +import 'services/api.dart' as api; import 'package:http/http.dart' as http; void main() async { @@ -48,6 +49,7 @@ class MyApp extends StatelessWidget { '/register': (context) => const RegisterPage(), '/reviews': (context) => const ReviewListPage(), '/create-review': (context) => const CreateReviewPage(), + '/tourist-guide-book': (context) => const TouristGuideBookPage(), }, ); } diff --git a/Mobile/lib/profile.dart b/Mobile/lib/profile.dart index 6fa34fc..121176c 100644 --- a/Mobile/lib/profile.dart +++ b/Mobile/lib/profile.dart @@ -4,7 +4,7 @@ import 'package:mobile/base/variables.dart'; import 'package:mobile/models.dart' as models; import 'package:shared_preferences/shared_preferences.dart'; import 'base/sidemenu.dart'; -import 'api.dart' as api; +import 'services/api.dart' as api; import 'editprofile.dart'; class ProfilePage extends StatefulWidget { diff --git a/Mobile/lib/register.dart b/Mobile/lib/register.dart index b5d9503..0e5df1b 100644 --- a/Mobile/lib/register.dart +++ b/Mobile/lib/register.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:mobile/base/sidemenu.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:mobile/base/variables.dart'; -import 'api.dart' as api; +import 'services/api.dart' as api; class RegisterPage extends StatefulWidget { const RegisterPage({super.key}); diff --git a/Mobile/lib/reviewlist.dart b/Mobile/lib/reviewlist.dart index 4dc2d1b..837d2cc 100644 --- a/Mobile/lib/reviewlist.dart +++ b/Mobile/lib/reviewlist.dart @@ -2,7 +2,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:mobile/base/sidemenu.dart'; import 'models.dart' as models; -import 'api.dart' as api; +import 'services/api.dart' as api; class ReviewListPage extends StatefulWidget { const ReviewListPage({super.key}); diff --git a/Mobile/lib/api.dart b/Mobile/lib/services/api.dart similarity index 98% rename from Mobile/lib/api.dart rename to Mobile/lib/services/api.dart index 7dc969f..e99a012 100644 --- a/Mobile/lib/api.dart +++ b/Mobile/lib/services/api.dart @@ -193,5 +193,3 @@ void logout() async { prefs.remove('refresh-token'); prefs.remove('id'); } - -//------------------------------OPENAI API------------------------------// diff --git a/Mobile/lib/services/openaiservice.dart b/Mobile/lib/services/openaiservice.dart new file mode 100644 index 0000000..a619232 --- /dev/null +++ b/Mobile/lib/services/openaiservice.dart @@ -0,0 +1,49 @@ +import 'package:http/http.dart' as http; +import 'dart:convert'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; + +class OpenAIService { + static Future> getGuideBook(String country) async { + final apiKey = dotenv.env['OPENAI_API_KEY']; + final uri = Uri.parse('https://api.openai.com/v1/chat/completions'); + + final requestBody = jsonEncode({ + "model": "gpt-4o-mini", + "messages": [ + { + "role": "system", + "content": "You are a Tourist-guide book that makes a guidebook over a given country and further instructions in the message." + }, + { + "role": "user", + "content": "Make a tourist guide book over $country. The topics should be: A little introduction to how the people of the country is like and what to expect from the environment, famous tourist attractions in the country(amusement park always included), Basic words that would be nice to learn in the country's language(should always be from English to the country's language) and transportation. These topics should be in a Json-Object format." + } + ], + }); + + final response = await http.post( + uri, + headers: { + 'Authorization': 'Bearer $apiKey', + 'Content-Type': 'application/json', + }, + body: requestBody, + ); + + if (response.statusCode == 200) { + + try { + return jsonDecode(response.body); + } catch (e) { + return { + 'navn': 'Fejl', + 'art': 'Ukendt', + 'type': 'Fejl', + 'description': 'Fejl ved JSON parsing: $e' + }; + } + } else { + throw Exception('Fejl ved hentning af data: ${response.statusCode}'); + } + } +} \ No newline at end of file diff --git a/Mobile/lib/touristguidebook.dart b/Mobile/lib/touristguidebook.dart new file mode 100644 index 0000000..85d44af --- /dev/null +++ b/Mobile/lib/touristguidebook.dart @@ -0,0 +1,86 @@ +import 'package:dropdown_search/dropdown_search.dart'; +import 'package:flutter/material.dart'; +import 'package:mobile/base/sidemenu.dart'; +import 'package:mobile/models.dart' as models; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'dart:convert'; +import 'services/openaiservice.dart' as api; +import 'base/variables.dart'; + +class TouristGuideBookPage extends StatefulWidget { + const TouristGuideBookPage({super.key}); + + @override + State createState() => _TouristGuideBookPageState(); +} + +class _TouristGuideBookPageState extends State { + String? _selectedCountry; + final List countries = [ + "Afghanistan", "Albania", "Algeria", "Andorra", "Angola", "Argentina", + // Add more countries + ]; + + Future getBook() async { + if (_selectedCountry != null) { + final response = await api.OpenAIService.getGuideBook(_selectedCountry!); + print(response); // For debugging to check the response + } else { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Choose a country')), + ); + } + } + + @override + Widget build(BuildContext context) { + return SideMenu( + selectedIndex: 5, + body: Scaffold( + appBar: AppBar( + title: Text('Select Country'), + ), + body: Center( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + children: [ + DropdownSearch( + items: countries, + popupProps: const PopupProps.menu( + showSearchBox: true, + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + labelText: "Search a country", + border: OutlineInputBorder(), + ), + ), + ), + dropdownDecoratorProps: const DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + labelText: "Select a country", + hintText: "Search a country", + border: OutlineInputBorder(), + ), + ), + onChanged: (String? country) { + setState(() { + _selectedCountry = country; + }); + }, + selectedItem: "Select a country you want a touristbook for", + ), + ElevatedButton( + onPressed: getBook, + child: Text('Get Guidebook'), + ), + ], + ), + ), + ), + ), + ); + } +} + diff --git a/Mobile/pubspec.lock b/Mobile/pubspec.lock index fb0194d..e1a71f1 100644 --- a/Mobile/pubspec.lock +++ b/Mobile/pubspec.lock @@ -73,6 +73,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + dropdown_search: + dependency: "direct main" + description: + name: dropdown_search + sha256: "55106e8290acaa97ed15bea1fdad82c3cf0c248dd410e651f5a8ac6870f783ab" + url: "https://pub.dev" + source: hosted + version: "5.0.6" fake_async: dependency: transitive description: @@ -142,6 +150,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_dotenv: + dependency: "direct main" + description: + name: flutter_dotenv + sha256: "9357883bdd153ab78cbf9ffa07656e336b8bbb2b5a3ca596b0b27e119f7c7d77" + url: "https://pub.dev" + source: hosted + version: "5.1.0" flutter_image_compress: dependency: "direct main" description: diff --git a/Mobile/pubspec.yaml b/Mobile/pubspec.yaml index 9b609b5..237d531 100644 --- a/Mobile/pubspec.yaml +++ b/Mobile/pubspec.yaml @@ -43,6 +43,8 @@ dependencies: geolocator: ^13.0.1 image_picker: ^1.1.2 flutter_image_compress: ^2.3.0 + flutter_dotenv: ^5.1.0 + dropdown_search: ^5.0.6 dev_dependencies: flutter_test: diff --git a/rust-backend/.env.example b/rust-backend/.env.example deleted file mode 100644 index f574e23..0000000 --- a/rust-backend/.env.example +++ /dev/null @@ -1,7 +0,0 @@ -JWT_SECRET=DenHerMåAldrigVæreOffentligKunIDetteDemoProjekt -AWS_ACCESS_KEY_ID= -AWS_SECRET_ACCESS_KEY= -AWS_ENDPOINT_URL= -AWS_REGION= -R2_BUCKET_NAME= -R2_BUCKET_URL= From 379112a67724be20a96b05fb54ce2b1ec4fb2920 Mon Sep 17 00:00:00 2001 From: LilleBRG Date: Fri, 13 Sep 2024 11:11:56 +0200 Subject: [PATCH 3/6] commit before bootcanp --- API/API.csproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/API/API.csproj b/API/API.csproj index 99e95d1..1cb680c 100644 --- a/API/API.csproj +++ b/API/API.csproj @@ -10,6 +10,10 @@ . + + <_ContentIncludedByDefault Remove="appsettings.json" /> + + From 5672be582a869c11b9fc9d3ee5867463ee39744b Mon Sep 17 00:00:00 2001 From: LilleBRG Date: Mon, 16 Sep 2024 16:33:37 +0200 Subject: [PATCH 4/6] guidebook work --- Mobile/.env | 1 + Mobile/.gitignore | 3 +- Mobile/lib/base/sidemenu.dart | 15 +- Mobile/lib/main.dart | 3 +- Mobile/lib/services/openaiservice.dart | 34 ++-- Mobile/lib/touristguidebook.dart | 211 ++++++++++++++++++------- Mobile/pubspec.yaml | 1 + 7 files changed, 192 insertions(+), 76 deletions(-) create mode 100644 Mobile/.env diff --git a/Mobile/.env b/Mobile/.env new file mode 100644 index 0000000..adb9b6c --- /dev/null +++ b/Mobile/.env @@ -0,0 +1 @@ +OPENAI_API_KEY=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 \ No newline at end of file diff --git a/Mobile/.gitignore b/Mobile/.gitignore index 6b4559a..d90f52b 100644 --- a/Mobile/.gitignore +++ b/Mobile/.gitignore @@ -43,5 +43,4 @@ app.*.map.json /android/app/release environment.json -node_modules -.env \ No newline at end of file +node_modules \ No newline at end of file diff --git a/Mobile/lib/base/sidemenu.dart b/Mobile/lib/base/sidemenu.dart index 95032a5..c24c80e 100644 --- a/Mobile/lib/base/sidemenu.dart +++ b/Mobile/lib/base/sidemenu.dart @@ -106,7 +106,7 @@ class _SideMenuState extends State { ), ListTile( title: const Text('GuideBook'), - leading: const Icon(Icons.person), + leading: const Icon(Icons.menu_book_sharp), selected: _selectedIndex == 5, onTap: () { Navigator.pushReplacementNamed(context, '/tourist-guide-book'); @@ -126,6 +126,19 @@ class _SideMenuState extends State { ), ] : [ + ListTile( + title: const Text('GuideBook'), + leading: const Icon(Icons.menu_book_sharp), + selected: _selectedIndex == 5, + onTap: () { + Navigator.pushReplacementNamed(context, '/tourist-guide-book'); + }, + ), + const Divider( + color: Colors.grey, + thickness: 2, + indent: 40, + ), ListTile( title: const Text('Register'), leading: const Icon(Icons.add_box_outlined), diff --git a/Mobile/lib/main.dart b/Mobile/lib/main.dart index 2214f47..e7ea6b0 100644 --- a/Mobile/lib/main.dart +++ b/Mobile/lib/main.dart @@ -15,11 +15,12 @@ import 'base/sidemenu.dart'; import 'profile.dart'; import 'models.dart'; import 'package:geolocator/geolocator.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'services/api.dart' as api; import 'package:http/http.dart' as http; void main() async { - // Refresh JWT on startup + await dotenv.load(fileName: ".env"); final prefs = await SharedPreferences.getInstance(); if (prefs.getString("token") != null && prefs.getString("refresh-token") != null) { final token = await api.request(null, api.ApiService.auth, "POST", "/RefreshToken", {'refreshToken': prefs.getString("refresh-token")}); diff --git a/Mobile/lib/services/openaiservice.dart b/Mobile/lib/services/openaiservice.dart index a619232..a9ed368 100644 --- a/Mobile/lib/services/openaiservice.dart +++ b/Mobile/lib/services/openaiservice.dart @@ -3,7 +3,7 @@ import 'dart:convert'; import 'package:flutter_dotenv/flutter_dotenv.dart'; class OpenAIService { - static Future> getGuideBook(String country) async { + static Future getGuideBook(String country) async { final apiKey = dotenv.env['OPENAI_API_KEY']; final uri = Uri.parse('https://api.openai.com/v1/chat/completions'); @@ -16,9 +16,10 @@ class OpenAIService { }, { "role": "user", - "content": "Make a tourist guide book over $country. The topics should be: A little introduction to how the people of the country is like and what to expect from the environment, famous tourist attractions in the country(amusement park always included), Basic words that would be nice to learn in the country's language(should always be from English to the country's language) and transportation. These topics should be in a Json-Object format." + "content": "Make a tourist guide book over $country. The topics should be: A little introduction to how the people of the country is like and what to expect from the environment, famous tourist attractions in the country(amusement park always included), Basic words that would be nice to learn in the country's language(should always be from English to the country's language) and transportation. These topics should be in a Json-Object format in this form: {Country: {introduction: {people: , environment: }, tourist_attractions: {famous_sites: [{name: , description: }]}, basic_words: {}, transportation: {overview: , public_transport: {buses: , trains: , taxis: }}}}" } ], + "max_tokens": 1500 }); final response = await http.post( @@ -30,20 +31,25 @@ class OpenAIService { body: requestBody, ); - if (response.statusCode == 200) { + if (response.statusCode == 200) { + final decodedBody = utf8.decode(response.bodyBytes); + final data = jsonDecode(decodedBody); + var content = data['choices'][0]['message']['content']; - try { - return jsonDecode(response.body); - } catch (e) { - return { - 'navn': 'Fejl', - 'art': 'Ukendt', - 'type': 'Fejl', - 'description': 'Fejl ved JSON parsing: $e' - }; - } + content = content.replaceAll('```json', '').replaceAll('```', '').trim(); + + return _extractDescription(content); } else { - throw Exception('Fejl ved hentning af data: ${response.statusCode}'); + throw Exception('Fejl ved billedanalyse: ${response.statusCode}'); } } + + static String _extractDescription(String content) { + final lines = content.split('\n'); + final startIndex = lines.indexWhere((line) => line.startsWith('**Beskrivelse:**')); + + if (startIndex == -1) return content; + + return lines.skip(startIndex).join('\n').trim(); + } } \ No newline at end of file diff --git a/Mobile/lib/touristguidebook.dart b/Mobile/lib/touristguidebook.dart index 85d44af..17fd777 100644 --- a/Mobile/lib/touristguidebook.dart +++ b/Mobile/lib/touristguidebook.dart @@ -1,12 +1,8 @@ +import 'dart:convert'; import 'package:dropdown_search/dropdown_search.dart'; import 'package:flutter/material.dart'; import 'package:mobile/base/sidemenu.dart'; -import 'package:mobile/models.dart' as models; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:google_fonts/google_fonts.dart'; -import 'dart:convert'; import 'services/openaiservice.dart' as api; -import 'base/variables.dart'; class TouristGuideBookPage extends StatefulWidget { const TouristGuideBookPage({super.key}); @@ -17,15 +13,66 @@ class TouristGuideBookPage extends StatefulWidget { class _TouristGuideBookPageState extends State { String? _selectedCountry; - final List countries = [ - "Afghanistan", "Albania", "Algeria", "Andorra", "Angola", "Argentina", - // Add more countries - ]; + bool _isLoading = false; + Map _touristbook = {}; + final List countries = [ + "Afghanistan", "Albania", "Algeria", "Andorra", "Angola", "Argentina", + "Armenia", "Australia", "Austria", "Azerbaijan", "Bahamas", "Bahrain", + "Bangladesh", "Barbados", "Belarus", "Belgium", "Belize", "Benin", + "Bhutan", "Bolivia", "Bosnia and Herzegovina", "Botswana", "Brazil", + "Brunei", "Bulgaria", "Burkina Faso", "Burundi", "Cabo Verde", "Cambodia", + "Cameroon", "Canada", "Central African Republic", "Chad", "Chile", "China", + "Colombia", "Comoros", "Congo (Congo-Brazzaville)", "Congo (Democratic Republic)", + "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic", "Denmark", + "Djibouti", "Dominica", "Dominican Republic", "Ecuador", "Egypt", "El Salvador", + "Equatorial Guinea", "Eritrea", "Estonia", "Eswatini", "Ethiopia", "Fiji", + "Finland", "France", "Gabon", "Gambia", "Georgia", "Germany", "Ghana", + "Greece", "Grenada", "Guatemala", "Guinea", "Guinea-Bissau", "Guyana", + "Haiti", "Honduras", "Hungary", "Iceland", "India", "Indonesia", "Iran", + "Iraq", "Ireland", "Israel", "Italy", "Jamaica", "Japan", "Jordan", "Kazakhstan", + "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos", "Latvia", "Lebanon", + "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg", + "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", + "Mauritania", "Mauritius", "Mexico", "Micronesia", "Moldova", "Monaco", + "Mongolia", "Montenegro", "Morocco", "Mozambique", "Myanmar", "Namibia", + "Nauru", "Nepal", "Netherlands", "New Zealand", "Nicaragua", "Niger", + "Nigeria", "North Korea", "North Macedonia", "Norway", "Oman", "Pakistan", + "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru", "Philippines", + "Poland", "Portugal", "Qatar", "Romania", "Russia", "Rwanda", "Saint Kitts and Nevis", + "Saint Lucia", "Saint Vincent and the Grenadines", "Samoa", "San Marino", + "Sao Tome and Principe", "Saudi Arabia", "Senegal", "Serbia", "Seychelles", + "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands", + "Somalia", "South Africa", "South Korea", "South Sudan", "Spain", "Sri Lanka", + "Sudan", "Suriname", "Sweden", "Switzerland", "Syria", "Taiwan", "Tajikistan", + "Tanzania", "Thailand", "Timor-Leste", "Togo", "Tonga", "Trinidad and Tobago", + "Tunisia", "Turkey", "Turkmenistan", "Tuvalu", "Uganda", "Ukraine", + "United Arab Emirates", "United Kingdom", "United States", "Uruguay", "Uzbekistan", + "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Yemen", "Zambia", "Zimbabwe" +]; Future getBook() async { if (_selectedCountry != null) { - final response = await api.OpenAIService.getGuideBook(_selectedCountry!); - print(response); // For debugging to check the response + setState(() { + _isLoading = true; + }); + + try { + final response = await api.OpenAIService.getGuideBook(_selectedCountry!); + print(response); + final jsonData = jsonDecode(response); + setState(() { + _touristbook = jsonData[_selectedCountry!]; + }); + } catch (e) { + print('Error fetching guidebook: $e'); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Failed to load guidebook')), + ); + } finally { + setState(() { + _isLoading = false; + }); + } } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Choose a country')), @@ -33,54 +80,102 @@ class _TouristGuideBookPageState extends State { } } - @override - Widget build(BuildContext context) { - return SideMenu( - selectedIndex: 5, - body: Scaffold( - appBar: AppBar( - title: Text('Select Country'), - ), - body: Center( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - children: [ - DropdownSearch( - items: countries, - popupProps: const PopupProps.menu( - showSearchBox: true, - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - labelText: "Search a country", - border: OutlineInputBorder(), - ), - ), - ), - dropdownDecoratorProps: const DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - labelText: "Select a country", - hintText: "Search a country", - border: OutlineInputBorder(), - ), - ), - onChanged: (String? country) { - setState(() { - _selectedCountry = country; - }); - }, - selectedItem: "Select a country you want a touristbook for", - ), - ElevatedButton( - onPressed: getBook, - child: Text('Get Guidebook'), - ), - ], - ), - ), - ), + Widget _buildTouristBookSection(String title, String content) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(title, style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), + SizedBox(height: 5), + Text(content, style: TextStyle(fontSize: 16)), + ], ), ); } -} + @override +Widget build(BuildContext context) { + return SideMenu( + selectedIndex: 5, + body: Scaffold( + appBar: AppBar( + title: Text('Select Country'), + ), + body: _isLoading + ? Center(child: CircularProgressIndicator()) + : SingleChildScrollView( // Added SingleChildScrollView here + padding: const EdgeInsets.all(16.0), + child: Column( + children: [ + DropdownSearch( + items: countries, + popupProps: const PopupProps.menu( + showSearchBox: true, + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + labelText: "Search a country", + border: OutlineInputBorder(), + ), + ), + ), + dropdownDecoratorProps: const DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + labelText: "Select a country", + hintText: "Search a country", + border: OutlineInputBorder(), + ), + ), + onChanged: (String? country) { + setState(() { + _selectedCountry = country; + }); + }, + selectedItem: "Select a country you want a touristbook for", + ), + SizedBox(height: 20), + ElevatedButton( + onPressed: getBook, + child: Text('Get Guidebook'), + ), + if (_touristbook.isNotEmpty) ...[ + _buildTouristBookSection( + "Introduction - People", + _touristbook['introduction']?['people'] ?? 'No data', + ), + _buildTouristBookSection( + "Introduction - Environment", + _touristbook['introduction']?['environment'] ?? 'No data', + ), + _buildTouristBookSection( + "Famous Sites", + _touristbook['tourist_attractions']?['famous_sites']?.map((site) => site['name'] + ':\n' + site['description']).join('\n') ?? 'No data', + ), + _buildTouristBookSection( + "Basic Language - Greetings", + _touristbook['basic_words']?.entries.map((e) => '${e.key}: ${e.value}').join('\n') ?? 'No data', + ), + _buildTouristBookSection( + "Transportation Overview", + _touristbook['transportation']?['overview'] ?? 'No data', + ), + _buildTouristBookSection( + "Public Transport - Buses", + _touristbook['transportation']?['public_transport']?['buses'] ?? 'No data', + ), + _buildTouristBookSection( + "Public Transport - Trains", + _touristbook['transportation']?['public_transport']?['trains'] ?? 'No data', + ), + _buildTouristBookSection( + "Public Transport - Taxis", + _touristbook['transportation']?['public_transport']?['taxis'] ?? 'No data', + ), + ], + ], + ), + ), + ), + ); +} +} diff --git a/Mobile/pubspec.yaml b/Mobile/pubspec.yaml index 237d531..aaf1ad7 100644 --- a/Mobile/pubspec.yaml +++ b/Mobile/pubspec.yaml @@ -64,6 +64,7 @@ dev_dependencies: flutter: assets: - assets/ + - .env uses-material-design: true # To add assets to your application, add an assets section, like this: From e5f7ca1560171a5eca072b19145dca24b361cfa7 Mon Sep 17 00:00:00 2001 From: LilleBRG Date: Tue, 17 Sep 2024 09:14:31 +0200 Subject: [PATCH 5/6] guidebook done --- Mobile/.gitignore | 3 ++- Mobile/lib/touristguidebook.dart | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Mobile/.gitignore b/Mobile/.gitignore index d90f52b..6b4559a 100644 --- a/Mobile/.gitignore +++ b/Mobile/.gitignore @@ -43,4 +43,5 @@ app.*.map.json /android/app/release environment.json -node_modules \ No newline at end of file +node_modules +.env \ No newline at end of file diff --git a/Mobile/lib/touristguidebook.dart b/Mobile/lib/touristguidebook.dart index 17fd777..75d9346 100644 --- a/Mobile/lib/touristguidebook.dart +++ b/Mobile/lib/touristguidebook.dart @@ -85,6 +85,7 @@ class _TouristGuideBookPageState extends State { padding: const EdgeInsets.symmetric(vertical: 8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, children: [ Text(title, style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), SizedBox(height: 5), @@ -139,6 +140,9 @@ Widget build(BuildContext context) { child: Text('Get Guidebook'), ), if (_touristbook.isNotEmpty) ...[ + _buildTouristBookSection( + _selectedCountry!,"" + ), _buildTouristBookSection( "Introduction - People", _touristbook['introduction']?['people'] ?? 'No data', From 65e3266de4399799fc1ceb51f8a00dddcbf52207 Mon Sep 17 00:00:00 2001 From: LilleBRG Date: Tue, 17 Sep 2024 09:20:20 +0200 Subject: [PATCH 6/6] created .env.example --- Mobile/.env | 1 - Mobile/.env.example | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 Mobile/.env create mode 100644 Mobile/.env.example diff --git a/Mobile/.env b/Mobile/.env deleted file mode 100644 index adb9b6c..0000000 --- a/Mobile/.env +++ /dev/null @@ -1 +0,0 @@ -OPENAI_API_KEY=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 \ No newline at end of file diff --git a/Mobile/.env.example b/Mobile/.env.example new file mode 100644 index 0000000..9847a1d --- /dev/null +++ b/Mobile/.env.example @@ -0,0 +1 @@ +OPENAI_API_KEY= \ No newline at end of file