[update] added validation for article data in NewsList.vue, removed unused Cypress config, expanded LLM models in example.env, adjusted context size and max article length in backend configuration, and updated workspace naming in yarn.lock

This commit is contained in:
2025-08-07 13:15:40 +02:00
parent 338b3ac7c1
commit 0a97a57c76
7 changed files with 112 additions and 86 deletions

View File

@@ -8,11 +8,11 @@ MIN_CRON_HOURS = float(os.getenv("MIN_CRON_HOURS", 0.5))
DEFAULT_CRON_HOURS = float(os.getenv("CRON_HOURS", MIN_CRON_HOURS)) DEFAULT_CRON_HOURS = float(os.getenv("CRON_HOURS", MIN_CRON_HOURS))
CRON_HOURS = max(MIN_CRON_HOURS, DEFAULT_CRON_HOURS) CRON_HOURS = max(MIN_CRON_HOURS, DEFAULT_CRON_HOURS)
SYNC_COOLDOWN_MINUTES = int(os.getenv("SYNC_COOLDOWN_MINUTES", 30)) SYNC_COOLDOWN_MINUTES = int(os.getenv("SYNC_COOLDOWN_MINUTES", 30))
LLM_MODEL = os.getenv("LLM_MODEL", "mistral-nemo:12b") LLM_MODEL = os.getenv("LLM_MODEL", "phi3:3.8b-mini-128k-instruct-q4_0")
LLM_TIMEOUT_SECONDS = int(os.getenv("LLM_TIMEOUT_SECONDS", 180)) LLM_TIMEOUT_SECONDS = int(os.getenv("LLM_TIMEOUT_SECONDS", 180))
OLLAMA_API_TIMEOUT_SECONDS = int(os.getenv("OLLAMA_API_TIMEOUT_SECONDS", 10)) OLLAMA_API_TIMEOUT_SECONDS = int(os.getenv("OLLAMA_API_TIMEOUT_SECONDS", 10))
ARTICLE_FETCH_TIMEOUT = int(os.getenv("ARTICLE_FETCH_TIMEOUT", 30)) ARTICLE_FETCH_TIMEOUT = int(os.getenv("ARTICLE_FETCH_TIMEOUT", 30))
MAX_ARTICLE_LENGTH = int(os.getenv("MAX_ARTICLE_LENGTH", 10_000)) MAX_ARTICLE_LENGTH = int(os.getenv("MAX_ARTICLE_LENGTH", 40_000))
frontend_path = os.path.join( frontend_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(__file__))), os.path.dirname(os.path.dirname(os.path.dirname(__file__))),

View File

@@ -209,7 +209,7 @@ class NewsFetcher:
"format": "json", "format": "json",
"options": { "options": {
"num_gpu": 1, # Force GPU usage "num_gpu": 1, # Force GPU usage
"num_ctx": 128_000, # Context size "num_ctx": 64_000, # Context size
} }
} }

View File

@@ -11,10 +11,11 @@ MIN_CRON_HOURS=0.5
SYNC_COOLDOWN_MINUTES=30 SYNC_COOLDOWN_MINUTES=30
# LLM model to use for summarization # LLM model to use for summarization
LLM_MODEL=qwen2:7b-instruct-q4_K_M LLM_MODEL=qwen2:7b-instruct-q4_K_M # ca 7-9GB (typisch 8GB)
LLM_MODEL=phi3:3.8b-mini-128k-instruct-q4_0 LLM_MODEL=phi3:3.8b-mini-128k-instruct-q4_0 # ca 6-8GB (langer kontext)
LLM_MODEL=mistral-nemo:12b LLM_MODEL=mistral-nemo:12b # ca 16-24+GB
LLM_MODEL=cnjack/mistral-samll-3.1:24b-it-q4_K_S LLM_MODEL=cnjack/mistral-samll-3.1:24b-it-q4_K_S # ca 22GB
LLM_MODEL=yarn-mistral:7b-64k-q4_K_M # ca 11GB
# Timeout in seconds for LLM requests # Timeout in seconds for LLM requests
LLM_TIMEOUT_SECONDS=180 LLM_TIMEOUT_SECONDS=180

