mirror of
https://github.com/foss42/apidash.git
synced 2025-12-02 02:39:19 +08:00
Consolidator & Tool Templates Done
This commit is contained in:
97
lib/apitoolgen/request_consolidator.dart
Normal file
97
lib/apitoolgen/request_consolidator.dart
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
class APIDashRequestDescription {
|
||||||
|
final String endpoint;
|
||||||
|
final String method;
|
||||||
|
final Map<String, dynamic>? queryParams;
|
||||||
|
final List<Map>? formData;
|
||||||
|
final Map<String, dynamic>? headers;
|
||||||
|
final String? bodyTXT;
|
||||||
|
final Map? bodyJSON;
|
||||||
|
final String? responseType;
|
||||||
|
final dynamic response;
|
||||||
|
|
||||||
|
APIDashRequestDescription({
|
||||||
|
required this.endpoint,
|
||||||
|
required this.method,
|
||||||
|
this.queryParams,
|
||||||
|
this.formData,
|
||||||
|
this.headers,
|
||||||
|
this.bodyTXT,
|
||||||
|
this.bodyJSON,
|
||||||
|
this.responseType,
|
||||||
|
this.response,
|
||||||
|
});
|
||||||
|
|
||||||
|
String get generateREQDATA {
|
||||||
|
//Note Down the Query parameters
|
||||||
|
String queryParamStr = '';
|
||||||
|
if (queryParams != null) {
|
||||||
|
for (final x in queryParams!.keys) {
|
||||||
|
queryParamStr +=
|
||||||
|
'\t$x: ${queryParams![x]} <${queryParams![x].runtimeType}>\n';
|
||||||
|
}
|
||||||
|
queryParamStr = 'QUERY_PARAMETERS: {\n$queryParamStr}';
|
||||||
|
}
|
||||||
|
|
||||||
|
//Note Down the Headers
|
||||||
|
String headersStr = '';
|
||||||
|
if (headers != null) {
|
||||||
|
for (final x in headers!.keys) {
|
||||||
|
headersStr += '\t$x: ${headers![x]} <${headers![x].runtimeType}>\n';
|
||||||
|
}
|
||||||
|
headersStr = 'HEADERS: {\n$headersStr}';
|
||||||
|
}
|
||||||
|
|
||||||
|
String bodyDetails = '';
|
||||||
|
if (bodyTXT != null) {
|
||||||
|
bodyDetails = 'BODY_TYPE: TEXT\nBODY_TEXT:$bodyTXT';
|
||||||
|
} else if (bodyJSON != null) {
|
||||||
|
//Note Down the JSONData
|
||||||
|
String jsonBodyStr = '';
|
||||||
|
if (bodyJSON != null) {
|
||||||
|
getTyp(input, [i = 0]) {
|
||||||
|
String indent = "\t";
|
||||||
|
for (int j = 0; j < i; j++) indent += "\t";
|
||||||
|
if (input.runtimeType.toString().toLowerCase().contains('map')) {
|
||||||
|
String typd = '{';
|
||||||
|
for (final z in input.keys) {
|
||||||
|
typd += "$indent$z: TYPE: ${getTyp(input[z], i + 1)}\n";
|
||||||
|
}
|
||||||
|
return "$indent$typd}";
|
||||||
|
}
|
||||||
|
return input.runtimeType.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final x in bodyJSON!.keys) {
|
||||||
|
jsonBodyStr += '\t$x: TYPE: <${getTyp(bodyJSON![x])}>\n';
|
||||||
|
}
|
||||||
|
jsonBodyStr = 'BODY_JSON: {\n$jsonBodyStr}';
|
||||||
|
}
|
||||||
|
bodyDetails = 'BODY_TYPE: JSON\n$jsonBodyStr';
|
||||||
|
} else if (formData != null) {
|
||||||
|
//Note Down the FormData
|
||||||
|
String formDataStr = '';
|
||||||
|
if (formData != null) {
|
||||||
|
for (final x in formData!) {
|
||||||
|
formDataStr += '\t$x\n';
|
||||||
|
}
|
||||||
|
formDataStr = 'BODY_FORM_DATA: {\n$formDataStr}';
|
||||||
|
}
|
||||||
|
bodyDetails = 'BODY_TYPE: FORM-DATA\n$formDataStr';
|
||||||
|
}
|
||||||
|
|
||||||
|
String responseDetails = '';
|
||||||
|
if (responseType != null && response != null) {
|
||||||
|
responseDetails =
|
||||||
|
'-----RESPONSE_DETAILS-----\nRESPONSE_TYPE: $responseType\nRESPONSE_BODY: $response';
|
||||||
|
}
|
||||||
|
|
||||||
|
return """REST API (HTTP)
|
||||||
|
METHOD: $method
|
||||||
|
ENDPOINT: $endpoint
|
||||||
|
HEADERS: ${headersStr.isEmpty ? '{}' : headersStr}
|
||||||
|
$queryParamStr
|
||||||
|
$bodyDetails
|
||||||
|
|
||||||
|
""";
|
||||||
|
}
|
||||||
|
}
|
||||||
93
lib/apitoolgen/tool_templates.dart
Normal file
93
lib/apitoolgen/tool_templates.dart
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
const GENERAL_ARG_PROPERTY_FORMAT_PY = """:ARG_NAME: {
|
||||||
|
"type": ":ARG_TYPE:",
|
||||||
|
"description: ":ARG_DESC:"
|
||||||
|
}""";
|
||||||
|
|
||||||
|
const GENERAL_PYTHON_TOOL_FORMAT = """
|
||||||
|
:FUNC:
|
||||||
|
|
||||||
|
api_tool = {
|
||||||
|
"function": func,
|
||||||
|
"definition": {
|
||||||
|
"name": ":TOOL_NAME:",
|
||||||
|
"description": ":TOOL_DESCRIPTION:",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": :TOOL_PARAMS:,
|
||||||
|
"required": [:REQUIRED_PARAM_NAMES:],
|
||||||
|
"additionalProperties": False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__all__ = ["api_tool"]
|
||||||
|
""";
|
||||||
|
|
||||||
|
const GENERAL_JAVASCRIPT_TOOL_FORMAT = """
|
||||||
|
:FUNC:
|
||||||
|
|
||||||
|
const apiTool = {
|
||||||
|
function: func,
|
||||||
|
definition: {
|
||||||
|
type: 'function',
|
||||||
|
function: {
|
||||||
|
name: ':TOOL_NAME:',
|
||||||
|
description: ':TOOL_DESCRIPTION:',
|
||||||
|
parameters: {
|
||||||
|
type: 'object',
|
||||||
|
properties: :TOOL_PARAMS:,
|
||||||
|
required: [:REQUIRED_PARAM_NAMES:]
|
||||||
|
additionalProperties: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export { apiTool };
|
||||||
|
""";
|
||||||
|
|
||||||
|
const LANGCHAIN_PYTHON_TOOL_FORMAT = """
|
||||||
|
from langchain.tools import StructuredTool
|
||||||
|
|
||||||
|
:INPUT_SCHEMA:
|
||||||
|
|
||||||
|
:FUNC:
|
||||||
|
|
||||||
|
api_tool = StructuredTool.from_function(
|
||||||
|
func=func,
|
||||||
|
name=":TOOL_NAME:",
|
||||||
|
description=":TOOL_DESCRIPTION:",
|
||||||
|
args_schema=INPUT_SCHEMA,
|
||||||
|
)
|
||||||
|
__all__ = ["api_tool"]
|
||||||
|
""";
|
||||||
|
|
||||||
|
const LANGCHAIN_JAVASCRIPT_TOOL_FORMAT = """
|
||||||
|
import { DynamicStructuredTool } from 'langchain/tools';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
:INPUT_SCHEMA:
|
||||||
|
|
||||||
|
:FUNC:
|
||||||
|
|
||||||
|
const apiTool = new DynamicStructuredTool({
|
||||||
|
func: func,
|
||||||
|
name: ':TOOL_NAME:',
|
||||||
|
description: ':TOOL_DESCRIPTION:',
|
||||||
|
schema: INPUT_SCHEMA
|
||||||
|
});
|
||||||
|
|
||||||
|
export { apiTool };
|
||||||
|
""";
|
||||||
|
|
||||||
|
const MICROSOFT_AUTOGEN_TOOL_FORMAT = """
|
||||||
|
:FUNC:
|
||||||
|
|
||||||
|
api_tool = {
|
||||||
|
"function": func,
|
||||||
|
"name": ":TOOL_NAME:",
|
||||||
|
"description": ":TOOL_DESCRIPTION:"
|
||||||
|
}
|
||||||
|
|
||||||
|
__all__ = ["api_tool"]
|
||||||
|
""";
|
||||||
@@ -3,3 +3,4 @@ export 'semantic_analyser.dart';
|
|||||||
export 'stac2flutter.dart';
|
export 'stac2flutter.dart';
|
||||||
export 'stacgen.dart';
|
export 'stacgen.dart';
|
||||||
export 'stacmodifier.dart';
|
export 'stacmodifier.dart';
|
||||||
|
export 'apitool_funcgen.dart';
|
||||||
|
|||||||
47
lib/services/agentic_services/agents/apitool_funcgen.dart
Normal file
47
lib/services/agentic_services/agents/apitool_funcgen.dart
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import 'package:genai/agentic_engine/blueprint.dart';
|
||||||
|
|
||||||
|
const String _sysprompt = """
|
||||||
|
You are an expert LANGUAGE SPECIFIC API CALL METHOD Creator.
|
||||||
|
You will be provided a complete API Details Text named (REQDATA) which consists of the method, endpoint, params, headers, body
|
||||||
|
and so on.
|
||||||
|
You are also provided with a Target Language named (TARGET_LANGUAGE).
|
||||||
|
|
||||||
|
Using this data, Create a method EXPLICITLY named `func`.
|
||||||
|
The method `func` should accept any variables if present (refer REQDATA for all details) and include it as part of the arguments
|
||||||
|
|
||||||
|
Use the Industry standard best practices while calling the API provided by REQDATA.
|
||||||
|
If REQDATA contains any Authorization (Eg: bearer key), embed that into the function itself and dont expect it to be passed in the function
|
||||||
|
same goes for any header details.
|
||||||
|
|
||||||
|
REQDATA: :REQDATA:
|
||||||
|
|
||||||
|
TARGET_LANGUAGE: :TARGET_LANGUAGE:
|
||||||
|
|
||||||
|
if REQDATA.BODY_TYPE is TEXT => use it as-is
|
||||||
|
if REQDATA.BODY_TYPE is JSON or FORM-DATA => use the types provided to create variables passed from the function arguments
|
||||||
|
|
||||||
|
ALWAYS return the output as code only and do not start or begin with any introduction or conclusion. ONLY THE CODE.
|
||||||
|
""";
|
||||||
|
|
||||||
|
class APIToolFunctionGenerator extends APIDashAIAgent {
|
||||||
|
@override
|
||||||
|
String get agentName => 'APITOOL_FUNCGEN';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String getSystemPrompt() {
|
||||||
|
return _sysprompt;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> validator(String aiResponse) async {
|
||||||
|
//Add any specific validations here as needed
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future outputFormatter(String validatedResponse) async {
|
||||||
|
return {
|
||||||
|
'FUNC': validatedResponse,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,16 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:apidash/apitoolgen/request_consolidator.dart';
|
||||||
import 'package:apidash/providers/collection_providers.dart';
|
import 'package:apidash/providers/collection_providers.dart';
|
||||||
|
import 'package:apidash/services/agentic_services/agent_caller.dart';
|
||||||
|
import 'package:apidash/services/agentic_services/agents/apitool_funcgen.dart';
|
||||||
import 'package:apidash/widgets/ai_ui_desginer_widgets.dart';
|
import 'package:apidash/widgets/ai_ui_desginer_widgets.dart';
|
||||||
|
import 'package:apidash_core/apidash_core.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:apidash_design_system/apidash_design_system.dart';
|
import 'package:apidash_design_system/apidash_design_system.dart';
|
||||||
import 'package:apidash/utils/utils.dart';
|
import 'package:apidash/utils/utils.dart';
|
||||||
import 'package:apidash/consts.dart';
|
import 'package:apidash/consts.dart';
|
||||||
|
import 'package:genai/agentic_engine/blueprint.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'button_clear_response.dart';
|
import 'button_clear_response.dart';
|
||||||
|
|
||||||
@@ -27,62 +34,142 @@ class ResponsePaneHeader extends ConsumerWidget {
|
|||||||
return Padding(
|
return Padding(
|
||||||
padding: kPv8,
|
padding: kPv8,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: kHeaderHeight,
|
// height: kHeaderHeight,
|
||||||
child: Row(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
children: [
|
||||||
kHSpacer10,
|
Row(
|
||||||
Expanded(
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
child: Text(
|
children: [
|
||||||
"$responseStatus: ${message ?? '-'}",
|
kHSpacer10,
|
||||||
softWrap: false,
|
Expanded(
|
||||||
overflow: TextOverflow.ellipsis,
|
child: Text(
|
||||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
"$responseStatus: ${message ?? '-'}",
|
||||||
fontFamily: kCodeStyle.fontFamily,
|
softWrap: false,
|
||||||
color: getResponseStatusCodeColor(
|
overflow: TextOverflow.ellipsis,
|
||||||
responseStatus,
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
brightness: Theme.of(context).brightness,
|
fontFamily: kCodeStyle.fontFamily,
|
||||||
),
|
color: getResponseStatusCodeColor(
|
||||||
),
|
responseStatus,
|
||||||
),
|
brightness: Theme.of(context).brightness,
|
||||||
),
|
),
|
||||||
FilledButton.tonalIcon(
|
),
|
||||||
style: FilledButton.styleFrom(
|
|
||||||
padding: kPh12,
|
|
||||||
minimumSize: const Size(44, 44),
|
|
||||||
),
|
|
||||||
onPressed: () {
|
|
||||||
final model = ref.watch(selectedRequestModelProvider
|
|
||||||
.select((value) => value?.httpResponseModel));
|
|
||||||
if (model == null) return;
|
|
||||||
final body = (model.sseOutput?.isNotEmpty ?? false)
|
|
||||||
? model.sseOutput?.join("\n")
|
|
||||||
: model.formattedBody ?? model.body;
|
|
||||||
showCustomDialog(context, body ?? "");
|
|
||||||
},
|
|
||||||
icon: Icon(
|
|
||||||
Icons.generating_tokens,
|
|
||||||
),
|
|
||||||
label: const SizedBox(
|
|
||||||
child: Text(
|
|
||||||
kLabelGenerateUI,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
kHSpacer10,
|
|
||||||
Text(
|
|
||||||
humanizeDuration(time),
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
|
||||||
fontFamily: kCodeStyle.fontFamily,
|
|
||||||
color: Theme.of(context).colorScheme.secondary,
|
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
kHSpacer10,
|
||||||
|
Text(
|
||||||
|
humanizeDuration(time),
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
|
fontFamily: kCodeStyle.fontFamily,
|
||||||
|
color: Theme.of(context).colorScheme.secondary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
kHSpacer10,
|
||||||
|
showClearButton
|
||||||
|
? ClearResponseButton(
|
||||||
|
onPressed: onClearResponse,
|
||||||
|
)
|
||||||
|
: const SizedBox.shrink(),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
kHSpacer10,
|
Row(
|
||||||
showClearButton
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
? ClearResponseButton(
|
children: [
|
||||||
onPressed: onClearResponse,
|
FilledButton.tonalIcon(
|
||||||
)
|
style: FilledButton.styleFrom(
|
||||||
: const SizedBox.shrink(),
|
padding: kPh12,
|
||||||
|
minimumSize: const Size(44, 44),
|
||||||
|
),
|
||||||
|
onPressed: () async {
|
||||||
|
final requestModel = ref.watch(selectedRequestModelProvider
|
||||||
|
.select((value) => value?.httpRequestModel));
|
||||||
|
final responseModel = ref.watch(selectedRequestModelProvider
|
||||||
|
.select((value) => value?.httpResponseModel));
|
||||||
|
|
||||||
|
if (requestModel == null) return;
|
||||||
|
if (responseModel == null) {
|
||||||
|
print("AA");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String? bodyTXT;
|
||||||
|
Map? bodyJSON;
|
||||||
|
List<Map>? bodyFormData;
|
||||||
|
|
||||||
|
if (requestModel.bodyContentType == ContentType.formdata) {
|
||||||
|
bodyFormData = requestModel.formDataMapList;
|
||||||
|
} else if (requestModel.bodyContentType ==
|
||||||
|
ContentType.json) {
|
||||||
|
bodyJSON = jsonDecode(requestModel.body.toString());
|
||||||
|
} else {
|
||||||
|
bodyTXT = requestModel.body!;
|
||||||
|
}
|
||||||
|
|
||||||
|
final reqDesModel = APIDashRequestDescription(
|
||||||
|
endpoint: requestModel.url,
|
||||||
|
method: requestModel.method.name.toUpperCase(),
|
||||||
|
responseType: responseModel.contentType.toString(),
|
||||||
|
headers: requestModel.headersMap,
|
||||||
|
response: responseModel.body,
|
||||||
|
formData: bodyFormData,
|
||||||
|
bodyTXT: bodyTXT,
|
||||||
|
bodyJSON: bodyJSON,
|
||||||
|
);
|
||||||
|
|
||||||
|
print(reqDesModel.generateREQDATA);
|
||||||
|
return;
|
||||||
|
|
||||||
|
final x = await APIDashAgentCaller.instance.call(
|
||||||
|
APIToolFunctionGenerator(),
|
||||||
|
ref: ref,
|
||||||
|
input: AgentInputs(variables: {
|
||||||
|
'REQDATA': reqDesModel.generateREQDATA,
|
||||||
|
'TARGET_LANGUAGE': 'JAVASCRIPT'
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
print(x);
|
||||||
|
|
||||||
|
// print(reqDesModel.generateREQDATA);
|
||||||
|
|
||||||
|
// final model = ref.watch(selectedRequestModelProvider
|
||||||
|
// .select((value) => value?.httpResponseModel));
|
||||||
|
// showCustomDialog(context, model?.formattedBody ?? "");
|
||||||
|
},
|
||||||
|
icon: Icon(
|
||||||
|
Icons.token_outlined,
|
||||||
|
),
|
||||||
|
label: const SizedBox(
|
||||||
|
child: Text(
|
||||||
|
"Generate Tool",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
kHSpacer10,
|
||||||
|
FilledButton.tonalIcon(
|
||||||
|
style: FilledButton.styleFrom(
|
||||||
|
padding: kPh12,
|
||||||
|
minimumSize: const Size(44, 44),
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
final model = ref.watch(selectedRequestModelProvider
|
||||||
|
.select((value) => value?.httpResponseModel));
|
||||||
|
if (model == null) return;
|
||||||
|
final body = (model.sseOutput?.isNotEmpty ?? false)
|
||||||
|
? model.sseOutput?.join("\n")
|
||||||
|
: model.formattedBody ?? model.body;
|
||||||
|
showCustomDialog(context, body ?? "");
|
||||||
|
},
|
||||||
|
icon: Icon(
|
||||||
|
Icons.generating_tokens,
|
||||||
|
),
|
||||||
|
label: const SizedBox(
|
||||||
|
child: Text(
|
||||||
|
kLabelGenerateUI,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
kHSpacer10,
|
||||||
|
],
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user