Skip to content

DashBot Update #699

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 25 commits into from
Jun 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
8edf981
Feat: API Documentation & process general queries
siddu015 Mar 11, 2025
c8eba4d
Merge branch 'foss42:main' into Dashbot_v2
siddu015 Mar 11, 2025
6fa9d22
Test cases generator
siddu015 Mar 12, 2025
877ea61
Test cases generator response with a button to run the test cases
siddu015 Mar 13, 2025
7582c78
Test cases generator modification to only Run test cases feature with…
siddu015 Mar 20, 2025
f44091a
Move DashBot to bottom-right, add close/minimize/maximize buttons and…
siddu015 Mar 22, 2025
8971666
Merge branch 'foss42:main' into Dashbot_v2
siddu015 Mar 22, 2025
225c984
Merge branch 'foss42:main' into Dashbot_v2
siddu015 Mar 23, 2025
1c0af6e
Update Dashboard widget to fix DashBot overlay positioning with Stack
siddu015 Mar 23, 2025
6d1ceee
Merge branch 'foss42:main' into Dashbot_v2
siddu015 Mar 23, 2025
7c5a841
Update Dashbot
siddu015 Mar 23, 2025
9c1fad2
Merge branch 'foss42:main' into Dashbot_v2
siddu015 Apr 25, 2025
6e3441f
Merge branch 'main' into Dashbot_v2
ashitaprasad May 17, 2025
1ba6a3f
Update dashbot.dart
ashitaprasad May 17, 2025
962bf0f
Update dashboard.dart
ashitaprasad May 17, 2025
2863bdd
fix formatting and imports
ashitaprasad May 17, 2025
b2ea4a4
format fix
ashitaprasad May 17, 2025
ede412f
Update hive_services.dart
ashitaprasad May 17, 2025
a4f0bb7
Update debug.dart
ashitaprasad Jun 22, 2025
65ba7ab
import correction
ashitaprasad Jun 22, 2025
9089179
Add consts.dart
ashitaprasad Jun 22, 2025
702b0d1
sharedprefs to hive
ashitaprasad Jun 22, 2025
194f76f
DashBot providers
ashitaprasad Jun 22, 2025
a05894d
Update dashbot
ashitaprasad Jun 22, 2025
bfd85c8
Update settings_model_test.dart
ashitaprasad Jun 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/dashbot/consts.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
const kModel = 'llama3.2:3b';
const kOllamaEndpoint = 'http://127.0.0.1:11434/api';
4 changes: 2 additions & 2 deletions lib/dashbot/features/debug.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'dart:convert';
import '../services/dashbot_service.dart';
import 'package:apidash/models/request_model.dart';
import '../services/services.dart';
import '../../models/models.dart';

