Merge pull request #608 from siddu015/main

Add ChatBot for API Assistance
This commit is contained in:
Ashita Prasad
2025-03-07 06:38:38 +05:30
committed by GitHub
12 changed files with 656 additions and 49 deletions

1
lib/dashbot/dashbot.dart Normal file
View File

@ -0,0 +1 @@
export 'widgets/dashbot_widget.dart';

View File

@ -0,0 +1,63 @@
import 'dart:convert';
import '../services/dashbot_service.dart';
import 'package:apidash/models/request_model.dart';
class DebugFeature {
final DashBotService _service;
DebugFeature(this._service);
Future<String> debugApi({
required RequestModel? requestModel,
required dynamic responseModel,
}) async {
if (requestModel == null || responseModel == null) {
return "No recent API requests found.";
}
final method = requestModel.httpRequestModel?.method
.toString()
.split('.')
.last
.toUpperCase() ??
"GET";
final endpoint = requestModel.httpRequestModel?.url ?? "Unknown Endpoint";
final headers = requestModel.httpRequestModel?.enabledHeadersMap ?? {};
final parameters = requestModel.httpRequestModel?.enabledParamsMap ?? {};
final body = requestModel.httpRequestModel?.body;
final rawResponse = responseModel.body;
final responseBody =
rawResponse is String ? rawResponse : jsonEncode(rawResponse);
final statusCode = responseModel.statusCode ?? 0;
final prompt = '''
URGENT API DEBUG ANALYSIS
**Request Overview:**
- Endpoint: $endpoint
- Method: $method
- Status Code: $statusCode
**Debugging Instructions:**
Provide a PRECISE, TEXT-ONLY explanation that:
1. Identifies the EXACT problem
2. Explains WHY the request failed
3. Describes SPECIFIC steps to resolve the issue
4. NO CODE SNIPPETS ALLOWED
**Request Details:**
- Headers: ${headers.isNotEmpty ? jsonEncode(headers) : "No headers"}
- Parameters: ${parameters.isNotEmpty ? jsonEncode(parameters) : "No parameters"}
- Request Body: ${body ?? "Empty body"}
**Response Context:**
\`\`\`
$responseBody
\`\`\`
Provide a CLEAR, ACTIONABLE solution in the SIMPLEST possible language.
''';
return _service.generateResponse(prompt);
}
}

View File

@ -0,0 +1,68 @@
import 'dart:convert';
import '../services/dashbot_service.dart';
import 'package:apidash/models/request_model.dart';
class ExplainFeature {
final DashBotService _service;
ExplainFeature(this._service);
Future<String> explainLatestApi({
required RequestModel? requestModel,
required dynamic responseModel,
}) async {
if (requestModel == null || responseModel == null) {
return "No recent API requests found.";
}
if (requestModel.httpRequestModel?.url == null) {
return "Error: Invalid API request (missing endpoint).";
}
final method = requestModel.httpRequestModel?.method
.toString()
.split('.')
.last
.toUpperCase() ??
"GET";
final endpoint = requestModel.httpRequestModel!.url!;
final headers = requestModel.httpRequestModel?.enabledHeadersMap ?? {};
final parameters = requestModel.httpRequestModel?.enabledParamsMap ?? {};
final body = requestModel.httpRequestModel?.body;
final rawResponse = responseModel.body;
final responseBody =
rawResponse is String ? rawResponse : jsonEncode(rawResponse);
final statusCode = responseModel.statusCode ?? 0;
final prompt = '''
FOCUSED API INTERACTION BREAKDOWN
**Essential Request Details:**
- Endpoint Purpose: What is this API endpoint designed to do?
- Interaction Type: Describe the core purpose of this specific request
**Request Mechanics:**
- Exact Endpoint: $endpoint
- HTTP Method: $method
- Key Parameters: ${parameters.isNotEmpty ? 'Specific inputs driving the request' : 'No custom parameters'}
**Response CORE Insights:**
- Status: Success or Failure?
- Key Data Extracted: What CRITICAL information does the response contain?
**Precise Analysis Requirements:**
1. Explain the API's PRIMARY function in ONE clear sentence
2. Identify the MOST IMPORTANT piece of information returned
3. Describe the PRACTICAL significance of this API call
AVOID:
- Technical jargon
- Unnecessary details
- Verbose explanations
Deliver a CRYSTAL CLEAR, CONCISE explanation that anyone can understand.
''';
return _service.generateResponse(prompt);
}
}

