Feat: add data type invoke (#5126)

### What problem does this PR solve?
```
Invoke agent
To be able to interact dynamically with the API, there is a customizable Data Type JSON or FormData, the default is JSON 
```

### Type of change

- [x] New Feature (non-breaking change which adds functionality)

---------

Co-authored-by: Kevin Hu <kevinhu.sh@gmail.com>
This commit is contained in:
so95 2025-02-27 15:15:33 +07:00 committed by GitHub
parent 7a6e70d6b3
commit 11de7599e5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 39 additions and 13 deletions

View File

@ -79,7 +79,6 @@ class ExeSQL(Generate, ABC):
ans = self.get_input() ans = self.get_input()
ans = "".join([str(a) for a in ans["content"]]) if "content" in ans else "" ans = "".join([str(a) for a in ans["content"]]) if "content" in ans else ""
ans = self._refactor(ans) ans = self._refactor(ans)
logging.info("db_type: ", self._param.db_type)
if self._param.db_type in ["mysql", "mariadb"]: if self._param.db_type in ["mysql", "mariadb"]:
db = pymysql.connect(db=self._param.database, user=self._param.username, host=self._param.host, db = pymysql.connect(db=self._param.database, user=self._param.username, host=self._param.host,
port=self._param.port, password=self._param.password) port=self._param.port, password=self._param.password)
@ -128,7 +127,6 @@ class ExeSQL(Generate, ABC):
single_sql = self._refactor(single_sql) single_sql = self._refactor(single_sql)
if self._loop > self._param.loop: if self._loop > self._param.loop:
sql_res.append({"content": "Can't query the correct data via SQL statement."}) sql_res.append({"content": "Can't query the correct data via SQL statement."})
# raise Exception("Maximum loop time exceeds. Can't query the correct data via SQL statement.")
db.close() db.close()
if not sql_res: if not sql_res:
return ExeSQL.be_output("") return ExeSQL.be_output("")

View File

@ -35,12 +35,14 @@ class InvokeParam(ComponentParamBase):
self.url = "" self.url = ""
self.timeout = 60 self.timeout = 60
self.clean_html = False self.clean_html = False
self.datatype = "json" # New parameter to determine data posting type
def check(self): def check(self):
self.check_valid_value(self.method.lower(), "Type of content from the crawler", ['get', 'post', 'put']) self.check_valid_value(self.method.lower(), "Type of content from the crawler", ['get', 'post', 'put'])
self.check_empty(self.url, "End point URL") self.check_empty(self.url, "End point URL")
self.check_positive_integer(self.timeout, "Timeout time in second") self.check_positive_integer(self.timeout, "Timeout time in second")
self.check_boolean(self.clean_html, "Clean HTML") self.check_boolean(self.clean_html, "Clean HTML")
self.check_valid_value(self.datatype.lower(), "Data post type", ['json', 'formdata']) # Check for valid datapost value
class Invoke(ComponentBase, ABC): class Invoke(ComponentBase, ABC):
@ -94,22 +96,36 @@ class Invoke(ComponentBase, ABC):
return Invoke.be_output(response.text) return Invoke.be_output(response.text)
if method == 'put': if method == 'put':
if self._param.datatype.lower() == 'json':
response = requests.put(url=url, response = requests.put(url=url,
json=args, json=args,
headers=headers, headers=headers,
proxies=proxies, proxies=proxies,
timeout=self._param.timeout) timeout=self._param.timeout)
else:
response = requests.put(url=url,
data=args,
headers=headers,
proxies=proxies,
timeout=self._param.timeout)
if self._param.clean_html: if self._param.clean_html:
sections = HtmlParser()(None, response.content) sections = HtmlParser()(None, response.content)
return Invoke.be_output("\n".join(sections)) return Invoke.be_output("\n".join(sections))
return Invoke.be_output(response.text) return Invoke.be_output(response.text)
if method == 'post': if method == 'post':
if self._param.datatype.lower() == 'json':
response = requests.post(url=url, response = requests.post(url=url,
json=args, json=args,
headers=headers, headers=headers,
proxies=proxies, proxies=proxies,
timeout=self._param.timeout) timeout=self._param.timeout)
else:
response = requests.post(url=url,
data=args,
headers=headers,
proxies=proxies,
timeout=self._param.timeout)
if self._param.clean_html: if self._param.clean_html:
sections = HtmlParser()(None, response.content) sections = HtmlParser()(None, response.content)
return Invoke.be_output("\n".join(sections)) return Invoke.be_output("\n".join(sections))

View File

@ -528,6 +528,7 @@ This auto-tag feature enhances retrieval by adding another layer of domain-speci
'Allows sentence rewriting with the specified language or defaults to the latest question if not selected.', 'Allows sentence rewriting with the specified language or defaults to the latest question if not selected.',
avatarHidden: 'Hide avatar', avatarHidden: 'Hide avatar',
locale: 'Locale', locale: 'Locale',
selectLanguage: 'Select a language',
reasoning: 'Reasoning', reasoning: 'Reasoning',
reasoningTip: reasoningTip:
'It will trigger reasoning process like Deepseek-R1/OpenAI o1. Integrates an agentic search process into the reasoning workflow, allowing models itself to dynamically retrieve external knowledge whenever they encounter uncertain information.', 'It will trigger reasoning process like Deepseek-R1/OpenAI o1. Integrates an agentic search process into the reasoning workflow, allowing models itself to dynamically retrieve external knowledge whenever they encounter uncertain information.',
@ -845,7 +846,7 @@ This auto-tag feature enhances retrieval by adding another layer of domain-speci
bingDescription: bingDescription:
'A component that searches from https://www.bing.com/, allowing you to specify the number of search results using TopN. It supplements the existing knowledge bases. Please note that this requires an API key from microsoft.com.', 'A component that searches from https://www.bing.com/, allowing you to specify the number of search results using TopN. It supplements the existing knowledge bases. Please note that this requires an API key from microsoft.com.',
apiKey: 'API KEY', apiKey: 'API KEY',
country: 'Country&Region', country: 'Country & Region',
language: 'Language', language: 'Language',
googleScholar: 'Google Scholar', googleScholar: 'Google Scholar',
googleScholarDescription: googleScholarDescription:
@ -1187,6 +1188,7 @@ This delimiter is used to split the input text into several text pieces echo of
addCategory: 'Add category', addCategory: 'Add category',
categoryName: 'Category name', categoryName: 'Category name',
nextStep: 'Next step', nextStep: 'Next step',
datatype: 'MINE type of the HTTP request',
insertVariableTip: `Enter / Insert variables`, insertVariableTip: `Enter / Insert variables`,
}, },
footer: { footer: {

View File

@ -606,6 +606,7 @@ export const initialInvokeValues = {
}`, }`,
proxy: 'http://', proxy: 'http://',
clean_html: false, clean_html: false,
datatype: 'json',
}; };
export const initialTemplateValues = { export const initialTemplateValues = {

View File

@ -69,6 +69,15 @@ const InvokeForm = ({ onValuesChange, form, node }: IOperatorForm) => {
> >
<Switch /> <Switch />
</Form.Item> </Form.Item>
<Form.Item name={'datatype'} label={t('flow.datatype')}>
<Select
options={[
{ value: 'json', label: 'application/json' },
{ value: 'formdata', label: 'multipart/form-data' },
]}
allowClear={true}
></Select>
</Form.Item>
<DynamicVariablesForm node={node}></DynamicVariablesForm> <DynamicVariablesForm node={node}></DynamicVariablesForm>
</Form> </Form>
</> </>