Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rohit/s3 en 2232 get prompts api #88

Merged
merged 8 commits into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
254 changes: 167 additions & 87 deletions app/api/promptset/route.ts
Original file line number Diff line number Diff line change
@@ -1,124 +1,204 @@
import { authOptions } from "@/lib/auth/options";
import prisma from "@/lib/prisma";
import { authApiKey, fillPromptStringTemplate, parseQueryString } from "@/lib/utils";
import { getServerSession } from "next-auth";
import { redirect } from "next/navigation";
import { NextRequest, NextResponse } from "next/server";

export async function GET(req: NextRequest) {
try {
const session = await getServerSession(authOptions);
if (!session || !session.user) {
redirect("/login");
Copy link
Contributor

Choose a reason for hiding this comment

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

can you revert this back to redirect("/login"). we need to find a better way to do this but for now this is the approach we are taking for apis used by the client

}

const id = req.nextUrl.searchParams.get("id") as string;
const promptsetId = req.nextUrl.searchParams.get("promptset_id") as string;
const pageParam = req.nextUrl.searchParams.get("page");
let page = pageParam ? parseInt(pageParam, 10) : 1;
const pageSizeParam = req.nextUrl.searchParams.get("pageSize");
const pageSize = pageSizeParam ? parseInt(pageSizeParam, 10) : 10;

if (!promptsetId && !id) {
return NextResponse.json(
{
message: "No promptset id or project id provided",
},
{ status: 404 }
);
}
const apiKey = req.headers.get("x-api-key");
if (apiKey !== null) {
const response = await authApiKey(apiKey);
if (response.status !== 200) {
return response;
}
const { promptset_id, variables, version } = parseQueryString(req.url);

if (promptsetId) {
// get the dataset and all the data for this dataset and sort them by createdAt
const promptset = await prisma.promptset.findFirst({
const projectData = await response.json();
const projectId = projectData.data.project.id;
const promptSet = await prisma.promptset.findFirst({
where: {
id: promptsetId,
projectId: projectId,
id: promptset_id as string,
},
include: {
Prompt: {
where: {
OR: version !== undefined ? [{ version: version }] : [{ live: true }],
},
},
},
});

if (!promptset) {
let prompts = promptSet?.Prompt ?? [];
if (prompts.length === 0 && version === undefined) {
return NextResponse.json(
{
message: "No promptset found",
error: "No live prompts found. A prompt version must be specified",
},
{ status: 400 }
);
} else if (prompts.length === 0 && version !== undefined) {
return NextResponse.json(
{
error: "No prompts found with the specified version",
},
{ status: 404 }
);
}
if (variables !== undefined) {
const errors: string[] = [];
const variablesSet = new Set(
Object.entries(variables as Record<string, string>).map((variable) =>
variable.join(",")
)
);
const livePromptVariables = prompts[0].variables;

const totalLen = await prisma.prompt.count({
where: {
promptsetId: promptset.id,
},
livePromptVariables.forEach((key) => {
const value =
variables !== null ? variables[key as keyof typeof variables] ?? "" : "";
if (!variablesSet.has(`${key},${value.length > 0 ? value : "undefined"}`)) {
errors.push(key);
}
});
if (errors.length > 0) {
const moreThanOneError = errors.length > 1;
return NextResponse.json(
{
error: `${moreThanOneError ? "Variables" : "Variable"} ${errors.join(", ")} ${moreThanOneError ? "are" : "is"} missing`,
},
{ status: 400 }
);
}
prompts[0].value = fillPromptStringTemplate(prompts[0].value, variables as Record<string, string>);
}
return NextResponse.json({
...promptSet,
Prompt: undefined,
prompts: prompts
});
} else {
const session = await getServerSession(authOptions);
if (!session || !session.user) {
return NextResponse.json(
{
message: "Unauthorized",
},
{ status: 401 }
);
}

const id = req.nextUrl.searchParams.get("id") as string;
const promptsetId = req.nextUrl.searchParams.get(
"promptset_id"
) as string;
const pageParam = req.nextUrl.searchParams.get("page");

let page = pageParam ? parseInt(pageParam, 10) : 1;
const pageSizeParam = req.nextUrl.searchParams.get("pageSize");
const pageSize = pageSizeParam ? parseInt(pageSizeParam, 10) : 10;

if (!promptsetId && !id) {
return NextResponse.json(
{
message: "No promptset id or project id provided",
},
{ status: 404 }
);
}

if (promptsetId) {
// get the dataset and all the data for this dataset and sort them by createdAt
const promptset = await prisma.promptset.findFirst({
where: {
id: promptsetId,
},
});

const totalPages =
Math.ceil(totalLen / pageSize) === 0
? 1
: Math.ceil(totalLen / pageSize);
const md = { page, page_size: pageSize, total_pages: totalPages };
if (!promptset) {
return NextResponse.json(
{
message: "No promptset found",
},
{ status: 404 }
);
}

if (page! > totalPages) {
page = totalPages;
const totalLen = await prisma.prompt.count({
where: {
promptsetId: promptset.id,
},
});

const totalPages =
Math.ceil(totalLen / pageSize) === 0
? 1
: Math.ceil(totalLen / pageSize);
const md = { page, page_size: pageSize, total_pages: totalPages };

if (page! > totalPages) {
page = totalPages;
}

const relatedPrompt = await prisma.prompt.findMany({
where: {
promptsetId: promptset.id,
},
orderBy: {
createdAt: "desc",
},
take: pageSize,
skip: (page - 1) * pageSize,
});

// Combine dataset with its related, ordered Data
const promptsetWithOrderedData = {
...promptset,
prompts: relatedPrompt,
};

return NextResponse.json({
promptsets: promptsetWithOrderedData,
metadata: md,
});
}

const relatedPrompt = await prisma.prompt.findMany({
const project = await prisma.project.findFirst({
where: {
id,
},
});
if (!project) {
return NextResponse.json(
{
message: "No projects found",
},
{ status: 404 }
);
}
// get all the datasets for this project
const promptsets = await prisma.promptset.findMany({
where: {
promptsetId: promptset.id,
projectId: id,
},
orderBy: {
createdAt: "desc",
},
take: pageSize,
skip: (page - 1) * pageSize,
include: {
_count: {
select: {
Prompt: true,
},
},
},
});

// Combine dataset with its related, ordered Data
const promptsetWithOrderedData = {
...promptset,
prompts: relatedPrompt,
};

return NextResponse.json({
promptsets: promptsetWithOrderedData,
metadata: md,
promptsets: promptsets,
});
}

const project = await prisma.project.findFirst({
where: {
id,
},
});

if (!project) {
return NextResponse.json(
{
message: "No projects found",
},
{ status: 404 }
);
}

// get all the datasets for this project
const promptsets = await prisma.promptset.findMany({
where: {
projectId: id,
},
orderBy: {
createdAt: "desc",
},
include: {
_count: {
select: {
Prompt: true,
},
},
},
});

return NextResponse.json({
promptsets: promptsets,
});
} catch (error) {
console.error(error);
Copy link
Contributor

Choose a reason for hiding this comment

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

could you remove this

return NextResponse.json(
{
message: "Internal server error",
Expand Down
25 changes: 25 additions & 0 deletions lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
PERPLEXITY_PRICING,
SpanStatusCode,
} from "./constants";
import qs from "qs";

export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
Expand Down Expand Up @@ -279,6 +280,30 @@ export function prepareForClickhouse(spans: Normalized[]): Span[] {
});
}

export function fillPromptStringTemplate(template: string, variables: { [key: string]: string }): string {
return template.replace(/\{(\w+)\}/g, (match, key) => {
return variables[key] || match;
});
}

//TODO: Move to a middleware
export function parseQueryString(url: string): Record<string, any>{
return qs.parse(url.split("?")[1], {
decoder(str) {
if (str === "true") return true;
if (str === "false") return false;
try {
return JSON.parse(str);
} catch {
return str;
}
},
interpretNumericEntities: true, // Ensures numeric entities are parsed correctly
parseArrays: true, // Ensures arrays are parsed correctly
allowDots: true, // Allows dot notation for nested objects
});
}

export async function authApiKey(api_key?: string): Promise<NextResponse> {
if (!api_key) {
return NextResponse.json(
Expand Down
Loading