add create group chat validation for custom and game master instructions
This commit is contained in:
parent
0201aae916
commit
bd4d9e43ed
10 changed files with 229 additions and 19 deletions
|
|
@ -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…
Add table
Reference in a new issue