Skip to content
Draft
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
29 changes: 5 additions & 24 deletions components/screens/HistoryStackScreen/HistoryScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,30 +123,6 @@ const HistoryScreen = () => {
);
}

if (flashcards.length === 0) {
return (
<BackgroundView>
<RefreshableScrollView
refreshing={refreshing}
onRefresh={handleRefresh}
contentContainerStyle={tw`flex-1 justify-center items-center p-5`}
>
<Text style={tw`text-xl mb-8 text-center px-4 ${theme.classes.textPrimary}`}>{t('no_flashcards_added')}</Text>
<Button
mode="contained"
onPress={() => navigation.reset({
index: 0,
routes: [{ name: 'Main', params: { screen: 'Read' } }],
})}
style={tw`bg-purple-600`}
>
<Text style={tw`text-white`}>{t('go_to_readings')}</Text>
</Button>
</RefreshableScrollView>
</BackgroundView>
);
}

const handleDeleteFlashcard = async (id: string) => {
await deleteFlashcard(id);
setFlashcards(prevFlashcards => prevFlashcards.filter(card => card.id !== id));
Expand Down Expand Up @@ -179,6 +155,11 @@ const HistoryScreen = () => {
</View>
</Button>
<View style={tw`pb-10`}>
{flashcards.length === 0 ?
<View style={tw`pt-20`}>
<Text style={tw`text-xl mb-8 text-center px-4 ${theme.classes.textPrimary}`}>{t('no_flashcards_added')}</Text>
</View>
: null}
{sortedDates.map(date => (
<View key={date} style={tw`mb-5`}>
<Text style={tw`text-base font-medium mb-3 ${theme.classes.textPrimary}`}>{date}:</Text>
Expand Down
40 changes: 37 additions & 3 deletions components/screens/ReadStackScreen/ReadingScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import { LanguageContext } from '../../../contexts/LanguageContext';
import { ActivityIndicator } from 'react-native-paper';
import { getWordTimeStamps } from '../../../services/whisper';
import { useTranslation } from 'react-i18next';
import { useHardestWord } from '../../../services/chatGpt';
import { translatePassage, useHardestWord } from '../../../services/chatGpt';
import RomanizeButton from '../../RomanizeButton';

type ReadingScreenRouteProp = RouteProp<RootStackParamList, 'Reading'>;

Expand All @@ -37,7 +38,11 @@ const ReadingScreen: React.FC<Props> = ({ route }) => {
const [pausedToOpenDefinition, setPausedToOpenDefinition] = useState(false);
const [flashingWordIndex, setFlashingWordIndex] = useState<number | null>(null);

const { targetLanguage } = useContext(LanguageContext);
const [translationVisible, setTranslationVisible] = useState<boolean>(false);
const [translationLoading, setTranslationLoading] = useState<boolean>(false);
const [translation, setTranslation] = useState<string>();

const { targetLanguage, nativeLanguage } = useContext(LanguageContext);

const {
pauseAudio,
Expand Down Expand Up @@ -102,6 +107,24 @@ const ReadingScreen: React.FC<Props> = ({ route }) => {
}
}, [audioFile, reading, wordTimestamps, duration]);

useEffect(() => {
const fetchTranslation = async () => {
if (!reading?.passage) return
setTranslationLoading(true)
const translation = await translatePassage({
passage: reading.passage,
language: targetLanguage,
translateTo: nativeLanguage,
});
console.log('translation: ', translation)
setTranslation(translation ?? undefined);
setTranslationLoading(false)
};
if (!translation) {
fetchTranslation();
}
}, [reading?.passage]);

useEffect(() => {
if (wordTimestamps) {
const interval = setInterval(() => {
Expand Down Expand Up @@ -177,7 +200,18 @@ const ReadingScreen: React.FC<Props> = ({ route }) => {
return (
<View style={tw`flex-1 ${theme.classes.backgroundPrimary} px-5`}>
<ScrollView style={tw`flex-1 px-5 pt-20`}>
<Text style={tw`text-2xl mb-4 ${theme.classes.textPrimary}`}>{reading.title}</Text>
<View style={tw`flex flex-row justify-between items-start`}>
<Text style={tw`text-2xl mb-4 ${theme.classes.textPrimary}`}>
{reading.title}
</Text>
{translationVisible && translationLoading ?
<ActivityIndicator size="small" color={theme.colors.purplePrimary} />
: <RomanizeButton show={!translationVisible} onPress={() => setTranslationVisible(!translationVisible)}/> }
</View>
{ translationVisible ?
<Text>{translation}</Text>
: null}

<View style={tw`mb-60`}>
{passage.split('\n').map((line, index) => (
<ParagraphComponent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const WordComponent: React.FC<Props> = ({
}, [isFlashing]);

const color = isHighlighted ? `text-[${theme.colors.tomato}]` : theme.classes.textPrimary;
const backgroundColor = flash ? 'bg-purple-300' : 'transparent';
const backgroundColor = flash ? 'bg-purple-300' : '';

return (
<View key={`${word}-${paragraphIndex}-${wordIndex}`} style={tw`flex-row`}>
Expand Down
30 changes: 30 additions & 0 deletions services/chatGpt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,3 +295,33 @@ export async function useHardestWord(passage: string) {
throw error;
}
}


export async function translatePassage({
passage,
language,
translateTo,
}: {
passage: string
language: LanguageCode
translateTo: LanguageCode
}) {
try {
const response = await openai.chat.completions.create({
model: "gpt-4o-mini",
messages: [
{
role: "user",
content:
`Translate the follow ${language} passage into ${translateTo}: \n\n${passage}. Only respond with the translated passage.` }
],
temperature: 0.7,
n: 1
});

return response.choices[0].message.content
} catch (error) {
console.error('Error getting hardest word:', error);
throw error;
}
}