将达人已回复导出到excel
This commit is contained in:
parent
82e418b684
commit
487a1a5960
468
apps/gmail/README_GMAIL.md
Normal file
468
apps/gmail/README_GMAIL.md
Normal file
@ -0,0 +1,468 @@
|
|||||||
|
# Gmail模块API接口文档 - Apifox测试版
|
||||||
|
|
||||||
|
## 1. 认证管理
|
||||||
|
|
||||||
|
### 1.1 启动OAuth授权
|
||||||
|
|
||||||
|
- **接口URL**: `/api/gmail/auth/initiate/`
|
||||||
|
- **请求方式**: `POST`
|
||||||
|
- **接口描述**: 生成Google OAuth授权URL,供用户访问并获取授权码
|
||||||
|
|
||||||
|
#### 请求参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"client_secret_json": "String (必填,二选一): Google OAuth客户端凭证(JSON格式字符串)",
|
||||||
|
"client_secret_file": "File (必填,二选一): 上传的客户端凭证JSON文件"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"auth_url": "String: 用户需访问的授权URL",
|
||||||
|
"status": "String: 接口调用状态"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 接口作用
|
||||||
|
生成Google OAuth授权链接,用户通过访问此链接授予应用访问Gmail账户的权限,并获取授权码用于后续步骤。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1.2 完成OAuth授权
|
||||||
|
|
||||||
|
- **接口URL**: `/api/gmail/auth/complete/`
|
||||||
|
- **请求方式**: `POST`
|
||||||
|
- **接口描述**: 使用授权码完成OAuth流程,获取并保存Gmail访问凭证
|
||||||
|
|
||||||
|
#### 请求参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"client_secret_json": "String (必填): Google OAuth客户端凭证(JSON格式)",
|
||||||
|
"auth_code": "String (必填): 用户从授权URL获得的授权码"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "Integer: 凭证ID",
|
||||||
|
"email": "String: 关联的Gmail邮箱地址",
|
||||||
|
"is_default": "Boolean: 是否为默认账户",
|
||||||
|
"created_at": "DateTime: 创建时间",
|
||||||
|
"status": "String: 操作状态"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 接口作用
|
||||||
|
完成OAuth2.0授权流程,将用户的授权码转换为访问令牌,并将凭证保存到系统中,以便后续API调用。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1.3 获取Gmail凭证列表
|
||||||
|
|
||||||
|
- **接口URL**: `/api/gmail/credentials/`
|
||||||
|
- **请求方式**: `GET`
|
||||||
|
- **接口描述**: 获取系统中所有已授权的Gmail账户凭证列表
|
||||||
|
|
||||||
|
#### 响应参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"id": "Integer: 凭证ID",
|
||||||
|
"email": "String: Gmail邮箱地址",
|
||||||
|
"is_default": "Boolean: 是否为默认账户",
|
||||||
|
"created_at": "DateTime: 创建时间"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"count": "Integer: 总记录数"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 接口作用
|
||||||
|
列出系统中所有已授权的Gmail账户,便于用户查看和管理多个Gmail账户。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1.4 设置默认Gmail账户
|
||||||
|
|
||||||
|
- **接口URL**: `/api/gmail/credentials/{id}/set_default/`
|
||||||
|
- **请求方式**: `POST`
|
||||||
|
- **接口描述**: 将指定ID的Gmail账户设置为默认账户
|
||||||
|
|
||||||
|
#### 路径参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "Integer (必填): 凭证ID"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "String: 操作状态",
|
||||||
|
"message": "String: 操作结果信息"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 接口作用
|
||||||
|
设置系统默认使用的Gmail账户,当未指定账户时,系统操作将使用此默认账户。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 对话管理
|
||||||
|
|
||||||
|
### 2.1 创建Gmail对话
|
||||||
|
|
||||||
|
- **接口URL**: `/api/gmail/conversations/`
|
||||||
|
- **请求方式**: `POST`
|
||||||
|
- **接口描述**: 创建并保存用户与特定联系人的邮件对话
|
||||||
|
|
||||||
|
#### 请求参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"user_email": "String (必填): 用户Gmail邮箱",
|
||||||
|
"influencer_email": "String (必填): 对话方Gmail邮箱",
|
||||||
|
"kb_id": "Integer (可选): 关联的知识库ID"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"conversation_id": "Integer: 创建的会话ID",
|
||||||
|
"user_email": "String: 用户Gmail邮箱",
|
||||||
|
"influencer_email": "String: 对话方Gmail邮箱",
|
||||||
|
"created_at": "DateTime: 创建时间",
|
||||||
|
"status": "String: 操作状态"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 接口作用
|
||||||
|
创建并保存特定邮箱之间的对话关系,为后续邮件往来、自动回复和内容分析建立基础。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.2 获取对话列表
|
||||||
|
|
||||||
|
- **接口URL**: `/api/gmail/conversations/`
|
||||||
|
- **请求方式**: `GET`
|
||||||
|
- **接口描述**: 获取所有保存的Gmail邮件对话
|
||||||
|
|
||||||
|
#### 查询参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"user_email": "String (可选): 筛选特定用户的对话",
|
||||||
|
"influencer_email": "String (可选): 筛选与特定联系人的对话"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"id": "Integer: 对话ID",
|
||||||
|
"user_email": "String: 用户Gmail邮箱",
|
||||||
|
"influencer_email": "String: 对话方Gmail邮箱",
|
||||||
|
"last_message_time": "DateTime: 最后消息时间",
|
||||||
|
"message_count": "Integer: 消息数量"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"count": "Integer: 总记录数"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 接口作用
|
||||||
|
查询系统中保存的所有Gmail对话,可通过筛选参数查找特定用户或联系人的对话记录。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.3 获取对话摘要
|
||||||
|
|
||||||
|
- **接口URL**: `/api/gmail/conversations/summary/{conversation_id}/`
|
||||||
|
- **请求方式**: `GET`
|
||||||
|
- **接口描述**: 获取特定对话的AI生成摘要信息
|
||||||
|
|
||||||
|
#### 路径参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"conversation_id": "Integer (必填): 对话ID"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"conversation_id": "Integer: 对话ID",
|
||||||
|
"summary": "String: AI生成的对话摘要",
|
||||||
|
"key_points": ["String: 关键点1", "String: 关键点2"],
|
||||||
|
"sentiment": "String: 情感分析结果",
|
||||||
|
"last_updated": "DateTime: 最后更新时间"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 接口作用
|
||||||
|
使用AI技术自动分析对话内容,生成对话摘要、提取关键点并进行情感分析,帮助用户快速了解对话内容和进展。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 邮件管理
|
||||||
|
|
||||||
|
### 3.1 发送邮件
|
||||||
|
|
||||||
|
- **接口URL**: `/api/gmail/send/`
|
||||||
|
- **请求方式**: `POST`
|
||||||
|
- **接口描述**: 通过指定Gmail账户发送邮件
|
||||||
|
|
||||||
|
#### 请求参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"email": "String (必填): 发件人Gmail邮箱",
|
||||||
|
"to": "String (必填): 收件人邮箱,多个收件人用逗号分隔",
|
||||||
|
"subject": "String (必填): 邮件主题",
|
||||||
|
"body": "String (必填): 邮件正文内容(支持HTML)",
|
||||||
|
"cc": "String (可选): 抄送邮箱,多个用逗号分隔",
|
||||||
|
"bcc": "String (可选): 密送邮箱,多个用逗号分隔",
|
||||||
|
"attachments": ["String: 附件ID1", "String: 附件ID2"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"message_id": "String: 发送的邮件ID",
|
||||||
|
"thread_id": "String: Gmail线程ID",
|
||||||
|
"status": "String: 发送状态",
|
||||||
|
"timestamp": "DateTime: 发送时间戳"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 接口作用
|
||||||
|
使用已授权的Gmail账户发送邮件,支持HTML内容、抄送、密送和附件,返回发送状态和邮件ID。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3.2 获取附件列表
|
||||||
|
|
||||||
|
- **接口URL**: `/api/gmail/attachments/{conversation_id}/`
|
||||||
|
- **请求方式**: `GET`
|
||||||
|
- **接口描述**: 获取特定对话中的所有附件
|
||||||
|
|
||||||
|
#### 路径参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"conversation_id": "Integer (必填): 对话ID"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"id": "String: 附件ID",
|
||||||
|
"filename": "String: 文件名",
|
||||||
|
"size": "Integer: 文件大小(字节)",
|
||||||
|
"mime_type": "String: MIME类型",
|
||||||
|
"message_id": "String: 所属邮件ID",
|
||||||
|
"created_at": "DateTime: 创建时间"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"count": "Integer: 总记录数"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 接口作用
|
||||||
|
检索特定对话中的所有邮件附件信息,包括文件名、大小和类型,便于管理和下载附件。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 推送通知
|
||||||
|
|
||||||
|
### 4.1 设置Gmail推送通知
|
||||||
|
|
||||||
|
- **接口URL**: `/api/gmail/notifications/setup/`
|
||||||
|
- **请求方式**: `POST`
|
||||||
|
- **接口描述**: 为指定Gmail账户设置实时邮件推送通知
|
||||||
|
|
||||||
|
#### 请求参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"email": "String (必填): 要监听的Gmail邮箱地址",
|
||||||
|
"topic_name": "String (可选): 自定义Pub/Sub主题名称"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "String: 设置状态",
|
||||||
|
"topic": "String: Pub/Sub主题名称",
|
||||||
|
"expiration": "DateTime: 通知过期时间",
|
||||||
|
"message": "String: 操作结果信息"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 接口作用
|
||||||
|
使用Google Pub/Sub为Gmail账户设置实时通知,当有新邮件时,系统会接收到推送通知,从而实现邮件的实时处理。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4.2 接收Gmail推送通知
|
||||||
|
|
||||||
|
- **接口URL**: `/api/gmail/webhook/`
|
||||||
|
- **请求方式**: `POST`
|
||||||
|
- **接口描述**: 接收Google Pub/Sub推送的Gmail新邮件通知
|
||||||
|
|
||||||
|
#### 请求参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"message": {
|
||||||
|
"data": "String (必填): Base64编码的通知数据",
|
||||||
|
"attributes": "Object (可选): 消息属性"
|
||||||
|
},
|
||||||
|
"subscription": "String (必填): 订阅名称"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "String: 处理状态",
|
||||||
|
"received": "Boolean: 是否成功接收"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 接口作用
|
||||||
|
作为Webhook端点接收Google Pub/Sub推送的Gmail新邮件通知,解析通知内容并触发相应的处理逻辑,如自动回复和更新对话。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 自动回复功能
|
||||||
|
|
||||||
|
### 5.1 设置对话目标
|
||||||
|
|
||||||
|
- **接口URL**: `/api/gmail/goals/`
|
||||||
|
- **请求方式**: `POST`
|
||||||
|
- **接口描述**: 为特定对话设置AI自动回复的目标
|
||||||
|
|
||||||
|
#### 请求参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"conversation_id": "Integer (必填): 对话ID",
|
||||||
|
"goal_description": "String (必填): 目标描述文本",
|
||||||
|
"priority": "Integer (可选): 优先级(1-5)",
|
||||||
|
"auto_reply": "Boolean (可选): 是否启用自动回复"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "Integer: 目标ID",
|
||||||
|
"conversation_id": "Integer: 对话ID",
|
||||||
|
"goal_description": "String: 目标描述",
|
||||||
|
"priority": "Integer: 优先级",
|
||||||
|
"auto_reply": "Boolean: 是否启用自动回复",
|
||||||
|
"created_at": "DateTime: 创建时间",
|
||||||
|
"status": "String: 操作状态"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 接口作用
|
||||||
|
为指定的Gmail对话设置AI处理目标,系统会根据目标生成推荐回复或自动回复邮件,帮助用户实现特定的沟通目标。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5.2 获取对话目标列表
|
||||||
|
|
||||||
|
- **接口URL**: `/api/gmail/goals/`
|
||||||
|
- **请求方式**: `GET`
|
||||||
|
- **接口描述**: 获取所有设置的对话目标
|
||||||
|
|
||||||
|
#### 查询参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"conversation_id": "Integer (可选): 筛选特定对话的目标",
|
||||||
|
"active": "Boolean (可选): 筛选活跃/非活跃目标"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"id": "Integer: 目标ID",
|
||||||
|
"conversation_id": "Integer: 对话ID",
|
||||||
|
"goal_description": "String: 目标描述",
|
||||||
|
"priority": "Integer: 优先级",
|
||||||
|
"auto_reply": "Boolean: 是否启用自动回复",
|
||||||
|
"created_at": "DateTime: 创建时间"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"count": "Integer: 总记录数"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 接口作用
|
||||||
|
获取系统中设置的所有对话目标,可通过参数筛选特定对话的目标或活跃/非活跃目标。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5.3 获取推荐回复
|
||||||
|
|
||||||
|
- **接口URL**: `/api/gmail/recommended-reply/`
|
||||||
|
- **请求方式**: `POST`
|
||||||
|
- **接口描述**: 获取针对特定对话的AI推荐回复内容
|
||||||
|
|
||||||
|
#### 请求参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"conversation_id": "Integer (必填): 对话ID",
|
||||||
|
"last_message_id": "String (可选): 最后接收的邮件ID",
|
||||||
|
"custom_instructions": "String (可选): 自定义回复指示"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应参数
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"goal": {
|
||||||
|
"id": "Integer: 目标ID",
|
||||||
|
"description": "String: 目标描述"
|
||||||
|
},
|
||||||
|
"conversation_summary": "String: 对话摘要",
|
||||||
|
"last_message": {
|
||||||
|
"sender": "String: 发送者",
|
||||||
|
"subject": "String: 主题",
|
||||||
|
"content": "String: 内容摘要"
|
||||||
|
},
|
||||||
|
"recommended_reply": "String: AI推荐的回复内容",
|
||||||
|
"alternative_replies": ["String: 备选回复1", "String: 备选回复2"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 接口作用
|
||||||
|
基于对话历史、设定目标和最新邮件内容,使用AI生成推荐回复,帮助用户快速回应邮件并实现沟通目标。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 使用说明
|
||||||
|
|
||||||
|
1. **授权流程**:
|
||||||
|
- 先调用"启动OAuth授权"接口获取授权URL
|
||||||
|
- 用户访问URL并获取授权码
|
||||||
|
- 调用"完成OAuth授权"接口保存Gmail账户凭证
|
||||||
|
|
||||||
|
2. **实时通知设置**:
|
||||||
|
- 授权成功后调用"设置Gmail推送通知"接口
|
||||||
|
- 确保webhook端点可从公网访问
|
||||||
|
|
||||||
|
3. **自动回复流程**:
|
||||||
|
- 创建对话并设置目标
|
||||||
|
- 系统接收新邮件推送通知
|
||||||
|
- 自动分析内容并生成回复
|
||||||
|
- 根据设置决定是推荐回复还是自动回复
|
@ -1,3 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
128
apps/gmail/services/export_service.py
Normal file
128
apps/gmail/services/export_service.py
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
import os
|
||||||
|
import logging
|
||||||
|
import pandas as pd
|
||||||
|
from datetime import datetime
|
||||||
|
from django.db.models import Q, F
|
||||||
|
from django.utils import timezone
|
||||||
|
from apps.gmail.models import GmailConversation, GmailAttachment, ConversationSummary
|
||||||
|
from apps.chat.models import ChatHistory
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class GmailExportService:
|
||||||
|
"""
|
||||||
|
Gmail导出服务,提供将达人回复导出为Excel的功能
|
||||||
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def export_replied_influencers(user, format='xlsx'):
|
||||||
|
"""
|
||||||
|
导出已回复的达人Gmail列表
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user: 用户对象
|
||||||
|
format: 导出格式, 默认为xlsx
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple: (文件路径, 错误信息)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# 获取用户所有的Gmail对话
|
||||||
|
conversations = GmailConversation.objects.filter(
|
||||||
|
user=user,
|
||||||
|
is_active=True
|
||||||
|
)
|
||||||
|
|
||||||
|
if not conversations.exists():
|
||||||
|
return None, "未找到任何Gmail对话"
|
||||||
|
|
||||||
|
# 准备导出数据
|
||||||
|
export_data = []
|
||||||
|
|
||||||
|
for conversation in conversations:
|
||||||
|
# 查询达人是否有回复
|
||||||
|
chat_history = ChatHistory.objects.filter(
|
||||||
|
user=user,
|
||||||
|
conversation_id=conversation.conversation_id,
|
||||||
|
metadata__contains={"from": conversation.influencer_email}
|
||||||
|
).order_by('created_at')
|
||||||
|
|
||||||
|
# 如果达人有回复,则添加到导出列表
|
||||||
|
if chat_history.exists():
|
||||||
|
# 获取第一条回复的时间
|
||||||
|
first_reply = chat_history.first()
|
||||||
|
first_reply_time = first_reply.created_at.replace(tzinfo=None) if first_reply else None
|
||||||
|
|
||||||
|
# 获取最后一条回复的时间
|
||||||
|
last_reply = chat_history.last()
|
||||||
|
last_reply_time = last_reply.created_at.replace(tzinfo=None) if last_reply else None
|
||||||
|
|
||||||
|
# 获取回复次数
|
||||||
|
reply_count = chat_history.count()
|
||||||
|
|
||||||
|
# 直接从数据库中获取对话摘要,不调用外部API
|
||||||
|
summary = ""
|
||||||
|
try:
|
||||||
|
# 先从ConversationSummary模型中查找
|
||||||
|
conversation_summary = ConversationSummary.objects.filter(
|
||||||
|
conversation=conversation
|
||||||
|
).first()
|
||||||
|
|
||||||
|
if conversation_summary:
|
||||||
|
summary = conversation_summary.content
|
||||||
|
else:
|
||||||
|
# 如果没有摘要,尝试获取最新的几条消息内容
|
||||||
|
recent_messages = ChatHistory.objects.filter(
|
||||||
|
user=user,
|
||||||
|
conversation_id=conversation.conversation_id
|
||||||
|
).order_by('-created_at')[:5]
|
||||||
|
|
||||||
|
if recent_messages:
|
||||||
|
summary = "最近消息: " + " | ".join([msg.content[:100] + ("..." if len(msg.content) > 100 else "") for msg in recent_messages])
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"获取对话摘要失败: {str(e)}")
|
||||||
|
summary = '无法获取摘要'
|
||||||
|
|
||||||
|
# 构建导出记录 - 注意移除时区信息
|
||||||
|
export_record = {
|
||||||
|
'用户邮箱': conversation.user_email,
|
||||||
|
'达人邮箱': conversation.influencer_email,
|
||||||
|
'对话标题': conversation.title,
|
||||||
|
'对话开始时间': conversation.created_at.replace(tzinfo=None),
|
||||||
|
'首次回复时间': first_reply_time,
|
||||||
|
'最近回复时间': last_reply_time,
|
||||||
|
'回复次数': reply_count,
|
||||||
|
'对话摘要': summary,
|
||||||
|
'对话ID': conversation.conversation_id
|
||||||
|
}
|
||||||
|
|
||||||
|
export_data.append(export_record)
|
||||||
|
|
||||||
|
if not export_data:
|
||||||
|
return None, "没有找到已回复的达人"
|
||||||
|
|
||||||
|
# 创建DataFrame
|
||||||
|
df = pd.DataFrame(export_data)
|
||||||
|
|
||||||
|
# 生成文件名和路径
|
||||||
|
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||||
|
file_name = f"influencer_replies_{timestamp}.{format}"
|
||||||
|
export_dir = os.path.join('media', 'exports')
|
||||||
|
os.makedirs(export_dir, exist_ok=True)
|
||||||
|
file_path = os.path.join(export_dir, file_name)
|
||||||
|
|
||||||
|
# 根据格式导出
|
||||||
|
if format == 'xlsx':
|
||||||
|
df.to_excel(file_path, index=False, engine='openpyxl')
|
||||||
|
elif format == 'csv':
|
||||||
|
df.to_csv(file_path, index=False, encoding='utf-8-sig')
|
||||||
|
else:
|
||||||
|
return None, f"不支持的导出格式: {format}"
|
||||||
|
|
||||||
|
return file_path, None
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"导出已回复达人失败: {str(e)}")
|
||||||
|
import traceback
|
||||||
|
logger.error(traceback.format_exc())
|
||||||
|
return None, f"导出失败: {str(e)}"
|
@ -11,7 +11,8 @@ from .views import (
|
|||||||
GmailConversationSummaryView,
|
GmailConversationSummaryView,
|
||||||
GmailGoalView,
|
GmailGoalView,
|
||||||
SimpleRecommendedReplyView,
|
SimpleRecommendedReplyView,
|
||||||
GmailCredentialViewSet
|
GmailCredentialViewSet,
|
||||||
|
GmailExportView
|
||||||
)
|
)
|
||||||
|
|
||||||
app_name = 'gmail'
|
app_name = 'gmail'
|
||||||
@ -34,6 +35,7 @@ urlpatterns = [
|
|||||||
path('conversations/summary/<str:conversation_id>/', GmailConversationSummaryView.as_view(), name='conversation_summary_detail'),
|
path('conversations/summary/<str:conversation_id>/', GmailConversationSummaryView.as_view(), name='conversation_summary_detail'),
|
||||||
path('goals/', GmailGoalView.as_view(), name='user_goals'),
|
path('goals/', GmailGoalView.as_view(), name='user_goals'),
|
||||||
path('recommended-reply/', SimpleRecommendedReplyView.as_view(), name='recommended_reply'),
|
path('recommended-reply/', SimpleRecommendedReplyView.as_view(), name='recommended_reply'),
|
||||||
|
path('export/', GmailExportView.as_view(), name='export_replied_influencers'),
|
||||||
# 包含Router生成的URL
|
# 包含Router生成的URL
|
||||||
path('', include(router.urls)),
|
path('', include(router.urls)),
|
||||||
]
|
]
|
@ -1393,3 +1393,79 @@ class SimpleRecommendedReplyView(APIView):
|
|||||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||||
|
|
||||||
|
|
||||||
|
class GmailExportView(APIView):
|
||||||
|
"""
|
||||||
|
API视图,用于导出已回复的达人Gmail列表为Excel文件。
|
||||||
|
"""
|
||||||
|
permission_classes = [IsAuthenticated] # 限制访问,仅允许已认证用户
|
||||||
|
|
||||||
|
def get(self, request, format=None):
|
||||||
|
"""
|
||||||
|
处理GET请求,导出已回复的达人Gmail列表。
|
||||||
|
|
||||||
|
Query参数:
|
||||||
|
- format: 导出格式,支持 'xlsx' 或 'csv',默认为 'xlsx'
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
HttpResponse: 包含Excel文件的响应(成功时),或错误消息的JSON响应(失败时)。
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# 获取导出格式参数
|
||||||
|
export_format = request.query_params.get('format', 'xlsx')
|
||||||
|
if export_format not in ['xlsx', 'csv']:
|
||||||
|
return Response({
|
||||||
|
'code': 400,
|
||||||
|
'message': f'不支持的导出格式: {export_format},支持的格式有: xlsx, csv',
|
||||||
|
'data': None
|
||||||
|
}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
logger.info(f"用户 {request.user.username} 请求导出已回复达人列表,格式: {export_format}")
|
||||||
|
|
||||||
|
# 直接从具体文件导入而不依赖__init__.py
|
||||||
|
from .services.export_service import GmailExportService
|
||||||
|
file_path, error = GmailExportService.export_replied_influencers(request.user, format=export_format)
|
||||||
|
|
||||||
|
if error:
|
||||||
|
logger.error(f"导出失败: {error}")
|
||||||
|
return Response({
|
||||||
|
'code': 500,
|
||||||
|
'message': error,
|
||||||
|
'data': None
|
||||||
|
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||||
|
|
||||||
|
if not file_path or not os.path.exists(file_path):
|
||||||
|
logger.error(f"导出文件不存在: {file_path}")
|
||||||
|
return Response({
|
||||||
|
'code': 500,
|
||||||
|
'message': '导出文件生成失败',
|
||||||
|
'data': None
|
||||||
|
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||||
|
|
||||||
|
# 读取生成的文件
|
||||||
|
with open(file_path, 'rb') as f:
|
||||||
|
file_data = f.read()
|
||||||
|
|
||||||
|
# 设置响应头,启用文件下载
|
||||||
|
response = HttpResponse(
|
||||||
|
file_data,
|
||||||
|
content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' if export_format == 'xlsx' else 'text/csv'
|
||||||
|
)
|
||||||
|
filename = os.path.basename(file_path)
|
||||||
|
response['Content-Disposition'] = f'attachment; filename="{filename}"'
|
||||||
|
|
||||||
|
logger.info(f"成功导出文件: {filename}")
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"导出过程中发生错误: {str(e)}")
|
||||||
|
error_details = traceback.format_exc()
|
||||||
|
return Response({
|
||||||
|
'code': 500,
|
||||||
|
'message': f'导出失败: {str(e)}',
|
||||||
|
'data': {
|
||||||
|
'details': error_details[:500]
|
||||||
|
}
|
||||||
|
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user