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 ...
随机推荐
- 十三、buildroot 系统package新增应用 编写步骤
4.7.package 添加配置文件 4.7.1.操作步骤 1.集成普通包 如 my-custom-package 在 my-custom-package 目录中创建 Config.in 文件 con ...
- 破解五大运营痛点:盘古信息IMS MOM重塑PCB工厂数字化基石
随着5G.物联网等技术发展,PCB行业下游消费电子.汽车电子等领域需求呈现小批量多品种.高精度高可靠性.快速交付特点.传统"规模驱动"生产模式难以适应新需求,行业竞争焦点转向质量. ...
- windows vs使用grpc-cpp的坑
1.通过vcpkg安装protoc和grpc-cpp 2.生成proto协议代码: protoc -I .. -I . --cpp_out=. test.proto 3.生成grpc服务代码: pr ...
- A2A MCP AG2 智能代理示例
项目介绍 本项目展示了如何使用 AG2(前身为 AutoGen)框架构建一个支持 MCP(Model Context Protocol)的智能代理,并通过 A2A(Agent to Agent)协议进 ...
- 5.8Gwifi串口服务器、485转wifi多功能串口转WIFI 、232转wifi、Modbus转RTU、工业自动化系统
ZLAN7146是继ZLAN7100.ZLAN7142.ZLAN7144之后推出的又一款WIFI串口服务器.该串口服务器可以方便地使得串口设备连接到WIFI无线网络,实现串口设备的无线化网络升级.RS ...
- 手把手教你在 Sevalla 上部署 Next.js 博客:从搭建到上线全流程
很多开发者会纠结:"现在博客平台这么多,为啥还要自己搭博客?" 答案很简单:用 Next.js 搭的博客,是真正属于你的 "数字资产". 为什么选 Next.j ...
- idea创建spring通用项目
创建spring基础项目 高清地址点此播放 springBoot: 3.2 java: v21 mybatis: v3.2.4.1 swagger: v3 初始化完成后,我们看看pom文件会发现 已经 ...
- 2023移动光猫H2-2超级密码获取教程
记录信息 普通账户登录光猫后台,记录下宽带的账密.loid. 如果后台查询不到以上信息,则可以按照如下办法获得 宽带的账密不知道,也可以登录移动APP去查询和重置. loid不知道,则联系10086安 ...
- C++ STL 源码 阅读
简介 STL 最常用的源码 下载链接 https://github.com/steveLauwh/SGI-STL
- 如何在非vue组件中使用vuex
简介 RT,有的时候想使用保存在vuex里面的东西 link https://laracasts.com/discuss/channels/vue/vuex-accessing-vuex-outsid ...