Skip to content

Instantly share code, notes, and snippets.

@npilk
Created May 21, 2023 03:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save npilk/bdcb5f97ed1d23f9fdb8ec434c61419d to your computer and use it in GitHub Desktop.
Save npilk/bdcb5f97ed1d23f9fdb8ec434c61419d to your computer and use it in GitHub Desktop.
Alternate custom web search script that uses GPT-3.5-turbo to determine whether queries should be sent to an LLM or search engine
// Cloudflare Worker script to automatically redirect search queries based on trigger words
addEventListener("fetch", event => {
event.respondWith(handleRequest(event.request))
})
// status code for redirect response; need something that won't cache
var statuscode = 303
// defining base URLs for search engines
var googleurl = "https://www.google.com/search?q="
var ddgurl = "https://www.duckduckgo.com/html/?q="
var duckyurl = "https://www.duckduckgo.com/html/?q=!+"
var openaiurl = "https://api.openai.com/v1/chat/completions"
// if any of these words are in the query, show Google search results
var filterwords = ["django","python","jquery","javascript","error"]
// we only want to match these words, not something like "errors"
var regex_string = "\\b(" + filterwords.join("|") + ")\\b"
async function postChat(url = "", data = {}) {
// Default options are marked with *
const response = fetch(url, {
method: "POST", // *GET, POST, PUT, DELETE, etc.
headers: {
"Content-Type": "application/json",
"Authorization": API_AUTH,
},
body: JSON.stringify(data), // body data type must match "Content-Type" header
});
return response;
}
async function handleRequest(request) {
// get the query from the page URL
const { searchParams } = new URL(request.url);
var query = searchParams.get("q");
if (query == null) {
var html = `<!DOCTYPE html>
<body>
<h1>Search</h1>
<p>Enter search:</p>
</body>`;
return new Response(html, {
headers: {
"content-type": "text/html; charset=UTF-8",
},
});
} else {
var lastchar = query.slice(-1);
var test = (query.slice(-1) == "?");
}
// if the query contains any bangs, pass to DDG
if (new RegExp(/!([a-zA-Z]+)\b/).test(query)) {
var url = ddgurl + encodeURIComponent(query).replace(/%20/g,"+");
return Response.redirect(url, statuscode)
// if there aren't any bangs pass to GPT
} else {
var queryAssess = "Query: " + query + "Answer: "
const assessData = {
"model": "gpt-3.5-turbo",
"messages": [
{"role": "system", "content": "You are a search query categorizer who identifies which queries would be better answered by an agent and which would be better for a search engine. Queries formed as sentences, questions, or directives will usually be better for an agent. Please reply with 'Agent' if the query would be best answered by an Agent and 'Search' if it would be best routed to a search engine. Examples: Query: How do I hang a picture? Answer: Agent Query: chinese food near me Answer: Search Query: javascript how to slice a string Answer: Search Query: give me some ideas for Mother's Day presents Answer: Agent"},
{"role": "user", "content": queryAssess}
],
"temperature": 0.6 };
var assessResponse = await postChat(url = "https://api.openai.com/v1/chat/completions", assessData);
console.log(assessResponse);
var assessResult = await assessResponse.json();
console.log(assessResult);
if (assessResult["choices"][0]["message"]["content"].includes("Agent")) {
const queryData = {
"model": "gpt-3.5-turbo",
"messages": [
{"role": "system", "content": "You are a helpful assistant. Please answer the user's questions concisely."},
{"role": "user", "content": query}
],
"temperature": 0.7 };
console.log('query:');
console.log(queryData);
var response = await postChat(url = "https://api.openai.com/v1/chat/completions", queryData);
console.log(response);
var resultData = await response.json();
console.log(resultData);
try {
var message = resultData["choices"][0]["message"]["content"];
} catch(error) {
var message = "An error occurred. " + error
}
var html = `<!DOCTYPE html>
<head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Search | ` + query + `</title>
<link rel="stylesheet" href="https://www.npilk.com/bootstrap4_slim.min.css">
<link rel="stylesheet" href="https://notes.npilk.com/blogstyles.css">
<link rel="shortcut icon" type="image/png" href="https://www.npilk.com/resources/favicon.png"/>
</head>
<body>
<div class="container-fluid px-3 main-block mt-5">
<h1>Search results</h1>
<p><i>` + query + `</i></p>
<p>Response: ` + message + `</p>
</div>
</body>`;
return new Response(html, {
headers: {
"content-type": "text/html; charset=UTF-8",
},
});
}
// if any words are on our filter list, send the query to Google
else if (new RegExp(regex_string).test(query)) {
var url = googleurl + encodeURIComponent(query).replace(/%20/g,"+");
return Response.redirect(url, statuscode)
// otherwise, pass the query to "I'm Feeling Ducky"
} else {
var url = duckyurl + encodeURIComponent(query).replace(/%20/g,"+");
return Response.redirect(url, statuscode)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment