"Updated BotAssistantsReqModel to include description, modified file picker to allow any file type, added description field to CreateBotAssistantsPage, and made various other UI and logic changes."
This commit is contained in:
parent
a2c0c97337
commit
dfd57937fb
|
|
@ -4,6 +4,7 @@ class BotAssistantsReqModel {
|
|||
final String type;
|
||||
final XFile? image;
|
||||
final String name;
|
||||
final String description;
|
||||
final int botId;
|
||||
final String prompt;
|
||||
final List<XFile>? files;
|
||||
|
|
@ -16,6 +17,7 @@ class BotAssistantsReqModel {
|
|||
required this.name,
|
||||
required this.botId,
|
||||
required this.prompt,
|
||||
required this.description,
|
||||
this.image,
|
||||
this.files,
|
||||
this.youtubeLink,
|
||||
|
|
@ -28,6 +30,7 @@ class BotAssistantsReqModel {
|
|||
data['name'] = name;
|
||||
data['botId'] = botId;
|
||||
data['prompt'] = prompt;
|
||||
data['description'] = description;
|
||||
data['isPrivate'] = isPrivate;
|
||||
if (youtubeLink != null) {
|
||||
data['youtubeLink'] = youtubeLink;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
import 'package:image_picker/image_picker.dart';
|
||||
|
||||
class FileCreateAssistantsModel {
|
||||
final bool fromNetwork;
|
||||
final XFile? file;
|
||||
final String? url;
|
||||
|
||||
FileCreateAssistantsModel(
|
||||
{required this.fromNetwork, required this.file, required this.url});
|
||||
}
|
||||
|
|
@ -141,22 +141,22 @@ class MediaService {
|
|||
try {
|
||||
return await FilePicker.platform
|
||||
.pickFiles(
|
||||
type: FileType.custom,
|
||||
allowedExtensions: [
|
||||
'pdf',
|
||||
'doc',
|
||||
'docx',
|
||||
'xls',
|
||||
'xlsx',
|
||||
'ppt',
|
||||
'pptx',
|
||||
'txt',
|
||||
'mp3',
|
||||
'wav',
|
||||
'aac',
|
||||
'ogg',
|
||||
'flac'
|
||||
], // You can specify allowed extensions if needed
|
||||
type: FileType.any,
|
||||
// allowedExtensions: [
|
||||
// 'pdf',
|
||||
// 'doc',
|
||||
// 'docx',
|
||||
// 'xls',
|
||||
// 'xlsx',
|
||||
// 'ppt',
|
||||
// 'pptx',
|
||||
// 'txt',
|
||||
// 'mp3',
|
||||
// 'wav',
|
||||
// 'aac',
|
||||
// 'ogg',
|
||||
// 'flac'
|
||||
// ], // You can specify allowed extensions if needed
|
||||
allowMultiple: true,
|
||||
// Note: The maxFiles parameter is not directly supported by FilePicker.
|
||||
// You will need to handle the limit after selection if necessary.
|
||||
|
|
|
|||
|
|
@ -238,6 +238,7 @@ class RequestHelper {
|
|||
static String updateAssistants(int id) => '$baseUrl/ai/bot/$id';
|
||||
static String getAssistant(int id) => '$baseUrl/ai/bot/user/$id';
|
||||
static String deleteAssistant(int id) => '$baseUrl/ai/bot/user/$id';
|
||||
static String nameOfAssistant() => '$baseUrl/ai/bot/name';
|
||||
|
||||
static String _urlConcatGenerator(List<MapEntry<String, dynamic>> additions) {
|
||||
String result = '';
|
||||
|
|
|
|||
|
|
@ -227,9 +227,9 @@ class _BotAssistantsPageState extends State<BotAssistantsPage> {
|
|||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
if (assistants.description != null)
|
||||
DidvanText(
|
||||
assistants.description ??
|
||||
'dsadsadsadadsadaddadadadsdadsad dsadsadsadadsadaddadadadsdadsad dsadsadsadadsadaddadadadsdadsaddsadsadsadadsadaddadadadsdadsad vdsadsadsadadsadaddadadadsdadsaddsadsadsadadsadaddadadadsdadsaddsadsadsadadsadaddadadadsdadsaddsadsadsadadsadaddadadadsdadsaddsadsadsadadsadaddadadadsdadsaddsadsadsadadsadaddadadadsdadsaddsadsadsadadsadaddadadadsdadsad',
|
||||
assistants.description!,
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).colorScheme.disabledText,
|
||||
maxLines: 2,
|
||||
|
|
|
|||
|
|
@ -1,18 +1,22 @@
|
|||
// ignore_for_file: deprecated_member_use
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:animated_custom_dropdown/custom_dropdown.dart';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:didvan/config/design_config.dart';
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/constants/app_icons.dart';
|
||||
import 'package:didvan/models/ai/bot_assistants_model.dart';
|
||||
import 'package:didvan/models/ai/bot_assistants_req_model.dart';
|
||||
import 'package:didvan/models/ai/bots_model.dart';
|
||||
import 'package:didvan/models/ai/file_create_assistants_model.dart';
|
||||
import 'package:didvan/models/enums.dart';
|
||||
import 'package:didvan/models/view/action_sheet_data.dart';
|
||||
import 'package:didvan/services/media/media.dart';
|
||||
import 'package:didvan/utils/action_sheet.dart';
|
||||
import 'package:didvan/utils/extension.dart';
|
||||
import 'package:didvan/views/ai/bot_assistants_state.dart';
|
||||
import 'package:didvan/views/ai/create_bot_assistants_state.dart';
|
||||
import 'package:didvan/views/ai/history_ai_chat_state.dart';
|
||||
|
|
@ -22,6 +26,7 @@ import 'package:didvan/views/widgets/didvan/switch.dart';
|
|||
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||
import 'package:didvan/views/widgets/didvan/text_field.dart';
|
||||
import 'package:didvan/views/widgets/hoshan_app_bar.dart';
|
||||
import 'package:didvan/views/widgets/marquee_text.dart';
|
||||
import 'package:didvan/views/widgets/shimmer_placeholder.dart';
|
||||
import 'package:didvan/views/widgets/skeleton_image.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
|
@ -59,12 +64,13 @@ class _CreateBotAssistantsPageState extends State<CreateBotAssistantsPage> {
|
|||
// String? youtubeLink;
|
||||
|
||||
List<String> countOfLink = [''];
|
||||
List<XFile> files = [];
|
||||
List<FileCreateAssistantsModel> files = [];
|
||||
ValueNotifier<XFile?> image = ValueNotifier(null);
|
||||
String selectedBotType = 'text';
|
||||
bool isPrivate = true;
|
||||
BotAssistants? assistant;
|
||||
BotsModel? initialBot;
|
||||
Timer? _timer;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
|
@ -92,20 +98,28 @@ class _CreateBotAssistantsPageState extends State<CreateBotAssistantsPage> {
|
|||
if (!isValid) {
|
||||
return;
|
||||
}
|
||||
final List<XFile> resultFiles = [];
|
||||
for (var file in files) {
|
||||
if (!file.fromNetwork) {
|
||||
resultFiles.add(file.file!);
|
||||
}
|
||||
}
|
||||
await state.createAssistants(
|
||||
id: widget.id,
|
||||
data: BotAssistantsReqModel(
|
||||
type: selectedBotType,
|
||||
name: name,
|
||||
description: desc,
|
||||
botId: selectedBotId,
|
||||
prompt: prompt,
|
||||
webLinks: countOfLink.first.isEmpty ? null : countOfLink,
|
||||
// youtubeLink: youtubeLink,
|
||||
isPrivate: isPrivate,
|
||||
files: files,
|
||||
files: resultFiles,
|
||||
image: image.value));
|
||||
|
||||
context.read<BotAssistantsState>().getMyAssissmant();
|
||||
context.read<CreateBotAssistantsState>().assistant = null;
|
||||
Navigator.pop(context);
|
||||
}
|
||||
|
||||
|
|
@ -123,22 +137,28 @@ class _CreateBotAssistantsPageState extends State<CreateBotAssistantsPage> {
|
|||
},
|
||||
child: Scaffold(
|
||||
appBar: HoshanAppBar(
|
||||
onBack: () => Navigator.pop(context),
|
||||
onBack: () {
|
||||
context.read<CreateBotAssistantsState>().assistant = null;
|
||||
Navigator.pop(context);
|
||||
},
|
||||
withActions: false,
|
||||
),
|
||||
body: Consumer<CreateBotAssistantsState>(builder: (BuildContext context,
|
||||
CreateBotAssistantsState state, Widget? child) {
|
||||
if (assistant == null && state.assistant != null) {
|
||||
assistant = state.assistant;
|
||||
if (assistant != null) {
|
||||
|
||||
name = assistant!.name ?? '';
|
||||
prompt = assistant!.prompt ?? '';
|
||||
desc = assistant!.description ?? '';
|
||||
// youtubeLink = assistant!.;
|
||||
isPrivate = assistant!.private ?? true;
|
||||
if (assistant!.files != null && assistant!.files!.isNotEmpty) {
|
||||
if (files.isEmpty &&
|
||||
assistant!.files != null &&
|
||||
assistant!.files!.isNotEmpty) {
|
||||
for (var file in assistant!.files!) {
|
||||
final data = File.fromUri(Uri.parse(file)).readAsBytesSync();
|
||||
files.add(XFile.fromData(data));
|
||||
files.add(FileCreateAssistantsModel(
|
||||
fromNetwork: true, file: null, url: file));
|
||||
}
|
||||
}
|
||||
countOfLink = assistant!.websites ?? [''];
|
||||
|
|
@ -262,6 +282,16 @@ class _CreateBotAssistantsPageState extends State<CreateBotAssistantsPage> {
|
|||
initialValue: name,
|
||||
onChanged: (value) {
|
||||
name = value;
|
||||
|
||||
if (value.isEmpty) {
|
||||
return;
|
||||
}
|
||||
_timer?.cancel();
|
||||
_timer =
|
||||
Timer(const Duration(seconds: 1), () async {
|
||||
await state.getAssistantsName(name: value);
|
||||
_formNameKey.currentState!.validate();
|
||||
});
|
||||
},
|
||||
validator: (value) {
|
||||
String? result;
|
||||
|
|
@ -269,6 +299,9 @@ class _CreateBotAssistantsPageState extends State<CreateBotAssistantsPage> {
|
|||
result = 'نام نباید خالی باشد';
|
||||
} else if (value.length < 4) {
|
||||
result = 'نام نباید کمتر از 4 حرف باشد';
|
||||
} else if (!state.successName) {
|
||||
result =
|
||||
'اسم دیگری انتخاب کنید این اسم موجود است';
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
|
@ -279,17 +312,26 @@ class _CreateBotAssistantsPageState extends State<CreateBotAssistantsPage> {
|
|||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(
|
||||
state.loadingName
|
||||
? const SizedBox(
|
||||
width: 18,
|
||||
height: 18,
|
||||
child: CircularProgressIndicator())
|
||||
: Icon(
|
||||
DidvanIcons.info_circle_light,
|
||||
color: Theme.of(context).colorScheme.caption,
|
||||
color:
|
||||
Theme.of(context).colorScheme.caption,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Expanded(
|
||||
child: DidvanText(
|
||||
'نام منحصر به فرد شامل 4 تا 20 کاراکتر (حروف، اعداد، خط تیره، نقطه و زیرخط) ',
|
||||
state.loadingName
|
||||
? '...درحال بررسی اسم'
|
||||
: 'نام منحصر به فرد شامل 4 تا 20 کاراکتر (حروف، اعداد، خط تیره، نقطه و زیرخط) ',
|
||||
textAlign: TextAlign.right,
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).colorScheme.caption,
|
||||
|
|
@ -416,6 +458,7 @@ class _CreateBotAssistantsPageState extends State<CreateBotAssistantsPage> {
|
|||
Column(
|
||||
children: [
|
||||
title(text: 'پایگاه دانش', isRequired: false),
|
||||
if (files.length != 3)
|
||||
SizedBox(
|
||||
height: 48,
|
||||
child: ElevatedButton(
|
||||
|
|
@ -424,14 +467,20 @@ class _CreateBotAssistantsPageState extends State<CreateBotAssistantsPage> {
|
|||
.colorScheme
|
||||
.disabledBackground,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
DesignConfig.lowBorderRadius)),
|
||||
borderRadius: DesignConfig
|
||||
.lowBorderRadius)),
|
||||
onPressed: () async {
|
||||
final picks =
|
||||
await MediaService.pickMultiFile();
|
||||
if (picks != null) {
|
||||
files.addAll(picks.xFiles);
|
||||
for (var file in picks.xFiles) {
|
||||
files.add(FileCreateAssistantsModel(
|
||||
fromNetwork: false,
|
||||
file: file,
|
||||
url: null));
|
||||
}
|
||||
}
|
||||
state.update();
|
||||
},
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
|
|
@ -456,6 +505,106 @@ class _CreateBotAssistantsPageState extends State<CreateBotAssistantsPage> {
|
|||
],
|
||||
)),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
...List.generate(
|
||||
files.length,
|
||||
(index) {
|
||||
return Stack(
|
||||
children: [
|
||||
Container(
|
||||
width: MediaQuery.sizeOf(context)
|
||||
.width /
|
||||
5,
|
||||
height: MediaQuery.sizeOf(context)
|
||||
.width /
|
||||
5,
|
||||
margin:
|
||||
const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 12),
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.disabledBackground,
|
||||
borderRadius: DesignConfig
|
||||
.lowBorderRadius),
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: files[index]
|
||||
.fromNetwork
|
||||
? files[index]
|
||||
.url!
|
||||
.isImage()
|
||||
? CachedNetworkImage(
|
||||
imageUrl:
|
||||
files[index]
|
||||
.url!)
|
||||
: const Icon(
|
||||
CupertinoIcons
|
||||
.doc)
|
||||
: files[index]
|
||||
.file!
|
||||
.path
|
||||
.isImage()
|
||||
? Image.file(File(
|
||||
files[index]
|
||||
.file!
|
||||
.path))
|
||||
: const Icon(
|
||||
CupertinoIcons
|
||||
.doc),
|
||||
),
|
||||
MarqueeText(
|
||||
text: files[index]
|
||||
.fromNetwork
|
||||
? files[index]
|
||||
.url!
|
||||
.split('/')
|
||||
.last
|
||||
: files[index]
|
||||
.file!
|
||||
.name,
|
||||
textDirection:
|
||||
TextDirection.rtl,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.labelSmall!)
|
||||
],
|
||||
)),
|
||||
Positioned(
|
||||
top: 8,
|
||||
left: 4,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
files.removeAt(index);
|
||||
state.update();
|
||||
},
|
||||
child: Container(
|
||||
padding:
|
||||
const EdgeInsets.all(6),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.error),
|
||||
child: const Icon(
|
||||
DidvanIcons.trash_solid,
|
||||
color: Colors.white,
|
||||
size: 18,
|
||||
),
|
||||
),
|
||||
))
|
||||
],
|
||||
);
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
|
|
@ -648,6 +797,10 @@ class _CreateBotAssistantsPageState extends State<CreateBotAssistantsPage> {
|
|||
onConfirmed: () async {
|
||||
await state.deleteAssistants(
|
||||
id: widget.id!);
|
||||
context
|
||||
.read<
|
||||
CreateBotAssistantsState>()
|
||||
.assistant = null;
|
||||
Navigator.pop(context);
|
||||
},
|
||||
));
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ class CreateBotAssistantsState extends CoreProvier {
|
|||
List<BotsModel> imageBots = [];
|
||||
bool loadingImageBots = false;
|
||||
bool loadingCreate = false;
|
||||
bool loadingName = false;
|
||||
bool successName = false;
|
||||
bool loading = false;
|
||||
BotAssistants? assistant;
|
||||
|
||||
|
|
@ -100,4 +102,30 @@ class CreateBotAssistantsState extends CoreProvier {
|
|||
loadingCreate = false;
|
||||
update();
|
||||
}
|
||||
|
||||
Future getAssistantsName({required final String name}) async {
|
||||
loadingName = true;
|
||||
update();
|
||||
|
||||
final service =
|
||||
RequestService(RequestHelper.nameOfAssistant(), body: {'name': name});
|
||||
await service.post();
|
||||
if (service.isSuccess) {
|
||||
appState = AppState.idle;
|
||||
loadingName = false;
|
||||
if (service.result['available'] as bool) {
|
||||
successName = true;
|
||||
} else {
|
||||
successName = false;
|
||||
}
|
||||
|
||||
update();
|
||||
return;
|
||||
}
|
||||
appState = AppState.failed;
|
||||
loadingName = false;
|
||||
successName = false;
|
||||
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:didvan/config/design_config.dart';
|
||||
import 'package:didvan/constants/app_icons.dart';
|
||||
import 'package:didvan/routes/routes.dart';
|
||||
import 'package:didvan/views/widgets/didvan/divider.dart';
|
||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||
import 'package:didvan/views/widgets/hoshan_app_bar.dart';
|
||||
|
|
@ -205,7 +206,12 @@ class _InfoPageState extends State<InfoPage> {
|
|||
),
|
||||
const DidvanText('هنوز سوالی دارید؟'),
|
||||
TextButton(
|
||||
onPressed: () {},
|
||||
onPressed: () {
|
||||
Navigator.of(context).pushNamed(
|
||||
Routes.direct,
|
||||
arguments: {'type': 'پشتیبانی اپلیکیشن'},
|
||||
);
|
||||
},
|
||||
child: const DidvanText(
|
||||
' پیام به پشتیبانی',
|
||||
color: Color(0xff007EA7),
|
||||
|
|
|
|||
Loading…
Reference in New Issue