mirror of
https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
synced 2025-05-23 22:20:23 +09:00
fix: 修复问题
This commit is contained in:
parent
e3d3eed74b
commit
a5bc735548
@ -18,10 +18,7 @@ export class DuckDuckGo extends Tool {
|
||||
|
||||
const results = searchResults.results
|
||||
.slice(0, this.maxResults)
|
||||
.map(
|
||||
({ title, description, url }) =>
|
||||
`title:${title}\ncontent:${htmlToText(description)}\nurl:${url}`,
|
||||
)
|
||||
.map(({ title, description, url }) => htmlToText(description))
|
||||
.join("\n\n");
|
||||
|
||||
return results;
|
||||
|
70
app/api/langchain-tools/http_get.ts
Normal file
70
app/api/langchain-tools/http_get.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import { htmlToText } from "html-to-text";
|
||||
import { Tool } from "langchain/tools";
|
||||
|
||||
export interface Headers {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
export interface RequestTool {
|
||||
headers: Headers;
|
||||
maxOutputLength?: number;
|
||||
timeout: number;
|
||||
}
|
||||
|
||||
export class HttpGetTool extends Tool implements RequestTool {
|
||||
name = "http_get";
|
||||
|
||||
maxOutputLength = Infinity;
|
||||
|
||||
timeout = 10000;
|
||||
|
||||
constructor(
|
||||
public headers: Headers = {},
|
||||
{ maxOutputLength }: { maxOutputLength?: number } = {},
|
||||
{ timeout }: { timeout?: number } = {},
|
||||
) {
|
||||
super(...arguments);
|
||||
|
||||
this.maxOutputLength = maxOutputLength ?? this.maxOutputLength;
|
||||
this.timeout = timeout ?? this.timeout;
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
async _call(input: string) {
|
||||
try {
|
||||
const res = await this.fetchWithTimeout(
|
||||
input,
|
||||
{
|
||||
headers: this.headers,
|
||||
},
|
||||
this.timeout,
|
||||
);
|
||||
let text = await res.text();
|
||||
text = htmlToText(text);
|
||||
text = text.slice(0, this.maxOutputLength);
|
||||
console.log(text);
|
||||
return text;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return (error as Error).toString();
|
||||
}
|
||||
}
|
||||
|
||||
async fetchWithTimeout(
|
||||
resource: RequestInfo | URL,
|
||||
options = {},
|
||||
timeout: number = 30000,
|
||||
) {
|
||||
const controller = new AbortController();
|
||||
const id = setTimeout(() => controller.abort(), timeout);
|
||||
const response = await fetch(resource, {
|
||||
...options,
|
||||
signal: controller.signal,
|
||||
});
|
||||
clearTimeout(id);
|
||||
return response;
|
||||
}
|
||||
|
||||
description = `A portal to the internet. Use this when you need to get specific content from a website.
|
||||
Input should be a url string (i.e. "https://www.google.com"). The output will be the text response of the GET request.`;
|
||||
}
|
@ -17,6 +17,7 @@ import { initializeAgentExecutorWithOptions } from "langchain/agents";
|
||||
import { SerpAPI } from "langchain/tools";
|
||||
import { Calculator } from "langchain/tools/calculator";
|
||||
import { DuckDuckGo } from "@/app/api/langchain-tools/duckduckgo";
|
||||
import { HttpGetTool } from "@/app/api/langchain-tools/http_get";
|
||||
|
||||
const serverConfig = getServerSideConfig();
|
||||
|
||||
@ -36,6 +37,7 @@ interface RequestBody {
|
||||
}
|
||||
|
||||
class ResponseBody {
|
||||
isSuccess: boolean = true;
|
||||
message!: string;
|
||||
isToolMessage: boolean = false;
|
||||
toolName?: string;
|
||||
@ -73,11 +75,17 @@ async function handle(req: NextRequest) {
|
||||
);
|
||||
}
|
||||
},
|
||||
// async handleChainError(err, runId, parentRunId, tags) {
|
||||
// console.log("writer error");
|
||||
// await writer.ready;
|
||||
// await writer.abort(err);
|
||||
// },
|
||||
async handleChainError(err, runId, parentRunId, tags) {
|
||||
console.log(err, "writer error");
|
||||
var response = new ResponseBody();
|
||||
response.isSuccess = false;
|
||||
response.message = err;
|
||||
await writer.ready;
|
||||
await writer.write(
|
||||
encoder.encode(`data: ${JSON.stringify(response)}\n\n`),
|
||||
);
|
||||
await writer.close();
|
||||
},
|
||||
async handleChainEnd(outputs, runId, parentRunId, tags) {
|
||||
await writer.ready;
|
||||
await writer.close();
|
||||
@ -87,9 +95,15 @@ async function handle(req: NextRequest) {
|
||||
// await writer.close();
|
||||
},
|
||||
async handleLLMError(e: Error) {
|
||||
console.log("writer error");
|
||||
console.log(e, "writer error");
|
||||
var response = new ResponseBody();
|
||||
response.isSuccess = false;
|
||||
response.message = e.message;
|
||||
await writer.ready;
|
||||
await writer.abort(e);
|
||||
await writer.write(
|
||||
encoder.encode(`data: ${JSON.stringify(response)}\n\n`),
|
||||
);
|
||||
await writer.close();
|
||||
},
|
||||
handleLLMStart(llm, _prompts: string[]) {
|
||||
// console.log("handleLLMStart: I'm the second handler!!", { llm });
|
||||
@ -115,6 +129,14 @@ async function handle(req: NextRequest) {
|
||||
);
|
||||
} catch (ex) {
|
||||
console.error("[handleAgentAction]", ex);
|
||||
var response = new ResponseBody();
|
||||
response.isSuccess = false;
|
||||
response.message = (ex as Error).message;
|
||||
await writer.ready;
|
||||
await writer.write(
|
||||
encoder.encode(`data: ${JSON.stringify(response)}\n\n`),
|
||||
);
|
||||
await writer.close();
|
||||
}
|
||||
},
|
||||
handleToolStart(tool, input) {
|
||||
@ -134,8 +156,9 @@ async function handle(req: NextRequest) {
|
||||
|
||||
const tools = [
|
||||
searchTool,
|
||||
new RequestsGetTool(),
|
||||
new RequestsPostTool(),
|
||||
new HttpGetTool(),
|
||||
// new RequestsGetTool(),
|
||||
// new RequestsPostTool(),
|
||||
new Calculator(),
|
||||
];
|
||||
|
||||
@ -175,14 +198,12 @@ async function handle(req: NextRequest) {
|
||||
maxIterations: 3,
|
||||
memory: memory,
|
||||
});
|
||||
executor
|
||||
.call(
|
||||
{
|
||||
input: reqBody.messages.slice(-1)[0].content,
|
||||
},
|
||||
[handler],
|
||||
)
|
||||
.catch((e: Error) => console.error(e));
|
||||
executor.call(
|
||||
{
|
||||
input: reqBody.messages.slice(-1)[0].content,
|
||||
},
|
||||
[handler],
|
||||
);
|
||||
|
||||
console.log("returning response");
|
||||
return new Response(transformStream.readable, {
|
||||
|
@ -2,7 +2,6 @@ import { getClientConfig } from "../config/client";
|
||||
import { ACCESS_CODE_PREFIX } from "../constant";
|
||||
import { ChatMessage, ModelType, useAccessStore } from "../store";
|
||||
import { ChatGPTApi } from "./platforms/openai";
|
||||
import { DuckDuckGoSearch } from "./tools/ddg_search";
|
||||
|
||||
export const ROLES = ["system", "user", "assistant"] as const;
|
||||
export type MessageRole = (typeof ROLES)[number];
|
||||
@ -80,11 +79,9 @@ export abstract class ToolApi {
|
||||
|
||||
export class ClientApi {
|
||||
public llm: LLMApi;
|
||||
public searchTool: ToolApi;
|
||||
|
||||
constructor() {
|
||||
this.llm = new ChatGPTApi();
|
||||
this.searchTool = new DuckDuckGoSearch();
|
||||
}
|
||||
|
||||
config() {}
|
||||
|
@ -23,13 +23,6 @@ export interface OpenAIListModelResponse {
|
||||
}>;
|
||||
}
|
||||
|
||||
interface LangChainAgentResponse {
|
||||
message: string;
|
||||
isToolMessage: boolean;
|
||||
toolName?: string;
|
||||
toolInput?: object;
|
||||
}
|
||||
|
||||
export class ChatGPTApi implements LLMApi {
|
||||
private disableListModels = true;
|
||||
|
||||
@ -165,6 +158,7 @@ export class ChatGPTApi implements LLMApi {
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("[Request] parse error", text, msg);
|
||||
throw e;
|
||||
}
|
||||
},
|
||||
onclose() {
|
||||
@ -296,14 +290,15 @@ export class ChatGPTApi implements LLMApi {
|
||||
if (msg.data === "[DONE]" || finished) {
|
||||
return finish();
|
||||
}
|
||||
let response: LangChainAgentResponse = JSON.parse(msg.data);
|
||||
let response = JSON.parse(msg.data);
|
||||
if (!response.isSuccess) {
|
||||
console.error("[Request]", response, msg);
|
||||
throw Error(response.message);
|
||||
}
|
||||
try {
|
||||
if (response && !response.isToolMessage) {
|
||||
responseText += response.message;
|
||||
options.onUpdate?.(
|
||||
responseText,
|
||||
JSON.stringify(response.toolInput),
|
||||
);
|
||||
options.onUpdate?.(responseText, response.message);
|
||||
} else {
|
||||
options.onToolUpdate?.(response.toolName!, response.message);
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
import { ToolApi, getHeaders } from "../api";
|
||||
|
||||
export class DuckDuckGoSearch implements ToolApi {
|
||||
name = "duckduckgo_search";
|
||||
description =
|
||||
"A wrapper around DuckDuckGo Search.Useful for when you need to answer questions about current events.Input should be a search query.";
|
||||
|
||||
async call(input: string): Promise<string> {
|
||||
const res = await fetch(`/api/tools/ddg?query=${input}`, {
|
||||
method: "GET",
|
||||
headers: getHeaders(),
|
||||
});
|
||||
return await res.json();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user