lfx-nightly 0.1.12.dev27__py3-none-any.whl → 0.1.12.dev29__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of lfx-nightly might be problematic. Click here for more details.

@@ -1,69 +0,0 @@
1
- import pandas as pd
2
- import requests
3
- from bs4 import BeautifulSoup
4
-
5
- from lfx.custom import Component
6
- from lfx.io import IntInput, MessageTextInput, Output
7
- from lfx.log.logger import logger
8
- from lfx.schema import DataFrame
9
-
10
-
11
- class RSSReaderComponent(Component):
12
- display_name = "RSS Reader"
13
- description = "Fetches and parses an RSS feed."
14
- documentation: str = "https://docs.langflow.org/components-data#rss-reader"
15
- icon = "rss"
16
- name = "RSSReaderSimple"
17
-
18
- inputs = [
19
- MessageTextInput(
20
- name="rss_url",
21
- display_name="RSS Feed URL",
22
- info="URL of the RSS feed to parse.",
23
- tool_mode=True,
24
- required=True,
25
- ),
26
- IntInput(
27
- name="timeout",
28
- display_name="Timeout",
29
- info="Timeout for the RSS feed request.",
30
- value=5,
31
- advanced=True,
32
- ),
33
- ]
34
-
35
- outputs = [Output(name="articles", display_name="Articles", method="read_rss")]
36
-
37
- def read_rss(self) -> DataFrame:
38
- try:
39
- response = requests.get(self.rss_url, timeout=self.timeout)
40
- response.raise_for_status()
41
- if not response.content.strip():
42
- msg = "Empty response received"
43
- raise ValueError(msg)
44
- # Check if the response is valid XML
45
- try:
46
- BeautifulSoup(response.content, "xml")
47
- except Exception as e:
48
- msg = f"Invalid XML response: {e}"
49
- raise ValueError(msg) from e
50
- soup = BeautifulSoup(response.content, "xml")
51
- items = soup.find_all("item")
52
- except (requests.RequestException, ValueError) as e:
53
- self.status = f"Failed to fetch RSS: {e}"
54
- return DataFrame(pd.DataFrame([{"title": "Error", "link": "", "published": "", "summary": str(e)}]))
55
-
56
- articles = [
57
- {
58
- "title": item.title.text if item.title else "",
59
- "link": item.link.text if item.link else "",
60
- "published": item.pubDate.text if item.pubDate else "",
61
- "summary": item.description.text if item.description else "",
62
- }
63
- for item in items
64
- ]
65
-
66
- # Ensure the DataFrame has the correct columns even if empty
67
- df_articles = pd.DataFrame(articles, columns=["title", "link", "published", "summary"])
68
- logger.info(f"Fetched {len(df_articles)} articles.")
69
- return DataFrame(df_articles)
@@ -1,225 +0,0 @@
1
- import json
2
- from collections.abc import AsyncIterator, Iterator
3
- from pathlib import Path
4
-
5
- import orjson
6
- import pandas as pd
7
- from fastapi import UploadFile
8
- from fastapi.encoders import jsonable_encoder
9
-
10
- from lfx.custom import Component
11
- from lfx.io import DropdownInput, HandleInput, StrInput
12
- from lfx.schema import Data, DataFrame, Message
13
- from lfx.services.deps import get_settings_service, get_storage_service
14
- from lfx.template.field.base import Output
15
-
16
-
17
- class SaveToFileComponent(Component):
18
- display_name = "Save File"
19
- description = "Save data to a local file in the selected format."
20
- documentation: str = "https://docs.langflow.org/components-processing#save-file"
21
- icon = "save"
22
- name = "SaveToFile"
23
-
24
- # File format options for different types
25
- DATA_FORMAT_CHOICES = ["csv", "excel", "json", "markdown"]
26
- MESSAGE_FORMAT_CHOICES = ["txt", "json", "markdown"]
27
-
28
- inputs = [
29
- HandleInput(
30
- name="input",
31
- display_name="Input",
32
- info="The input to save.",
33
- dynamic=True,
34
- input_types=["Data", "DataFrame", "Message"],
35
- required=True,
36
- ),
37
- StrInput(
38
- name="file_name",
39
- display_name="File Name",
40
- info="Name file will be saved as (without extension).",
41
- required=True,
42
- ),
43
- DropdownInput(
44
- name="file_format",
45
- display_name="File Format",
46
- options=list(dict.fromkeys(DATA_FORMAT_CHOICES + MESSAGE_FORMAT_CHOICES)),
47
- info="Select the file format to save the input. If not provided, the default format will be used.",
48
- value="",
49
- advanced=True,
50
- ),
51
- ]
52
-
53
- outputs = [Output(display_name="File Path", name="message", method="save_to_file")]
54
-
55
- async def save_to_file(self) -> Message:
56
- """Save the input to a file and upload it, returning a confirmation message."""
57
- # Validate inputs
58
- if not self.file_name:
59
- msg = "File name must be provided."
60
- raise ValueError(msg)
61
- if not self._get_input_type():
62
- msg = "Input type is not set."
63
- raise ValueError(msg)
64
-
65
- # Validate file format based on input type
66
- file_format = self.file_format or self._get_default_format()
67
- allowed_formats = (
68
- self.MESSAGE_FORMAT_CHOICES if self._get_input_type() == "Message" else self.DATA_FORMAT_CHOICES
69
- )
70
- if file_format not in allowed_formats:
71
- msg = f"Invalid file format '{file_format}' for {self._get_input_type()}. Allowed: {allowed_formats}"
72
- raise ValueError(msg)
73
-
74
- # Prepare file path
75
- file_path = Path(self.file_name).expanduser()
76
- if not file_path.parent.exists():
77
- file_path.parent.mkdir(parents=True, exist_ok=True)
78
- file_path = self._adjust_file_path_with_format(file_path, file_format)
79
-
80
- # Save the input to file based on type
81
- if self._get_input_type() == "DataFrame":
82
- confirmation = self._save_dataframe(self.input, file_path, file_format)
83
- elif self._get_input_type() == "Data":
84
- confirmation = self._save_data(self.input, file_path, file_format)
85
- elif self._get_input_type() == "Message":
86
- confirmation = await self._save_message(self.input, file_path, file_format)
87
- else:
88
- msg = f"Unsupported input type: {self._get_input_type()}"
89
- raise ValueError(msg)
90
-
91
- # Upload the saved file
92
- await self._upload_file(file_path)
93
-
94
- # Return the final file path and confirmation message
95
- final_path = Path.cwd() / file_path if not file_path.is_absolute() else file_path
96
-
97
- return Message(text=f"{confirmation} at {final_path}")
98
-
99
- def _get_input_type(self) -> str:
100
- """Determine the input type based on the provided input."""
101
- # Use exact type checking (type() is) instead of isinstance() to avoid inheritance issues.
102
- # Since Message inherits from Data, isinstance(message, Data) would return True for Message objects,
103
- # causing Message inputs to be incorrectly identified as Data type.
104
- if type(self.input) is DataFrame:
105
- return "DataFrame"
106
- if type(self.input) is Message:
107
- return "Message"
108
- if type(self.input) is Data:
109
- return "Data"
110
- msg = f"Unsupported input type: {type(self.input)}"
111
- raise ValueError(msg)
112
-
113
- def _get_default_format(self) -> str:
114
- """Return the default file format based on input type."""
115
- if self._get_input_type() == "DataFrame":
116
- return "csv"
117
- if self._get_input_type() == "Data":
118
- return "json"
119
- if self._get_input_type() == "Message":
120
- return "json"
121
- return "json" # Fallback
122
-
123
- def _adjust_file_path_with_format(self, path: Path, fmt: str) -> Path:
124
- """Adjust the file path to include the correct extension."""
125
- file_extension = path.suffix.lower().lstrip(".")
126
- if fmt == "excel":
127
- return Path(f"{path}.xlsx").expanduser() if file_extension not in ["xlsx", "xls"] else path
128
- return Path(f"{path}.{fmt}").expanduser() if file_extension != fmt else path
129
-
130
- async def _upload_file(self, file_path: Path) -> None:
131
- """Upload the saved file using the upload_user_file service."""
132
- try:
133
- from langflow.api.v2.files import upload_user_file
134
- from langflow.services.database.models.user.crud import get_user_by_id
135
- except ImportError as e:
136
- msg = (
137
- "Langflow file upload functionality is not available. "
138
- "This feature requires the full Langflow installation. "
139
- )
140
- raise ImportError(msg) from e
141
-
142
- if not file_path.exists():
143
- msg = f"File not found: {file_path}"
144
- raise FileNotFoundError(msg)
145
-
146
- with file_path.open("rb") as f:
147
- try:
148
- from langflow.services.database.models.user.crud import get_user_by_id
149
- from langflow.services.deps import session_scope
150
- except ImportError as e:
151
- msg = (
152
- "Langflow MCP server functionality is not available. "
153
- "This feature requires the full Langflow installation."
154
- )
155
- raise ImportError(msg) from e
156
- async with session_scope() as db:
157
- if not self.user_id:
158
- msg = "User ID is required for file saving."
159
- raise ValueError(msg)
160
- current_user = await get_user_by_id(db, self.user_id)
161
-
162
- await upload_user_file(
163
- file=UploadFile(filename=file_path.name, file=f, size=file_path.stat().st_size),
164
- session=db,
165
- current_user=current_user,
166
- storage_service=get_storage_service(),
167
- settings_service=get_settings_service(),
168
- )
169
-
170
- def _save_dataframe(self, dataframe: DataFrame, path: Path, fmt: str) -> str:
171
- """Save a DataFrame to the specified file format."""
172
- if fmt == "csv":
173
- dataframe.to_csv(path, index=False)
174
- elif fmt == "excel":
175
- dataframe.to_excel(path, index=False, engine="openpyxl")
176
- elif fmt == "json":
177
- dataframe.to_json(path, orient="records", indent=2)
178
- elif fmt == "markdown":
179
- path.write_text(dataframe.to_markdown(index=False), encoding="utf-8")
180
- else:
181
- msg = f"Unsupported DataFrame format: {fmt}"
182
- raise ValueError(msg)
183
- return f"DataFrame saved successfully as '{path}'"
184
-
185
- def _save_data(self, data: Data, path: Path, fmt: str) -> str:
186
- """Save a Data object to the specified file format."""
187
- if fmt == "csv":
188
- pd.DataFrame(data.data).to_csv(path, index=False)
189
- elif fmt == "excel":
190
- pd.DataFrame(data.data).to_excel(path, index=False, engine="openpyxl")
191
- elif fmt == "json":
192
- path.write_text(
193
- orjson.dumps(jsonable_encoder(data.data), option=orjson.OPT_INDENT_2).decode("utf-8"), encoding="utf-8"
194
- )
195
- elif fmt == "markdown":
196
- path.write_text(pd.DataFrame(data.data).to_markdown(index=False), encoding="utf-8")
197
- else:
198
- msg = f"Unsupported Data format: {fmt}"
199
- raise ValueError(msg)
200
- return f"Data saved successfully as '{path}'"
201
-
202
- async def _save_message(self, message: Message, path: Path, fmt: str) -> str:
203
- """Save a Message to the specified file format, handling async iterators."""
204
- content = ""
205
- if message.text is None:
206
- content = ""
207
- elif isinstance(message.text, AsyncIterator):
208
- async for item in message.text:
209
- content += str(item) + " "
210
- content = content.strip()
211
- elif isinstance(message.text, Iterator):
212
- content = " ".join(str(item) for item in message.text)
213
- else:
214
- content = str(message.text)
215
-
216
- if fmt == "txt":
217
- path.write_text(content, encoding="utf-8")
218
- elif fmt == "json":
219
- path.write_text(json.dumps({"message": content}, indent=2), encoding="utf-8")
220
- elif fmt == "markdown":
221
- path.write_text(f"**Message:**\n\n{content}", encoding="utf-8")
222
- else:
223
- msg = f"Unsupported Message format: {fmt}"
224
- raise ValueError(msg)
225
- return f"Message saved successfully as '{path}'"