• Ở trình duyệt Chrome ấn F12 hoặc bấm vào dấu ba chấm ở góc trên, bên phải cửa sổ trình duyệt, chọn More Tools → Developer Tools. Chọn thẻ Application và xóa theo các bước trong ảnh. Sau đó ấn F5 để tải lại trang.

  • Lúc này OpenAI sẽ cho phép bạn đăng ký. Điền các thông tin theo yêu cầu. Đến bước xác thực qua số điện thoại thì vào trang https://sms-activate.org hoặc http://smspool.net thuê một số điện thoại để nhận tin nhắn.

  • Sau khi thuê được số điện thoại thì điền vào và đợi mã xác thực gửi về smspool. Điền mã xác thực và tiến hành trải nghiệm ChatGPT.

  • Khi tạo tài khoản và lấy API bạn sẽ có 18$ trong tài khoản OpenAI để sử dụng dịch vụ.
  • Đối với dịch vụ Language models (vì chúng ta dùng nó để trả lời tự động) của OpenAI thì có đơn giá là $0.02/1Ktokens. (Chi tiết https://openai.com/api/pricing/)
  • Hãy chắc chắn rằng bạn không chia sẻ API key của mình với bất kỳ ai khác. (Chi tiết hãy xem tại https://beta.openai.com/docs/usage-policies)
  • Hãy chắc chắn rằng bạn luôn luôn sử dụng API key của mình một cách an toàn và không làm spam hay sử dụng với mục đích xấu hoặc làm ảnh hưởng đến hệ thống của OpenAI. (Chi tiết hãy xem tại https://beta.openai.com/docs/usage-policies)
import 'package:flutter/material.dart';
import 'package:flutter_application_1/model.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: ChatPage(),
      debugShowCheckedModeBanner: false,
    );
  }
}


class ChatPage extends StatefulWidget {
  const ChatPage({super.key});

  @override
  State<ChatPage> createState() => _ChatPageState();
}

class _ChatPageState extends State<ChatPage> {
  @override
  Widget build(BuildContext context) {
    return Container();
  }
}
class _ChatPageState extends State<ChatPage> {
  final _textController = TextEditingController();
  final _scrollController = ScrollController();
  final List<ChatMessage> _messages = [];
  late bool isLoading;

  @override
  void initState() {
    super.initState();
    isLoading = false;
  }
 @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        toolbarHeight: 100,
        title: const Padding(
          padding: EdgeInsets.all(8.0),
          child: Text(
            "OpenAI's ChatGPT Flutter",
            maxLines: 2,
            textAlign: TextAlign.center,
          ),
        ),
        backgroundColor: const Color(0xff10a37f),
      ),
      backgroundColor: Colors.white,
      body: _buildBody(context),
    );
  }

  Widget _buildBody(BuildContext context) {
    return SafeArea(
      child: Column(
        children: [
          Expanded(
            child: _buildList(),
          ),
          Visibility(
            visible: isLoading,
            child: const Padding(
              padding: EdgeInsets.all(8.0),
              child: CircularProgressIndicator(
                color: Color(0xff10a37f),
              ),
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: Row(
              children: [
                _buildInput(),
                const SizedBox(width: 5),
                _buildSubmit(),
              ],
            ),
          ),
        ],
      ),
    );
  }
 Widget _buildList() {
    if (_messages.isEmpty) {
      return Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          CircleAvatar(
            backgroundColor: const Color(0xff10a37f),
            radius: 50,
            child: Image.asset(
              'assets/bot.png',
              color: Colors.white,
              scale: 0.6,
            ),
          ),
          const SizedBox(
            height: 10,
          ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 50),
            child: Text(
              'Hi, I\'m Duy\nTell me your dreams and i\'ll make them happen',
              style: Theme.of(context).textTheme.titleLarge?.copyWith(
                    color: Colors.black,
                  ),
              textAlign: TextAlign.center,
            ),
          ),
        ],
      );
    }

    return ListView.builder(
      physics: const BouncingScrollPhysics(),
      controller: _scrollController,
      itemCount: _messages.length,
      itemBuilder: (context, index) {
        var message = _messages[index];
        return ChatMessageWidget(
          text: message.text,
          chatMessageType: message.chatMessageType,
        );
      },
    );
  }
