classify.ts123 lines · main
1import { generateText, Output } from 'ai'
2import { NextApiRequest, NextApiResponse } from 'next'
3import { z } from 'zod'
4
5import { getModel } from '@/lib/ai/model'
6import { DEFAULT_COMPLETION_MODEL } from '@/lib/ai/model.utils'
7import apiWrapper from '@/lib/api/apiWrapper'
8
9async function handler(req: NextApiRequest, res: NextApiResponse) {
10 const { method } = req
11
12 switch (method) {
13 case 'POST':
14 return handlePost(req, res)
15 default:
16 res.setHeader('Allow', ['POST'])
17 res.status(405).json({ data: null, error: { message: `Method ${method} Not Allowed` } })
18 }
19}
20
21export async function handlePost(req: NextApiRequest, res: NextApiResponse) {
22 const {
23 body: { prompt },
24 } = req
25
26 if (!prompt) {
27 return res.status(400).json({
28 error: 'Prompt is required',
29 })
30 }
31
32 try {
33 const { modelParams, error: modelError } = await getModel({
34 provider: 'openai',
35 modelEntry: DEFAULT_COMPLETION_MODEL,
36 })
37
38 if (modelError) {
39 return res.status(500).json({ error: modelError.message })
40 }
41
42 const { output } = await generateText({
43 ...modelParams,
44 output: Output.object({
45 schema: z.object({
46 feedback_category: z.enum(['support', 'feedback', 'unknown']),
47 }),
48 }),
49 temperature: 0,
50 prompt: `
51 Classify the following feedback as ONE of: support, feedback, unknown.
52 - support: bug reports, help requests, or issues
53 - feedback: feature requests or suggestions
54 - unknown: unclear or unrelated
55
56 If you can't determine support or feedback, always output "unknown".
57
58 Only output a JSON object in this format: { "feedback_category": "support|feedback|unknown" }
59
60 Examples:
61 Feedback: "Whenever I try to invite a team member, the invite email doesn't get sent."
62 Response: { "feedback_category": "support" }
63
64 Feedback: "I have reached the storage limit for my project and my plan. I cannot understand how I can expand the storage space in my project."
65 Response: { "feedback_category": "support" }
66
67 Feedback: "Please delete the project x in my account"
68 Response: { "feedback_category": "support" }
69
70 Feedback: "My billing page is broken"
71 Response: { "feedback_category": "support" }
72
73 Feedback: "I accidentally deleted my database—can it be recovered?"
74 Response: { "feedback_category": "support" }
75
76 Feedback: "My login tokens are expiring too quickly, even though I didn't change any settings."
77 Response: { "feedback_category": "support" }
78
79 Feedback: "Can you add more integrations?"
80 Response: { "feedback_category": "feedback" }
81
82 Feedback: "I'm getting charged for a project I thought I deleted. Can you help me stop billing?"
83 Response: { "feedback_category": "support" }
84
85 Feedback: "Could you support OAuth login for more providers like Apple or LinkedIn?"
86 Response: { "feedback_category": "feedback" }
87
88 Feedback: "It's unclear in the docs how to set up row-level security with multiple roles."
89 Response: { "feedback_category": "feedback" }
90
91 Feedback: "I am trying to pause my Pro project"
92 Response: { "feedback_category": "feedback" }
93
94 Feedback: "${prompt}"
95 Response:
96 `,
97 })
98
99 return res.json({ feedback_category: output.feedback_category })
100 } catch (error) {
101 if (error instanceof Error) {
102 console.error(`Classifying this feedback failed`)
103
104 // Check for context length error
105 if (error.message.includes('context_length') || error.message.includes('too long')) {
106 return res.status(400).json({
107 error: 'This prompt is too large to ingest',
108 })
109 }
110 } else {
111 console.error(`Unknown error: ${error}`)
112 }
113
114 return res.status(500).json({
115 error: 'There was an unknown error generating the feedback category.',
116 })
117 }
118}
119
120const wrapper = (req: NextApiRequest, res: NextApiResponse) =>
121 apiWrapper(req, res, handler, { withAuth: true })
122
123export default wrapper