add create group chat validation for custom and game master instructions

pull/1384/head
WilsonLe 1 year ago
parent 0201aae916
commit bd4d9e43ed

@ -4003,6 +4003,7 @@
"conversationBotCustomZone_title": "Custom Settings",
"conversationBotCustomZone_customSystemPromptLabel": "System prompt",
"conversationBotCustomZone_customSystemPromptPlaceholder": "Set custom system prompt",
"conversationBotCustomZone_customSystemPromptEmptyError": "Missing custom system prompt",
"conversationBotCustomZone_customTriggerReactionEnabledLabel": "Responds on ⏩ reaction",
"botConfig": "Conversation Bot Settings",
"addConversationBotDialogTitleInvite": "Confirm inviting conversation bot",
@ -4013,6 +4014,10 @@
"addConversationBotDialogRemoveConfirmation": "Remove",
"conversationBotConfigConfirmChange": "Confirm",
"conversationBotStatus": "Bot Status",
"conversationBotTextAdventureZone_title": "Text Adventure",
"conversationBotTextAdventureZone_instructionLabel": "Game Master Instructions",
"conversationBotTextAdventureZone_instructionPlaceholder": "Set game master instructions",
"conversationBotCustomZone_instructionSystemPromptEmptyError": "Missing game master instructions",
"studentAnalyticsNotAvailable": "Student data not currently available",
"roomDataMissing": "Some data may be missing from rooms in which you are not a member.",
"updatePhoneOS": "You may need to update your device's OS version.",

