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:
parent
bd0eff2954
commit
aef9286181
4 changed files with 53 additions and 4 deletions
|
|
@ -393,7 +393,7 @@ class ComponentParamBase(ABC):
|
||||||
class ComponentBase(ABC):
|
class ComponentBase(ABC):
|
||||||
component_name: str
|
component_name: str
|
||||||
thread_limiter = asyncio.Semaphore(int(os.environ.get("MAX_CONCURRENT_CHATS", 10)))
|
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):
|
def __str__(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import nest_asyncio
|
||||||
|
nest_asyncio.apply()
|
||||||
import inspect
|
import inspect
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
|
@ -207,7 +209,7 @@ class Message(ComponentBase):
|
||||||
import pypandoc
|
import pypandoc
|
||||||
doc_id = get_uuid()
|
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"
|
self._param.output_format = "markdown"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -227,6 +229,46 @@ class Message(ComponentBase):
|
||||||
|
|
||||||
binary_content = converted.encode("utf-8")
|
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
|
else: # pdf, docx
|
||||||
with tempfile.NamedTemporaryFile(suffix=f".{self._param.output_format}", delete=False) as tmp:
|
with tempfile.NamedTemporaryFile(suffix=f".{self._param.output_format}", delete=False) as tmp:
|
||||||
tmp_name = tmp.name
|
tmp_name = tmp.name
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import inspect
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
@ -299,8 +300,13 @@ async def debug():
|
||||||
for k in outputs.keys():
|
for k in outputs.keys():
|
||||||
if isinstance(outputs[k], partial):
|
if isinstance(outputs[k], partial):
|
||||||
txt = ""
|
txt = ""
|
||||||
for c in outputs[k]():
|
iter_obj = outputs[k]()
|
||||||
txt += c
|
if inspect.isasyncgen(iter_obj):
|
||||||
|
async for c in iter_obj:
|
||||||
|
txt += c
|
||||||
|
else:
|
||||||
|
for c in iter_obj:
|
||||||
|
txt += c
|
||||||
outputs[k] = txt
|
outputs[k] = txt
|
||||||
return get_json_result(data=outputs)
|
return get_json_result(data=outputs)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
|
|
@ -832,6 +832,7 @@ export enum ExportFileType {
|
||||||
HTML = 'html',
|
HTML = 'html',
|
||||||
Markdown = 'md',
|
Markdown = 'md',
|
||||||
DOCX = 'docx',
|
DOCX = 'docx',
|
||||||
|
Excel = 'xlsx',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum TypesWithArray {
|
export enum TypesWithArray {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue