Compare commits

..

2 Commits

8 changed files with 291 additions and 101 deletions

View File

@@ -145,6 +145,10 @@ jobs:
needs: check-changes needs: check-changes
if: needs.check-changes.outputs.has_changes == 'true' || github.event_name == 'workflow_dispatch' || startsWith(github.ref, 'refs/tags/v') if: needs.check-changes.outputs.has_changes == 'true' || github.event_name == 'workflow_dispatch' || startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest runs-on: ubuntu-latest
env:
LANG: en_US.UTF-8
LC_ALL: en_US.UTF-8
steps: steps:
- name: Checkout repository - name: Checkout repository

View File

@@ -6,6 +6,11 @@
Export chat conversations to Excel spreadsheet format for analysis, archiving, and sharing. Export chat conversations to Excel spreadsheet format for analysis, archiving, and sharing.
### What's New in v0.3.5
- **Export Scope**: Added `EXPORT_SCOPE` valve to choose between exporting tables from the "Last Message" (default) or "All Messages".
- **Smart Sheet Naming**: Automatically names sheets based on Markdown headers, AI titles (if enabled), or message index (e.g., `Msg1-Tab1`).
- **Multiple Tables Support**: Improved handling of multiple tables within single or multiple messages.
## What's New in v0.3.4 ## What's New in v0.3.4
- **Smart Filename Generation**: Now supports generating filenames based on Chat Title, AI Summary, or Markdown Headers. - **Smart Filename Generation**: Now supports generating filenames based on Chat Title, AI Summary, or Markdown Headers.

View File

@@ -6,7 +6,12 @@
将聊天记录导出为 Excel 表格,便于分析、归档和分享。 将聊天记录导出为 Excel 表格,便于分析、归档和分享。
## v0.3.4 更新内容 ### v0.3.5 更新内容
- **导出范围**: 新增 `EXPORT_SCOPE` 配置项,可选择导出“最后一条消息”(默认)或“所有消息”中的表格。
- **智能 Sheet 命名**: 根据 Markdown 标题、AI 标题(如启用)或消息索引(如 `消息1-表1`)自动命名 Sheet。
- **多表格支持**: 优化了对单条或多条消息中包含多个表格的处理。
### v0.3.4 更新内容
- **智能文件名生成**支持根据对话标题、AI 总结或 Markdown 标题生成文件名。 - **智能文件名生成**支持根据对话标题、AI 总结或 Markdown 标题生成文件名。
- **配置选项**:新增 `TITLE_SOURCE` 设置,用于控制文件名生成策略。 - **配置选项**:新增 `TITLE_SOURCE` 设置,用于控制文件名生成策略。

View File

@@ -53,7 +53,7 @@ Actions are interactive plugins that:
Export chat conversations to Excel spreadsheet format for analysis and archiving. Export chat conversations to Excel spreadsheet format for analysis and archiving.
**Version:** 0.3.4 **Version:** 0.3.5
[:octicons-arrow-right-24: Documentation](export-to-excel.md) [:octicons-arrow-right-24: Documentation](export-to-excel.md)

View File

@@ -2,6 +2,11 @@
This plugin allows you to export your chat history to an Excel (.xlsx) file directly from the chat interface. This plugin allows you to export your chat history to an Excel (.xlsx) file directly from the chat interface.
### What's New in v0.3.5
- **Export Scope**: Added `EXPORT_SCOPE` valve to choose between exporting tables from the "Last Message" (default) or "All Messages".
- **Smart Sheet Naming**: Automatically names sheets based on Markdown headers, AI titles (if enabled), or message index (e.g., `Msg1-Tab1`).
- **Multiple Tables Support**: Improved handling of multiple tables within single or multiple messages.
## What's New in v0.3.4 ## What's New in v0.3.4
- **Smart Filename Generation**: Now supports generating filenames based on Chat Title, AI Summary, or Markdown Headers. - **Smart Filename Generation**: Now supports generating filenames based on Chat Title, AI Summary, or Markdown Headers.

View File

