From a93ed9850b7d95bb3bae5ec4fd7d1a7cae20ca0a Mon Sep 17 00:00:00 2001 From: ericcccliu Date: Fri, 29 Mar 2024 04:47:58 -0500 Subject: [PATCH] add feature to hide messages --- api/__pycache__/index.cpython-311.pyc | Bin 1948 -> 1948 bytes .../__pycache__/auth_routes.cpython-311.pyc | Bin 6485 -> 6485 bytes .../conversation_routes.cpython-311.pyc | Bin 6106 -> 6701 bytes api/routes/conversation_routes.py | 16 ++- .../__pycache__/auth_utils.cpython-311.pyc | Bin 1862 -> 1862 bytes .../conversation_utils.cpython-311.pyc | Bin 4960 -> 5928 bytes .../__pycache__/db_utils.cpython-311.pyc | Bin 1092 -> 1092 bytes .../__pycache__/llm_utils.cpython-311.pyc | Bin 3128 -> 3425 bytes api/utils/conversation_utils.py | 17 ++- api/utils/llm_utils.py | 2 + app/components/ConversationMessages.tsx | 22 +++- app/components/Sidebar.tsx | 105 +++++++++++++----- app/page.tsx | 29 ++++- 13 files changed, 155 insertions(+), 36 deletions(-) diff --git a/api/__pycache__/index.cpython-311.pyc b/api/__pycache__/index.cpython-311.pyc index 6319d2b93d5a6968230d1710e11354b4f3f4b48a..3f0a288a189baccf1387d845f997127481d205eb 100644 GIT binary patch delta 21 bcmbQkKZl=ZIWI340}xDzVM*J_Gl3ldH4g;X delta 21 bcmbQkKZl=ZIWI340}!Z9`H{MjX97C_IQj*d diff --git a/api/routes/__pycache__/auth_routes.cpython-311.pyc b/api/routes/__pycache__/auth_routes.cpython-311.pyc index a725a0904ab8c19a53408bf5861250b2106e6989..d92823a6bc2fdfd9c6ed804743848abb037abedb 100644 GIT binary patch delta 21 bcmca=bk&GwIWI340}w2&V@un}<0%OML{9~j delta 21 bcmca=bk&GwIWI340}ymg{gJwn$5RpjNxuex diff --git a/api/routes/__pycache__/conversation_routes.cpython-311.pyc b/api/routes/__pycache__/conversation_routes.cpython-311.pyc index 1819319f728f8eaa766508b1e6ef7ca877591ae5..94c29058a8933539603648c462ddc39d33b53286 100644 GIT binary patch delta 1539 zcmcIj-D@0G6u);qc6YKnGn@U$er3Daex#WsMjMqhU9lygfnZuNvFNn2U3O+abSGKw zOp294f~`nF#N`SW`cnE33qer!MG&EX!Yr=1Ok3JV`yi}{KKbCiGu@aP3%+=E?(d#^ z?>Xn5-??X6B_(sWSOC5N8qi<^7*K_f>P&+%Sd}$6we^aU zakqSpkRhs~A*qrftFjSR!^W`Mx^^PVZj*pJG^#6Vh5?H}3tk0UNEccUGf-&#NdPBd zA`FWa-87`r1VunI)^fzE(7J(=1hW6Mx4RaFCmC zU*MKF7;NtZa&U+zA+C_|+aI_SisMJZNAdwHNCSIfiTJ&tG`=x(TM@_(8mADVAX1p3 z;HMC#;3J^;a3lEKj7jw|S5Tg)&TvW72Duc``i7;W0yQDSyn*ip>v@(x4e!fiKj!DZ zo$llpyZJ?XwQ9??j$G@?H9JtlZ%0zh2MXR2CMHcM?2+9KYL-b0@5(N*1|gP;TxQ;EAH^f;(&Nx1-FS(@1Odly zZj{T!#pK9}688AUAHT(*{Es=GBu2Dq=34}QCciE4dkDmjeVwxxUbj~-bXO~#ShX9g z+7kT^d6S1*i#@;82eeMTaLUe{u;qdsDA2OBuY^V+l<`e5nRCCHx@#OYrYU_Tis~Pw{8S$yq!a zIe%!<@mZIe^|dOZRd@WAl4+HibwrDRXz`H`e;P^5(B^Og%}ZKo&8nACfG!inaK>2I z^oBXJw^fmVe~27Rx&@~_xTn!1vc$8|);R4Mhiz_Hh*r|!n;sCoSG@VoGu~_$ z%bv0qe`NtP--XBfjO!Q!OyJ}6hiN-B*MZ0BegLHN*AsUBSSK~xP0jZGf_nkQUOd@n dsq%0neSPk8qt6RaAh-KKG|~6BH%HFFzW|@wVQK&X delta 1084 zcmcJNO=uHA6vuaVv-wUoUrl4uG}Y3N*qVx8NNh0pfnaGc6ffIi2-#^H%qC%WTM!jJ z6s*Va4vGl&R0|?lf)_#XS`eCQ!4Ro<^&sR}M8uh-rBvX z+~KftwAEl6k2@;PK;(?TagR8KQ&53Zk&IMc=2bx!5S!x*mCMnPYM1S*Lw2Z6*{Mph zq`G8R%WW)F9>&9HnF_vOs;wr6c#$f9^D3CtU=dZqwd%#7#;2yVcWVA zHB*!HGq5WqHijVv7lV;Oq==ee&33%AA?@y!(R6~ds%E0j9{6R8SVx&fKkXR|*z++8)-?Di4T(uQGh7v1s|a0!*Y0U_0lGXlkpmVzSH&^vJP)5d-)(!@ zh_LQWisRHX20q_ZVz6PF&T4wLoG0|@a>T&Ec5k?M=3~2=YON|X%;j53wy5WG!~}1A zVPuB7??}SJ;`S2lTbRK*VL6a-SnCLTr>MzZy7r!)v?(Bj>frWwLd0)`L4W+7$~WnP|HC?Wv9`b0 kxwEx>y}ItdjUpD5LQRfwWuiU4JJud+nOu{reh5sW-&th;1^@s6 diff --git a/api/routes/conversation_routes.py b/api/routes/conversation_routes.py index 1486be2..95783c0 100644 --- a/api/routes/conversation_routes.py +++ b/api/routes/conversation_routes.py @@ -1,9 +1,9 @@ +from typing import List from fastapi import APIRouter, Depends, HTTPException from fastapi.responses import StreamingResponse from pydantic import BaseModel from api.models.conversation import Message -from api.utils.conversation_utils import create_conversation, add_message, get_conversation_by_id, rename_conversation, get_conversations_by_user, update_conversation_model -from api.utils.llm_providers.openai import openai_generate_response +from api.utils.conversation_utils import update_conversation_messages, create_conversation, add_message, get_conversation_by_id, get_conversations_by_user, update_conversation_model from api.utils.llm_utils import generate_response_stream from api.utils.auth_utils import get_current_user from api.models.user import User @@ -40,6 +40,18 @@ async def add_message_route(conversation_id: str, message_create: MessageCreate, else: raise HTTPException(status_code=404, detail="Conversation not found") +@router.put("/conversations/{conversation_id}/messages") +async def update_messages_route( + conversation_id: str, + updated_messages: List[Message], + current_user: User = Depends(get_current_user), +): + success = await update_conversation_messages(conversation_id, updated_messages, current_user.email) + if success: + return {"message": "Messages updated successfully"} + else: + raise HTTPException(status_code=404, detail="Conversation not found") + @router.patch("/conversations/{conversation_id}") async def update_conversation_route( conversation_id: str, diff --git a/api/utils/__pycache__/auth_utils.cpython-311.pyc b/api/utils/__pycache__/auth_utils.cpython-311.pyc index 7a851550e5f658c081c5f76973d9d1d327498e81..18962857991145a5090f02c2d8f69186fe8165e3 100644 GIT binary patch delta 21 bcmX@ccZ`o`IWI340}xDzVM*J_W5o^tI?V*s delta 21 bcmX@ccZ`o`IWI340}$j){*k(o$BG>QK;Z@2 diff --git a/api/utils/__pycache__/conversation_utils.cpython-311.pyc b/api/utils/__pycache__/conversation_utils.cpython-311.pyc index ac87f03c3b4e7031725b15b0d8bb291ebb25d68a..8b4eaa8d9e2805a0566c6f80db7883258b339e5f 100644 GIT binary patch delta 1837 zcmah}UuauZ7{537ZNz(` zXGRA0VS=dPDDE+HLY=+{eG!Dc3Br6xWnj4v(ig$U%EX6)==YtQ^bew5?)}~GeBU|W z|L<&1evvlU4I?PPGxnZZ?3iuyh`7_9dLkkUwqVN@wW=*?RehM{b0r-NBS=8;&n!FUT!>~3Stti_jtfPD#0Uqoxs&*83G0wxaY{y_d$YlY05a_r) z%%wf8+zOm72JOU}GQE`G!lWZP+EH|wKRwk$a6DDAn5FADI4`gxHb_Y?530w6YQ?k4vqr@chU~)8rDWhen+guVC_k{ zvVC2dSZUC!o?dk*&6gYsW>B{mY^>OM*U8mu4#DISbQgq=BRzpIf^Zyw$^c{VkTD>< zP~Nt4J$1waPK>>(ek`Uoeo@~RkE7*#0Wt|cKOUrZ4-tt4^*^uf63Ens>|f8aWM{Fd!Ni*`_gl zw=fXMqG#ku1a#@1U@1HkWENRG1;>!m0YJp_z_ae#XLmy5Q)3|WhDwfm$XafB6*5iE zfDqNwFQE=6Sv3oR?E{C|PDDlFybIr>Uj^0?pJFd)v8a1sLsMu5*nQ;~>u8E}wkfkwV^|EZNMwY4 zps1RytO-r=MfR04`;xi$ANq9qi5i z=+JbgQZM8yGz&!k#Ot7ljse^hx~a?l`*o>vrnR2=EORIOd3KLWFq@0>y>aHvw_n)) z5S@oTehm+o?;k@n@?VaUc>#vv66m7$@rq$rqLVF6Np6{wKbfa~G*4|AgP**7JGYsb zd6<~#hSOU{{G)3Q|ryFj$LeutgjuZZz4Wj^>-2utLVi0UNKJxss z_2gv=w+EjMt(d1S93yxu5q>q`P0MdQa{4Tie420^$vK311ndy*DZeat^$b{TRGcii z00L|}`Yro8mWmB`g+uT5#$T}oac(jsCclw(1o(aLb{DVwaD&s`YgPXLSKuc92JIiA Ai~s-t delta 1130 zcmYjPy>HV%6!#@|?0h&MP0}`$(xenpQxsHGb)hX1LLES2>6RsOdv7Wn z|2jO=&yJE0{rXIxCTw_s!fxoVV`j{SEVNG zvvQvW4$iv?ngcE;Iozu>5Bt3I#b^QS0xe1J@vG>eaNAAM;;z;lqC+c+RsIbEMU`9_ z+#!F+YzB6g%F^&*Xop(Ir%pRetuea0A1RDha=Oo&f z5ylWM0&o?e3O_ahMwqrKZ5=f*>4o5i+TiAa}q`oO6;HVzz50H8wDDDEdK z+D#xv241oeTf*RM1_7h)DV7!$^#)Qh^$J=#0JvoSvdB>g@g-fGmU$1aJ3(vB?>=-G zw*$}bwpJfQh1on@yatQER)n9N7R#BZq$WOPKHig&@hyvliMG>S4>qiLRDKmx4fVip zwLKo3jKNt}c=cS}#W!<8y9M05I5M}OtXtW+sLQMXEGr`55JibzM=J)fe3C4RWOW40 zILyMRd9DXTw&wS`ft8B#jz$Vk$qLAFpJ~EMhvxCzz~xGta&`$wjy;mqmjEqT%ui^y zfm{%F{$IWZmPH;|MHUB(sp5TUbVqi4#NPB8a_o8Id}$drRJKIUeyFZ;zZ*%{U7H7R zjbTtGTUSL3Cy`;>WkVPii=hNIhkz2~_#PSy5U+7#V7q!x_RDrZX}!^r)CI%$%4{)6VQFEgWnp5dVS)I2 zavh_%Ei+lJRx)EqVO_vBc^;$6WDaINixjpR)-~+QfPu0a9!RxpC4z`x0D6%V#;ajl z!vRq{nU6)xp+poW!GID!sG*j^nGFuXqUaKF6!n~wo0ua7*-K>6MBgw=GPAGYn#{qX z8prLI3=e*wGGLNm5C-DU3P55yLpspfSZ+}CBNE33&KkyvOg%io3@aHl8E>&=WTvE~ z=4mqBV$w6X#h#m5T%4GmS`6~6g2LprtloUTxNLGVi%XL8a|`UMbS4Y4DVZY#IDqPk z<$**4!v*nZ2wLEN!u^aNkUfJPF7_FygkiHjOF1Kd5f6}ABm^P^fW+h{1_o~iMuzDO=?t}uH4IrGc`(Rggt1Z> zvw^A@7>Z0wSSQb6)Z}EUVJecUVO+pG`4f|h2_r)dQ#eBy!*oVQh8`6&hP+Z7#xTK+ z;lwmX3BwqJ6y_F&T4pAO8s=p{+gCG8UdJfT$^^4F2t|XE8AA%o0#=xlk?9)7Wk9d2 zhI^-$rGytDpTb(hvW9IL(1WX)Ci5|ii2)tY0h6v_UBeEQvSSf*C=rH9Ffag>fx{9c zf@*#WM>g25qUaKF6!jdFH!(*FvX#i9iOR4@GPAAWoNU3O%EaZjIhVDZk$ok@XOODN zyIH)MZi!DeU>Bdv!*0zeI@yDLx6m#2+|=UY#Prmcpm@<_Es~rp$YC)#n8Vuh76(+S zxQGQPS0o1_I6(v`Y&6+#@g(Qxm8BLHCzfR9=iL%W&dQR7zBH_u}oN~gtKoO8=aW&BD7eLs+u(_JEib-?{n 0 - return False \ No newline at end of file + return False + +async def update_conversation_messages(conversation_id: str, updated_messages: List[Message], user_email: str): + db = await get_db() + conversations_collection = db["conversations"] + conversation = await get_conversation_by_id(conversation_id, user_email) + if conversation: + await conversations_collection.update_one( + {"_id": ObjectId(conversation_id)}, + {"$set": {"messages": [message.dict() for message in updated_messages]}}, + ) + return True + else: + return False \ No newline at end of file diff --git a/api/utils/llm_utils.py b/api/utils/llm_utils.py index 4cf9a05..4c7bc2a 100644 --- a/api/utils/llm_utils.py +++ b/api/utils/llm_utils.py @@ -5,6 +5,8 @@ from api.utils.llm_providers.anthropic import anthropic_generate_response, generate_conversation_name async def generate_response_stream(conversation): + visible_messages = [message for message in conversation.messages if not message.hidden] + conversation.messages = visible_messages collected_chunks = [] if conversation.model.provider == "openai": async for chunk in openai_generate_response(conversation): diff --git a/app/components/ConversationMessages.tsx b/app/components/ConversationMessages.tsx index c1d82ae..7b2d4c5 100644 --- a/app/components/ConversationMessages.tsx +++ b/app/components/ConversationMessages.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useRef } from "react"; -import { Box, Text, VStack } from "@chakra-ui/react"; +import { Box, Text, VStack, Button } from "@chakra-ui/react"; import ReactMarkdown from "react-markdown"; import remarkGfm from "remark-gfm"; import remarkMath from "remark-math"; @@ -12,10 +12,12 @@ import { Components } from "react-markdown"; export interface Message { role: "user" | "assistant"; content: string; + hidden?: boolean; } interface ConversationMessagesProps { messages: Message[]; + handleHideMessage: (index: number) => Promise; userName?: string; } @@ -27,6 +29,7 @@ type MathComponents = { const ConversationMessages: React.FC = ({ messages, + handleHideMessage, userName = "User", }) => { const messagesEndRef = useRef(null); @@ -43,11 +46,15 @@ const ConversationMessages: React.FC = ({ borderRadius="none" borderWidth="1px" p={4} - borderColor="black" + borderColor={message.hidden ? "gray.300" : "black"} alignSelf={message.role === "user" ? "flex-end" : "flex-start"} maxWidth="100%" > - + [{index}] {message.role === "user" ? userName : "Assistant"} = ({ > {message.content} + ))}
diff --git a/app/components/Sidebar.tsx b/app/components/Sidebar.tsx index ff5ca44..3ab0f77 100644 --- a/app/components/Sidebar.tsx +++ b/app/components/Sidebar.tsx @@ -9,8 +9,9 @@ import { DrawerOverlay, useDisclosure, IconButton, + Text, + Divider, } from "@chakra-ui/react"; - import { ChevronRightIcon } from "@chakra-ui/icons"; import { ConversationInfo } from "../utils"; @@ -19,14 +20,34 @@ interface SidebarProps { setConversationId: (id: string) => void; } +const handleConversationClick = ( + id: string, + setConversationId: (id: string) => void, + onClose: () => void +) => { + setConversationId(id); + onClose(); +}; + const Sidebar = ({ conversations, setConversationId }: SidebarProps) => { const { isOpen, onOpen, onClose } = useDisclosure(); - const handleConversationClick = (id: string) => { - setConversationId(id); - onClose(); + const groupConversationsByDate = (conversations: ConversationInfo[]) => { + const groupedConversations: Record = {}; + + conversations.forEach((conversation) => { + const date = new Date(conversation.created_at).toDateString(); + if (!groupedConversations[date]) { + groupedConversations[date] = []; + } + groupedConversations[date].push(conversation); + }); + + return groupedConversations; }; + const groupedConversations = groupConversationsByDate(conversations); + return ( <> { variant="ghost" height="100px" /> - - {/* */} - - - - - {conversations.map((conversation) => ( - - ))} - - - - - {/* */} + + + + + + + {Object.entries(groupedConversations).map( + ([date, conversationsOnDate]) => ( + + + {date} + + {conversationsOnDate.map((conversation) => ( + + ))} + + + ) + )} + + + + + ); diff --git a/app/page.tsx b/app/page.tsx index 6c23d54..6be55f3 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -48,6 +48,30 @@ export default function Home() { setTextValue(event.target.value); }; + const handleHideMessage = async (index: number) => { + try { + const updatedMessages = messages.map((msg, i) => + i === index ? { ...msg, hidden: !msg.hidden } : msg + ); + await fetch( + `${process.env.BACKEND_URL}/conversations/${conversationId}/messages`, + { + method: "PUT", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${cookies.token}`, + }, + body: JSON.stringify({ messages: updatedMessages }), + mode: "cors", + credentials: "include", + } + ); + setMessages(updatedMessages); + } catch (error) { + console.error("Error toggling message visibility:", error); + } + }; + useEffect(() => { const token = searchParams.get("token"); @@ -139,7 +163,10 @@ export default function Home() { justify="space-between" > - +