ci: script and workflow to update starter projects (#5195)

This commit is contained in:
Jordan Frazier 2024-12-11 18:48:55 -08:00 committed by GitHub
commit ba31d436c4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 1315 additions and 2077 deletions

View file

@ -19,3 +19,25 @@ jobs:
- uses: autofix-ci/action@ff86a557419858bb967097bfc916833f5647fa8c
- name: Minimize uv cache
run: uv cache prune --ci
update-starter-projects:
name: Update Starter Projects
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: "Setup Environment"
uses: ./.github/actions/setup-uv
- name: "Install dependencies"
run: |
uv sync --frozen
uv pip install -e .
- name: Run starter projects update
run: uv run python scripts/ci/update_starter_projects.py
- uses: autofix-ci/action@ff86a557419858bb967097bfc916833f5647fa8c
- name: Minimize uv cache
run: uv cache prune --ci

View file

@ -6,10 +6,6 @@ on:
paths:
- "**/*.py"
jobs:
lint:
name: Ruff Style Check

View file

@ -0,0 +1,43 @@
"""Script to update Langflow starter projects with the latest component versions."""
import asyncio
import os
import langflow.main # noqa: F401
from langflow.initial_setup.setup import (
get_project_data,
load_starter_projects,
update_edges_with_latest_component_versions,
update_project_file,
update_projects_components_with_latest_component_versions,
)
from langflow.interface.types import get_and_cache_all_types_dict
from langflow.services.deps import get_settings_service
from langflow.services.utils import initialize_services
async def main():
"""Updates the starter projects with the latest component versions.
Copies the code from langflow/initial_setup/setup.py. Doesn't use the
create_or_update_starter_projects function directly to avoid sql interactions.
"""
await initialize_services(fix_migration=False)
all_types_dict = await get_and_cache_all_types_dict(get_settings_service())
starter_projects = await load_starter_projects()
for project_path, project in starter_projects:
_, _, _, _, project_data, _, _, _, _ = get_project_data(project)
do_update_starter_projects = os.environ.get("LANGFLOW_UPDATE_STARTER_PROJECTS", "true").lower() == "true"
if do_update_starter_projects:
updated_project_data = update_projects_components_with_latest_component_versions(
project_data.copy(), all_types_dict
)
updated_project_data = update_edges_with_latest_component_versions(updated_project_data)
if updated_project_data != project_data:
project_data = updated_project_data
await update_project_file(project_path, project, updated_project_data)
if __name__ == "__main__":
asyncio.run(main())

View file

@ -611,7 +611,13 @@ async def find_existing_flow(session, flow_id, flow_endpoint_name):
return None
async def create_or_update_starter_projects(all_types_dict: dict) -> None:
async def create_or_update_starter_projects(all_types_dict: dict, *, do_create: bool = True) -> None:
"""Create or update starter projects.
Args:
all_types_dict (dict): Dictionary containing all component types and their templates
do_create (bool, optional): Whether to create new projects. Defaults to True.
"""
async with async_session_scope() as session:
new_folder = await create_starter_folder(session)
starter_projects = await load_starter_projects()
@ -639,7 +645,7 @@ async def create_or_update_starter_projects(all_types_dict: dict) -> None:
project_data = updated_project_data
# We also need to update the project data in the file
await update_project_file(project_path, project, updated_project_data)
if project_name and project_data:
if do_create and project_name and project_data:
for existing_project in await get_all_flows_similar_to_project(session, new_folder.id):
await session.delete(existing_project)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -920,7 +920,7 @@
"show": true,
"title_case": false,
"type": "code",
"value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import MessageTextInput, Output, PromptInput\nfrom langflow.schema.message import Message\nfrom langflow.template.utils import update_template_values\n\n\nclass PromptComponent(Component):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n MessageTextInput(\n name=\"tool_placeholder\",\n display_name=\"Tool Placeholder\",\n tool_mode=True,\n advanced=True,\n info=\"A placeholder input for tool mode.\",\n ),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(self) -> Message:\n prompt = Message.from_template(**self._attributes)\n self.status = prompt.text\n return prompt\n\n def _update_template(self, frontend_node: dict):\n prompt_template = frontend_node[\"template\"][\"template\"][\"value\"]\n custom_fields = frontend_node[\"custom_fields\"]\n frontend_node_template = frontend_node[\"template\"]\n _ = process_prompt_template(\n template=prompt_template,\n name=\"template\",\n custom_fields=custom_fields,\n frontend_node_template=frontend_node_template,\n )\n return frontend_node\n\n def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):\n \"\"\"This function is called after the code validation is done.\"\"\"\n frontend_node = super().post_code_processing(new_frontend_node, current_frontend_node)\n template = frontend_node[\"template\"][\"template\"][\"value\"]\n # Kept it duplicated for backwards compatibility\n _ = process_prompt_template(\n template=template,\n name=\"template\",\n custom_fields=frontend_node[\"custom_fields\"],\n frontend_node_template=frontend_node[\"template\"],\n )\n # Now that template is updated, we need to grab any values that were set in the current_frontend_node\n # and update the frontend_node with those values\n update_template_values(new_template=frontend_node, previous_template=current_frontend_node[\"template\"])\n return frontend_node\n\n def _get_fallback_input(self, **kwargs):\n return DefaultPromptField(**kwargs)\n"
"value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import MessageTextInput, Output, PromptInput\nfrom langflow.schema.message import Message\nfrom langflow.template.utils import update_template_values\n\n\nclass PromptComponent(Component):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n MessageTextInput(\n name=\"tool_placeholder\",\n display_name=\"Tool Placeholder\",\n tool_mode=True,\n advanced=True,\n info=\"A placeholder input for tool mode.\",\n ),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(self) -> Message:\n prompt = Message.from_template(**self._attributes)\n self.status = prompt.text\n return prompt\n\n def _update_template(self, frontend_node: dict):\n prompt_template = frontend_node[\"template\"][\"template\"][\"value\"]\n custom_fields = frontend_node[\"custom_fields\"]\n frontend_node_template = frontend_node[\"template\"]\n _ = process_prompt_template(\n template=prompt_template,\n name=\"template\",\n custom_fields=custom_fields,\n frontend_node_template=frontend_node_template,\n )\n return frontend_node\n\n async def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):\n \"\"\"This function is called after the code validation is done.\"\"\"\n frontend_node = await super().post_code_processing(new_frontend_node, current_frontend_node)\n template = frontend_node[\"template\"][\"template\"][\"value\"]\n # Kept it duplicated for backwards compatibility\n _ = process_prompt_template(\n template=template,\n name=\"template\",\n custom_fields=frontend_node[\"custom_fields\"],\n frontend_node_template=frontend_node[\"template\"],\n )\n # Now that template is updated, we need to grab any values that were set in the current_frontend_node\n # and update the frontend_node with those values\n update_template_values(new_template=frontend_node, previous_template=current_frontend_node[\"template\"])\n return frontend_node\n\n def _get_fallback_input(self, **kwargs):\n return DefaultPromptField(**kwargs)\n"
},
"template": {
"_input_type": "PromptInput",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -269,9 +269,11 @@ class ArizePhoenixTracer(BaseTracer):
if not self._ready:
return
def _convert_to_arize_phoenix_types(self, io_dict: dict[str, Any]):
def _convert_to_arize_phoenix_types(self, io_dict: dict[str | Any, Any]) -> dict[str, Any]:
"""Converts data types to Arize/Phoenix compatible formats."""
return {key: self._convert_to_arize_phoenix_type(value) for key, value in io_dict.items()}
return {
str(key): self._convert_to_arize_phoenix_type(value) for key, value in io_dict.items() if key is not None
}
def _convert_to_arize_phoenix_type(self, value):
"""Recursively converts a value to a Arize/Phoenix compatible type."""

2358
uv.lock generated

File diff suppressed because it is too large Load diff