feat(note): 添加标签系统和内容提炼功能

- 实现笔记标签功能,支持添加、编辑和按标签筛选
- 新增内容提炼功能,可自动生成摘要和关键词
- 添加批量提炼功能,支持一键处理所有笔记
- 在统计面板中增加标签统计信息
- 更新笔记数据结构和UI以支持新功能
This commit is contained in:
陈宏宇 2026-01-08 15:41:08 +08:00
parent 4d36b7df93
commit ea47c7ad09
3 changed files with 165 additions and 10 deletions

View File

@ -19,3 +19,8 @@
3. 启动:`uv run streamlit run note_organizer.py`
## 四、开发心得
在开发这个学习笔记整理器的过程中,我们深刻体会到了技术与需求之间的平衡。这个项目的目的是为了帮助学生更好地管理和查询学习笔记,让学习变得更加高效有序。我们面向的主要是在校学生,他们需要记录大量的学习内容,我们希望能提供给他们一个有效的整理和检索工具。项目功能包括笔记的创建、编辑、删除、分类管理、标签系统、智能搜索、内容提炼以及导入导出等核心功能,力求为学生们提供一个简单易用的笔记管理平台。
最初我们考虑使用Chainlit框架因为它在AI交互方面表现突出但在实际开发过程中发现虽然Chainlit在对话式交互上有优势但在笔记管理功能上显得不够完善而且智能搜索的效果也没有达到预期。为了让搜索更加智能我们尝试了各种prompt设计包括语义搜索的prompt要求AI根据用户查询理解意图而非简单关键词匹配概括提取的prompt让AI对搜索结果进行智能总结和关键点提取意图识别的prompt用于判断用户是想创建、编辑还是删除笔记删除意图的prompt区分删除单个笔记、删除所有笔记还是删除某个分类的笔记以及笔记识别的prompt让AI从多个笔记中找到用户指定的目标。这些prompt设计经过多次调整包括改变temperature参数、调整max_tokens长度、优化system prompt的表述方式但效果始终不尽如人意AI经常误解用户意图或返回不相关的内容。
最终我们意识到单纯依赖AI并不能解决所有问题于是转向了更传统但更可靠的解决方案。在搜索功能上我们结合了关键词匹配和简单的语义分析虽然不如纯AI搜索那么智能但准确性和稳定性大大提升。在笔记管理方面我们采用了传统的CRUD操作配合Streamlit的交互组件让用户能够通过直观的界面进行操作而不是完全依赖自然语言交互。这种混合模式既保留了AI的辅助功能又确保了核心功能的可靠性。经过反复比较和测试最终选择了Streamlit框架它在界面设计和功能实现上更加成熟能够更好地满足我们的需求。
这次开发经历让我们对自己的技术能力有了更清晰的认识。如果没有AI的辅助我们可能根本无法独立完成这样一个项目我们在编程基础、框架使用、算法设计等方面都存在很多不足。这次经历既让我们看到了AI工具的强大也让我们明白了自己需要学习的地方还有很多未来还需要更加努力地提升自己的技术能力。

View File

