Flutter Templates
Как создать приложение AI-ответчика на электронные письма с помощью Flutter и Back4App
42 мин
введение в этом учебном пособии вы создадите приложение для автоматического ответа на электронные письма с использованием flutter для фронтенда и back4app для бэкенда приложение будет интегрироваться с почтовыми сервисами, такими как gmail или outlook, анализировать входящие электронные письма с помощью ии моделей (таких как gpt 3 от openai) и генерировать персонализированные ответы к концу этого учебного пособия у вас будет функциональное приложение, которое может управлять электронными письмами, генерировать автоматические ответы и позволять пользователям персонализировать свои взаимодействия по электронной почте это приложение использует мощь сервера parse от back4app для обработки аутентификации пользователей, хранения данных и облачных функций, предоставляя масштабируемое решение для бэкенда без необходимости управлять серверной инфраструктурой интеграция возможностей ии и почтовых сервисов улучшит ваши навыки разработки на flutter и создаст основу для создания продвинутых, основанных на данных приложений предварительные требования чтобы завершить это учебное пособие, вам потребуется аккаунт back4app зарегистрируйтесь для получения бесплатного аккаунта на back4app https //www back4app com/ установленный flutter sdk , на вашем локальном компьютере следуйте официальному руководству по установке flutter https //flutter dev/docs/get started/install , соответствующему вашей операционной системе базовые знания dart и flutter разработки если вы новичок в flutter, рассмотрите возможность изучения документации flutter https //flutter dev/docs перед тем, как продолжить знание rest api и асинхронного программирования в dart аккаунт у поставщика ии услуг (например, openai) зарегистрируйтесь для получения api ключа для доступа к ии моделям аккаунт электронной почты (gmail или outlook) для тестирования интеграции шаг 1 — настройка вашего бэкенда back4app на этом этапе вы создадите новое приложение back4app, настроите свои классы данных и сконфигурируете бэкенд для работы с вашим приложением на flutter 1 1 создание нового приложения на back4app войдите в ваш панель управления back4app https //dashboard back4app com/ нажмите на "создать новое приложение" введите название приложения (например, "ai email responder") и выберите ваш иконку приложения выберите местоположение вашего сервера, если будет предложено нажмите "создать" 1 2 получить ключи приложения в панели управления вашего приложения перейдите в настройки приложения > безопасность и ключи запишите идентификатор приложения и ключ клиента они понадобятся для настройки вашего приложения flutter 1 3 определите классы вашей модели данных мы создадим следующие классы в back4app пользователь (по умолчанию) emailaccount emailtemplate responsehistory 1 3 1 создайте класс emailaccount перейдите к база данных > обозреватель нажмите "создать класс" выберите "пользовательский" и назовите его emailaccount нажмите "создать класс" добавьте следующие столбцы к emailaccount пользователь (pointer< user>) указывает на пользователь объект emailaddress (строка) accounttype (строка) например, gmail, outlook authtoken (строка) будет хранить зашифрованные токены 1 3 2 создайте класс emailtemplate повторите шаги, чтобы создать новый класс с именем emailtemplate добавьте следующие столбцы к emailtemplate пользователь (pointer< user>) templatename (строка) templatecontent (строка) templatetype (строка) например, формальный, неформальный, последующий 1 3 3 создайте класс responsehistory создайте новый класс с именем responsehistory добавьте следующие столбцы к responsehistory пользователь (pointer< user>) оригинальноерезюмеэлектроннойпочты (string) сгенерированныйответ (string) пользовательизменилответ (string) сэкономленноевремя (number) 1 4 установить разрешения на уровне класса убедитесь, что только аутентифицированные пользователи могут получить доступ к своим данным в каждом классе перейдите в раздел безопасность установите разрешения на уровне класса (clp) для разрешения на чтение/запись только для аутентифицированных пользователей шаг 2 — инициализация вашего проекта flutter на этом этапе вы настроите свой проект flutter и сконфигурируете его для подключения к back4app 2 1 создать новый проект flutter откройте терминал и выполните flutter create ai email responder перейдите в каталог проекта cd ai email responder 2 2 добавьте необходимые зависимости откройте pubspec yaml и добавьте следующие зависимости dependencies flutter sdk flutter parse server sdk flutter ^4 0 1 flutter email sender ^5 0 2 http ^0 13 4 provider ^6 0 2 fl chart ^0 45 1 запустите flutter pub get для установки пакетов 2 3 инициализируйте parse в вашем приложении создайте новый файл lib/config/back4app config dart // lib/config/back4app config dart const string keyapplicationid = 'your application id'; const string keyclientkey = 'your client key'; const string keyparseserverurl = 'https //parseapi back4app com'; замените 'your application id' и 'your client key' на ключи из back4app в lib/main dart , инициализируйте parse // lib/main dart import 'package\ flutter/material dart'; import 'package\ parse server sdk flutter/parse server sdk dart'; import 'config/back4app config dart'; import 'app dart'; void main() async { widgetsflutterbinding ensureinitialized(); await parse() initialize( keyapplicationid, keyparseserverurl, clientkey keyclientkey, autosendsessionid true, debug true, ); runapp(myapp()); } создайте lib/app dart // lib/app dart import 'package\ flutter/material dart'; import 'screens/home screen dart'; class myapp extends statelesswidget { @override widget build(buildcontext context) { return materialapp( title 'ai email responder', theme themedata( primaryswatch colors blue, ), home homescreen(), ); } } шаг 3 — реализация аутентификации пользователей теперь вы реализуете регистрацию и вход пользователей с использованием parse server 3 1 создание экранов аутентификации создайте lib/screens/login screen dart и lib/screens/signup screen dart для краткости мы сосредоточимся на функциональности входа // lib/screens/login screen dart import 'package\ flutter/material dart'; import 'package\ parse server sdk flutter/parse server sdk dart'; import 'home screen dart'; class loginscreen extends statefulwidget { @override loginscreenstate createstate() => loginscreenstate(); } class loginscreenstate extends state\<loginscreen> { final texteditingcontroller usernamecontroller = texteditingcontroller(); final texteditingcontroller passwordcontroller = texteditingcontroller(); future\<void> douserlogin() async { final username = usernamecontroller text trim(); final password = passwordcontroller text trim(); final user = parseuser(username, password, null); final response = await user login(); if (response success) { navigator pushreplacement( context, materialpageroute(builder (context) => homescreen()), ); } else { showerror(response error! message); } } void showerror(string message) { scaffoldmessenger of(context) showsnackbar(snackbar(content text('error $message'))); } @override widget build(buildcontext context) { return scaffold( appbar appbar( title text('login'), ), body padding( padding const edgeinsets all(16), child column( children \[ textfield( controller usernamecontroller, decoration inputdecoration(labeltext 'username', icon icon(icons person)), ), textfield( controller passwordcontroller, decoration inputdecoration(labeltext 'password', icon icon(icons lock)), obscuretext true, ), sizedbox(height 20), elevatedbutton( onpressed douserlogin, child text('login'), ), ], ), ), ); } } 3 2 обновление навигации на главном экране измените lib/app dart чтобы направить пользователей на экран входа, если они не аутентифицированы // lib/app dart import 'package\ flutter/material dart'; import 'package\ parse server sdk flutter/parse server sdk dart'; import 'screens/home screen dart'; import 'screens/login screen dart'; class myapp extends statelesswidget { future\<bool> hasuserloggedin() async { final currentuser = await parseuser currentuser() as parseuser?; return currentuser != null; } @override widget build(buildcontext context) { return futurebuilder\<bool>( future hasuserloggedin(), builder (context, snapshot) { if (snapshot hasdata && snapshot data == true) { return materialapp( title 'ai email responder', theme themedata(primaryswatch colors blue), home homescreen(), ); } else { return materialapp( title 'ai email responder', theme themedata(primaryswatch colors blue), home loginscreen(), ); } }, ); } } шаг 4 — интеграция почтовых сервисов на этом этапе вы настроите интеграцию электронной почты с использованием пакета flutter email sender 4 1 настройка отправителя электронной почты добавьте необходимые разрешения в ваши конфигурации для android и ios для android , обновите android/app/src/main/androidmanifest xml \<uses permission android\ name="android permission internet"/> для ios , убедитесь, что ваш info plist включает \<key>nsapptransportsecurity\</key> \<dict> \<key>nsallowsarbitraryloads\</key> \<true/> \</dict> 4 2 реализация функциональности отправки электронной почты создайте lib/services/email service dart // lib/services/email service dart import 'package\ flutter email sender/flutter email sender dart'; class emailservice { future\<void> sendemail(string subject, string body, list\<string> recipients) async { final email email = email( body body, subject subject, recipients recipients, ishtml false, ); await flutteremailsender send(email); } } 4 3 реализация получения электронной почты (заглушка) получение электронной почты от провайдеров, таких как gmail, требует oauth и интеграции api, что может быть сложно в этом учебном пособии мы будем имитировать получение электронной почты создайте lib/models/email dart // lib/models/email dart class email { final string sender; final string subject; final string body; final datetime date; email({ required this sender, required this subject, required this body, required this date, }); } создайте lib/services/email service dart (обновите с фиктивными данными) // lib/services/email service dart import ' /models/email dart'; class emailservice { future\<list\<email>> fetchemails() async { // simulate network delay await future delayed(duration(seconds 2)); return \[ email( sender 'john doe\@example com', subject 'meeting reminder', body 'don\\'t forget about our meeting tomorrow at 10 am ', date datetime now() subtract(duration(hours 1)), ), // add more dummy emails ]; } // existing sendemail method } шаг 5 — интеграция ai сервисов для генерации ответов теперь вы настроите интеграцию ai для генерации ответов на электронные письма 5 1 настройка http запросов к ai api установите http пакет (уже добавлен) создайте lib/services/ai service dart // lib/services/ai service dart import 'dart\ convert'; import 'package\ http/http dart' as http; class aiservice { final string apikey = 'your openai api key'; final string apiurl = 'https //api openai com/v1/engines/davinci/completions'; future\<string> generateresponse(string emailcontent) async { final response = await http post( uri parse(apiurl), headers { 'authorization' 'bearer $apikey', 'content type' 'application/json', }, body jsonencode({ 'prompt' 'reply to the following email \n$emailcontent', 'max tokens' 150, }), ); if (response statuscode == 200) { final data = jsondecode(response body); return data\['choices']\[0]\['text'] trim(); } else { throw exception('failed to generate response'); } } } примечание замените 'your openai api key' на ваш фактический api ключ 5 2 реализация виджета редактора ответов создайте lib/widgets/response editor dart // lib/widgets/response editor dart import 'package\ flutter/material dart'; class responseeditor extends statelesswidget { final string initialresponse; final texteditingcontroller controller; responseeditor({required this initialresponse}) controller = texteditingcontroller(text initialresponse); @override widget build(buildcontext context) { return textfield( controller controller, maxlines null, decoration inputdecoration( hinttext 'edit your response here ', border outlineinputborder(), ), ); } } 5 3 отображение ответов, сгенерированных ии в lib/screens/email detail screen dart , интегрируйте сервис ии // lib/screens/email detail screen dart import 'package\ flutter/material dart'; import ' /models/email dart'; import ' /services/ai service dart'; import ' /widgets/response editor dart'; import ' /services/email service dart'; class emaildetailscreen extends statefulwidget { final email email; emaildetailscreen({required this email}); @override emaildetailscreenstate createstate() => emaildetailscreenstate(); } class emaildetailscreenstate extends state\<emaildetailscreen> { final aiservice aiservice = aiservice(); final emailservice emailservice = emailservice(); string? airesponse; bool isloading = false; future\<void> generateresponse() async { setstate(() { isloading = true; }); try { final response = await aiservice generateresponse(widget email body); setstate(() { airesponse = response; }); } catch (e) { scaffoldmessenger of(context) showsnackbar(snackbar(content text('ai error $e'))); } finally { setstate(() { isloading = false; }); } } void sendresponse(string responsetext) { emailservice sendemail( 're ${widget email subject}', responsetext, \[widget email sender], ); scaffoldmessenger of(context) showsnackbar(snackbar(content text('email sent'))); } @override void initstate() { super initstate(); generateresponse(); } @override widget build(buildcontext context) { final responseeditor = airesponse != null ? responseeditor(initialresponse airesponse!) null; return scaffold( appbar appbar( title text('email from ${widget email sender}'), ), body padding( padding const edgeinsets all(16), child isloading ? center(child circularprogressindicator()) column( children \[ text(widget email body), sizedbox(height 20), responseeditor != null ? expanded(child responseeditor) container(), elevatedbutton( onpressed () { if (responseeditor != null) { sendresponse(responseeditor controller text); } }, child text('send response'), ), ], ), ), ); } } шаг 6 — управление шаблонами электронной почты теперь вы реализуете управление шаблонами электронной почты с использованием back4app 6 1 определите модель emailtemplate создайте lib/models/email template dart // lib/models/email template dart import 'package\ parse server sdk flutter/parse server sdk dart'; class emailtemplate extends parseobject implements parsecloneable { emailtemplate() super('emailtemplate'); emailtemplate clone() this(); @override emailtemplate clone(map\<string, dynamic> map) => emailtemplate clone() fromjson(map); string? get templatename => get\<string>('templatename'); set templatename(string? value) => set\<string>('templatename', value); string? get templatecontent => get\<string>('templatecontent'); set templatecontent(string? value) => set\<string>('templatecontent', value); string? get templatetype => get\<string>('templatetype'); set templatetype(string? value) => set\<string>('templatetype', value); } 6 2 реализуйте сервис шаблонов создать lib/services/template service dart // lib/services/template service dart import 'package\ parse server sdk flutter/parse server sdk dart'; import ' /models/email template dart'; class templateservice { future\<list\<emailtemplate>> fetchtemplates() async { final query = querybuilder\<emailtemplate>(emailtemplate()); final response = await query find(); if (response success && response results != null) { return response results as list\<emailtemplate>; } else { return \[]; } } future\<void> addtemplate(emailtemplate template) async { await template save(); } } 6 3 создать экран управления шаблонами создать lib/screens/template management screen dart // lib/screens/template management screen dart import 'package\ flutter/material dart'; import ' /models/email template dart'; import ' /services/template service dart'; class templatemanagementscreen extends statefulwidget { @override templatemanagementscreenstate createstate() => templatemanagementscreenstate(); } class templatemanagementscreenstate extends state\<templatemanagementscreen> { final templateservice templateservice = templateservice(); list\<emailtemplate> templates = \[]; bool isloading = true; future\<void> loadtemplates() async { final fetchedtemplates = await templateservice fetchtemplates(); setstate(() { templates = fetchedtemplates; isloading = false; }); } @override void initstate() { super initstate(); loadtemplates(); } @override widget build(buildcontext context) { return scaffold( appbar appbar( title text('email templates'), ), body isloading ? center(child circularprogressindicator()) listview\ builder( itemcount templates length, itembuilder (context, index) { final template = templates\[index]; return listtile( title text(template templatename ?? 'unnamed'), subtitle text(template templatetype ?? 'no type'), ); }, ), floatingactionbutton floatingactionbutton( onpressed () { // implement template creation }, child icon(icons add), )); } } шаг 7 — реализация отслеживания истории ответов теперь вы будете сохранять ответы, сгенерированные ии, и редактирования пользователей в back4app для аналитики 7 1 определить модель responsehistory создайте lib/models/response history dart // lib/models/response history dart import 'package\ parse server sdk flutter/parse server sdk dart'; class responsehistory extends parseobject implements parsecloneable { responsehistory() super('responsehistory'); responsehistory clone() this(); @override responsehistory clone(map\<string, dynamic> map) => responsehistory clone() fromjson(map); string? get originalemailsummary => get\<string>('originalemailsummary'); set originalemailsummary(string? value) => set\<string>('originalemailsummary', value); string? get generatedresponse => get\<string>('generatedresponse'); set generatedresponse(string? value) => set\<string>('generatedresponse', value); string? get usereditedresponse => get\<string>('usereditedresponse'); set usereditedresponse(string? value) => set\<string>('usereditedresponse', value); int? get timesaved => get\<int>('timesaved'); set timesaved(int? value) => set\<int>('timesaved', value); } 7 2 сохранение истории ответов после отправки электронной почты обновите lib/screens/email detail screen dart в методе sendresponse import ' /models/response history dart'; // void sendresponse(string responsetext) async { await emailservice sendemail( 're ${widget email subject}', responsetext, \[widget email sender], ); // save response history final responsehistory = responsehistory() set('originalemailsummary', widget email body) set('generatedresponse', airesponse) set('usereditedresponse', responsetext) set('timesaved', calculatetimesaved()); await responsehistory save(); scaffoldmessenger of(context) showsnackbar(snackbar(content text('email sent'))); navigator pop(context); } int calculatetimesaved() { // placeholder implementation return 5; // assume 5 minutes saved } шаг 8 — добавление аналитики с помощью графиков теперь вы реализуете базовую панель аналитики, используя fl chart 8 1 реализация сервиса аналитики создайте lib/services/analytics service dart // lib/services/analytics service dart import 'package\ parse server sdk flutter/parse server sdk dart'; import ' /models/response history dart'; class analyticsservice { future\<list\<responsehistory>> fetchresponsehistories() async { final query = querybuilder\<responsehistory>(responsehistory()); final response = await query find(); if (response success && response results != null) { return response results as list\<responsehistory>; } else { return \[]; } } future\<int> calculatetotaltimesaved() async { final histories = await fetchresponsehistories(); return histories fold(0, (sum, item) => sum + (item timesaved ?? 0)); } } 8 2 создание аналитической панели создайте lib/screens/analytics screen dart // lib/screens/analytics screen dart import 'package\ flutter/material dart'; import 'package\ fl chart/fl chart dart'; import ' /services/analytics service dart'; class analyticsscreen extends statefulwidget { @override analyticsscreenstate createstate() => analyticsscreenstate(); } class analyticsscreenstate extends state\<analyticsscreen> { final analyticsservice analyticsservice = analyticsservice(); int totaltimesaved = 0; future\<void> loadanalytics() async { final timesaved = await analyticsservice calculatetotaltimesaved(); setstate(() { totaltimesaved = timesaved; }); } @override void initstate() { super initstate(); loadanalytics(); } @override widget build(buildcontext context) { return scaffold( appbar appbar( title text('analytics'), ), body center( child text('total time saved $totaltimesaved minutes'), )); } } шаг 9 — реализация поддержки оффлайн теперь вы добавите оффлайн возможности в ваше приложение, используя локальное хранилище данных parse 9 1 включить локальное хранилище данных в lib/main dart , включите локальное хранилище данных await parse() initialize( keyapplicationid, keyparseserverurl, clientkey keyclientkey, autosendsessionid true, debug true, corestore await corestoresembastimp getinstance(), ); 9 2 измените модели данных для закрепления в ваших моделях (например, responsehistory ), добавьте методы для закрепления и открепления объектов future\<void> pin() async { await this pin(); } future\<void> unpin() async { await this unpin(); } 9 3 реализуйте менеджер оффлайн создайте lib/utils/offline manager dart // lib/utils/offline manager dart import ' /models/email dart'; import 'package\ parse server sdk flutter/parse server sdk dart'; class offlinemanager { future\<void> cacheemails(list\<email> emails) async { for (var email in emails) { final parseobject = parseobject('email') set('sender', email sender) set('subject', email subject) set('body', email body) set('date', email date); await parseobject pin(); } } future\<list\<email>> getcachedemails() async { final query = querybuilder\<parseobject>(parseobject('email')); final response = await query frompin() find(); if (response success && response results != null) { return response results! map((e) { return email( sender e get\<string>('sender') ?? '', subject e get\<string>('subject') ?? '', body e get\<string>('body') ?? '', date e get\<datetime>('date') ?? datetime now(), ); }) tolist(); } else { return \[]; } } } 9 4 используйте оффлайн данные при отсутствии подключения в вашей логике получения электронной почты проверьте подключение и используйте кэшированные данные, если нет подключения заключение в этом учебном пособии вы создали приложение ai email responder с использованием flutter и back4app вы настроили бэкенд back4app с необходимыми моделями данных и конфигурациями безопасности инициализировали проект flutter и подключили его к back4app реализовали аутентификацию пользователей с помощью parse server интегрировали отправку электронной почты и смоделировали получение электронной почты интегрировали ai сервисы для генерации ответов на электронные письма управляли шаблонами электронной почты и хранили их в back4app отслеживали историю ответов для аналитики добавили базовую аналитику с использованием fl chart реализовали поддержку оффлайн режима с использованием локального хранилища данных parse это приложение предоставляет основу для создания более продвинутых функций, таких как реальная интеграция электронной почты с oauth, расширенные возможности ии и улучшенный дизайн ui/ux следующие шаги интеграция электронной почты реализовать реальную выборку электронной почты с использованием api gmail или outlook с аутентификацией oauth расширенные функции ии настроить подсказки ии для получения лучших ответов и реализовать персонализацию на основе данных пользователя улучшения ui/ux улучшить интерфейс приложения для лучшего пользовательского опыта тестирование и развертывание написать модульные и интеграционные тесты и подготовить приложение к развертыванию в магазинах приложений улучшения безопасности шифровать конфиденциальные данные и реализовать надежную обработку ошибок и валидацию ввода для получения дополнительной информации о использовании back4app с flutter, обратитесь к руководству back4app по flutter https //www back4app com/docs/flutter/parse sdk/