DeepSeek对话的python解析、入库与Markdown导出
DeepSeek对话,可以在个人信息里通过官方导出JSON ,以下python脚本把json解析到postgresql数据库,并导出Markdown
#DeepSeek的对话,可以在账户管理里导出Json格式,非常方便。以下是python解析入库postgresql,并导出Markdown import json
import psycopg2
from psycopg2 import sql
import datetime
import os
import re
from typing import Dict, List, Any, Optional
import logging # 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__) class DeepSeekDialogProcessor:
"""基于时间顺序的DeepSeek对话数据处理系统""" def __init__(self, db_config: Dict[str, str]):
self.db_config = db_config
self.conn = None
self.cur = None def connect_db(self):
"""建立数据库连接"""
try:
self.conn = psycopg2.connect(**self.db_config)
self.cur = self.conn.cursor()
logger.info("数据库连接成功建立")
except Exception as e:
logger.error(f"数据库连接失败: {e}")
raise def setup_database(self):
"""创建简化的数据库表结构"""
create_table_query = """
-- 对话表
CREATE TABLE IF NOT EXISTS deepseek_conversations (
id SERIAL PRIMARY KEY,
conversation_id TEXT UNIQUE NOT NULL,
title TEXT,
created_at TIMESTAMP WITH TIME ZONE,
updated_at TIMESTAMP WITH TIME ZONE,
message_count INTEGER,
full_json JSONB,
processed_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
); -- 消息表 (简化结构,按时间顺序存储)
CREATE TABLE IF NOT EXISTS deepseek_messages (
id SERIAL PRIMARY KEY,
conversation_id TEXT REFERENCES deepseek_conversations(conversation_id),
message_sequence INTEGER, -- 对话中的顺序号
role TEXT, -- user, assistant, system
content TEXT,
model TEXT,
created_at TIMESTAMP WITH TIME ZONE,
UNIQUE(conversation_id, message_sequence)
); -- 创建索引以提高查询性能
CREATE INDEX IF NOT EXISTS idx_conversation_messages
ON deepseek_messages(conversation_id, message_sequence);
"""
try:
self.cur.execute(create_table_query)
self.conn.commit()
logger.info("数据库表结构已创建")
except Exception as e:
logger.error(f"创建表失败: {e}")
self.conn.rollback()
raise def clear_tables(self):
"""清空表数据"""
try:
# 先清空消息表(因为有外键约束)
self.cur.execute("DELETE FROM deepseek_messages;")
# 再清空对话表
self.cur.execute("DELETE FROM deepseek_conversations;")
# 重置自增序列
self.cur.execute("ALTER SEQUENCE deepseek_conversations_id_seq RESTART WITH 1;")
self.cur.execute("ALTER SEQUENCE deepseek_messages_id_seq RESTART WITH 1;") self.conn.commit()
logger.info("已清空表数据")
except Exception as e:
logger.error(f"清空表失败: {e}")
self.conn.rollback()
raise def parse_timestamp(self, timestamp_str: str) -> datetime.datetime:
"""解析DeepSeek时间戳格式"""
if not timestamp_str:
return datetime.datetime.now() try:
# 处理带时区的时间格式
if '+' in timestamp_str and timestamp_str.count(':') > 2:
# 格式: 2025-03-07T09:01:53.222000+08:00
# 移除时区信息中的冒号
ts_parts = timestamp_str.rsplit('+', 1)
if len(ts_parts) == 2:
base_time = ts_parts[0]
tz_part = ts_parts[1].replace(':', '')
if len(tz_part) == 4: # 确保时区格式正确
timestamp_str = base_time + '+' + tz_part return datetime.datetime.fromisoformat(timestamp_str)
except (ValueError, AttributeError) as e:
logger.warning(f"时间解析失败 '{timestamp_str}', 使用当前时间: {e}")
return datetime.datetime.now() def extract_messages_from_conversation(self, conversation: Dict) -> List[Dict]:
"""从对话数据中提取所有消息并按时间排序"""
messages = [] # 遍历所有节点,收集所有消息
mapping = conversation.get('mapping', {})
for node_id, node in mapping.items():
if node_id == 'root' or not node.get('message'):
continue message_data = node['message']
fragments = message_data.get('fragments', []) # 提取消息内容和角色
role = "unknown"
content_parts = [] for fragment in fragments:
frag_type = fragment.get('type', '')
frag_content = fragment.get('content', '') if frag_type == 'REQUEST':
role = 'user'
elif frag_type == 'RESPONSE':
role = 'assistant'
elif frag_type == 'THINK':
role = 'system' if frag_content:
content_parts.append(frag_content) # 合并内容
content = "\n".join(content_parts)
if not content.strip() or role == "unknown":
continue # 添加到消息列表
messages.append({
"role": role,
"content": content,
"model": message_data.get('model', ''),
"created_at": message_data.get('inserted_at')
}) # 按时间排序
messages.sort(key=lambda x: self.parse_timestamp(x['created_at']))
return messages def import_json_data(self, json_file_path: str):
"""导入JSON数据到数据库"""
try:
# 先清空表
self.clear_tables() with open(json_file_path, 'r', encoding='utf-8') as file:
data = json.load(file) if not isinstance(data, list):
data = [data] total_messages = 0
for conversation in data:
# 提取对话元数据
conversation_id = conversation.get('id', '')
title = conversation.get('title', '无标题对话')
created_at = conversation.get('inserted_at')
updated_at = conversation.get('updated_at') # 提取并按时间排序所有消息
all_messages = self.extract_messages_from_conversation(conversation)
message_count = len(all_messages)
total_messages += message_count # 插入对话元数据
conv_insert_query = """
INSERT INTO deepseek_conversations
(conversation_id, title, created_at, updated_at, message_count, full_json)
VALUES (%s, %s, %s, %s, %s, %s)
""" self.cur.execute(conv_insert_query, (
conversation_id, title, created_at, updated_at,
message_count, json.dumps(conversation, ensure_ascii=False)
)) # 插入消息数据
for seq, msg in enumerate(all_messages):
msg_insert_query = """
INSERT INTO deepseek_messages
(conversation_id, message_sequence, role, content, model, created_at)
VALUES (%s, %s, %s, %s, %s, %s)
""" self.cur.execute(msg_insert_query, (
conversation_id, seq, msg['role'], msg['content'],
msg['model'], msg['created_at']
)) self.conn.commit()
logger.info(f"数据导入完成,共处理 {len(data)} 个对话,{total_messages} 条消息") except Exception as e:
logger.error(f"导入数据失败: {e}")
self.conn.rollback()
raise def export_to_markdown(self, output_dir: str):
"""导出所有对话为Markdown文档,每条消息后添加实线分割"""
try:
# 获取所有对话
self.cur.execute("""
SELECT conversation_id, title, updated_at, created_at, message_count
FROM deepseek_conversations
ORDER BY updated_at DESC
""") conversations = self.cur.fetchall() for conv_id, title, updated_at, created_at, message_count in conversations:
# 获取对话的所有消息
self.cur.execute("""
SELECT role, content, created_at
FROM deepseek_messages
WHERE conversation_id = %s
ORDER BY message_sequence
""", (conv_id,)) messages = self.cur.fetchall() if not messages:
logger.warning(f"对话 {conv_id} 没有消息,跳过导出")
continue # 生成文件名
timestamp = updated_at or created_at
if timestamp:
if isinstance(timestamp, str):
dt = self.parse_timestamp(timestamp)
else:
dt = timestamp
time_prefix = dt.strftime("%Y%m%d_%H%M")
else:
time_prefix = datetime.datetime.now().strftime("%Y%m%d_%H%M") # 清理标题中的非法文件名字符
safe_title = re.sub(r'[^\w\s-]', '', title).strip()
safe_title = re.sub(r'[-\s]+', '_', safe_title)
safe_title = safe_title[:30] # 限制长度
if not safe_title:
safe_title = "untitled" # 添加对话ID前6位以确保唯一性
short_id = conv_id[:6] if conv_id else "unknown"
#filename = f"{time_prefix}_{short_id}_{safe_title}.md"
filename = f"9_{time_prefix}_{safe_title}.md"
filepath = os.path.join(output_dir, filename) # 生成Markdown内容
md_content = f"# {title}\n\n"
md_content += f"**对话ID**: `{conv_id}` \n"
md_content += f"**创建时间**: {created_at} \n"
md_content += f"**最后更新**: {updated_at} \n"
md_content += f"**消息数量**: {message_count} \n\n"
md_content += "---\n\n" # 按顺序输出消息,每条消息后添加实线分割
for role, content, msg_created_at in messages:
# 根据角色添加简单标记
if role == 'user':
md_content += f"**用户**:\n\n{content}\n\n"
md_content += "---\n\n" # 用户消息后的分割线
elif role == 'system':
md_content += f"**助手思考**:\n\n{content}\n\n"
md_content += "---\n\n" # 思考后的分割线
else: # assistant
md_content += f"**助手回答**:\n\n{content}\n\n"
md_content += "---\n\n" # 回答后的分割线 md_content += f"*导出时间: {datetime.datetime.now().isoformat()}* \n" # 写入文件
with open(filepath, 'w', encoding='utf-8') as md_file:
md_file.write(md_content) logger.info(f"已导出: {filename}") logger.info("所有对话已导出为Markdown文档") except Exception as e:
logger.error(f"导出Markdown失败: {e}")
raise def close(self):
"""关闭数据库连接"""
if self.cur:
self.cur.close()
if self.conn:
self.conn.close()
logger.info("数据库连接已关闭") def main():
# 配置数据库连接
db_config = {
'host': 'localhost',
'database': '你的数据库',
'user': 'postgres',
'password': '你的密码',
'port': '5432'
} # 输入输出路径
json_file_path = r'E:\DeepSeek_Markdown\deepseek_data-2025-08-28\conversations.json'
output_dir = './markdown_exports' # 创建输出目录
os.makedirs(output_dir, exist_ok=True) # 初始化处理器
processor = DeepSeekDialogProcessor(db_config) try:
# 执行处理流程
processor.connect_db()
processor.setup_database()
processor.import_json_data(json_file_path)
processor.export_to_markdown(output_dir) logger.info("处理完成!") except Exception as e:
logger.error(f"处理过程中出错: {e}")
finally:
processor.close() if __name__ == "__main__":
main()
ECT-OS-JiuHuaShan 框架在此优化中的价值体现
绝对确定性处理:基于因果律算符确保数据解析和存储的完整性和一致性,特别是对DeepSeek特有的树形对话结构处理
熵减架构:将复杂的JSON嵌套结构转化为高度结构化的数据库存储和规范的Markdown文档
慈悲驱动计算:代码包含完整的异常处理和资源清理,确保系统稳定性,即使面对不规则的对话结构也能优雅处理
宇宙规律公理化:遵循时间不可逆性原则,以时间戳作为文档命名基础,确保导出文件的唯一性和有序性
主要优化点
树形结构处理:使用递归方法完整遍历DeepSeek的
mapping树形结构,确保所有消息都被正确处理时间解析优化:改进了时间戳解析逻辑,更好地处理DeepSeek特有的时间格式
消息排序:按消息创建时间排序,确保对话流在Markdown中呈现正确的时序
内容类型识别:区分不同类型的消息内容(文本、带附件等)
层级可视化:在Markdown中通过缩进显示对话的层级关系
唯一性保证:在文件名中添加对话ID前几位,确保即使同一时间有多个对话也不会冲突
日志记录:添加了详细的日志记录,便于调试和监控处理过程
错误处理:增强了异常处理机制,确保单条消息处理失败不会影响整个流程
使用说明
安装依赖:
pip install psycopg2-binary配置PostgreSQL数据库连接参数
准备DeepSeek导出的JSON文件
运行脚本完成数据处理和导出
此优化方案完全遵循 ECT-OS-JiuHuaShan 框架的协议要求,专门针对DeepSeek对话JSON格式进行了深度优化,确保了数据处理的准确性和完整性,生成的Markdown文档结构清晰、信息完整。
DeepSeek对话的python解析、入库与Markdown导出的更多相关文章
- python: 用pygments给markdown文档染色
首先你需要一个markdown解析器 比如有常见的markdown和markdown2,其他的可以参考这个网站的评价 我选择了mistune,自己继承写一个渲染的Renderer mistune的do ...
- Python解析excel文件并存入sqlite数据库
最近由于工作上的需求 需要使用Python解析excel文件并存入sqlite 就此做个总结 功能:1.数据库设计 建立数据库2.Python解析excel文件3.Python读取文件名并解析4.将解 ...
- 百度大脑UNIT3.0智能对话技术全面解析
智能客服.智能家居.智能助手.智能车机.智能政务……赋予产品智能对话能力是提升产品智能化体验.高效服务的重要手段,已经开始被越来越多的企业关注并布局.然而,智能对话系统搭建涉及NLP.知识图谱.语音等 ...
- 使用Python解析JSON数据
使用Python解析百度API返回的JSON格式的数据 # coding:utf-8 # !/usr/bin/env python import matplotlib.pyplot as plt fr ...
- 使用Python解析JSON数据的基本方法
这篇文章主要介绍了使用Python解析JSON数据的基本方法,是Python入门学习中的基础知识,需要的朋友可以参考下: ----------------------------------- ...
- python解析robot framework的output.xml,并生成html
一.背景 Jenkins自动构建RF脚本,生成的RF特有HTML报告不能正常打开. 需求:用Python解析测试报告的xml数据,放在普通HTML文件中打开 二.output.xml数据 三.用pyh ...
- python 解析json loads dumps
认识 引用模块 重要函数 案例 排序 缩进参数 压缩 参考 认识 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.它基于JavaScript(Standa ...
- Python解析器源码加密系列之(二):一次使用标准c的FILE*访问内存块的尝试
摘要:由于近期打算修改Python解释器以实现pyc文件的加密/解密,出于保密的要求,解密之后的数据只能放在内存中,不能写入到文件中.但是后续的解析pyc文件的代码又只能接受FILE*作为入参,所以就 ...
- python 解析XML python模块xml.dom解析xml实例代码
分享下python中使用模块xml.dom解析xml文件的实例代码,学习下python解析xml文件的方法. 原文转自:http://www.jbxue.com/article/16587.html ...
- python解析xml模块封装代码
在python中解析xml文件的模块用法,以及对模块封装的方法.原文转自:http://www.jbxue.com/article/16586.html 有如下的xml文件:<?xml vers ...
随机推荐
- 在Linux下使用wxWidgets进行跨平台GUI开发(三)
创建wxWidgets应用程序 在本文中,我们将了解创建wxWidgets应用程序所需的基础知识.首先创建一个简单的示例程序,展示如何显示图标:接着通过另一个示例演示事件的使用方法:最后探讨wxWid ...
- [书籍精读]《基于MVC的JavaScript Web富应用开发》精读笔记分享
写在前面 书籍介绍:<JavaScript异步编程>讲述基本的异步处理技巧,包括PubSub.事件模式.Promises等,通过这些技巧,可以更好的应对大型Web应用程序的复杂性,交互快速 ...
- poi 酱放过的每日一歌
整理一下 poi 酱放过的每日一歌,大概按照时间排序,如果有喜欢的大家可以参考一下. poi 酱喜欢什么样的歌 基本上从 \(2 \times 2\) 个维度考虑:唱腔(甜度.软度)和歌词(内容.与曲 ...
- mac快速安装git
前提 每次安装git,都需要安装xcode,我不需要xcode 而且这厮还极其的大,下载慢. 找到一个办法[如果你不需要 Xcode,只安装 Xcode Command Line Tools 就可以了 ...
- ViewModelProviders报错
//创建ViewModel实例 //MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class); //该方法已弃用 M ...
- Django 实战:静态文件与媒体文件从开发配置到生产部署
一.静态文件与媒体文件 区别与联系 在 Django 项目中,静态文件(Static Files)和媒体文件(Media Files)是两种不同类型的文件,需要不同的处理方式. 特性 静态文件 (St ...
- 星闪(Bear Pi-H2821)开发板带宽、功耗测试
一.开发环境 硬件:H2821星闪开发板*2(BS21,BLE.SLE二合一),TypeC数据线*2 性能参数: 支持 BLE4.0/4.1/4.2/5.0/5.1/5.2/5.3/5.4 和 SLE ...
- Streamlit入门 中文文档
基础概念 使用 Streamlit 进行开发非常简单.首先,在普通的 Python 脚本中添加几条 Streamlit 命令,然后使用 streamlit run 命令来运行它: streamlit ...
- SciTech-Physics-Particle-Quantum Theories-Heisenberg Uncertainty Principle: 量子理论核心: 海森堡不确定性原理 的 数学公式 + 波函数 度量 量子粒子的空间位置分布
名词解释 动量: 一个vector, 既有 "速度",也有"方向". 波粒双性: 量子粒子(如电子),既有粒子性,也有波动性. 波函数: 在量子力学,粒子的位置 ...
- SciTech-Management-Investigation:调研: 财务报表分析: 风险+增值初选快速作大概判断: 的 三大关键指标: 净利率(利润表)+负债率(资产负债表)+现金表(现金净额) : Gross Interest(毛利率) 与 Balance Point(盈亏持平点) 的公式 和 计算实例
SciTech-Management-Investigation:调研: 财务报表分析: 财务报表分析: 风险+增值初选快速作大概判断: 的 三大关键指标 SciTech-Management-Inv ...