Skip to content

Commit

Permalink
Handle config
Browse files Browse the repository at this point in the history
  • Loading branch information
ascorbic committed Apr 8, 2023
1 parent d1ad75c commit eccebbc
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 31 deletions.
35 changes: 34 additions & 1 deletion config.edge.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,36 @@
export const appConfig = {
import type { AppConfig } from "./lib/edge/types.ts";

export const appConfig: AppConfig = {
// This should be set in an environment variable
// See https://platform.openai.com/account/api-keys
OPENAI_API_KEY: Deno.env.get("OPENAI_API_KEY") ?? "",

// The maximum number of message in the history to send to the API
// You should also set this in the config.browser.ts file.
historyLength: 8,

// The maximum length in characters of each message sent to the API
// You should also set this in the config.browser.ts file.
maxMessageLength: 1000,

// The config values sent to the OpenAI API
// You should not need to change these values
// See https://platform.openai.com/docs/api-reference/chat/create
apiConfig: {
temperature: 1,
},

// This is where the magic happens. See the README for details
// This can be a plain string if you'd prefer, or you can use
// information from the request or context to generate it.
systemPrompt: (_req, context) => `
You are the world's best movie critic. You are very strongly opinionated.
You have favorite movies and movies you hate. You are devoted to recommending movies
that a user will like. It is very important that the user enjoys your recommendations.
Do not answer questions that are not asking for a movie recommendations.
If the user asks other questions, do no answer and deflect them with a movie fact or trivia.
Respond with valid markdown. Put movie names in bold. Knowledge cutoff September 2021.
Current date: ${new Date().toDateString()}. User location: ${
context.geo.city
}, ${context.geo.country}`,
};
20 changes: 20 additions & 0 deletions lib/edge/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { ChatCompletionOptions } from "https://deno.land/x/[email protected]/mod.ts";
import type { Context } from "https://edge.netlify.com/";
export interface AppConfig {
// The maximum number of message in the history to send to the API
historyLength: number;

// The maximum length of each message sent to the API
maxMessageLength: number;

// See https://platform.openai.com/account/api-keys
OPENAI_API_KEY: string;

// This is where the magic happens. See the README for details
systemPrompt:
| string
| ((request: Request, Context: Context) => string | Promise<string>);

// See https://platform.openai.com/docs/api-reference/chat/create
apiConfig?: Omit<ChatCompletionOptions, "stream" | "model" | "messages">;
}
60 changes: 31 additions & 29 deletions netlify/edge-functions/chat.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,48 @@
import { Config } from "https://edge.netlify.com/";
import type { Config, Context } from "https://edge.netlify.com/";
import { getChatStream, sanitizeMessages } from "../../lib/edge/openai.ts";

const OPENAI_API_KEY = Deno.env.get("OPENAI_API_KEY");
import { appConfig } from "../../config.edge.ts";

const systemPrompt = [
"You are the world's best movie critic. A fusion of Roger Ebert, Mark Kermode",
"and all the best movie critics. You are very strongly opinionated.",
"You have favorite movies and movies you hate. You are devoted to recommending movies",
"that a user will like. It is very important that the user enjoys your recommendations.",
"Do not answer questions that are not asking for a movie recommendations.",
"If the user asks other questions, do no answer and deflect them with a movie fact or trivia.",
`Knowledge cutoff September 2021. Current date is ${new Date().toLocaleString()}`,
"Respond with valid markdown. Put movie names in bold",
].join(" ");

export default async function handler(request: Request): Promise<Response> {
if (!OPENAI_API_KEY) {
return new Response("OPENAI_API_KEY is not set", {
status: 500,
headers: {
"Content-Type": "text/plain",
},
});
}
const data = await request.json();
console.log(data);
if (!appConfig.OPENAI_API_KEY || !appConfig.systemPrompt) {
throw new Error(
"OPENAI_API_KEY and systemPrompt must be set in config.edge.ts"
);
}

const messages = sanitizeMessages(data?.messages ?? []);
export default async function handler(
request: Request,
context: Context
): Promise<Response> {
const prompt =
typeof appConfig.systemPrompt === "function"
? await appConfig.systemPrompt(request, context)
: appConfig.systemPrompt;

try {
const data = await request.json();

// This only trims the size of the messages, to avoid abuse of the API.
// You should do any extra validation yourself.
const messages = sanitizeMessages(
data?.messages ?? [],
appConfig.historyLength,
appConfig.maxMessageLength
);
const stream = await getChatStream(
{
// Optional. This can also be set to a real user id, session id or leave blank.
// See https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids
user: context.ip,
...appConfig.apiConfig,
messages: [
{
role: "system",
content: systemPrompt,
content: prompt,
},
...messages,
],
temperature: 1,
},
OPENAI_API_KEY ?? ""
appConfig.OPENAI_API_KEY ?? ""
);
return new Response(stream, {
headers: {
Expand All @@ -59,5 +61,5 @@ export default async function handler(request: Request): Promise<Response> {
}

export const config: Config = {
path: "/chat",
path: "/api/chat",
};
4 changes: 3 additions & 1 deletion src/hooks/use-chat.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { fetchEventSource } from "@fortaine/fetch-event-source";
import { useState, useMemo } from "react";
import { appConfig } from "../../config.browser";

const API_PATH = "/api/chat";
interface ChatMessage {
role: "user" | "assistant";
content: string;
Expand Down Expand Up @@ -64,7 +66,7 @@ export function useChat() {

// This is like an EventSource, but allows things like
// POST requests and headers
fetchEventSource("/chat", {
fetchEventSource(API_PATH, {
body,
method: "POST",
signal: abortController.signal,
Expand Down

0 comments on commit eccebbc

Please sign in to comment.