@@ -2,6 +2,11 @@
此插件允许你直接从聊天界面将对话历史导出为 Excel (.xlsx) 文件。 此插件允许你直接从聊天界面将对话历史导出为 Excel (.xlsx) 文件。
### v0.3.5 更新内容
- **导出范围**: 新增 `EXPORT_SCOPE` 配置项,可选择导出“最后一条消息”(默认)或“所有消息”中的表格。
- **智能 Sheet 命名**: 根据 Markdown 标题、AI 标题(如启用)或消息索引(如 `消息1-表1`)自动命名 Sheet。
- **多表格支持**: 优化了对单条或多条消息中包含多个表格的处理。
## v0.3.4 更新内容 ## v0.3.4 更新内容
- **智能文件名生成**支持根据对话标题、AI 总结或 Markdown 标题生成文件名。 - **智能文件名生成**支持根据对话标题、AI 总结或 Markdown 标题生成文件名。

View File

@@ -3,7 +3,7 @@ title: Export to Excel
author: Fu-Jie author: Fu-Jie
author_url: https://github.com/Fu-Jie author_url: https://github.com/Fu-Jie
funding_url: https://github.com/Fu-Jie/awesome-openwebui funding_url: https://github.com/Fu-Jie/awesome-openwebui
version: 0.3.4 version: 0.3.5
icon_url: data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik0xNSAySDZhMiAyIDAgMCAwLTIgMnYxNmEyIDIgMCAwIDAgMiAyaDEyYTIgMiAwIDAgMCAyLTJWN1oiLz48cGF0aCBkPSJNMTQgMnY0YTIgMiAwIDAgMCAyIDJoNCIvPjxwYXRoIGQ9Ik04IDEzaDIiLz48cGF0aCBkPSJNMTQgMTNoMiIvPjxwYXRoIGQ9Ik04IDE3aDIiLz48cGF0aCBkPSJNMTQgMTdoMiIvPjwvc3ZnPg== icon_url: data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik0xNSAySDZhMiAyIDAgMCAwLTIgMnYxNmEyIDIgMCAwIDAgMiAyaDEyYTIgMiAwIDAgMCAyLTJWN1oiLz48cGF0aCBkPSJNMTQgMnY0YTIgMiAwIDAgMCAyIDJoNCIvPjxwYXRoIGQ9Ik04IDEzaDIiLz48cGF0aCBkPSJNMTQgMTNoMiIvPjxwYXRoIGQ9Ik04IDE3aDIiLz48cGF0aCBkPSJNMTQgMTdoMiIvPjwvc3ZnPg==
description: Exports the current chat history to an Excel (.xlsx) file, with automatic header extraction. description: Exports the current chat history to an Excel (.xlsx) file, with automatic header extraction.
""" """
@@ -30,6 +30,10 @@ class Action:
default="chat_title", default="chat_title",
description="Title Source: 'chat_title' (Chat Title), 'ai_generated' (AI Generated), 'markdown_title' (Markdown Title)", description="Title Source: 'chat_title' (Chat Title), 'ai_generated' (AI Generated), 'markdown_title' (Markdown Title)",
) )
EXPORT_SCOPE: str = Field(
default="last_message",
description="Export Scope: 'last_message' (Last Message Only), 'all_messages' (All Messages)",
)
def __init__(self): def __init__(self):
self.valves = self.Valves() self.valves = self.Valves()
@@ -64,8 +68,6 @@ class Action:
user_id = __user__.get("id", "unknown_user") user_id = __user__.get("id", "unknown_user")
if __event_emitter__: if __event_emitter__:
last_assistant_message = body["messages"][-1]
await __event_emitter__( await __event_emitter__(
{ {
"type": "status", "type": "status",
@@ -74,19 +76,115 @@ class Action:
) )
try: try:
message_content = last_assistant_message["content"] messages = body.get("messages", [])
tables = self.extract_tables_from_message(message_content) if not messages:
raise HTTPException(status_code=400, detail="No messages found.")
if not tables: # Determine messages to process based on scope
raise HTTPException(status_code=400, detail="No tables found.") target_messages = []
if self.valves.EXPORT_SCOPE == "all_messages":
target_messages = messages
else:
target_messages = [messages[-1]]
# Generate filename all_tables = []
all_sheet_names = []
# Process messages
for msg_index, msg in enumerate(target_messages):
content = msg.get("content", "")
tables = self.extract_tables_from_message(content)
if not tables:
continue
# Generate sheet names for this message's tables
# If multiple messages, we need to ensure uniqueness across the whole workbook
# We'll generate base names here and deduplicate later if needed,
# or better: generate unique names on the fly.
# Extract headers for this message
headers = []
lines = content.split("\n")
for i, line in enumerate(lines):
if re.match(r"^#{1,6}\s+", line):
headers.append(
{
"text": re.sub(r"^#{1,6}\s+", "", line).strip(),
"line_num": i,
}
)
for table_index, table in enumerate(tables):
sheet_name = ""
# 1. Try Markdown Header (closest above)
table_start_line = table["start_line"] - 1
closest_header_text = None
candidate_headers = [
h for h in headers if h["line_num"] < table_start_line
]
if candidate_headers:
closest_header = max(
candidate_headers, key=lambda x: x["line_num"]
)
closest_header_text = closest_header["text"]
if closest_header_text:
sheet_name = self.clean_sheet_name(closest_header_text)
# 2. AI Generated (Only if explicitly enabled and we have a request object)
# Note: Generating titles for EVERY table in all messages might be too slow/expensive.
# We'll skip this for 'all_messages' scope to avoid timeout, unless it's just one message.
if (
not sheet_name
and self.valves.TITLE_SOURCE == "ai_generated"
and len(target_messages) == 1
):
# Logic for AI generation (simplified for now, reusing existing flow if possible)
pass
# 3. Fallback: Message Index
if not sheet_name:
if len(target_messages) > 1:
# Use global message index (from original list if possible, but here we iterate target_messages)
# Let's use the loop index.
# If multiple tables in one message: "Msg 1 - Table 1"
if len(tables) > 1:
sheet_name = f"Msg{msg_index+1}-Tab{table_index+1}"
else:
sheet_name = f"Msg{msg_index+1}"
else:
# Single message (last_message scope)
if len(tables) > 1:
sheet_name = f"Table {table_index+1}"
else:
sheet_name = "Sheet1"
all_tables.append(table)
all_sheet_names.append(sheet_name)
if not all_tables:
raise HTTPException(
status_code=400, detail="No tables found in the selected scope."
)
# Deduplicate sheet names
final_sheet_names = []
seen_names = {}
for name in all_sheet_names:
base_name = name
counter = 1
while name in seen_names:
name = f"{base_name} ({counter})"
counter += 1
seen_names[name] = True
final_sheet_names.append(name)
# Generate Workbook Title (Filename)
# Use the title of the chat, or the first header of the first message with tables
title = "" title = ""
chat_id = self.extract_chat_id( chat_id = self.extract_chat_id(body, None)
body, None
) # metadata not available in action signature yet, but usually in body
# Fetch chat_title directly via chat_id as it's usually missing in body
chat_title = "" chat_title = ""
if chat_id: if chat_id:
chat_title = await self.fetch_chat_title(chat_id, user_id) chat_title = await self.fetch_chat_title(chat_id, user_id)
@@ -97,43 +195,29 @@ class Action:
): ):
title = chat_title title = chat_title
elif self.valves.TITLE_SOURCE == "markdown_title": elif self.valves.TITLE_SOURCE == "markdown_title":
title = self.extract_title(message_content) # Try to find first header in the first message that has content
elif self.valves.TITLE_SOURCE == "ai_generated": for msg in target_messages:
# We need request object for AI generation, but it's not passed in standard action signature in this version extracted = self.extract_title(msg.get("content", ""))
# However, we can try to use the one from global context if available or skip if extracted:
# For now, let's assume we might not have it and fallback or use what we have title = extracted
# Wait, export_to_word uses __request__. Let's check if we can add it to signature. break
pass
# Get dynamic filename and sheet names # Fallback for filename
workbook_name_from_content, sheet_names = (
self.generate_names_from_content(message_content, tables)
)
# If AI generation is selected but we need request, we need to update signature.
# Let's update signature in next chunk.
# Fallback logic for title
if not title: if not title:
if self.valves.TITLE_SOURCE == "ai_generated": if chat_title:
# AI generation needs request, handled later
pass
elif self.valves.TITLE_SOURCE == "markdown_title":
pass # Already tried
# If still no title, try workbook_name_from_content (which uses headers)
if not title and workbook_name_from_content:
title = workbook_name_from_content
# If still no title, use chat_title if available
if not title and chat_title:
title = chat_title title = chat_title
else:
# Try extracting from content again if not already tried
if self.valves.TITLE_SOURCE != "markdown_title":
for msg in target_messages:
extracted = self.extract_title(msg.get("content", ""))
if extracted:
title = extracted
break
# Use optimized filename generation logic
current_datetime = datetime.datetime.now() current_datetime = datetime.datetime.now()
formatted_date = current_datetime.strftime("%Y%m%d") formatted_date = current_datetime.strftime("%Y%m%d")
# If no title found, use user_yyyymmdd format
if not title: if not title:
workbook_name = f"{user_name}_{formatted_date}" workbook_name = f"{user_name}_{formatted_date}"
else: else:
@@ -146,8 +230,10 @@ class Action:
os.makedirs(os.path.dirname(excel_file_path), exist_ok=True) os.makedirs(os.path.dirname(excel_file_path), exist_ok=True)
# Save tables to Excel (using enhanced formatting) # Save tables to Excel
self.save_tables_to_excel_enhanced(tables, excel_file_path, sheet_names) self.save_tables_to_excel_enhanced(
all_tables, excel_file_path, final_sheet_names
)
# Trigger file download # Trigger file download
if __event_call__: if __event_call__:

View File

@@ -3,7 +3,7 @@ title: 导出为 Excel
author: Fu-Jie author: Fu-Jie
author_url: https://github.com/Fu-Jie author_url: https://github.com/Fu-Jie
funding_url: https://github.com/Fu-Jie/awesome-openwebui funding_url: https://github.com/Fu-Jie/awesome-openwebui
version: 0.3.4 version: 0.3.5
icon_url: data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik0xNSAySDZhMiAyIDAgMCAwLTIgMnYxNmEyIDIgMCAwIDAgMiAyaDEyYTIgMiAwIDAgMCAyLTJWN1oiLz48cGF0aCBkPSJNMTQgMnY0YTIgMiAwIDAgMCAyIDJoNCIvPjxwYXRoIGQ9Ik04IDEzaDIiLz48cGF0aCBkPSJNMTQgMTNoMiIvPjxwYXRoIGQ9Ik04IDE3aDIiLz48cGF0aCBkPSJNMTQgMTdoMiIvPjwvc3ZnPg== icon_url: data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik0xNSAySDZhMiAyIDAgMCAwLTIgMnYxNmEyIDIgMCAwIDAgMiAyaDEyYTIgMiAwIDAgMCAyLTJWN1oiLz48cGF0aCBkPSJNMTQgMnY0YTIgMiAwIDAgMCAyIDJoNCIvPjxwYXRoIGQ9Ik04IDEzaDIiLz48cGF0aCBkPSJNMTQgMTNoMiIvPjxwYXRoIGQ9Ik04IDE3aDIiLz48cGF0aCBkPSJNMTQgMTdoMiIvPjwvc3ZnPg==
description: 将当前对话历史导出为 Excel (.xlsx) 文件,支持自动提取表头。 description: 将当前对话历史导出为 Excel (.xlsx) 文件,支持自动提取表头。
""" """
@@ -28,7 +28,11 @@ class Action:
class Valves(BaseModel): class Valves(BaseModel):
TITLE_SOURCE: str = Field( TITLE_SOURCE: str = Field(
default="chat_title", default="chat_title",
description="标题来源'chat_title' (对话标题), 'ai_generated' (AI生成), 'markdown_title' (Markdown标题)", description="标题来源: 'chat_title' (对话标题), 'ai_generated' (AI生成), 'markdown_title' (Markdown标题)",
)
EXPORT_SCOPE: str = Field(
default="last_message",
description="导出范围: 'last_message' (仅最后一条消息), 'all_messages' (所有消息)",
) )
def __init__(self): def __init__(self):
@@ -50,43 +54,127 @@ class Action:
print(f"action:{__name__}") print(f"action:{__name__}")
if isinstance(__user__, (list, tuple)): if isinstance(__user__, (list, tuple)):
user_language = ( user_language = (
__user__[0].get("language", "zh-CN") if __user__ else "zh-CN" __user__[0].get("language", "en-US") if __user__ else "en-US"
) )
user_name = __user__[0].get("name", "用户") if __user__[0] else "用户" user_name = __user__[0].get("name", "User") if __user__[0] else "User"
user_id = ( user_id = (
__user__[0]["id"] __user__[0]["id"]
if __user__ and "id" in __user__[0] if __user__ and "id" in __user__[0]
else "unknown_user" else "unknown_user"
) )
elif isinstance(__user__, dict): elif isinstance(__user__, dict):
user_language = __user__.get("language", "zh-CN") user_language = __user__.get("language", "en-US")
user_name = __user__.get("name", "用户") user_name = __user__.get("name", "User")
user_id = __user__.get("id", "unknown_user") user_id = __user__.get("id", "unknown_user")
if __event_emitter__: if __event_emitter__:
last_assistant_message = body["messages"][-1]
await __event_emitter__( await __event_emitter__(
{ {
"type": "status", "type": "status",
"data": {"description": "正在保存文件...", "done": False}, "data": {"description": "正在保存文件...", "done": False},
} }
) )
try: try:
message_content = last_assistant_message["content"] messages = body.get("messages", [])
tables = self.extract_tables_from_message(message_content) if not messages:
raise HTTPException(status_code=400, detail="未找到消息。")
if not tables: # Determine messages to process based on scope
raise HTTPException(status_code=400, detail="未找到任何表格。") target_messages = []
if self.valves.EXPORT_SCOPE == "all_messages":
target_messages = messages
else:
target_messages = [messages[-1]]
# 生成文件名 all_tables = []
all_sheet_names = []
# Process messages
for msg_index, msg in enumerate(target_messages):
content = msg.get("content", "")
tables = self.extract_tables_from_message(content)
if not tables:
continue
# Generate sheet names for this message's tables
# Extract headers for this message
headers = []
lines = content.split("\n")
for i, line in enumerate(lines):
if re.match(r"^#{1,6}\s+", line):
headers.append(
{
"text": re.sub(r"^#{1,6}\s+", "", line).strip(),
"line_num": i,
}
)
for table_index, table in enumerate(tables):
sheet_name = ""
# 1. Try Markdown Header (closest above)
table_start_line = table["start_line"] - 1
closest_header_text = None
candidate_headers = [
h for h in headers if h["line_num"] < table_start_line
]
if candidate_headers:
closest_header = max(
candidate_headers, key=lambda x: x["line_num"]
)
closest_header_text = closest_header["text"]
if closest_header_text:
sheet_name = self.clean_sheet_name(closest_header_text)
# 2. AI Generated (Only if explicitly enabled and we have a request object)
if (
not sheet_name
and self.valves.TITLE_SOURCE == "ai_generated"
and len(target_messages) == 1
):
pass
# 3. Fallback: Message Index
if not sheet_name:
if len(target_messages) > 1:
if len(tables) > 1:
sheet_name = f"消息{msg_index+1}-表{table_index+1}"
else:
sheet_name = f"消息{msg_index+1}"
else:
# Single message (last_message scope)
if len(tables) > 1:
sheet_name = f"{table_index+1}"
else:
sheet_name = "Sheet1"
all_tables.append(table)
all_sheet_names.append(sheet_name)
if not all_tables:
raise HTTPException(
status_code=400, detail="在选定范围内未找到表格。"
)
# Deduplicate sheet names
final_sheet_names = []
seen_names = {}
for name in all_sheet_names:
base_name = name
counter = 1
while name in seen_names:
name = f"{base_name} ({counter})"
counter += 1
seen_names[name] = True
final_sheet_names.append(name)
# Generate Workbook Title (Filename)
title = "" title = ""
chat_id = self.extract_chat_id( chat_id = self.extract_chat_id(body, None)
body, None
) # metadata 在此版本 action 签名中不可用,但通常在 body 中
# 直接通过 chat_id 获取对话标题,因为 body 中通常缺少该信息
chat_title = "" chat_title = ""
if chat_id: if chat_id:
chat_title = await self.fetch_chat_title(chat_id, user_id) chat_title = await self.fetch_chat_title(chat_id, user_id)
@@ -97,37 +185,27 @@ class Action:
): ):
title = chat_title title = chat_title
elif self.valves.TITLE_SOURCE == "markdown_title": elif self.valves.TITLE_SOURCE == "markdown_title":
title = self.extract_title(message_content) for msg in target_messages:
elif self.valves.TITLE_SOURCE == "ai_generated": extracted = self.extract_title(msg.get("content", ""))
# AI 生成需要 request 对象,稍后处理 if extracted:
pass title = extracted
break
# 获取动态文件名和sheet名称 # Fallback for filename
workbook_name_from_content, sheet_names = (
self.generate_names_from_content(message_content, tables)
)
# 标题回退逻辑
if not title: if not title:
if self.valves.TITLE_SOURCE == "ai_generated": if chat_title:
# AI 生成需要 request稍后处理
pass
elif self.valves.TITLE_SOURCE == "markdown_title":
pass # 已尝试
# 如果仍无标题,尝试使用 workbook_name_from_content (基于表头)
if not title and workbook_name_from_content:
title = workbook_name_from_content
# 如果仍无标题,尝试使用 chat_title
if not title and chat_title:
title = chat_title title = chat_title
else:
if self.valves.TITLE_SOURCE != "markdown_title":
for msg in target_messages:
extracted = self.extract_title(msg.get("content", ""))
if extracted:
title = extracted
break
# 使用优化后的文件名生成逻辑
current_datetime = datetime.datetime.now() current_datetime = datetime.datetime.now()
formatted_date = current_datetime.strftime("%Y%m%d") formatted_date = current_datetime.strftime("%Y%m%d")
# 如果没找到标题则使用 user_yyyymmdd 格式
if not title: if not title:
workbook_name = f"{user_name}_{formatted_date}" workbook_name = f"{user_name}_{formatted_date}"
else: else:
@@ -140,10 +218,12 @@ class Action:
os.makedirs(os.path.dirname(excel_file_path), exist_ok=True) os.makedirs(os.path.dirname(excel_file_path), exist_ok=True)
# 保存表格到Excel使用符合中国规范的格式化功能 # Save tables to Excel
self.save_tables_to_excel_enhanced(tables, excel_file_path, sheet_names) self.save_tables_to_excel_enhanced(
all_tables, excel_file_path, final_sheet_names
)
# 触发文件下载 # Trigger file download
if __event_call__: if __event_call__:
with open(excel_file_path, "rb") as file: with open(excel_file_path, "rb") as file:
file_content = file.read() file_content = file.read()
@@ -174,7 +254,7 @@ class Action:
URL.revokeObjectURL(url); URL.revokeObjectURL(url);
document.body.removeChild(a); document.body.removeChild(a);
}} catch (error) {{ }} catch (error) {{
console.error('触发下载时出错:', error); console.error('Error triggering download:', error);
}} }}
""" """
}, },
@@ -183,15 +263,15 @@ class Action:
await __event_emitter__( await __event_emitter__(
{ {
"type": "status", "type": "status",
"data": {"description": "输出已保存", "done": True}, "data": {"description": "文件已保存", "done": True},
} }
) )
# 清理临时文件 # Clean up temp file
if os.path.exists(excel_file_path): if os.path.exists(excel_file_path):
os.remove(excel_file_path) os.remove(excel_file_path)
return {"message": "下载事件已触发"} return {"message": "下载已触发"}
except HTTPException as e: except HTTPException as e:
print(f"Error processing tables: {str(e.detail)}") print(f"Error processing tables: {str(e.detail)}")
@@ -199,13 +279,13 @@ class Action:
{ {
"type": "status", "type": "status",
"data": { "data": {
"description": f"保存文件时出错: {e.detail}", "description": f"保存文件错: {e.detail}",
"done": True, "done": True,
}, },
} }
) )
await self._send_notification( await self._send_notification(
__event_emitter__, "error", "没有找到可导出的表格!" __event_emitter__, "error", "找到可导出的表格"
) )
raise e raise e
except Exception as e: except Exception as e:
@@ -214,13 +294,13 @@ class Action:
{ {
"type": "status", "type": "status",
"data": { "data": {
"description": f"保存文件时出错: {str(e)}", "description": f"保存文件错: {str(e)}",
"done": True, "done": True,
}, },
} }
) )
await self._send_notification( await self._send_notification(
__event_emitter__, "error", "没有找到可导出的表格!" __event_emitter__, "error", "找到可导出的表格"
) )
async def generate_title_using_ai( async def generate_title_using_ai(