fix ki modell

This commit is contained in:
nadja
2026-08-26 20:23:52 +02:00
parent 39b6a16598
commit bd1549449c
4 changed files with 53 additions and 42 deletions

View File

@@ -7,5 +7,10 @@ JWT_SECRET=super-langes-geheimnis-hier-aendern
ADMIN_USER=admin
ADMIN_PASS=DEIN-SICHERES-PASSWORT
# Ollama KI-Modell (optional, Standard: mistral)
# OLLAMA_MODEL=mistral
# Groq API (kostenloser Cloud-Zugang zu LLMs)
# 1. Account erstellen: https://console.groq.com
# 2. API Key erstellen und hier eintragen
GROQ_API_KEY=gsk_dein-api-key-hier
# Modell (optional, Standard: llama-3.1-8b-instant)
# GROQ_MODEL=llama-3.1-8b-instant

View File

@@ -4,7 +4,7 @@ import {
updateRecipe, deleteRecipe, getCategories, getDb
} from '../db.js';
import { getTikTokData } from '../services/tiktok.js';
import { isOllamaAvailable, extractRecipe } from '../services/ai.js';
import { isAiAvailable, extractRecipe } from '../services/ai.js';
import { trackEvent } from '../analytics-db.js';
const router = Router();
@@ -34,8 +34,8 @@ router.get('/authors', (req, res) => {
});
router.get('/ai-status', async (req, res) => {
const available = await isOllamaAvailable();
res.json({ ollama: available });
const available = await isAiAvailable();
res.json({ ai: available });
});
router.get('/:id', (req, res) => {
@@ -78,29 +78,29 @@ router.post('/from-tiktok', async (req, res) => {
const tiktokData = await getTikTokData(url);
const ollamaAvailable = await isOllamaAvailable();
const aiAvailable = await isAiAvailable();
let extracted = null;
let aiStatus = ollamaAvailable ? 'available' : 'unavailable';
let aiStatus = aiAvailable ? 'available' : 'unavailable';
let aiMessage = '';
if (ollamaAvailable && tiktokData.title) {
if (aiAvailable && tiktokData.title) {
try {
extracted = await extractRecipe(tiktokData.title);
aiStatus = 'success';
} catch (e) {
console.error('Ollama Extraktion fehlgeschlagen:', e.message);
console.error('KI Extraktion fehlgeschlagen:', e.message);
aiStatus = 'error';
aiMessage = e.message;
}
} else if (!ollamaAvailable) {
aiMessage = 'Ollama-Server nicht erreichbar';
} else if (!aiAvailable) {
aiMessage = 'KI-Service nicht erreichbar';
} else if (!tiktokData.title) {
aiMessage = 'Kein Titel im Video gefunden';
}
res.json({
tiktok: tiktokData,
ollama: ollamaAvailable,
ai: aiAvailable,
aiStatus,
aiMessage,
extracted,

View File

@@ -1,11 +1,25 @@
import { SYSTEM_PROMPT } from '../prompts/extractRecipe.js';
const OLLAMA_URL = process.env.OLLAMA_URL || 'http://localhost:11434';
const MODEL = process.env.OLLAMA_MODEL || 'mistral';
const GROQ_API_KEY = process.env.GROQ_API_KEY;
const GROQ_MODEL = process.env.GROQ_MODEL || 'llama-3.1-8b-instant';
const GROQ_URL = 'https://api.groq.com/openai/v1/chat/completions';
export async function isOllamaAvailable() {
export async function isAiAvailable() {
if (!GROQ_API_KEY) return false;
try {
const res = await fetch(`${OLLAMA_URL}/api/tags`, { signal: AbortSignal.timeout(3000) });
const res = await fetch(GROQ_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${GROQ_API_KEY}`,
},
body: JSON.stringify({
model: GROQ_MODEL,
messages: [{ role: 'user', content: 'ping' }],
max_tokens: 1,
}),
signal: AbortSignal.timeout(10000),
});
return res.ok;
} catch {
return false;
@@ -13,28 +27,31 @@ export async function isOllamaAvailable() {
}
export async function extractRecipe(description) {
const response = await fetch(`${OLLAMA_URL}/api/generate`, {
const response = await fetch(GROQ_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${GROQ_API_KEY}`,
},
body: JSON.stringify({
model: MODEL,
system: SYSTEM_PROMPT,
prompt: `Extrahiere ein Rezept aus dieser TikTok-Videobeschreibung:\n\n${description}`,
stream: false,
options: {
num_ctx: 2048,
temperature: 0.1,
},
model: GROQ_MODEL,
messages: [
{ role: 'system', content: SYSTEM_PROMPT },
{ role: 'user', content: `Extrahiere ein Rezept aus dieser TikTok-Videobeschreibung:\n\n${description}` },
],
temperature: 0.1,
max_tokens: 2048,
}),
signal: AbortSignal.timeout(240000),
signal: AbortSignal.timeout(30000),
});
if (!response.ok) {
throw new Error(`Ollama Fehler: ${response.status}`);
const err = await response.text();
throw new Error(`Groq Fehler: ${response.status} - ${err}`);
}
const data = await response.json();
let text = data.response.trim();
let text = data.choices[0].message.content.trim();
if (text.startsWith('```')) {
text = text.replace(/^```(?:json)?\n?/, '').replace(/\n?```$/, '');

View File

@@ -13,22 +13,11 @@ services:
- PORT=3001
- DB_PATH=/app/data/data.json
- ANALYTICS_PATH=/app/data/analytics.json
- OLLAMA_URL=http://ollama:11434
- OLLAMA_MODEL=${OLLAMA_MODEL:-mistral}
- GROQ_API_KEY=${GROQ_API_KEY}
- GROQ_MODEL=${GROQ_MODEL:-llama-3.1-8b-instant}
- JWT_SECRET=${JWT_SECRET}
- ADMIN_USER=${ADMIN_USER:-admin}
- ADMIN_PASS=${ADMIN_PASS}
volumes:
- ./data:/app/data
depends_on:
- ollama
restart: unless-stopped
ollama:
image: ollama/ollama
volumes:
- ollama_data:/root/.ollama
restart: unless-stopped
volumes:
ollama_data: