ChatGPT Clone | Stream API | Custom Code Explanation

preview_player
Показать описание
Learn how to create the streaming response effect similar to the ChatGPT app using OpenAI's Chat Completion Stream API and custom code in FlutterFlow.

--------------

FlutterFlow is a low-code builder for native apps, bringing design and development into one tool. With drag-and-drop functionality, you can build pixel-perfect UIs and easily connect your app to live data via Firebase or APIs. Plus, you can add advanced features like push notifications, payments, animations, and more. Whether you build your own custom widgets or write custom code, FlutterFlow makes it easy to bring your app ideas to life.
Рекомендации по теме
Комментарии
Автор

Super useful clarification, I'd love to know how we can adjust the message history to only send x amount of responses for the history? Otherwise long conversation threads will throw errors as they overflow the context window. Technically the best practice here is to:
1. After 5 messages in the chathistory => Summarise the conversation thread and add that into the system msg.
2. Include the last 5 msgs in the chatHistory (not all the messages, as is being done here).

Amazing work! I'd love to see if we can get the best quality experiences with AI directly in FF.

Also if it's helpful to others here is the code, pls let me know if there are any bugs!
STREAM API RESPONSE CODE:
// Automatic FlutterFlow imports
import '/backend/backend.dart';
import
import
import
import 'index.dart'; // Imports other custom actions
import // Imports custom functions
import
// Begin custom action code
// DO NOT REMOVE OR MODIFY THE CODE ABOVE!

// streamApiResponse.dart

import 'dart:convert';
import 'package:http/http.dart' as http; // Fixed the import

var _client;

Future streamApiResponse(
List<dynamic> jsonBody,
Future<dynamic> Function() callbackAction,
) async {
// Add your function code here!

_client = http.Client();

// Prepare Request

final headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer ${FFAppState().apiKey}',
};

String body = getApiBody(jsonBody);

// Create Request
var request = http.Request("POST",
request.body = body;

final http.StreamedResponse response = await _client.send(request);

// Before streaming response, add an empty ChatResponse object to chatHistory

author: "assistant",
content: "",
));

// Stream Response
value) {
// Fixed the callback function definition
var str = utf8.decode(value);

// Process the results or add it to UI
if (str.contains("data:")) {
String data = str.split("data:")[1];
addToChatHistory(data, callbackAction);
}
});
}

void addToChatHistory(String data, callbackAction) {
if (data.contains("content")) {
ContentResponse contentResponse =


if (contentResponse.choices != null &&
!= null &&
!= null) {
String content =


- 1,
(e) {
// Removed the extra period
return e..content = "${e.content}$content";
},
);
//setState and scroll to last item in list
callbackAction();
}
}
}

String getApiBody(dynamic jsonBody) {
// Added return type 'String'
String body = jsonEncode({
"model": "gpt-3.5-turbo",
"messages": jsonBody,
"stream": true,
});
return body; // Added return statement to return the body
}

//sc3
class ContentResponse {
String? id;
String? object;
int? created;
String? model;
List<Choices>? choices;

ContentResponse(
{this.id, this.object, this.created, this.model, this.choices});

ContentResponse.fromJson(Map<String, dynamic> json) {
// Fixed method name and parameters
id = json['id']; // Fixed assignment syntax
object = json['object']; // Fixed assignment syntax
created = json['created'];
model = json['model'];

if (json['choices'] != null) {
choices = <Choices>[];
json['choices'].forEach((v) {
choices!.add(new Choices.fromJson(v));
});
}
}

//sc2
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['object'] = this.object;
data['created'] = this.created;
data['model'] = this.model;

if (this.choices != null) {
data['choices'] = this.choices!.map((v) => v.toJson()).toList();
}

return data;
}
}

class Choices {
int? index;
Delta? delta;
String? finishReason;

Choices({this.index, this.delta, this.finishReason}); // Fixed spacing

Choices.fromJson(Map<String, dynamic> json) {
index = json['index'];
delta = json['delta'] != null ? new Delta.fromJson(json['delta']) : null;
finishReason = json['finish_reason']; // Fixed assignment syntax
}

//sc1
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['index'] = this.index;

if (this.delta != null) {
data['delta'] = this.delta!.toJson();
}

data['finish_reason'] = this.finishReason;
return data;
}
}

class Delta {
String? content;

Delta({this.content});

Delta.fromJson(Map<String, dynamic> json) {
content = json['content'];
}

Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['content'] = this.content;
return data;
}
}

CONVERT LIST TO JSON CODE:
// Automatic FlutterFlow imports
import '/backend/backend.dart';
import
import
import
import 'index.dart'; // Imports other custom actions
import // Imports custom functions
import
// Begin custom action code
// DO NOT REMOVE OR MODIFY THE CODE ABOVE!

// convertListToJson.dart

Future<List<dynamic>> convertListToJson(
List<ChatResponseStruct> responseList) async {
// convert responseList to list of json body
List<dynamic> jsonList = [];

for (var response in responseList) {
Map<String, dynamic> jsonBody = {
"role": response.author,
"content": response.content,
};
jsonList.add(jsonBody);
}
return jsonList;
}

MrBenjo
Автор

I currently have a very big problem when I make an API call with gpt-3.5-turbo. Every time I ask it to generate 5 paragraphs of 400 words for me, when I test the api call, lapi gives me XMLHTTPREQUEST error. do you have a solution for this? THANKS

julesvincent
Автор

It would be cool if you attach the code that we can clone it and try ourselves

KaiCodingJourney
Автор

i do not know how to say this but FF you people seem very ignorant when viewers are asking you to just paste the code in the description or the entire project in the marketplace so that even we the pro users can get access to it....just because of this hassle that you puting some of use throught makes some of my collegue prefer to return and start using bubble instead because they have the project in thier market this serous is simple to put it into your marketplace

shabatidjani
Автор

Could you please add this to the marketplace? As a Pro User, it would be very helpful for me

williemccool
Автор

I've managed to replicate it, though it only works on mobile/emulator and not on web. Also for some reason, it kept cutting out certain words at the beginning, when I debugPrint the data. I can see it's something to do with the UTF8 decoding or something because when I tried to debugPrint the str, it works. Still trying to figure that out.

KennethMak
Автор

Thanks for the explanation and the great video. I have replicated your tutorial exactly, but unfortunately the API call does not work. I have tested the app both in test mode and locally on an IOS simulator. I never get a response on a prompt, it always just shows my typed text.

What could I do? I am grateful for any tips.

orhang
Автор

Have watched this video countless times, I still don't get it 😭😭😭😭😭😭😭

David_tommy
Автор

I believe I've faithfully replicated the code and the FF logic after watching your fantastic video, but my app still isn't working. I'm not sure how to go about debugging it. Could you please share the code or provide a cloneable version of the app?"

watanocode
Автор

Thank you Pooja for this amazing video 🎉

flutterflowexpert
Автор

Where is the code ? Are we expected to just write it ourself ?

SolanaBoardGames
Автор

How are you supposed to save your api key? Do you enter it as a variable in the API call? Or do you do something with the app state?

matilda
Автор

Use try catch method when you doing json decode of response message

niteshjaiswal
Автор

NEED HELP!
After following both videoes, I am getting this error:

Error while compiling the code in flutterflow:

Custom Action error: Errors Found in custom action "streamApiResponse"


Error: Command failed: flutter build web --web-renderer html --no-pub --no-version-check --no-tree-shake-icons
Target dart2js failed: Exception:
Error: The method 'addToChatHistory' isn't defined for the class 'FFAppState'.
- 'FFAppState' is from ('lib/app_state.dart').



Error: The method 'updateChatHistoryAtIndex' isn't defined for the class 'FFAppState'.
- 'FFAppState' is from ('lib/app_state.dart').



Error: The getter 'chatHistory' isn't defined for the class 'FFAppState'.
- 'FFAppState' is from ('lib/app_state.dart').
- 1,

Error: Compilation failed.


Exception: Failed to compile application for the Web.

RohitK-zye