200 lines
6.1 KiB
PL/PgSQL
200 lines
6.1 KiB
PL/PgSQL
-- n8n article ingestion helper and verified starter RSS sources.
|
|
-- PostgreSQL 12+. Safe to run more than once in DBeaver.
|
|
|
|
BEGIN;
|
|
|
|
CREATE OR REPLACE FUNCTION public.ingest_news_article(
|
|
p_source_id BIGINT,
|
|
p_title TEXT,
|
|
p_summary TEXT,
|
|
p_url TEXT,
|
|
p_author TEXT,
|
|
p_language_code VARCHAR,
|
|
p_region VARCHAR,
|
|
p_category VARCHAR,
|
|
p_topics JSONB,
|
|
p_keywords JSONB,
|
|
p_importance_score INTEGER,
|
|
p_published_at TIMESTAMPTZ,
|
|
p_raw_payload JSONB,
|
|
p_skip BOOLEAN DEFAULT FALSE
|
|
)
|
|
RETURNS TABLE (
|
|
report_id BIGINT,
|
|
article_id BIGINT,
|
|
report_date DATE,
|
|
item_count INTEGER
|
|
)
|
|
LANGUAGE plpgsql
|
|
AS $$
|
|
DECLARE
|
|
v_article_id BIGINT;
|
|
v_report_id BIGINT;
|
|
v_report_date DATE := (CURRENT_TIMESTAMP AT TIME ZONE 'Asia/Shanghai')::DATE;
|
|
v_item_count INTEGER;
|
|
v_topics TEXT[];
|
|
v_keywords TEXT[];
|
|
BEGIN
|
|
IF COALESCE(p_skip, FALSE) THEN
|
|
RETURN;
|
|
END IF;
|
|
|
|
IF p_source_id IS NULL OR NULLIF(BTRIM(p_title), '') IS NULL
|
|
OR NULLIF(BTRIM(p_url), '') IS NULL THEN
|
|
RETURN;
|
|
END IF;
|
|
|
|
SELECT COALESCE(ARRAY_AGG(value), ARRAY[]::TEXT[])
|
|
INTO v_topics
|
|
FROM JSONB_ARRAY_ELEMENTS_TEXT(COALESCE(p_topics, '[]'::JSONB));
|
|
|
|
SELECT COALESCE(ARRAY_AGG(value), ARRAY[]::TEXT[])
|
|
INTO v_keywords
|
|
FROM JSONB_ARRAY_ELEMENTS_TEXT(COALESCE(p_keywords, '[]'::JSONB));
|
|
|
|
INSERT INTO news_articles (
|
|
source_id, title, summary, url, author, language_code,
|
|
translation_status, region, category, topics, keywords,
|
|
importance_score, published_at, raw_payload
|
|
)
|
|
VALUES (
|
|
p_source_id,
|
|
BTRIM(p_title),
|
|
NULLIF(BTRIM(COALESCE(p_summary, '')), ''),
|
|
BTRIM(p_url),
|
|
NULLIF(BTRIM(COALESCE(p_author, '')), ''),
|
|
CASE WHEN p_language_code = 'zh' THEN 'zh' ELSE 'en' END,
|
|
CASE WHEN p_language_code = 'zh' THEN 'not_needed' ELSE 'skipped' END,
|
|
CASE WHEN p_region = 'domestic' THEN 'domestic' ELSE 'international' END,
|
|
CASE
|
|
WHEN p_category IN (
|
|
'general', 'ai_agent', 'agri_hardware',
|
|
'agri_solutions', 'agri_services', 'policy_market'
|
|
) THEN p_category
|
|
ELSE 'general'
|
|
END,
|
|
v_topics,
|
|
v_keywords,
|
|
LEAST(100, GREATEST(0, COALESCE(p_importance_score, 50))),
|
|
COALESCE(p_published_at, CURRENT_TIMESTAMP),
|
|
p_raw_payload
|
|
)
|
|
ON CONFLICT (url) DO UPDATE SET
|
|
source_id = EXCLUDED.source_id,
|
|
title = EXCLUDED.title,
|
|
summary = COALESCE(EXCLUDED.summary, news_articles.summary),
|
|
author = COALESCE(EXCLUDED.author, news_articles.author),
|
|
language_code = EXCLUDED.language_code,
|
|
region = EXCLUDED.region,
|
|
category = EXCLUDED.category,
|
|
topics = EXCLUDED.topics,
|
|
keywords = EXCLUDED.keywords,
|
|
importance_score = EXCLUDED.importance_score,
|
|
published_at = EXCLUDED.published_at,
|
|
raw_payload = EXCLUDED.raw_payload,
|
|
updated_at = CURRENT_TIMESTAMP
|
|
RETURNING id INTO v_article_id;
|
|
|
|
INSERT INTO daily_reports (
|
|
report_date, title, introduction, status, email_status
|
|
)
|
|
VALUES (
|
|
v_report_date,
|
|
'每日资讯热点 - ' || TO_CHAR(v_report_date, 'YYYY-MM-DD'),
|
|
'自动抓取的国内外 AI、Agent、智慧农业硬件、落地方案与农业服务资讯。',
|
|
'published',
|
|
'skipped'
|
|
)
|
|
ON CONFLICT (report_date) DO UPDATE SET
|
|
title = EXCLUDED.title,
|
|
introduction = EXCLUDED.introduction,
|
|
status = 'published',
|
|
updated_at = CURRENT_TIMESTAMP
|
|
RETURNING id INTO v_report_id;
|
|
|
|
INSERT INTO report_articles (
|
|
report_id, article_id, section, display_order, is_highlight
|
|
)
|
|
SELECT
|
|
v_report_id,
|
|
v_article_id,
|
|
category,
|
|
100 - importance_score,
|
|
importance_score >= 85
|
|
FROM news_articles
|
|
WHERE id = v_article_id
|
|
ON CONFLICT (report_id, article_id) DO UPDATE SET
|
|
section = EXCLUDED.section,
|
|
display_order = EXCLUDED.display_order,
|
|
is_highlight = EXCLUDED.is_highlight;
|
|
|
|
SELECT COUNT(*)::INTEGER
|
|
INTO v_item_count
|
|
FROM report_articles
|
|
WHERE report_articles.report_id = v_report_id;
|
|
|
|
UPDATE daily_reports
|
|
SET item_count = v_item_count,
|
|
updated_at = CURRENT_TIMESTAMP
|
|
WHERE id = v_report_id;
|
|
|
|
UPDATE news_sources
|
|
SET last_fetched_at = CURRENT_TIMESTAMP,
|
|
updated_at = CURRENT_TIMESTAMP
|
|
WHERE id = p_source_id;
|
|
|
|
RETURN QUERY
|
|
SELECT v_report_id, v_article_id, v_report_date, v_item_count;
|
|
END;
|
|
$$;
|
|
|
|
INSERT INTO news_sources (
|
|
name, homepage_url, feed_url, region, category, priority, enabled
|
|
)
|
|
VALUES
|
|
(
|
|
'量子位',
|
|
'https://www.qbitai.com/',
|
|
'https://www.qbitai.com/feed',
|
|
'domestic', 'ai_agent', 90, TRUE
|
|
),
|
|
(
|
|
'智慧农业(中英文)',
|
|
'https://www.smartag.net.cn/',
|
|
'https://www.smartag.net.cn/CN/rss_dqml_2096-8094.xml',
|
|
'domestic', 'agri_solutions', 88, TRUE
|
|
),
|
|
(
|
|
'Google Blog',
|
|
'https://blog.google/',
|
|
'https://blog.google/rss/',
|
|
'international', 'general', 78, TRUE
|
|
),
|
|
(
|
|
'USDA Agricultural Research Service',
|
|
'https://www.ars.usda.gov/news-events/',
|
|
'https://www.ars.usda.gov/rss/?productName=Research%20News',
|
|
'international', 'agri_solutions', 82, TRUE
|
|
),
|
|
(
|
|
'AGCO Newsroom',
|
|
'https://news.agcocorp.com/',
|
|
'https://news.agcocorp.com/news?pagetemplate=rss',
|
|
'international', 'agri_hardware', 84, TRUE
|
|
),
|
|
(
|
|
'FAO Newsroom',
|
|
'https://www.fao.org/newsroom/en',
|
|
'https://www.fao.org/feeds/fao-newsroom-rss',
|
|
'international', 'agri_services', 80, TRUE
|
|
)
|
|
ON CONFLICT (feed_url) DO UPDATE SET
|
|
name = EXCLUDED.name,
|
|
homepage_url = EXCLUDED.homepage_url,
|
|
region = EXCLUDED.region,
|
|
category = EXCLUDED.category,
|
|
priority = EXCLUDED.priority,
|
|
updated_at = CURRENT_TIMESTAMP;
|
|
|
|
COMMIT;
|