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

Store pinecone from scraper #657

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
9 changes: 9 additions & 0 deletions app/(chat)/chat/[id]/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use server'

import { User } from '@/lib/types'
import { kv } from '@vercel/kv'

export async function getUser(email: string) {
const user = await kv.hgetall<User>(`user:${email}`)
return user
}
2 changes: 1 addition & 1 deletion app/(chat)/chat/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export async function generateMetadata({
}

export default async function ChatPage({ params }: ChatPageProps) {
const session = (await auth()) as Session
const session = (await auth()) as unknown as Session
const missingKeys = await getMissingKeys()

if (!session?.user) {
Expand Down
4 changes: 2 additions & 2 deletions app/(chat)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import { Session } from '@/lib/types'
import { getMissingKeys } from '@/app/actions'

export const metadata = {
title: 'Next.js AI Chatbot'
title: 'LexGPT Chatbots'
}

export default async function IndexPage() {
const id = nanoid()
const session = (await auth()) as Session
const session = (await auth()) as unknown as Session
const missingKeys = await getMissingKeys()

return (
Expand Down
2 changes: 1 addition & 1 deletion app/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,4 @@ export async function getMissingKeys() {
return keysRequired
.map(key => (process.env[key] ? '' : key))
.filter(key => key !== '')
}
}
68 changes: 68 additions & 0 deletions app/api/session/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// /api/session route
import { auth } from '@/auth';
import { kv } from '@vercel/kv';
import { getUser } from '@/app/login/actions';
import { stripe } from '@/lib/stripe'
import Stripe from 'stripe';
import { User } from '@/lib/types';

export async function POST(req: Request) {
if (req.method !== 'POST') {
return new Response('Method Not Allowed', { status: 405 });
}

// Authenticate the user
const session = await auth();

// Fetch user details from Vercel KV
const user = await kv.hgetall<User>(`user:${session?.user?.email}`);

if (!user) {
return new Response(JSON.stringify({ error: 'User not found' }), { status: 404 });
}

// Fetch the Stripe customer info using the stored Stripe ID
let stripeCustomer: Stripe.Customer | null = null;
if (user.stripeId) {
try {
const customer = await stripe.customers.retrieve(user.stripeId);

// Type guard to handle both Customer and DeletedCustomer cases
if (!customer.deleted) {
stripeCustomer = customer; // `customer` is guaranteed to be a `Stripe.Customer` here
} else {
console.error('Customer is deleted:', customer);
}
} catch (error) {
console.error('Error fetching Stripe customer:', error);
}
}

// Check if there's an active subscription in Stripe
let activeSubscription = 'free';
if (stripeCustomer) {
const subscriptions = await stripe.subscriptions.list({
customer: stripeCustomer.id,
status: 'active',
limit: 1,
});

if (subscriptions.data.length > 0) {
const subscription = subscriptions.data[0];
if (subscription.items.data[0].plan.id.includes('premium')) {
activeSubscription = 'premium';
} else if (subscription.items.data[0].plan.id.includes('basic')) {
activeSubscription = 'basic';
}
}
}

// Return user data along with Stripe subscription info
return new Response(
JSON.stringify({
...user,
plan: activeSubscription, // Override the plan from Stripe if active subscription exists
}),
{ status: 200 }
);
}
70 changes: 70 additions & 0 deletions app/api/stj/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { storeDocumentsInPinecone } from "@/lib/chat/embeddingsProviders";
import { NextResponse } from "next/server";
import slugify from 'slugify';
import { Pinecone } from "@pinecone-database/pinecone"

export async function POST(req: Request) {
try {
const body = await req.json();
const namespace = slugify(body.search, { lower: true, strict: false, trim: true });

const pinecone = new Pinecone({
apiKey: process.env.PINECONE_API_KEY || '',
});

const index = pinecone.index('lexgpt');
const indexStats = await index.describeIndexStats();
const namespaces = indexStats.namespaces || {};

// Checar se o namespace existe
if (namespaces.hasOwnProperty(namespace)) {
console.log(`Namespace "${namespace}" already exists.`);

// TODO Puxar dados do pinecone ou retornar erro
return NextResponse.json({ success: true, data: 'data' });
} else {

const response = await fetch('https://lextgpt-puppeteer.onrender.com/scrape', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body)
});

if (!response.ok) {
throw new Error(`Failed to fetch data: ${response.statusText}`);
}

const data = await response.json();

await storeDocumentsInPinecone(data, namespace);

return NextResponse.json({ success: true, data: 'data' });
}
} catch (error: any) {
return NextResponse.json(
{ success: false, message: error.message },
{ status: 500 }
);
}
}


// [
// {
// "process": "\n\tRESP 1913638\n\t",
// "relator": "Ministro GURGEL DE FARIA (1160)",
// "classe": "S1 - PRIMEIRA SEÇÃO",
// "ementa": " \n\t\t\"A contratação de servidores públicos temporários sem concurso\npúblico, mas baseada em legislação local, por si só, não configura a\nimprobidade administrativa prevista no art. 11 da Lei 8.429/1992,\npor estar ausente o elemento subjetivo (dolo) necessário para a\nconfiguração do ato de improbidade violador dos princípios da\nadministração pública\".Veja o Tema Repetitivo 1108\n\t\t",
// "acordao": "\n\t\t\n\n\t\tPROCESSUAL CIVIL E ADMINISTRATIVO. RECURSO ESPECIAL REPRESENTATIVODA CONTROVÉRSIA. IMPROBIDADE. CONTRATAÇÃO DE SERVIDOR TEMPORÁRIO.AUTORIZAÇÃO. LEI LOCAL. DOLO. AFASTAMENTO.1. Em face dos princípios a que está submetida a administração pública (art. 37 da CF/1988) e tendo em vista a supremacia deles, sendo representantes daquela os agentes públicos passíveis de serem alcançados pela lei de improbidade, o legislador ordinário quis impedir o ajuizamento de ações temerárias, evitando, com isso, além de eventuais perseguições políticas e o descrédito social de atos ou decisões político-administrativos,
// "link": "https://processo.stj.jus.br/processo/pesquisa/?num_registro=202003436012%27"
// },
// {
// "process": "\n\tRESP 1926832\n\t",
// "relator": "Ministro GURGEL DE FARIA (1160)",
// "classe": "S1 - PRIMEIRA SEÇÃO",
// "ementa": " \n\t\t\"A contratação de servidores públicos temporários sem concurso\npúblico, mas baseada em legislação local, por si só, não configura a\nimprobidade administrativa prevista no art. 11 da Lei n. 8.429/1992,\npor estar ausente o elemento subjetivo (dolo) necessário para a\nconfiguração do ato de improbidade violador dos princípios da\nadministração pública\".Veja o Tema Repetitivo 1108\n\t\t",
// "acordao": "\n\t\t\n\n\t\tPROCESSUAL CIVIL E ADMINISTRATIVO. RECURSO ESPECIAL REPRESENTATIVODA CONTROVÉRSIA. IMPROBIDADE. CONTRATAÇÃO DE SERVIDOR TEMPORÁRIO.AUTORIZAÇÃO. LEI LOCAL. DOLO. AFASTAMENTO.1. Em face dos princípios a que está submetida a administração pública (art. 37 da CF/1988) e tendo em vista a supremacia deles, sendo representantes daquela os agentes públicos passíveis de serem alcançados pela lei de improbidade, o legislador ordinário quis impedir o ajuizamento de ações temerárias, evitando, com isso, al",
// "link": "https://processo.stj.jus.br/processo/pesquisa/?num_registro=202100720958%27"
// },
57 changes: 57 additions & 0 deletions app/api/stripe/checkout/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { stripe } from '@/lib/stripe'
import { translatePlan } from '@/lib/utils';
import { NextRequest, NextResponse } from 'next/server';
import { Stripe } from 'stripe';
import { Plan, Period } from "@/lib/types";

export async function POST(request: NextRequest) {
try {
// you can implement some basic check here like, is user valid or not
const data = await request.json();
const { priceId, session } = data;

const period_plan = priceId.split('_')
const period = period_plan[0] as Period
const plan = period_plan[1] as Plan

let userExists = false;

try {
const stripeUser = await stripe.customers.retrieve(session.stripeId)
userExists = stripeUser && !stripeUser.deleted
} catch(error) {
console.log(error)
}

const checkoutSession: Stripe.Checkout.Session =
await stripe.checkout.sessions.create({
//payment_method_types: ['card', 'apple_pay'],
line_items: [
{
price: priceId,
quantity: 1,
}
],
custom_text: {
submit: {
message: `Você está assinando o plano ${translatePlan[plan]} ${translatePlan[period]}.`,
},
},
customer: userExists ? session?.stripeId : undefined,
customer_email: userExists ? undefined : session?.email,
mode: 'subscription',
success_url: `${process.env.VERCEL_URL}/checkout/result?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${process.env.VERCEL_URL}/checkout`,
metadata: {
userId: session.id,
email: session.email,
period,
plan,
}
});
return NextResponse.json({ result: checkoutSession, ok: true });
} catch (error) {
console.log(error);
return new NextResponse('Internal Server', { status: 500 });
}
}
76 changes: 76 additions & 0 deletions app/api/webhooks/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
'use server'

import { kv } from '@vercel/kv'
import { getUser } from '@/app/login/actions'
import { auth } from '@/auth'
import { stripe } from '@/lib/stripe'
//import { subscription, User, Session } from '@/lib/types'
import { fromUnixTime } from 'date-fns'
import { User } from '@/lib/types'

export async function updateSubscription({
email,
customer,
period,
plan,
}: User) {
console.log('Atualizando mensalidade: ', email)

try {
const user = await getUser(email as string)
const newUser = {
...user,
plan,
period,
stripeId: customer,
startDate: new Date(),
chargeDate: period === 'month' ? fromUnixTime(Date.now() / 1000 + 30 * 24 * 60 * 60) : period === 'anual' ? fromUnixTime(Date.now() / 1000 + 365 * 24 * 60 * 60) : null,
}
console.log('updating user', newUser)

await kv.hmset(`user:${email}`, newUser)

} catch(error) {
console.log(error)
throw new Error('Ocorreu um erro ao adicionar usuário ',error.message)
}
}

export async function cancelStripeSubscriptions(stripeId: string, filterId?: string) {
// filterId is the current id that will not be cancelled
try {
const subscriptions = await stripe.subscriptions.list({
customer: stripeId,
})

subscriptions.data.forEach(async (subscription) => {
if (subscription.id !== filterId) {
await stripe.subscriptions.cancel(subscription.id)
}
})
} catch(error) {
console.log(error)
}
}

export async function removeSubscription(email?: string, stripeId: string) {
let userEmail = email

if (!email) {
const stripeUser = await stripe.customers.retrieve(stripeId)
userEmail = stripeUser.email
}

console.log('Cancelando mensalidade: ', userEmail)

const subscription = {
email: userEmail,
customer: stripeId,
plan: 'free',
period: null,
}

await cancelStripeSubscriptions(stripeId);
await updateSubscription(subscription)

}
Loading