View File

@ -0,0 +1,44 @@
import 'dart:convert';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../services/dashbot_service.dart';
final chatMessagesProvider =
StateNotifierProvider<ChatMessagesNotifier, List<Map<String, dynamic>>>(
(ref) => ChatMessagesNotifier(),
);
final dashBotServiceProvider = Provider<DashBotService>((ref) {
return DashBotService();
});
class ChatMessagesNotifier extends StateNotifier<List<Map<String, dynamic>>> {
ChatMessagesNotifier() : super([]) {
_loadMessages();
}
static const _storageKey = 'chatMessages';
Future<void> _loadMessages() async {
final prefs = await SharedPreferences.getInstance();
final messages = prefs.getString(_storageKey);
if (messages != null) {
state = List<Map<String, dynamic>>.from(json.decode(messages));
}
}
Future<void> _saveMessages() async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString(_storageKey, json.encode(state));
}
void addMessage(Map<String, dynamic> message) {
state = [...state, message];
_saveMessages();
}
void clearMessages() {
state = [];
_saveMessages();
}
}

View File

@ -0,0 +1,36 @@
import 'package:apidash/dashbot/features/debug.dart';
import 'package:ollama_dart/ollama_dart.dart';
import '../features/explain.dart';
import 'package:apidash/models/request_model.dart';
class DashBotService {
final OllamaClient _client;
late final ExplainFeature _explainFeature;
late final DebugFeature _debugFeature;
DashBotService()
: _client = OllamaClient(baseUrl: 'http://127.0.0.1:11434/api') {
_explainFeature = ExplainFeature(this);
_debugFeature = DebugFeature(this);
}
Future<String> generateResponse(String prompt) async {
final response = await _client.generateCompletion(
request: GenerateCompletionRequest(model: 'llama3.2:3b', prompt: prompt),
);
return response.response.toString();
}
Future<String> handleRequest(
String input, RequestModel? requestModel, dynamic responseModel) async {
if (input == "Explain API") {
return _explainFeature.explainLatestApi(
requestModel: requestModel, responseModel: responseModel);
} else if (input == "Debug API") {
return _debugFeature.debugApi(
requestModel: requestModel, responseModel: responseModel);
}
return generateResponse(input);
}
}

View File

@ -0,0 +1,50 @@
// lib/dashbot/widgets/chat_bubble.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'content_renderer.dart';
class ChatBubble extends StatelessWidget {
final String message;
final bool isUser;
const ChatBubble({super.key, required this.message, this.isUser = false});
@override
Widget build(BuildContext context) {
return Align(
alignment: isUser ? Alignment.centerRight : Alignment.centerLeft,
child: Container(
margin: const EdgeInsets.symmetric(vertical: 4, horizontal: 12),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: isUser
? Theme.of(context).colorScheme.primaryContainer
: Theme.of(context).colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(8),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: renderContent(context, message),
),
if (!isUser) ...[
const SizedBox(width: 8),
IconButton(
icon: const Icon(Icons.copy, size: 20),
tooltip: 'Copy Response',
onPressed: () {
Clipboard.setData(ClipboardData(text: message));
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Copied to clipboard')),
);
},
),
],
],
),
),
);
}
}

View File

