mirror of
https://github.com/foss42/apidash.git
synced 2025-12-02 18:57:05 +08:00
Update Dashbot
This commit is contained in:
@@ -2,11 +2,9 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:apidash/dashbot/widgets/dashbot_widget.dart';
|
import 'package:apidash/dashbot/widgets/dashbot_widget.dart';
|
||||||
|
|
||||||
// Provider to manage DashBot visibility state
|
|
||||||
final dashBotVisibilityProvider = StateProvider<bool>((ref) => false);
|
final dashBotVisibilityProvider = StateProvider<bool>((ref) => false);
|
||||||
final dashBotMinimizedProvider = StateProvider<bool>((ref) => false);
|
final dashBotMinimizedProvider = StateProvider<bool>((ref) => false);
|
||||||
|
|
||||||
// Function to show DashBot in a bottom sheet (old style)
|
|
||||||
void showDashBotBottomSheet(BuildContext context) {
|
void showDashBotBottomSheet(BuildContext context) {
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
@@ -18,13 +16,11 @@ void showDashBotBottomSheet(BuildContext context) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to toggle DashBot overlay (new style)
|
|
||||||
void toggleDashBotOverlay(WidgetRef ref) {
|
void toggleDashBotOverlay(WidgetRef ref) {
|
||||||
ref.read(dashBotVisibilityProvider.notifier).state = true;
|
ref.read(dashBotVisibilityProvider.notifier).state = true;
|
||||||
ref.read(dashBotMinimizedProvider.notifier).state = false;
|
ref.read(dashBotMinimizedProvider.notifier).state = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// DashBot Overlay Widget
|
|
||||||
class DashBotOverlay extends ConsumerWidget {
|
class DashBotOverlay extends ConsumerWidget {
|
||||||
const DashBotOverlay({super.key});
|
const DashBotOverlay({super.key});
|
||||||
|
|
||||||
@@ -36,7 +32,7 @@ class DashBotOverlay extends ConsumerWidget {
|
|||||||
elevation: 8,
|
elevation: 8,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: 400, // Fixed width for the DashBot
|
width: 400,
|
||||||
height: isMinimized ? 120 : 450,
|
height: isMinimized ? 120 : 450,
|
||||||
child: const DashBotWidget(),
|
child: const DashBotWidget(),
|
||||||
),
|
),
|
||||||
@@ -44,7 +40,6 @@ class DashBotOverlay extends ConsumerWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FloatingActionButton for DashBot
|
|
||||||
class DashBotFAB extends ConsumerWidget {
|
class DashBotFAB extends ConsumerWidget {
|
||||||
final bool useOverlay;
|
final bool useOverlay;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import '../services/dashbot_service.dart';
|
import 'package:apidash/dashbot/services/dashbot_service.dart';
|
||||||
import 'package:apidash/models/request_model.dart';
|
import 'package:apidash/models/request_model.dart';
|
||||||
|
|
||||||
class DocumentationFeature {
|
class DocumentationFeature {
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ class GeneralQueryFeature {
|
|||||||
GeneralQueryFeature(this._client);
|
GeneralQueryFeature(this._client);
|
||||||
|
|
||||||
Future<String> generateResponse(String prompt, {RequestModel? requestModel, dynamic responseModel}) async {
|
Future<String> generateResponse(String prompt, {RequestModel? requestModel, dynamic responseModel}) async {
|
||||||
// Create a more focused prompt that incorporates request/response context if available
|
|
||||||
String enhancedPrompt = prompt;
|
String enhancedPrompt = prompt;
|
||||||
|
|
||||||
if (requestModel != null && responseModel != null) {
|
if (requestModel != null && responseModel != null) {
|
||||||
|
|||||||
@@ -22,20 +22,15 @@ class TestGeneratorFeature {
|
|||||||
.toUpperCase() ??
|
.toUpperCase() ??
|
||||||
"GET";
|
"GET";
|
||||||
final endpoint = requestModel.httpRequestModel?.url ?? "Unknown Endpoint";
|
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 rawResponse = responseModel.body;
|
||||||
final responseBody =
|
final responseBody =
|
||||||
rawResponse is String ? rawResponse : jsonEncode(rawResponse);
|
rawResponse is String ? rawResponse : jsonEncode(rawResponse);
|
||||||
final statusCode = responseModel.statusCode ?? 0;
|
final statusCode = responseModel.statusCode ?? 0;
|
||||||
|
|
||||||
// Extract base URL and endpoint path
|
|
||||||
Uri uri = Uri.parse(endpoint);
|
Uri uri = Uri.parse(endpoint);
|
||||||
final baseUrl = "${uri.scheme}://${uri.host}";
|
final baseUrl = "${uri.scheme}://${uri.host}";
|
||||||
final path = uri.path;
|
final path = uri.path;
|
||||||
|
|
||||||
// Analyze parameter types and values
|
|
||||||
final parameterAnalysis = _analyzeParameters(uri.queryParameters);
|
final parameterAnalysis = _analyzeParameters(uri.queryParameters);
|
||||||
|
|
||||||
final prompt = """
|
final prompt = """
|
||||||
@@ -67,11 +62,7 @@ For each test case:
|
|||||||
Focus on creating realistic test values based on the API context (e.g., for a country flag API, use real country codes, invalid codes, etc.)
|
Focus on creating realistic test values based on the API context (e.g., for a country flag API, use real country codes, invalid codes, etc.)
|
||||||
""";
|
""";
|
||||||
|
|
||||||
// Generate the test cases
|
|
||||||
final testCases = await _service.generateResponse(prompt);
|
final testCases = await _service.generateResponse(prompt);
|
||||||
|
|
||||||
// Return only a button trigger message with the test cases hidden
|
|
||||||
// This will be detected in DashBotWidget to show only a button instead of the full text
|
|
||||||
return "TEST_CASES_HIDDEN\n$testCases";
|
return "TEST_CASES_HIDDEN\n$testCases";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +74,6 @@ Focus on creating realistic test values based on the API context (e.g., for a co
|
|||||||
Map<String, String> analysis = {};
|
Map<String, String> analysis = {};
|
||||||
|
|
||||||
parameters.forEach((key, value) {
|
parameters.forEach((key, value) {
|
||||||
// Try to determine parameter type and format
|
|
||||||
if (RegExp(r'^[A-Z]{3}$').hasMatch(value)) {
|
if (RegExp(r'^[A-Z]{3}$').hasMatch(value)) {
|
||||||
analysis[key] = "Appears to be a 3-letter country code (ISO 3166-1 alpha-3)";
|
analysis[key] = "Appears to be a 3-letter country code (ISO 3166-1 alpha-3)";
|
||||||
} else if (RegExp(r'^[A-Z]{2}$').hasMatch(value)) {
|
} else if (RegExp(r'^[A-Z]{2}$').hasMatch(value)) {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import 'package:apidash/dashbot/features/debug.dart';
|
|||||||
import 'package:apidash/dashbot/features/documentation.dart';
|
import 'package:apidash/dashbot/features/documentation.dart';
|
||||||
import 'package:ollama_dart/ollama_dart.dart';
|
import 'package:ollama_dart/ollama_dart.dart';
|
||||||
import 'package:apidash/dashbot/features/explain.dart';
|
import 'package:apidash/dashbot/features/explain.dart';
|
||||||
import 'package:apidash/dashbot/features/test_generator.dart'; // New import
|
import 'package:apidash/dashbot/features/test_generator.dart';
|
||||||
import 'package:apidash/models/request_model.dart';
|
import 'package:apidash/models/request_model.dart';
|
||||||
import 'package:apidash/dashbot/features/general_query.dart';
|
import 'package:apidash/dashbot/features/general_query.dart';
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ class DashBotService {
|
|||||||
late final ExplainFeature _explainFeature;
|
late final ExplainFeature _explainFeature;
|
||||||
late final DebugFeature _debugFeature;
|
late final DebugFeature _debugFeature;
|
||||||
late final DocumentationFeature _documentationFeature;
|
late final DocumentationFeature _documentationFeature;
|
||||||
late final TestGeneratorFeature _testGeneratorFeature; // New feature
|
late final TestGeneratorFeature _testGeneratorFeature;
|
||||||
final GeneralQueryFeature _generalQueryFeature;
|
final GeneralQueryFeature _generalQueryFeature;
|
||||||
|
|
||||||
DashBotService()
|
DashBotService()
|
||||||
@@ -20,7 +20,7 @@ class DashBotService {
|
|||||||
_explainFeature = ExplainFeature(this);
|
_explainFeature = ExplainFeature(this);
|
||||||
_debugFeature = DebugFeature(this);
|
_debugFeature = DebugFeature(this);
|
||||||
_documentationFeature = DocumentationFeature(this);
|
_documentationFeature = DocumentationFeature(this);
|
||||||
_testGeneratorFeature = TestGeneratorFeature(this); // Initialize new feature
|
_testGeneratorFeature = TestGeneratorFeature(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> generateResponse(String prompt) async {
|
Future<String> generateResponse(String prompt) async {
|
||||||
@@ -38,7 +38,7 @@ class DashBotService {
|
|||||||
} else if (input == "Document API") {
|
} else if (input == "Document API") {
|
||||||
return _documentationFeature.generateApiDocumentation(
|
return _documentationFeature.generateApiDocumentation(
|
||||||
requestModel: requestModel, responseModel: responseModel);
|
requestModel: requestModel, responseModel: responseModel);
|
||||||
} else if (input == "Test API") { // New condition
|
} else if (input == "Test API") {
|
||||||
return _testGeneratorFeature.generateApiTests(
|
return _testGeneratorFeature.generateApiTests(
|
||||||
requestModel: requestModel, responseModel: responseModel);
|
requestModel: requestModel, responseModel: responseModel);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ import 'test_runner_widget.dart';
|
|||||||
import 'chat_bubble.dart';
|
import 'chat_bubble.dart';
|
||||||
|
|
||||||
class DashBotWidget extends ConsumerStatefulWidget {
|
class DashBotWidget extends ConsumerStatefulWidget {
|
||||||
const DashBotWidget({super.key});
|
const DashBotWidget({
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ConsumerState<DashBotWidget> createState() => _DashBotWidgetState();
|
ConsumerState<DashBotWidget> createState() => _DashBotWidgetState();
|
||||||
@@ -33,7 +35,6 @@ class _DashBotWidgetState extends ConsumerState<DashBotWidget> {
|
|||||||
|
|
||||||
Future<void> _sendMessage(String message) async {
|
Future<void> _sendMessage(String message) async {
|
||||||
if (message.trim().isEmpty) return;
|
if (message.trim().isEmpty) return;
|
||||||
|
|
||||||
final dashBotService = ref.read(dashBotServiceProvider);
|
final dashBotService = ref.read(dashBotServiceProvider);
|
||||||
final requestModel = ref.read(selectedRequestModelProvider);
|
final requestModel = ref.read(selectedRequestModelProvider);
|
||||||
final responseModel = requestModel?.httpResponseModel;
|
final responseModel = requestModel?.httpResponseModel;
|
||||||
@@ -48,13 +49,8 @@ class _DashBotWidgetState extends ConsumerState<DashBotWidget> {
|
|||||||
try {
|
try {
|
||||||
final response = await dashBotService.handleRequest(
|
final response = await dashBotService.handleRequest(
|
||||||
message, requestModel, responseModel);
|
message, requestModel, responseModel);
|
||||||
|
|
||||||
// Check if this is a test case response with hidden content
|
|
||||||
if (response.startsWith("TEST_CASES_HIDDEN\n")) {
|
if (response.startsWith("TEST_CASES_HIDDEN\n")) {
|
||||||
// Extract the test cases but don't show them in the message
|
|
||||||
final testCases = response.replaceFirst("TEST_CASES_HIDDEN\n", "");
|
final testCases = response.replaceFirst("TEST_CASES_HIDDEN\n", "");
|
||||||
|
|
||||||
// Add a message with a marker that will trigger the button display
|
|
||||||
ref.read(chatMessagesProvider.notifier).addMessage({
|
ref.read(chatMessagesProvider.notifier).addMessage({
|
||||||
'role': 'bot',
|
'role': 'bot',
|
||||||
'message': "Test cases generated successfully. Click the button below to run them.",
|
'message': "Test cases generated successfully. Click the button below to run them.",
|
||||||
@@ -62,7 +58,6 @@ class _DashBotWidgetState extends ConsumerState<DashBotWidget> {
|
|||||||
'showTestButton': true,
|
'showTestButton': true,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Normal message handling
|
|
||||||
ref.read(chatMessagesProvider.notifier).addMessage({
|
ref.read(chatMessagesProvider.notifier).addMessage({
|
||||||
'role': 'bot',
|
'role': 'bot',
|
||||||
'message': response,
|
'message': response,
|
||||||
@@ -135,7 +130,6 @@ class _DashBotWidgetState extends ConsumerState<DashBotWidget> {
|
|||||||
|
|
||||||
Widget _buildHeader(BuildContext context) {
|
Widget _buildHeader(BuildContext context) {
|
||||||
final isMinimized = ref.watch(dashBotMinimizedProvider);
|
final isMinimized = ref.watch(dashBotMinimizedProvider);
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(16, 16, 16, 0),
|
padding: const EdgeInsets.fromLTRB(16, 16, 16, 0),
|
||||||
child: Row(
|
child: Row(
|
||||||
@@ -147,7 +141,6 @@ class _DashBotWidgetState extends ConsumerState<DashBotWidget> {
|
|||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
// Minimize/Maximize button with proper alignment
|
|
||||||
IconButton(
|
IconButton(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
visualDensity: VisualDensity.compact,
|
visualDensity: VisualDensity.compact,
|
||||||
@@ -160,7 +153,6 @@ class _DashBotWidgetState extends ConsumerState<DashBotWidget> {
|
|||||||
ref.read(dashBotMinimizedProvider.notifier).state = !isMinimized;
|
ref.read(dashBotMinimizedProvider.notifier).state = !isMinimized;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
// Close button
|
|
||||||
IconButton(
|
IconButton(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
visualDensity: VisualDensity.compact,
|
visualDensity: VisualDensity.compact,
|
||||||
@@ -170,7 +162,6 @@ class _DashBotWidgetState extends ConsumerState<DashBotWidget> {
|
|||||||
ref.read(dashBotVisibilityProvider.notifier).state = false;
|
ref.read(dashBotVisibilityProvider.notifier).state = false;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
// Clear chat button
|
|
||||||
IconButton(
|
IconButton(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
visualDensity: VisualDensity.compact,
|
visualDensity: VisualDensity.compact,
|
||||||
@@ -302,7 +293,6 @@ class _DashBotWidgetState extends ConsumerState<DashBotWidget> {
|
|||||||
|
|
||||||
Widget _buildInputArea(BuildContext context) {
|
Widget _buildInputArea(BuildContext context) {
|
||||||
final isMinimized = ref.watch(dashBotMinimizedProvider);
|
final isMinimized = ref.watch(dashBotMinimizedProvider);
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'package:apidash_core/apidash_core.dart' as http;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'dart:convert';
|
|
||||||
import 'package:http/http.dart' as http;
|
|
||||||
import 'content_renderer.dart';
|
import 'content_renderer.dart';
|
||||||
|
|
||||||
class TestRunnerWidget extends ConsumerStatefulWidget {
|
class TestRunnerWidget extends ConsumerStatefulWidget {
|
||||||
|
|||||||
Reference in New Issue
Block a user