"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:
OkaykOrhmn 2024-11-17 10:48:55 +03:30
parent a2c0c97337
commit dfd57937fb
8 changed files with 277 additions and 76 deletions

View File

@ -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;

View File

@ -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});
}

View File

@ -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.

View File

@ -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 = '';

View File

@ -227,14 +227,14 @@ class _BotAssistantsPageState extends State<BotAssistantsPage> {
const SizedBox(
height: 8,
),
DidvanText(
assistants.description ??
'dsadsadsadadsadaddadadadsdadsad dsadsadsadadsadaddadadadsdadsad dsadsadsadadsadaddadadadsdadsaddsadsadsadadsadaddadadadsdadsad vdsadsadsadadsadaddadadadsdadsaddsadsadsadadsadaddadadadsdadsaddsadsadsadadsadaddadadadsdadsaddsadsadsadadsadaddadadadsdadsaddsadsadsadadsadaddadadadsdadsaddsadsadsadadsadaddadadadsdadsaddsadsadsadadsadaddadadadsdadsad',
fontSize: 12,
color: Theme.of(context).colorScheme.disabledText,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
if (assistants.description != null)
DidvanText(
assistants.description!,
fontSize: 12,
color: Theme.of(context).colorScheme.disabledText,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
const SizedBox(
height: 18,
),

View File

@ -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) {
assistant = state.assistant;
if (assistant != null) {
if (assistant == null && state.assistant != null) {
assistant = state.assistant;
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(
DidvanIcons.info_circle_light,
color: Theme.of(context).colorScheme.caption,
),
state.loadingName
? const SizedBox(
width: 18,
height: 18,
child: CircularProgressIndicator())
: Icon(
DidvanIcons.info_circle_light,
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,45 +458,152 @@ class _CreateBotAssistantsPageState extends State<CreateBotAssistantsPage> {
Column(
children: [
title(text: 'پایگاه دانش', isRequired: false),
SizedBox(
height: 48,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context)
.colorScheme
.disabledBackground,
shape: const RoundedRectangleBorder(
borderRadius:
DesignConfig.lowBorderRadius)),
onPressed: () async {
final picks =
await MediaService.pickMultiFile();
if (picks != null) {
files.addAll(picks.xFiles);
}
if (files.length != 3)
SizedBox(
height: 48,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context)
.colorScheme
.disabledBackground,
shape: const RoundedRectangleBorder(
borderRadius: DesignConfig
.lowBorderRadius)),
onPressed: () async {
final picks =
await MediaService.pickMultiFile();
if (picks != null) {
for (var file in picks.xFiles) {
files.add(FileCreateAssistantsModel(
fromNetwork: false,
file: file,
url: null));
}
}
state.update();
},
child: Row(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Icon(
CupertinoIcons.add,
color: Theme.of(context)
.colorScheme
.caption,
),
const SizedBox(
width: 4,
),
DidvanText(
'آپلود فایل (فایل صوتی، پی دی اف)',
color: Theme.of(context)
.colorScheme
.caption,
fontSize: 16,
)
],
)),
),
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,
),
),
))
],
);
},
child: Row(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Icon(
CupertinoIcons.add,
color: Theme.of(context)
.colorScheme
.caption,
),
const SizedBox(
width: 4,
),
DidvanText(
'آپلود فایل (فایل صوتی، پی دی اف)',
color: Theme.of(context)
.colorScheme
.caption,
fontSize: 16,
)
],
)),
)
],
),
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);
},
));

View File

@ -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();
}
}

View File

@ -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),