mirror of
https://github.com/formbricks/formbricks.git
synced 2026-04-19 11:11:05 -05:00
remove open text summary
This commit is contained in:
@@ -1,11 +1,10 @@
|
||||
import { DocumentSearch } from "@/app/(app)/environments/[environmentId]/documents/components/DocumentSearch";
|
||||
import { Metadata } from "next";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { getInsights } from "@formbricks/ee/ai-analysis/lib/insight/service";
|
||||
import { authOptions } from "@formbricks/lib/authOptions";
|
||||
import { getOrganizationByEnvironmentId } from "@formbricks/lib/organization/service";
|
||||
import { getProductByEnvironmentId } from "@formbricks/lib/product/service";
|
||||
import { getUser } from "@formbricks/lib/user/service";
|
||||
import { TTemplateRole } from "@formbricks/types/templates";
|
||||
import { Card } from "@formbricks/ui/Card";
|
||||
import { PageContentWrapper } from "@formbricks/ui/PageContentWrapper";
|
||||
import { PageHeader } from "@formbricks/ui/PageHeader";
|
||||
|
||||
@@ -22,7 +21,7 @@ interface SurveyTemplateProps {
|
||||
};
|
||||
}
|
||||
|
||||
const Page = async ({ params, searchParams }: SurveyTemplateProps) => {
|
||||
const Page = async ({ params }: SurveyTemplateProps) => {
|
||||
const session = await getServerSession(authOptions);
|
||||
|
||||
if (!session) {
|
||||
@@ -34,10 +33,14 @@ const Page = async ({ params, searchParams }: SurveyTemplateProps) => {
|
||||
throw new Error("User not found");
|
||||
}
|
||||
|
||||
const insights = await getInsights(params.environmentId);
|
||||
|
||||
return (
|
||||
<PageContentWrapper>
|
||||
<PageHeader pageTitle="Documents" />
|
||||
<DocumentSearch environmentId={params.environmentId} />
|
||||
<PageHeader pageTitle="Insights" />
|
||||
{insights.map((insight) => (
|
||||
<Card key={insight.id} label={insight.title} description={insight.description} />
|
||||
))}
|
||||
</PageContentWrapper>
|
||||
);
|
||||
};
|
||||
@@ -1,12 +1,8 @@
|
||||
"use server";
|
||||
|
||||
import { getEmailTemplateHtml } from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/emailTemplate";
|
||||
import { generateText } from "ai";
|
||||
import { customAlphabet } from "nanoid";
|
||||
import { z } from "zod";
|
||||
import { clusterDocuments } from "@formbricks/ee/ai-analysis/lib/document/kmeans";
|
||||
import { getQuestionResponseReferenceId } from "@formbricks/ee/ai-analysis/lib/document/utils";
|
||||
import { llmModel } from "@formbricks/ee/ai/lib/utils";
|
||||
import { sendEmbedSurveyPreviewEmail } from "@formbricks/email";
|
||||
import { authenticatedActionClient } from "@formbricks/lib/actionClient";
|
||||
import { checkAuthorization } from "@formbricks/lib/actionClient/utils";
|
||||
@@ -144,42 +140,3 @@ export const getEmailHtmlAction = authenticatedActionClient
|
||||
|
||||
return await getEmailTemplateHtml(parsedInput.surveyId);
|
||||
});
|
||||
|
||||
const ZGetOpenTextSummaryAction = z.object({
|
||||
surveyId: ZId,
|
||||
questionId: ZId,
|
||||
});
|
||||
|
||||
export const getOpenTextSummaryAction = authenticatedActionClient
|
||||
.schema(ZGetOpenTextSummaryAction)
|
||||
.action(async ({ ctx, parsedInput }) => {
|
||||
await checkAuthorization({
|
||||
userId: ctx.user.id,
|
||||
organizationId: await getOrganizationIdFromSurveyId(parsedInput.surveyId),
|
||||
rules: ["survey", "read"],
|
||||
});
|
||||
|
||||
const survey = await getSurvey(parsedInput.surveyId);
|
||||
|
||||
if (!survey) {
|
||||
throw new ResourceNotFoundError("Survey", parsedInput.surveyId);
|
||||
}
|
||||
|
||||
const documents = []; // TODO
|
||||
|
||||
const topics = await clusterDocuments(documents, 3);
|
||||
|
||||
const question = survey.questions.find((q) => q.id === parsedInput.questionId);
|
||||
const prompt = `You are an AI research assistant and answer the question: "${question?.headline.default}". Please in markdown provide a short summary sentence and provide 3 bullet points for insights you got from these samples including the number of responses for this topic:\n${topics.map((t) => t.centralDocument.text).join("\n")}`;
|
||||
|
||||
try {
|
||||
const { text } = await generateText({
|
||||
model: llmModel,
|
||||
prompt,
|
||||
});
|
||||
return text;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw new Error("Failed to generate summary");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
import { getOpenTextSummaryAction } from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/actions";
|
||||
import Markdown from "markdown-to-jsx";
|
||||
import Link from "next/link";
|
||||
import { useState } from "react";
|
||||
import { getPersonIdentifier } from "@formbricks/lib/person/utils";
|
||||
import { timeSince } from "@formbricks/lib/time";
|
||||
import { TAttributeClass } from "@formbricks/types/attribute-classes";
|
||||
import { TSurvey, TSurveyQuestionSummaryOpenText } from "@formbricks/types/surveys/types";
|
||||
import { Alert, AlertDescription, AlertTitle } from "@formbricks/ui/Alert";
|
||||
import { PersonAvatar } from "@formbricks/ui/Avatars";
|
||||
import { Button } from "@formbricks/ui/Button";
|
||||
import { LoadingSpinner } from "@formbricks/ui/LoadingSpinner";
|
||||
import { QuestionSummaryHeader } from "./QuestionSummaryHeader";
|
||||
|
||||
interface OpenTextSummaryProps {
|
||||
@@ -38,22 +34,6 @@ export const OpenTextSummary = ({
|
||||
);
|
||||
};
|
||||
|
||||
const getOpenTextSummary = async () => {
|
||||
setIsLoadingAiSummary(true);
|
||||
// This function is not implemented yet
|
||||
const res = await getOpenTextSummaryAction({
|
||||
surveyId: survey.id,
|
||||
questionId: questionSummary.question.id,
|
||||
});
|
||||
const openTextSummary = res?.data;
|
||||
if (openTextSummary) {
|
||||
setAiSummary(openTextSummary);
|
||||
} else {
|
||||
setAiSummary("No summary available");
|
||||
}
|
||||
setIsLoadingAiSummary(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="rounded-xl border border-slate-200 bg-white shadow-sm">
|
||||
<QuestionSummaryHeader
|
||||
@@ -61,32 +41,7 @@ export const OpenTextSummary = ({
|
||||
survey={survey}
|
||||
attributeClasses={attributeClasses}
|
||||
/>
|
||||
<div className="p-4">
|
||||
{isAiEnabled && (
|
||||
<>
|
||||
<Alert variant="info">
|
||||
<AlertTitle>✨ AI Summary</AlertTitle>
|
||||
{isLoadingAiSummary && <LoadingSpinner />}
|
||||
{!isLoadingAiSummary && aiSummary && (
|
||||
<>
|
||||
<hr className="my-4 text-slate-200" />
|
||||
<AlertDescription>
|
||||
<Markdown>{aiSummary}</Markdown>
|
||||
</AlertDescription>
|
||||
</>
|
||||
)}
|
||||
<hr className="my-4 text-slate-200" />
|
||||
{questionSummary.responseCount < 10 ? (
|
||||
<p className="text-sm">This question needs at least 10 responses to access AI summaries</p>
|
||||
) : (
|
||||
<Button onClick={() => getOpenTextSummary()} disabled={isLoadingAiSummary}>
|
||||
Generate Summary
|
||||
</Button>
|
||||
)}
|
||||
</Alert>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="p-4"></div>
|
||||
<div className="">
|
||||
<div className="grid h-10 grid-cols-4 items-center border-y border-slate-200 bg-slate-100 text-sm font-bold text-slate-600">
|
||||
<div className="pl-4 md:pl-6">User</div>
|
||||
|
||||
@@ -1,15 +1,52 @@
|
||||
import "server-only";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { cache as reactCache } from "react";
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { cache } from "@formbricks/lib/cache";
|
||||
import { validateInputs } from "@formbricks/lib/utils/validate";
|
||||
import { ZId } from "@formbricks/types/environment";
|
||||
import { DatabaseError } from "@formbricks/types/errors";
|
||||
import { TInsight, TInsightCreateInput, ZInsightCreateInput } from "@formbricks/types/insights";
|
||||
import { insightCache } from "./cache";
|
||||
|
||||
export type TPrismaInsight = Omit<TInsight, "vector"> & {
|
||||
vector: string;
|
||||
};
|
||||
const INSIGHTS_PER_PAGE = 10;
|
||||
|
||||
export const getInsights = reactCache(
|
||||
(environmentId: string, limit?: number, offset?: number): Promise<TInsight[]> =>
|
||||
cache(
|
||||
async () => {
|
||||
validateInputs([environmentId, ZId]);
|
||||
|
||||
limit = limit ?? INSIGHTS_PER_PAGE;
|
||||
try {
|
||||
const insights = await prisma.insight.findMany({
|
||||
where: {
|
||||
environmentId,
|
||||
},
|
||||
orderBy: [
|
||||
{
|
||||
createdAt: "desc",
|
||||
},
|
||||
],
|
||||
take: limit ? limit : undefined,
|
||||
skip: offset ? offset : undefined,
|
||||
});
|
||||
|
||||
return insights;
|
||||
} catch (error) {
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
throw new DatabaseError(error.message);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
[`getInsights-${environmentId}-${limit}-${offset}`],
|
||||
{
|
||||
tags: [insightCache.tag.byEnvironmentId(environmentId)],
|
||||
}
|
||||
)()
|
||||
);
|
||||
|
||||
export const createInsight = async (insightGroupInput: TInsightCreateInput): Promise<TInsight> => {
|
||||
validateInputs([insightGroupInput, ZInsightCreateInput]);
|
||||
@@ -59,7 +96,7 @@ export const findNearestInsights = async (
|
||||
const vectorString = `[${vector.join(",")}]`;
|
||||
|
||||
// Execute raw SQL query to find nearest neighbors and exclude the vector column
|
||||
const prismaInsights: TPrismaInsight[] = await prisma.$queryRaw`
|
||||
const insights: TInsight[] = await prisma.$queryRaw`
|
||||
SELECT
|
||||
id,
|
||||
created_at AS "createdAt",
|
||||
@@ -67,8 +104,7 @@ export const findNearestInsights = async (
|
||||
title,
|
||||
description,
|
||||
category,
|
||||
"environmentId",
|
||||
vector::text
|
||||
"environmentId"
|
||||
FROM "Insight" d
|
||||
WHERE d."environmentId" = ${environmentId}
|
||||
AND d."vector" <=> ${vectorString}::vector(512) <= ${threshold}
|
||||
@@ -76,17 +112,5 @@ export const findNearestInsights = async (
|
||||
LIMIT ${limit};
|
||||
`;
|
||||
|
||||
const insights = prismaInsights.map((prismaDocumentGroup) => {
|
||||
// Convert the string representation of the vector back to an array of numbers
|
||||
const vector = prismaDocumentGroup.vector
|
||||
.slice(1, -1) // Remove the surrounding square brackets
|
||||
.split(",") // Split the string into an array of strings
|
||||
.map(Number); // Convert each string to a number
|
||||
return {
|
||||
...prismaDocumentGroup,
|
||||
vector,
|
||||
};
|
||||
});
|
||||
|
||||
return insights;
|
||||
};
|
||||
|
||||
@@ -12,7 +12,6 @@ export const ZInsight = z.object({
|
||||
environmentId: ZId,
|
||||
title: z.string(),
|
||||
description: z.string(),
|
||||
vector: z.array(z.number()).length(512),
|
||||
category: ZInsightCategory,
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user