@ -2,11 +2,50 @@ import streamlit as st
from datetime import datetime
import json
import os
import re
from collections import Counter
# 1. 页面配置
st.set_page_config(page_title="学习笔记整理器", page_icon="📚", layout="wide")
st.title("📚 学习笔记整理器")
# 文本提炼函数
def extract_key_content(content, max_sentences=3, max_keywords=5):
"""提炼笔记的关键内容"""
if not content or len(content.strip()) < 10:
return {"summary": "内容太短,无法提炼", "keywords": []}
# 分句
sentences = re.split(r'[。!?\n]', content)
sentences = [s.strip() for s in sentences if s.strip()]
# 提取关键句子(基于句子长度和关键词密度)
sentence_scores = []
for sentence in sentences:
score = len(sentence)
# 检查是否包含常见关键词
keywords = ['重要', '关键', '核心', '主要', '注意', '必须', '应该', '需要', '总结', '结论']
for kw in keywords:
if kw in sentence:
score += 20
sentence_scores.append((sentence, score))
# 按分数排序,取前几句
sentence_scores.sort(key=lambda x: x[1], reverse=True)
top_sentences = [s[0] for s in sentence_scores[:max_sentences]]
# 提取关键词
words = re.findall(r'[\u4e00-\u9fa5]{2,}', content)
word_freq = Counter(words)
# 过滤常见词
stop_words = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '我们', '你们', '他们']
keywords = [w for w, c in word_freq.most_common(max_keywords * 2) if w not in stop_words][:max_keywords]
return {
"summary": "".join(top_sentences) + "" if top_sentences else "无法提取摘要",
"keywords": keywords
}
# 2. 数据持久化函数
def save_notes():
"""保存笔记到 JSON 文件"""
@ -76,6 +115,25 @@ with st.sidebar:
height=200
)
# 标签输入
tags_input = st.text_input(
"标签",
placeholder="输入标签,用逗号分隔 (例如: 重要, 复习, 考试)",
help="为笔记添加多个标签,便于分类和搜索"
)
tags = [tag.strip() for tag in tags_input.split(",") if tag.strip()]
# 实时预览提炼结果
if content and len(content.strip()) > 10:
with st.expander("🔍 预览提炼结果", expanded=False):
extracted = extract_key_content(content)
st.markdown("**摘要预览:**")
st.info(extracted['summary'])
st.markdown("**关键词预览:**")
if extracted['keywords']:
keywords_html = " ".join([f'<span style="background-color: #fff3e0; color: #e65100; padding: 2px 8px; border-radius: 4px; margin-right: 5px; font-size: 12px;">{kw}</span>' for kw in extracted['keywords']])
st.markdown(keywords_html, unsafe_allow_html=True)
# 添加按钮
if st.button("添加笔记", type="primary"):
if title and content:
@ -84,6 +142,7 @@ with st.sidebar:
"title": title,
"category": category,
"content": content,
"tags": tags,
"created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"updated_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
@ -104,7 +163,7 @@ with st.sidebar:
st.header("📖 我的笔记")
# 搜索和排序区域
col1, col2, col3, col4 = st.columns([2, 1, 1, 1])
col1, col2, col3, col4, col5 = st.columns([2, 1, 1, 1, 1])
with col1:
# 搜索关键词
@ -118,7 +177,7 @@ with col2:
# 搜索范围选择
search_scope = st.selectbox(
"搜索范围",
["全部", "仅标题", "仅内容", "仅类型"],
["全部", "仅标题", "仅内容", "仅类型", "仅标签"],
help="选择搜索的范围"
)
@ -131,6 +190,15 @@ with col3:
)
with col4:
# 标签筛选
all_tags = list(set(tag for note in st.session_state.notes for tag in note.get("tags", [])))
filter_tag = st.selectbox(
"筛选标签",
["全部"] + sorted(all_tags),
help="按标签筛选笔记"
)
with col5:
# 排序方式
sort_by = st.selectbox(
"排序方式",
@ -138,6 +206,20 @@ with col4:
help="选择笔记的排序方式"
)
# 批量提炼功能
st.divider()
col_batch1, col_batch2 = st.columns([3, 1])
with col_batch1:
st.markdown("### ✨ 批量提炼")
with col_batch2:
if st.button("🔄 提炼所有笔记", key="batch_extract"):
for note in st.session_state.notes:
if len(note['content'].strip()) > 10:
extracted = extract_key_content(note['content'])
st.session_state[f'extracted_{note["id"]}'] = extracted
st.success(f"已提炼 {len(st.session_state.notes)} 条笔记的关键内容!")
st.rerun()
# 6. 显示笔记
if st.session_state.notes:
# 筛选和搜索逻辑
@ -146,6 +228,9 @@ if st.session_state.notes:
# 分类筛选
category_match = filter_category == "全部" or note["category"] == filter_category
# 标签筛选
tag_match = filter_tag == "全部" or filter_tag in note.get("tags", [])
# 关键词搜索(根据选择范围)
search_match = True
if search_query:
@ -154,7 +239,8 @@ if st.session_state.notes:
search_match = (
query in note["title"].lower() or
query in note["content"].lower() or
query in note["category"].lower()
query in note["category"].lower() or
any(query in tag.lower() for tag in note.get("tags", []))
)
elif search_scope == "仅标题":
search_match = query in note["title"].lower()
@ -162,8 +248,10 @@ if st.session_state.notes:
search_match = query in note["content"].lower()
elif search_scope == "仅类型":
search_match = query in note["category"].lower()
elif search_scope == "仅标签":
search_match = any(query in tag.lower() for tag in note.get("tags", []))
if category_match and search_match:
if category_match and tag_match and search_match:
filtered_notes.append(note)
# 排序逻辑
@ -201,6 +289,16 @@ if st.session_state.notes:
)
edit_content = st.text_area("内容", value=note['content'], height=200, key=f"edit_content_{note['id']}")
# 编辑标签
current_tags = ", ".join(note.get("tags", []))
edit_tags = st.text_input(
"标签",
value=current_tags,
key=f"edit_tags_{note['id']}",
help="输入标签,用逗号分隔"
)
edit_tags_list = [tag.strip() for tag in edit_tags.split(",") if tag.strip()]
# 保存和取消按钮
col_save, col_cancel = st.columns(2)
with col_save:
@ -208,6 +306,7 @@ if st.session_state.notes:
note['title'] = edit_title
note['category'] = edit_category
note['content'] = edit_content
note['tags'] = edit_tags_list
note['updated_at'] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
st.session_state.editing_note = None
save_notes()
@ -222,10 +321,35 @@ if st.session_state.notes:
with st.expander(f"📌 {note['title']}", expanded=False):
# 显示笔记元信息
st.markdown(f"**分类:** {note['category']}")
# 显示标签
if note.get("tags"):
tags_html = " ".join([f'<span style="background-color: #e1f5fe; color: #01579b; padding: 2px 8px; border-radius: 4px; margin-right: 5px; font-size: 12px;">{tag}</span>' for tag in note["tags"]])
st.markdown(f"**标签:** {tags_html}", unsafe_allow_html=True)
st.markdown(f"**创建时间:** {note['created_at']}")
if 'updated_at' in note:
st.markdown(f"**更新时间:** {note['updated_at']}")
st.markdown("---")
# 提炼内容按钮
if st.button("✨ 提炼内容", key=f"extract_{note['id']}"):
extracted = extract_key_content(note['content'])
st.session_state[f'extracted_{note["id"]}'] = extracted
# 显示提炼结果
if f'extracted_{note["id"]}' in st.session_state:
extracted = st.session_state[f'extracted_{note["id"]}']
with st.expander("📝 提炼结果", expanded=True):
st.markdown("**摘要:**")
st.info(extracted['summary'])
st.markdown("**关键词:**")
if extracted['keywords']:
keywords_html = " ".join([f'<span style="background-color: #fff3e0; color: #e65100; padding: 2px 8px; border-radius: 4px; margin-right: 5px; font-size: 12px;">{kw}</span>' for kw in extracted['keywords']])
st.markdown(keywords_html, unsafe_allow_html=True)
else:
st.warning("未找到关键词")
# 显示笔记内容
st.markdown(note['content'])
@ -250,17 +374,33 @@ else:
st.divider()
st.subheader("📊 统计信息")
# 动态生成统计列
stat_cols = st.columns(min(5, len(st.session_state.categories) + 1))
with stat_cols[0]:
# 笔记和分类统计
col_stats1, col_stats2 = st.columns(2)
with col_stats1:
st.metric("总笔记数", len(st.session_state.notes))
with col_stats2:
all_tags = list(set(tag for note in st.session_state.notes for tag in note.get("tags", [])))
st.metric("总标签数", len(all_tags))
# 分类统计
st.markdown("### 分类统计")
cat_stat_cols = st.columns(min(5, len(st.session_state.categories)))
for i, cat in enumerate(st.session_state.categories):
if i + 1 < len(stat_cols):
with stat_cols[i + 1]:
if i < len(cat_stat_cols):
with cat_stat_cols[i]:
count = len([n for n in st.session_state.notes if n["category"] == cat])
st.metric(cat, count)
# 标签统计
if all_tags:
st.markdown("### 标签统计")
tag_stat_cols = st.columns(min(5, len(all_tags)))
for i, tag in enumerate(sorted(all_tags)):
if i < len(tag_stat_cols):
with tag_stat_cols[i]:
count = len([n for n in st.session_state.notes if tag in n.get("tags", [])])
st.metric(tag, count)
# 8. 数据管理
st.divider()
st.subheader("💾 数据管理")

