fix ki modell
This commit is contained in:
@@ -7,5 +7,10 @@ JWT_SECRET=super-langes-geheimnis-hier-aendern
|
|||||||
ADMIN_USER=admin
|
ADMIN_USER=admin
|
||||||
ADMIN_PASS=DEIN-SICHERES-PASSWORT
|
ADMIN_PASS=DEIN-SICHERES-PASSWORT
|
||||||
|
|
||||||
# Ollama KI-Modell (optional, Standard: mistral)
|
# Groq API (kostenloser Cloud-Zugang zu LLMs)
|
||||||
# OLLAMA_MODEL=mistral
|
# 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
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
updateRecipe, deleteRecipe, getCategories, getDb
|
updateRecipe, deleteRecipe, getCategories, getDb
|
||||||
} from '../db.js';
|
} from '../db.js';
|
||||||
import { getTikTokData } from '../services/tiktok.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';
|
import { trackEvent } from '../analytics-db.js';
|
||||||
|
|
||||||
const router = Router();
|
const router = Router();
|
||||||
@@ -34,8 +34,8 @@ router.get('/authors', (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
router.get('/ai-status', async (req, res) => {
|
router.get('/ai-status', async (req, res) => {
|
||||||
const available = await isOllamaAvailable();
|
const available = await isAiAvailable();
|
||||||
res.json({ ollama: available });
|
res.json({ ai: available });
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/:id', (req, res) => {
|
router.get('/:id', (req, res) => {
|
||||||
@@ -78,29 +78,29 @@ router.post('/from-tiktok', async (req, res) => {
|
|||||||
|
|
||||||
const tiktokData = await getTikTokData(url);
|
const tiktokData = await getTikTokData(url);
|
||||||
|
|
||||||
const ollamaAvailable = await isOllamaAvailable();
|
const aiAvailable = await isAiAvailable();
|
||||||
let extracted = null;
|
let extracted = null;
|
||||||
let aiStatus = ollamaAvailable ? 'available' : 'unavailable';
|
let aiStatus = aiAvailable ? 'available' : 'unavailable';
|
||||||
|
|
||||||
let aiMessage = '';
|
let aiMessage = '';
|
||||||
if (ollamaAvailable && tiktokData.title) {
|
if (aiAvailable && tiktokData.title) {
|
||||||
try {
|
try {
|
||||||
extracted = await extractRecipe(tiktokData.title);
|
extracted = await extractRecipe(tiktokData.title);
|
||||||
aiStatus = 'success';
|
aiStatus = 'success';
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Ollama Extraktion fehlgeschlagen:', e.message);
|
console.error('KI Extraktion fehlgeschlagen:', e.message);
|
||||||
aiStatus = 'error';
|
aiStatus = 'error';
|
||||||
aiMessage = e.message;
|
aiMessage = e.message;
|
||||||
}
|
}
|
||||||
} else if (!ollamaAvailable) {
|
} else if (!aiAvailable) {
|
||||||
aiMessage = 'Ollama-Server nicht erreichbar';
|
aiMessage = 'KI-Service nicht erreichbar';
|
||||||
} else if (!tiktokData.title) {
|
} else if (!tiktokData.title) {
|
||||||
aiMessage = 'Kein Titel im Video gefunden';
|
aiMessage = 'Kein Titel im Video gefunden';
|
||||||
}
|
}
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
tiktok: tiktokData,
|
tiktok: tiktokData,
|
||||||
ollama: ollamaAvailable,
|
ai: aiAvailable,
|
||||||
aiStatus,
|
aiStatus,
|
||||||
aiMessage,
|
aiMessage,
|
||||||
extracted,
|
extracted,
|
||||||
|
|||||||
@@ -1,11 +1,25 @@
|
|||||||
import { SYSTEM_PROMPT } from '../prompts/extractRecipe.js';
|
import { SYSTEM_PROMPT } from '../prompts/extractRecipe.js';
|
||||||
|
|
||||||
const OLLAMA_URL = process.env.OLLAMA_URL || 'http://localhost:11434';
|
const GROQ_API_KEY = process.env.GROQ_API_KEY;
|
||||||
const MODEL = process.env.OLLAMA_MODEL || 'mistral';
|
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 {
|
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;
|
return res.ok;
|
||||||
} catch {
|
} catch {
|
||||||
return false;
|
return false;
|
||||||
@@ -13,28 +27,31 @@ export async function isOllamaAvailable() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function extractRecipe(description) {
|
export async function extractRecipe(description) {
|
||||||
const response = await fetch(`${OLLAMA_URL}/api/generate`, {
|
const response = await fetch(GROQ_URL, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: {
|
||||||
body: JSON.stringify({
|
'Content-Type': 'application/json',
|
||||||
model: MODEL,
|
'Authorization': `Bearer ${GROQ_API_KEY}`,
|
||||||
system: SYSTEM_PROMPT,
|
|
||||||
prompt: `Extrahiere ein Rezept aus dieser TikTok-Videobeschreibung:\n\n${description}`,
|
|
||||||
stream: false,
|
|
||||||
options: {
|
|
||||||
num_ctx: 2048,
|
|
||||||
temperature: 0.1,
|
|
||||||
},
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
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) {
|
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();
|
const data = await response.json();
|
||||||
let text = data.response.trim();
|
let text = data.choices[0].message.content.trim();
|
||||||
|
|
||||||
if (text.startsWith('```')) {
|
if (text.startsWith('```')) {
|
||||||
text = text.replace(/^```(?:json)?\n?/, '').replace(/\n?```$/, '');
|
text = text.replace(/^```(?:json)?\n?/, '').replace(/\n?```$/, '');
|
||||||
|
|||||||
@@ -13,22 +13,11 @@ services:
|
|||||||
- PORT=3001
|
- PORT=3001
|
||||||
- DB_PATH=/app/data/data.json
|
- DB_PATH=/app/data/data.json
|
||||||
- ANALYTICS_PATH=/app/data/analytics.json
|
- ANALYTICS_PATH=/app/data/analytics.json
|
||||||
- OLLAMA_URL=http://ollama:11434
|
- GROQ_API_KEY=${GROQ_API_KEY}
|
||||||
- OLLAMA_MODEL=${OLLAMA_MODEL:-mistral}
|
- GROQ_MODEL=${GROQ_MODEL:-llama-3.1-8b-instant}
|
||||||
- JWT_SECRET=${JWT_SECRET}
|
- JWT_SECRET=${JWT_SECRET}
|
||||||
- ADMIN_USER=${ADMIN_USER:-admin}
|
- ADMIN_USER=${ADMIN_USER:-admin}
|
||||||
- ADMIN_PASS=${ADMIN_PASS}
|
- ADMIN_PASS=${ADMIN_PASS}
|
||||||
volumes:
|
volumes:
|
||||||
- ./data:/app/data
|
- ./data:/app/data
|
||||||
depends_on:
|
|
||||||
- ollama
|
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
ollama:
|
|
||||||
image: ollama/ollama
|
|
||||||
volumes:
|
|
||||||
- ollama_data:/root/.ollama
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
ollama_data:
|
|
||||||
|
|||||||
Reference in New Issue
Block a user