Skip to content

Commit

Permalink
Update bio template and enhance API functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
ehsanghaffar committed May 27, 2024
1 parent db08b5d commit 5d189ce
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 47 deletions.
27 changes: 20 additions & 7 deletions app/api/langchain/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,24 @@ import { z } from "zod";
import { createStructuredOutputChainFromZod } from "langchain/chains/openai_functions";
import { PromptTemplate } from "@langchain/core/prompts";
import { createOpenAIModel } from "@/libs/Langchain";
import { getIP } from "@/libs/utils";
import { createUserMessage, getIP } from "@/libs/utils";
import { checkRateLimit } from "@/store/rateLimitStore";

export const runtime = "edge";

const TEMPLATE = `Generate a compelling social media bio for user centered around context which them provide you.
The bio should be concise (150-200 characters) and capture the essence of user in a way that resonates with context.
Include elements that showcase personality, passion, and any relevant hashtags or keywords.
Feel free to add a touch of creativity to make it engaging.
const TEMPLATE = `Craft a personalized social media bio in Farsi (Persian) that captures the essence of the user, based on the specific vibe they choose: advanced, normal, or joke. This bio should weave together their personality, passions, and context into a narrative that aligns with their selected vibe.
Guidelines:
Language: The bio must be written in Farsi (Persian) to connect authentically with the target linguistic audience.
Vibe Options:
- advanced: Create a bio with a sophisticated, professional tone, showcasing achievements and expertise.
- normal: Ensure the bio is relatable and down-to-earth, highlighting everyday interests and personal traits.
- joke: Infuse the bio with humor, making it light-hearted and entertaining while still capturing the user's essence.
Length: Maintain a concise length of 150-200 characters to ensure the bio is both impactful and suitable for social media.
Content: Emphasize personality traits, passions, and include relevant keywords that resonate with their vibe choice and interests.
Creativity: Add a unique creative flair to make the bio captivating and reflective of the chosen vibe, ensuring it stands out.
{input}`;

Expand All @@ -29,7 +38,11 @@ export async function POST(req: NextRequest) {
return NextResponse.json({ error: "شما بیش از حد مجاز از سرویس استفاده کرده اید. چند ساعت بعد امتحان کنید" }, { status: 429 });
}

const messages = await req.json()
console.log(`USER IP: ${ip}`)

const userMessage = await req.json()

const messages = createUserMessage(userMessage)

const prompt = PromptTemplate.fromTemplate<{ input: string }>(TEMPLATE);

Expand All @@ -45,13 +58,13 @@ export async function POST(req: NextRequest) {

});

console.log(prompt)

const chain = createStructuredOutputChainFromZod(schema, {
llm: model,
prompt,
outputKey: "output",
});
console.log(chain)

const result = await chain.call({
input: messages,
Expand Down
69 changes: 33 additions & 36 deletions app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { useEffect, useRef, useState } from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import { Toaster, toast } from "react-hot-toast";
import { CheckSquare, Loader2 } from "lucide-react";
import { Textarea } from "@/components/ui/textarea";
import { toast as sonnar } from "sonner";
import { Button } from "@/components/ui/button";
import { GeneratedBio } from "@/types/types";
import { GeneratedBio, UserInputPayload, VibeType } from "@/types/types";


export type VibeType = "حرفه‌ای" | "معمولی" | "طنز";
let vibes: VibeType[] = ["حرفه‌ای", "معمولی", "طنز"];

const NEXT_PUBLIC_COOLDOWN_TIME = process.env.NEXT_PUBLIC_COOLDOWN_TIME
const NEXT_PUBLIC_COOLDOWN_TIME = process.env.NEXT_PUBLIC_COOLDOWN_TIME || 10

const BioGenerator = () => {
const [loading, setLoading] = useState(false);
Expand Down Expand Up @@ -51,9 +51,12 @@ const BioGenerator = () => {
}
};

const handleBioChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
setBio(event.target.value);
};
const handleBioChange = useCallback(
(event: React.ChangeEvent<HTMLTextAreaElement>) => {
setBio(event.target.value);
},
[]
);

const generateBio = async (
e: React.MouseEvent<HTMLButtonElement, MouseEvent>
Expand All @@ -74,21 +77,18 @@ const BioGenerator = () => {
setCooldownTimer(NEXT_PUBLIC_COOLDOWN_TIME);

try {
const messages = `Generate 2 ${vibe} biographies with no hashtags, in Persian language. ${
vibe === "طنز"
? "Make sure there is a joke in there and it's a little ridiculous."
: ""
} base them on this context: ${bio}${bio.slice(-1) === "." ? "" : " "}`;
const userInput: UserInputPayload = {
vibe,
bio,
};

const response = await fetch("/api/langchain", {
method: "POST",
mode: "no-cors",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(messages),
body: JSON.stringify(userInput),
});
console.log(response);

if (!response.ok) {
const errormessage = await response.json();
Expand All @@ -97,15 +97,13 @@ const BioGenerator = () => {
duration: 15000,
className: "text-base",
});
return;
}

if (response.ok) {
const data = await response.json();

const allBios: GeneratedBio[] = data.output;
setGeneratedBios(allBios);
scrollToBios();
}
const data = await response.json();
const allBios: GeneratedBio[] = data.output;
setGeneratedBios(allBios);
scrollToBios();
} catch (error) {
const err = error as Error;
console.log(err);
Expand All @@ -122,18 +120,17 @@ const BioGenerator = () => {
<>
<div className="flex flex-1 w-full flex-col items-center justify-center text-center px-4">
<div className="flex items-center">
<h2 className=" text-xl sm:text-2xl !leading-[4rem] font-bold text-slate-700">
با</h2>
<h2 className="text-xl sm:text-2xl !leading-[4rem] font-bold text-slate-700">
با
</h2>
<img
alt="ClubGPT icon"
src="/screenshot.png"
className="sm:w-36"
width={100}
height={50}
/>
<h2>
برای خودت بایو حـرفه‌ای بساز 😎
</h2>
alt="ClubGPT icon"
src="/screenshot.png"
className="sm:w-36"
width={100}
height={50}
/>
<h2>برای خودت بایو حـرفه‌ای بساز 😎</h2>
</div>
<div className="w-full sm:max-w-2xl mt-6 sm:mt-1 p-4 border rounded">
<div className="grid w-full gap-2">
Expand Down Expand Up @@ -195,7 +192,7 @@ const BioGenerator = () => {
className={`w-full rounded-md text-white font-semibold px-4 py-3 sm:mt-10 mt-8 ${
bio.length === 0 || isCooldown ? "bg-orange-600" : "bg-black"
} ${isCooldown ? "hover:bg-orange-600" : "hover:bg-black/70"}`}
onClick={(e) => generateBio(e)}
onClick={generateBio}
disabled={bio.length === 0}
>
{isCooldown
Expand All @@ -208,7 +205,7 @@ const BioGenerator = () => {
className="w-full bg-black rounded-lg text-white font-medium gap-2 px-4 py-2 sm:mt-10 mt-8 hover:bg-black/80"
disabled
>
در حال فکر کردن <Loader2 className="mr-2 h-4 w-4 animate-spin" />
در حال فکر کردن <Loader2 className="mr-2 h-4 w-4 animate-spin" />
</Button>
)}
</div>
Expand All @@ -218,7 +215,7 @@ const BioGenerator = () => {
toastOptions={{ duration: 2000 }}
/>
<hr className="h-px bg-gray-700 border-1 dark:bg-gray-700" />
<div className="my-4" >
<div className="my-4">
<div className="space-y-8 flex flex-col items-center justify-center max-w-xl mx-auto">
{generatedBios &&
generatedBios.map((bio) => (
Expand Down
4 changes: 2 additions & 2 deletions libs/Langchain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { ChatOpenAI } from "@langchain/openai";
export const createOpenAIModel = (apiKey: string) => {
const model = new ChatOpenAI({
apiKey: apiKey,
temperature: 0.8,
modelName: "gpt-4",
temperature: 0.1,
modelName: "gpt-4o",
});
return model;
}
17 changes: 15 additions & 2 deletions libs/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import ServerError from "@/types/types";
import ServerError, { UserInputPayload } from "@/types/types";
import { type ClassValue, clsx } from "clsx"
import { NextRequest, NextResponse } from "next/server";
import { twMerge } from "tailwind-merge"
Expand Down Expand Up @@ -35,7 +35,20 @@ export function getIP(req: NextRequest) {
if (!ip && forwardedFor) {
ip = forwardedFor.split(",").at(0) ?? "";
}

return ip;
}


export const createUserMessage = (input: UserInputPayload) => {
let userVibe = ""
if (input.vibe === "حرفه‌ای") {
userVibe = "Advanced"
} else if (input.vibe === "طنز") {
userVibe = "Joke"
} else if (input.vibe === "معمولی") {
userVibe = "Normal"
}
const messages = `Generate 2 ${userVibe} bios.base them on this context: ${input.bio}${input.bio.slice(-1) === "." ? "" : " "}`;

return messages
}
8 changes: 8 additions & 0 deletions types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,12 @@ export type JWTPayload = {
export interface GeneratedBio {
id: string;
content: string;
}

export type VibeType = "حرفه‌ای" | "معمولی" | "طنز";


export interface UserInputPayload {
vibe: VibeType;
bio: string;
}

1 comment on commit 5d189ce

@vercel
Copy link

@vercel vercel bot commented on 5d189ce May 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.