Skip to content

Commit 6aa41a3

Browse files
authored
Merge pull request #84 from otjamin/dev
Project submission
2 parents bd63957 + 9475e16 commit 6aa41a3

11 files changed

Lines changed: 112 additions & 41 deletions

File tree

README.md

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,49 @@
11
# GetDressed
22

3+
## Erste Schritte
4+
5+
Es gibt verschiedene Möglichkeiten die App zu testen. Um es einfach zu machen haben wir eine `compose.yaml` erstellt, die alle benötigten Dienste enthält und eine kurze Schritt für Schritt Anleitung verfasst.
6+
7+
Als erstes installiere dir Docker und Node.js, falls noch nicht geschehen.
8+
9+
Dann kannst du das Repository herunterladen oder klonen.
10+
11+
### Backend
12+
13+
#### Ohne Ollama (lokale Installation)
14+
15+
Installiere zuerst [Ollama](https://ollama.com/download) und lade `gemma3` als Modell.
16+
17+
```bash
18+
ollama pull gemma3
19+
```
20+
21+
Jetzt kannst du das Backend starten.
22+
23+
```bash
24+
docker compose up
25+
```
26+
27+
Damit Ollama aus den Containern erreichbar ist, musst du es mit `OLLAMA_HOST=0.0.0.0` starten.
28+
29+
#### Mit Ollama (benötigt NVIDIA Container Toolkit)
30+
31+
```
32+
docker compose -f compose.yaml -f compose.ollama.yaml up
33+
```
34+
35+
### App
36+
37+
Wechsle in den mobile Ordner und installiere mit `npm install` alle Abhängigkeiten.
38+
39+
Bevor du die App starten kannst, musst du in der .env Datei die richtige IP eintragen. Wenn du die App an deinem Smartphone testen möchtest musst du die IP von deinem Computer nehmen. Für den Android Emulator musst du `10.0.2.2` eintragen.
40+
41+
Jetzt kannst du die App starten und ausprobieren.
42+
43+
```bash
44+
npx expo start
45+
```
46+
347
## Agents
448

549
Alle Agenten werden mit CrewAI erstellt.
@@ -15,16 +59,6 @@ Du kannst die Agents auch einzeln testen. Dafür solltest du Ollama installiert
1559

1660
Mit `uv run my_crew` lässt sich dieser ausführen.
1761

18-
## Erste Schritte
19-
20-
Zum Starten des Servers wird **Docker** oder **Podman** benötigt. Alle benötigten Dienste sind in einer zentralen `compose.yaml` definiert, sodass das gesamte System mit nur einem Befehl gestartet werden kann:
21-
22-
```bash
23-
docker compose up
24-
```
25-
26-
Die Expo App muss separat gestartet werden. Navigiere dazu in das entsprechende Verzeichnis und starte sie.
27-
2862
## Mitmachen
2963

3064
Du möchtest mit an diesem Projekt arbeiten? Wir haben das wichtigste zusammengeschrieben um dir den Einstieg so einfach wie möglich zu machen.

compose.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ services:
44
api:
55
build: ./server
66
environment:
7-
- MODEL=ollama/gemma3:12b
7+
- MODEL=ollama/gemma3
88
- API_BASE=http://host.docker.internal:11434
99
- PB_URL=http://pb:8080
1010
ports:

mobile/.env

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
EXPO_PUBLIC_API_URL=http://h46.finsterwiese.de:8000
2-
EXPO_PUBLIC_PB_URL=http://h46.finsterwiese.de:8090
1+
EXPO_PUBLIC_API_URL=http://localhost:8000
2+
EXPO_PUBLIC_PB_URL=http://localhost:8090

mobile/app/(tabs)/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import {
44
Text,
55
View,
66
FlatList,
7-
SafeAreaView,
87
TouchableOpacity,
98
Image,
109
Vibration,
@@ -23,6 +22,7 @@ import EditLookbookModal from '@/components/EditLookbookModal';
2322
import { pb } from '@/utils/pocketbase';
2423
import 'react-native-get-random-values';
2524
import { generateTags } from '@/utils/wardrobeApi';
25+
import { SafeAreaView } from 'react-native-safe-area-context';
2626

2727
export type WardrobeItem = {
2828
id: string;

mobile/app/(tabs)/quiz/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { useState } from 'react';
2-
import { SafeAreaView, View, Text, TouchableOpacity, StyleSheet } from 'react-native';
2+
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
33
import { useRouter } from 'expo-router';
44
import { questions } from '@/utils/questions';
55
import QuestionCard from '@/components/QuestionCard';
66
import { useQuiz } from '@/ctx/Quiz';
77
import SectionHeader from '@/components/SectionHeader';
8+
import { SafeAreaView } from 'react-native-safe-area-context';
89

910
export default function QuizScreen() {
1011
const [started, setStarted] = useState(false);

mobile/app/(tabs)/quiz/result.tsx

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
1+
import { View, Text, TouchableOpacity, StyleSheet, Share } from 'react-native';
22
import { useRouter } from 'expo-router';
33
import { useQuiz } from '@/ctx/Quiz';
44
import AsyncStorage from '@react-native-async-storage/async-storage';
@@ -50,6 +50,17 @@ export default function ResultScreen() {
5050
router.replace('/(tabs)/quiz'); // zurück zur ersten Frage
5151
};
5252

53+
const handleShare = async () => {
54+
try {
55+
const shareMessage = `Mein Style-Profil:\n\n${summary}\n\nMach jetzt auch das Style-Quiz und finde deinen Look!`;
56+
await Share.share({
57+
message: shareMessage,
58+
});
59+
} catch (error) {
60+
console.error('Fehler beim Teilen:', error);
61+
}
62+
};
63+
5364
return (
5465
<View style={styles.container}>
5566
<Text style={styles.title}>Dein Style-Profil</Text>
@@ -66,6 +77,12 @@ export default function ResultScreen() {
6677
<TouchableOpacity style={styles.button} onPress={handleRestart}>
6778
<Text style={styles.buttonText}>Quiz neu starten</Text>
6879
</TouchableOpacity>
80+
81+
{summary && (
82+
<TouchableOpacity style={styles.button} onPress={handleShare}>
83+
<Text style={styles.buttonText}>Ergebnis teilen</Text>
84+
</TouchableOpacity>
85+
)}
6986
</View>
7087
);
7188
}
@@ -90,4 +107,11 @@ const styles = StyleSheet.create({
90107
textAlign: 'center',
91108
paddingHorizontal: 10,
92109
},
110+
shareButton: {
111+
marginTop: 20,
112+
backgroundColor: '#555',
113+
padding: 14,
114+
borderRadius: 12,
115+
alignSelf: 'center',
116+
},
93117
});

mobile/app/(tabs)/trends/index.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,23 @@ import CustomSafeAreaView from '@/components/CustomSafeAreaView';
22
import SectionHeader from '@/components/SectionHeader';
33
import TrendList from '@/components/TrendList';
44
import TrendPrompt from '@/components/TrendPrompt';
5+
import { fetchTrends, Trend } from '@/utils/trendApi';
6+
import { useCallback, useState } from 'react';
57
import { StyleSheet, Text, View } from 'react-native';
68

79
export default function TrendScout() {
10+
const [trends, setTrends] = useState<Trend[]>([]);
11+
12+
const getTrends = useCallback(async () => {
13+
fetchTrends()
14+
.then((fetchedTrends) => {
15+
setTrends(fetchedTrends);
16+
})
17+
.catch((error) => {
18+
console.error('Error fetching trends:', error);
19+
});
20+
}, []);
21+
822
return (
923
<CustomSafeAreaView style={styles.container}>
1024
<SectionHeader title="Trend-Scout" />
@@ -14,11 +28,11 @@ export default function TrendScout() {
1428
Wonach suchst du gerade? Erhalte Antworten basierend auf aktuellen Daten aus Social Media,
1529
Online-Shops & Style-Blogs.
1630
</Text>
17-
<TrendPrompt />
31+
<TrendPrompt getTrends={getTrends} />
1832
</View>
1933
<View style={styles.trendsContainer}>
2034
<Text style={styles.title}>Aktuelle Trends</Text>
21-
<TrendList />
35+
<TrendList trends={trends} getTrends={getTrends} />
2236
</View>
2337
</CustomSafeAreaView>
2438
);

mobile/components/TrendList.tsx

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,25 @@
11
import { FlatList, RefreshControl, View } from 'react-native';
22
import TrendListItem from './TrendListItem';
33
import { useCallback, useEffect, useState } from 'react';
4-
import { fetchTrends, Trend } from '@/utils/trendApi';
4+
import { Trend } from '@/utils/trendApi';
55

6-
export default function TrendList() {
7-
const [trends, setTrends] = useState<Trend[]>([]);
8-
const [refreshing, setRefreshing] = useState(false);
6+
interface TrendListProps {
7+
trends: Trend[];
8+
getTrends: () => Promise<void>;
9+
}
910

10-
const getTrends = async () => {
11-
fetchTrends()
12-
.then((fetchedTrends) => {
13-
setTrends(fetchedTrends);
14-
})
15-
.catch((error) => {
16-
console.error('Error fetching trends:', error);
17-
});
18-
};
11+
export default function TrendList({ trends, getTrends }: TrendListProps) {
12+
const [refreshing, setRefreshing] = useState(false);
1913

2014
useEffect(() => {
2115
getTrends();
22-
}, []);
16+
}, [getTrends]);
2317

2418
const onRefresh = useCallback(async () => {
2519
setRefreshing(true);
2620
await getTrends();
2721
setRefreshing(false);
28-
}, []);
22+
}, [getTrends]);
2923

3024
return (
3125
<View style={{ flex: 1 }}>

mobile/components/TrendPrompt.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ import {
1111
View,
1212
} from 'react-native';
1313

14-
export default function TrendPrompt() {
14+
interface TrendPromptProps {
15+
getTrends: () => Promise<void>;
16+
}
17+
18+
export default function TrendPrompt({ getTrends }: TrendPromptProps) {
1519
const [prompt, setPrompt] = useState<string>('');
1620
const [isThinking, setIsThinking] = useState<boolean>(false);
1721
const rotateValue = useAnimatedValue(0);
@@ -53,14 +57,13 @@ export default function TrendPrompt() {
5357
const handleSubmit = async () => {
5458
setIsThinking(true);
5559

56-
await generateTrends(prompt).then((trends) => {
57-
console.log('Generated Trends:', trends);
60+
const trends = await generateTrends(prompt);
61+
console.log('Generated Trends:', trends);
5862

59-
saveTrends(trends); // Save trends to db
60-
});
63+
await saveTrends(trends); // Save trends to db
64+
getTrends(); // Refresh the trends list
6165

6266
setPrompt(''); // Clear the input after submission
63-
6467
setIsThinking(false);
6568
};
6669

ollama.Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
FROM ollama/ollama:0.9.4
2-
ARG MODELS="gemma3:12b"
2+
ARG MODELS="gemma3"
33
ENV OLLAMA_KEEP_ALIVE=24h
44
RUN ollama serve & server=$! ; sleep 5 ; for m in $MODELS ; do ollama pull $m ; done ; kill $server

0 commit comments

Comments
 (0)