View File

@ -6,7 +6,8 @@
"category": "语文",
"content": "李白的《静夜思》表达了思乡之情,意境深远。",
"created_at": "",
"updated_at": ""
"updated_at": "2026-01-08 15:28:37",
"tags": []
},
{
"id": 2,
@ -95,6 +96,15 @@
"content": "look forward to意为期待、盼望后接名词或动名词。",
"created_at": "",
"updated_at": ""
},
{
"id": 13,
"title": "中国古典诗词艺术",
"category": "语文",
"content": "中国古典诗词是中华文化的瑰宝,承载着数千年的历史与智慧。从《诗经》的质朴纯真,到唐诗的辉煌灿烂,再到宋词的婉约豪放,诗词艺术在中国文学史上占据着极其重要的地位。\n\n诗歌的起源可以追溯到远古时期先民们在劳动和生活中创造了最初的歌谣。这些歌谣经过长期的传承和演变逐渐形成了具有固定格式的诗歌。《诗经》是中国最早的诗歌总集收录了从西周初期到春秋中叶的305篇诗歌分为风、雅、颂三个部分。《诗经》中的诗歌以四言为主运用了赋、比、兴的表现手法开创了中国诗歌的现实主义传统。\n\n汉代乐府诗继承了《诗经》的现实主义精神反映了当时的社会生活和人民的思想感情。《古诗十九首》是汉代文人五言诗的代表作语言质朴自然情感真挚深沉被誉为\"五言之冠冕\"。这些诗歌为后来诗歌的发展奠定了坚实的基础。\n\n唐代是中国诗歌发展的黄金时代涌现出了李白、杜甫、白居易等一大批杰出的诗人。李白的诗歌豪放飘逸想象奇特充满了浪漫主义色彩。他的《将进酒》\"君不见黄河之水天上来,奔流到海不复回\"气势磅礴,展现了他豪迈不羁的性格。杜甫的诗歌沉郁顿挫,关注民生疾苦,被称为\"诗圣\"。他的《春望》\"国破山河在,城春草木深\"表达了对国家命运的忧虑。白居易的诗歌通俗易懂,关注社会现实,他的《长恨歌》\"在天愿作比翼鸟,在地愿为连理枝\"传唱千古。\n\n宋词是中国诗歌的另一种重要形式分为豪放派和婉约派两大流派。苏轼是豪放派的代表人物他的词作气势磅礴意境开阔。他的《念奴娇·赤壁怀古》\"大江东去,浪淘尽,千古风流人物\"展现了豪迈的气概。李清照是婉约派的代表人物,她的词作细腻婉约,情感真挚。她的《声声慢》\"寻寻觅觅,冷冷清清,凄凄惨惨戚戚\"表达了她内心的愁苦。\n\n中国古典诗词的艺术特色主要体现在以下几个方面一是意境深远诗人通过生动的意象和精妙的语言营造出深远的艺术境界二是语言精炼诗词要求字斟句酌每一个字都要发挥最大的表现力三是韵律优美诗词讲究平仄和对仗读起来朗朗上口四是情感真挚诗人将自己的真情实感融入诗中使读者产生共鸣。\n\n诗歌的创作技巧丰富多彩包括比喻、拟人、夸张、对偶、排比等多种修辞手法。比喻可以使抽象的事物变得具体形象如\"问君能有几多愁,恰似一江春水向东流\"。拟人可以使事物具有人的情感和动作,如\"感时花溅泪,恨别鸟惊心\"。夸张可以突出事物的特征,如\"飞流直下三千尺,疑是银河落九天\"。对偶可以使诗歌更加工整优美,如\"两个黄鹂鸣翠柳,一行白鹭上青天\"。\n\n中国古典诗词蕴含着深刻的思想内涵。许多诗歌表达了诗人对国家和人民的关怀如杜甫的\"安得广厦千万间,大庇天下寒士俱欢颜\"。有些诗歌表达了诗人对人生的感悟,如苏轼的\"人有悲欢离合,月有阴晴圆缺,此事古难全\"。还有些诗歌表达了诗人对自然的热爱,如王维的\"空山新雨后,天气晚来秋\"。\n\n学习古典诗词不仅可以提高我们的文学素养还可以陶冶我们的情操丰富我们的精神世界。通过阅读和欣赏古典诗词我们可以感受到古人的智慧和情感体会到中华文化的博大精深。古典诗词是我们民族的精神财富值得我们认真学习和传承。\n\n在现代社会古典诗词依然具有重要的意义。它可以帮助我们更好地理解传统文化增强文化自信。它可以提高我们的审美能力和语言表达能力。它还可以帮助我们缓解压力陶冶情操。因此我们应该重视古典诗词的学习和传承让这一优秀的文化遗产在新时代焕发出新的光彩。",
"created_at": "2026-01-08 16:00:00",
"updated_at": "2026-01-08 16:00:00",
"tags": ["诗词", "文学", "文化", "艺术", "经典"]
}
],
"categories": [