mirror of
https://github.com/browseros-ai/BrowserOS.git
synced 2026-05-21 04:45:12 +00:00
* feat: created auth client * feat: created login page for testing auth * feat: setup logout page * feat: setup graphql codegen * feat: setup graphql + react query utils * feat: setup queryprovider with localforage * feat: created auth provider * feat: update claude.md * feat: documents for bulk conversation upload * chore: install missing package * fix: setup codegen to scan for .ts files * chore: setup check conversation query * feat: upload conversation by profileId * chore: upload messages in batches * feat: account for edge cases in conversation upload * feat: delete uploaded conversations from localstorage * feat: load conversation history from api * feat: implement delete conversation using graphql * feat: delete confirmation for conversation history * fix: issue with clearing conversations after upload * feat: implement pagination for graphql chat history * chore: update CLAUDE.md * chore: update claude.md * feat: save conversations to server * fix: handle streaming check on remote conversation save * feat: restore conversation from graphql * fix: timestamp issue on the chat history page * feat: sync llm providers from background script * feat: update llm providers on change via background script * chore: added a try catch block * feat: display incomplete providers in separate UI * feat: delete provider on server when initiated by user * feat: setup scheduled tasks storage to sync to graphql * feat: auto run sync in background script * fix: sync all keys of scheduled tasks based on updatedAt timestamp * feat: added login dropdown on the sidebar * feat: simplify sidenav header * feat: update header design after login * feat: setup profile page * feat: added back button to profile page * fix: scrollbar flash in profile page * feat: finish login handshake * feat: clear storage on logout * fix: logout page style * feat: added tooltip to encourage user to sign in * feat: added back button to login page * fix: upload logic for profile picture * feat: account for profile name in sidebar branding * chore: set file upload url from backend request * chore: remove default placeholder from profile component * chore: sync with main * Revert "chore: sync with main" This reverts commit 77e06b894ce30235d1bfa31c8e2699b34df423a5. * Reapply "chore: sync with main" This reverts commit dd921d97cc9794d1872e13689c881f68e4dfee47. * chore: updated lock file * fix: run codegen before build:ext * fix: run codegen before build:gent * fix: remove hardcoded localhost header in magic link --------- Co-authored-by: Nikhil Sonti <nikhilsv92@gmail.com>
95 lines
2.9 KiB
TypeScript
95 lines
2.9 KiB
TypeScript
import { execute } from '@/lib/graphql/execute'
|
|
import { sessionStorage } from '../auth/sessionStorage'
|
|
import { sentry } from '../sentry/sentry'
|
|
import { type Conversation, conversationStorage } from './conversationStorage'
|
|
import {
|
|
BulkCreateConversationMessagesDocument,
|
|
ConversationExistsDocument,
|
|
CreateConversationForUploadDocument,
|
|
GetProfileIdByUserIdDocument,
|
|
GetUploadedMessageCountDocument,
|
|
} from './graphql/uploadConversationDocument'
|
|
|
|
export async function uploadConversationsToGraphql(
|
|
conversations: Conversation[],
|
|
) {
|
|
if (conversations.length === 0) return
|
|
|
|
const sessionInfo = await sessionStorage.getValue()
|
|
const userId = sessionInfo?.user?.id
|
|
if (!userId) return
|
|
|
|
const profileResult = await execute(GetProfileIdByUserIdDocument, { userId })
|
|
const profileId = profileResult.profileByUserId?.rowId
|
|
if (!profileId) return
|
|
|
|
const uploadedIds: string[] = []
|
|
|
|
for (const conversation of conversations) {
|
|
try {
|
|
const existsResult = await execute(ConversationExistsDocument, {
|
|
pConversationId: conversation.id,
|
|
})
|
|
|
|
let uploadedCount = 0
|
|
|
|
if (existsResult.conversationExists) {
|
|
const countResult = await execute(GetUploadedMessageCountDocument, {
|
|
conversationId: conversation.id,
|
|
})
|
|
uploadedCount = countResult.conversationMessages?.totalCount ?? 0
|
|
|
|
if (uploadedCount >= conversation.messages.length) {
|
|
uploadedIds.push(conversation.id)
|
|
continue
|
|
}
|
|
} else {
|
|
await execute(CreateConversationForUploadDocument, {
|
|
input: {
|
|
conversation: {
|
|
rowId: conversation.id,
|
|
profileId,
|
|
lastMessagedAt: new Date(
|
|
conversation.lastMessagedAt,
|
|
).toISOString(),
|
|
createdAt: new Date(conversation.lastMessagedAt).toISOString(),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
const remainingMessages = conversation.messages.slice(uploadedCount)
|
|
|
|
if (remainingMessages.length > 0) {
|
|
const BATCH_SIZE = 50
|
|
for (let i = 0; i < remainingMessages.length; i += BATCH_SIZE) {
|
|
const batch = remainingMessages.slice(i, i + BATCH_SIZE)
|
|
await execute(BulkCreateConversationMessagesDocument, {
|
|
input: {
|
|
pConversationId: conversation.id,
|
|
pMessages: batch.map((msg, batchIndex) => ({
|
|
orderIndex: uploadedCount + i + batchIndex,
|
|
message: msg,
|
|
})),
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
uploadedIds.push(conversation.id)
|
|
} catch (error) {
|
|
sentry.captureException(error, {
|
|
extra: {
|
|
conversationId: conversation.id,
|
|
messageCount: conversation.messages.length,
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
if (uploadedIds.length > 0) {
|
|
const remaining = conversations.filter((c) => !uploadedIds.includes(c.id))
|
|
conversationStorage.setValue(remaining)
|
|
}
|
|
}
|