docs: 更新README和笔记数据文件
更新README.md中的开发心得部分,添加了关于AI学习报告功能的描述并优化了段落结构。同时调整notes_data.json中的标签和分类格式,添加新分类"1"。
This commit is contained in:
parent
c3d78266c7
commit
da1a41cdad
@ -20,9 +20,11 @@
|
|||||||
|
|
||||||
## 四、开发心得
|
## 四、开发心得
|
||||||
|
|
||||||
在开发这个学习笔记整理器的过程中,我们深刻体会到了技术与需求之间的平衡。这个项目的目的是为了帮助学生更好地管理和查询学习笔记,让学习变得更加高效有序。我们面向的主要是在校学生,他们需要记录大量的学习内容,我们希望能提供给他们一个有效的整理和检索工具。项目功能包括笔记的创建、编辑、删除、分类管理、标签系统、智能搜索、内容提炼以及导入导出等核心功能,力求为学生们提供一个简单易用的笔记管理平台。
|
在开发这个学习笔记整理器的过程中,我们深刻体会到了技术与需求之间的平衡。这个项目的目的是为了帮助学生更好地管理和查询学习笔记,让学习变得更加高效有序。我们面向的主要是在校学生,他们需要记录大量的学习内容,我们希望能提供给他们一个有效的整理和检索工具。项目功能包括笔记的创建、编辑、删除、分类管理、标签系统、智能搜索、内容提炼以及导入导出等核心功能,同时也利用ai为项目增加了一个“ai学习报告”的功能,力求为学生们提供一个简单易用的笔记管理平台。
|
||||||
|
|
||||||
最初我们考虑使用Chainlit框架,因为它在AI交互方面表现突出,但在实际开发过程中发现,虽然Chainlit在对话式交互上有优势,但在笔记管理功能上显得不够完善,而且智能搜索的效果也没有达到预期。为了让搜索更加智能,我们尝试了各种prompt设计,包括语义搜索的prompt,要求AI根据用户查询理解意图而非简单关键词匹配;概括提取的prompt,让AI对搜索结果进行智能总结和关键点提取;意图识别的prompt,用于判断用户是想创建、编辑还是删除笔记;删除意图的prompt,区分删除单个笔记、删除所有笔记还是删除某个分类的笔记;以及笔记识别的prompt,让AI从多个笔记中找到用户指定的目标。这些prompt设计经过多次调整,包括改变temperature参数、调整max_tokens长度、优化system prompt的表述方式,但效果始终不尽如人意,AI经常误解用户意图或返回不相关的内容。
|
最初我们考虑使用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搜索那么智能,但准确性和稳定性大大提升。在笔记管理方面,我们采用了传统的CRUD操作配合Streamlit的交互组件,让用户能够通过直观的界面进行操作,而不是完全依赖自然语言交互。这种混合模式既保留了AI的辅助功能,又确保了核心功能的可靠性。经过反复比较和测试,最终选择了Streamlit框架,它在界面设计和功能实现上更加成熟,能够更好地满足我们的需求。
|
||||||
|
|
||||||
|
|||||||
@ -4,10 +4,46 @@ import json
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
|
import requests
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
# 1. 页面配置
|
# 1. 页面配置
|
||||||
st.set_page_config(page_title="学习笔记整理器", page_icon="📚", layout="wide")
|
st.set_page_config(page_title="学习笔记整理器", page_icon="📚", layout="wide")
|
||||||
|
|
||||||
|
# 加载环境变量
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
# DeepSeek API配置
|
||||||
|
DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY")
|
||||||
|
DEEPSEEK_API_URL = "https://api.deepseek.com/v1/chat/completions"
|
||||||
|
|
||||||
|
# 常量定义
|
||||||
|
DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
|
||||||
|
|
||||||
|
def call_deepseek_api(messages, model="deepseek-chat", temperature=0.7, max_tokens=2000):
|
||||||
|
"""调用DeepSeek API"""
|
||||||
|
try:
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": f"Bearer {DEEPSEEK_API_KEY}"
|
||||||
|
}
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
"model": model,
|
||||||
|
"messages": messages,
|
||||||
|
"temperature": temperature,
|
||||||
|
"max_tokens": max_tokens
|
||||||
|
}
|
||||||
|
|
||||||
|
response = requests.post(DEEPSEEK_API_URL, headers=headers, json=payload, timeout=30)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
result = response.json()
|
||||||
|
return result["choices"][0]["message"]["content"]
|
||||||
|
except Exception as e:
|
||||||
|
st.error(f"AI API调用失败: {str(e)}")
|
||||||
|
return None
|
||||||
|
|
||||||
# 添加自定义CSS样式
|
# 添加自定义CSS样式
|
||||||
st.markdown("""
|
st.markdown("""
|
||||||
<style>
|
<style>
|
||||||
@ -151,6 +187,9 @@ st.markdown("""
|
|||||||
|
|
||||||
st.title("📚 学习笔记整理器")
|
st.title("📚 学习笔记整理器")
|
||||||
|
|
||||||
|
# 创建主标签页
|
||||||
|
tab_notes, tab_report = st.tabs(["📝 笔记管理", "🤖 AI学习报告"])
|
||||||
|
|
||||||
# 文本提炼函数
|
# 文本提炼函数
|
||||||
def extract_key_content(content, max_sentences=3, max_keywords=5):
|
def extract_key_content(content, max_sentences=3, max_keywords=5):
|
||||||
"""提炼笔记的关键内容"""
|
"""提炼笔记的关键内容"""
|
||||||
@ -188,6 +227,170 @@ def extract_key_content(content, max_sentences=3, max_keywords=5):
|
|||||||
"keywords": keywords
|
"keywords": keywords
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 辅助函数:获取所有标签
|
||||||
|
def get_all_tags():
|
||||||
|
"""获取所有笔记中的标签"""
|
||||||
|
return list(set(tag for note in st.session_state.notes for tag in note.get("tags", [])))
|
||||||
|
|
||||||
|
# 辅助函数:筛选笔记
|
||||||
|
def filter_notes(notes, search_query="", search_scope="全部", filter_category="全部", filter_tag="全部"):
|
||||||
|
"""根据条件筛选笔记"""
|
||||||
|
filtered = []
|
||||||
|
for note in 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:
|
||||||
|
query = search_query.lower()
|
||||||
|
if search_scope == "全部":
|
||||||
|
search_match = (
|
||||||
|
query in note["title"].lower() or
|
||||||
|
query in note["content"].lower() or
|
||||||
|
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()
|
||||||
|
elif search_scope == "仅内容":
|
||||||
|
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 tag_match and search_match:
|
||||||
|
filtered.append(note)
|
||||||
|
|
||||||
|
return filtered
|
||||||
|
|
||||||
|
# 辅助函数:格式化标签HTML
|
||||||
|
def format_tags_html(tags, style="default"):
|
||||||
|
"""格式化标签为HTML"""
|
||||||
|
if style == "default":
|
||||||
|
return " ".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 tags])
|
||||||
|
elif style == "preview":
|
||||||
|
return " ".join([f'<span style="background-color: #fff3e0; color: #e65100; padding: 2px 8px; border-radius: 4px; margin-right: 5px; font-size: 12px;">{tag}</span>' for tag in tags])
|
||||||
|
return ""
|
||||||
|
|
||||||
|
# 辅助函数:排序笔记
|
||||||
|
def sort_notes(notes, sort_by="最新"):
|
||||||
|
"""根据指定方式排序笔记"""
|
||||||
|
sorted_notes = notes.copy()
|
||||||
|
if sort_by == "最新":
|
||||||
|
sorted_notes.sort(key=lambda x: x["created_at"], reverse=True)
|
||||||
|
elif sort_by == "最旧":
|
||||||
|
sorted_notes.sort(key=lambda x: x["created_at"])
|
||||||
|
elif sort_by == "标题A-Z":
|
||||||
|
sorted_notes.sort(key=lambda x: x["title"].lower())
|
||||||
|
elif sort_by == "标题Z-A":
|
||||||
|
sorted_notes.sort(key=lambda x: x["title"].lower(), reverse=True)
|
||||||
|
elif sort_by == "类型A-Z":
|
||||||
|
sorted_notes.sort(key=lambda x: x["category"].lower())
|
||||||
|
elif sort_by == "类型Z-A":
|
||||||
|
sorted_notes.sort(key=lambda x: x["category"].lower(), reverse=True)
|
||||||
|
return sorted_notes
|
||||||
|
|
||||||
|
# AI学习报告生成函数
|
||||||
|
def generate_study_report(notes):
|
||||||
|
"""生成AI学习报告"""
|
||||||
|
if not notes:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 统计分析
|
||||||
|
total_notes = len(notes)
|
||||||
|
categories = {}
|
||||||
|
all_tags = []
|
||||||
|
total_content_length = 0
|
||||||
|
notes_summary = []
|
||||||
|
|
||||||
|
for note in notes:
|
||||||
|
# 分类统计
|
||||||
|
cat = note['category']
|
||||||
|
categories[cat] = categories.get(cat, 0) + 1
|
||||||
|
|
||||||
|
# 标签统计
|
||||||
|
all_tags.extend(note.get('tags', []))
|
||||||
|
|
||||||
|
# 内容长度统计
|
||||||
|
total_content_length += len(note['content'])
|
||||||
|
|
||||||
|
# 收集笔记摘要(用于AI分析)
|
||||||
|
notes_summary.append({
|
||||||
|
"title": note['title'],
|
||||||
|
"category": note['category'],
|
||||||
|
"tags": note.get('tags', []),
|
||||||
|
"content_length": len(note['content']),
|
||||||
|
"created_at": note.get('created_at', '')
|
||||||
|
})
|
||||||
|
|
||||||
|
# 标签频率统计
|
||||||
|
tag_counts = Counter(all_tags)
|
||||||
|
top_tags = tag_counts.most_common(10)
|
||||||
|
|
||||||
|
# 使用DeepSeek API生成智能学习建议
|
||||||
|
ai_suggestions = []
|
||||||
|
|
||||||
|
if DEEPSEEK_API_KEY:
|
||||||
|
with st.spinner("🤖 AI正在分析您的学习数据..."):
|
||||||
|
# 构建AI分析的prompt
|
||||||
|
system_prompt = """你是一位专业的学习顾问,擅长分析学生的学习笔记并提供个性化的学习建议。
|
||||||
|
请根据提供的笔记数据,生成3-5条具体、实用的学习建议。
|
||||||
|
建议应该包括:
|
||||||
|
1. 学习方法和策略
|
||||||
|
2. 知识体系的构建
|
||||||
|
3. 学习重点和方向
|
||||||
|
4. 改进建议
|
||||||
|
每条建议应该简洁明了,不超过50字,使用emoji开头。"""
|
||||||
|
|
||||||
|
user_prompt = f"""请分析以下学习笔记数据,并给出个性化学习建议:
|
||||||
|
|
||||||
|
笔记总数:{total_notes}
|
||||||
|
分类统计:{categories}
|
||||||
|
热门标签:{tag_counts.most_common(5)}
|
||||||
|
总字数:{total_content_length}
|
||||||
|
平均每条笔记字数:{int(total_content_length/total_notes) if total_notes > 0 else 0}
|
||||||
|
|
||||||
|
笔记概览:
|
||||||
|
{json.dumps(notes_summary[:10], ensure_ascii=False, indent=2)}
|
||||||
|
|
||||||
|
请基于以上数据,给出3-5条具体的学习建议。"""
|
||||||
|
|
||||||
|
messages = [
|
||||||
|
{"role": "system", "content": system_prompt},
|
||||||
|
{"role": "user", "content": user_prompt}
|
||||||
|
]
|
||||||
|
|
||||||
|
ai_response = call_deepseek_api(messages, temperature=0.8, max_tokens=500)
|
||||||
|
|
||||||
|
if ai_response:
|
||||||
|
ai_suggestions = ai_response.strip().split('\n')
|
||||||
|
ai_suggestions = [s.strip() for s in ai_suggestions if s.strip()]
|
||||||
|
else:
|
||||||
|
st.error("❌ AI生成建议失败,请检查API配置或稍后重试")
|
||||||
|
|
||||||
|
# 生成学习进度报告
|
||||||
|
report = {
|
||||||
|
"总览": {
|
||||||
|
"笔记总数": total_notes,
|
||||||
|
"分类数量": len(categories),
|
||||||
|
"标签总数": len(set(all_tags)),
|
||||||
|
"总字数": total_content_length,
|
||||||
|
"平均每条笔记字数": int(total_content_length/total_notes) if total_notes > 0 else 0
|
||||||
|
},
|
||||||
|
"分类统计": categories,
|
||||||
|
"热门标签": top_tags,
|
||||||
|
"学习建议": ai_suggestions,
|
||||||
|
"生成时间": datetime.now().strftime(DATETIME_FORMAT),
|
||||||
|
"AI生成": len(ai_suggestions) > 0 and DEEPSEEK_API_KEY is not None
|
||||||
|
}
|
||||||
|
|
||||||
|
return report
|
||||||
|
|
||||||
# 2. 数据持久化函数
|
# 2. 数据持久化函数
|
||||||
def save_notes():
|
def save_notes():
|
||||||
"""保存笔记到 JSON 文件"""
|
"""保存笔记到 JSON 文件"""
|
||||||
@ -219,7 +422,12 @@ if "categories" not in st.session_state:
|
|||||||
if "editing_note" not in st.session_state:
|
if "editing_note" not in st.session_state:
|
||||||
st.session_state.editing_note = None
|
st.session_state.editing_note = None
|
||||||
|
|
||||||
|
# 初始化清空确认状态
|
||||||
|
if "confirm_clear" not in st.session_state:
|
||||||
|
st.session_state.confirm_clear = False
|
||||||
|
|
||||||
# 4. 左侧侧边栏 - 添加笔记和管理类型
|
# 4. 左侧侧边栏 - 添加笔记和管理类型
|
||||||
|
with tab_notes:
|
||||||
with st.sidebar:
|
with st.sidebar:
|
||||||
st.header("📝 添加笔记")
|
st.header("📝 添加笔记")
|
||||||
|
|
||||||
@ -273,7 +481,7 @@ with st.sidebar:
|
|||||||
st.info(extracted['summary'])
|
st.info(extracted['summary'])
|
||||||
st.markdown("**关键词预览:**")
|
st.markdown("**关键词预览:**")
|
||||||
if extracted['keywords']:
|
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']])
|
keywords_html = format_tags_html(extracted['keywords'], style="preview")
|
||||||
st.markdown(keywords_html, unsafe_allow_html=True)
|
st.markdown(keywords_html, unsafe_allow_html=True)
|
||||||
|
|
||||||
# 添加按钮
|
# 添加按钮
|
||||||
@ -285,8 +493,8 @@ with st.sidebar:
|
|||||||
"category": category,
|
"category": category,
|
||||||
"content": content,
|
"content": content,
|
||||||
"tags": tags,
|
"tags": tags,
|
||||||
"created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
"created_at": datetime.now().strftime(DATETIME_FORMAT),
|
||||||
"updated_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
"updated_at": datetime.now().strftime(DATETIME_FORMAT)
|
||||||
}
|
}
|
||||||
st.session_state.notes.append(note)
|
st.session_state.notes.append(note)
|
||||||
save_notes()
|
save_notes()
|
||||||
@ -333,7 +541,7 @@ with col3:
|
|||||||
|
|
||||||
with col4:
|
with col4:
|
||||||
# 标签筛选
|
# 标签筛选
|
||||||
all_tags = list(set(tag for note in st.session_state.notes for tag in note.get("tags", [])))
|
all_tags = get_all_tags()
|
||||||
filter_tag = st.selectbox(
|
filter_tag = st.selectbox(
|
||||||
"筛选标签",
|
"筛选标签",
|
||||||
["全部"] + sorted(all_tags),
|
["全部"] + sorted(all_tags),
|
||||||
@ -364,51 +572,15 @@ with col_batch2:
|
|||||||
|
|
||||||
# 6. 显示笔记
|
# 6. 显示笔记
|
||||||
if st.session_state.notes:
|
if st.session_state.notes:
|
||||||
# 筛选和搜索逻辑
|
# 使用辅助函数进行筛选和排序
|
||||||
filtered_notes = []
|
filtered_notes = filter_notes(
|
||||||
for note in st.session_state.notes:
|
st.session_state.notes,
|
||||||
# 分类筛选
|
search_query=search_query,
|
||||||
category_match = filter_category == "全部" or note["category"] == filter_category
|
search_scope=search_scope,
|
||||||
|
filter_category=filter_category,
|
||||||
# 标签筛选
|
filter_tag=filter_tag
|
||||||
tag_match = filter_tag == "全部" or filter_tag in note.get("tags", [])
|
|
||||||
|
|
||||||
# 关键词搜索(根据选择范围)
|
|
||||||
search_match = True
|
|
||||||
if search_query:
|
|
||||||
query = search_query.lower()
|
|
||||||
if search_scope == "全部":
|
|
||||||
search_match = (
|
|
||||||
query in note["title"].lower() or
|
|
||||||
query in note["content"].lower() or
|
|
||||||
query in note["category"].lower() or
|
|
||||||
any(query in tag.lower() for tag in note.get("tags", []))
|
|
||||||
)
|
)
|
||||||
elif search_scope == "仅标题":
|
filtered_notes = sort_notes(filtered_notes, sort_by)
|
||||||
search_match = query in note["title"].lower()
|
|
||||||
elif search_scope == "仅内容":
|
|
||||||
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 tag_match and search_match:
|
|
||||||
filtered_notes.append(note)
|
|
||||||
|
|
||||||
# 排序逻辑
|
|
||||||
if sort_by == "最新":
|
|
||||||
filtered_notes.sort(key=lambda x: x["created_at"], reverse=True)
|
|
||||||
elif sort_by == "最旧":
|
|
||||||
filtered_notes.sort(key=lambda x: x["created_at"])
|
|
||||||
elif sort_by == "标题A-Z":
|
|
||||||
filtered_notes.sort(key=lambda x: x["title"].lower())
|
|
||||||
elif sort_by == "标题Z-A":
|
|
||||||
filtered_notes.sort(key=lambda x: x["title"].lower(), reverse=True)
|
|
||||||
elif sort_by == "类型A-Z":
|
|
||||||
filtered_notes.sort(key=lambda x: x["category"].lower())
|
|
||||||
elif sort_by == "类型Z-A":
|
|
||||||
filtered_notes.sort(key=lambda x: x["category"].lower(), reverse=True)
|
|
||||||
|
|
||||||
# 显示筛选结果
|
# 显示筛选结果
|
||||||
if filtered_notes:
|
if filtered_notes:
|
||||||
@ -449,7 +621,7 @@ if st.session_state.notes:
|
|||||||
note['category'] = edit_category
|
note['category'] = edit_category
|
||||||
note['content'] = edit_content
|
note['content'] = edit_content
|
||||||
note['tags'] = edit_tags_list
|
note['tags'] = edit_tags_list
|
||||||
note['updated_at'] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
note['updated_at'] = datetime.now().strftime(DATETIME_FORMAT)
|
||||||
st.session_state.editing_note = None
|
st.session_state.editing_note = None
|
||||||
save_notes()
|
save_notes()
|
||||||
st.success("笔记已更新!")
|
st.success("笔记已更新!")
|
||||||
@ -466,7 +638,7 @@ if st.session_state.notes:
|
|||||||
|
|
||||||
# 显示标签
|
# 显示标签
|
||||||
if note.get("tags"):
|
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"]])
|
tags_html = format_tags_html(note["tags"])
|
||||||
st.markdown(f"**标签:** {tags_html}", unsafe_allow_html=True)
|
st.markdown(f"**标签:** {tags_html}", unsafe_allow_html=True)
|
||||||
|
|
||||||
st.markdown(f"**创建时间:** {note['created_at']}")
|
st.markdown(f"**创建时间:** {note['created_at']}")
|
||||||
@ -487,7 +659,7 @@ if st.session_state.notes:
|
|||||||
st.info(extracted['summary'])
|
st.info(extracted['summary'])
|
||||||
st.markdown("**关键词:**")
|
st.markdown("**关键词:**")
|
||||||
if extracted['keywords']:
|
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']])
|
keywords_html = format_tags_html(extracted['keywords'], style="preview")
|
||||||
st.markdown(keywords_html, unsafe_allow_html=True)
|
st.markdown(keywords_html, unsafe_allow_html=True)
|
||||||
else:
|
else:
|
||||||
st.warning("未找到关键词")
|
st.warning("未找到关键词")
|
||||||
@ -508,7 +680,7 @@ if st.session_state.notes:
|
|||||||
save_notes()
|
save_notes()
|
||||||
st.rerun()
|
st.rerun()
|
||||||
else:
|
else:
|
||||||
st.warning("没有找到匹配的笔记")
|
st.info("没有找到匹配的笔记")
|
||||||
else:
|
else:
|
||||||
st.info("还没有笔记,请在左侧添加您的第一条笔记!")
|
st.info("还没有笔记,请在左侧添加您的第一条笔记!")
|
||||||
|
|
||||||
@ -521,7 +693,7 @@ col_stats1, col_stats2 = st.columns(2)
|
|||||||
with col_stats1:
|
with col_stats1:
|
||||||
st.metric("总笔记数", len(st.session_state.notes))
|
st.metric("总笔记数", len(st.session_state.notes))
|
||||||
with col_stats2:
|
with col_stats2:
|
||||||
all_tags = list(set(tag for note in st.session_state.notes for tag in note.get("tags", [])))
|
all_tags = get_all_tags()
|
||||||
st.metric("总标签数", len(all_tags))
|
st.metric("总标签数", len(all_tags))
|
||||||
|
|
||||||
# 分类统计
|
# 分类统计
|
||||||
@ -636,8 +808,8 @@ with tab_txt:
|
|||||||
"title": import_title,
|
"title": import_title,
|
||||||
"category": import_category,
|
"category": import_category,
|
||||||
"content": content,
|
"content": content,
|
||||||
"created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
"created_at": datetime.now().strftime(DATETIME_FORMAT),
|
||||||
"updated_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
"updated_at": datetime.now().strftime(DATETIME_FORMAT)
|
||||||
}
|
}
|
||||||
st.session_state.notes.append(note)
|
st.session_state.notes.append(note)
|
||||||
save_notes()
|
save_notes()
|
||||||
@ -670,7 +842,7 @@ with export_tab_txt:
|
|||||||
if st.button("📤 导出所有笔记为文本", type="primary", key="export_all_txt"):
|
if st.button("📤 导出所有笔记为文本", type="primary", key="export_all_txt"):
|
||||||
# 合并所有笔记为一个文本文件
|
# 合并所有笔记为一个文本文件
|
||||||
all_content = "=" * 50 + "\n"
|
all_content = "=" * 50 + "\n"
|
||||||
all_content += f"学习笔记备份 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
|
all_content += f"学习笔记备份 - {datetime.now().strftime(DATETIME_FORMAT)}\n"
|
||||||
all_content += "=" * 50 + "\n\n"
|
all_content += "=" * 50 + "\n\n"
|
||||||
|
|
||||||
for note in st.session_state.notes:
|
for note in st.session_state.notes:
|
||||||
@ -724,14 +896,176 @@ st.divider()
|
|||||||
# 清空功能
|
# 清空功能
|
||||||
col_clear = st.columns(1)[0]
|
col_clear = st.columns(1)[0]
|
||||||
with col_clear:
|
with col_clear:
|
||||||
|
if not st.session_state.confirm_clear:
|
||||||
if st.button("🗑️ 清空所有笔记"):
|
if st.button("🗑️ 清空所有笔记"):
|
||||||
if st.session_state.notes:
|
if st.session_state.notes:
|
||||||
st.warning("⚠️ 此操作不可恢复!")
|
st.session_state.confirm_clear = True
|
||||||
if st.button("确认清空"):
|
|
||||||
st.session_state.notes = []
|
|
||||||
st.session_state.editing_note = None
|
|
||||||
save_notes()
|
|
||||||
st.success("所有笔记已清空!")
|
|
||||||
st.rerun()
|
st.rerun()
|
||||||
else:
|
else:
|
||||||
st.info("没有笔记可清空")
|
st.info("没有笔记可清空")
|
||||||
|
else:
|
||||||
|
st.warning("⚠️ 确定要清空所有笔记吗?此操作不可恢复!")
|
||||||
|
col_confirm, col_cancel_clear = st.columns(2)
|
||||||
|
with col_confirm:
|
||||||
|
if st.button("✅ 确认清空", type="primary"):
|
||||||
|
st.session_state.notes = []
|
||||||
|
st.session_state.editing_note = None
|
||||||
|
st.session_state.confirm_clear = False
|
||||||
|
save_notes()
|
||||||
|
st.success("所有笔记已清空!")
|
||||||
|
st.rerun()
|
||||||
|
with col_cancel_clear:
|
||||||
|
if st.button("❌ 取消"):
|
||||||
|
st.session_state.confirm_clear = False
|
||||||
|
st.rerun()
|
||||||
|
|
||||||
|
# AI学习报告标签页
|
||||||
|
with tab_report:
|
||||||
|
st.header("🤖 AI学习报告")
|
||||||
|
st.markdown("根据您的笔记生成个性化的学习报告和建议")
|
||||||
|
|
||||||
|
# 筛选选项
|
||||||
|
st.divider()
|
||||||
|
st.subheader("📊 筛选笔记")
|
||||||
|
|
||||||
|
col_report1, col_report2, col_report3 = st.columns(3)
|
||||||
|
|
||||||
|
with col_report1:
|
||||||
|
# 分类筛选
|
||||||
|
report_category = st.selectbox(
|
||||||
|
"筛选分类",
|
||||||
|
["全部"] + st.session_state.categories,
|
||||||
|
help="选择要分析的分类"
|
||||||
|
)
|
||||||
|
|
||||||
|
with col_report2:
|
||||||
|
# 标签筛选
|
||||||
|
all_tags = get_all_tags()
|
||||||
|
report_tag = st.selectbox(
|
||||||
|
"筛选标签",
|
||||||
|
["全部"] + sorted(all_tags),
|
||||||
|
help="选择要分析的标签"
|
||||||
|
)
|
||||||
|
|
||||||
|
with col_report3:
|
||||||
|
# 时间范围筛选
|
||||||
|
report_time_range = st.selectbox(
|
||||||
|
"时间范围",
|
||||||
|
["全部时间", "最近7天", "最近30天", "最近90天"],
|
||||||
|
help="选择分析的时间范围"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 生成报告按钮
|
||||||
|
st.divider()
|
||||||
|
if st.button("🚀 生成学习报告", type="primary"):
|
||||||
|
# 筛选笔记
|
||||||
|
filtered_notes = []
|
||||||
|
for note in st.session_state.notes:
|
||||||
|
# 分类筛选
|
||||||
|
category_match = report_category == "全部" or note["category"] == report_category
|
||||||
|
|
||||||
|
# 标签筛选
|
||||||
|
tag_match = report_tag == "全部" or report_tag in note.get("tags", [])
|
||||||
|
|
||||||
|
# 时间筛选
|
||||||
|
time_match = True
|
||||||
|
if report_time_range != "全部时间":
|
||||||
|
try:
|
||||||
|
note_date = datetime.strptime(note["created_at"], DATETIME_FORMAT)
|
||||||
|
now = datetime.now()
|
||||||
|
if report_time_range == "最近7天":
|
||||||
|
time_match = (now - note_date).days <= 7
|
||||||
|
elif report_time_range == "最近30天":
|
||||||
|
time_match = (now - note_date).days <= 30
|
||||||
|
elif report_time_range == "最近90天":
|
||||||
|
time_match = (now - note_date).days <= 90
|
||||||
|
except Exception as e:
|
||||||
|
time_match = True
|
||||||
|
|
||||||
|
if category_match and tag_match and time_match:
|
||||||
|
filtered_notes.append(note)
|
||||||
|
|
||||||
|
# 生成报告
|
||||||
|
if filtered_notes:
|
||||||
|
report = generate_study_report(filtered_notes)
|
||||||
|
|
||||||
|
# 显示报告
|
||||||
|
st.success(f"✅ 基于筛选后的 {len(filtered_notes)} 条笔记生成报告")
|
||||||
|
|
||||||
|
# 总览部分
|
||||||
|
st.divider()
|
||||||
|
st.subheader("📈 学习总览")
|
||||||
|
col_overview1, col_overview2, col_overview3 = st.columns(3)
|
||||||
|
with col_overview1:
|
||||||
|
st.metric("笔记总数", report["总览"]["笔记总数"])
|
||||||
|
with col_overview2:
|
||||||
|
st.metric("总字数", report["总览"]["总字数"])
|
||||||
|
with col_overview3:
|
||||||
|
st.metric("平均字数", report["总览"]["平均每条笔记字数"])
|
||||||
|
|
||||||
|
# 分类统计
|
||||||
|
if report["分类统计"]:
|
||||||
|
st.divider()
|
||||||
|
st.subheader("📂 分类分布")
|
||||||
|
cat_cols = st.columns(min(4, len(report["分类统计"])))
|
||||||
|
for i, (cat, count) in enumerate(report["分类统计"].items()):
|
||||||
|
if i < len(cat_cols):
|
||||||
|
with cat_cols[i]:
|
||||||
|
st.metric(cat, count)
|
||||||
|
|
||||||
|
# 热门标签
|
||||||
|
if report["热门标签"]:
|
||||||
|
st.divider()
|
||||||
|
st.subheader("🏷️ 热门标签")
|
||||||
|
tag_cols = st.columns(min(5, len(report["热门标签"])))
|
||||||
|
for i, (tag, count) in enumerate(report["热门标签"]):
|
||||||
|
if i < len(tag_cols):
|
||||||
|
with tag_cols[i]:
|
||||||
|
st.metric(tag, count)
|
||||||
|
|
||||||
|
# 学习建议
|
||||||
|
if report["学习建议"]:
|
||||||
|
st.divider()
|
||||||
|
st.subheader("💡 AI学习建议")
|
||||||
|
for i, suggestion in enumerate(report["学习建议"], 1):
|
||||||
|
st.info(f"{i}. {suggestion}")
|
||||||
|
|
||||||
|
# 导出报告
|
||||||
|
st.divider()
|
||||||
|
if st.button("📥 导出报告"):
|
||||||
|
report_text = "=" * 60 + "\n"
|
||||||
|
report_text += "AI学习报告\n"
|
||||||
|
report_text += f"生成时间: {report['生成时间']}\n"
|
||||||
|
report_text += "=" * 60 + "\n\n"
|
||||||
|
|
||||||
|
report_text += "【学习总览】\n"
|
||||||
|
report_text += f"笔记总数: {report['总览']['笔记总数']}\n"
|
||||||
|
report_text += f"分类数量: {report['总览']['分类数量']}\n"
|
||||||
|
report_text += f"标签总数: {report['总览']['标签总数']}\n"
|
||||||
|
report_text += f"总字数: {report['总览']['总字数']}\n"
|
||||||
|
report_text += f"平均每条笔记字数: {report['总览']['平均每条笔记字数']}\n\n"
|
||||||
|
|
||||||
|
report_text += "【分类统计】\n"
|
||||||
|
for cat, count in report["分类统计"].items():
|
||||||
|
report_text += f"{cat}: {count}条\n"
|
||||||
|
report_text += "\n"
|
||||||
|
|
||||||
|
report_text += "【热门标签】\n"
|
||||||
|
for tag, count in report["热门标签"]:
|
||||||
|
report_text += f"{tag}: {count}次\n"
|
||||||
|
report_text += "\n"
|
||||||
|
|
||||||
|
report_text += "【AI学习建议】\n"
|
||||||
|
for i, suggestion in enumerate(report["学习建议"], 1):
|
||||||
|
report_text += f"{i}. {suggestion}\n"
|
||||||
|
|
||||||
|
st.download_button(
|
||||||
|
label="下载学习报告",
|
||||||
|
data=report_text,
|
||||||
|
file_name=f"study_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt",
|
||||||
|
mime="text/plain"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
st.warning("⚠️ 没有找到符合条件的笔记,请调整筛选条件")
|
||||||
|
else:
|
||||||
|
st.info("👆 请选择筛选条件后点击生成报告按钮")
|
||||||
|
|||||||
@ -104,7 +104,13 @@
|
|||||||
"content": "中国古典诗词是中华文化的瑰宝,承载着数千年的历史与智慧。从《诗经》的质朴纯真,到唐诗的辉煌灿烂,再到宋词的婉约豪放,诗词艺术在中国文学史上占据着极其重要的地位。\n\n诗歌的起源可以追溯到远古时期,先民们在劳动和生活中创造了最初的歌谣。这些歌谣经过长期的传承和演变,逐渐形成了具有固定格式的诗歌。《诗经》是中国最早的诗歌总集,收录了从西周初期到春秋中叶的305篇诗歌,分为风、雅、颂三个部分。《诗经》中的诗歌以四言为主,运用了赋、比、兴的表现手法,开创了中国诗歌的现实主义传统。\n\n汉代乐府诗继承了《诗经》的现实主义精神,反映了当时的社会生活和人民的思想感情。《古诗十九首》是汉代文人五言诗的代表作,语言质朴自然,情感真挚深沉,被誉为\"五言之冠冕\"。这些诗歌为后来诗歌的发展奠定了坚实的基础。\n\n唐代是中国诗歌发展的黄金时代,涌现出了李白、杜甫、白居易等一大批杰出的诗人。李白的诗歌豪放飘逸,想象奇特,充满了浪漫主义色彩。他的《将进酒》\"君不见黄河之水天上来,奔流到海不复回\"气势磅礴,展现了他豪迈不羁的性格。杜甫的诗歌沉郁顿挫,关注民生疾苦,被称为\"诗圣\"。他的《春望》\"国破山河在,城春草木深\"表达了对国家命运的忧虑。白居易的诗歌通俗易懂,关注社会现实,他的《长恨歌》\"在天愿作比翼鸟,在地愿为连理枝\"传唱千古。\n\n宋词是中国诗歌的另一种重要形式,分为豪放派和婉约派两大流派。苏轼是豪放派的代表人物,他的词作气势磅礴,意境开阔。他的《念奴娇·赤壁怀古》\"大江东去,浪淘尽,千古风流人物\"展现了豪迈的气概。李清照是婉约派的代表人物,她的词作细腻婉约,情感真挚。她的《声声慢》\"寻寻觅觅,冷冷清清,凄凄惨惨戚戚\"表达了她内心的愁苦。\n\n中国古典诗词的艺术特色主要体现在以下几个方面:一是意境深远,诗人通过生动的意象和精妙的语言,营造出深远的艺术境界;二是语言精炼,诗词要求字斟句酌,每一个字都要发挥最大的表现力;三是韵律优美,诗词讲究平仄和对仗,读起来朗朗上口;四是情感真挚,诗人将自己的真情实感融入诗中,使读者产生共鸣。\n\n诗歌的创作技巧丰富多彩,包括比喻、拟人、夸张、对偶、排比等多种修辞手法。比喻可以使抽象的事物变得具体形象,如\"问君能有几多愁,恰似一江春水向东流\"。拟人可以使事物具有人的情感和动作,如\"感时花溅泪,恨别鸟惊心\"。夸张可以突出事物的特征,如\"飞流直下三千尺,疑是银河落九天\"。对偶可以使诗歌更加工整优美,如\"两个黄鹂鸣翠柳,一行白鹭上青天\"。\n\n中国古典诗词蕴含着深刻的思想内涵。许多诗歌表达了诗人对国家和人民的关怀,如杜甫的\"安得广厦千万间,大庇天下寒士俱欢颜\"。有些诗歌表达了诗人对人生的感悟,如苏轼的\"人有悲欢离合,月有阴晴圆缺,此事古难全\"。还有些诗歌表达了诗人对自然的热爱,如王维的\"空山新雨后,天气晚来秋\"。\n\n学习古典诗词,不仅可以提高我们的文学素养,还可以陶冶我们的情操,丰富我们的精神世界。通过阅读和欣赏古典诗词,我们可以感受到古人的智慧和情感,体会到中华文化的博大精深。古典诗词是我们民族的精神财富,值得我们认真学习和传承。\n\n在现代社会,古典诗词依然具有重要的意义。它可以帮助我们更好地理解传统文化,增强文化自信。它可以提高我们的审美能力和语言表达能力。它还可以帮助我们缓解压力,陶冶情操。因此,我们应该重视古典诗词的学习和传承,让这一优秀的文化遗产在新时代焕发出新的光彩。",
|
"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",
|
"created_at": "2026-01-08 16:00:00",
|
||||||
"updated_at": "2026-01-08 16:00:00",
|
"updated_at": "2026-01-08 16:00:00",
|
||||||
"tags": ["诗词", "文学", "文化", "艺术", "经典"]
|
"tags": [
|
||||||
|
"诗词",
|
||||||
|
"文学",
|
||||||
|
"文化",
|
||||||
|
"艺术",
|
||||||
|
"经典"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"categories": [
|
"categories": [
|
||||||
@ -112,6 +118,7 @@
|
|||||||
"数学",
|
"数学",
|
||||||
"英语",
|
"英语",
|
||||||
"其他",
|
"其他",
|
||||||
"语文"
|
"语文",
|
||||||
|
"1"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user