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": [