@ -0,0 +1,100 @@
// lib/dashbot/widgets/content_renderer.dart
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_highlighter/flutter_highlighter.dart';
import 'package:flutter_highlighter/themes/monokai-sublime.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
Widget renderContent(BuildContext context, String text) {
if (text.isEmpty) {
return const Text("No content to display.");
}
final codeBlockPattern = RegExp(r'```(\w+)?\n([\s\S]*?)```', multiLine: true);
final matches = codeBlockPattern.allMatches(text);
if (matches.isEmpty) {
return _renderMarkdown(context, text);
}
List<Widget> children = [];
int lastEnd = 0;
for (var match in matches) {
if (match.start > lastEnd) {
children
.add(_renderMarkdown(context, text.substring(lastEnd, match.start)));
}
final language = match.group(1) ?? 'text';
final code = match.group(2)!.trim();
children.add(_renderCodeBlock(context, language, code));
lastEnd = match.end;
}
if (lastEnd < text.length) {
children.add(_renderMarkdown(context, text.substring(lastEnd)));
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: children,
);
}
Widget _renderMarkdown(BuildContext context, String markdown) {
return MarkdownBody(
data: markdown,
selectable: true,
styleSheet: MarkdownStyleSheet(
p: TextStyle(color: Theme.of(context).colorScheme.onSurface),
),
);
}
Widget _renderCodeBlock(BuildContext context, String language, String code) {
if (language == 'json') {
try {
final prettyJson =
const JsonEncoder.withIndent(' ').convert(jsonDecode(code));
return Container(
padding: const EdgeInsets.all(8),
color: Theme.of(context).colorScheme.surfaceContainerLow,
child: SelectableText(
prettyJson,
style: const TextStyle(fontFamily: 'monospace', fontSize: 12),
),
);
} catch (e) {
return _renderFallbackCode(context, code);
}
} else {
try {
return Container(
padding: const EdgeInsets.all(8),
color: Theme.of(context).colorScheme.surfaceContainerLow,
child: HighlightView(
code,
language: language,
theme: monokaiSublimeTheme,
textStyle: const TextStyle(fontFamily: 'monospace', fontSize: 12),
),
);
} catch (e) {
return _renderFallbackCode(context, code);
}
}
}
Widget _renderFallbackCode(BuildContext context, String code) {
return Container(
padding: const EdgeInsets.all(8),
color: Theme.of(context).colorScheme.surfaceContainerLow,
child: SelectableText(
code,
style: const TextStyle(
fontFamily: 'monospace', fontSize: 12, color: Colors.red),
),
);
}

View File

@ -0,0 +1,198 @@
// lib/dashbot/widgets/dashbot_widget.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:apidash/dashbot/providers/dashbot_providers.dart';
import 'package:apidash/providers/providers.dart';
import 'chat_bubble.dart';
class DashBotWidget extends ConsumerStatefulWidget {
const DashBotWidget({Key? key}) : super(key: key);
@override
_DashBotWidgetState createState() => _DashBotWidgetState();
}
class _DashBotWidgetState extends ConsumerState<DashBotWidget> {
final TextEditingController _controller = TextEditingController();
late ScrollController _scrollController;
bool _isLoading = false;
@override
void initState() {
super.initState();
_scrollController = ScrollController();
}
@override
void dispose() {
_scrollController.dispose();
_controller.dispose();
super.dispose();
}
Future<void> _sendMessage(String message) async {
if (message.trim().isEmpty) return;
final dashBotService = ref.read(dashBotServiceProvider);
final requestModel = ref.read(selectedRequestModelProvider);
final responseModel = requestModel?.httpResponseModel;
setState(() => _isLoading = true);
ref.read(chatMessagesProvider.notifier).addMessage({
'role': 'user',
'message': message,
});
try {
final response = await dashBotService.handleRequest(
message, requestModel, responseModel);
ref.read(chatMessagesProvider.notifier).addMessage({
'role': 'bot',
'message': response,
});
} catch (error, stackTrace) {
print('Error in _sendMessage: $error');
print('StackTrace: $stackTrace');
ref.read(chatMessagesProvider.notifier).addMessage({
'role': 'bot',
'message': "Error: ${error.toString()}",
});
} finally {
setState(() => _isLoading = false);
WidgetsBinding.instance.addPostFrameCallback((_) {
_scrollController.animateTo(
0,
duration: const Duration(milliseconds: 300),
curve: Curves.easeOut,
);
});
}
}
@override
Widget build(BuildContext context) {
final messages = ref.watch(chatMessagesProvider);
final requestModel = ref.read(selectedRequestModelProvider);
final statusCode = requestModel?.httpResponseModel?.statusCode;
final showDebugButton = statusCode != null && statusCode >= 400;
return Container(
height: 450,
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(12),
boxShadow: const [
BoxShadow(color: Colors.black12, blurRadius: 8, offset: Offset(0, 4))
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildHeader(context),
const SizedBox(height: 12),
_buildQuickActions(showDebugButton),
const SizedBox(height: 12),
Expanded(child: _buildChatArea(messages)),
if (_isLoading) _buildLoadingIndicator(),
const SizedBox(height: 10),
_buildInputArea(context),
],
),
);
}
Widget _buildHeader(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text('DashBot',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
IconButton(
icon: const Icon(Icons.delete_sweep),
tooltip: 'Clear Chat',
onPressed: () =>
ref.read(chatMessagesProvider.notifier).clearMessages(),
),
],
);
}
Widget _buildQuickActions(bool showDebugButton) {
return Wrap(
spacing: 8,
runSpacing: 8,
children: [
ElevatedButton.icon(
onPressed: () => _sendMessage("Explain API"),
icon: const Icon(Icons.info_outline),
label: const Text("Explain"),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
),
),
if (showDebugButton)
ElevatedButton.icon(
onPressed: () => _sendMessage("Debug API"),
icon: const Icon(Icons.bug_report_outlined),
label: const Text("Debug"),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
),
),
],
);
}
Widget _buildChatArea(List<Map<String, dynamic>> messages) {
return ListView.builder(
controller: _scrollController,
reverse: true,
itemCount: messages.length,
itemBuilder: (context, index) {
final message = messages.reversed.toList()[index];
return ChatBubble(
message: message['message'],
isUser: message['role'] == 'user',
);
},
);
}
Widget _buildLoadingIndicator() {
return const Padding(
padding: EdgeInsets.all(8.0),
child: LinearProgressIndicator(),
);
}
Widget _buildInputArea(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Theme.of(context).colorScheme.surfaceContainer,
),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
child: Row(
children: [
Expanded(
child: TextField(
controller: _controller,
decoration: const InputDecoration(
hintText: 'Ask DashBot...',
border: InputBorder.none,
),
onSubmitted: _sendMessage,
maxLines: 1,
),
),
IconButton(
icon: const Icon(Icons.send),
onPressed: () => _sendMessage(_controller.text),
),
],
),
);
}
}

