Skip to content

Commit

Permalink
feat: delete the concept of product
Browse files Browse the repository at this point in the history
  • Loading branch information
YanceyOfficial committed Dec 18, 2024
1 parent 3461e32 commit f87d8b9
Show file tree
Hide file tree
Showing 62 changed files with 1,081 additions and 3,272 deletions.
297 changes: 34 additions & 263 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s"
},
"dependencies": {
"@azure/openai": "1.0.0-beta.12",
"@anthropic-ai/sdk": "^0.32.1",
"@emoji-mart/data": "^1.2.1",
"@emoji-mart/react": "^1.1.1",
"@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0",
"@google/generative-ai": "^0.21.0",
"@heroicons/react": "^2.1.5",
"@lottiefiles/react-lottie-player": "^3.5.4",
"@mui/material": "^6.1.2",
Expand All @@ -38,7 +39,6 @@
"js-tiktoken": "^1.0.15",
"luxon": "^3.5.0",
"marked": "^15.0.3",
"microsoft-cognitiveservices-speech-sdk": "^1.40.0",
"notistack": "^3.0.1",
"openai": "^4.76.0",
"react": "^18.3.1",
Expand Down
79 changes: 79 additions & 0 deletions src/components/ChatBox/AttachmentPreview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { FC } from 'react'
import { useRecoilState } from 'recoil'
import { base64FilePromptState } from 'src/stores/conversation'
import { SolidCloseIcon } from '../Icons'

interface Props {
className?: string
}

const AttachmentPreview: FC<Props> = ({ className }) => {
const [base64FilePrompt, setBase64FilePrompt] = useRecoilState(
base64FilePromptState
)

const deleteBase64FilePrompt = (id: string) => {
setBase64FilePrompt(base64FilePrompt.filter((prompt) => prompt.id !== id))
}

return (
<section className={className}>
{base64FilePrompt.map((prompt) => {
if (prompt.mimeType.includes('image')) {
return (
<section
className="mb-2 ml-4 mt-4 flex w-full flex-row gap-2"
key={prompt.id}
>
<section className="group relative">
<span className="absolute -right-2 -top-2 hidden rounded-full bg-white group-hover:block">
<SolidCloseIcon
className="h-6 w-6 text-black"
onClick={() => deleteBase64FilePrompt(prompt.id)}
/>
</span>
<img
src={prompt.data}
className="h-16 w-16 rounded-xl object-cover"
/>
</section>
</section>
)
}

if (prompt.mimeType.includes('audio')) {
return (
<section
className="ml-4 mt-4 flex w-1/2 rounded-3xl bg-main-purple"
key={prompt.id}
>
<audio src={prompt.data} controls />
</section>
)
}

if (prompt.mimeType.includes('video')) {
return (
<section
className="ml-4 mt-4 flex w-1/2 rounded-3xl bg-main-purple"
key={prompt.id}
>
<video src={prompt.data} controls />
</section>
)
}

return (
<section
className="ml-4 mt-4 flex w-1/2 rounded-3xl bg-main-purple"
key={prompt.id}
>
{prompt.name}
</section>
)
})}
</section>
)
}

export default AttachmentPreview
63 changes: 15 additions & 48 deletions src/components/ChatBox/AttachmentUploader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,70 +2,38 @@ import { PaperClipIcon } from '@heroicons/react/24/outline'
import classNames from 'classnames'
import { enqueueSnackbar } from 'notistack'
import { ChangeEvent, FC, useRef } from 'react'
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import { multiMedialConfig } from 'src/shared/constants'
import { convertBase64 } from 'src/shared/utils'
import { audioFileState, base64ImagesState } from 'src/stores/conversation'
import { metaOfCurrProductSelector } from 'src/stores/global'
import { Functions } from 'src/types/global'
import { useRecoilState } from 'recoil'
import { convertToBase64 } from 'src/shared/utils'
import { base64FilePromptState } from 'src/stores/conversation'

interface Props {
className?: string
}

const AttachmentUploader: FC<Props> = ({ className }) => {
const metaOfCurrProduct = useRecoilValue(metaOfCurrProductSelector)
const fileInputRef = useRef<HTMLInputElement>(null)
const [audioFile, setAudioFile] = useRecoilState(audioFileState)
const setBase64Images = useSetRecoilState(base64ImagesState)

const validate = () => true

const canAddAudioAttachment = metaOfCurrProduct.functions.includes(
Functions.AudioAttachment
)
const canAddImageAttachment = metaOfCurrProduct.functions.includes(
Functions.ImageAttachment
const [base64FilePrompt, setBase64FilePrompt] = useRecoilState(
base64FilePromptState
)

const mediaType = canAddAudioAttachment
? Functions.AudioAttachment
: Functions.ImageAttachment
const validate = () => true

const onFileChange = async (e: ChangeEvent<HTMLInputElement>) => {
const files = e.target.files
if (!files) return

if (canAddAudioAttachment) {
const file = files[0]
setAudioFile({
...audioFile,
binary: file
})

const arrayBuffer = await file.arrayBuffer()
const response = await window.electronAPI.saveFileToAppDataDir({
arrayBuffer,
filename: file.name
})
setAudioFile({
...audioFile,
filename: response.filename
})
}

if (canAddImageAttachment) {
try {
const promises = []
for (const file of files) {
promises.push(convertBase64(file))
promises.push(convertToBase64(file))
}

try {
const base64Files = await Promise.all(promises)
setBase64Images(base64Files)
} catch {
enqueueSnackbar('Can not upload images.', { variant: 'error' })
}
const base64Files = await Promise.all(promises)
setBase64FilePrompt([...base64FilePrompt, ...base64Files])
} catch {
enqueueSnackbar('Can not upload images.', { variant: 'error' })
} finally {
fileInputRef.current.files = null
}
}

Expand All @@ -78,9 +46,8 @@ const AttachmentUploader: FC<Props> = ({ className }) => {
<input
type="file"
id="$$file-input"
accept={multiMedialConfig[mediaType].accept}
className="absolute h-6 w-6 opacity-0 file:h-6 file:w-6"
multiple={multiMedialConfig[mediaType].multiple}
multiple
ref={fileInputRef}
onChange={onFileChange}
/>
Expand Down
66 changes: 53 additions & 13 deletions src/components/ChatBox/ChatBubble.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import classNames from 'classnames'
import { ChatCompletionContentPartText } from 'openai/resources'
import { FC, memo } from 'react'
import ChatGPTLogoImg from 'src/assets/chatbot.png'
import { useSettings } from 'src/hooks'
import { Message, Roles } from 'src/types/conversation'
import {
ContentPartType,
Message,
Roles,
TextPrompt
} from 'src/types/conversation'
import Avatar from '../Avatar'
import Markdown from './Markdown'
import ToolsBox from './ToolsBox'
Expand Down Expand Up @@ -52,27 +56,63 @@ const ChatBubble: FC<Props> = ({ message }) => {
})}
>
{message.role === Roles.Assistant && (
<Markdown
src={(message.content as ChatCompletionContentPartText[])[0].text}
/>
<Markdown src={(message.content as TextPrompt[])[0].text} />
)}

{message.role === Roles.User && (
<div>
{message.content.map((item, key) => {
if (item.type === 'image_url') {
if (item.type === ContentPartType.TextPrompt) {
return <p key={key}>{item.text}</p>
}

if (
item.type === ContentPartType.Base64FilePromptType &&
item.mimeType.includes('image')
) {
return (
<img
src={item.image_url.url}
key={key}
className="mb-2 max-w-80"
/>
<img src={item.data} key={key} className="mb-2 max-w-80" />
)
}

if (item.type === 'text') {
return <p key={key}>{item.text}</p>
if (
item.type === ContentPartType.UrlFileUrlPromptType &&
item.mimeType.includes('image')
) {
return (
<img src={item.url} key={key} className="mb-2 max-w-80" />
)
}

if (
item.type === ContentPartType.Base64FilePromptType &&
item.mimeType.includes('audio')
) {
return <audio src={item.data} key={key} controls />
}

if (
item.type === ContentPartType.UrlFileUrlPromptType &&
item.mimeType.includes('audio')
) {
return <audio src={item.url} key={key} controls />
}

if (
item.type === ContentPartType.Base64FilePromptType &&
item.mimeType.includes('video')
) {
return <video src={item.data} key={key} controls />
}

if (
item.type === ContentPartType.UrlFileUrlPromptType &&
item.mimeType.includes('video')
) {
return <video src={item.url} key={key} controls />
}

return <div>File: {item.name}</div>
})}
</div>
)}
Expand Down
14 changes: 1 addition & 13 deletions src/components/ChatBox/ChatMessages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,11 @@ import classNames from 'classnames'
import { FC, memo, useEffect, useMemo, useRef } from 'react'
import { useRecoilValue } from 'recoil'
import NoDataIllustration from 'src/assets/illustrations/no-data.svg'
import { isSupportAudio } from 'src/shared/utils'
import { currConversationState } from 'src/stores/conversation'
import { currProductState } from 'src/stores/global'
import { Message } from 'src/types/conversation'
import ChatBubble from './ChatBubble'

const ChatMessages: FC = () => {
const chatBoxRef = useRef<HTMLDivElement>(null)
const currProduct = useRecoilValue(currProductState)
const currConversation = useRecoilValue(currConversationState)
const hasMessages = useMemo(
() => currConversation && currConversation.messages.length > 0,
Expand All @@ -29,14 +25,6 @@ const ChatMessages: FC = () => {
}
}

const getAudioFilename = (message: Message) => {
if (isSupportAudio(currProduct) && message.content[0].type === 'audio') {
return message.content[0].audioUrl.url
}

return ''
}

useEffect(() => {
scrollToBottom()
}, [currConversation])
Expand All @@ -52,7 +40,7 @@ const ChatMessages: FC = () => {
{hasMessages ? (
<>
{currConversation?.messages.map((message) => (
<ChatBubble key={message.messageId} message={message}></ChatBubble>
<ChatBubble key={message.id} message={message} />
))}
</>
) : (
Expand Down
8 changes: 4 additions & 4 deletions src/components/ChatBox/ContactHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const ContactHeader: FC = () => {

const summary =
currConversation?.summary ||
currConversation?.conversationId ||
currConversation?.id ||
EMPTY_CHAT_HINT

const openAvatarPicker = () => {
Expand Down Expand Up @@ -83,7 +83,7 @@ const ContactHeader: FC = () => {
summary: summaryValue,
updatedAt: +new Date()
}
await updateOneById(currConversation.conversationId, changes)
await updateOneById(currConversation.id, changes)
setCurrConversation({ ...currConversation, ...changes })
setSummaryInputVisible(false)
}
Expand All @@ -102,7 +102,7 @@ const ContactHeader: FC = () => {
avatar: data.native,
updatedAt: +new Date()
}
await updateOneById(currConversation.conversationId, changes)
await updateOneById(currConversation.id, changes)
setCurrConversation({ ...currConversation, ...changes })
setAvatarPickerVisible(false)
}
Expand All @@ -114,7 +114,7 @@ const ContactHeader: FC = () => {
return
}
if (currConversation) {
await deleteOneById(currConversation.conversationId)
await deleteOneById(currConversation.id)
}
}

Expand Down
Loading

0 comments on commit f87d8b9

Please sign in to comment.