feat: init rssKeeper - RSS 抓取、管理与检索系统
完整功能包括: - FastAPI 后端 + SQLite + FTS5 全文搜索 - RSS 源管理、自动发现、OPML 导入导出 - 文章抓取、去重、分类、全文检索 - RSS 源健康度监控 - Vue 3 + Element Plus 暗色主题 Web UI - 对外 REST API 供 AI 分析调用 - Docker + docker-compose 部署
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
"""SQLite FTS5 全文搜索封装"""
|
||||
from sqlalchemy import text
|
||||
from database import engine
|
||||
|
||||
|
||||
def search_articles(query: str, limit: int = 50, offset: int = 0):
|
||||
"""全文搜索文章
|
||||
返回 [(article_id, title, content_snippet, rank), ...]
|
||||
"""
|
||||
if not query or not query.strip():
|
||||
return [], 0
|
||||
|
||||
# 转义 FTS5 特殊字符
|
||||
query = query.replace('"', '""').strip()
|
||||
|
||||
conn = engine.raw_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
try:
|
||||
# 使用 FTS5 查询
|
||||
sql = """
|
||||
SELECT a.id, a.title, a.summary, a.link, a.published_at, a.created_at,
|
||||
f.id as feed_id, f.title as feed_title, f.category,
|
||||
rank
|
||||
FROM articles_fts
|
||||
JOIN articles a ON articles_fts.rowid = a.id
|
||||
JOIN feeds f ON a.feed_id = f.id
|
||||
WHERE articles_fts MATCH ?
|
||||
ORDER BY rank
|
||||
LIMIT ? OFFSET ?
|
||||
"""
|
||||
cursor.execute(sql, (query, limit, offset))
|
||||
rows = cursor.fetchall()
|
||||
|
||||
# 获取总数
|
||||
count_sql = """
|
||||
SELECT COUNT(*) FROM articles_fts WHERE articles_fts MATCH ?
|
||||
"""
|
||||
cursor.execute(count_sql, (query,))
|
||||
total = cursor.fetchone()[0]
|
||||
|
||||
results = []
|
||||
for row in rows:
|
||||
results.append({
|
||||
"id": row[0],
|
||||
"title": row[1],
|
||||
"summary": row[2],
|
||||
"link": row[3],
|
||||
"published_at": row[4],
|
||||
"created_at": row[5],
|
||||
"feed_id": row[6],
|
||||
"feed_title": row[7],
|
||||
"category": row[8],
|
||||
})
|
||||
|
||||
return results, total
|
||||
except Exception as e:
|
||||
# FTS5 查询失败时返回空结果
|
||||
return [], 0
|
||||
finally:
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
|
||||
def rebuild_fts_index():
|
||||
"""重建 FTS5 索引(数据不一致时使用)"""
|
||||
conn = engine.raw_connection()
|
||||
cursor = conn.cursor()
|
||||
try:
|
||||
cursor.execute("DELETE FROM articles_fts")
|
||||
cursor.execute("""
|
||||
INSERT INTO articles_fts(rowid, title, content)
|
||||
SELECT id, title, content FROM articles
|
||||
""")
|
||||
conn.commit()
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
finally:
|
||||
cursor.close()
|
||||
conn.close()
|
||||
Reference in New Issue
Block a user