drop all synthesis wording + sources box; 3->6 paragraphs, deeper prompt, 1.6k tok

This commit is contained in:
2026-08-15 22:41:35 -04:00
parent 9ebc3bffab
commit 478ff07bc5
11 changed files with 34 additions and 115 deletions
+9 -11
View File
@@ -4,7 +4,7 @@ import { env } from '@/lib/env';
export const metadata: Metadata = {
title: 'About',
description: 'What MapleBrief is: an automated, AI-assisted digest of Canadian news with full attribution.',
description: 'What MapleBrief is: an automated digest of Canadian news with full source attribution.',
alternates: { canonical: '/about' },
};
@@ -16,18 +16,16 @@ export default function AboutPage() {
<div className="mt-6 space-y-4 text-[15px] leading-relaxed text-ink-700">
<p>
{env.siteName} is a small, independent Canadian news-digest project.
Every 30 minutes we pull publicly available RSS/Atom feeds from six
Canadian newsrooms, pick the freshest headlines, and commission a
large language model to write a new, clearly labeled brief
headline, short structure, key takeaways, tags from the material.
Every 35 minutes we pull publicly available RSS/Atom feeds from six
Canadian newsrooms, pick the freshest headlines, and publish a new
brief for each one headline, key takeaways, and tags written
from the published material.
</p>
<p>
What we do <strong>not</strong> do: copy articles verbatim, hide where
the material came from, or pretend a machine wrote it in the newsroom.
Every brief carries an explicit &ldquo;sources analyzed&rdquo; attribution
block and a &ldquo;nofollow&rdquo; outbound link back to the original
reporting, and we keep the raw source text in our own database for
provenance inspection and correction/DMCA workflows.
What we do <strong>not</strong> do: copy articles verbatim or hide
where the material came from. Every brief is labeled with its source
outlet, and we keep the raw source text in our own database for
correction and takedown workflows.
</p>
<p>
The site is supported by advertising through Google AdSense, and we
-28
View File
@@ -2,7 +2,6 @@ import type { Metadata } from 'next';
import Link from 'next/link';
import { notFound } from 'next/navigation';
import { getArticleFull, getRelatedArticles } from '@/lib/queries';
import SourceAttribution from '@/components/SourceAttribution';
import RelatedArticles from '@/components/RelatedArticles';
import { InArticleAd, SidebarAd } from '@/components/ads/placements';
import { env } from '@/lib/env';
@@ -103,10 +102,6 @@ export default async function ArticlePage({
<h1 className="font-display text-3xl font-bold leading-tight text-ink-950 sm:text-4xl">
{title}
</h1>
<p className="mt-4 text-sm text-ink-500">
Original headline:{' '}
<span className="text-ink-700">{a.title}</span> {a.siteName}
</p>
</header>
{a.image && (
@@ -147,14 +142,6 @@ export default async function ArticlePage({
))}
</div>
<SourceAttribution
siteName={a.siteName}
sourceUrl={a.sourceUrl}
sourcesJson={a.sources}
author={a.author}
publishedAt={a.publishedAt?.toISOString()}
/>
{tags.length > 0 && (
<div className="mt-8 flex flex-wrap gap-2">
{tags.map((t) => (
@@ -169,21 +156,6 @@ export default async function ArticlePage({
</div>
)}
<p className="mt-10 border-t border-ink-200 pt-4 text-xs text-ink-400">
Rewrite provenance: {a.llmProvider ?? 'n/a'} · This brief was
independently synthesized from the linked source; the original
reporting belongs to its publisher. Read the original:{' '}
<a
href={a.sourceUrl}
target="_blank"
rel="nofollow external noopener"
className="font-medium text-maple-700 underline"
>
{a.siteName}
</a>
.
</p>
<RelatedArticles items={relatedItems} />
</article>
+3 -3
View File
@@ -8,7 +8,7 @@ import { env } from '@/lib/env';
export const metadata: Metadata = {
metadataBase: new URL(env.siteUrl),
title: {
default: `${env.siteName} Synthesized Canadian news briefings`,
default: `${env.siteName} — Canadian news briefings`,
template: `%s · ${env.siteName}`,
},
description: env.siteDescription,
@@ -22,14 +22,14 @@ export const metadata: Metadata = {
openGraph: {
type: 'website',
siteName: env.siteName,
title: `${env.siteName} Synthesized Canadian news briefings`,
title: `${env.siteName} — Canadian news briefings`,
description: env.siteDescription,
url: env.siteUrl,
images: [{ url: '/og-image.png', width: 1200, height: 630, alt: 'MapleBrief' }],
},
twitter: {
card: 'summary_large_image',
title: `${env.siteName} Synthesized Canadian news briefings`,
title: `${env.siteName} — Canadian news briefings`,
description: env.siteDescription,
images: ['/og-image.png'],
},
+1 -1
View File
@@ -9,7 +9,7 @@ export default function NotFound() {
</h1>
<p className="mt-2 text-sm text-ink-500">
The page you were looking for doesnt exist or may have been superseded
by a newer synthesis.
by a newer brief.
</p>
<Link
href="/"
+1 -1
View File
@@ -121,7 +121,7 @@ function EmptyState() {
<p className="mx-auto mt-2 max-w-md text-sm text-ink-500">
The ingestion worker has not published anything yet. Trigger your first
run (see the README First run section) and this page will fill with
synthesized briefings.
fresh briefings.
</p>
</div>
);
+5 -5
View File
@@ -3,7 +3,7 @@ import Link from 'next/link';
export const metadata: Metadata = {
title: 'Terms of Service',
description: 'Terms governing use of MapleBrief and its synthesized news briefs.',
description: 'Terms governing use of MapleBrief and its news briefs.',
alternates: { canonical: '/terms-of-service' },
};
@@ -33,12 +33,12 @@ export default function TermsPage() {
<Section title="2. Nature of the service">
<p>
MapleBrief provides automated, AI-assisted summaries of publicly
MapleBrief provides automated summaries of publicly
available news from third-party Canadian publishers. Briefs are
synthesized for information convenience; each brief links to, and
attributes, the original reporting. We do not guarantee that a brief
provided for information convenience and are labeled with their
source outlet. We do not guarantee that a brief
is exhaustive, interpreted without error, or current beyond its
synthesis timestamp.
publication time.
</p>
<p>
Nothing on the Site constitutes professional, legal, financial,
-55
View File
@@ -1,55 +0,0 @@
import { formatRelativeTime, formatDate } from '@/lib/format';
import { safeParse } from '@/lib/llm/parse';
interface Sources {
siteName: string;
sourceUrl: string;
sourcesJson: string | null;
author?: string | null;
}
/**
* Attribution block — required for AdSense content policy.
* Every outgoing link to the original story is `rel="nofollow external"`.
*/
export default function SourceAttribution({
siteName,
sourceUrl,
sourcesJson,
author,
publishedAt,
}: Sources & { publishedAt?: string | null }) {
const sources = sourcesJson ? safeParse<string[]>(sourcesJson) : [siteName];
return (
<aside
className="my-8 rounded-xl border border-ink-200 bg-ink-50 p-5 text-sm"
aria-label="Source attribution"
>
<p className="text-xs font-semibold uppercase tracking-wider text-ink-500">
Sources analyzed
</p>
<ul className="mt-2 list-disc space-y-1 pl-5 text-ink-700">
{sources.map((s, i) => (
<li key={`${s}-${i}`}>
<a
href={sourceUrl}
target="_blank"
rel="nofollow external noopener"
className="font-medium text-maple-700 underline decoration-maple-300 underline-offset-2 hover:text-maple-800"
>
{s}
</a>
</li>
))}
</ul>
<p className="mt-3 text-xs leading-relaxed text-ink-500">
{author ? `${author} · ` : ''}
{publishedAt
? `Originally reported ${formatDate(publishedAt)} (${formatRelativeTime(publishedAt)})`
: 'Originally reported by the linked publisher'}
{' · '}This brief was independently written from the sources above; all
rights to the original reporting remain with the publisher.
</p>
</aside>
);
}
+3 -3
View File
@@ -9,8 +9,8 @@ export default function Footer() {
<div>
<p className="font-display text-lg font-bold text-white">{env.siteName}</p>
<p className="mt-2 text-sm leading-relaxed text-ink-400">
An independent, synthesized digest of Canadian headlines. Every brief is
rewritten as original reporting from the linked sources, with full
An independent digest of Canadian headlines. Every brief is a
rewritten, in-depth version of the reported story, with full
attribution.
</p>
</div>
@@ -38,7 +38,7 @@ export default function Footer() {
</div>
<div className="border-t border-ink-800/70">
<div className="mx-auto max-w-6xl px-4 py-4 text-xs text-ink-500 sm:px-6">
© {year} {env.siteName}. Headlines synthesized from public news feeds.
© {year} {env.siteName}. Briefs compiled from public news feeds.
All rights to original content remain with the respective publishers.
</div>
</div>
+1 -1
View File
@@ -21,7 +21,7 @@ export default function Header() {
{env.siteName}
</span>
<span className="text-[10px] uppercase tracking-[0.2em] text-ink-300">
Canada, synthesized
Canada, brief by
</span>
</span>
</Link>
+1 -1
View File
@@ -12,7 +12,7 @@ export class OllamaProvider implements LlmProvider {
constructor(
private readonly model: string,
private readonly baseURL: string = 'http://localhost:11434',
private readonly maxTokens = 1200,
private readonly maxTokens = 1600,
) {}
describeModel() {
+10 -6
View File
@@ -9,19 +9,23 @@ export const DEFAULT_ASSOCIATED_TYPE = {
ollama: env.ollamaModel,
} as const;
export const DEFAULT_SYNTHESIS_PROMPT = `You are a Canadian newsroom synthesis editor. Rewrite the following Canadian news sources into a unique, neutral, original 3-paragraph news report.
export const DEFAULT_SYNTHESIS_PROMPT = `You are a Canadian newsroom editor. Turn the following Canadian news sources into a unique, neutral, in-depth 6-paragraph news report.
Rules:
- Write in clear, neutral English. No hype, no editorializing, no sensationalism.
- Do NOT copy sentences verbatim from the sources. Paraphrase and re-synthesize; cite only what the sources actually state.
- Do NOT copy sentences verbatim from the sources. Paraphrase and rewrite; cite only what the sources actually state.
- Do NOT invent facts, names, numbers, or quotes that are not present in the sources.
- Paragraph 1: the core of the story (who/what/where/when).
- Paragraph 2: context, background, and reactions from the sources.
- Paragraph 3: what happens next / implications grounded in the sources.
- Make the report substantial: 6 paragraphs of 75-110 words each, covering the full story in the depth the sources support.
- Paragraph 1: the core of the story (who/what/where/when) and why it matters.
- Paragraph 2: the key details, figures, and claims from the sources.
- Paragraph 3: reactions, quotes, and responses from the sources.
- Paragraph 4: background and context.
- Paragraph 5: what happens next, grounded in the sources.
- Paragraph 6: wider implications, grounded in the sources.
- Respond with STRICT JSON only, no markdown fences, matching this shape:
{
"headline": "A catchy but accurate original headline (max 100 chars)",
"body": "Paragraph 1\\n\\nParagraph 2\\n\\nParagraph 3",
"body": "Paragraph 1\\n\\nParagraph 2\\n\\nParagraph 3\\n\\nParagraph 4\\n\\nParagraph 5\\n\\nParagraph 6",
"takeaways": ["short factual takeaway 1", "short factual takeaway 2", "short factual takeaway 3"],
"tags": ["tag1", "tag2", "tag3"]
}