Skip to content

Commit ee4a6df

Browse files
AndlerRLBran18sheriffjimohBrandon fernandez
authored
chore: june 1st release (#510)
* fix: change toggler wording + util hook (#424) * impr: makes threads open on profile page and profile tweaks (#421) * update * fix: update * update * update * update * update * fix: opening threads * fix: rm threads dropdwon & added back link to bot page thread view page * fix: rm threads dropdwon & added back link to bot page thread view page * fix: update * fix: added back to profile page * fix: added sticky and color * fix: codeblock ctas refactor markdown rendering, sidebar nav, code block & clipboard hook (#425) * fix: codeblock ctas * fix: ts build * fix: continue thread + allMessages sequence + mobile chat css tweak (#426) * fix: css handleCLick condition * fix: get latest search params, continuous thread * fix(impr): all messages sorting * perf(impr): sign in & up redirection tweak * perf(impr): mobile chat css * chore: next + react security ver upt (#427) * refactor: use chat and continue thread + continue conversation fallback (#432) * refactor: use chat and continue generation * fix: uniq slug and id gen (#433) * fix: uniq thread + msg slug gen * style: formatting * fix: thread user attachments state upt * perf: impr thread component at all pages + mobile tweaks * refactor: thread-component card * chore: restore continue generation v1 * feat(impr): thread component card * fix: admin panel n actions * fix: fetch getThreads * chore: continue conversation v1.2 * chore: continue and update thread content * chore: add ui control continue generation state * chore: fix infinity loop * chore(impr): enable upt msg table permission * fix: seo thread fetch * chore: style formating * fix(impr): continued thread title + thread component reusability * chore: refactor loadings + extending sonners --------- Co-authored-by: bran18 <andreyfdez18@gmail.com> --------- Co-authored-by: Roberto Lucas <andler@bitcash.org> * feat: add gemini provider (#437) * feat: add gemini provider * chore: update icons * feat: impr continuing thread tags + accordion first msg toggle (#435) * feat(wip): impr continuing thread tags + accordion first msg toggle * feat(impr): continuing thread tags + accordion at first message + header mobile tweak * style(impr): mobile thread-component x-axis space * perf(style): coderabbitai feedbacks * fix: css typo * perf: sendMessageFromResponse clicked guard + continued thread tags label tweak * chore: user thread panel clean up * fix: user-thread-panel infinite loader * perf: impr shared accordion animation and ux * style: defaultAccordionState comments loc * fix: record type warning, hasura updateMessage * fix: getThread user data, shared-accordion * fix: coderabbitai observations * fix: impr file management per llm, multimodel feat flag, chat tool labels, parent thread guard * fix: tunningUserContent parentThread condition * fix: feature flag typo * feat: profile page thread popup feature flag and tweaks (#434) * update * fix: update * update * update * update * update * refactor: profile page threads pop up * fix: update config * fix: update * fix: update * fix: make profile page scroll on hero * fix: bot make popup and scroll * fix: make profile page sidebar scroll independently * fix: make profile page sidebar scroll independently * fix: check the category along the chatbot when it's not checked * fix: check the category along the chatbot when it's not checked --------- Co-authored-by: Roberto Lucas <andler.dev@gmail.com> Co-authored-by: Roberto Lucas <andler@bitcash.org> * feat: add new llm models (#444) * feat-add-models * feat-add-models * feat-add-models * chore: add model * fix: typo * chore: add toggler color * perf(impr): thread llm context, last question & response + new models seeds (#447) * feat(wip): thread llm context, prev questions * fix: previousQuestionsString slice * fix: clickedContentId in followingQuestionsPrompt * feat: isContinued + model type in message table * fix: ts typo + sendMessageFromResponse callback call * fix: ts typo * fix: bot profile page view (#449) * fix(wip): bot profile thread list * style: formatting * fix: new chats and share + og img (#451) * fix: new chat state reset * fix: genql gen + share link check * fix: og img * fix: duplicate role permission in msg table * feat: initial continuation logic flow (#450) * chore: restore base version * chore: add new logic and hooks * chore: fix providers file * chore: improve continuation prompt * chore: add exlucision flag * chore: add better handler * chore: updated flow + experimental delay * chore: extended time * chore(impr): streamDelayMs experimental feat flag * style: formatting --------- Co-authored-by: Roberto Lucas <andler.dev@gmail.com> * fix: profile sidebar cat opt render (#453) * fix: profile sidebar cat opt render * chore: clean-up * [masterbots.ai] refactor: slug generation logic with improved uniqueness and type support (#456) * fix: slugify fn * chore: devMode logs * fix: uniq slug gen fn nanoid flag typo * feat: sentry logs in webapp (#457) * fix(impr): llm enum data, thread creation, ts, and log behavior (#458) * fix: slugify first request delay incr + genql ts, seeds & model migration upt * fix: create thread & msg ts * fix(impr): profile page bugs & tweaks v1 4/15/25 (#455) * update * fix: update * update * update * update * update * fix: use the user avatar or robohash * fix: added avater to user menu * fix: user avatar * fix: reset search input when filter by category or chatbot * fix: personal chat browse provider + username chk in sign up * chore: clean duplicated if condition signup --------- Co-authored-by: Roberto Lucas <andler.dev@gmail.com> * refactor: continuation flow (#460) * impr: continuation logic flow * impr: continuation logic flow * chore: update createImprovementPrompt * chore: upt logs --------- Co-authored-by: Roberto Lucas <andler.dev@gmail.com> * feat: models table, enum type, and refactor chat msg deduplication logic (#462) * feat: models table * style: formatting * fix: continuation accordion content * fix: sql + metadata typo * fix: db migrations and messages uniqby condition (#463) * fix: db migrations + messages uniqby condition * fix: typo * perf(impr): verify duplicate message return condition * chore: upt default available models * perf(impr): reassign continued prompt * chore: incr fn stream max duration * fix: mob prof sidebar + sign-up pw verif + username chk (#464) * fix: mob prof sidebar + sign-up pw verif + username chk * chore: upt genql gen * perf(impr): profile navigation * feat: model selector (#466) * wip: model selector query * wip: model selector query * chore: improve funtions * chore: add coderabbit suggestion * chore: add hasura permissions, models table * style: formatting * chore: fix get model client type * chore: add model --------- Co-authored-by: Roberto Romero Lucas <contact@andler.dev> * chore: impr models (#472) * chore: fix model name and condition (#473) * refactor: user fetching code (#471) * refactor: profile sidebar ui, upt styling, and disable prefetch (#470) * chore: remove prefetch on sidebar & profile navigation * perf: impr profile sidebar * fix: infinite scroll load more fetch * perf(impr): google sign-in * perf(impr): session loaders tweak * perf: impr categoriesId obtention * fix: tailwind typo * chore(impr): pro user guard in model selector * chore: category label upt to topic * chore: rm dev mode guard (#476) * feat: add reasoning compatibility (#480) * feat: add resoning stable * chore: add reasoning stable v * chore: activate reasoning * chore: activate reasoning * feat: pro users whitelist (#481) * feat(wip): whitelist pro users * chore: add whitelist pro users + page size fetch * perf(impr): following question impr prompt * fix: pro whitelist users clean up * feat: user account setting (#468) * update * fix: update * update * update * update * update * feat: imple account setting * feat: added dialog to delete button * feat: update user deletion func * fix: move back exmaples files * fix: update * fix: user account scheduling api * fix: user account deletion request function * refactor: account deletion request api * fix: user account request and thread deletion * fix: added permission and account deletion page * fix: update on permission * fix: enable new col permission * fix: profile side bar * fix: update * fix: function rerendering * fix: update route * chore(impr): preferences actions and ui tweaks --------- Co-authored-by: Roberto Lucas <andler.dev@gmail.com> * chore: enable twitter pixel track (#479) * chore: enable twitter pixel track * perf(impr): twitter ads availability + dynamic config * feat: impr profile navigation page (#478) * fix(wip): subscriptions page render * feat(impr): profile navigation + page ui tweaks * style: lintin + formatting * style(css): nav links px on mob * fix: goToProfile in mob prof sidebar * fix: build * fix: thread popup opening at nav * chore: enable preferences nav on prod * feat: image generation (#486) * feat: add image generation support - gemini provider * chore: add mineType * chore: add conditional checks * chore: upt model enums & list * chore: hasura, set icl seeds chunks (#484) * chore: hasura, set icl seeds chunks * chore: track backup icl seed loc to lfs * chore(seeds): uncomment phase 3 topics & add new chatbots + icl metadata rel * chore: upt phase 3 init config seeds, adding rel * fix: example seeds integrity * test: incr hasura max req body * revert: cloudbuild og config * chore: restore skipped seed lines * fix: thread rendering (#487) * fix: thread list render states * chore: linting & format * fix: thread pop-up on refresh * fix: user table selection * fix(impr): type safety for image data and refactor model enums in chat (#489) * fix: image generation flow * chore: impr gemini generation logic * fix: build issue * chore: change subscription page * chore: change subscription page + lint * chore: user pref disable options --------- Co-authored-by: bran18 <andreyfdez18@gmail.com> * fix: add hotfix image generation * chore: add more image models * fix: models_enum values + genql upt * feat: improved subscription section (#491) * feat: add improved subscription section * feat: add type * chore: add conditional dislay * feat: add username tags * chore: add new order and benefits * fix: thread empty state on user profile (#490) * update * fix: update * update * update * update * update * feat: added empty state to user profile page * feat: added empty state to user profile page * fix: update * fix: update * fix: account creation slug issue * chore: restore public models table select permissions + clean up --------- Co-authored-by: Roberto Lucas <andler@bitcash.org> Co-authored-by: Roberto Lucas <andler.dev@gmail.com> * feat(wip): web search v2 (#494) * feat(wip): web search * feat(wip): thread config actions * feat(wip): share cta impr * chore: upt domain slugs list * chore: comment legacy getWebSearchTool * fix: preference insert * wip: user preferences set * fix: typo * fix: updateUser data upt * fix: pref table sel (#496) * fix: og render + tweaks (#492) * fix: og render + tweaks * fix: zIndex in og * perf: impr defaultOgImage chk * chore: bun lock upt * chore: next-auth patch upt * fix: app build by mv uuidregexp loc * fix: drizzle service actions loc + msg slug check + msg uniqueness (#499) * [masterbots.ai] chore: standarize pop-up on profile & bot page for thread display (#500) * update * fix: update * update * update * update * update * fix: added popup to thread view page on user profile(both on page reload) * fix: added popup to thread view page on user profile(both on page reload) * fix: added profile link to thread share * fix: update * fix: chatbot page thread pop-up * fix: update * fix: appendMessage concurrency + getBrowseThreads admin mode chk (#505) * feat: attachment thread metadata (#502) * feat(wip): track thread attch data * chore: upt drizzle & genql schemas * feat(wip): save user attachments on load chk * perf: file upload throughout indexed db hook * feat(wip): gcp bucket setup * feat: enlarge thread attachment * fix: attachment upload loop * fix: gcloud storage + thread metadata check & upload * fix: bucket upload + after upload mutations * feat: store remote thread metadata to indexeddb * fix: read file content instead url * fix(wip): get attachments on chat onFinish * fix: attach new stack of files to chat * [masterbots.ai] fix: og card dimensions and spacing + profile props (#506) * fix: og card dimensions and spacing + profile props * fix: og card dimensions + profile props * perf(impr): rm long usernames + autogen num + form input control * perf: dynamic short username number gen * chore(impr): update default thread publicity flag + attachments concurrency & render (#508) * chore(impr): update default thread publicity flag * fix: default thread publicity * fix: ai generated formulas * fix: eslint rule, display name in markdown * fix: eslint rule, display name in markdown * fix: following questions prompt + isNewThread guard * fix: attachments render && concurrency + optimistic activeThread updates * fix: build * perf(impr): earlier downloadedAttachments array upt * chore(impr): clean remote processed ids, indexeddb attachments * fix: user should be able to delete threads (#507) * update * fix: update * update * update * update * update * fix: user can delete thread * fix: delete thread messages * fix: update * fix: obs update * chore: file clean up --------- Co-authored-by: Roberto 'Andler' Lucas <contact@andler.dev> * [masterbots.ai] feat: image generation support (#504) * feat: add support to image generation * feat: add GPT-image-1 support route * feat: fix biome lint * feat: add edit mode * chore: enable img gen feature flag * style: format n lint --------- Co-authored-by: Roberto 'Andler' Lucas <contact@andler.dev> * fix: bun lock * fix: ts build --------- Co-authored-by: Brandon Fernández <31634868+Bran18@users.noreply.github.com> Co-authored-by: Jimoh sherifdeen <63134009+sheriffjimoh@users.noreply.github.com> Co-authored-by: bran18 <andreyfdez18@gmail.com> Co-authored-by: Brandon fernandez <brandonfernandez@Brandons-Mac-mini.local>
1 parent 5e58fb9 commit ee4a6df

File tree

73 files changed

+4153
-1450
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+4153
-1450
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ __dev
1212
.vercel
1313

1414
bun.lockb
15+
16+
gcp-serv-acct-key.json

apps/hasura/metadata/databases/masterbots/tables/public_thread.yaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ select_permissions:
7575
- is_approved
7676
- is_blocked
7777
- is_public
78+
- metadata
7879
- model
7980
- parent_thread_id
8081
- short_link
@@ -93,6 +94,7 @@ select_permissions:
9394
- is_approved
9495
- is_blocked
9596
- is_public
97+
- metadata
9698
- model
9799
- parent_thread_id
98100
- short_link
@@ -111,6 +113,7 @@ select_permissions:
111113
- is_approved
112114
- is_blocked
113115
- is_public
116+
- metadata
114117
- model
115118
- parent_thread_id
116119
- short_link
@@ -166,7 +169,6 @@ delete_permissions:
166169
- role: user
167170
permission:
168171
filter:
169-
thread:
170-
user_id:
171-
_eq: X-Hasura-User-Id
172+
user_id:
173+
_eq: X-Hasura-User-Id
172174
comment: ""
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
alter table "public"."thread" alter column "is_public" set default 'true';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
alter table "public"."thread" alter column "is_public" set default 'false';
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- Could not auto-generate a down migration.
2+
-- Please write an appropriate down migration for the SQL below:
3+
-- alter table "public"."thread" add column "metadata" jsonb
4+
-- null default jsonb_build_object();
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
alter table "public"."thread" add column "metadata" jsonb null default null;

apps/masterbots.ai/.env.example

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,8 @@ NEXT_PUBLIC_PROFILE_N_BOT_PAGE_HAS_POPUP="true"
2424

2525
SENTRY_AUTH_TOKEN="your_sentry_auth_token"
2626

27-
# DATABASE_URL="postgres://user:pass@localhost:5433/masterbots?sslmode=disable"
27+
DATABASE_URL="postgres://user:pass@localhost:5433/masterbots?sslmode=disable"
28+
GCS_BUCKET_NAME="your_bucket"
29+
GCS_PROJECT_ID="your_project_id"
30+
GCS_CLIENT_EMAIL="your_service_account_email@your_project_id.iam.gserviceaccount.com"
31+
GCS_SECRET_ACCESS_KEY="-----BEGIN PRIVATE KEY-----\n0x1...\n-----END PRIVATE KEY-----\n"

apps/masterbots.ai/app/actions/ai-main-call.actions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ export async function createResponseStream(
341341
try {
342342
let response: ReturnType<typeof streamText>
343343

344-
const coreMessages = convertToCoreMessages(
344+
const coreMessages = await convertToCoreMessages(
345345
messages as OpenAI.ChatCompletionMessageParam[],
346346
)
347347

apps/masterbots.ai/app/actions/thread.actions.ts

Lines changed: 179 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
'use server'
22

3-
import { eq } from 'drizzle-orm'
3+
import type { FileAttachment } from '@/lib/hooks/use-chat-attachments'
4+
import type { ThreadMetadata } from '@/lib/hooks/use-indexed-db'
5+
import { Storage } from '@google-cloud/storage'
6+
import { eq, inArray, isNotNull } from 'drizzle-orm'
7+
import { uniqBy } from 'lodash'
48
import { db, message, thread } from 'mb-drizzle'
9+
import { appConfig } from 'mb-env'
510

611
export async function doesMessageSlugExist(slug: string) {
712
const results = await db
@@ -30,3 +35,176 @@ export async function doesThreadSlugExist(slug: string) {
3035
Number.parseFloat(results[0]?.slug.split('-').pop() as string) || 0,
3136
}
3237
}
38+
39+
export async function getUserThreadsMetadata(messageIds: string[]) {
40+
const results = await db
41+
.select({
42+
threadId: thread.threadId,
43+
slug: thread.slug,
44+
metadata: thread.metadata,
45+
})
46+
.from(thread)
47+
.innerJoin(message, eq(thread.threadId, message.threadId))
48+
.where(inArray(message.messageId, messageIds))
49+
50+
if (results.length === 0) return null
51+
52+
return results[0]
53+
}
54+
55+
export async function getAllUserThreadMetadata() {
56+
const results = await db
57+
.select({
58+
metadata: thread.metadata,
59+
})
60+
.from(thread)
61+
.where(isNotNull(thread.metadata))
62+
63+
if (results.length === 0) return null
64+
65+
const metadata = results.flatMap(
66+
(result) => (result.metadata as ThreadMetadata).attachments,
67+
)
68+
69+
return metadata
70+
}
71+
72+
export async function updateThreadMetadata(
73+
messagesIds: string[],
74+
metadata: ThreadMetadata,
75+
) {
76+
// First, select the threadIds that need to be updated
77+
const threadsToUpdate = await db
78+
.selectDistinct({
79+
threadId: message.threadId,
80+
messageId: message.messageId,
81+
})
82+
.from(message)
83+
.where(inArray(message.messageId, messagesIds))
84+
85+
if (threadsToUpdate.length === 0) {
86+
console.error(
87+
'No threads found for the provided message IDs. Cannot update metadata.',
88+
)
89+
return {
90+
threads: [],
91+
attachments: {},
92+
}
93+
}
94+
95+
const threadsDataIds = threadsToUpdate.map(
96+
(t) => [t.threadId as string, t.messageId] as const,
97+
)
98+
99+
const attachments: ThreadMetadata = {}
100+
101+
let result: (typeof thread.$inferSelect)[] = []
102+
103+
let previousThreadId: string | null = null
104+
105+
for (const [threadId, messageId] of threadsDataIds) {
106+
let relatedThreadAttachments = metadata.attachments.filter((att) =>
107+
att.messageIds.includes(messageId),
108+
)
109+
110+
if (previousThreadId === threadId) {
111+
relatedThreadAttachments.push(...(attachments[threadId] || []))
112+
}
113+
114+
previousThreadId = threadId
115+
relatedThreadAttachments = uniqBy(relatedThreadAttachments, 'id')
116+
117+
// Then, update the threads using the selected threadIds
118+
result = [
119+
...result,
120+
...(await db
121+
.update(thread)
122+
.set({
123+
metadata: {
124+
attachments: relatedThreadAttachments,
125+
},
126+
})
127+
.where(eq(thread.threadId, threadId))
128+
.returning()),
129+
]
130+
131+
attachments[threadId] = relatedThreadAttachments
132+
}
133+
134+
result = uniqBy(result, 'threadId')
135+
136+
return {
137+
threads: result,
138+
attachments,
139+
}
140+
}
141+
142+
export async function uploadAttachmentToBucket({
143+
attachment,
144+
threadSlug,
145+
}: {
146+
attachment: FileAttachment
147+
threadSlug: string
148+
}) {
149+
const { id, name, contentType, content, size } = attachment
150+
151+
if (!content) {
152+
throw new Error('Attachment content is required for upload')
153+
}
154+
155+
const buffer: Buffer =
156+
typeof content === 'string'
157+
? Buffer.from(content.split(',')[1], 'base64')
158+
: Buffer.from(content)
159+
const byteSize = buffer.byteLength
160+
const fileExtension = name.split('.').pop() || 'txt'
161+
const bucketKey = `attachments/${threadSlug}/${name}`
162+
163+
console.log(
164+
`Uploading attachment: ${name}, ID: ${id}, Size: ${size} bytes, Content-Type: ${contentType}`,
165+
)
166+
167+
if (byteSize !== size) {
168+
throw new Error(
169+
`Attachment size mismatch: expected ${size} bytes, got ${byteSize} bytes`,
170+
)
171+
}
172+
173+
const storage = new Storage({
174+
projectId: appConfig.features.storageProjectId,
175+
credentials: {
176+
client_email: appConfig.features.storageClientEmail,
177+
private_key: appConfig.features.storageSecretAccessKey,
178+
},
179+
})
180+
const bucket = storage.bucket(appConfig.features.storageBucketName)
181+
const fileUpload = bucket.file(bucketKey)
182+
183+
await fileUpload.save(buffer, {
184+
metadata: {
185+
id,
186+
fileExtension,
187+
contentType,
188+
threadSlug,
189+
},
190+
resumable: false,
191+
// public: true,
192+
})
193+
194+
const expires = Date.now() + 1000 * 60 * 60 * 24 * 7 // 7 days
195+
const [signedUrl] = await fileUpload.getSignedUrl({
196+
version: 'v4',
197+
action: 'read',
198+
expires,
199+
})
200+
201+
return {
202+
id,
203+
name,
204+
contentType,
205+
url: signedUrl,
206+
size: byteSize,
207+
content: bucketKey, // Store the bucket key instead of the content
208+
expires: new Date(expires).toISOString(),
209+
}
210+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { uploadAttachmentToBucket } from '@/app/actions'
2+
import { logErrorToSentry } from '@/lib/sentry'
3+
import { appConfig } from 'mb-env'
4+
5+
export async function POST(request: Request) {
6+
const { attachment, thread } = await request.json()
7+
8+
if (!attachment || !thread) {
9+
return new Response(
10+
JSON.stringify({
11+
error: 'Attachment and thread data are required.',
12+
}),
13+
{
14+
status: 400,
15+
headers: {
16+
'Content-Type': 'application/json',
17+
},
18+
},
19+
)
20+
}
21+
22+
try {
23+
const uploadResults = await uploadAttachmentToBucket({
24+
attachment,
25+
threadSlug: thread.slug,
26+
})
27+
28+
if (appConfig.features.devMode) {
29+
console.info(
30+
'Attachment uploaded successfully to gCloud Bucket:',
31+
uploadResults,
32+
)
33+
}
34+
35+
return new Response(
36+
JSON.stringify({
37+
data: uploadResults,
38+
error: null,
39+
}),
40+
)
41+
} catch (error) {
42+
logErrorToSentry(
43+
(error as Error)?.message || 'Failed to upload file to Bucket',
44+
{
45+
error,
46+
message: 'Failed to complete chat.',
47+
level: 'error',
48+
extra: {
49+
attachmentName: attachment.name,
50+
attachmentContentType: attachment.contentType,
51+
attachmentMessageIds: attachment.messageIds,
52+
threadSlug: thread.slug,
53+
},
54+
},
55+
)
56+
57+
return new Response(
58+
JSON.stringify({
59+
data: null,
60+
error: 'Failed to upload attachment to Bucket.',
61+
}),
62+
{
63+
status: 500,
64+
headers: {
65+
'Content-Type': 'application/json',
66+
},
67+
},
68+
)
69+
}
70+
}

0 commit comments

Comments
 (0)