@ -106,6 +106,34 @@ class NewGroupController extends State<NewGroup> {
if (!mounted) return;
// #Pangea
// validate init bot options
final addBot = addConversationBotKey.currentState?.addBot ?? false;
if (addBot) {
final botOptions = addConversationBotKey.currentState!.botOptions;
if (botOptions.mode == "custom") {
if (botOptions.customSystemPrompt == null ||
botOptions.customSystemPrompt!.isEmpty) {
setState(() {
error = L10n.of(context)!
.conversationBotCustomZone_customSystemPromptEmptyError;
loading = false;
});
return;
}
} else if (botOptions.mode == "text_adventure") {
if (botOptions.textAdventureGameMasterInstructions == null ||
botOptions.textAdventureGameMasterInstructions!.isEmpty) {
setState(() {
error = L10n.of(context)!
.conversationBotCustomZone_instructionSystemPromptEmptyError;
loading = false;
});
return;
}
}
}
final roomId = await client.createGroupChat(
// #Pangea
// visibility:

@ -114,6 +114,9 @@ class ModelKey {
"custom_trigger_reaction_enabled";
static const String customTriggerReactionKey = "custom_trigger_reaction_key";
static const String textAdventureGameMasterInstructions =
"text_adventure_game_master_instructions";
static const String prevEventId = "prev_event_id";
static const String prevLastUpdated = "prev_last_updated";
}

@ -20,6 +20,7 @@ class BotOptionsModel {
String? customSystemPrompt;
bool? customTriggerReactionEnabled;
String? customTriggerReactionKey;
String? textAdventureGameMasterInstructions;
BotOptionsModel({
////////////////////////////////////////////////////////////////////////////
@ -45,6 +46,11 @@ class BotOptionsModel {
this.customSystemPrompt,
this.customTriggerReactionEnabled = true,
this.customTriggerReactionKey = "",
////////////////////////////////////////////////////////////////////////////
// Text Adventure Mode Options
////////////////////////////////////////////////////////////////////////////
this.textAdventureGameMasterInstructions,
});
factory BotOptionsModel.fromJson(json) {
@ -73,6 +79,12 @@ class BotOptionsModel {
customTriggerReactionEnabled:
json[ModelKey.customTriggerReactionEnabled] ?? true,
customTriggerReactionKey: json[ModelKey.customTriggerReactionKey] ?? "",
//////////////////////////////////////////////////////////////////////////
// Text Adventure Mode Options
//////////////////////////////////////////////////////////////////////////
textAdventureGameMasterInstructions:
json[ModelKey.textAdventureGameMasterInstructions],
);
}
@ -93,6 +105,8 @@ class BotOptionsModel {
data[ModelKey.customTriggerReactionEnabled] =
customTriggerReactionEnabled ?? true;
data[ModelKey.customTriggerReactionKey] = customTriggerReactionKey ?? "";
data[ModelKey.textAdventureGameMasterInstructions] =
textAdventureGameMasterInstructions;
return data;
} catch (e, s) {
debugger(when: kDebugMode);
@ -134,6 +148,9 @@ class BotOptionsModel {
case ModelKey.customTriggerReactionKey:
customTriggerReactionKey = value;
break;
case ModelKey.textAdventureGameMasterInstructions:
textAdventureGameMasterInstructions = value;
break;
default:
throw Exception('Invalid key for bot options - $key');
}

@ -20,6 +20,9 @@ class ConversationBotCustomSystemPromptInput extends StatelessWidget {
final TextEditingController textFieldController =
TextEditingController(text: customSystemPrompt);
final GlobalKey<FormState> customSystemPromptFormKey =
GlobalKey<FormState>();
void setBotCustomSystemPromptAction() async {
showDialog(
context: context,
@ -28,14 +31,25 @@ class ConversationBotCustomSystemPromptInput extends StatelessWidget {
title: Text(
L10n.of(context)!.conversationBotCustomZone_customSystemPromptLabel,
),
content: TextField(
minLines: 1,
maxLines: 10,
maxLength: 1000,
controller: textFieldController,
onChanged: (value) {
customSystemPrompt = value;
},
content: Form(
key: customSystemPromptFormKey,
child: TextFormField(
minLines: 1,
maxLines: 10,
maxLength: 1000,
controller: textFieldController,
onChanged: (value) {
if (value.isNotEmpty) {
customSystemPrompt = value;
}
},
validator: (value) {
if (value == null || value.isEmpty) {
return 'This field cannot be empty';
}
return null;
},
),
),
actions: [
TextButton(
@ -47,11 +61,12 @@ class ConversationBotCustomSystemPromptInput extends StatelessWidget {
TextButton(
child: Text(L10n.of(context)!.ok),
onPressed: () {
if (customSystemPrompt == "") return;
if (customSystemPrompt !=
initialBotOptions.customSystemPrompt) {
initialBotOptions.customSystemPrompt = customSystemPrompt;
onChanged.call(initialBotOptions);
if (customSystemPromptFormKey.currentState!.validate()) {
if (customSystemPrompt !=
initialBotOptions.customSystemPrompt) {
initialBotOptions.customSystemPrompt = customSystemPrompt;
onChanged.call(initialBotOptions);
}
Navigator.of(context).pop();
}
},
@ -68,6 +83,13 @@ class ConversationBotCustomSystemPromptInput extends StatelessWidget {
L10n.of(context)!
.conversationBotCustomZone_customSystemPromptPlaceholder,
),
subtitle: customSystemPrompt.isEmpty
? Text(
L10n.of(context)!
.conversationBotCustomZone_customSystemPromptEmptyError,
style: const TextStyle(color: Colors.red),
)
: null,
);
}
}

@ -16,7 +16,6 @@ class ConversationBotCustomZone extends StatelessWidget {
@override
Widget build(BuildContext context) {
print(initialBotOptions.toJson());
return Column(
children: [
const SizedBox(height: 12),

@ -1,5 +1,6 @@
import 'package:fluffychat/pangea/models/bot_options_model.dart';
import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_custom_zone.dart';
import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_text_adventure_zone.dart';
import 'package:flutter/material.dart';
import 'conversation_bot_discussion_zone.dart';
@ -26,7 +27,10 @@ class ConversationBotModeDynamicZone extends StatelessWidget {
onChanged: onChanged,
),
// "conversation": const ConversationBotConversationZone(),
// "text_adventure": const ConversationBotTextAdventureZone(),
"text_adventure": ConversationBotTextAdventureZone(
initialBotOptions: initialBotOptions,
onChanged: onChanged,
),
};
return Container(
decoration: BoxDecoration(

@ -19,8 +19,8 @@ class ConversationBotModeSelect extends StatelessWidget {
"custom": L10n.of(context)!.conversationBotModeSelectOption_custom,
// "conversation":
// L10n.of(context)!.conversationBotModeSelectOption_conversation,
// "text_adventure":
// L10n.of(context)!.conversationBotModeSelectOption_textAdventure,
"text_adventure":
L10n.of(context)!.conversationBotModeSelectOption_textAdventure,
};
return Padding(

@ -0,0 +1,91 @@
import 'package:fluffychat/pangea/models/bot_options_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
class ConversationBotGameMasterInstructionsInput extends StatelessWidget {
final BotOptionsModel initialBotOptions;
// call this to update propagate changes to parents
final void Function(BotOptionsModel) onChanged;
const ConversationBotGameMasterInstructionsInput({
super.key,
required this.initialBotOptions,
required this.onChanged,
});
@override
Widget build(BuildContext context) {
String gameMasterInstructions =
initialBotOptions.textAdventureGameMasterInstructions ?? "";
final TextEditingController textFieldController =
TextEditingController(text: gameMasterInstructions);
final GlobalKey<FormState> gameMasterInstructionsFormKey =
GlobalKey<FormState>();
void setBotTextAdventureGameMasterInstructionsAction() async {
showDialog(
context: context,
useRootNavigator: false,
builder: (BuildContext context) => AlertDialog(
title: Text(
L10n.of(context)!
.conversationBotTextAdventureZone_instructionPlaceholder,
),
content: Form(
key: gameMasterInstructionsFormKey,
child: TextFormField(
minLines: 1,
maxLines: 10,
maxLength: 1000,
controller: textFieldController,
onChanged: (value) {
if (value.isNotEmpty) {
gameMasterInstructions = value;
}
},
validator: (value) {
if (value == null || value.isEmpty) {
return 'This field cannot be empty';
}
return null;
},
),
),
actions: [
TextButton(
child: Text(L10n.of(context)!.cancel),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: Text(L10n.of(context)!.ok),
onPressed: () {
if (gameMasterInstructionsFormKey.currentState!.validate()) {
if (gameMasterInstructions !=
initialBotOptions.textAdventureGameMasterInstructions) {
initialBotOptions.textAdventureGameMasterInstructions =
gameMasterInstructions;
onChanged.call(initialBotOptions);
}
Navigator.of(context).pop();
}
},
),
],
),
);
}
return ListTile(
onTap: setBotTextAdventureGameMasterInstructionsAction,
title: Text(
initialBotOptions.textAdventureGameMasterInstructions ??
L10n.of(context)!
.conversationBotTextAdventureZone_instructionPlaceholder,
),
);
}
}

@ -1,15 +1,56 @@
import 'package:fluffychat/pangea/models/bot_options_model.dart';
import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_text_adventure_game_master_instruction_input.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
class ConversationBotTextAdventureZone extends StatelessWidget {
final BotOptionsModel initialBotOptions;
// call this to update propagate changes to parents
final void Function(BotOptionsModel) onChanged;
const ConversationBotTextAdventureZone({
super.key,
required this.initialBotOptions,
required this.onChanged,
});
@override
Widget build(BuildContext context) {
return const Column(
return Column(
children: [
Text('Text Adventure Zone'),
Text(
L10n.of(context)!.conversationBotTextAdventureZone_title,
style: TextStyle(
color: Theme.of(context).colorScheme.secondary,
fontWeight: FontWeight.bold,
),
),
const Divider(
color: Colors.grey,
thickness: 1,
),
const SizedBox(height: 12),
Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: const EdgeInsets.fromLTRB(12, 0, 0, 0),
child: Text(
L10n.of(context)!
.conversationBotTextAdventureZone_instructionLabel,
style: TextStyle(
color: Theme.of(context).colorScheme.secondary,
fontWeight: FontWeight.bold,
),
),
),
),
Padding(
padding: const EdgeInsets.all(8),
child: ConversationBotGameMasterInstructionsInput(
initialBotOptions: initialBotOptions,
onChanged: onChanged,
),
),
],
);
}

Loading…
Cancel
Save