Binary file not shown.

View File

@@ -1,8 +0,0 @@
import { defineConfig } from 'cypress'
export default defineConfig({
e2e: {
specPattern: 'cypress/e2e/**/*.{cy,spec}.{js,jsx,ts,tsx}',
baseUrl: 'http://localhost:4173',
},
})

View File

@@ -14,9 +14,10 @@
<!-- Articles Grid --> <!-- Articles Grid -->
<div v-else class="grid gap-4 sm:gap-6 md:grid-cols-2 xl:grid-cols-3"> <div v-else class="grid gap-4 sm:gap-6 md:grid-cols-2 xl:grid-cols-3">
<template v-for="article in news.articles"
:key="article.id">
<article <article
v-for="article in news.articles" v-if="isValidArticleContent(article)"
:key="article.id"
class="flex flex-col h-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 hover:shadow-md dark:hover:shadow-lg dark:hover:shadow-gray-800/50 transition-all duration-200 overflow-hidden group" class="flex flex-col h-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 hover:shadow-md dark:hover:shadow-lg dark:hover:shadow-gray-800/50 transition-all duration-200 overflow-hidden group"
> >
<!-- Article Header --> <!-- Article Header -->
@@ -28,7 +29,7 @@
</span> </span>
<time <time
:datetime="new Date(article.published * 1000).toISOString()" :datetime="new Date(article.published * 1000).toISOString()"
:title="new Date(article.published * 1000).toLocaleString(userLocale.value, { :title="new Date(article.published * 1000).toLocaleString(userLocale, {
dateStyle: 'full', dateStyle: 'full',
timeStyle: 'long' timeStyle: 'long'
})" })"
@@ -83,6 +84,7 @@
</a> </a>
</div> </div>
</article> </article>
</template>
</div> </div>
<!-- Loading State & Load More Trigger --> <!-- Loading State & Load More Trigger -->
@@ -129,6 +131,37 @@ const loadMoreArticles = async () => {
} }
}; };
interface Article {
id: number;
title: string;
summary: string;
url: string;
published: number;
country: string;
created_at: number;
}
const INVALID_MARKERS = ['---', '...', '…', 'Title', 'Summary', 'Titel', 'Zusammenfassung'] as const;
const REQUIRED_TEXT_FIELDS = ['title', 'summary', 'url'] as const;
const isValidArticleContent = (article: Article): boolean => {
const hasEmptyRequiredFields = REQUIRED_TEXT_FIELDS.some(
field => article[field as keyof Pick<Article, typeof REQUIRED_TEXT_FIELDS[number]>].length === 0
);
if (hasEmptyRequiredFields) {
return false;
}
const hasInvalidMarkers = REQUIRED_TEXT_FIELDS.some(field =>
INVALID_MARKERS.some(marker =>
article[field as keyof Pick<Article, typeof REQUIRED_TEXT_FIELDS[number]>].includes(marker)
)
);
return !hasInvalidMarkers;
};
const observer = ref<IntersectionObserver | null>(null); const observer = ref<IntersectionObserver | null>(null);
const loadMoreTrigger = ref<HTMLElement | null>(null); const loadMoreTrigger = ref<HTMLElement | null>(null);

View File

@@ -6470,9 +6470,9 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"owly-news-summariser@workspace:.": "owly-news@workspace:.":
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "owly-news-summariser@workspace:." resolution: "owly-news@workspace:."
dependencies: dependencies:
"@tailwindcss/vite": "npm:^4.1.11" "@tailwindcss/vite": "npm:^4.1.11"
"@tsconfig/node22": "npm:^22.0.2" "@tsconfig/node22": "npm:^22.0.2"