View File

@ -4,6 +4,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:apidash/providers/providers.dart';
import 'package:apidash/widgets/widgets.dart';
import 'package:apidash/consts.dart';
import 'package:apidash/dashbot/dashbot.dart';
import 'common_widgets/common_widgets.dart';
import 'envvar/environment_page.dart';
import 'home_page/home_page.dart';
@ -124,6 +125,17 @@ class Dashboard extends ConsumerWidget {
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) => const Padding(
padding: EdgeInsets.all(16.0),
child: DashBotWidget(),
),
),
child: const Icon(Icons.help_outline),
),
);
}
}

View File

@ -54,6 +54,7 @@ class ResponseDetails extends ConsumerWidget {
.watch(selectedRequestModelProvider.select((value) => value?.message));
final responseModel = ref.watch(selectedRequestModelProvider
.select((value) => value?.httpResponseModel));
return Column(
children: [
ResponsePaneHeader(

View File

@ -51,10 +51,10 @@ packages:
dependency: transitive
description:
name: archive
sha256: "0c64e928dcbefddecd234205422bcfc2b5e6d31be0b86fef0d0dd48d7b4c9742"
sha256: "528579c7e4579719f04b21eeeeddfd73a18b31dabc22766893b7d1be7f49b967"
url: "https://pub.dev"
source: hosted
version: "4.0.4"
version: "4.0.3"
args:
dependency: transitive
description:
@ -83,10 +83,10 @@ packages:
dependency: transitive
description:
name: barcode
sha256: ab180ce22c6555d77d45f0178a523669db67f95856e3378259ef2ffeb43e6003
sha256: "7b6729c37e3b7f34233e2318d866e8c48ddb46c1f7ad01ff7bb2a8de1da2b9f4"
url: "https://pub.dev"
source: hosted
version: "2.2.8"
version: "2.2.9"
bidi:
dependency: transitive
description:
@ -123,18 +123,18 @@ packages:
dependency: transitive
description:
name: build_config
sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
version: "1.1.2"
build_daemon:
dependency: transitive
description:
name: build_daemon
sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
version: "4.0.4"
build_resolvers:
dependency: transitive
description:
@ -171,10 +171,10 @@ packages:
dependency: transitive
description:
name: built_value
sha256: "28a712df2576b63c6c005c465989a348604960c0958d28be5303ba9baa841ac2"
sha256: "8b158ab94ec6913e480dc3f752418348b5ae099eb75868b5f4775f0572999c61"
url: "https://pub.dev"
source: hosted
version: "8.9.3"
version: "8.9.4"
characters:
dependency: transitive
description:
@ -390,14 +390,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.2"
fetch_api:
dependency: transitive
description:
name: fetch_api
sha256: "97f46c25b480aad74f7cc2ad7ccba2c5c6f08d008e68f95c1077286ce243d0e6"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
fetch_client:
dependency: transitive
description:
name: fetch_client
sha256: "9666ee14536778474072245ed5cba07db81ae8eb5de3b7bf4a2d1e2c49696092"
url: "https://pub.dev"
source: hosted
version: "1.1.2"
ffi:
dependency: transitive
description:
name: ffi
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418"
url: "https://pub.dev"
source: hosted
version: "2.1.3"
version: "2.1.4"
file:
dependency: transitive
description:
@ -466,10 +482,10 @@ packages:
dependency: transitive
description:
name: file_selector_windows
sha256: "8f5d2f6590d51ecd9179ba39c64f722edc15226cc93dcc8698466ad36a4a85a4"
sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b"
url: "https://pub.dev"
source: hosted
version: "0.9.3+3"
version: "0.9.3+4"
fixnum:
dependency: transitive
description:
@ -504,6 +520,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_highlighter:
dependency: "direct main"
description:
name: flutter_highlighter
sha256: "93173afd47a9ada53f3176371755e7ea4a1065362763976d06d6adfb4d946e10"
url: "https://pub.dev"
source: hosted
version: "0.1.1"
flutter_hooks:
dependency: "direct main"
description:
@ -675,10 +699,10 @@ packages:
dependency: transitive
description:
name: glob
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.3"
google_fonts:
dependency: transitive
description:
@ -1065,6 +1089,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.2"
ollama_dart:
dependency: "direct main"
description:
name: ollama_dart
sha256: "4e40bc499b6fe46ba54a004d2da601c40bd73d66e3f18cf7b03225ccf3d481a6"
url: "https://pub.dev"
source: hosted
version: "0.2.2+1"
package_config:
dependency: transitive
description:
@ -1173,10 +1205,10 @@ packages:
dependency: transitive
description:
name: petitparser
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646"
url: "https://pub.dev"
source: hosted
version: "6.0.2"
version: "6.1.0"
platform:
dependency: transitive
description:
@ -1252,10 +1284,10 @@ packages:
dependency: "direct main"
description:
name: printing
sha256: b535d177fc6e8f8908e19b0ff5c1d4a87e3c4d0bf675e05aa2562af1b7853906
sha256: "482cd5a5196008f984bb43ed0e47cbfdca7373490b62f3b27b3299275bf22a93"
url: "https://pub.dev"
source: hosted
version: "5.13.4"
version: "5.14.2"
process:
dependency: transitive
description:
@ -1412,10 +1444,10 @@ packages:
dependency: transitive
description:
name: shared_preferences_android
sha256: "02a7d8a9ef346c9af715811b01fbd8e27845ad2c41148eefd31321471b41863d"
sha256: a768fc8ede5f0c8e6150476e14f38e2417c0864ca36bb4582be8e21925a03c22
url: "https://pub.dev"
source: hosted
version: "2.4.0"
version: "2.4.6"
shared_preferences_foundation:
dependency: transitive
description:
@ -1444,10 +1476,10 @@ packages:
dependency: transitive
description:
name: shared_preferences_web
sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e
sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
url: "https://pub.dev"
source: hosted
version: "2.4.2"
version: "2.4.3"
shared_preferences_windows:
dependency: transitive
description:
@ -1460,10 +1492,10 @@ packages:
dependency: transitive
description:
name: shelf
sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
url: "https://pub.dev"
source: hosted
version: "1.4.1"
version: "1.4.2"
shelf_gzip:
dependency: transitive
description:
@ -1500,10 +1532,10 @@ packages:
dependency: transitive
description:
name: shelf_web_socket
sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
url: "https://pub.dev"
source: hosted
version: "2.0.1"
version: "3.0.0"
shlex:
dependency: transitive
description:
@ -1745,18 +1777,18 @@ packages:
dependency: transitive
description:
name: url_launcher_web
sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e"
sha256: "3ba963161bd0fe395917ba881d320b9c4f6dd3c4a233da62ab18a5025c85f1e9"
url: "https://pub.dev"
source: hosted
version: "2.3.3"
version: "2.4.0"
url_launcher_windows:
dependency: transitive
description:
name: url_launcher_windows
sha256: "44cf3aabcedde30f2dba119a9dea3b0f2672fbe6fa96e85536251d678216b3c4"
sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77"
url: "https://pub.dev"
source: hosted
version: "3.1.3"
version: "3.1.4"
uuid:
dependency: "direct main"
description:
@ -1769,18 +1801,18 @@ packages:
dependency: transitive
description:
name: vector_graphics
sha256: "27d5fefe86fb9aace4a9f8375b56b3c292b64d8c04510df230f849850d912cb7"
sha256: "44cc7104ff32563122a929e4620cf3efd584194eec6d1d913eb5ba593dbcf6de"
url: "https://pub.dev"
source: hosted
version: "1.1.15"
version: "1.1.18"
vector_graphics_codec:
dependency: transitive
description:
name: vector_graphics_codec
sha256: "2430b973a4ca3c4dbc9999b62b8c719a160100dcbae5c819bae0cacce32c9cdb"
sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146"
url: "https://pub.dev"
source: hosted
version: "1.1.12"
version: "1.1.13"
vector_graphics_compiler:
dependency: "direct main"
description:
@ -1809,18 +1841,18 @@ packages:
dependency: transitive
description:
name: video_player_android
sha256: "391e092ba4abe2f93b3e625bd6b6a6ec7d7414279462c1c0ee42b5ab8d0a0898"
sha256: "7018dbcb395e2bca0b9a898e73989e67c0c4a5db269528e1b036ca38bcca0d0b"
url: "https://pub.dev"
source: hosted
version: "2.7.16"
version: "2.7.17"
video_player_avfoundation:
dependency: transitive
description:
name: video_player_avfoundation
sha256: "33224c19775fd244be2d6e3dbd8e1826ab162877bd61123bf71890772119a2b7"
sha256: "84b4752745eeccb6e75865c9aab39b3d28eb27ba5726d352d45db8297fbd75bc"
url: "https://pub.dev"
source: hosted
version: "2.6.5"
version: "2.7.0"
video_player_platform_interface:
dependency: "direct main"
description:
@ -1833,10 +1865,10 @@ packages:
dependency: transitive
description:
name: video_player_web
sha256: "881b375a934d8ebf868c7fb1423b2bfaa393a0a265fa3f733079a86536064a10"
sha256: "3ef40ea6d72434edbfdba4624b90fd3a80a0740d260667d91e7ecd2d79e13476"
url: "https://pub.dev"
source: hosted
version: "2.3.3"
version: "2.3.4"
vm_service:
dependency: transitive
description:
@ -1873,10 +1905,10 @@ packages:
dependency: transitive
description:
name: web_socket_channel
sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
version: "3.0.2"
webdriver:
dependency: transitive
description:
@ -1897,10 +1929,10 @@ packages:
dependency: transitive
description:
name: win32
sha256: "8b338d4486ab3fbc0ba0db9f9b4f5239b6697fcee427939a40e720cbb9ee0a69"
sha256: b89e6e24d1454e149ab20fbb225af58660f0c0bf4475544650700d8e2da54aef
url: "https://pub.dev"
source: hosted
version: "5.9.0"
version: "5.11.0"
window_manager:
dependency: "direct main"
description:
@ -1946,10 +1978,10 @@ packages:
dependency: transitive
description:
name: yaml_edit
sha256: e9c1a3543d2da0db3e90270dbb1e4eebc985ee5e3ffe468d83224472b2194a5f
sha256: fb38626579fb345ad00e674e2af3a5c9b0cc4b9bfb8fd7f7ff322c7c9e62aef5
url: "https://pub.dev"
source: hosted
version: "2.2.1"
version: "2.2.2"
sdks:
dart: ">=3.7.0-0 <3.999.0"
dart: ">=3.7.0 <3.999.0"
flutter: ">=3.29.0"

View File

@ -22,6 +22,7 @@ dependencies:
extended_text_field: ^16.0.0
file_selector: ^1.0.3
flex_color_scheme: ^8.1.1
flutter_highlighter: ^0.1.0
flutter_hooks: ^0.21.2
flutter_markdown: ^0.7.6+2
flutter_portal: ^1.1.4
@ -47,6 +48,7 @@ dependencies:
multi_split_view: ^3.2.2
multi_trigger_autocomplete_plus:
path: packages/multi_trigger_autocomplete_plus
ollama_dart: ^0.2.2
package_info_plus: ^8.3.0
path: ^1.8.3
path_provider: ^2.1.2