feat: Add Excel export support and fix variable reference regex

Changes:
- Add Excel export output format option to Message component
- Apply nest_asyncio patch to handle nested event loops
- Fix async generator iteration in canvas_app.py debug endpoint
- Add underscore support in variable reference regex pattern
This commit is contained in:
Shivam Johri 2025-12-11 21:23:34 +05:30
parent bd0eff2954
commit aef9286181
4 changed files with 53 additions and 4 deletions

View file

@ -393,7 +393,7 @@ class ComponentParamBase(ABC):
class ComponentBase(ABC):
component_name: str
thread_limiter = asyncio.Semaphore(int(os.environ.get("MAX_CONCURRENT_CHATS", 10)))
variable_ref_patt = r"\{* *\{([a-zA-Z:0-9]+@[A-Za-z0-9_.]+|sys\.[A-Za-z0-9_.]+|env\.[A-Za-z0-9_.]+)\} *\}*"
variable_ref_patt = r"\{* *\{([a-zA-Z_:0-9]+@[A-Za-z0-9_.]+|sys\.[A-Za-z0-9_.]+|env\.[A-Za-z0-9_.]+)\} *\}*"
def __str__(self):
"""

View file

@ -14,6 +14,8 @@
# limitations under the License.
#
import asyncio
import nest_asyncio
nest_asyncio.apply()
import inspect
import json
import os
@ -207,7 +209,7 @@ class Message(ComponentBase):
import pypandoc
doc_id = get_uuid()
if self._param.output_format.lower() not in {"markdown", "html", "pdf", "docx"}:
if self._param.output_format.lower() not in {"markdown", "html", "pdf", "docx", "xlsx"}:
self._param.output_format = "markdown"
try:
@ -227,6 +229,46 @@ class Message(ComponentBase):
binary_content = converted.encode("utf-8")
elif self._param.output_format == "xlsx":
import pandas as pd
from io import BytesIO
if isinstance(content, str):
try:
# Convert markdown to HTML tables to help pandas parse it
html_content = pypandoc.convert_text(content, to="html", format="markdown")
dfs = pd.read_html(html_content)
except Exception as e:
dfs = []
if not dfs:
df = pd.DataFrame({"Content": [content]})
dfs = [df]
else:
# Should not accept file path for Excel generation from agent response usually,
# but if it does, read it as text
with open(content, "r") as f:
txt_content = f.read()
try:
html_content = pypandoc.convert_text(txt_content, to="html", format="markdown")
dfs = pd.read_html(html_content)
except Exception:
dfs = []
if not dfs:
df = pd.DataFrame({"Content": [txt_content]})
dfs = [df]
# Write to Excel
excel_io = BytesIO()
with pd.ExcelWriter(excel_io, engine='openpyxl') as writer:
for i, df in enumerate(dfs):
sheet_name = f"Sheet{i+1}"
df.to_excel(writer, sheet_name=sheet_name, index=False)
excel_io.seek(0)
binary_content = excel_io.read()
else: # pdf, docx
with tempfile.NamedTemporaryFile(suffix=f".{self._param.output_format}", delete=False) as tmp:
tmp_name = tmp.name

View file

@ -14,6 +14,7 @@
# limitations under the License.
#
import asyncio
import inspect
import json
import logging
from functools import partial
@ -299,8 +300,13 @@ async def debug():
for k in outputs.keys():
if isinstance(outputs[k], partial):
txt = ""
for c in outputs[k]():
txt += c
iter_obj = outputs[k]()
if inspect.isasyncgen(iter_obj):
async for c in iter_obj:
txt += c
else:
for c in iter_obj:
txt += c
outputs[k] = txt
return get_json_result(data=outputs)
except Exception as e:

View file

@ -832,6 +832,7 @@ export enum ExportFileType {
HTML = 'html',
Markdown = 'md',
DOCX = 'docx',
Excel = 'xlsx',
}
export enum TypesWithArray {