Friendzone Lite is an AI-powered memory capture and organization system that helps you extract, refine, and structure memories from images through intelligent conversation. It transforms images into structured, searchable memories through natural language interaction.
Memory Processing Function: update_memory_details() - AI-powered memory extraction and refinement
Session Node: Maintains persistent memory state across interactions
Update Walker: Handles user interactions and memory updates
objResponse{hasfollow_up_questions:str;# Next question to askhassummary:str;# Concise memory summaryhaswhen:str;# Date in YYYY-MM-DD formathaswho:List[str];# Names of people involvedhaswhat:str;# What the memory is abouthaswhere:List[str];# Relevant locationshasterminate_conversation:bool;# Completion flaghasshow_summary:bool;# Display summary flag}
importfrombyllm.llm{Model}importfrombyllm.types{Image}importfromtyping{List,Dict,Any}importos;globllm=Model(model_name="gemini/gemini-2.5-flash");objResponse{hasfollow_up_questions:str,summary:str,when:str,who:List[str],what:str,where:List[str],terminate_conversation:bool,show_summary:bool;}semResponse="Memory details refined using the user's input and prior context.";semResponse.follow_up_questions="Ask one follow-up question to continue the conversation. If all required details are present, ask to terminate the conversation.";semResponse.summary="A concise summary of the memory.";semResponse.when="The date of the memory in YYYY-MM-DD format.";semResponse.who="Exact names of people in the memory (e.g., [John, Kate]); return [] if none.";semResponse.where="List of places relevant to the memory.";semResponse.what="What the memory is about.";semResponse.show_summary="True if all required details are present and the summary should be shown.";semResponse.terminate_conversation="True if the user asked to terminate the conversation; otherwise false.";""" Update and extract memory details based on user input and context."""defupdate_memory_details(image:Image,utterance:str="",summary:str="",when:str="",who:List[str]=[],where:List[str]=[],what:str="",conversation:List[dict]=[],show_summary:bool=False,terminate_conversation:bool=False)->Responsebyllm();nodesession{hassummary:str="",when:str="",who:list=[],where:list=[],what:str="",conversation:list=[],image_url:str="",show_summary:bool=False,terminate_conversation:bool=False;}walkerupdate_session{hasimage_url:str,utterance:str="";canvisit_sessionwith`rootentry{# Find or create session for this imagematching_sessions=[sessforsessin[-->](`?session)ifsess.image_url==self.image_urlandnotsess.terminate_conversation];ifmatching_sessions{visitmatching_sessions[0];}else{session_node=here++>session();visitsession_node[0];}}canupdate_sessionwithsessionentry{ifhere.image_url==""{here.image_url=self.image_url;}response=update_memory_details(image=Image(url=self.image_url),utterance=self.utterance,summary=here.summary,when=here.when,who=here.who,where=here.where,what=here.what,conversation=here.conversation,show_summary=here.show_summary,terminate_conversation=here.terminate_conversation);here.summary=response.summary;here.when=response.when;here.who=response.who;here.where=response.where;here.what=response.what;here.show_summary=response.show_summary;self.show_summary=response.show_summary;here.terminate_conversation=response.terminate_conversation;self.terminate_conversation=response.terminate_conversation;here.conversation=here.conversation+[{"role":"user","content":self.utterance}]+[{"role":"assistant","content":response.follow_up_questions}];ifresponse.show_summary{ifresponse.terminate_conversation{print("Assistant: "+response.follow_up_questions);print("Final Memory Summary:"+response.summary);}else{print("Memory Summary (in progress):"+response.summary);print("Assistant: "+response.follow_up_questions);}}else{print("Assistant: "+response.follow_up_questions);}# Report session state for frontendreport{"summary":here.summary,"when":here.when,"who":here.who,"where":here.where,"what":here.what,"show_summary":here.show_summary,"terminate_conversation":here.terminate_conversation,"follow_up_questions":response.follow_up_questions,"conversation":here.conversation,"image_url":here.image_url};}}walkerget_memories{canget_all_memorieswith`rootentry{memories=[];formemin[-->](`?session){# Only include completed memoriesifmem.terminate_conversationandmem.show_summary{memories.append({"summary":mem.summary,"when":mem.when,"who":mem.who,"where":mem.where,"what":mem.what,"image_url":mem.image_url});}}report{"memories":memories};}}
importstreamlitasst;importrequests;defbootstrap_frontend(token:str){st.set_page_config(page_title="Friendzone Lite - Memory Assistant",page_icon="🧠",layout="wide");st.title("🧠 Friendzone Lite - Memory Assistant");st.markdown("✨ Capture and organize your memories from images");# Initialize session stateif"memory_results"notinst.session_state{st.session_state.memory_results=None;}if"conversation_active"notinst.session_state{st.session_state.conversation_active=False;}if"image_url"notinst.session_state{st.session_state.image_url="";}if"conversation_history"notinst.session_state{st.session_state.conversation_history=[];}if"loading"notinst.session_state{st.session_state.loading=False;}if"view_memories"notinst.session_state{st.session_state.view_memories=False;}if"captured_memories"notinst.session_state{st.session_state.captured_memories=[];}# Main interfacest.markdown("### 📷 Start Your Memory Journey");# Add button to view captured memoriescolumns=st.columns([3,1]);withcolumns[1]{ifst.button("📚 View Captured Memories"){st.session_state.view_memories=notst.session_state.view_memories;ifst.session_state.view_memories{# Fetch memories from backendtry{response=requests.post("http://localhost:8000/walker/get_memories",json={},headers={"Authorization":f"Bearer {token}"});ifresponse.status_code==200{result=response.json();st.session_state.captured_memories=result.get("reports",[{}])[0].get("memories",[]);}}exceptExceptionase{st.error(f"❌ Error loading memories: {str(e)}");}}st.rerun();}}# Display captured memories if view_memories is Trueifst.session_state.view_memories{st.markdown("---");st.markdown("### 📚 Captured Memories");ifst.session_state.captured_memories{mem_idx=0;formemoryinst.session_state.captured_memories{mem_idx=mem_idx+1;withst.expander(f"Memory {mem_idx}: {memory.get('summary','Untitled')[:50]}...",expanded=False){mem_columns=st.columns([1,2]);withmem_columns[0]{ifmemory.get("image_url"){try{st.image(memory["image_url"],caption="Memory Image",use_column_width=True);}exceptException{st.write("🖼️ Image not available");}}}withmem_columns[1]{st.markdown(f"**📋 Summary:**");st.write(memory.get("summary","N/A"));st.markdown(f"**📅 When:** {memory.get('when','Not specified')}");who_list=memory.get("who",[]);st.markdown(f"**👥 Who:** {', '.join(who_list)ifwho_listelse'Not specified'}");where_list=memory.get("where",[]);st.markdown(f"**📍 Where:** {', '.join(where_list)ifwhere_listelse'Not specified'}");st.markdown(f"**🎯 What:** {memory.get('what','Not specified')}");}}}}else{st.info("📭 No captured memories yet. Start a memory session to create your first memory!");}st.markdown("---");}# Image URL input sectionifnotst.session_state.conversation_active{st.markdown("#### 🌐 Enter Image URL");image_url=st.text_input("🔗 Image URL:",placeholder="https://example.com/your-image.jpg",help="Enter the URL of an image containing a memory you'd like to capture");ifst.button("🚀 Start Memory Session"){ifimage_url.strip(){st.session_state.image_url=image_url;st.session_state.conversation_active=True;st.session_state.loading=True;st.rerun();}else{st.warning("⚠️ Please enter a valid image URL!");}}}# Active conversation sectionifst.session_state.conversation_active{# Display current imagest.markdown("#### 📷 Current Image");try{st.image(st.session_state.image_url,caption="Memory Image",use_column_width=True);}exceptException{st.warning("⚠️ Could not display image. Proceeding with URL...");}# Initialize session if loadingifst.session_state.loadingandnotst.session_state.memory_results{withst.spinner("🧠 AI is analyzing your image..."){try{response=requests.post("http://localhost:8000/walker/update_session",json={"image_url":st.session_state.image_url,"utterance":""},headers={"Authorization":f"Bearer {token}"});ifresponse.status_code==200{result=response.json();st.session_state.memory_results=result.get("reports",[{}])[0];st.session_state.loading=False;st.success("✅ Memory session started!");st.rerun();}else{st.error(f"❌ Failed to start session: {response.text}");st.session_state.loading=False;}}exceptExceptionase{st.error(f"❌ Error: {str(e)}");st.session_state.loading=False;}}}# Display memory progressifst.session_state.memory_results{results=st.session_state.memory_results;# Memory summary sectionst.markdown("#### 📝 Memory Details");st.markdown("**📅 When:**");when_val=results.get("when","Not specified");ifwhen_val{st.info(when_val);}else{st.info("Not specified");}st.markdown("**👥 Who:**");who_val=results.get("who",[]);ifwho_val{st.info(", ".join(who_val));}else{st.info("Not specified");}st.markdown("**📍 Where:**");where_val=results.get("where",[]);ifwhere_val{st.info(", ".join(where_val));}else{st.info("Not specified");}st.markdown("**🎯 What:**");what_val=results.get("what","");ifwhat_val{st.info(what_val);}else{st.info("Not specified");}# Summaryifresults.get("summary"){st.markdown("**📋 Memory Summary:**");ifresults.get("show_summary",False){ifresults.get("terminate_conversation",False){st.success(f"✅ Final Memory Summary: {results['summary']}");}else{st.info(f"📝 Memory Summary (in progress): {results['summary']}");}}else{st.write("📝 Building memory summary...");}}# Conversation sectionst.markdown("#### 💬 Conversation");# Display conversation historyifst.session_state.conversation_history{formsginst.session_state.conversation_history{ifmsg["role"]=="user"{st.chat_message("user").write(f"👤 {msg['content']}");}else{st.chat_message("assistant").write(f"🤖 {msg['content']}");}}}# Check if conversation is completeifresults.get("show_summary",False)andresults.get("terminate_conversation",False){st.success("🎉 Memory capture complete!");ifst.button("🔄 Start New Memory Session"){st.session_state.conversation_active=False;st.session_state.memory_results=None;st.session_state.image_url="";st.session_state.conversation_history=[];st.session_state.loading=False;st.rerun();}}else{# User input for continuing conversationuser_input=st.chat_input("Continue the conversation...");ifuser_input{# Add user message to historyst.session_state.conversation_history.append({"role":"user","content":user_input});# Send to backendwithst.spinner("🤖 AI is processing your response..."){try{response=requests.post("http://localhost:8000/walker/update_session",json={"image_url":st.session_state.image_url,"utterance":user_input},headers={"Authorization":f"Bearer {token}"});ifresponse.status_code==200{result=response.json();st.session_state.memory_results=result.get("reports",[{}])[0];# Add assistant response to historyif"follow_up_questions"inst.session_state.memory_results{st.session_state.conversation_history.append({"role":"assistant","content":st.session_state.memory_results["follow_up_questions"]});}st.rerun();}else{st.error(f"❌ Failed to process response: {response.text}");}}exceptExceptionase{st.error(f"❌ Error: {str(e)}");}}}}}# Reset session buttonifst.button("🔄 Reset Session"){st.session_state.conversation_active=False;st.session_state.memory_results=None;st.session_state.image_url="";st.session_state.conversation_history=[];st.session_state.loading=False;st.rerun();}}# Footerst.markdown("---");st.markdown("**🧠 Powered by Friendzone Lite AI Assistant**");st.markdown("✨ Features: 📷 Image analysis • 💭 Memory extraction • 📝 Structured capture");}globINSTANCE_URL="http://localhost:8000",TEST_USER_EMAIL="test@mail.com",TEST_USER_PASSWORD="password",response=requests.post(f"{INSTANCE_URL}/user/login",json={"email":TEST_USER_EMAIL,"password":TEST_USER_PASSWORD});withentry{ifresponse.status_code!=200{# Try registering the user if login failsresponse=requests.post(f"{INSTANCE_URL}/user/register",json={"email":TEST_USER_EMAIL,"password":TEST_USER_PASSWORD});assertresponse.status_code==201;response=requests.post(f"{INSTANCE_URL}/user/login",json={"email":TEST_USER_EMAIL,"password":TEST_USER_PASSWORD});assertresponse.status_code==200;}}globtoken=response.json()["token"];withentry{bootstrap_frontend(token);}
AI Initial Response:
"I can see this appears to be a beach scene with several people. To help me capture this memory completely, when was this photo taken?"
Consistency Checking: Validates logical coherence of memory details
Completeness Assessment: Ensures all key aspects are captured
Accuracy Verification: Cross-references visual and textual information
Looking for the full version? This is a lite version for learning purposes. Check out the full-scale FriendZone project for a complete implementation with advanced features.
{"memory_id":"unique_identifier","created_at":"timestamp","image_url":"source_image_url","details":{"when":"2024-07-15","who":["User","Sarah","Mike"],"where":["Santa Monica Beach","California"],"what":"Beach day celebration for Sarah's birthday"},"summary":"Comprehensive memory description","conversation_log":["question_response_pairs"]}
Ensure image file size is within reasonable limits
Conversation Flow Issues:
Provide clear, specific answers to AI questions
If stuck, try rephrasing or providing additional context
Restart the session if conversation becomes inconsistent
Memory Quality Concerns:
Be specific and detailed in your responses
Correct any misunderstandings immediately
Use follow-up sessions to refine captured memories
Friendzone Lite showcases the potential of combining visual AI with conversational intelligence to create meaningful, structured memory systems that preserve and organize life's important moments.