diff --git a/README.md b/README.md
index 1303b55..30c6e57 100644
--- a/README.md
+++ b/README.md
@@ -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工具的强大,也让我们明白了自己需要学习的地方还有很多,未来还需要更加努力地提升自己的技术能力。
diff --git a/note_organizer.py b/note_organizer.py
index 43e8ca6..f1d507d 100644
--- a/note_organizer.py
+++ b/note_organizer.py
@@ -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'{kw}' 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'{tag}' 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'{kw}' 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("💾 数据管理")
diff --git a/notes_data.json b/notes_data.json
index 6f5fbb7..edca3e7 100644
--- a/notes_data.json
+++ b/notes_data.json
@@ -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": [