in frontend/frontend-flutter/lib/screens/bot.dart [1181:1927]
Future<void> copyGraphToClipBoard(String imageKey, String summaryText) async {
print('Bot : copyGraphToClipBoard() : START');
print('Bot : copyGraphToClipBoard() : imageKey = $imageKey');
print('Bot : copyGraphToClipBoard() : summaryText = $summaryText');
//For now, the copy button only copies text. Copy of images/widgets is supported, so I'm commenting out the copy of image until
//the flutter_inappwebview package used to render Google Charts is implementing InAppWebViewController.takeScreenshot() on Flutter Web.
if(false) {
//if (imageKey != "no_image") {
print('Bot : copyGraphToClipBoard() : imageKey != "no_image"');
print('Bot : copyGraphToClipBoard() : _graphsImagesMap.length = ${_graphsImagesMap.length}');
Uint8List imgBytes = _graphsImagesMap[imageKey!]!;
if (imgBytes != null) {
print('Bot : copyGraphToClipBoard() : imgBytes != null');
final base64Image = base64Encode(imgBytes);
try {
js.context.callMethod('copyBase64ImageToClipboard', [base64Image]);
} catch (e) {
print('Bot : copyGraphToClipBoard() : EXCEPTION : e = $e');
}
}
} else if (summaryText != null || summaryText.length > 0) {
print('Bot : copyGraphToClipBoard() : summaryText != null || summaryText.length > 0');
await Clipboard.setData(ClipboardData(text: summaryText));
} else {
print('Bot : copyGraphToClipBoard() : else');
await Clipboard.setData(ClipboardData(text: "No data available."));
}
}
Future<List<Object>?> getChatResponseNew(String msg, String mime, String id,
{types.User? user}) async {
List<String>? reqResp = [];
List<Object> RespList = [];
Uri urlGenerateSQL;
Uri urlRunQuery;
String generatedSQLText = "";
String userQuestion = "";
int statusCodeRunQuery = 0;
String jsonResponseRunQuery = "";
print('Bot : getChatResponseNew() : START ');
urlGenerateSQL =
Uri.parse('${TextToDocParameter.endpoint_opendataqnq}/generate_sql');
print('Bot : getChatResponseNew() : urlGenerateSQL = ' +
urlGenerateSQL.host +
urlGenerateSQL.path);
print('Bot : getChatResponseNew() : mime = ' + mime);
Map<String, String>? _headers = {
"Content-Type": "$mime",
};
print(
'Bot : getChatResponseNew() : BEFORE prepending main question : msg = ' +
msg);
if (mainQuestionsFollowUpQuestions.containsKey(msg)) {
msg = mainQuestionsFollowUpQuestions[msg];
}
print(
'Bot : getChatResponseNew() : AFTER prepending main question : msg = ' +
msg);
userQuestion = msg;
print('Bot : getChatResponseNew() : userQuestion = ' + userQuestion);
String _body1 = '''{
"session_id" :"${TextToDocParameter.sessionId}",
"user_id":"${TextToDocParameter.userID}",
"user_question":"${userQuestion}",
"user_grouping":"${TextToDocParameter.currentUserGrouping}"
}''';
print('Bot : getChatResponseNew() : _body1 = ' + _body1);
final stopwatchGenerateSQL = Stopwatch()..start();
final _response =
await http.post(urlGenerateSQL, headers: _headers, body: _body1);
stopwatchGenerateSQL.stop();
responsePalMBody = _response.body.replaceAll(
RegExp(r'(\\u003cb|\\u003e|\\u003c|\\u003e|(\/n)|(\\r))'), '');
print('Bot : getChatResponseNew() : responsePalMBody = $responsePalMBody');
var error = pickFromJson(responsePalMBody!, 'Error').asStringOrNull();
print('Bot : getChatResponseNew() : error = $error');
print(
'Bot : getChatResponseNew() : _response.statusCode = ${_response.statusCode}');
if (_response.statusCode == 200 &&
responsePalMBody!.toLowerCase().contains("select") &&
(error!.length == 0 ?? false)) {
print(
'Bot : getChatResponseNew() : _response.statusCode == 200 && (error!.length == 0 ?? false )');
TextToDocParameter.sessionId =
pickFromJson(responsePalMBody!, 'SessionID').asStringOrNull()!;
print(
'Bot : getChatResponseNew() : _response.statusCode == 200 && (error!.length == 0 ?? false ) : TextToDocParameter.sessionId = ${TextToDocParameter.sessionId}');
reqResp.add(_body1);
reqResp.add(responsePalMBody);
print('Bot : getChatResponseNew() : /generate_sql : reqResp[0] = ' +
reqResp[0]);
print('Bot : getChatResponseNew() : /generate_sql : reqResp[1] = ' +
reqResp[1]);
//get the generated SQL query
generatedSQLText = extractContentGenerateSQL(responsePalMBody);
//Update stepper state to generate_sql
BlocProvider.of<UpdateStepperCubit>(context).updateStepperStatusUploaded(
status: StepperStatus.generate_sql,
message: "SQL request generated.",
stateStepper: StepState.complete,
isActiveStepper: true,
debugInfo: StepperExpertInfo(
uri: urlGenerateSQL.host + urlGenerateSQL.path,
body: _body1,
header: jsonEncode(_headers),
response: responsePalMBody,
generatedSQLText: generatedSQLText,
statusCode: _response.statusCode,
stepDuration: stopwatchGenerateSQL.elapsed.inMilliseconds,
answerList: [generatedSQLText]));
print(
"main: getChatResponseNew() : After BlocProvider.of<UpdateStepperCubit>(context).updateStepperStatusUploaded() : generate_sql");
print(
"main: getChatResponseNew() : generate_sql : generatedSQLText = $generatedSQLText");
urlRunQuery =
Uri.parse('${TextToDocParameter.endpoint_opendataqnq}/run_query');
String _body2 = '''{
"user_question": "${userQuestion}",
"user_grouping": "${TextToDocParameter.currentUserGrouping}",
"generated_sql": "${generatedSQLText}",
"session_id" : "${TextToDocParameter.sessionId}"
}''';
//send the request to get the results in tabular format
var stopwatchRunQuery = Stopwatch()..start();
final _responseTabResults =
await http.post(urlRunQuery, headers: _headers, body: _body2);
stopwatchRunQuery.stop();
statusCodeRunQuery = _responseTabResults.statusCode;
jsonResponseRunQuery = _responseTabResults.body;
print('Bot : getChatResponseNew() : tabular results: urlRunQuery = ' +
urlRunQuery.toString());
print(
'Bot : getChatResponseNew() : tabular results : _body2 = ' + _body2);
print(
'Bot : getChatResponseNew() : tabular results: _responseTabResults.body = ' +
jsonResponseRunQuery);
if (TextToDocParameter.anonymized_data) {
print(
'Bot : getChatResponseNew() : tabular results: TextToDocParameter.anonymized_data = ${TextToDocParameter.anonymized_data}');
jsonResponseRunQuery = anonymizedData(jsonResponseRunQuery!);
}
//return extractContent(_responseTabResults.body, id, user: user!);
return extractContentResultsOpenDataQnA(
jsonResponseRunQuery: jsonResponseRunQuery,
userQuestion: userQuestion,
generatedSQLText: generatedSQLText,
urlRunQuery: urlRunQuery,
bodyRunQuery: _body2,
headersRunQuery: _headers,
statusCodeRunQuery: statusCodeRunQuery,
elapsedTimeRunQuery: stopwatchRunQuery.elapsed.inMilliseconds);
} else {
//Update stepper state to generate_sql
BlocProvider.of<UpdateStepperCubit>(context).updateStepperStatusUploaded(
status: StepperStatus.generate_sql,
message: "SQL request generated in",
stateStepper: StepState.complete,
isActiveStepper: true,
debugInfo: StepperExpertInfo(
uri: urlGenerateSQL.host + urlGenerateSQL.path,
body: _body1,
header: jsonEncode(_headers),
response: responsePalMBody,
generatedSQLText:
"An error occurred, no SQL request has been generated.",
statusCode: _response.statusCode,
stepDuration: stopwatchGenerateSQL.elapsed.inMilliseconds,
answerList: [
"An error occurred, no SQL request has been generated."
]));
print(
'Bot : getChatResponseNew() : tabular results : _response.statusCode = ${_response.statusCode} and error attribute is set');
RespList.add("");
RespList.add(true);
RespList.add("");
RespList.add(
"The request did not return meaningful information. It could be because the question has not been formulated properly or some context is missing.");
return RespList;
}
}
String extractContentGenerateSQL(String jsonResponse) {
print("bot() : extractContentGenerateSQL() : START");
print("bot() : extractContentGenerateSQL() : jsonResponse = $jsonResponse");
String generatedSQLText = "";
var error = pickFromJson(jsonResponse, 'Error');
var generatedSQLTmp =
pickFromJson(jsonResponse, 'GeneratedSQL').asStringOrNull();
var responseCode = pickFromJson(jsonResponse, 'ResponseCode');
print(
"bot() : extractContentGenerateSQL() : generatedSQLTmp = ${generatedSQLTmp}");
generatedSQLText = generatedSQLTmp!
.replaceAll('\n', ' ')
.replaceAll('"', '\\"'); //generates an exception if null => fix it
print(
"bot() : extractContentGenerateSQL() : generatedSQLText = ${generatedSQLText}; ");
return generatedSQLText!;
}
Future<List<Object>> extractContentResultsOpenDataQnA(
{String? jsonResponseRunQuery,
String? userQuestion,
String? generatedSQLText,
Uri? urlRunQuery,
String? bodyRunQuery,
Map<String, String>? headersRunQuery,
int? statusCodeRunQuery,
int? elapsedTimeRunQuery}) async {
//String generatedSQLText = "";
List<Object> RespList = [];
bool isText = true;
dynamic googleChartVizRes;
String? naturalResponseText = "";
String textSummary =
"The request did not return meaningful information. It could be because the question has not been formulated properly or some context is missing.";
String? knownDB = "";
String? error = "";
error = pickFromJson(jsonResponseRunQuery!, 'Error').asStringOrNull();
knownDB = pickFromJson(jsonResponseRunQuery!, 'KnownDB').asStringOrNull();
var responseCode = pickFromJson(jsonResponseRunQuery!, 'ResponseCode');
naturalResponseText =
pickFromJson(jsonResponseRunQuery!, 'NaturalResponse').asStringOrNull();
print(
"bot() : extractContentResultsOpenDataQnA() : knownDB.length = ${knownDB!.length}; ");
print(
"bot() : extractContentResultsOpenDataQnA() : knownDB = ${knownDB}; ");
print(
"bot() : extractContentResultsOpenDataQnA() : bodyRunQuery = ${bodyRunQuery}; ");
//Update stepper state to run_query
BlocProvider.of<UpdateStepperCubit>(context).updateStepperStatusUploaded(
status: StepperStatus.run_query,
message: "Tabular data retrieved in",
stateStepper: StepState.complete,
isActiveStepper: true,
debugInfo: StepperExpertInfo(
uri: urlRunQuery!.host + urlRunQuery!.path,
body: bodyRunQuery,
header: jsonEncode(headersRunQuery!),
response: jsonResponseRunQuery
.replaceAll("\"[", "[")
.replaceAll("]\"", "]")
.replaceAll("\\\"", "\""),
knownDB: knownDB,
statusCode: statusCodeRunQuery,
stepDuration: elapsedTimeRunQuery,
answerList: [knownDB]));
print(
"main: extractContentResultsOpenDataQnA() : After BlocProvider.of<UpdateStepperCubit>(context).updateStepperStatusUploaded() : run_query");
try {
if (knownDB != "[]" && error!.length == 0 ?? false) {
print("bot() : extractContentResults() : VALID ANSWER");
var knowDBJson = jsonDecode(knownDB!);
//Check if it is worth displaying data. If just one row is returned, no use.
//if (true) {
if ((knowDBJson!.length <= 1 && (knowDBJson![0] as Map).length <= 1) ||
(knowDBJson![0] as Map).length > 2) {
print(
"bot() : extractContentResultsOpenDataQnA() : knowDBJson!.length <= 1 and MAP has at most 1 element");
isText = true;
//Get graph description in case we want to display a graph
googleChartVizRes = await getDataVisualization(
userQuestion!, knownDB!, generatedSQLText!);
print(
"bot() : extractContentResultsOpenDataQnA() : googleChartVizRes = ${googleChartVizRes}");
} else {
print(
"bot() : extractContentResultsOpenDataQnA() : knowDBJson!.length > 1 or MAP has at least 1 element");
isText = false;
//Get graph description in case we want to display a graph
googleChartVizRes = await getDataVisualization(
userQuestion!, knownDB!, generatedSQLText!);
print(
"bot() : extractContentResultsOpenDataQnA() : googleChartVizRes = ${googleChartVizRes}");
}
print(
"bot() : extractContentResultsOpenDataQnA() : isText = ${isText}; ");
//get ML summarize
//textSummary = await getTextSummary(userQuestion!, knownDB!);
RespList.add(knownDB!);
RespList.add(isText);
RespList.add(googleChartVizRes!);
RespList.add(naturalResponseText!.trim());
} else {
print("bot() : extractContentResultsOpenDataQnA() : UNVALID ANSWER");
RespList.add("");
RespList.add(true);
RespList.add({"chart_div": "empty", "chart_div_1": "empty"});
RespList.add(
"The request did not return meaningful information. It could be because the question has not been formulated properly or some context is missing.");
}
} catch (e) {
print("bot() : extractContentResultsOpenDataQnA() : EXCEPTION : $e");
} finally {
print("bot() : extractContentResultsOpenDataQnA() : FINALLY CLAUSE ");
RespList.add(knownDB!);
RespList.add(isText);
RespList.add(googleChartVizRes!);
RespList.add(naturalResponseText!);
return RespList;
}
}
Future<dynamic> getDataVisualization(
String question, String tabularAnswer, String generatedSQLText) async {
dynamic generatedChartjsMap;
//Create the header
Map<String, String>? _headers = {
"Content-Type": "application/json",
};
String tmpReplace = tabularAnswer.replaceAll('"', '\\"');
print('Bot : getDataVisualization() : tnpReplace = ' + tmpReplace);
//Create the body
String _body = '''{
"user_question": "$question",
"sql_generated": "${generatedSQLText}",
"sql_results": "${tmpReplace}",
"session_id" : "${TextToDocParameter.sessionId}"
}''';
print('Bot : getDataVisualization() : _body = ' + _body);
try {
var stopwatchGetDataVisulization = Stopwatch()..start();
print('Bot: getDataVisualization() : BEFORE HttpRequest');
var response = await html.HttpRequest.requestCrossOrigin(
'${TextToDocParameter.endpoint_opendataqnq}/generate_viz',
method: "POST",
sendData: _body);
print('Bot: getDataVisualization() : AFTER HttpRequest');
stopwatchGetDataVisulization.stop();
print('Bot : getDataVisualization() : response = ' + response.toString());
var jsonData = jsonDecode(response);
if (jsonData != null) {
print('Bot: getDataVisualization() : jsonData = $jsonData');
generatedChartjsMap = jsonData["GeneratedChartjs"];
print(
'Bot: getDataVisualization() : generatedChartjsMap = $generatedChartjsMap');
if(TextToDocParameter.anonymized_data) {
//update generatedChartjsMap
mapAnonymisationGraph.forEach((key, value) {
print(
'Bot : getDataVisualization() : update jsonData : key = $key, value = $value');
generatedChartjsMap['chart_div'] =
generatedChartjsMap['chart_div'].replaceAll(key, value);
});
}
//Update stepper state to get_graph_description
BlocProvider.of<UpdateStepperCubit>(context)
.updateStepperStatusUploaded(
status: StepperStatus.get_graph_description,
message: "Graph generated",
stateStepper: StepState.complete,
isActiveStepper: true,
debugInfo: StepperExpertInfo(
uri:
"${TextToDocParameter.endpoint_opendataqnq}/generate_viz",
body: _body
.replaceAll("\"[", "[")
.replaceAll("]\"", "]")
.replaceAll("\\\"", "\""),
header:
'''{"Header not accessible": "CORS headers are not accessible as they are sent directly by the web browser"}''',
response: response
.replaceAll("\"[", "[")
.replaceAll("]\"", "]")
.replaceAll("\\\"", "\""),
statusCode: 0,
stepDuration:
stopwatchGetDataVisulization.elapsed.inMilliseconds,
));
print(
"Bot: getDataVisualization() : After BlocProvider.of<UpdateStepperCubit>(context).updateStepperStatusUploaded() : get Google Charts");
} else {
print('Bot: getDataVisualization() : jsonData is null');
}
} catch (e) {
generatedChartjsMap = {"chart_div": "empty", "chart_div_1": "empty"};
print('Bot: getDataVisualization() : EXCEPTION : error = $e');
} finally {
return generatedChartjsMap!;
}
}
List<String> setBubbleColor(String text, {types.User? user}) {
String tmp = "";
String userType = "";
const String datastoreGenerated = "ap :";
const String nMatchLLMGenerated = "nh :";
int startIndex = 0;
List<String> rep = [];
print('Bot : setBubbleColor() : text = ' + text);
if (user != null) if (_user.id == user!.id) userType = "user";
if (text.contains(datastoreGenerated)) {
startIndex =
text.indexOf(datastoreGenerated) + datastoreGenerated.length + 1;
colorBubble = "datastoreData";
} else if (text.contains(nMatchLLMGenerated)) {
startIndex =
text.indexOf(nMatchLLMGenerated) + datastoreGenerated.length + 1;
colorBubble = "noMatchLLM";
} else if (userType == "user") {
colorBubble = "user";
} else {
colorBubble = "regularDF";
}
tmp = text.substring(startIndex);
print('Bot : setBubbleColor() : startIndex = ' + startIndex.toString());
print('Bot : setBubbleColor() : tmp = ' + tmp);
print('Bot : setBubbleColor() : colorBubble = ' + colorBubble);
rep.add(tmp);
rep.add(colorBubble);
return rep;
}
int countOccurences(String mainString, String search) {
int lInx = 0;
int count = 0;
while (lInx != -1) {
lInx = mainString.indexOf(search, lInx);
if (lInx != -1) {
count++;
lInx += search.length;
}
}
return count;
}
Future<void> _dialogExtension(BuildContext context, String extension) {
return showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text("Format d'image non supporté",
style: TextStyle(
fontWeight: FontWeight.normal,
fontSize: 22.0,
color: Colors.blue)),
content: Text(
"Le format d'image $extension n'est pas supporté.\n" +
"Choisissez une image du type :\ngif, tiff, tif, jpg, jpeg, png, bmp, webp",
),
actions: <Widget>[
TextButton(
style: TextButton.styleFrom(
textStyle: Theme.of(context).textTheme.labelLarge,
),
child: const Text('Ok'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
String displayDateTime() {
String? dateTimeS;
final now = DateTime.now();
dateTimeS = DateFormat('yyyy-MM-dd HH:mm:ss').format(now);
return dateTimeS!;
}
List<types.Message> get messages {
return _messages;
}
Map<String, Uint8List> get graphsImages {
return _graphsImagesMap;
}
Map<String, PaginatedDataTable> get tableKeysMap {
return tableKeyMap;
}
Widget avatarBuilder(types.User user) {
bool isUserAvatar = user.id == '82091010-a484-4a89-ae75-a22bf8d6f3ab';
return CircleAvatar(
backgroundColor: Colors.green,
backgroundImage:
isUserAvatar ? NetworkImage(TextToDocParameter.picture) : null,
radius: 16,
child: !isUserAvatar
? Text(
"TA",
)
: null,
);
}
String anonymizedData(String responseRunQuery) {
String anonymizedData = "";
Random random = new Random();
mapAnonymisationGraph.clear();
print("Bot : anonymizedData() : START");
print("Bot : anonymizedData() : responseRunQuery = ${responseRunQuery}");
var responseRunQueryJson = jsonDecode(responseRunQuery);
print(
"Bot : anonymizedData() : responseRunQueryJson = ${responseRunQueryJson}");
var knownDB = jsonDecode(responseRunQueryJson["KnownDB"]);
String naturalResponse = responseRunQueryJson["NaturalResponse"];
print("Bot : anonymizedData() : knownDB = ${knownDB}");
print("Bot : anonymizedData() : naturalResponse = ${naturalResponse}");
for (int i = 0; i < knownDB.length; i++) {
var entry = knownDB[i];
print("Bot : anonymizedData() : for : i = $i : entry = ${entry}");
entry.forEach((key, value) {
print('Bot : anonymizedData() : key = $key : value = $value');
try {
if (value is double) {
print(
'Bot : anonymizedData() : i = $i : value = $value is of type double');
double randomNumber = random.nextDouble() * value;
int truncatedInt = (randomNumber * 100).toInt();
randomNumber = truncatedInt / 100;
print(
'Bot : anonymizedData() : i = $i : randomNumber = $randomNumber');
entry[key] = randomNumber;
NumberFormat formatter = NumberFormat("#,##0", "en_US"); // Adjust locale if needed
String formattedNumber = formatter.format(value);
mapAnonymisationGraph[formattedNumber] = formatter.format(randomNumber);//randomNumber.toString();
}
if (value is String) {
print(
'Bot : anonymizedData() : i = $i : value = $value is of type String');
String randomString = generateRandomString(value.toString().length);
print(
'Bot : anonymizedData() : i = $i : randomString = $randomString');
entry[key] = randomString;
mapAnonymisationGraph[value.toString()] = randomString;
}
} catch (e) {
print('Bot : anonymizedData() : PARSING EXCEPTION = $e');
}
});
}
responseRunQueryJson["KnownDB"] = jsonEncode(knownDB);
//update NaturalResponse
mapAnonymisationGraph.forEach((key, value) {
print(
'Bot : anonymizedData() : update NaturalResponse : key = $key, value = $value');
naturalResponse = naturalResponse.replaceAll(key,value);
});
print("Bot : anonymizedData() : END : knownDB = ${knownDB}");
print("Bot : anonymizedData() : END : naturalResponse = ${naturalResponse}");
responseRunQueryJson["NaturalResponse"] = naturalResponse;
print(
"Bot : anonymizedData() : END : responseRunQueryJson = ${responseRunQueryJson}");
return jsonEncode(responseRunQueryJson);
}
String generateRandomString(int length) {
const _chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890';
Random _rnd = Random();
return String.fromCharCodes(Iterable.generate(
length, (_) => _chars.codeUnitAt(_rnd.nextInt(_chars.length))));
}
Future<void> _updateUserGroupingInSessionLogs() async {
int count = 0;
print(
"Bot: _updateUserGroupingInSessionLogs() : START");
//get all the documents corresponding to the user_id of the current user
try {
var querySnapshot = await widget.db!
.collection("${TextToDocParameter.firestore_history_collection}")
.where("user_id", isEqualTo: TextToDocParameter.userID)
.orderBy('timestamp', descending: true)
.limit(1)
.get();
print(
"Bot: _updateUserGroupingInSessionLogs() : Add user_grouping : querySnapshot.docs.length = ${querySnapshot.docs.length}");
print(
"Bot: _updateUserGroupingInSessionLogs() : Add user_grouping : querySnapshot = ${querySnapshot}");
//update all these documents with the user_grouping scenario_name
if(TextToDocParameter.currentScenarioName.isEmpty)
TextToDocParameter.currentScenarioName = "Scenario";
for (var docSnapshot in querySnapshot.docs) {
print(
'Bot: _updateUserGroupingInSessionLogs() : Add user_grouping : TextToDocParameter.currentUserGrouping = ${TextToDocParameter.currentUserGrouping}');
print(
'Bot: _updateUserGroupingInSessionLogs() : Add user_grouping : TextToDocParameter.currentScenarioName = ${TextToDocParameter.currentScenarioName}');
print(
'Bot: _updateUserGroupingInSessionLogs() : Add user_grouping : ${docSnapshot.id} => ${docSnapshot.data()}');
widget.db!.collection("${TextToDocParameter.firestore_history_collection}").doc('${docSnapshot.id}').set(
{"user_grouping": "${TextToDocParameter.currentUserGrouping}", "scenario_name": "${TextToDocParameter.currentScenarioName}"},
SetOptions(merge: true));
count++;
}
} catch (e) {
print(
'Bot: _updateUserGroupingInSessionLogs() : Add user_grouping : EXCEPTION : $e');
}
var snackBar = SnackBar(
content:
Text('Updated $count questions on ${TextToDocParameter.firestore_database_id} collection'),
duration: Duration(seconds: 3),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
PaginatedDataTable? createPaginatedTable(String data) {
print("bot() : createPaginatedTable() : START");
print("bot() : createPaginatedTable() : data = $data");
List<DataColumn> dataColumnList = <DataColumn>[];
List<dynamic> dataList = jsonDecode(data!);
print("bot() : createPaginatedTable() : dataList = $dataList");
print("bot() : createPaginatedTable() : dataList.length = ${dataList.length}");
//get headers of columns
var entry = dataList.first;
print("bot() : createPaginatedTable() : entry = ${entry}");
print("bot() : createPaginatedTable() : entry.length = ${entry.length}");
print("bot() : createPaginatedTable() : entry['tconst'] = ${entry['tconst']}");
print("bot() : createPaginatedTable() : entry['original_title'] = ${entry['original_title']}");
print("bot() : createPaginatedTable() : entry['average_rating'] = ${entry['average_rating']}");
print("bot() : createPaginatedTable() : entry['title_type'] = ${entry['title_type']}");
for (var element in (entry as Map<String, dynamic>).entries) {
print('bot() : createPaginatedTable() : Key: ${element.key}, Value: ${element.value}');
dataColumnList.add(DataColumn(label: Text(element.key.toString(), style: TextStyle(fontWeight: FontWeight.bold, color : Colors.white))));
}
if (dataList.length != 0) {
print("bot() : createPaginatedTable() : dataList.length != 0}");
var rowsList = dataList.map((data) {
List<DataCell> dataCellsList = <DataCell>[];
for (var element in (data as Map<String, dynamic>).entries) {
print('bot() : createPaginatedTable() : Key: ${element.key}, Value: ${element.value}');
DataCell cell = DataCell(Text(element.value.toString()));
dataCellsList.add(cell);
}
return DataRow(cells: dataCellsList);
}).toList();
return PaginatedDataTable(
//header: Text('Results'),
headingRowColor: WidgetStateProperty.all(Colors.blue),
rowsPerPage: 3, // Customize as needed
columns: dataColumnList,
source: OpenDataQnASource(rowsList as List<DataRow>),
);
}
else
return null;
}
}