Flutter Templates
Flutter와 Back4App을 사용하여 AI 이메일 응답기 앱을 만드는 방법
41 분
소개 이 튜토리얼에서는 flutter 를 프론트엔드로 사용하고 back4app 를 백엔드로 사용하는 ai 기반 이메일 응답기 앱을 구축할 것입니다 이 앱은 gmail 또는 outlook과 같은 이메일 서비스와 통합되어 ai 모델(예 openai의 gpt 3)을 사용하여 수신 이메일을 분석하고 개인화된 응답을 생성합니다 이 튜토리얼이 끝나면 이메일을 관리하고 자동 응답을 생성하며 사용자가 이메일 상호작용을 개인화할 수 있는 기능적인 앱을 갖추게 될 것입니다 이 앱은 back4app의 parse server의 힘을 활용하여 사용자 인증, 데이터 저장 및 클라우드 기능을 처리하여 서버 인프라를 관리할 필요 없이 확장 가능한 백엔드 솔루션을 제공합니다 ai 기능과 이메일 서비스를 통합하면 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 및 비동기 프로그래밍 에 대한 친숙함 ai 서비스 제공업체 (예 openai)와의 계정 ai 모델에 접근하기 위해 api 키에 가입하세요 이메일 계정 (gmail 또는 outlook)으로 통합 테스트 1단계 — back4app 백엔드 설정 이 단계에서는 새로운 back4app 애플리케이션을 만들고, 데이터 클래스를 설정하고, flutter 앱과 함께 작동하도록 백엔드를 구성합니다 1 1 back4app에서 새 애플리케이션 만들기 귀하의 back4app 대시보드 https //dashboard back4app com/ 에 로그인하십시오 "새 앱 만들기"를 클릭하십시오 앱 이름을 입력하십시오 (예 "ai 이메일 응답기") 및 앱 아이콘 을 선택하십시오 프롬프트가 표시되면 서버 위치를 선택하십시오 "생성"을 클릭하십시오 1 2 애플리케이션 키 가져오기 앱의 대시보드에서 앱 설정 > 보안 및 키 로 이동하십시오 애플리케이션 id 와 클라이언트 키 를 적어 두십시오 flutter 앱 구성에 필요합니다 1 3 데이터 모델 클래스 정의하기 우리는 back4app에서 다음 클래스를 생성할 것입니다 사용자 (기본) 이메일 계정 이메일 템플릿 응답 기록 1 3 1 emailaccount 클래스 생성하기 이동하기 데이터베이스 > 브라우저 클릭하기 "클래스 생성" "사용자 정의"를 선택하고 이름을 emailaccount 로 지정하세요 클릭하기 "클래스 생성" 다음 열을 추가하십시오 emailaccount 사용자 (pointer< user>) user 객체를 가리킵니다 emailaddress (string) accounttype (string) 예 gmail, outlook authtoken (string) 암호화된 토큰을 저장합니다 1 3 2 emailtemplate 클래스 생성하기 새로운 클래스 이름을 생성하는 단계를 반복하십시오 emailtemplate 다음 열을 추가하십시오 emailtemplate 사용자 (pointer< user>) templatename (string) templatecontent (string) templatetype (string) 예 공식, 캐주얼, 후속 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 ai api에 대한 http 요청 설정하기 “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 ai 생성 응답 표시하기 다음에서 lib/screens/email detail screen dart ai 서비스를 통합합니다 // 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 이메일 템플릿 모델 정의하기 생성하기 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 — 응답 이력 추적 구현 이제 ai가 생성한 응답과 사용자 편집을 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 연결이 없을 때 오프라인 데이터 사용 이메일 가져오기 로직에서 연결 상태를 확인하고 오프라인일 경우 캐시된 데이터를 사용하세요 결론 이 튜토리얼에서는 flutter와 back4app을 사용하여 ai 이메일 응답기 앱을 만들었습니다 당신은 필요한 데이터 모델과 보안 구성을 갖춘 back4app 백엔드를 설정했습니다 flutter 프로젝트를 초기화하고 back4app에 연결했습니다 parse server로 사용자 인증을 구현했습니다 이메일 전송을 통합하고 이메일 가져오기를 시뮬레이션했습니다 ai 서비스를 통합하여 이메일 응답을 생성했습니다 이메일 템플릿을 관리하고 back4app에 저장했습니다 분석을 위한 응답 기록을 추적했습니다 기본 분석을 추가했습니다 fl chart 를 사용하여 parse의 로컬 데이터 저장소를 사용하여 오프라인 지원을 구현했습니다 이 앱은 oauth를 통한 실제 이메일 통합, 고급 ai 기능 및 개선된 ui/ux 디자인과 같은 더 발전된 기능을 구축하기 위한 기반을 제공합니다 다음 단계 이메일 통합 oauth 인증을 사용하여 gmail 또는 outlook api를 통해 실제 이메일 가져오기를 구현합니다 향상된 ai 기능 더 나은 응답을 위해 ai 프롬프트를 미세 조정하고 사용자 데이터를 기반으로 개인화를 구현합니다 ui/ux 개선 더 나은 사용자 경험을 위해 앱의 인터페이스를 향상시킵니다 테스트 및 배포 단위 및 통합 테스트를 작성하고 앱을 앱 스토어에 배포할 준비를 합니다 보안 강화 민감한 데이터를 암호화하고 강력한 오류 처리 및 입력 유효성 검사를 구현합니다 flutter와 함께 back4app을 사용하는 방법에 대한 자세한 내용은 back4app flutter 가이드 https //www back4app com/docs/flutter/parse sdk/ 를 참조하십시오