[Flutter] AI 챗봇 실습

2025. 5. 14. 00:20·Flutter/Flutter Study

오랜만에 포스팅이긴한데 공부하느라 바빴음..ㅎ

AI챗봇 실습을 하면서 사용한 주요 기능을 정리해보려고함


1. 📦 실시간 메시지 갱신 (Isar + StreamBuilder)

StreamBuilder<List<MessageModel>>(
  stream: GetIt.I<Isar>().messageModels.where().watch(fireImmediately: true),
  builder: (context, snapshot) {
    final messages = snapshot.data ?? [];

    // 위젯 트리 빌드 완료 후 맨 아래로 자동 스크롤
    WidgetsBinding.instance.addPostFrameCallback((_) async => scrollToBottom());

    return buildMessageList(messages); // 메시지 리스트 렌더링
  },
)
  • Isar DB에서 실시간으로 데이터를 감지 (`watch`)
  • 새로운 메시지가 저장되면 자동으로 UI가 업데이트되며 아래로 스크롤됨
  • 빌드 완료 후 최신 메시지로 자동 스크롤

2. 🤖 Gemini API 연동 및 스트리밍 응답 처리

final model = GenerativeModel(
  model: "gemini-1.5-flash",
  apiKey: "YOUR_API_KEY", // Gemini API Key 입력
  systemInstruction: Content.system(
    "너는 GPT-4급 지능을 가진 스마트한 AI야. 사용자의 질문에 성의 있고 창의적으로 답변해.",
  ),
);
model.generateContentStream(promptContext).listen(
  (event) async {
    // 응답 텍스트가 있으면 누적
    if (event.text != null) {
      message += event.text!;
    }

    // 현재까지 받은 텍스트를 메시지 객체로 만듦
    final MessageModel model = MessageModel(
      isMine: false,
      message: message,
      date: DateTime.now(),
    );

    // 기존 메시지 덮어쓰기용 ID 설정
    if (currentModelMessageId != null) {
      model.id = currentModelMessageId!;
    }

    // DB에 저장
    currentModelMessageId =
        await isar.writeTxn<int>(() => isar.messageModels.put(model));
  },

  onDone: () => setState(() => isRunning = false), // 응답 완료 → 로딩 종료

  onError: (e) async {
    // 에러 발생 시 유저 메시지 삭제
    await isar.writeTxn(() async {
      return isar.messageModels.delete(currentUserMessageId!);
    });

    // 에러 상태 설정
    setState(() {
      error = e.toString();
      isRunning = false;
    });
  },
);
  • 제미나이 API를 가져옴
  • 제미나이한테 `"너는 GPT-4급 지능을 가진 스마트한 AI야. 사용자의 질문에 성의 있고 창의적으로 답변해.`라고 정해둠
    -> 실제로 답변의 차이가 있었음

3. 🧠 대화 맥락 구성 (최근 메시지 → 프롬프트화)

final contextMessages = await isar.messageModels.where().limit(20).findAll();

final List<Content> promptContext = contextMessages.map((e) => Content(
  e.isMine ? "user" : "model", // 역할 분리
  [TextPart(e.message)],       // 메시지를 TextPart로 구성
)).toList();
  • 최근 메세지를 기반으로 프롬프트를 구성
  • 제미나이가 대화 흐름을 이해하고 자연스럽게 이어가도록 함

4. 📝 메시지 저장 (사용자 입력, Gemini 응답)

// 사용자 메시지 저장
currentUserMessageId = await isar.writeTxn(() async {
  return await isar.messageModels.put(
    MessageModel(
      isMine: true,
      message: currentPrompt,
      point: myMesageCount + 1, // 포인트 시스템 등에서 활용 가능
      date: DateTime.now(),
    ),
  );
});

 

  • 사용자의 입력 메시지를 Isar에 저장
  • Gemini 응답도 동일한 방식으로 저장됨

5. 🧩 입력창 컴포넌트화 (ChatTextField)

ChatTextField(
  error: error,                 // 입력 유효성 오류 메시지
  loading: isRunning,          // 로딩 상태 표시
  onSend: handleSendMessage,   // 전송 시 호출 함수
  controller: controller,      // 텍스트 입력 컨트롤러
),

 

 

  • 단순한 `TextField`가 아닌 커스텀 위젯으로 구성
  • 상태에 따라 로딩 중, 에러 메시지 등도 같이 보여줌

7. 📅 날짜 구분선 (DateDivider) 자동 표시

final shouldDrawDateDivider =
    prevMessage == null || getStringDate(prevMessage.date) != getStringDate(message.date);

if (shouldDrawDateDivider)
  Padding(
    padding: const EdgeInsets.symmetric(vertical: 16.0),
    child: DateDivider(date: message.date),
  );

 

 

  • 이전 메시지와 날짜가 다르면 날짜 구분선 삽입
  • 날짜 단위로 대화 흐름을 시각적으로 구분

✅ 전체 기술 스택 요약

기능 기술/패키지 설명
로컬 DB `isar`, `get_it` 메시지 저장 및 실시간 스트림 처리
AI 응답 `google_generative_ai` Gemini API로 대화형 응답 구현
UI `StreamBuilder`, `ListView`, `Custom Widget` 실시간 채팅 UI
상태 관리 `StatefulWidget`, `setState` 로딩/에러 상태 처리
UX 개선 자동 스크롤, 날짜 구분선 대화 흐름을 직관적으로 표현

 

https://github.com/Leedoseo/Flutter_WidgetStudy/tree/main/ai_talk

 

Flutter_WidgetStudy/ai_talk at main · Leedoseo/Flutter_WidgetStudy

Contribute to Leedoseo/Flutter_WidgetStudy development by creating an account on GitHub.

github.com

 

 

'Flutter > Flutter Study' 카테고리의 다른 글

[Flutter] Drawer사용법  (1) 2025.06.24
[Flutter] Rest API  (0) 2025.05.14
[Flutter] 위젯 생명주기  (0) 2025.04.22
[Flutter] 웹뷰 사용해서 앱에서 웹연결 실습 간단 정리  (0) 2025.04.17
[Flutter] Basic Widget 기본 개념 (실습)  (0) 2025.04.15
'Flutter/Flutter Study' 카테고리의 다른 글
  • [Flutter] Drawer사용법
  • [Flutter] Rest API
  • [Flutter] 위젯 생명주기
  • [Flutter] 웹뷰 사용해서 앱에서 웹연결 실습 간단 정리
이도서
이도서
  • 이도서
    도서의 코딩노트
    이도서
  • 전체
    오늘
    어제
    • 분류 전체보기 (249)
      • Today I Learned (79)
        • 2024 (78)
      • Swift (25)
        • Swift 문법 정리 (19)
        • RxSwift (5)
      • Swift Study (12)
        • Playground (2)
        • Storyboard (9)
        • UIKit (1)
      • Flutter (27)
        • Dart 언어 (16)
        • Flutter Study (11)
      • React (37)
        • HTML & CSS (8)
        • JavaScript 기본 (12)
        • JavaScript 심화 (14)
        • Node.js (2)
        • React (1)
      • Git (3)
      • 코딩테스트 (60)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

    • 개발 공부 공유 링크
  • 인기 글

  • 태그

    CLASS
    DART
    ios
    ios앱개발자
    function
    객체지향
    html
    iOS앱개발
    javascript
    함수
    코딩테스트Level.1
    React
    javascript 기본
    코딩테스트
    Flutter
    Swift
    코딩테스트 level.1
    내일배움캠프
    storyboard
    Til
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
이도서
[Flutter] AI 챗봇 실습
상단으로

티스토리툴바