class DebugFeature {
final DashBotService _service;
Expand Down
66 changes: 66 additions & 0 deletions lib/dashbot/features/documentation.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import 'dart:convert';
import '../services/services.dart';
import '../../models/models.dart';

class DocumentationFeature {
final DashBotService _service;

DocumentationFeature(this._service);

Future<String> generateApiDocumentation({
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 = """
API DOCUMENTATION GENERATION

**API Details:**
- Endpoint: $endpoint
- Method: $method
- Status Code: $statusCode

**Request Components:**
- Headers: ${headers.isNotEmpty ? jsonEncode(headers) : "None"}
- Query Parameters: ${parameters.isNotEmpty ? jsonEncode(parameters) : "None"}
- Request Body: ${body != null && body.isNotEmpty ? body : "None"}

**Response Example:**
```
$responseBody
```

**Documentation Instructions:**
Create comprehensive API documentation that includes:

1. **Overview**: A clear, concise description of what this API endpoint does
2. **Authentication**: Required authentication method based on headers
3. **Request Details**: All required and optional parameters with descriptions
4. **Response Structure**: Breakdown of response fields and their meanings
5. **Error Handling**: Possible error codes and troubleshooting
6. **Example Usage**: A complete code example showing how to call this API

Format in clean markdown with proper sections and code blocks where appropriate.
""";

return _service.generateResponse(prompt);
}
}
4 changes: 2 additions & 2 deletions lib/dashbot/features/explain.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import '../services/dashbot_service.dart';
import 'package:apidash/models/request_model.dart';
import '../services/services.dart';
import '../../models/models.dart';

class ExplainFeature {
final DashBotService _service;
Expand Down
5 changes: 5 additions & 0 deletions lib/dashbot/features/features.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export 'debug.dart';
export 'documentation.dart';
export 'explain.dart';
export 'general_query.dart';
export 'test_generator.dart';
54 changes: 54 additions & 0 deletions lib/dashbot/features/general_query.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import 'package:ollama_dart/ollama_dart.dart';
import '../../models/models.dart';
import '../consts.dart';

class GeneralQueryFeature {
final OllamaClient _client;

GeneralQueryFeature(this._client);

Future<String> generateResponse(String prompt,
{RequestModel? requestModel, dynamic responseModel}) async {
String enhancedPrompt = prompt;

if (requestModel != null && responseModel != null) {
final method = requestModel.httpRequestModel?.method
.toString()
.split('.')
.last
.toUpperCase() ??
"GET";
final endpoint = requestModel.httpRequestModel?.url ?? "Unknown Endpoint";
final statusCode = responseModel.statusCode ?? 0;

enhancedPrompt = '''
CONTEXT-AWARE RESPONSE

**User Question:**
$prompt

**Related API Context:**
- Endpoint: $endpoint
- Method: $method
- Status Code: $statusCode

**Instructions:**
1. Directly address the user's specific question
2. Provide relevant, concise information
3. Reference the API context when helpful
4. Focus on practical, actionable insights
5. Avoid generic explanations or documentation

Respond in a helpful, direct manner that specifically answers what was asked.
''';
}

final response = await _client.generateCompletion(
request: GenerateCompletionRequest(
model: kModel,
prompt: enhancedPrompt,
),
);
return response.response.toString();
}
}
94 changes: 94 additions & 0 deletions lib/dashbot/features/test_generator.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import 'dart:convert';
import '../services/services.dart';
import '../../models/models.dart';

class TestGeneratorFeature {
final DashBotService _service;

TestGeneratorFeature(this._service);

Future<String> generateApiTests({
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 rawResponse = responseModel.body;
final responseBody =
rawResponse is String ? rawResponse : jsonEncode(rawResponse);
final statusCode = responseModel.statusCode ?? 0;

Uri uri = Uri.parse(endpoint);
final baseUrl = "${uri.scheme}://${uri.host}";
final path = uri.path;

final parameterAnalysis = _analyzeParameters(uri.queryParameters);

final prompt = """
EXECUTABLE API TEST CASES GENERATOR

**API Analysis:**
- Base URL: $baseUrl
- Endpoint: $path
- Method: $method
- Current Parameters: ${uri.queryParameters}
- Current Response: $responseBody (Status: $statusCode)
- Parameter Types: $parameterAnalysis

**Test Generation Task:**
Generate practical, ready-to-use test cases for this API in cURL format. Each test should be executable immediately.

Include these test categories:
1. **Valid Cases**: Different valid parameter values (use real-world examples like other country codes if this is a country API)
2. **Invalid Parameter Tests**: Missing parameters, empty values, incorrect formats
3. **Edge Cases**: Special characters, long values, unexpected inputs
4. **Validation Tests**: Test input validation and error handling

For each test case:
1. Provide a brief description of what the test verifies
2. Include a complete, executable cURL command
3. Show the expected outcome (status code and sample response)
4. Organize tests in a way that's easy to copy and run

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.)
""";

final testCases = await _service.generateResponse(prompt);
return "TEST_CASES_HIDDEN\n$testCases";
}

String _analyzeParameters(Map<String, String> parameters) {
if (parameters.isEmpty) {
return "No parameters detected";
}

Map<String, String> analysis = {};

parameters.forEach((key, value) {
if (RegExp(r'^[A-Z]{3}$').hasMatch(value)) {
analysis[key] =
"Appears to be a 3-letter country code (ISO 3166-1 alpha-3)";
} else if (RegExp(r'^[A-Z]{2}$').hasMatch(value)) {
analysis[key] =
"Appears to be a 2-letter country code (ISO 3166-1 alpha-2)";
} else if (RegExp(r'^\d+$').hasMatch(value)) {
analysis[key] = "Numeric value";
} else if (RegExp(r'^[a-zA-Z]+$').hasMatch(value)) {
analysis[key] = "Alphabetic string";
} else {
analysis[key] = "Unknown format: $value";
}
});

return jsonEncode(analysis);
}
}
17 changes: 9 additions & 8 deletions lib/dashbot/providers/dashbot_providers.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import 'dart:convert';
import 'package:apidash/services/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../services/dashbot_service.dart';
import '../services/services.dart';

final dashBotMinimizedProvider = StateProvider<bool>((ref) {
return true;
});

final chatMessagesProvider =
StateNotifierProvider<ChatMessagesNotifier, List<Map<String, dynamic>>>(
Expand All @@ -17,19 +21,16 @@ class ChatMessagesNotifier extends StateNotifier<List<Map<String, dynamic>>> {
_loadMessages();
}

static const _storageKey = 'chatMessages';

Future<void> _loadMessages() async {
final prefs = await SharedPreferences.getInstance();
final messages = prefs.getString(_storageKey);
final messages = await hiveHandler.getDashbotMessages();
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));
final messages = json.encode(state);
await hiveHandler.saveDashbotMessages(messages);
}

void addMessage(Map<String, dynamic> message) {
Expand Down
47 changes: 36 additions & 11 deletions lib/dashbot/services/dashbot_service.dart
Original file line number Diff line number Diff line change
@@ -1,36 +1,61 @@
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';
import '../consts.dart';
import '../features/features.dart';

class DashBotService {
final OllamaClient _client;
late final ExplainFeature _explainFeature;
late final DebugFeature _debugFeature;
late final DocumentationFeature _documentationFeature;
late final TestGeneratorFeature _testGeneratorFeature;
final GeneralQueryFeature _generalQueryFeature;

DashBotService()
: _client = OllamaClient(baseUrl: 'http://127.0.0.1:11434/api') {
: _client = OllamaClient(baseUrl: kOllamaEndpoint),
_generalQueryFeature =
GeneralQueryFeature(OllamaClient(baseUrl: kOllamaEndpoint)) {
_explainFeature = ExplainFeature(this);
_debugFeature = DebugFeature(this);
_documentationFeature = DocumentationFeature(this);
_testGeneratorFeature = TestGeneratorFeature(this);
}

Future<String> generateResponse(String prompt) async {
final response = await _client.generateCompletion(
request: GenerateCompletionRequest(model: 'llama3.2:3b', prompt: prompt),
);
return response.response.toString();
return _generalQueryFeature.generateResponse(prompt);
}

Future<String> handleRequest(
String input, RequestModel? requestModel, dynamic responseModel) async {
String input,
RequestModel? requestModel,
dynamic responseModel,
) async {
if (input == "Explain API") {
return _explainFeature.explainLatestApi(
requestModel: requestModel, responseModel: responseModel);
requestModel: requestModel,
responseModel: responseModel,
);
} else if (input == "Debug API") {
return _debugFeature.debugApi(
requestModel: requestModel, responseModel: responseModel);
requestModel: requestModel,
responseModel: responseModel,
);
} else if (input == "Document API") {
return _documentationFeature.generateApiDocumentation(
requestModel: requestModel,
responseModel: responseModel,
);
} else if (input == "Test API") {
return _testGeneratorFeature.generateApiTests(
requestModel: requestModel,
responseModel: responseModel,
);
}

return generateResponse(input);
return _generalQueryFeature.generateResponse(
input,
requestModel: requestModel,
responseModel: responseModel,
);
}
}
1 change: 1 addition & 0 deletions lib/dashbot/services/services.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export 'dashbot_service.dart';
6 changes: 5 additions & 1 deletion lib/dashbot/widgets/chat_bubble.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ class ChatBubble extends StatelessWidget {
final String message;
final bool isUser;

const ChatBubble({super.key, required this.message, this.isUser = false});
const ChatBubble({
super.key,
required this.message,
this.isUser = false,
});

@override
Widget build(BuildContext context) {
Expand Down
Loading