Created
May 21, 2023 03:11
-
-
Save npilk/0a2cdb90a226c4c3dd9ca754bb22c056 to your computer and use it in GitHub Desktop.
Cloudflare Worker script to automatically route queries to search engines or an LLM based on their content.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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", "css", "html"] | |
// 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 and it ends in a question mark, pass to GPT | |
} else if (query.slice(-1) == "?") { | |
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 reg = /```([^`]*)```/ | |
var rep = "<code>$1</code>" | |
var message = message.replace(reg, rep) | |
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://notes.npilk.com/bootstrap4_slim_blog.min.css"> | |
<link rel="stylesheet" href="https://notes.npilk.com/blogstyles.css"> | |
<link rel="stylesheet" href="https://notes.npilk.com/searchstyles.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"> | |
<div class="title"><h1>Search results</h1></div> | |
<div class="row user-query py-3 px-3"><p class="mb-0">🔎: ` + query + `</p></div> | |
<div class="row llm-reply py-3 px-3"><p class="mb-0">🤖: ` + message + `</p></div> | |
<div class="row py-3 px-3"> | |
<form action="https://www.npilk.com/search" method="GET" class="w-100"> | |
<div class="form-inline row"> | |
<div class="col-7 col-sm-9"> | |
<input type="search" placeholder="Enter another query..." id="q" name="q" class="form-control w-100" required> | |
</div> | |
<div class="col-5 col-sm-3"> | |
<button type="submit" class="form-control w-100 blog-button" placeholder="Enter another query..." id="submit"><strong>Search</strong></button> | |
</div> | |
</div> | |
</form> | |
</div> | |
</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