Skip to content
This repository has been archived by the owner on May 22, 2024. It is now read-only.

Commit

Permalink
✨ Implemented chat history #3
Browse files Browse the repository at this point in the history
  • Loading branch information
iqfareez committed Aug 12, 2023
1 parent bc62c2e commit 3df8ed8
Show file tree
Hide file tree
Showing 14 changed files with 700 additions and 105 deletions.
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
# FlutterChatGPT
![Flutter](https://img.shields.io/badge/Flutter%203-%2302569B.svg?style=for-the-badge&logo=Flutter&logoColor=white)

# Flutter ChatGPT

ChatGPT app built with Flutter

![Flutter ChatGPT](https://imgur.com/YGUBL4x.png)

## Features

- Chat streaming
- Chats are preserved in local storage, you can get back to the conversation at any time
- Upcoming: Dark mode
- Upcoming: Better UI

## Try it out

App is available for Android, Web and Windows. See [releases](https://github.com/iqfareez/flutter_chatgpt/releases) for info

## Getting Started

This project is a starting point for a Flutter application.
Expand Down
14 changes: 14 additions & 0 deletions lib/hive_model/chat_item.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import 'package:hive/hive.dart';

part 'chat_item.g.dart';

@HiveType(typeId: 0)
class ChatItem extends HiveObject {
@HiveField(0)
String title;

@HiveField(1)
HiveList messages;

ChatItem(this.title, this.messages);
}
44 changes: 44 additions & 0 deletions lib/hive_model/chat_item.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions lib/hive_model/message_item.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import 'package:hive_flutter/hive_flutter.dart';

import 'message_role.dart';

part 'message_item.g.dart';

@HiveType(typeId: 1)
class MessageItem extends HiveObject {
@HiveField(0)
final String message;
@HiveField(1)
final MessageRole role;
@HiveField(2)
final DateTime createdAt;

MessageItem(this.message, this.role, this.createdAt);

@override
String toString() =>
'MessageItem(message: $message, role: $role, createdAt: $createdAt)';
}
47 changes: 47 additions & 0 deletions lib/hive_model/message_item.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions lib/hive_model/message_role.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import 'package:hive_flutter/hive_flutter.dart';

part 'message_role.g.dart';

@HiveType(typeId: 2)
enum MessageRole {
@HiveField(0)
ai,
@HiveField(1)
user
}
46 changes: 46 additions & 0 deletions lib/hive_model/message_role.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 12 additions & 1 deletion lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
import 'package:flutter/material.dart';
import 'package:hive_flutter/hive_flutter.dart';

import 'hive_model/chat_item.dart';
import 'hive_model/message_item.dart';
import 'hive_model/message_role.dart';
import 'screens/home.dart';

void main() async {
await Hive.initFlutter();
Hive.registerAdapter(ChatItemAdapter());
Hive.registerAdapter(MessageItemAdapter());
Hive.registerAdapter(MessageRoleAdapter());
await Hive.openBox('chats');
await Hive.openBox('messages');

runApp(const MyApp());
}

Expand All @@ -12,7 +23,7 @@ class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'ChatGPT Flutter',
title: 'ChatGPT',
theme: ThemeData(primarySwatch: Colors.purple, useMaterial3: true),
darkTheme: ThemeData.dark(useMaterial3: true),
themeMode: ThemeMode.system,
Expand Down
62 changes: 43 additions & 19 deletions lib/screens/chat_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@ import 'package:dart_openai/openai.dart';
import 'package:flutter/material.dart';
import 'package:flutter_chat_ui/flutter_chat_ui.dart';
import 'package:flutter_chat_types/flutter_chat_types.dart' as types;
import 'package:hive/hive.dart';

import '../hive_model/chat_item.dart';
import '../hive_model/message_item.dart';
import '../hive_model/message_role.dart';

class ChatPage extends StatefulWidget {
const ChatPage({super.key, this.name});
const ChatPage({super.key, required this.chatItem});

final String? name;
final ChatItem chatItem;

@override
State<ChatPage> createState() => _ChatPageState();
Expand All @@ -20,6 +25,7 @@ class _ChatPageState extends State<ChatPage> {
final List<OpenAIChatCompletionChoiceMessageModel> _aiMessages = [];
late types.User ai;
late types.User user;
late Box messageBox;

late String appBarTitle;

Expand All @@ -34,7 +40,31 @@ class _ChatPageState extends State<ChatPage> {
ai = const types.User(id: 'ai', firstName: 'AI');
user = const types.User(id: 'user', firstName: 'You');

appBarTitle = widget.name ?? 'New Chat';
messageBox = Hive.box('messages');

appBarTitle = widget.chatItem.title;

// read chat history from Hive
for (var messageItem in widget.chatItem.messages) {
messageItem as MessageItem;
// Add to chat view
final textMessage = types.TextMessage(
author: messageItem.role == MessageRole.ai ? ai : user,
createdAt: messageItem.createdAt.millisecondsSinceEpoch,
id: randomString(),
text: messageItem.message,
);

_messages.insert(0, textMessage);

// construct chatgpt messages
_aiMessages.add(OpenAIChatCompletionChoiceMessageModel(
content: messageItem.message,
role: messageItem.role == MessageRole.ai
? OpenAIChatMessageRole.assistant
: OpenAIChatMessageRole.user,
));
}
}

String randomString() {
Expand All @@ -44,22 +74,6 @@ class _ChatPageState extends State<ChatPage> {
}

void _completeChat(String prompt) async {
// OpenAIChatCompletionModel chatCompletion =
// await OpenAI.instance.chat.create(
// model: "gpt-3.5-turbo",
// messages: [
// OpenAIChatCompletionChoiceMessageModel(
// content: prompt,
// role: OpenAIChatMessageRole.user,
// ),
// ],
// );

// debugPrint(chatCompletion.choices.toString());
// debugPrint(chatCompletion.toString());

// onMessageReceived(chatCompletion.choices.first.message.content);

_aiMessages.add(OpenAIChatCompletionChoiceMessageModel(
content: prompt,
role: OpenAIChatMessageRole.user,
Expand All @@ -86,6 +100,7 @@ class _ChatPageState extends State<ChatPage> {
content: chatResponseContent,
role: OpenAIChatMessageRole.assistant,
));
_saveMessage(chatResponseContent, MessageRole.ai);
chatResponseId = '';
chatResponseContent = '';
}
Expand Down Expand Up @@ -116,6 +131,14 @@ class _ChatPageState extends State<ChatPage> {
});
}

/// Save message to Hive database
void _saveMessage(String message, MessageRole role) {
final messageItem = MessageItem(message, role, DateTime.now());
messageBox.add(messageItem);
widget.chatItem.messages.add(messageItem);
widget.chatItem.save();
}

// modify last bubble in chat
void _addMessageStream(String message) {
setState(() {
Expand All @@ -133,6 +156,7 @@ class _ChatPageState extends State<ChatPage> {
);

_addMessage(textMessage);
_saveMessage(message.text, MessageRole.user);
_completeChat(message.text);
}

Expand Down
Loading

0 comments on commit 3df8ed8

Please sign in to comment.