Skip to content

Commit

Permalink
adds server, fixes server and frontend code to include field_name and…
Browse files Browse the repository at this point in the history
… tool_name
  • Loading branch information
mrmps committed Jan 29, 2023
1 parent eb65e9d commit 31f632e
Show file tree
Hide file tree
Showing 41 changed files with 566 additions and 46 deletions.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions pages/api/generate.ts → client/pages/api/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ const handler = async (req: NextRequest): Promise<Response> => {
const { toolName, formData } = (await req.json()) as {
toolName: string;
formData: { [key: string]: string };
};
};

// if (!prompt) {
// return new Response("No prompt in the request", { status: 400 });
Expand All @@ -140,7 +140,7 @@ const handler = async (req: NextRequest): Promise<Response> => {
// stream: true,
// n: 1,
// };


const payload = await fetch('http://localhost:5001/toolModel', {
method: 'POST',
Expand Down
File renamed without changes.
220 changes: 176 additions & 44 deletions pages/tools/[tool].tsx → client/pages/tools/[tool].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,24 @@ const Tool: NextPage<Props> = ({ schema }) => {
"Professional"
);
const [generatedBios, setGeneratedBios] = useState<String>("");
const [generatedBios2, setGeneratedBios2] = useState<String>("");
const initialFormData = schema.fields.reduce((formData, field) => {
formData[field.name] = field.type === "select" && field.options ? field.options[0].value : "";
formData[field.field_name] = field.type === "select" && field.options ? field.options[0].value : "";
return formData;
}, {} as FormData);
//TODO is it ok to have it as type string instead of String?
const [generatedResponsesList, setGeneratedResponsesList] = useState<string[]>([]);

const [formData, setFormData] = useState<FormData>(initialFormData);

console.log("Streamed response: ", generatedBios);
console.log("Streamed response: ", generatedResponsesList);

const prompt =
vibe === "Funny"
? `Generate 2 funny twitter bios with no hashtags and clearly labeled "1." and "2.". Make sure there is a joke in there and it's a little ridiculous. Make sure each generated bio is at max 20 words and base it on this context: ${bio}${bio.slice(-1) === "." ? "" : "."
}`
: `Generate 2 ${vibe} twitter bios with no hashtags and clearly labeled "1." and "2.". Make sure each generated bio is at least 14 words and at max 20 words and base them on this context: ${bio}${bio.slice(-1) === "." ? "" : "."
}`;
// const prompt =
// vibe === "Funny"
// ? `Generate 2 funny twitter bios with no hashtags and clearly labeled "1." and "2.". Make sure there is a joke in there and it's a little ridiculous. Make sure each generated bio is at max 20 words and base it on this context: ${bio}${bio.slice(-1) === "." ? "" : "."
// }`
// : `Generate 2 ${vibe} twitter bios with no hashtags and clearly labeled "1." and "2.". Make sure each generated bio is at least 14 words and at max 20 words and base them on this context: ${bio}${bio.slice(-1) === "." ? "" : "."
// }`;

const handleSelect = (event: React.ChangeEvent<HTMLSelectElement>, formDataName: string) => {
const { name, value } = event.target;
Expand All @@ -63,13 +66,13 @@ const Tool: NextPage<Props> = ({ schema }) => {
input = (
<>
<div className="flex mb-5 items-center space-x-3">
<Image src={`/${index+1}-icon.png`} width={30} height={30} alt={`${index+1} icon`} />
<p className="text-left font-medium">Select your vibe.</p>
<Image src={`/${index + 1}-icon.png`} width={30} height={30} alt={`${index + 1} icon`} />
<p className="text-left font-medium">{field.command}</p>
</div>
<div className="block mb-5">
<DropDownNew
value={formData[field.name]}
name={field.name}
value={formData[field.field_name]}
name={field.field_name}
options={field.options}
formData={formData}
setFormData={(newFormData: SetStateAction<FormData>) => setFormData(newFormData)}
Expand All @@ -87,46 +90,129 @@ const Tool: NextPage<Props> = ({ schema }) => {
<>
<div className="flex items-center space-x-3">
<Image
src={`/${index+1}-icon.png`}
src={`/${index + 1}-icon.png`}
width={30}
height={30}
alt={`${index+1} icon`}
alt={`${index + 1} icon`}
className="mb-5 sm:mb-0"
/>
<p className="text-left font-medium">
Copy your current bio{" "}
<span className="text-slate-500">
{field.command}{" "}
{/* <span className="text-slate-500">
(or write a few sentences about yourself)
</span>
.
</span> */}
{/* . */}
</p>
</div>
<textarea
value={formData[field.name]}
onChange={(e) => { handleChange(e, field.name) }}
value={formData[field.field_name]}
onChange={(e) => { handleChange(e, field.field_name) }}
rows={4}
className="w-full rounded-md border-gray-300 shadow-sm focus:border-black focus:ring-black my-5"
placeholder={
"e.g. Senior Developer Advocate @vercel. Tweeting about web development, AI, and React / Next.js. Writing nutlope.substack.com."
field.placeholder ? field.placeholder : `Enter your ${field.field_name} here`
}
/>
</>
);
}
return (
<div>
{input}
{input}
</div>
)
});

// const generateBio = async (e: any) => {
// e.preventDefault();
// setGeneratedBios("");
// setLoading(true);
// const toolPrompt = schema.prompt;
// const payload = {
// toolName: schema.name,
// formData: formData
// }
// const response = await fetch("/api/generate", {
// method: "POST",
// headers: {
// "Content-Type": "application/json",
// },
// body: JSON.stringify(payload),
// });
// console.log("Edge function returned.");

// if (!response.ok) {
// throw new Error(response.statusText);
// }

// // This data is a ReadableStream
// const data = response.body;
// if (!data) {
// return;
// }

// const reader = data.getReader();
// const decoder = new TextDecoder();

// let done = false;
// let tempState = "";

// while (!done) {
// const { value, done: doneReading } = await reader.read();
// done = doneReading;
// const newValue = decoder
// .decode(value)
// .replaceAll("data: ", "")
// .split("\n\n")
// .filter(Boolean);

// if (tempState) {
// newValue[0] = tempState + newValue[0];
// tempState = "";
// }

// newValue.forEach((newVal) => {
// if (newVal === "[DONE]") {
// return;
// }

// try {
// const json = JSON.parse(newVal) as {
// id: string;
// object: string;
// created: number;
// choices?: {
// text: string;
// index: number;
// logprobs: null;
// finish_reason: null | string;
// }[];
// model: string;
// };

// if (!json.choices?.length) {
// throw new Error("Something went wrong.");
// }

// const choice = json.choices[0];
// setGeneratedBios((prev) => prev + choice.text);
// } catch (error) {
// tempState = newVal;
// }
// });
// }

// setLoading(false);
// };
const generateBio = async (e: any) => {
e.preventDefault();
setGeneratedBios("");
setGeneratedBios2("");
setGeneratedResponsesList([]);
setLoading(true);
const toolPrompt = schema.prompt;
const payload = {
toolName: schema.name,
toolName: schema.tool_name,
formData: formData
}
const response = await fetch("/api/generate", {
Expand All @@ -148,6 +234,8 @@ const Tool: NextPage<Props> = ({ schema }) => {
return;
}



const reader = data.getReader();
const decoder = new TextDecoder();

Expand Down Expand Up @@ -191,17 +279,57 @@ const Tool: NextPage<Props> = ({ schema }) => {
throw new Error("Something went wrong.");
}

console.log("json", json)

const choice = json.choices[0];
setGeneratedBios((prev) => prev + choice.text);
console.log("choiceText", choice.text + " " + choice.index)
setGeneratedBios((prev) => choice.index == 0 ? prev + choice.text : prev);

// setGeneratedResponsesList((prev) => {
// prev[choice.index] = prev[choice.index] + choice.text;
// return prev;
// });
// setGeneratedResponsesList((prev) => {
// if (!prev[choice.index]) prev[choice.index] = ""; // check if there is already an element at that index, if not add an empty string
// prev[choice.index] = prev[choice.index] + choice.text;
// // console.log("prev");
// // console.log("")
// return prev;
// });
// setGeneratedResponsesList((prev) => {
// let currentValue = prev[choice.index] || ""; // check if there is already an element at that index, if not set currentValue to an empty string
// currentValue = choice.text;
// prev[choice.index] = currentValue;
// // console.log("dataIs", prev, currentValue, choice.text, choice.index)
// return prev;
// });
setGeneratedResponsesList(existingItems => {

if (!existingItems[choice.index]) existingItems[choice.index] = "";

return existingItems.map((item, j) => {

return j === choice.index ? item + choice.text : item

5 })});



// const choice2 = json.choices[1];
// console.log("json choices", json.choices)
// setGeneratedBios2((prev) => prev + choice2.text);
// console.log(generatedBios2)
} catch (error) {
tempState = newVal;
}
});
}


setLoading(false);
};


return (
<div className="flex max-w-5xl mx-auto flex-col items-center justify-center py-2 min-h-screen">
<Head>
Expand All @@ -211,28 +339,28 @@ const Tool: NextPage<Props> = ({ schema }) => {

<Header />
<main className="flex flex-1 w-full flex-col items-center justify-center text-center px-4 mt-12 sm:mt-20">
<a
{/* <a
className="flex max-w-fit items-center justify-center space-x-2 rounded-full border border-gray-300 bg-white px-4 py-2 text-sm text-gray-600 shadow-md transition-colors hover:bg-gray-100 mb-5"
href="https://github.com/Nutlope/twitterbio"
target="_blank"
rel="noopener noreferrer"
>
<Github />
<p>Star on GitHub</p>
</a>
</a> */}
<h1 className="sm:text-6xl mb-12 text-4xl max-w-2xl font-bold text-slate-900">
Generate your next Twitter bio in seconds
Generate your {schema.display_name} in seconds
</h1>

<div className="max-w-xl">
<div className="max-w-xl min-w-[77%]">
{formFields}

{!loading && (
<button
className="bg-black rounded-xl text-white font-medium px-4 py-2 sm:mt-8 mt-8 hover:bg-black/80 w-full"
onClick={(e) => generateBio(e)}
>
Generate your bio &rarr;
Create Content &rarr;
</button>
)}
{loading && (
Expand All @@ -253,30 +381,33 @@ const Tool: NextPage<Props> = ({ schema }) => {
<ResizablePanel>
<AnimatePresence mode="wait">
<motion.div className="space-y-10 my-10">
{generatedBios && !loading && (
{generatedResponsesList && !loading && (
<>
<div>
<h2 className="sm:text-4xl text-3xl font-bold text-slate-900 mx-auto">
Your generated bios
Your results
</h2>
</div>
<div className="space-y-8 flex flex-col items-center justify-center max-w-xl mx-auto">
{generatedBios
.substring(generatedBios.indexOf("1") + 3)
.split("2.")
.map((generatedBio) => {
{generatedResponsesList.map((generatedResponse) => {
const trimmedResponse = generatedResponse.trim().replace(/\\n/g, "\n")


// .substring(generatedBios.indexOf("1") + 3)
// .split("2.")
// .map((generatedBio) => {
return (
<div
className="bg-white rounded-xl shadow-md p-4 hover:bg-gray-100 transition cursor-copy border"
onClick={() => {
navigator.clipboard.writeText(generatedBio);
navigator.clipboard.writeText(trimmedResponse);
toast("Bio copied to clipboard", {
icon: "✂️",
});
}}
key={generatedBio}
key={trimmedResponse}
>
<p>{generatedBio}</p>
<p>{trimmedResponse}</p>
</div>
);
})}
Expand Down Expand Up @@ -311,21 +442,22 @@ const Tool: NextPage<Props> = ({ schema }) => {


interface ToolSchema {
name: string;
tool_name: string;
display_name: string;
fields: {
name: string;
field_name: string;
type: string;
label: string;
required: boolean;
options?: { value: string; label: string }[];
placeholder?: string;
command: string;
}[];
prompt: string;
}

interface ToolData {
name: string;
tool_name: string;
}

//TODO should this default be blog-idea-geenrator?
Expand All @@ -340,9 +472,9 @@ export const getStaticPaths: GetStaticPaths<{ tool: string }> = async () => {
const res = await fetch("http://localhost:5001/allTools");
const data = await res.json() as ToolData[];
const paths = data.map((tool) => {
return { params: { tool: tool.name } };
return { params: { tool: tool.tool_name } };
});
return { paths, fallback: false };
return { paths, fallback: true};
};


Expand Down
File renamed without changes.
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes.
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions server/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DATABASE_URL=postgresql://postgres:[email protected]:5763/railway
Loading

0 comments on commit 31f632e

Please sign in to comment.