diff --git a/apps/masterbots.ai/app/(browse)/[category]/page.tsx b/apps/masterbots.ai/app/(browse)/[category]/page.tsx
index 97851750..790e2629 100644
--- a/apps/masterbots.ai/app/(browse)/[category]/page.tsx
+++ b/apps/masterbots.ai/app/(browse)/[category]/page.tsx
@@ -25,7 +25,7 @@ export default async function CategoryPage({
const limit = searchParams.limit ? parseInt(searchParams.limit) : 20
const page = searchParams.page ? parseInt(searchParams.page) : 1
- const threads = await getThreads({ query })
+ const threads = await getThreads()
// Extract users and total number of users from the result
// const users = result.users.items
diff --git a/apps/masterbots.ai/app/(browse)/page.tsx b/apps/masterbots.ai/app/(browse)/page.tsx
index 0771d1eb..216125e5 100644
--- a/apps/masterbots.ai/app/(browse)/page.tsx
+++ b/apps/masterbots.ai/app/(browse)/page.tsx
@@ -3,15 +3,16 @@ import { CategoryTabs } from '@/components/shared/category-tabs/category-tabs'
import { SearchInput } from '@/components/shared/search-input'
import { Card } from '@/components/ui/card'
import { decodeQuery } from '@/lib/url-params'
-import { getThreads } from '../actions'
+import { getThreads, getThreadsLike } from '../actions'
export default async function HomePage({ searchParams }: HomePageProps) {
const query = searchParams.query ? decodeQuery(searchParams.query) : null
const limit = searchParams.limit ? parseInt(searchParams.limit) : 20
const page = searchParams.page ? parseInt(searchParams.page) : 1
// console.log({ query, limit, page })
- const threads = await getThreads({ query })
+ const threads = await (query? getThreadsLike({ query }) : getThreads())
+ console.log(' ============== THREADS ============== ')
return (
diff --git a/apps/masterbots.ai/app/actions.ts b/apps/masterbots.ai/app/actions.ts
index aa04b36b..a27cda3c 100644
--- a/apps/masterbots.ai/app/actions.ts
+++ b/apps/masterbots.ai/app/actions.ts
@@ -1,10 +1,13 @@
'use server'
+
import { createSupabaseServerClient } from '@/services/supabase'
import { objectToCamel } from 'ts-case-convert'
import type { MB } from '@repo/supabase'
-import { omit } from 'lodash'
+import { omit, uniq } from 'lodash'
import { getFirstMessages } from '@/lib/threads'
+// TODO: move complex queries to postgres funciton, maybe even ts gen works
+
// Shared ThreadFull like filter for supabase queries
// It ensure you get the data you need to construct the ThreadFull object
// Important to select only the data you need, nothing more
@@ -15,14 +18,22 @@ const ThreadFullFilter = `
user (user_id,username,avatar)
` as const
-export async function getThreads({ query }: { query?: string }): Promise {
+export async function getThreads(): Promise {
const supabase = await createSupabaseServerClient()
- const threadsQuery = supabase.from('thread').select(ThreadFullFilter).range(0, 20)
- const { data, error } = await threadsQuery
- if (error) return []
- return data.map(createThreadFull)
+
+ let threadsQuery = supabase
+ .from('thread')
+ .select(ThreadFullFilter, { count: 'exact' });
+
+ const { data, error, count } = await threadsQuery.range(30, 39)
+ console.log('🤌🏻', count);
+
+ if (error) return [];
+ const filteredData = data.filter(thread => thread.message && thread.message.length > 0);
+ return filteredData.map(createThreadFull);
}
+
export async function getThread({
threadId
}: {
@@ -49,15 +60,82 @@ function createThreadFull(threadData: any, messageCount = 0) {
}) as unknown as MB.ThreadFull
}
+
+export async function getThreadsLike({ query }: { query?: string }) {
+ console.log('🧑🏻💻 get threads like', query)
+ const supabase = await createSupabaseServerClient();
+
+ // Fetch message IDs that match the content criteria and prioritize by role
+ let messageResults = await supabase
+ .from('message')
+ .select('id, thread_id') // Assuming messages have a 'thread_id' to link to their thread
+ .filter('content', 'ilike', `%${query}%`) // Using 'like' for content matching
+ .order('role', { ascending: false }) // Order by role descending to prioritize 'user' over 'assistant'
+ .in('role', ['user', 'assistant']); // Ensure only 'user' and 'assistant' roles are considered
+
+ if (messageResults.error || messageResults.data.length === 0) return [];
+
+
+ // Map to thread IDs for the next query
+ const threadIds = uniq(messageResults.data.map(msg => msg.thread_id))
+ console.log('🙌🏻 threadIds', threadIds.length)
+
+ // Fetch threads that have these message IDs
+ const threadsQuery = supabase
+ .from('thread')
+ .select(ThreadFullFilter)
+ // TODO: verify slicing doesnt affect priority
+ .in('thread_id', threadIds.slice(0,20))
+
+ const { data, error, count } = await threadsQuery;
+
+ console.log('🤌🏻', error, count, data?.length)
+
+ if (error) return [];
+
+ return data.map(createThreadFull)
+}
+
+export async function searchThreads({ query }: { query?: string }): Promise {
+ console.log('🧑🏻💻 search threads for', query)
+ const supabase = await createSupabaseServerClient()
+
+ // First, fetch message IDs that match the text search criteria
+ const threadIds = await supabase
+ .from('message')
+ .select(`thread_id`)
+ .filter('role', 'eq', 'user')
+ .textSearch('content', query, {
+ config: 'english',
+ type: 'websearch' // Using 'websearch' for more natural queries
+ });
+
+ console.log(threadIds.data?.length, threadIds?.data)
+
+ if (threadIds.error || threadIds.data?.length === 0) return [];
+
+ // Extract the message IDs to use in the main query
+ const ids = threadIds.data.map(msg => msg.thread_id);
+
+ // Now fetch threads that have these messages
+ const threadsQuery = supabase
+ .from('thread')
+ .select(ThreadFullFilter, { count: 'exact' })
+ .in('thread_id', ids.slice(0,20));
+
+ const { data, error, count } = await threadsQuery
+ console.log('🤌🏻', error, count, data?.length);
+
+ if (error) return [];
+ return data.map(createThreadFull)
+}
+
+
export async function getMessagePairs(threadId: string) {
console.log('get message pairs for', threadId)
return [] as MB.MessagePair[]
}
-// if (query) {
-// supaQuery = supaQuery
-// .filter('message.role', 'neq', 'system')
-// .textSearch('message.content', query.toString())
-// }
+
diff --git a/bun.lockb b/bun.lockb
index f3d6e89a..fb6c1e69 100755
Binary files a/bun.lockb and b/bun.lockb differ