From b2794171f042d5b068012a759998bf81b0a8489f Mon Sep 17 00:00:00 2001 From: nnhuyhoang Date: Tue, 2 Jul 2024 03:04:33 +0700 Subject: [PATCH 1/2] feat: add multimodal retrieval --- Makefile | 2 +- drizzle.config.ts | 8 +- package.json | 12 +- src/app/api/sync-bot-source/route.ts | 2 +- src/env.js | 10 ++ src/pages/bots/[id]/index.tsx | 25 ++- src/server/api/routers/chat.ts | 244 ++++++++++++++++++++------- src/server/db/migration/schema.ts | 4 + src/utils/utils.ts | 27 +++ 9 files changed, 262 insertions(+), 72 deletions(-) diff --git a/Makefile b/Makefile index 5367f51..269cd98 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ db-down-prune: docker-compose -p chatbot_builder -f ./build/local/docker-compose.yml down --volumes db-migrate: - bun drizzle-kit push:pg + bun drizzle-kit push db-seed: bun src/server/db/migration/seed.ts diff --git a/drizzle.config.ts b/drizzle.config.ts index 1c9eade..fbf45cf 100644 --- a/drizzle.config.ts +++ b/drizzle.config.ts @@ -4,9 +4,13 @@ import { env } from '~/env' export default { schema: './src/server/db/migration/schema.ts', - driver: 'pg', + dialect: 'postgresql', dbCredentials: { - connectionString: env.DATABASE_URL, + url: env.DATABASE_URL, + }, + migrations: { + table: 'migrations', + schema: 'public', }, // tablesFilter: ["chatbot-builder_*"], out: './src/server/db/migrations', diff --git a/package.json b/package.json index 84ea320..fa4b8fc 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,9 @@ "@dwarvesf/react-hooks": "^0.8.2", "@dwarvesf/react-utils": "^0.4.2", "@hookform/resolvers": "^3.3.4", - "@langchain/community": "^0.2.3", + "@langchain/community": "^0.2.13", + "@langchain/core": "^0.2.9", + "@langchain/openai": "^0.2.0", "@mochi-ui/core": "^0.14.3", "@mochi-ui/icons": "^0.8.1", "@mochi-ui/theme": "^0.20.1", @@ -28,12 +30,14 @@ "@trpc/next": "next", "@trpc/react-query": "next", "@trpc/server": "next", + "@types/pg": "^8.11.6", "@types/react-color": "^3.0.12", "@vercel/blob": "^0.23.2", "async": "^3.2.5", + "buffer": "^6.0.3", "clsx": "^2.1.1", "dayjs": "^1.11.11", - "drizzle-orm": "^0.29.4", + "drizzle-orm": "^0.31.0", "fast-xml-parser": "^4.3.6", "jsdom": "^24.0.0", "langchain": "^0.2.2", @@ -42,12 +46,14 @@ "next": "^14.1.3", "next-auth": "^4.24.6", "openai": "^4.42.0", + "pg": "^8.12.0", "postgres": "^3.4.4", "react": "18.2.0", "react-color": "^2.19.3", "react-dom": "18.2.0", "react-dropzone": "^14.2.3", "react-hook-form": "^7.51.3", + "sharp": "^0.33.4", "superjson": "^2.2.1", "tailwindcss-animate": "^1.0.7", "use-debounce": "^10.0.1", @@ -68,7 +74,7 @@ "@typescript-eslint/parser": "^7.1.1", "cheerio": "^1.0.0-rc.12", "domhandler": "^5.0.3", - "drizzle-kit": "^0.20.14", + "drizzle-kit": "^0.22.7", "eslint": "^8.57.0", "eslint-config-next": "^14.1.3", "eslint-plugin-drizzle": "^0.2.3", diff --git a/src/app/api/sync-bot-source/route.ts b/src/app/api/sync-bot-source/route.ts index 9ee026e..06a8357 100644 --- a/src/app/api/sync-bot-source/route.ts +++ b/src/app/api/sync-bot-source/route.ts @@ -58,7 +58,7 @@ export async function POST(req: Request) { return new Response(`Sync bot source from ${process.env.VERCEL_REGION} xxx`) } -async function syncBotSource(bsId: string) { +export async function syncBotSource(bsId: string) { const bs = await db.query.botSources.findFirst({ where: eq(schema.botSources.id, bsId), }) diff --git a/src/env.js b/src/env.js index 3d1ab0c..0f59ea2 100644 --- a/src/env.js +++ b/src/env.js @@ -8,6 +8,11 @@ export const env = createEnv({ */ server: { DATABASE_URL: z.string().url(), + DATABASE_HOST: z.string(), + DATABASE_PORT: z.number(), + DATABASE_NAME: z.string(), + DATABASE_USER: z.string(), + DATABASE_PASSWORD: z.string(), NODE_ENV: z .enum(['development', 'test', 'production']) .default('development'), @@ -53,6 +58,11 @@ export const env = createEnv({ */ runtimeEnv: { DATABASE_URL: process.env.DATABASE_URL, + DATABASE_HOST: process.env.DATABASE_HOST, + DATABASE_PORT: process.env.DATABASE_PORT, + DATABASE_NAME: process.env.DATABASE_NAME, + DATABASE_USER: process.env.DATABASE_USER, + DATABASE_PASSWORD: process.env.DATABASE_PASSWORD, NODE_ENV: process.env.NODE_ENV, NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET, NEXTAUTH_URL: process.env.NEXTAUTH_URL, diff --git a/src/pages/bots/[id]/index.tsx b/src/pages/bots/[id]/index.tsx index 25c7376..9008ff0 100644 --- a/src/pages/bots/[id]/index.tsx +++ b/src/pages/bots/[id]/index.tsx @@ -5,18 +5,18 @@ import { PageHeader, PageHeaderTitle, Separator, - Typography, Tooltip, + Typography, } from '@mochi-ui/core' import { PaperplaneSolid, Spinner } from '@mochi-ui/icons' -import { FeedbackFormWrapper } from '~/components/FeedbackForm' -import { Like, DisLike } from '~/components/icons/svg' import clsx from 'clsx' import type { GetServerSideProps, NextPage } from 'next' import { useParams } from 'next/navigation' import { useEffect, useState } from 'react' import { Controller, useForm } from 'react-hook-form' +import { FeedbackFormWrapper } from '~/components/FeedbackForm' import { SeoHead } from '~/components/common/SeoHead' +import { DisLike, Like } from '~/components/icons/svg' import { ROUTES } from '~/constants/routes' import { getServerAuthSession } from '~/server/auth' import { api } from '~/utils/api' @@ -115,7 +115,7 @@ const BotDetail: NextPage = () => { addNewMessage( data.chatIdAssistants ?? '', data.referSourceLinks ?? null, - data.assistants?.[0]?.[0]?.msg ?? '', + data.assistants?.[0]?.toString() ?? '', false, ) }, @@ -176,6 +176,23 @@ const BotDetail: NextPage = () => { } }, [createNewThread, serverThread, apiToken]) + // useEffect(() => { + // if (chatData) { + // addNewMessage( + // chatData.referSourceLinks ?? null, + // // chatData.assistants?.[0]?.[0]?.msg ?? '', + // chatData.res ?? '', + // false, + // ) + // } + // }, [JSON.stringify(chatData)]) + + // useEffect(() => { + // if (chatError) { + // addNewMessage(null, chatError.message, false, true) + // } + // }, [chatError]) + async function sendMessage(data: { message: string }) { const submittedMessage = data.message.trim() if (!submittedMessage) { diff --git a/src/server/api/routers/chat.ts b/src/server/api/routers/chat.ts index 98ac39e..c1d191e 100644 --- a/src/server/api/routers/chat.ts +++ b/src/server/api/routers/chat.ts @@ -1,18 +1,53 @@ -import { and, asc, desc, eq, gte, sql } from 'drizzle-orm' -import lodash from 'lodash' +import { PGVectorStore } from '@langchain/community/vectorstores/pgvector' +import { type Document } from '@langchain/core/documents' +import { + HumanMessageChunk, + type BaseMessage, + type MessageContentComplex, +} from '@langchain/core/messages' +import { ChatOpenAI, OpenAIEmbeddings } from '@langchain/openai' +import { and, desc, eq, gte, sql } from 'drizzle-orm' import OpenAI from 'openai' +import pg from 'pg' +import sharp from 'sharp' import { uuidv7 } from 'uuidv7' import { z } from 'zod' import { env } from '~/env' import { BotModelEnum } from '~/model/bot-model' -import { BotSourceTypeEnum } from '~/model/bot-source-type' import { ChatRoleEnum } from '~/model/chat' import { UsageLimitTypeEnum } from '~/model/usage-limit-type' import { db } from '~/server/db' import * as schema from '~/server/db/migration/schema' import getEmbeddingsFromContents from '~/server/gateway/openai/embedding' import { type Nullable } from '~/utils/types' -import { createTRPCRouter, integrationProcedure } from '~/server/api/trpc' +import { isBase64, isImageData } from '~/utils/utils' +import { createTRPCRouter, integrationProcedure } from '../trpc' + +const reusablePool = new pg.Pool({ + host: env.DATABASE_HOST, + port: env.DATABASE_PORT, + user: env.DATABASE_USER, + password: env.DATABASE_PASSWORD, + database: env.DATABASE_NAME, +}) + +const originalConfig = { + pool: reusablePool, + tableName: 'bot_source_extracted_data_vector', + columns: { + idColumnName: 'id', + vectorColumnName: 'vector', + contentColumnName: 'content', + }, +} + +const pgvectorStore = new PGVectorStore( + new OpenAIEmbeddings({ + model: 'text-embedding-3-small', + dimensions: 1024, + }), + originalConfig, +) const openai = new OpenAI({ apiKey: env.OPENAI_API_KEY, // This is the default and can be omitted @@ -117,81 +152,91 @@ function createChatHandler() { }) .returning() - const contexts = await getRelatedContexts(bot.id, msg.message) + const retriever = pgvectorStore.asRetriever() + const contexts = await retriever.invoke(msg.message) + + // const contexts = await getRelatedContexts(bot.id, msg.message) const assistantMsgs = [] if (contexts.length > 0) { // Build prompt - const prompt = await buildPrompt(contexts, msg.message) - console.log('Prompt:', prompt) + // const prompt = await buildPrompt(contexts, msg.message) + const prompt = await buildPromptv2(contexts, msg.message) + // console.log('Prompt:', prompt) // Ask bot - const res = await askAI(bot, msg.message) + // const res = await askAI(bot, msg.message) + const res = await askAIv2(bot, prompt) if (!res) { throw new Error('Failed to ask AI') } + // console.log('AI Response:', res) - console.log( - 'Refer Links:', - contexts.map((row) => row.referLinks), - ) + // console.log( + // 'Refer Links:', + // contexts.map((row) => row.referLinks), + // ) - const sourceLinks: string[] = [] + //const sourceLinks: string[] = [] - contexts.forEach((context) => { - if (context.sourceType === Number(BotSourceTypeEnum.File)) { - return - } + // contexts.forEach((context) => { + // if (context.sourceType === Number(BotSourceTypeEnum.File)) { + // return + // } - if (!context.referLinks) { - return - } + // if (!context.referLinks) { + // return + // } - sourceLinks.push(context.referLinks) - }) + // sourceLinks.push(context.referLinks) + // }) - const formatSourceLinks = lodash.uniq(sourceLinks) // filter duplicate link + // const formatSourceLinks = lodash.uniq(sourceLinks) // filter duplicate link - const { completion } = res + // const { completion } = res - const resChoices = completion?.choices?.filter( - (c) => c?.message?.role === 'assistant', - ) + // const resChoices = completion?.choices?.filter( + // (c) => c?.message?.role === 'assistant', + // ) // Save bot response - if (resChoices?.length) { - for (const res of resChoices) { - const isLastMsg = res === resChoices[resChoices.length - 1] - - const resId = uuidv7() - const m = await db - .insert(schema.chats) - .values({ - id: resId, - botModelId: bot.modelId, - roleId: ChatRoleEnum.Assistant, - parentChatId: chatId, - threadId, - msg: res.message.content, - prompt, - promptTokens: isLastMsg ? completion?.usage?.prompt_tokens : 0, - completionTokens: isLastMsg - ? completion?.usage?.completion_tokens - : 0, - totalTokens: isLastMsg ? completion?.usage?.total_tokens : 0, - }) - .returning() - - assistantMsgs.push(m) - - return { - chat: c, - chatIdAssistants: resId, - assistants: assistantMsgs, - referSourceLinks: formatSourceLinks, - res: completion, - } - } + // if (resChoices?.length) { + // for (const res of resChoices) { + // const isLastMsg = res === resChoices[resChoices.length - 1] + + // const resId = uuidv7() + // const m = await db + // .insert(schema.chats) + // .values({ + // id: resId, + // botModelId: bot.modelId, + // roleId: ChatRoleEnum.Assistant, + // parentChatId: chatId, + // threadId, + // msg: res.message.content, + // prompt, + // promptTokens: isLastMsg ? completion?.usage?.prompt_tokens : 0, + // completionTokens: isLastMsg + // ? completion?.usage?.completion_tokens + // : 0, + // totalTokens: isLastMsg ? completion?.usage?.total_tokens : 0, + // }) + // .returning() + + // assistantMsgs.push(m) + // } + // } + // return { + // chat: c, + // assistants: assistantMsgs, + // referSourceLinks: formatSourceLinks, + // res: completion, + // } + return { + chat: c, + assistants: prompt, + referSourceLinks: null, + res: res.content.toString(), } } else { console.log('Context: No relevant context') @@ -247,6 +292,29 @@ async function askAI( return { completion } } +async function askAIv2( + bot: { id: string; modelId: BotModelEnum }, + prompt: BaseMessage[], +) { + if (!bot || !prompt) { + return + } + + const model = new ChatOpenAI({ + model: 'gpt-4o', + // model: getAIModel(bot.modelId), + maxTokens: 1024, + temperature: 0, + }) + for (const p of prompt) { + console.log('Prompt:', p.content) + } + + const result = await model.invoke(prompt) + + return result +} + async function getRelatedContexts(botId: string, msg: string) { const msgVectors = await getEmbeddingsFromContents([msg]) if (!msgVectors?.length) { @@ -305,10 +373,48 @@ async function buildPrompt( return prompt } +async function buildPromptv2(context: Document[], question: string) { + const messages: MessageContentComplex[] = [] + const textMessages = [] + for (const r of context) { + if (isBase64(r.pageContent) && isImageData(r.pageContent)) { + // image data + const resizeImage = await resizeBase64Image(r.pageContent, [1300, 600]) + messages.push({ + type: 'image_url', + image_url: { + url: `data:image/jpeg;base64,${resizeImage}`, + }, + }) + } else { + // text, table + textMessages.push(r.pageContent) + } + } + const formattedTextMessages = textMessages.join('\n') + messages.push({ + type: 'text', + text: ` + You are AI assistant which is capable of answering questions.\n + You will be given a mixed of text, tables, and image(s) usually of charts or graphs.\n + Use this information to provide answer related to the user question but keep answer clean and understandable.\n + User-provided question: ${question}\n + Text and/or tables provided: \n + ${formattedTextMessages} + `, + }) + + const humanMessages: BaseMessage[] = [ + new HumanMessageChunk({ content: messages }), + ] + + return humanMessages +} + function getAIModel(modelID: BotModelEnum): string { switch (modelID) { case BotModelEnum.GPT3: - return 'gpt-3.5-turbo' + return 'gpt-4o' default: throw new Error('Invalid model') } @@ -367,3 +473,19 @@ async function isUserUsageLimitValid( } return true } + +async function resizeBase64Image( + base64String: string, + size: [number, number] = [128, 128], +): Promise { + // Decode the Base64 string to a Buffer + const imgBuffer = Buffer.from(base64String, 'base64') + + // Resize the image using sharp + const resizedImgBuffer = await sharp(imgBuffer) + .resize(...size) + .toBuffer() + + // Encode the resized image to Base64 + return resizedImgBuffer.toString('base64') +} diff --git a/src/server/db/migration/schema.ts b/src/server/db/migration/schema.ts index d0f7224..4714dba 100644 --- a/src/server/db/migration/schema.ts +++ b/src/server/db/migration/schema.ts @@ -300,6 +300,10 @@ export const botSourceExtractedDataVector = createTable( botSourceExtractedDataIdIdx: index( 'bot_source_extracted_data_vector_bot_source_extracted_data_id_idx', ).on(vector.botSourceExtractedDataId), + vectorIdx: index('bot_source_extracted_data_vector_vector_idx').using( + 'hnsw', + vector.vector.op('vector_cosine_ops'), + ), }), ) diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 56efdf4..c986a51 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -1,3 +1,4 @@ +import { Buffer } from 'buffer' import dayjs from 'dayjs' export const isValidURL = (url: string) => { @@ -30,3 +31,29 @@ export function delay(time: number) { setTimeout(resolve, time) }) } + +export function isBase64(str: string) { + const base64Pattern = /^[A-Za-z0-9+/]+={0,2}$/ + return base64Pattern.test(str) +} + +export function isImageData(b64data: string): boolean { + const imageSignatures: Record = { + '\xFF\xD8\xFF': 'jpg', + '\x89\x50\x4E\x47\x0D\x0A\x1A\x0A': 'png', + '\x47\x49\x46\x38': 'gif', + '\x52\x49\x46\x46': 'webp', + } + + try { + const header = Buffer.from(b64data, 'base64').subarray(0, 8) // Decode and get the first 8 bytes + for (const [sig, format] of Object.entries(imageSignatures)) { + if (header.indexOf(Buffer.from(sig, 'latin1')) === 0) { + return true + } + } + return false + } catch (error) { + return false + } +} From c564c09e4fb5246f88c5c8676d4c2c3d1bdda0ed Mon Sep 17 00:00:00 2001 From: nnhuyhoang Date: Wed, 10 Jul 2024 11:22:39 +0700 Subject: [PATCH 2/2] feat: add preprocessor --- .gitignore | 5 +- Makefile | 2 + build/local/docker-compose.yml | 1 + bun.lockb | Bin 459529 -> 469972 bytes preprocessor/Dockerfile | 15 + preprocessor/app/__init__.py | 0 preprocessor/app/config/__init__.py | 0 preprocessor/app/config/config.py | 11 + preprocessor/app/db/__init__.py | 0 preprocessor/app/db/database.py | 19 + preprocessor/app/models/__init__.py | 0 preprocessor/app/models/models.py | 518 +++++++++++++++++++++++++++ preprocessor/app/utils/__init__.py | 0 preprocessor/app/utils/image.py | 103 ++++++ preprocessor/app/utils/pdf.py | 88 +++++ preprocessor/docker-compose.yml | 12 + preprocessor/main.py | 122 +++++++ preprocessor/requirements.txt | 27 ++ src/env.js | 2 +- src/server/api/routers/bot-source.ts | 5 +- src/server/api/routers/chat.ts | 2 +- 21 files changed, 927 insertions(+), 5 deletions(-) create mode 100644 preprocessor/Dockerfile create mode 100644 preprocessor/app/__init__.py create mode 100644 preprocessor/app/config/__init__.py create mode 100644 preprocessor/app/config/config.py create mode 100644 preprocessor/app/db/__init__.py create mode 100644 preprocessor/app/db/database.py create mode 100644 preprocessor/app/models/__init__.py create mode 100644 preprocessor/app/models/models.py create mode 100644 preprocessor/app/utils/__init__.py create mode 100644 preprocessor/app/utils/image.py create mode 100644 preprocessor/app/utils/pdf.py create mode 100644 preprocessor/docker-compose.yml create mode 100644 preprocessor/main.py create mode 100644 preprocessor/requirements.txt diff --git a/.gitignore b/.gitignore index f5eea6f..495f044 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,7 @@ .env.production.local # devbox stuff -.devbox/* \ No newline at end of file +.devbox/* + +# python cache +__pycache__ \ No newline at end of file diff --git a/Makefile b/Makefile index 269cd98..b1438dc 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ build: bun run build dev: + docker-compose -p preprocessor -f ./preprocessor/docker-compose.yml up -d bun dev local-up: db @@ -29,3 +30,4 @@ db-seed: lint-staged: bun lint-staged + diff --git a/build/local/docker-compose.yml b/build/local/docker-compose.yml index 8bbb1a0..be71e51 100644 --- a/build/local/docker-compose.yml +++ b/build/local/docker-compose.yml @@ -15,3 +15,4 @@ volumes: networks: default: name: chatbot-builder-network + external: true diff --git a/bun.lockb b/bun.lockb index 57974bc8b07c19d5c03c8855d0a4f8d5ec0a4671..1d10aff8fd9f79e484840abdab1a6de66d2e360b 100755 GIT binary patch delta 104663 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
<8Vsg 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 sh%Q}6UtEE3pIp|puTE>Q=h^4~?|v3;+NC delta 97702 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 Yi>~oe)t_tC5su{5U1(p8T5NIpKde)u$^ZZW diff --git a/preprocessor/Dockerfile b/preprocessor/Dockerfile new file mode 100644 index 0000000..64829f8 --- /dev/null +++ b/preprocessor/Dockerfile @@ -0,0 +1,15 @@ +FROM python:3.12 + +WORKDIR /preprocessor + +RUN apt-get update && apt-get install ffmpeg libsm6 libxext6 poppler-utils tesseract-ocr -y + +COPY ./requirements.txt /preprocessor/requirements.txt + +RUN pip install --no-cache-dir -r /preprocessor/requirements.txt + +COPY . /preprocessor/ + +EXPOSE 80 + +CMD ["fastapi", "run", "main.py", "--port", "80"] \ No newline at end of file diff --git a/preprocessor/app/__init__.py b/preprocessor/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/preprocessor/app/config/__init__.py b/preprocessor/app/config/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/preprocessor/app/config/config.py b/preprocessor/app/config/config.py new file mode 100644 index 0000000..4a7213b --- /dev/null +++ b/preprocessor/app/config/config.py @@ -0,0 +1,11 @@ +import os + +from dotenv import load_dotenv +from pydantic_settings import BaseSettings + +load_dotenv() + +class Settings(BaseSettings): + database_url: str =os.getenv("DATABASE_URL") + +settings = Settings() \ No newline at end of file diff --git a/preprocessor/app/db/__init__.py b/preprocessor/app/db/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/preprocessor/app/db/database.py b/preprocessor/app/db/database.py new file mode 100644 index 0000000..1bb0efa --- /dev/null +++ b/preprocessor/app/db/database.py @@ -0,0 +1,19 @@ +from app.config.config import settings +from sqlalchemy import create_engine +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker + +SQLALCHEMY_DATABASE_URL = settings.database_url + +engine = create_engine(SQLALCHEMY_DATABASE_URL) + +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + +Base = declarative_base() + +def get_db(): + db = SessionLocal() + try: + yield db + finally: + db.close() \ No newline at end of file diff --git a/preprocessor/app/models/__init__.py b/preprocessor/app/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/preprocessor/app/models/models.py b/preprocessor/app/models/models.py new file mode 100644 index 0000000..622e3c0 --- /dev/null +++ b/preprocessor/app/models/models.py @@ -0,0 +1,518 @@ +import datetime +import uuid +from typing import Any, List, Optional + +from pgvector.sqlalchemy import Vector +from sqlalchemy import (Boolean, DateTime, ForeignKeyConstraint, Index, + Integer, PrimaryKeyConstraint, String, Text, Uuid, + text) +from sqlalchemy.dialects.postgresql import JSONB +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship + + +class Base(DeclarativeBase): + pass + + +class LogType(Base): + __tablename__ = 'log_type' + __table_args__ = ( + PrimaryKeyConstraint('id', name='log_type_pkey'), + ) + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + name: Mapped[Optional[str]] = mapped_column(String(256)) + + +class SubscriptionPlan(Base): + __tablename__ = 'subscription_plan' + __table_args__ = ( + PrimaryKeyConstraint('id', name='subscription_plan_pkey'), + ) + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + name: Mapped[Optional[str]] = mapped_column(String(255)) + description: Mapped[Optional[str]] = mapped_column(Text) + weekly_price: Mapped[Optional[int]] = mapped_column(Integer) + monthly_price: Mapped[Optional[int]] = mapped_column(Integer) + yearly_price: Mapped[Optional[int]] = mapped_column(Integer) + created_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime) + + user: Mapped[List['User']] = relationship('User', back_populates='subscription_plan') + invoice: Mapped[List['Invoice']] = relationship('Invoice', back_populates='plan') + + +class User(Base): + __tablename__ = 'user' + __table_args__ = ( + ForeignKeyConstraint(['subscription_plan_id'], ['subscription_plan.id'], name='user_subscription_plan_id_subscription_plan_id_fk'), + PrimaryKeyConstraint('id', name='user_pkey') + ) + + id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True,default=uuid.uuid4) + email: Mapped[str] = mapped_column(Text) + created_at: Mapped[datetime.datetime] = mapped_column(DateTime, server_default=text('now()')) + subscription_plan_id: Mapped[Optional[int]] = mapped_column(Integer) + name: Mapped[Optional[str]] = mapped_column(Text) + last_name: Mapped[Optional[str]] = mapped_column(Text) + emailVerified: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime) + image: Mapped[Optional[str]] = mapped_column(Text) + created_by: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + updated_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime) + updated_by: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + + subscription_plan: Mapped['SubscriptionPlan'] = relationship('SubscriptionPlan', back_populates='user') + account: Mapped[List['Account']] = relationship('Account', back_populates='user') + attachment: Mapped[List['Attachment']] = relationship('Attachment', foreign_keys='[Attachment.created_by]', back_populates='user') + attachment_: Mapped[List['Attachment']] = relationship('Attachment', foreign_keys='[Attachment.updated_by]', back_populates='user_') + attachment1: Mapped[List['Attachment']] = relationship('Attachment', foreign_keys='[Attachment.user_id]', back_populates='user1') + bot_model: Mapped[List['BotModel']] = relationship('BotModel', foreign_keys='[BotModel.created_by]', back_populates='user') + bot_model_: Mapped[List['BotModel']] = relationship('BotModel', foreign_keys='[BotModel.updated_by]', back_populates='user_') + bot_source_status: Mapped[List['BotSourceStatus']] = relationship('BotSourceStatus', back_populates='user') + bot_source_type: Mapped[List['BotSourceType']] = relationship('BotSourceType', back_populates='user') + feedback_type: Mapped[List['FeedbackType']] = relationship('FeedbackType', back_populates='user') + invoice: Mapped[List['Invoice']] = relationship('Invoice', foreign_keys='[Invoice.created_by]', back_populates='user') + invoice_: Mapped[List['Invoice']] = relationship('Invoice', foreign_keys='[Invoice.user_id]', back_populates='user_') + session: Mapped[List['Session']] = relationship('Session', back_populates='user') + bot: Mapped[List['Bot']] = relationship('Bot', foreign_keys='[Bot.created_by]', back_populates='user') + bot_: Mapped[List['Bot']] = relationship('Bot', foreign_keys='[Bot.updated_by]', back_populates='user_') + bot1: Mapped[List['Bot']] = relationship('Bot', foreign_keys='[Bot.user_id]', back_populates='user1') + bot_integration: Mapped[List['BotIntegration']] = relationship('BotIntegration', foreign_keys='[BotIntegration.created_by]', back_populates='user') + bot_integration_: Mapped[List['BotIntegration']] = relationship('BotIntegration', foreign_keys='[BotIntegration.updated_by]', back_populates='user_') + bot_source: Mapped[List['BotSource']] = relationship('BotSource', foreign_keys='[BotSource.created_by]', back_populates='user') + bot_source_: Mapped[List['BotSource']] = relationship('BotSource', foreign_keys='[BotSource.updated_by]', back_populates='user_') + thread: Mapped[List['Thread']] = relationship('Thread', foreign_keys='[Thread.created_by]', back_populates='user') + thread_: Mapped[List['Thread']] = relationship('Thread', foreign_keys='[Thread.updated_by]', back_populates='user_') + thread1: Mapped[List['Thread']] = relationship('Thread', foreign_keys='[Thread.user_id]', back_populates='user1') + bot_source_extracted_data: Mapped[List['BotSourceExtractedData']] = relationship('BotSourceExtractedData', back_populates='user') + chat: Mapped[List['Chat']] = relationship('Chat', foreign_keys='[Chat.chat_user_id]', back_populates='chat_user') + chat_: Mapped[List['Chat']] = relationship('Chat', foreign_keys='[Chat.created_by]', back_populates='user') + chat1: Mapped[List['Chat']] = relationship('Chat', foreign_keys='[Chat.updated_by]', back_populates='user_') + bot_source_extracted_data_vector: Mapped[List['BotSourceExtractedDataVector']] = relationship('BotSourceExtractedDataVector', back_populates='user') + chat_feedback: Mapped[List['ChatFeedback']] = relationship('ChatFeedback', foreign_keys='[ChatFeedback.created_by]', back_populates='user') + chat_feedback_: Mapped[List['ChatFeedback']] = relationship('ChatFeedback', foreign_keys='[ChatFeedback.updated_by]', back_populates='user_') + + +class Account(Base): + __tablename__ = 'account' + __table_args__ = ( + ForeignKeyConstraint(['userId'], ['user.id'], name='account_userId_user_id_fk'), + PrimaryKeyConstraint('provider', 'providerAccountId', name='account_provider_providerAccountId_pk'), + Index('account_userId_idx', 'userId') + ) + + userId: Mapped[uuid.UUID] = mapped_column(Uuid) + type: Mapped[str] = mapped_column(String(255)) + provider: Mapped[str] = mapped_column(String(255), primary_key=True) + providerAccountId: Mapped[str] = mapped_column(String(255), primary_key=True) + refresh_token: Mapped[Optional[str]] = mapped_column(Text) + access_token: Mapped[Optional[str]] = mapped_column(Text) + expires_at: Mapped[Optional[int]] = mapped_column(Integer) + token_type: Mapped[Optional[str]] = mapped_column(String(255)) + scope: Mapped[Optional[str]] = mapped_column(String(255)) + id_token: Mapped[Optional[str]] = mapped_column(Text) + session_state: Mapped[Optional[str]] = mapped_column(String(255)) + + user: Mapped['User'] = relationship('User', back_populates='account') + + +class Attachment(Base): + __tablename__ = 'attachment' + __table_args__ = ( + ForeignKeyConstraint(['created_by'], ['user.id'], name='attachment_created_by_user_id_fk'), + ForeignKeyConstraint(['updated_by'], ['user.id'], name='attachment_updated_by_user_id_fk'), + ForeignKeyConstraint(['user_id'], ['user.id'], name='attachment_user_id_user_id_fk'), + PrimaryKeyConstraint('id', name='attachment_pkey'), + Index('attachment_user_id_idx', 'user_id') + ) + + id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4) + user_id: Mapped[uuid.UUID] = mapped_column(Uuid) + type_id: Mapped[int] = mapped_column(Integer) + created_at: Mapped[datetime.datetime] = mapped_column(DateTime, server_default=text('now()')) + original_name: Mapped[Optional[str]] = mapped_column(Text) + cloud_path: Mapped[Optional[str]] = mapped_column(Text) + created_by: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + updated_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime) + updated_by: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + + user: Mapped['User'] = relationship('User', foreign_keys=[created_by], back_populates='attachment') + user_: Mapped['User'] = relationship('User', foreign_keys=[updated_by], back_populates='attachment_') + user1: Mapped['User'] = relationship('User', foreign_keys=[user_id], back_populates='attachment1') + bot: Mapped[List['Bot']] = relationship('Bot', foreign_keys='[Bot.bot_avatar_attachment_id]', back_populates='bot_avatar_attachment') + bot_: Mapped[List['Bot']] = relationship('Bot', foreign_keys='[Bot.company_logo_attachment_id]', back_populates='company_logo_attachment') + + +class BotModel(Base): + __tablename__ = 'bot_model' + __table_args__ = ( + ForeignKeyConstraint(['created_by'], ['user.id'], name='bot_model_created_by_user_id_fk'), + ForeignKeyConstraint(['updated_by'], ['user.id'], name='bot_model_updated_by_user_id_fk'), + PrimaryKeyConstraint('id', name='bot_model_pkey') + ) + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + created_at: Mapped[datetime.datetime] = mapped_column(DateTime, server_default=text('now()')) + name: Mapped[Optional[str]] = mapped_column(Text) + created_by: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + updated_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime) + updated_by: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + + user: Mapped['User'] = relationship('User', foreign_keys=[created_by], back_populates='bot_model') + user_: Mapped['User'] = relationship('User', foreign_keys=[updated_by], back_populates='bot_model_') + bot: Mapped[List['Bot']] = relationship('Bot', back_populates='model') + chat: Mapped[List['Chat']] = relationship('Chat', back_populates='bot_model') + + +class BotSourceStatus(Base): + __tablename__ = 'bot_source_status' + __table_args__ = ( + ForeignKeyConstraint(['created_by'], ['user.id'], name='bot_source_status_created_by_user_id_fk'), + PrimaryKeyConstraint('id', name='bot_source_status_pkey') + ) + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + created_at: Mapped[datetime.datetime] = mapped_column(DateTime, server_default=text('now()')) + name: Mapped[Optional[str]] = mapped_column(Text) + created_by: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + + user: Mapped['User'] = relationship('User', back_populates='bot_source_status') + + +class BotSourceType(Base): + __tablename__ = 'bot_source_type' + __table_args__ = ( + ForeignKeyConstraint(['created_by'], ['user.id'], name='bot_source_type_created_by_user_id_fk'), + PrimaryKeyConstraint('id', name='bot_source_type_pkey') + ) + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + name: Mapped[Optional[str]] = mapped_column(Text) + visible: Mapped[Optional[bool]] = mapped_column(Boolean) + created_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime) + created_by: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + + user: Mapped['User'] = relationship('User', back_populates='bot_source_type') + + +class FeedbackType(Base): + __tablename__ = 'feedback_type' + __table_args__ = ( + ForeignKeyConstraint(['created_by'], ['user.id'], name='feedback_type_created_by_user_id_fk'), + PrimaryKeyConstraint('id', name='feedback_type_pkey') + ) + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + created_at: Mapped[datetime.datetime] = mapped_column(DateTime, server_default=text('now()')) + name: Mapped[Optional[str]] = mapped_column(Text) + created_by: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + + user: Mapped['User'] = relationship('User', back_populates='feedback_type') + + +class Invoice(Base): + __tablename__ = 'invoice' + __table_args__ = ( + ForeignKeyConstraint(['created_by'], ['user.id'], name='invoice_created_by_user_id_fk'), + ForeignKeyConstraint(['plan_id'], ['subscription_plan.id'], name='invoice_plan_id_subscription_plan_id_fk'), + ForeignKeyConstraint(['user_id'], ['user.id'], name='invoice_user_id_user_id_fk'), + PrimaryKeyConstraint('id', name='invoice_pkey'), + Index('invoice_plan_id_idx', 'plan_id'), + Index('invoice_user_id_idx', 'user_id') + ) + + id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4) + plan_id: Mapped[int] = mapped_column(Integer) + user_id: Mapped[uuid.UUID] = mapped_column(Uuid) + created_at: Mapped[datetime.datetime] = mapped_column(DateTime, server_default=text('now()')) + amount: Mapped[Optional[str]] = mapped_column(Text) + created_by: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + + user: Mapped['User'] = relationship('User', foreign_keys=[created_by], back_populates='invoice') + plan: Mapped['SubscriptionPlan'] = relationship('SubscriptionPlan', back_populates='invoice') + user_: Mapped['User'] = relationship('User', foreign_keys=[user_id], back_populates='invoice_') + + +class Session(Base): + __tablename__ = 'session' + __table_args__ = ( + ForeignKeyConstraint(['userId'], ['user.id'], name='session_userId_user_id_fk'), + PrimaryKeyConstraint('sessionToken', name='session_pkey'), + Index('session_user_id_idx', 'userId') + ) + + sessionToken: Mapped[str] = mapped_column(String(255), primary_key=True) + userId: Mapped[uuid.UUID] = mapped_column(Uuid) + expires: Mapped[datetime.datetime] = mapped_column(DateTime) + + user: Mapped['User'] = relationship('User', back_populates='session') + + +class Bot(Base): + __tablename__ = 'bot' + __table_args__ = ( + ForeignKeyConstraint(['bot_avatar_attachment_id'], ['attachment.id'], name='bot_bot_avatar_attachment_id_attachment_id_fk'), + ForeignKeyConstraint(['company_logo_attachment_id'], ['attachment.id'], name='bot_company_logo_attachment_id_attachment_id_fk'), + ForeignKeyConstraint(['created_by'], ['user.id'], name='bot_created_by_user_id_fk'), + ForeignKeyConstraint(['model_id'], ['bot_model.id'], name='bot_model_id_bot_model_id_fk'), + ForeignKeyConstraint(['updated_by'], ['user.id'], name='bot_updated_by_user_id_fk'), + ForeignKeyConstraint(['user_id'], ['user.id'], name='bot_user_id_user_id_fk'), + PrimaryKeyConstraint('id', name='bot_pkey') + ) + + id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4) + user_id: Mapped[uuid.UUID] = mapped_column(Uuid) + model_id: Mapped[int] = mapped_column(Integer) + status: Mapped[int] = mapped_column(Integer, server_default=text('1')) + created_at: Mapped[datetime.datetime] = mapped_column(DateTime, server_default=text('now()')) + name: Mapped[Optional[str]] = mapped_column(Text) + description: Mapped[Optional[str]] = mapped_column(Text) + company_logo_attachment_id: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + bot_avatar_attachment_id: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + chat_bubble_icon_id: Mapped[Optional[int]] = mapped_column(Integer) + accent_colour: Mapped[Optional[str]] = mapped_column(Text) + subheading: Mapped[Optional[str]] = mapped_column(Text) + welcome_msg: Mapped[Optional[str]] = mapped_column(Text) + input_box_placeholder: Mapped[Optional[str]] = mapped_column(Text) + show_branding_on_widget: Mapped[Optional[str]] = mapped_column(Text) + widget_position: Mapped[Optional[int]] = mapped_column(Integer) + widget_name: Mapped[Optional[str]] = mapped_column(Text) + widget_subheading: Mapped[Optional[str]] = mapped_column(Text) + widget_placeholder: Mapped[Optional[str]] = mapped_column(Text) + widget_welcome_message: Mapped[Optional[str]] = mapped_column(Text) + show_source_with_response: Mapped[Optional[str]] = mapped_column(Text) + post_chat_feedback: Mapped[Optional[str]] = mapped_column(Text) + widget_open_default: Mapped[Optional[str]] = mapped_column(Text) + show_floating_welcome_msg: Mapped[Optional[str]] = mapped_column(Text) + show_floating_starter_questions: Mapped[Optional[str]] = mapped_column(Text) + uploaded_chars: Mapped[Optional[int]] = mapped_column(Integer) + max_chars: Mapped[Optional[int]] = mapped_column(Integer) + max_msg_count: Mapped[Optional[int]] = mapped_column(Integer) + msg_count: Mapped[Optional[int]] = mapped_column(Integer) + multi_languages_support: Mapped[Optional[str]] = mapped_column(Text) + response_length: Mapped[Optional[int]] = mapped_column(Integer) + send_email_transcript: Mapped[Optional[str]] = mapped_column(Text) + suggest_followup_questions: Mapped[Optional[str]] = mapped_column(Text) + customization: Mapped[Optional[str]] = mapped_column(Text) + no_source_warning_message: Mapped[Optional[str]] = mapped_column(Text) + server_error_message: Mapped[Optional[str]] = mapped_column(Text) + no_relevant_context_message: Mapped[Optional[str]] = mapped_column(Text) + usage_limit_per_user: Mapped[Optional[int]] = mapped_column(Integer) + usage_limit_per_user_type: Mapped[Optional[int]] = mapped_column(Integer) + user_limit_warning_msg: Mapped[Optional[str]] = mapped_column(Text) + while_list_ips_only: Mapped[Optional[str]] = mapped_column(Text) + created_by: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + updated_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime) + updated_by: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + + bot_avatar_attachment: Mapped['Attachment'] = relationship('Attachment', foreign_keys=[bot_avatar_attachment_id], back_populates='bot') + company_logo_attachment: Mapped['Attachment'] = relationship('Attachment', foreign_keys=[company_logo_attachment_id], back_populates='bot_') + user: Mapped['User'] = relationship('User', foreign_keys=[created_by], back_populates='bot') + model: Mapped['BotModel'] = relationship('BotModel', back_populates='bot') + user_: Mapped['User'] = relationship('User', foreign_keys=[updated_by], back_populates='bot_') + user1: Mapped['User'] = relationship('User', foreign_keys=[user_id], back_populates='bot1') + bot_integration: Mapped[List['BotIntegration']] = relationship('BotIntegration', back_populates='bot') + bot_source: Mapped[List['BotSource']] = relationship('BotSource', back_populates='bot') + thread: Mapped[List['Thread']] = relationship('Thread', back_populates='bot') + + +class BotIntegration(Base): + __tablename__ = 'bot_integration' + __table_args__ = ( + ForeignKeyConstraint(['bot_id'], ['bot.id'], name='bot_integration_bot_id_bot_id_fk'), + ForeignKeyConstraint(['created_by'], ['user.id'], name='bot_integration_created_by_user_id_fk'), + ForeignKeyConstraint(['updated_by'], ['user.id'], name='bot_integration_updated_by_user_id_fk'), + PrimaryKeyConstraint('id', name='bot_integration_pkey'), + Index('bot_integration_api_token_idx', 'api_token'), + Index('bot_integration_bot_id_idx', 'bot_id') + ) + + id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4) + bot_id: Mapped[uuid.UUID] = mapped_column(Uuid) + created_at: Mapped[datetime.datetime] = mapped_column(DateTime, server_default=text('now()')) + embeded_token: Mapped[Optional[str]] = mapped_column(Text) + api_token: Mapped[Optional[str]] = mapped_column(Text) + white_list_ips: Mapped[Optional[str]] = mapped_column(Text) + created_by: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + updated_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime) + updated_by: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + + bot: Mapped['Bot'] = relationship('Bot', back_populates='bot_integration') + user: Mapped['User'] = relationship('User', foreign_keys=[created_by], back_populates='bot_integration') + user_: Mapped['User'] = relationship('User', foreign_keys=[updated_by], back_populates='bot_integration_') + + +class BotSource(Base): + __tablename__ = 'bot_source' + __table_args__ = ( + ForeignKeyConstraint(['bot_id'], ['bot.id'], name='bot_source_bot_id_bot_id_fk'), + ForeignKeyConstraint(['created_by'], ['user.id'], name='bot_source_created_by_user_id_fk'), + ForeignKeyConstraint(['parent_id'], ['bot_source.id'], name='bot_sources_parent_id_fk'), + ForeignKeyConstraint(['updated_by'], ['user.id'], name='bot_source_updated_by_user_id_fk'), + PrimaryKeyConstraint('id', name='bot_source_pkey'), + Index('bot_source_bot_id_idx', 'bot_id'), + Index('bot_source_parent_id_idx', 'parent_id'), + Index('bot_source_status_id_idx', 'status_id'), + Index('bot_source_type_id_idx', 'type_id') + ) + + id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4) + bot_id: Mapped[uuid.UUID] = mapped_column(Uuid) + type_id: Mapped[int] = mapped_column(Integer) + status_id: Mapped[int] = mapped_column(Integer) + created_at: Mapped[datetime.datetime] = mapped_column(DateTime, server_default=text('now()')) + parent_id: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + url: Mapped[Optional[str]] = mapped_column(Text) + name: Mapped[Optional[str]] = mapped_column(Text) + extracted_token_length: Mapped[Optional[int]] = mapped_column(Integer) + created_by: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + updated_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime) + updated_by: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + visible: Mapped[Optional[bool]] = mapped_column(Boolean, server_default=text('true')) + + bot: Mapped['Bot'] = relationship('Bot', back_populates='bot_source') + user: Mapped['User'] = relationship('User', foreign_keys=[created_by], back_populates='bot_source') + parent: Mapped['BotSource'] = relationship('BotSource', remote_side=[id], back_populates='parent_reverse') + parent_reverse: Mapped[List['BotSource']] = relationship('BotSource', remote_side=[parent_id], back_populates='parent') + user_: Mapped['User'] = relationship('User', foreign_keys=[updated_by], back_populates='bot_source_') + bot_source_extracted_data: Mapped[List['BotSourceExtractedData']] = relationship('BotSourceExtractedData', back_populates='bot_source') + + +class Thread(Base): + __tablename__ = 'thread' + __table_args__ = ( + ForeignKeyConstraint(['bot_id'], ['bot.id'], name='thread_bot_id_bot_id_fk'), + ForeignKeyConstraint(['created_by'], ['user.id'], name='thread_created_by_user_id_fk'), + ForeignKeyConstraint(['updated_by'], ['user.id'], name='thread_updated_by_user_id_fk'), + ForeignKeyConstraint(['user_id'], ['user.id'], name='thread_user_id_user_id_fk'), + PrimaryKeyConstraint('id', name='thread_pkey'), + Index('thread_bot_id_idx', 'bot_id'), + Index('thread_user_id_idx', 'user_id') + ) + + id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4) + bot_id: Mapped[uuid.UUID] = mapped_column(Uuid) + created_at: Mapped[datetime.datetime] = mapped_column(DateTime, server_default=text('now()')) + user_id: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + title: Mapped[Optional[str]] = mapped_column(Text) + created_by: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + updated_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime) + updated_by: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + + bot: Mapped['Bot'] = relationship('Bot', back_populates='thread') + user: Mapped['User'] = relationship('User', foreign_keys=[created_by], back_populates='thread') + user_: Mapped['User'] = relationship('User', foreign_keys=[updated_by], back_populates='thread_') + user1: Mapped['User'] = relationship('User', foreign_keys=[user_id], back_populates='thread1') + chat: Mapped[List['Chat']] = relationship('Chat', back_populates='thread') + chat_feedback: Mapped[List['ChatFeedback']] = relationship('ChatFeedback', back_populates='thread') + + +class BotSourceExtractedData(Base): + __tablename__ = 'bot_source_extracted_data' + __table_args__ = ( + ForeignKeyConstraint(['bot_source_id'], ['bot_source.id'], name='bot_source_extracted_data_bot_source_id_bot_source_id_fk'), + ForeignKeyConstraint(['created_by'], ['user.id'], name='bot_source_extracted_data_created_by_user_id_fk'), + PrimaryKeyConstraint('id', name='bot_source_extracted_data_pkey'), + Index('bot_source_extracted_data_bot_source_id_idx', 'bot_source_id') + ) + + id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4) + bot_source_id: Mapped[uuid.UUID] = mapped_column(Uuid) + created_at: Mapped[datetime.datetime] = mapped_column(DateTime, server_default=text('now()')) + data: Mapped[Optional[dict]] = mapped_column(JSONB) + created_by: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + + bot_source: Mapped['BotSource'] = relationship('BotSource', back_populates='bot_source_extracted_data') + user: Mapped['User'] = relationship('User', back_populates='bot_source_extracted_data') + bot_source_extracted_data_vector: Mapped[List['BotSourceExtractedDataVector']] = relationship('BotSourceExtractedDataVector', back_populates='bot_source_extracted_data') + + +class Chat(Base): + __tablename__ = 'chat' + __table_args__ = ( + ForeignKeyConstraint(['bot_model_id'], ['bot_model.id'], name='chat_bot_model_id_bot_model_id_fk'), + ForeignKeyConstraint(['chat_user_id'], ['user.id'], name='chat_chat_user_id_user_id_fk'), + ForeignKeyConstraint(['created_by'], ['user.id'], name='chat_created_by_user_id_fk'), + ForeignKeyConstraint(['parent_chat_id'], ['chat.id'], name='chat_parent_chat_id_fk'), + ForeignKeyConstraint(['thread_id'], ['thread.id'], name='chat_thread_id_thread_id_fk'), + ForeignKeyConstraint(['updated_by'], ['user.id'], name='chat_updated_by_user_id_fk'), + PrimaryKeyConstraint('id', name='chat_pkey'), + Index('chat_chat_user_id_idx', 'chat_user_id'), + Index('chat_thread_id_idx', 'thread_id') + ) + + id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4) + thread_id: Mapped[uuid.UUID] = mapped_column(Uuid) + role_id: Mapped[int] = mapped_column(Integer) + bot_model_id: Mapped[int] = mapped_column(Integer) + created_at: Mapped[datetime.datetime] = mapped_column(DateTime, server_default=text('now()')) + msg: Mapped[Optional[str]] = mapped_column(Text) + storage_id: Mapped[Optional[str]] = mapped_column(Text) + chat_user_id: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + parent_chat_id: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + prompt: Mapped[Optional[str]] = mapped_column(Text) + promt_tokens: Mapped[Optional[int]] = mapped_column(Integer) + completion_tokens: Mapped[Optional[int]] = mapped_column(Integer) + total_tokens: Mapped[Optional[int]] = mapped_column(Integer) + created_by: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + updated_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime) + updated_by: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + + bot_model: Mapped['BotModel'] = relationship('BotModel', back_populates='chat') + chat_user: Mapped['User'] = relationship('User', foreign_keys=[chat_user_id], back_populates='chat') + user: Mapped['User'] = relationship('User', foreign_keys=[created_by], back_populates='chat_') + parent_chat: Mapped['Chat'] = relationship('Chat', remote_side=[id], back_populates='parent_chat_reverse') + parent_chat_reverse: Mapped[List['Chat']] = relationship('Chat', remote_side=[parent_chat_id], back_populates='parent_chat') + thread: Mapped['Thread'] = relationship('Thread', back_populates='chat') + user_: Mapped['User'] = relationship('User', foreign_keys=[updated_by], back_populates='chat1') + chat_feedback: Mapped[List['ChatFeedback']] = relationship('ChatFeedback', back_populates='chat') + + +class BotSourceExtractedDataVector(Base): + __tablename__ = 'bot_source_extracted_data_vector' + __table_args__ = ( + ForeignKeyConstraint(['bot_source_extracted_data_id'], ['bot_source_extracted_data.id'], name='bot_source_extracted_data_vector_bot_source_extracted_data_id_b'), + ForeignKeyConstraint(['created_by'], ['user.id'], name='bot_source_extracted_data_vector_created_by_user_id_fk'), + PrimaryKeyConstraint('id', name='bot_source_extracted_data_vector_pkey'), + Index('bot_source_extracted_data_vector_bot_source_extracted_data_id_i', 'bot_source_extracted_data_id'), + Index('bot_source_extracted_data_vector_vector_idx', 'vector') + ) + + id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4) + bot_source_extracted_data_id: Mapped[uuid.UUID] = mapped_column(Uuid) + created_at: Mapped[datetime.datetime] = mapped_column(DateTime, server_default=text('now()')) + content: Mapped[Optional[str]] = mapped_column(Text) + vector: Mapped[Optional[Any]] = mapped_column(Vector(1024)) + created_by: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + + bot_source_extracted_data: Mapped['BotSourceExtractedData'] = relationship('BotSourceExtractedData', back_populates='bot_source_extracted_data_vector') + user: Mapped['User'] = relationship('User', back_populates='bot_source_extracted_data_vector') + + +class ChatFeedback(Base): + __tablename__ = 'chat_feedback' + __table_args__ = ( + ForeignKeyConstraint(['chat_id'], ['chat.id'], name='chat_feedback_chat_id_chat_id_fk'), + ForeignKeyConstraint(['created_by'], ['user.id'], name='chat_feedback_created_by_user_id_fk'), + ForeignKeyConstraint(['thread_id'], ['thread.id'], name='chat_feedback_thread_id_thread_id_fk'), + ForeignKeyConstraint(['updated_by'], ['user.id'], name='chat_feedback_updated_by_user_id_fk'), + PrimaryKeyConstraint('id', name='chat_feedback_pkey'), + Index('chat_feedback_id_idx', 'chat_id'), + Index('feedback_type_id_idx', 'feedback_type'), + Index('threadId_feedback_id_idx', 'thread_id') + ) + + id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4) + thread_id: Mapped[uuid.UUID] = mapped_column(Uuid) + chat_id: Mapped[uuid.UUID] = mapped_column(Uuid) + feedback_type: Mapped[int] = mapped_column(Integer) + created_at: Mapped[datetime.datetime] = mapped_column(DateTime, server_default=text('now()')) + notes: Mapped[Optional[str]] = mapped_column(Text) + created_by: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + updated_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime) + updated_by: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid) + + chat: Mapped['Chat'] = relationship('Chat', back_populates='chat_feedback') + user: Mapped['User'] = relationship('User', foreign_keys=[created_by], back_populates='chat_feedback') + thread: Mapped['Thread'] = relationship('Thread', back_populates='chat_feedback') + user_: Mapped['User'] = relationship('User', foreign_keys=[updated_by], back_populates='chat_feedback_') \ No newline at end of file diff --git a/preprocessor/app/utils/__init__.py b/preprocessor/app/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/preprocessor/app/utils/image.py b/preprocessor/app/utils/image.py new file mode 100644 index 0000000..4adb084 --- /dev/null +++ b/preprocessor/app/utils/image.py @@ -0,0 +1,103 @@ +import base64 +import io +import os +import re + +from langchain_core.messages import HumanMessage +from langchain_openai import ChatOpenAI +from PIL import Image + + +def encode_image(image_path): + """Getting the base64 string""" + with open(image_path, "rb") as image_file: + return base64.b64encode(image_file.read()).decode("utf-8") + +def looks_like_base64(sb): + """Check if the string looks like base64""" + return re.match("^[A-Za-z0-9+/]+[=]{0,2}$", sb) is not None + + +def is_image_data(b64data): + """ + Check if the base64 data is an image by looking at the start of the data + """ + image_signatures = { + b"\xff\xd8\xff": "jpg", + b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a": "png", + b"\x47\x49\x46\x38": "gif", + b"\x52\x49\x46\x46": "webp", + } + try: + header = base64.b64decode(b64data)[:8] # Decode and get the first 8 bytes + for sig, format in image_signatures.items(): + if header.startswith(sig): + return True + return False + except Exception: + return False + + +def resize_base64_image(base64_string, size=(128, 128)): + """ + Resize an image encoded as a Base64 string + """ + # Decode the Base64 string + img_data = base64.b64decode(base64_string) + img = Image.open(io.BytesIO(img_data)) + + # Resize the image + resized_img = img.resize(size, Image.LANCZOS) + + # Save the resized image to a bytes buffer + buffered = io.BytesIO() + resized_img.save(buffered, format=img.format) + + # Encode the resized image to Base64 + return base64.b64encode(buffered.getvalue()).decode("utf-8") + + +def image_summarize(img_base64): + """Make image summary""" + prompt= """You are an assistant tasked with summarizing images for retrieval. \ + These summaries will be embedded and used to retrieve the raw image. \ + Give a concise summary of the image that is well optimized for retrieval.""" + + chat = ChatOpenAI(model="gpt-4o", max_tokens=1024) + + msg = chat.invoke( + [ + HumanMessage( + content=[ + {"type": "text", "text": prompt}, + { + "type": "image_url", + "image_url": {"url": f"data:image/jpeg;base64,{img_base64}"}, + }, + ] + ) + ] + ) + return msg.content + +def generate_img_summaries(path): + """ + Generate summaries and base64 encoded strings for images + path: Path to list of .jpg files extracted by Unstructured + """ + + # Store base64 encoded images + img_base64_list = [] + + # Store image summaries + image_summaries = [] + + # Apply to images + for img_file in sorted(os.listdir(path)): + if img_file.endswith(".jpg"): + img_path = os.path.join(path, img_file) + base64_image = encode_image(img_path) + img_base64_list.append(base64_image) + image_summaries.append(image_summarize(base64_image)) + + return img_base64_list, image_summaries \ No newline at end of file diff --git a/preprocessor/app/utils/pdf.py b/preprocessor/app/utils/pdf.py new file mode 100644 index 0000000..1b578cf --- /dev/null +++ b/preprocessor/app/utils/pdf.py @@ -0,0 +1,88 @@ +from langchain_core.output_parsers import StrOutputParser +from langchain_core.prompts import ChatPromptTemplate +from langchain_openai import ChatOpenAI +from markdownify import markdownify as md +from unstructured.partition.pdf import partition_pdf + + +def extract_pdf_elements(path, fname): + """ + Extract images, tables, and chunk text from a PDF file. + path: File path, which is used to dump images (.jpg) + fname: File name + """ + return partition_pdf( + filename=path + fname, + extract_images_in_pdf=True, + infer_table_structure=True, + chunking_strategy="by_title", + max_characters=4000, + new_after_n_chars=3800, + combine_text_under_n_chars=2000, + extract_image_block_types=["Image", "Table"], + extract_image_block_output_dir=path, + extract_image_block_to_payload=False + ) + + +# Categorize elements by type +def categorize_elements(raw_pdf_elements): + """ + Categorize extracted elements from a PDF into tables and texts. + raw_pdf_elements: List of unstructured.documents.elements + """ + tables = [] + texts = [] + for element in raw_pdf_elements: + if "unstructured.documents.elements.Table" in str(type(element)): + tables.append(md(element.metadata.text_as_html, heading_style="ATX")) + elif "unstructured.documents.elements.CompositeElement" in str(type(element)): + texts.append(str(element)) + return texts, tables + + +def generate_text_summaries(texts): + """ + Generate summaries of text elements + texts: List of str + """ + # Prompt + prompt_text = """You are an assistant tasked with summarizing text for retrieval. \ + These summaries will be embedded and used to retrieve the raw text elements. Text: {element} """ + prompt = ChatPromptTemplate.from_template(prompt_text) + + # Text summary chain + model = ChatOpenAI(temperature=0, model="gpt-4") + summarize_chain = {"element": lambda x: x} | prompt | model | StrOutputParser() + + # Initialize empty summaries + text_summaries = [] + + # Apply to text if texts are provided + if texts: + text_summaries = summarize_chain.batch(texts, {"max_concurrency": 5}) + + return text_summaries + +def generate_table_summaries(tables): + """ + Generate summaries of table elements + tables: List of str + """ + # Prompt + prompt_text = """You are an assistant tasked with summarizing tables for retrieval. \ + These summaries will be embedded and used to retrieve the raw table elements. Table: {element} """ + prompt = ChatPromptTemplate.from_template(prompt_text) + + # Table summary chain + model = ChatOpenAI(temperature=0, model="gpt-4") + summarize_chain = {"element": lambda x: x} | prompt | model | StrOutputParser() + + # Initialize empty summaries + table_summaries = [] + + # Apply to tables if tables are provided + if tables: + table_summaries = summarize_chain.batch(tables, {"max_concurrency": 5}) + + return table_summaries diff --git a/preprocessor/docker-compose.yml b/preprocessor/docker-compose.yml new file mode 100644 index 0000000..2c64fac --- /dev/null +++ b/preprocessor/docker-compose.yml @@ -0,0 +1,12 @@ +services: + preprocessor: + build: + context: . + dockerfile: Dockerfile + ports: + - 80:80 + +networks: + default: + name: chatbot-builder-network + external: true diff --git a/preprocessor/main.py b/preprocessor/main.py new file mode 100644 index 0000000..2d23a07 --- /dev/null +++ b/preprocessor/main.py @@ -0,0 +1,122 @@ +import os +import shutil +from typing import Union + +import requests +from app.db.database import get_db +from app.models.models import * +from app.utils.image import generate_img_summaries +from app.utils.pdf import (categorize_elements, extract_pdf_elements, + generate_table_summaries) +from fastapi import Depends, FastAPI, HTTPException +from langchain_openai.embeddings import OpenAIEmbeddings +from langchain_text_splitters import RecursiveCharacterTextSplitter +from pydantic import BaseModel +from sqlalchemy.orm import Session +from starlette import status + + +class SyncBotSourceRequest(BaseModel): + botSourceId: str + +app = FastAPI() + +@app.post("/api/sync-bot-source") +def sync_bot_source(request: SyncBotSourceRequest, db: Session = Depends(get_db)): + botsourceID = request.botSourceId + botSource = db.query(BotSource).filter(BotSource.id == botsourceID).first() + if botSource is None: + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f"Bot source not found") + + botSourceExtractedData = db.query(BotSourceExtractedData).filter(BotSourceExtractedData.bot_source_id == botsourceID).first() + if botSourceExtractedData is None: + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f"Bot source extracted data not found") + + try: + response = requests.get(botSource.url, stream=True) + response.raise_for_status() + except requests.exceptions.HTTPError as error: + raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"internal server error") + + current_directory = os.getcwd() + final_directory = os.path.join(current_directory, str(botsourceID)) + if os.path.exists(final_directory): + shutil.rmtree(final_directory) + os.makedirs(final_directory) + + filePath=os.path.join(final_directory, botSource.name) + pdf = open(filePath, 'wb') + pdf.write(response.content) + pdf.close() + + raw_pdf_elements = extract_pdf_elements(final_directory+'/', botSource.name) + + # Categorize elements by type + texts,tables=categorize_elements(raw_pdf_elements) + + joined_texts = " ".join(texts) + + text_splitter=RecursiveCharacterTextSplitter( + chunk_size=512, + chunk_overlap=64, + separators=[ + ' ', + '\n', + '\n\n', + ',', + '.', + '\u2022', + '\u200b', + '\uff0c', + '\u3001', + '\uff0e', + '\u3002' + ], + ) + text_chunks=text_splitter.create_documents([joined_texts]) + embeddings = OpenAIEmbeddings( + model='text-embedding-3-small', + dimensions=1024, + ) + embeddings_text_output = embeddings.embed_documents([text.page_content for text in text_chunks]) + + for i, embedding in enumerate(embeddings_text_output): + db.add(BotSourceExtractedDataVector( + bot_source_extracted_data_id=botSourceExtractedData.id, + content=text_chunks[i].page_content, + vector=embedding + )) + + table_summaries=generate_table_summaries(tables) + + embeddings_table_output = embeddings.embed_documents(table_summaries) + + for i, embedding in enumerate(embeddings_table_output): + db.add(BotSourceExtractedDataVector( + bot_source_extracted_data_id=botSourceExtractedData.id, + content=tables[i], + vector=embedding + )) + + # images + base64_img,img_summaries=generate_img_summaries(final_directory) + + embeddings_image_output = embeddings.embed_documents(img_summaries) + + for i, embedding in enumerate(embeddings_image_output): + db.add(BotSourceExtractedDataVector( + bot_source_extracted_data_id=botSourceExtractedData.id, + content=base64_img[i], + vector=embedding + )) + + shutil.rmtree(final_directory) + + try: + db.commit() + except Exception as e: + db.rollback() + raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"internal server error") + + return {"message": "ok"} + diff --git a/preprocessor/requirements.txt b/preprocessor/requirements.txt new file mode 100644 index 0000000..dc60e4f --- /dev/null +++ b/preprocessor/requirements.txt @@ -0,0 +1,27 @@ +fastapi[all] +pydantic +uvicorn[standard] +setuptools +sqlalchemy==2.0.31 +sqlacodegen==3.0.0rc5 +python-dotenv +tiktoken +langchain +langchain-openai +langchain-text-splitters +requests +bs4 +sentence_transformers +unstructured +openai +pgvector +psycopg2 +unstructured[all-docs] +pillow +pydantic +lxml +pillow +matplotlib +pdf2image +markdownify +psutil diff --git a/src/env.js b/src/env.js index 0f59ea2..bea59c8 100644 --- a/src/env.js +++ b/src/env.js @@ -9,7 +9,7 @@ export const env = createEnv({ server: { DATABASE_URL: z.string().url(), DATABASE_HOST: z.string(), - DATABASE_PORT: z.number(), + DATABASE_PORT: z.string(), DATABASE_NAME: z.string(), DATABASE_USER: z.string(), DATABASE_PASSWORD: z.string(), diff --git a/src/server/api/routers/bot-source.ts b/src/server/api/routers/bot-source.ts index d505b13..05fca0f 100644 --- a/src/server/api/routers/bot-source.ts +++ b/src/server/api/routers/bot-source.ts @@ -4,6 +4,7 @@ import { and, eq, inArray, sql, type InferSelectModel } from 'drizzle-orm' import { XMLParser } from 'fast-xml-parser' import { uuidv7 } from 'uuidv7' import { z } from 'zod' +import { syncBotSource } from '~/app/api/sync-bot-source/route' import { env } from '~/env' import { BotSourceStatusEnum } from '~/model/bot-source-status' import { BotSourceTypeEnum } from '~/model/bot-source-type' @@ -207,10 +208,10 @@ function createBotSourceHandler() { // Sync the bot source if (botSources.length) { for (const bs of botSources) { - // await syncBotSource(bs.id) + await syncBotSource(bs.id) // eslint-disable-next-line @typescript-eslint/no-floating-promises - submitSyncBotSource(bs.id) + //submitSyncBotSource(bs.id) } } diff --git a/src/server/api/routers/chat.ts b/src/server/api/routers/chat.ts index c1d191e..a2e5605 100644 --- a/src/server/api/routers/chat.ts +++ b/src/server/api/routers/chat.ts @@ -25,7 +25,7 @@ import { createTRPCRouter, integrationProcedure } from '../trpc' const reusablePool = new pg.Pool({ host: env.DATABASE_HOST, - port: env.DATABASE_PORT, + port: Number(env.DATABASE_PORT), user: env.DATABASE_USER, password: env.DATABASE_PASSWORD, database: env.DATABASE_NAME,