Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 45 additions & 3 deletions app/src/screens/chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {
Keyboard
} from 'react-native'
import 'react-native-get-random-values'
import { useContext, useState, useRef } from 'react'
import { useContext, useState, useRef, useEffect, useCallback } from 'react'
import AsyncStorage from '@react-native-async-storage/async-storage'
import { ThemeContext, AppContext } from '../context'
import { getEventSource, getFirstNCharsOrLess, getChatType } from '../utils'
import { v4 as uuid } from 'uuid'
Expand Down Expand Up @@ -40,6 +41,31 @@ export function Chat() {

// Per-model chat state - each model has its own conversation history
const [chatStates, setChatStates] = useState<Record<string, ChatState>>({})
const [chatLoaded, setChatLoaded] = useState(false)

// Load persisted chat history on mount
useEffect(() => {
async function loadChatHistory() {
try {
const stored = await AsyncStorage.getItem('rnai-chatStates')
if (stored) {
setChatStates(JSON.parse(stored))
}
} catch (err) {
console.log('error loading chat history', err)
} finally {
setChatLoaded(true)
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.
}
}
loadChatHistory()
}, [])

// Persist chat history when it changes
const saveChatHistory = useCallback((states: Record<string, ChatState>) => {
AsyncStorage.setItem('rnai-chatStates', JSON.stringify(states)).catch(err =>
console.log('error saving chat history', err)
)
}, [])

// Helper to get or create chat state for current model
const getChatState = (modelLabel: string): ChatState => {
Expand All @@ -54,12 +80,20 @@ export function Chat() {
}))
}

// Persist the current chat states to AsyncStorage
const persistChatStates = () => {
setChatStates(current => {
saveChatHistory(current)
return current
})
}

const { theme } = useContext(ThemeContext)
const { chatType } = useContext(AppContext)
const styles = getStyles(theme)

async function chat() {
if (!input) return
if (!input || !chatLoaded) return
Keyboard.dismiss()
if (chatType.label.includes('claude')) {
generateClaudeResponse()
Expand Down Expand Up @@ -137,6 +171,7 @@ export function Chat() {
}))
} else {
setLoading(false)
persistChatStates()
es.close()
}
} else if (event.type === "error") {
Expand Down Expand Up @@ -215,6 +250,7 @@ export function Chat() {
...prev,
apiMessages: `${prev.apiMessages}\n\nPrompt: ${input}\n\nResponse:${localResponse}`
}))
persistChatStates()
es.close()
}
} else if (event.type === "error") {
Expand Down Expand Up @@ -292,6 +328,7 @@ export function Chat() {
...prev,
apiMessages: `${prev.apiMessages}\n\nHuman: ${input}\n\nAssistant:${getFirstNCharsOrLess(localResponse, 2000)}`
}))
persistChatStates()
es.close()
}
} else if (event.type === "error") {
Expand Down Expand Up @@ -329,7 +366,12 @@ export function Chat() {
async function clearChat() {
if (loading) return
const modelLabel = chatType.label
updateChatState(modelLabel, () => createEmptyChatState())
setChatStates(prev => {
const next = { ...prev }
delete next[modelLabel]
saveChatHistory(next)
return next
})
}

function renderItem({
Expand Down
50 changes: 43 additions & 7 deletions app/src/screens/images.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
Keyboard,
Image
} from 'react-native'
import { useState, useRef, useContext } from 'react'
import { useState, useRef, useContext, useEffect, useCallback } from 'react'
import { DOMAIN, IMAGE_MODELS } from '../../constants'
import { v4 as uuid } from 'uuid'
import { ThemeContext, AppContext } from '../context'
Expand All @@ -21,6 +21,7 @@ import { useActionSheet } from '@expo/react-native-action-sheet'
import * as FileSystem from 'expo-file-system'
import * as ImagePicker from 'expo-image-picker'
import * as Clipboard from 'expo-clipboard'
import AsyncStorage from '@react-native-async-storage/async-storage'

const { width } = Dimensions.get('window')

Expand All @@ -41,6 +42,35 @@ export function Images() {
index: uuid,
values: []
})
const [imagesLoaded, setImagesLoaded] = useState(false)

// Load persisted image history on mount
useEffect(() => {
async function loadImageHistory() {
try {
const stored = await AsyncStorage.getItem('rnai-imageHistory')
if (stored) {
const parsed = JSON.parse(stored)
setImages(parsed)
if (parsed.values.length > 0) {
setCallMade(true)
}
}
} catch (err) {
console.log('error loading image history', err)
} finally {
setImagesLoaded(true)
}
}
loadImageHistory()
}, [])

// Persist image history when it changes
const saveImageHistory = useCallback((state: ImagesState) => {
AsyncStorage.setItem('rnai-imageHistory', JSON.stringify(state)).catch(err =>
console.log('error saving image history', err)
)
}, [])
const {
handlePresentModalPress,
closeModal,
Expand All @@ -56,7 +86,7 @@ export function Images() {
const showImagePickerButton = !hideInput

async function generate() {
if (loading) return
if (loading || !imagesLoaded) return
if (hideInput && !image) {
console.log('no image selected')
return
Expand Down Expand Up @@ -128,10 +158,12 @@ export function Images() {
imagesArray[imagesArray.length - 1].image = response.image
imagesArray[imagesArray.length - 1].model = currentModel
imagesArray[imagesArray.length - 1].provider = providerLabel
setImages(i => ({
index: i.index,
const newState = {
index: images.index,
values: imagesArray
}))
}
setImages(newState)
saveImageHistory(newState)
setLoading(false)
setTimeout(() => {
scrollViewRef.current?.scrollToEnd({
Expand Down Expand Up @@ -177,10 +209,14 @@ export function Images() {

function clearPrompts() {
setCallMade(false)
setImages({
const emptyState = {
index: uuid,
values: []
})
}
setImages(emptyState)
AsyncStorage.removeItem('rnai-imageHistory').catch(err =>
console.log('error clearing image history', err)
)
}

async function showClipboardActionsheet(d) {
Expand Down