diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..257de9c --- /dev/null +++ b/.env.example @@ -0,0 +1,2 @@ +EXPO_PUBLIC_OLLAMA_BASE_URL=http://localhost:11434 +EXPO_PUBLIC_OLLAMA_MODEL=llama3.2 diff --git a/README.md b/README.md index 5276ad5..861fb84 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,26 @@ Abhaengigkeiten installieren: npm install ``` +Optionale lokale KI-Konfiguration anlegen: + +```bash +cp .env.example .env +``` + +In `.env` kannst du dein Ollama-Modell eintragen: + +```text +EXPO_PUBLIC_OLLAMA_BASE_URL=http://localhost:11434 +EXPO_PUBLIC_OLLAMA_MODEL=llama3.2 +``` + +Wenn du die App auf einem echten Smartphone mit Expo Go testest, ist `localhost` das Smartphone selbst. Nutze dann die IP deines PCs, zum Beispiel: + +```text +EXPO_PUBLIC_OLLAMA_BASE_URL=http://192.168.10.102:11434 +EXPO_PUBLIC_OLLAMA_MODEL=qwen2.5:7b +``` + App starten: ```bash @@ -98,9 +118,9 @@ npm run web Hinweis: Fuer lokale iOS-Simulator-Builds wird macOS mit Xcode benoetigt. Mit Expo Go kann die App auf einem echten Geraet getestet werden. -## Ollama Integration Geplant +## Ollama Integration -Der aktuelle Chat nutzt `src/services/mockAiCoach.ts`. Dieser Service ist die vorgesehene Stelle, um spaeter einen echten KI-Client zu integrieren. +Der Chat nutzt `src/services/ollamaClient.ts` fuer echte lokale KI-Antworten. Falls Ollama nicht erreichbar ist, faellt `src/services/mockAiCoach.ts` automatisch auf Beispielantworten zurueck. Die Modell-Konfiguration liegt in `src/config/ai.ts` und liest Werte aus `.env`. Moeglicher lokaler Ablauf: diff --git a/src/config/ai.ts b/src/config/ai.ts new file mode 100644 index 0000000..dbe3d6d --- /dev/null +++ b/src/config/ai.ts @@ -0,0 +1,4 @@ +export const aiConfig = { + ollamaBaseUrl: process.env.EXPO_PUBLIC_OLLAMA_BASE_URL ?? 'http://localhost:11434', + ollamaModel: process.env.EXPO_PUBLIC_OLLAMA_MODEL ?? 'llama3.2', +}; diff --git a/src/services/mockAiCoach.ts b/src/services/mockAiCoach.ts index 29f11a1..277d139 100644 --- a/src/services/mockAiCoach.ts +++ b/src/services/mockAiCoach.ts @@ -1,4 +1,6 @@ import type { EnglishLevel } from '../navigation/types'; +import { aiConfig } from '../config/ai'; +import { askOllama } from './ollamaClient'; const examples: Record = { A1: 'Fast richtig! Correct: "I am learning English." Warum? Bei "I" nutzt du "am".', @@ -8,11 +10,15 @@ const examples: Record = { }; export async function getMockAiReply(input: string, level: EnglishLevel) { - await new Promise((resolve) => setTimeout(resolve, 350)); - if (!input.trim()) { return 'Schreib einen kurzen englischen Satz, dann korrigiere ich ihn fuer dein Level.'; } - return `${examples[level]}\n\nDein Satz: "${input.trim()}"`; + try { + return await askOllama(input.trim(), level); + } catch { + await new Promise((resolve) => setTimeout(resolve, 350)); + } + + return `${examples[level]}\n\nDein Satz: "${input.trim()}"\n\nKI Backend vorbereitet: ${aiConfig.ollamaModel}`; } diff --git a/src/services/ollamaClient.ts b/src/services/ollamaClient.ts new file mode 100644 index 0000000..a61249b --- /dev/null +++ b/src/services/ollamaClient.ts @@ -0,0 +1,39 @@ +import { aiConfig } from '../config/ai'; +import type { EnglishLevel } from '../navigation/types'; + +type OllamaGenerateResponse = { + response?: string; +}; + +export async function askOllama(input: string, level: EnglishLevel) { + const response = await fetch(`${aiConfig.ollamaBaseUrl}/api/generate`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + model: aiConfig.ollamaModel, + stream: false, + prompt: buildPrompt(input, level), + }), + }); + + if (!response.ok) { + throw new Error(`Ollama request failed with ${response.status}`); + } + + const data = (await response.json()) as OllamaGenerateResponse; + return data.response?.trim() || 'Ich konnte keine Antwort erzeugen.'; +} + +function buildPrompt(input: string, level: EnglishLevel) { + return `Du bist ein freundlicher Englisch-Coach fuer deutsche Lernende. +Level: ${level} +Aufgabe: +1. Korrigiere den englischen Satz. +2. Erklaere den wichtigsten Fehler kurz auf Deutsch. +3. Gib eine bessere natuerliche Variante. +4. Antworte kurz und motivierend. + +Satz des Nutzers: ${input}`; +}