diff --git a/apps/masterbots.ai/app/b/[id]/[threadId]/page.tsx b/apps/masterbots.ai/app/b/[id]/[threadId]/page.tsx
new file mode 100644
index 00000000..f75f4276
--- /dev/null
+++ b/apps/masterbots.ai/app/b/[id]/[threadId]/page.tsx
@@ -0,0 +1,12 @@
+import { BrowseThread } from '@/components/browse-thread'
+import { ChatPageProps } from '@/app/chat/[chatbot]/[threadId]/page'
+import { getThread } from '@/app/actions'
+
+export { generateMbMetadata as generateMetadata } from '@/lib/metadata'
+
+export default async function ChatPage({ params }: ChatPageProps) {
+ const thread = await getThread({
+ threadId: params.threadId,
+ })
+ return
+}
diff --git a/apps/masterbots.ai/app/og/route.tsx b/apps/masterbots.ai/app/og/route.tsx
index 68bcc501..17c1d641 100644
--- a/apps/masterbots.ai/app/og/route.tsx
+++ b/apps/masterbots.ai/app/og/route.tsx
@@ -1,119 +1,48 @@
-/* eslint-disable @next/next/no-img-element */
-
import { ImageResponse } from '@vercel/og'
import { NextRequest } from 'next/server'
-import { GeistMono } from 'geist/font/mono' // Import the GeistMono font
import '@/app/globals.css'
-import { getThread } from '../actions'
-
+import { getThread } from '@/app/actions'
+import OgImage from '@/components/og-image'
export const runtime = 'edge'
export async function GET(req: NextRequest) {
try {
const { searchParams } = req.nextUrl
- const threadId = searchParams.get('threadId')
- const thread = await getThread({ threadId })
-
- // You may need to convert GeistMono or fetch it as ArrayBuffer if needed
- // const font = GeistMono; // Assuming GeistMono can be directly used, modify as needed
+ const threadId = searchParams.get('threadId');
+ const thread = await getThread({ threadId },)
+ const question = thread.firstMessage.content
+ const answer = thread.firstAnswer.content
+ const username = thread.account?.username
+ const user_avatar = thread.account?.avatar || ''
+ let theme = 'dark'
+ if (typeof window !== 'undefined') {
+ theme = localStorage.getItem('theme') || 'dark'
+ }
+ const isLightTheme = theme === 'light'
return new ImageResponse(
(
-
-
-
-
- {thread.chatbot.name}
-
-
- {thread.firstMessage.content}
-
-
- {thread.chatbot.categories[0].name}
-
-
- {thread.chatbot.avatar ? (
-
-
-
-
-
- ) : null}
-
-
+
),
{
width: 1200,
height: 627
}
)
- } catch (e) {
+ } catch (e: any) {
console.log(`${e.message}`)
return new Response(`Failed to generate the image`, {
status: 500
})
}
}
+function useTheme() {
+ throw new Error('Function not implemented.')
+}
diff --git a/apps/masterbots.ai/components/og-bg-image.tsx b/apps/masterbots.ai/components/og-bg-image.tsx
new file mode 100644
index 00000000..63a45ece
--- /dev/null
+++ b/apps/masterbots.ai/components/og-bg-image.tsx
@@ -0,0 +1,392 @@
+export default function OgBgImage({ isLightTheme }: { isLightTheme: boolean }) {
+ return (
+
+
+
+ )
+}
diff --git a/apps/masterbots.ai/components/og-image.tsx b/apps/masterbots.ai/components/og-image.tsx
new file mode 100644
index 00000000..08929d0d
--- /dev/null
+++ b/apps/masterbots.ai/components/og-image.tsx
@@ -0,0 +1,150 @@
+import OgBgImage from '@/components/og-bg-image'
+interface OgImageProps {
+ thread: any
+ question: string
+ answer: string
+ username: string | undefined
+ user_avatar: string
+ isLightTheme: boolean
+}
+
+export default function OgImage({ thread, question, answer, username, user_avatar, isLightTheme }: OgImageProps) {
+
+ return (
+
+
+
+
+
+ {thread.chatbot.name}
+
+
+ {' '}
+ {thread.chatbot.categories[0]?.category.name}
+
+
+ {question}
+
+
+ {answer}
+
+
+
+
+
+ {username}
+
+
+
+ {thread.chatbot.avatar ? (
+
+
+
+
+
+ ) : null}
+
+
+ )
+}
diff --git a/apps/masterbots.ai/lib/metadata.ts b/apps/masterbots.ai/lib/metadata.ts
index 72baded9..0f509c5b 100644
--- a/apps/masterbots.ai/lib/metadata.ts
+++ b/apps/masterbots.ai/lib/metadata.ts
@@ -1,19 +1,27 @@
+import { getThread } from '@/services/hasura'
import type { Metadata } from 'next'
-import { getThread } from '@/app/actions'
import { getThreadLink } from './threads'
export async function generateMbMetadata({
params
+}: {
+ params: any;
}): Promise {
- const thread = await getThread({ threadId: params.threadId })
+ const threadId = params?.threadId
+ const thread = await getThread({ threadId, jwt: '' })
if (!thread) return
+ const firstQuestion =
+ thread.messages.find(m => m.role === 'user')?.content || 'not found'
+ const firstResponse =
+ thread.messages.find(m => m.role === 'assistant')?.content || 'not found'
+
const data = {
- title: thread.firstMessage.content,
+ title: firstQuestion,
publishedAt: thread.updatedAt, // format(thread.updatedAt, 'MMMM dd, yyyy'),
- summary: thread.firstAnswer.content,
- image: `https://alpha.masterbots.ai/og?threadId=${thread.threadId}`,
- pathname: getThreadLink({ thread, chat: false })
+ summary: firstResponse,
+ image: `${process.env.VERCEL_URL}/og?threadId=${thread.threadId}`,
+ pathname: getThreadLink({ thread: thread, chat: false })
}
return {
@@ -25,7 +33,7 @@ export async function generateMbMetadata({
description: data.summary,
type: 'article',
publishedTime: data.publishedAt,
- url: `https://alpha.masterbots.ai/${data.pathname}`,
+ url: `${process.env.VERCEL_URL}${data.pathname}`,
images: [
{
url: data.image
diff --git a/apps/masterbots.ai/lib/threads.ts b/apps/masterbots.ai/lib/threads.ts
index 2472c94e..56e93b6d 100644
--- a/apps/masterbots.ai/lib/threads.ts
+++ b/apps/masterbots.ai/lib/threads.ts
@@ -1,6 +1,7 @@
import type * as AI from 'ai'
import { MB } from '@repo/supabase'
import { toSlug } from './url-params'
+import { extractBetweenMarkers } from '@/lib/utils'
export function createMessagePairs(messages: AI.Message[]): MB.MessagePair[] {
const messagePairs: MB.MessagePair[] = []
@@ -41,19 +42,38 @@ export function cleanPrompt(str: string) {
return extracted || str
}
+export interface MessagePair {
+ userMessage: MB.Message | AI.Message
+ chatGptMessage: MB.Message[]
+}
+
+export function convertMessage(message: MB.Message) {
+ return {
+ id: message.messageId,
+ content: message.content,
+ createAt: message.createdAt,
+ role: message.role
+ } as AI.Message
+}
+
+export function getAllUserMessagesAsStringArray(
+ allMessages: MB.Message[] | AI.Message[]
+) {
+ const userMessages = allMessages.filter(m => m.role === 'user')
+ const cleanMessages = userMessages.map(m =>
+ extractBetweenMarkers(m.content, 'Then answer this question:')
+ )
+ return cleanMessages.join(', ')
+}
+
export function getThreadLink({
chat = false,
- param = false,
thread
}: {
chat?: boolean
- param?: boolean
- thread: MB.ThreadFull
+ thread: MB.Thread
}) {
- console.log('getThreadLink', thread.chatbot?.categories)
- if (param)
- return `/${toSlug(thread.chatbot.categories[0].name)}?threadId=${thread.threadId.trim()}`
return chat
- ? `/c/${toSlug(thread.chatbot.name)}/${thread.threadId.trim()}`
- : `/${toSlug(thread.chatbot.categories[0].name)}/${thread.threadId.trim()}`
+ ? `/c/${toSlug(thread.chatbot.name)}/${thread.threadId}`
+ : `/${toSlug(thread.chatbot.categories[0]?.category.name)}/${thread.threadId}}`
}
diff --git a/apps/masterbots.ai/lib/url.ts b/apps/masterbots.ai/lib/url.ts
new file mode 100644
index 00000000..6fca4411
--- /dev/null
+++ b/apps/masterbots.ai/lib/url.ts
@@ -0,0 +1,29 @@
+import { z, ZodSchema } from 'zod'
+
+// Zod schema for validating slug strings
+export const SlugSchema: ZodSchema = z
+ .string()
+ .min(1)
+ .regex(/^[a-z0-9]+[a-z0-9+_-]*[a-z0-9]+$/, 'Invalid slug format.')
+
+// Function to convert a username into a slug
+export const toSlug = (username: string, separator = '_'): string => {
+ return username
+ .toLowerCase()
+ .replace(/ & /g, '_n_')
+ .replace(/&/g, '_')
+ .replace(/[^a-z0-9_+-]/g, separator)
+}
+
+
+
+//Encodes a string for use in a URL, replacing spaces with the '+' character.
+export const encodeQuery = (input: string): string => {
+ return encodeURIComponent(input).replace(/%20/g, '+').replace(/ /g, '+')
+}
+
+//Decodes a URL-encoded string, converting '+' back into spaces.
+
+export const decodeQuery = (input: string): string => {
+ return decodeURIComponent(input.replace(/\+/g, ' '))
+}
\ No newline at end of file
diff --git a/apps/masterbots.ai/package.json b/apps/masterbots.ai/package.json
index 8c26c901..afc0f2e1 100644
--- a/apps/masterbots.ai/package.json
+++ b/apps/masterbots.ai/package.json
@@ -68,7 +68,7 @@
"remark-math": "^5.1.1",
"ts-case-convert": "^2.0.7",
"use-debounce": "^10.0.0",
- "zod": "^3.22.4",
+ "zod": "^3.23.8",
"@repo/supabase": "workspace:*"
},
"devDependencies": {
diff --git a/apps/masterbots.ai/public/og-background-image.svg b/apps/masterbots.ai/public/og-background-image.svg
new file mode 100644
index 00000000..e69de29b
diff --git a/bun.lockb b/bun.lockb
index 5ab3f772..00f71681 100755
Binary files a/bun.lockb and b/bun.lockb differ