class ChatMessageWidget extends StatelessWidget {
  const ChatMessageWidget(
      {super.key, required this.text, required this.chatMessageType});

  final String text;
  final ChatMessageType chatMessageType;

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.symmetric(vertical: 10.0),
      padding: const EdgeInsets.all(16),
      color: chatMessageType == ChatMessageType.bot
          ? const Color(0xff10a37f)
          : Colors.white,
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          chatMessageType == ChatMessageType.bot
              ? Container(
                  margin: const EdgeInsets.only(right: 16.0),
                  child: CircleAvatar(
                    backgroundColor: const Color(0xff10a37f),
                    child: Image.asset(
                      'assets/bot.png',
                      color: Colors.white,
                      scale: 1.5,
                    ),
                  ),
                )
              : Container(
                  margin: const EdgeInsets.only(right: 16.0),
                  child: const CircleAvatar(
                    child: Icon(
                      Icons.person,
                    ),
                  ),
                ),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Container(
                  padding: const EdgeInsets.all(8.0),
                  decoration: const BoxDecoration(
                    borderRadius: BorderRadius.all(Radius.circular(8.0)),
                  ),
                  child: Text(
                    text,
                    style: Theme.of(context).textTheme.bodyLarge?.copyWith(
                          color: chatMessageType == ChatMessageType.bot
                              ? Colors.white
                              : Colors.black,
                        ),
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}
 
  Expanded _buildInput() {
    return Expanded(
      child: TextField(
        textCapitalization: TextCapitalization.sentences,
        minLines: 1,
        maxLines: 9,
        controller: _textController,
        decoration: InputDecoration(
          filled: true,
          fillColor: Colors.grey[300],
          focusedBorder: InputBorder.none,
          enabledBorder: InputBorder.none,
          errorBorder: InputBorder.none,
          disabledBorder: InputBorder.none,
        ),
      ),
    );
  }
Widget _buildSubmit() {
    return Visibility(
      visible: !isLoading,
      child: Container(
        decoration: BoxDecoration(
          color: const Color(0xff10a37f),
          borderRadius: BorderRadius.circular(
            6,
          ),
        ),
        child: IconButton(
          icon: const Icon(
            Icons.send_rounded,
            color: Colors.white,
          ),
          onPressed: () async {
            setState(
              () {
                _messages.add(
                  ChatMessage(
                    text: _textController.text,
                    chatMessageType: ChatMessageType.user,
                  ),
                );
                isLoading = true;
              },
            );
            _textController.clear();
            Future.delayed(const Duration(milliseconds: 50))
                .then((_) => _scrollDown());
            setState(() {
              isLoading = false;
              _messages.add(
                ChatMessage(
                  text: "hello",
                  chatMessageType: ChatMessageType.bot,
                ),
              );
            });
          },
        ),
      ),
    );
  }

  void _scrollDown() {
    _scrollController.animateTo(
      _scrollController.position.maxScrollExtent,
      duration: const Duration(milliseconds: 300),
      curve: Curves.easeOut,
    );
  }
 
 
  • Thêm tin nhắn mình vừa gửi vào ListView
  • Clear text trong TextField
  • Scroll đến cuối trang tức là vị trí của tin nhắn mới nhất.
  • Fake data cho con bot để nó trả lời lại với nội dung là “hello”. Đoạn này vì chưa có dữ liệu từ ChatGPT nên mình cần phải fake data như vậy để hoàn thành UI.
  • Mình sẽ tiến hành tích hợp API OpenAI vào ứng dụng Flutter
  • Tích hợp xử lý voice để nó trở thành một Smart Voice Assistant