diff --git a/lib/core/util/chat_title.dart b/lib/core/util/chat_title.dart index 677a454..02557b0 100644 --- a/lib/core/util/chat_title.dart +++ b/lib/core/util/chat_title.dart @@ -5,9 +5,9 @@ abstract final class ChatTitleUtil { static final claudeEndReg = RegExp(r'\[\]\(ID:\d+\|UUID:\S+'); - static const toolPrompt = ''' -Only returns the toolCall part. -If there is no toolCall section returned, return the message as empty.'''; +// static const toolPrompt = ''' +// Only returns the toolCall part. +// If there is no toolCall section returned, return the message as empty.'''; static const titlePrompt = ''' Generate a title for the user content behind `$userCotentLocator` with requirements: diff --git a/lib/core/util/tool_func/func/http.dart b/lib/core/util/tool_func/func/http.dart index ac3578b..367110f 100644 --- a/lib/core/util/tool_func/func/http.dart +++ b/lib/core/util/tool_func/func/http.dart @@ -9,7 +9,24 @@ final class TfHttpReq extends ToolFunc { description: ''' Send an HTTP request. It can be used for searching, downloading, etc. -If user wants to search, use `bing.com` as the search engine and set `forSearch` to true. + +If user want to access some content having an json API, use the API directly. +Such as api.github.com. You can use all the APIs that you(AI model) know. + + +If users wants to search: +- set `forSearch` to true +- set `url` to search engine's url +- set `headers` to search engine's headers, includes cookies, headers and etc. + +Example search engines: +- Google: `https://www.google.com/search?q=` +- Baidu: `https://www.baidu.com/s?wd=` +- Bing: `https://www.bing.com/search?q=` +Default: +- user's language is Chinese: Baidu +- Non-Chinese: Google + Both request/response body is String. If json, encode it into String. If blob, encode it into base64 String.''', @@ -130,21 +147,25 @@ If blob, encode it into base64 String.''', if (count++ > 5) break; final url = entry.value; log('Http $method -> $url'); - final resp = await myDio.request( - entry.value, - options: Options( - method: 'GET', - maxRedirects: followRedirects, - validateStatus: (_) => true, - responseType: ResponseType.plain, - ), - ); - - final data = resp.data; - if (data is! String) continue; - final html = await compute(_filterHtmlBody, data); - if (html != null) { - respBody += html; + try { + final resp = await myDio.request( + entry.value, + options: Options( + method: 'GET', + maxRedirects: followRedirects, + validateStatus: (_) => true, + responseType: ResponseType.plain, + ), + ); + + final data = resp.data; + if (data is! String) continue; + final html = await compute(_filterHtmlBody, data); + if (html != null) { + respBody += html; + } + } catch (e) { + log('Http $method -> ${l10n.error}: $e'); } } } @@ -161,3 +182,55 @@ If blob, encode it into base64 String.''', return [ChatContent.text(respBody)]; } } + +/// Only return the content insides body tag as a map. +Map _filterHtmlUrls(String html) { + // Remove the first line of + if (html.startsWith('') + 1); + } + final doc = html_parser.parse(html); + final aInBody = doc.querySelectorAll('body a'); + final map = {}; + // Find all tag with href. + for (final a in aInBody) { + var href = a.attributes['href']; + if (href == null) continue; + // If there is no complete url in href, ignore it. + // Usually, the uncomplete url is a relative path for the search engine. + if (!httpReg.hasMatch(href)) continue; + final title = a.text; + // `/url?q=` is the query string for google search result. + if (href.startsWith('/url?q=')) { + final uri = Uri.parse(href); + href = uri.queryParameters['q'] ?? href; + } + map[title] = href; + } + return map; +} + +/// Return all text content insides body tag. +String? _filterHtmlBody(String raw) { + final doc = html_parser.parse(raw); + final body = doc.querySelector('body'); + final text = body?.text; + if (text == null || text.isEmpty) return null; + + final lines = text.split('\n'); + final rmIdxs = []; + for (var i = 0; i < lines.length; i++) { + final line = lines[i]; + if (line.trim().isEmpty) { + rmIdxs.add(i); + } + } + + for (var i = rmIdxs.length - 1; i >= 0; i--) { + lines.removeAt(rmIdxs[i]); + } + + return lines.join('\n'); +} + +final httpReg = RegExp(r'https?://'); diff --git a/lib/core/util/tool_func/type.dart b/lib/core/util/tool_func/type.dart index bafe385..8b6283c 100644 --- a/lib/core/util/tool_func/type.dart +++ b/lib/core/util/tool_func/type.dart @@ -24,55 +24,3 @@ Future> _parseMap(dynamic value) async { if (value is Map) return value; return {}; } - -/// Only return the content insides body tag as a map. -Map _filterHtmlUrls(String html) { - // Remove the first line of - if (html.startsWith('') + 1); - } - final doc = html_parser.parse(html); - final aInBody = doc.querySelectorAll('body a'); - final map = {}; - // Find all tag with href. - for (final a in aInBody) { - var href = a.attributes['href']; - if (href == null) continue; - // If there is no complete url in href, ignore it. - // Usually, the uncomplete url is a relative path for the search engine. - if (!httpReg.hasMatch(href)) continue; - final title = a.text; - // `/url?q=` is the query string for google search result. - if (href.startsWith('/url?q=')) { - final uri = Uri.parse(href); - href = uri.queryParameters['q'] ?? href; - } - map[title] = href; - } - return map; -} - -/// Return all text content insides body tag. -String? _filterHtmlBody(String raw) { - final doc = html_parser.parse(raw); - final body = doc.querySelector('body'); - final text = body?.text; - if (text == null || text.isEmpty) return null; - - final lines = text.split('\n'); - final rmIdxs = []; - for (var i = 0; i < lines.length; i++) { - final line = lines[i]; - if (line.trim().isEmpty) { - rmIdxs.add(i); - } - } - - for (var i = rmIdxs.length - 1; i >= 0; i--) { - lines.removeAt(rmIdxs[i]); - } - - return lines.join('\n'); -} - -final httpReg = RegExp(r'https?://'); diff --git a/lib/view/page/home/req.dart b/lib/view/page/home/req.dart index 8da3b20..1ede03f 100644 --- a/lib/view/page/home/req.dart +++ b/lib/view/page/home/req.dart @@ -155,13 +155,7 @@ Future _onCreateText( try { resp = await OpenAI.instance.chat.create( model: config.model, - messages: [ - ChatHistoryItem.single( - role: ChatRole.system, - raw: ChatTitleUtil.toolPrompt, - ).toOpenAI, - ...msgs, - ], + messages: msgs, tools: availableTools, ); } catch (e, s) {