1. Anuncie Aqui ! Entre em contato fdantas@4each.com.br

[Flutter] the chatbot is not working on my flutter app

Discussão em 'Mobile' iniciado por Stack, Outubro 3, 2024 às 18:33.

  1. Stack

    Stack Membro Participativo

    I made a flutter app and the problem is the model for the chatbot is not working it says in the chat bubbled 'Model Not Initialized' I don't know what's wrong or what's missing I've downloaded a distilgpt2 from python and convert it to tflite and downloded the tokenizer files to use them on my flutter app on android studio so I added them in the assets in pubspec.yaml and I installed tflite_flutter package and as the package instructions was to install melos as I've installed it and made melos.yaml but I don't have packages or apps used it just the main app I'm working on so I just put name and packages was ' . ' (root)

    packages:
    - .


    and I ran this command melos run ffigen but it gave me NoScriptException: This workspace has no scripts defined in its 'melos.yaml' file.

    and this the files in pubsbe.yaml

    assets/distilgpt2/distilgpt2_model.tflite
    - assets/tokenizer/merges.txt
    - assets/tokenizer/special_tokens_map.json
    - assets/tokenizer/tokenizer.json
    - assets/tokenizer/tokenizer_config.json
    - assets/tokenizer/vocab.json


    and this the dart code in android studio also here I made the functions for loading the model and used the tokenizer files but I'm not sure that the functions are complete or written correctly that if this all the functionalities needed to make the model works properly and if it mades correctly or there are mistakes or missing functionalities I need help to know why the model is not working and with implementation to ensure that the code is complete and or should I modify it what are the modifications needed?

    class _ChatProAiScreenState extends State<ChatProAiScreen> {
    final List<Map<String, dynamic>> _messages = [];
    late TextEditingController _inputController;
    String _fromLanguage = SharedPrefController.instance.getFromLanguage();
    final FlutterTts _flutterTts = FlutterTts();
    bool _isListening = false;
    SpeechToText _speechToText = SpeechToText();
    bool _isSpeechAvailable = false;
    double progressValue = 0.0; // Value for progress (elapsed time)
    int totalDuration = 59; // Duration of speech in seconds
    Timer? _timer; // Timer for progress bar
    bool _isRecording = false;
    Interpreter? _interpreter; // TensorFlow Lite interpreter
    IsolateInterpreter? _isolateInterpreter; // IsolateInterpreter for async inference
    Map<String, dynamic>? _vocab;
    List<dynamic>? _merges;
    Map<String, int>? _specialTokens;
    Map<String, dynamic>? _tokenizerConfig; // Config from tokenizer_config.json
    late Map<String, int> _tokenToId;
    late Map<int, String> _idToToken;
    bool _isCaseInsensitive = false;
    bool _paddingEnabled = false;
    int _maxLength = 64;
    bool _truncationEnabled = false;
    bool _useAttentionMasks = false;
    String? _specialPrefixToken;
    String? _specialSuffixToken;
    bool _addPrefixSpace = false;
    double _bpeDropout = 0.0;
    bool byteLevel = false;
    int? _padToMultipleOf;
    int _modelMaxLength = 64;
    bool _returnTokenTypeIds = false;


    @override
    void initState() {
    // TODO: implement initState
    super.initState();
    _inputController = TextEditingController();
    _initializeSpeech();
    _initializeModel();
    _loadModelAndTokenizer();
    }

    @override
    void dispose() {
    // TODO: implement dispose
    _inputController.dispose();
    _speechToText.stop();
    _interpreter?.close();
    super.dispose();
    }

    // Initialize TensorFlow Lite Model
    Future<void> _initializeModel() async {
    try {
    _interpreter = await Interpreter.fromAsset(
    'assets/distilgpt2/distilgpt2_model.tflite'); // Load TFLite model
    if (_interpreter != null) {
    _isolateInterpreter = await IsolateInterpreter.create(address: _interpreter!.address); // Wrap interpreter
    print('Model initialized successfully');
    } else {
    throw Exception('Interpreter could not be initialized');
    }
    } catch (e) {
    print('Error loading model: $e');
    }
    }

    // Load tokenizer data (vocab, merges, and special tokens)
    Future<void> _loadModelAndTokenizer() async {
    try {
    // Load vocab.json
    String vocabJson = await rootBundle.loadString('assets/tokenizer/vocab.json');
    _vocab = jsonDecode(vocabJson);

    // Load merges.txt
    String mergesTxt = await rootBundle.loadString('assets/tokenizer/merges.txt');
    _merges = mergesTxt.split('\n');

    // Load special_tokens_map.json
    String specialTokensMapJson = await rootBundle.loadString('assets/tokenizer/special_tokens_map.json');
    _specialTokens = jsonDecode(specialTokensMapJson);

    // Load tokenizer.json for additional token mappings
    String tokenizerJson = await rootBundle.loadString('assets/tokenizer/tokenizer.json');
    Map<String, dynamic> tokenizerData = jsonDecode(tokenizerJson);
    _addAdditionalTokenMappings(tokenizerData);

    // Load tokenizer_config.json to apply specific settings
    String tokenizerConfigJson = await rootBundle.loadString('assets/tokenizer/tokenizer_config.json');
    _tokenizerConfig = jsonDecode(tokenizerConfigJson);
    _applyConfigSettings();

    // Map vocab to token IDs
    _tokenToId = _vocab!.map((key, value) => MapEntry(key, value as int));
    _idToToken = _tokenToId.map((key, value) => MapEntry(value, key));

    // Incorporate special tokens into vocab if needed
    if (_specialTokens != null) {
    _specialTokens!.forEach((key, value) {
    if (!_tokenToId.containsKey(key)) {
    _tokenToId[key] = value as int;
    _idToToken[value as int] = key;
    }
    });
    }

    print('Tokenizer loaded successfully');
    } catch (e) {
    print('Error loading tokenizer: $e');
    }
    }

    // Function to apply BPE rules for subword tokenization
    List<String> applyBPE(String word) {
    if (_merges == null || _merges!.isEmpty) return [word];

    // Tokenize the word into characters (initial BPE step)
    List<String> tokens = word.split('');

    while (true) {
    String bestPair;
    int bestPairIndex = -1;

    // Look for the best pair to merge based on the _merges rules
    for (var i = 0; i < tokens.length - 1; i++) {
    String pair = tokens + ' ' + tokens[i + 1];
    // if (_merges!.contains([tokens, tokens[i + 1]]) && (bestPairIndex == -1 || _merges!.indexOf([tokens, tokens[i + 1]]) < bestPairIndex)) {
    if (_merges!.contains(pair) && (bestPairIndex == -1 || _merges!.indexOf(pair) < bestPairIndex)) {
    bestPair = pair;
    bestPairIndex = i;
    }
    }

    if (bestPairIndex == -1) {
    // No more merges can be applied, break out of the loop
    break;
    }

    // Merge the best pair
    tokens[bestPairIndex] = tokens[bestPairIndex] + tokens[bestPairIndex + 1];
    tokens.removeAt(bestPairIndex + 1);
    }
    return tokens;
    }

    // Function to add additional token mappings from tokenizer.json
    void _addAdditionalTokenMappings(Map<String, dynamic> tokenizerData) {
    if (tokenizerData.containsKey('model')) {
    var tokenMap = tokenizerData['model']['vocab'] as Map<String, dynamic>;
    tokenMap.forEach((token, id) {
    if (!_tokenToId.containsKey(token)) {
    _tokenToId[token] = id as int;
    _idToToken[id as int] = token;
    }
    });
    }
    }

    // Function to apply configurations from tokenizer_config.json
    void _applyConfigSettings() {
    if (_tokenizerConfig == null) return;

    // 1. Apply case-insensitivity if configured
    if (_tokenizerConfig!.containsKey('do_lower_case') && _tokenizerConfig!['do_lower_case']) {
    _isCaseInsensitive = true;
    } else {
    _isCaseInsensitive = false;
    }
    // 2. Handle padding if padding is specified in the config
    if (_tokenizerConfig!.containsKey('padding') && _tokenizerConfig!['padding'] == 'max_length') {
    _paddingEnabled = true; // Add class member to control padding
    if (_tokenizerConfig!.containsKey('max_length')) {
    _maxLength = _tokenizerConfig!['max_length']; // Set the max length for padding
    print('Padding enabled with max length: $_maxLength');
    } else {
    _maxLength = 64; // Set default max length if not provided
    print('Padding enabled with default max length: $_maxLength');
    }
    } else {
    _paddingEnabled = false;
    }

    // 2.1 Handle padding to multiple of a specific value
    if (_tokenizerConfig!.containsKey('pad_to_multiple_of')) {
    var padValue = _tokenizerConfig!['pad_to_multiple_of'];
    if (padValue is int && padValue > 0) {
    _padToMultipleOf = padValue;
    print('Padding to multiple of: $_padToMultipleOf');
    } else {
    print('Invalid pad_to_multiple_of, skipping.');
    }
    }

    // 3. Handle truncation if configured
    if (_tokenizerConfig!.containsKey('truncation') && _tokenizerConfig!['truncation']) {
    _truncationEnabled = true; // Track truncation setting
    print('Truncation is enabled.');
    } else {
    _truncationEnabled = false;
    }

    // 3.1 Handle maximum model length if provided (model_max_length)
    if (_tokenizerConfig!.containsKey('model_max_length')) {
    _modelMaxLength = _tokenizerConfig!['model_max_length'];
    print('Model max length: $_modelMaxLength');
    }

    // 4. Handle special tokens if defined in the config
    if (_tokenizerConfig!.containsKey('special_tokens')) {
    var specialTokens = _tokenizerConfig!['special_tokens'] as Map<String, dynamic>;
    _applySpecialTokens(specialTokens);
    print('Special tokens applied: $specialTokens');
    }

    // 5. Apply prefix and suffix tokens if configured correctly
    if (_tokenizerConfig!.containsKey('prefix_token')) {
    _specialPrefixToken = _tokenizerConfig!['prefix_token'];
    _addPrefixSpace = _tokenizerConfig!.containsKey('add_prefix_space') && _tokenizerConfig!['add_prefix_space'];
    }

    if (_tokenizerConfig!.containsKey('suffix_token')) {
    _specialSuffixToken = _tokenizerConfig!['suffix_token'];
    }

    // 6. Byte-level encoding (for GPT models)
    if (_tokenizerConfig!.containsKey('byte_level') && _tokenizerConfig!['byte_level']) {
    _applyByteLevelEncoding();
    }

    // 7. Stride (for overlapping tokens)
    if (_tokenizerConfig!.containsKey('stride')) {
    int stride = _tokenizerConfig!['stride'];
    print('Stride for overlapping tokens: $stride');
    }

    // 8. Attention masks
    _useAttentionMasks = _tokenizerConfig!.containsKey('use_attention_masks') && _tokenizerConfig!['use_attention_masks'] ?? false;

    // 9. Handle BPE dropout if configured (optional for some models)
    _bpeDropout = _tokenizerConfig!.containsKey('bpe_dropout') && _tokenizerConfig!['bpe_dropout'] > 0
    ? _tokenizerConfig!['bpe_dropout']
    : 0.0;

    // 10. Return token type IDs (needed for models like BERT)
    _returnTokenTypeIds = _tokenizerConfig!.containsKey('return_token_type_ids') && _tokenizerConfig!['return_token_type_ids'];
    print('Return token type IDs: $_returnTokenTypeIds');
    // Add any additional config options if required
    }

    // Helper function to apply special tokens
    void _applySpecialTokens(Map<String, dynamic> specialTokens) {
    specialTokens.forEach((key, value) {
    _specialTokens![key] = value as int;
    });
    }

    // Send message function
    void _handleSendPressed(String messageText) async {
    if (messageText.trim().isNotEmpty) {
    setState(() {
    _messages.add({
    'message': messageText,
    'isUser': true,
    });
    });
    _inputController.clear();
    String botResponse = await _generateResponse(messageText);
    setState(() {
    _messages.add({
    'message': botResponse,
    'isUser': false,
    });
    });
    } else {
    print('Error: Message text is empty');
    }
    }

    // Generate response using TFLite model (async with IsolateInterpreter)
    Future<String> _generateResponse(String inputText) async {
    if (_isolateInterpreter == null) return 'Model not initialized';

    // Tokenize input text (now returns a map)
    Map<String, dynamic> tokenizedInput = _tokenizeInput(inputText);
    List<int> inputTokenIds = tokenizedInput['input_ids'];
    List<int> attentionMasks = tokenizedInput['attention_masks'];

    // Prepare input tensor
    final inputTensor = _prepareInputTensor(inputTokenIds);

    // Prepare attention masks tensor if needed (if attention masks are used in the model)
    final attentionMaskTensor = _prepareInputTensor(attentionMasks);

    // Prepare output tensor
    List<int> outputTokenIds = List.filled(64, 0); // Assuming max length of 64 tokens for output

    // Asynchronous inference with IsolateInterpreter
    try {
    await _isolateInterpreter?.run([inputTensor, attentionMaskTensor], outputTokenIds);
    } catch (e) {
    print('Error during model inference: $e');
    return 'Error generating response';
    }

    // Decode the output
    return _decodeOutput(outputTokenIds);
    }

    // Prepare input tensor for TFLite model
    Uint8List _prepareInputTensor(List<int> inputTokenIds) {
    // Convert List<int> to Uint8List for TFLite
    return Uint8List.fromList(inputTokenIds);
    }

    // Tokenize input string into token IDs
    Map<String, dynamic> _tokenizeInput(String input) {
    List<int> tokenIds = [];

    // 1. Apply case insensitivity if configured
    if (_isCaseInsensitive) {
    input = input.toLowerCase();
    }

    // 2. Tokenize input (split into words or byte-level encoding)
    List<String> tokens = byteLevel ? _byteTokenize(input) : input.split(' ');

    // 3. Add prefix token if available
    if (_specialPrefixToken != null) {
    if (_addPrefixSpace) tokens.insert(0, ' ');
    tokens.insert(0, _specialPrefixToken!);
    }

    for (String token in tokens) {
    // 4. Apply BPE rules to tokenize the word into subwords
    List<String> subwordTokens = applyBPE(token);

    // Convert subword tokens to token IDs
    for (String subwordToken in subwordTokens) {
    if (_tokenToId.containsKey(subwordToken)) {
    tokenIds.add(_tokenToId[subwordToken]!);
    } else if (_specialTokens != null && _specialTokens!.containsKey(subwordToken)) {
    tokenIds.add(_specialTokens![subwordToken]!); // Handle special tokens
    } else {
    tokenIds.add(_tokenToId['<unk>']!); // Handle unknown tokens
    }
    }
    }

    // 5. Optionally add suffix special token
    if (_specialSuffixToken != null) {
    tokenIds.add(_tokenToId[_specialSuffixToken!]!); // Add suffix token (e.g., <sep>)
    }

    // 6. Apply padding if enabled
    if (_paddingEnabled && tokenIds.length < _maxLength) {
    int padCount = _maxLength - tokenIds.length;
    tokenIds.addAll(List.filled(padCount, _tokenToId['<pad>']!));
    }

    // 7. Apply truncation if enabled
    if (_truncationEnabled && tokenIds.length > _maxLength) {
    tokenIds = tokenIds.sublist(0, _maxLength);
    }

    // 8. Generate attention masks based on token IDs
    List<int> attentionMasks = _generateAttentionMasks(tokenIds);

    // Return both token IDs and attention masks as a map
    return {
    'input_ids': tokenIds,
    'attention_masks': attentionMasks,
    };
    }

    // Helper function to generate attention masks
    List<int> _generateAttentionMasks(List<int> tokenIds) {
    if (!_useAttentionMasks) return [];

    // Create an attention mask: 1 for real tokens, 0 for padding
    return List<int>.generate(tokenIds.length, (index) => tokenIds[index] == _tokenToId['<pad>'] ? 0 : 1);
    }

    // Byte-level encoding function (for GPT models)
    List<String> _byteTokenize(String input) {
    return input.runes.map((rune) => String.fromCharCode(rune)).toList();
    }

    // Function to handle byte-level encoding
    void _applyByteLevelEncoding() {
    // Ensure the vocabulary and merges are loaded
    if (_vocab == null || _merges == null) {
    print('Error: Vocabulary or merges not loaded for byte-level encoding.');
    return;
    }

    print('Byte-level tokenization enabled.');

    // Iterate through the vocabulary and create byte-level tokens if necessary
    for (String token in _vocab!.keys) {
    // Break down the token into individual byte representations
    List<int> byteRepresentation = _convertToBytes(token);

    // Map the byte tokens to the model's vocabulary IDs
    for (int byte in byteRepresentation) {
    String byteToken = _byteToToken(byte);
    if (!_tokenToId.containsKey(byteToken)) {
    _tokenToId[byteToken] = byte;
    _idToToken[byte] = byteToken;
    }
    }
    }
    }

    // Helper function to convert a string into its byte representation
    List<int> _convertToBytes(String input) {
    // Convert each character to its UTF-8 byte value
    return input.codeUnits;
    }

    // Helper function to convert byte values to corresponding token representations
    String _byteToToken(int byteValue) {
    // Map byte values to corresponding token format, e.g., '<byte_23>' for byte 23
    return '<byte_$byteValue>';
    }

    // Decode output token IDs into a string
    String _decodeOutput(List<int> tokenIds) {
    StringBuffer decodedText = StringBuffer();

    for (int id in tokenIds) {
    if (_idToToken.containsKey(id)) {
    decodedText.write(_idToToken[id]! + ' ');
    }
    }

    return decodedText.toString().trim();
    }

    Future<void> _initializeSpeech() async {
    var status = await Permission.microphone.request();
    if (status.isGranted) {
    bool available = await _speechToText.initialize(
    onStatus: _onSpeechStatus, onError: _onSpeechError);
    if (available) {
    setState(() {
    _isSpeechAvailable = true;
    });
    } else {
    // Handle case where speech recognition is not available
    print("Speech recognition not available");
    }
    } else {
    print('Microphone permission denied');
    }
    }


    and this the python code I've downloaded from the model and tokenizer files

    from transformers import TFAutoModelForCausalLM, AutoTokenizer
    import tensorflow as tf

    # Step 1: Load the pre-trained model and tokenizer
    model = TFAutoModelForCausalLM.from_pretrained("distilgpt2")
    tokenizer = AutoTokenizer.from_pretrained("distilgpt2")

    # Step 2: Tokenize input
    def tokenize_input(text):
    input_ids = tokenizer.encode(text, return_tensors='tf')
    return input_ids

    # Step 3: Convert model to TensorFlow Lite
    converter = tf.lite.TFLiteConverter.from_keras_model(model)
    converter.optimizations = [tf.lite.Optimize.DEFAULT]
    tflite_model = converter.convert()

    # Step 4: Save the TensorFlow Lite model
    with open('distilgpt2_model.tflite', 'wb') as f:
    f.write(tflite_model)

    # Step 5: Save the tokenizer
    tokenizer.save_pretrained('./tokenizer')

    # Function to decode model output
    def decode_output(output_ids):
    return tokenizer.decode(output_ids, clean_up_tokenization_spaces=True)


    I tried to install chatbot model with the tokenizer files from python and use it in my flutter app but the model didn't work and I need help with completing the implementation and all the functionalities needed to make it work

    Continue reading...

Compartilhe esta Página