diff --git a/.github/workflows/auto-update.yml b/.github/workflows/auto-update.yml new file mode 100644 index 000000000..85deafa82 --- /dev/null +++ b/.github/workflows/auto-update.yml @@ -0,0 +1,14 @@ +name: Auto-update + +on: + push: + branches: + - dev + - main + +jobs: + Auto: + name: Auto-update + runs-on: ubuntu-latest + steps: + - uses: tibdex/auto-update@v2 \ No newline at end of file diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 75c136202..e327ce1aa 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -8,6 +8,11 @@ on: release_type: required: true type: string + pre_release: + required: false + type: boolean + default: false + workflow_dispatch: inputs: version: @@ -19,6 +24,10 @@ on: options: - base - main + pre_release: + required: false + type: boolean + default: true env: POETRY_VERSION: "1.8.2" TEST_TAG: "langflowai/langflow:test" @@ -35,10 +44,14 @@ jobs: id: set-vars run: | if [[ "${{ inputs.release_type }}" == "base" ]]; then - echo "tags=langflowai/langflow:base-${{ inputs.version }}" >> $GITHUB_OUTPUT + echo "tags=langflowai/langflow:base-${{ inputs.version }},langflowai/langflow:base-latest" >> $GITHUB_OUTPUT echo "file=./docker/build_and_push_base.Dockerfile" >> $GITHUB_OUTPUT else - echo "tags=langflowai/langflow:${{ inputs.version }},langflowai/langflow:1.0-alpha" >> $GITHUB_OUTPUT + if [[ "${{ inputs.pre_release }}" == "true" ]]; then + echo "tags=langflowai/langflow:${{ inputs.version }}" >> $GITHUB_OUTPUT + else + echo "tags=langflowai/langflow:${{ inputs.version }},langflowai/langflow:latest" >> $GITHUB_OUTPUT + fi echo "file=./docker/build_and_push.Dockerfile" >> $GITHUB_OUTPUT fi build: @@ -54,7 +67,7 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and Push Docker Image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . push: true @@ -73,10 +86,10 @@ jobs: include: - component: backend dockerfile: ./docker/build_and_push_backend.Dockerfile - tags: langflowai/langflow-backend:${{ inputs.version }},langflowai/langflow-backend:1.0-alpha + tags: ${{ inputs.pre_release == 'true' && format('langflowai/langflow-backend:{0}', inputs.version) || format('langflowai/langflow-backend:{0},langflowai/langflow-backend:latest', inputs.version) }} - component: frontend dockerfile: ./docker/frontend/build_and_push_frontend.Dockerfile - tags: langflowai/langflow-frontend:${{ inputs.version }},langflowai/langflow-frontend:1.0-alpha + tags: ${{ inputs.pre_release == 'true' && format('langflowai/langflow-frontend:{0}', inputs.version) || format('langflowai/langflow-frontend:{0},langflowai/langflow-frontend:latest', inputs.version) }} steps: - uses: actions/checkout@v4 - name: Set up Docker Buildx @@ -89,7 +102,7 @@ jobs: - name: Wait for Docker Hub to propagate (for backend) run: sleep 120 - name: Build and push ${{ matrix.component }} - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . push: true diff --git a/.github/workflows/docs_test.yml b/.github/workflows/docs_test.yml new file mode 100644 index 000000000..cc25b56f6 --- /dev/null +++ b/.github/workflows/docs_test.yml @@ -0,0 +1,47 @@ +name: Test Docs Build + +on: + pull_request: + paths: + - "docs/**" + merge_group: + types: [checks_requested] + +env: + NODE_VERSION: "21" + + +jobs: + test-docs-build: + name: Test Docs Build + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + id: setup-node + with: + node-version: ${{ env.NODE_VERSION }} + + - name: Cache Node.js dependencies + uses: actions/cache@v4 + id: npm-cache + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('docs/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + + - name: Install Node.js dependencies + run: | + cd docs + npm install + if: ${{ steps.setup-node.outputs.cache-hit != 'true' }} + + - name: Build Docs + run: | + cd docs + npm run build diff --git a/.github/workflows/js_autofix.yml b/.github/workflows/js_autofix.yml new file mode 100644 index 000000000..f6501baab --- /dev/null +++ b/.github/workflows/js_autofix.yml @@ -0,0 +1,50 @@ +name: autofix.ci + +on: + pull_request: + types: [opened, synchronize, reopened, auto_merge_enabled, auto_merge_disabled] + paths: + - "src/frontend/**" + push: + branches: [ "main" ] + paths: + - "src/frontend/**" + +permissions: + contents: read + +env: + NODE_VERSION: "21" +jobs: + autofix: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + id: setup-node + with: + node-version: ${{ env.NODE_VERSION }} + + - name: Cache Node.js dependencies + uses: actions/cache@v4 + id: npm-cache + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('src/frontend/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + + - name: Install Node.js dependencies + run: | + cd src/frontend + npm ci + if: ${{ steps.setup-node.outputs.cache-hit != 'true' }} + - name: Run Prettier + run: | + cd src/frontend + npm run format + + - uses: autofix-ci/action@dd55f44df8f7cdb7a6bf74c78677eb8acd40cd0a \ No newline at end of file diff --git a/.github/workflows/lint-js.yml b/.github/workflows/lint-js.yml index d381a467f..b528ee8ed 100644 --- a/.github/workflows/lint-js.yml +++ b/.github/workflows/lint-js.yml @@ -4,6 +4,8 @@ on: pull_request: paths: - "src/frontend/**" + merge_group: + types: [checks_requested] env: NODE_VERSION: "21" @@ -43,10 +45,6 @@ jobs: - name: Run Prettier run: | cd src/frontend - npm run format - - name: Commit changes - uses: stefanzweifel/git-auto-commit-action@v5 - with: - commit_message: Apply Prettier formatting - branch: ${{ github.head_ref }} + npm run check-format + diff --git a/.github/workflows/lint-py.yml b/.github/workflows/lint-py.yml index 95fbb15e6..10bf7ad90 100644 --- a/.github/workflows/lint-py.yml +++ b/.github/workflows/lint-py.yml @@ -2,17 +2,15 @@ name: Lint Python on: pull_request: - paths: - - "poetry.lock" - - "pyproject.toml" - - "src/backend/**" - - "tests/**" - + types: [opened, synchronize, reopened] + merge_group: + types: [checks_requested] env: POETRY_VERSION: "1.8.2" jobs: lint: + name: Run Mypy runs-on: ubuntu-latest strategy: matrix: @@ -32,6 +30,8 @@ jobs: run: | poetry env use ${{ matrix.python-version }} poetry install + - name: Run Mypy + run: | make lint env: GITHUB_TOKEN: ${{ secrets.github_token }} diff --git a/.github/workflows/pre-release-base.yml b/.github/workflows/pre-release-base.yml index e732af993..6d9e2f0bd 100644 --- a/.github/workflows/pre-release-base.yml +++ b/.github/workflows/pre-release-base.yml @@ -69,7 +69,7 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . push: true diff --git a/.github/workflows/pre-release-langflow.yml b/.github/workflows/pre-release-langflow.yml index 879fb9da5..5a052dcc8 100644 --- a/.github/workflows/pre-release-langflow.yml +++ b/.github/workflows/pre-release-langflow.yml @@ -75,7 +75,7 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . push: true @@ -86,7 +86,7 @@ jobs: langflowai/langflow:${{ needs.release.outputs.version }} langflowai/langflow:1.0-alpha - name: Build and push (frontend) - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . push: true @@ -99,7 +99,7 @@ jobs: - name: Wait for Docker Hub to propagate run: sleep 120 - name: Build and push (backend) - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . push: true diff --git a/.github/workflows/py_autofix.yml b/.github/workflows/py_autofix.yml new file mode 100644 index 000000000..53d40bb14 --- /dev/null +++ b/.github/workflows/py_autofix.yml @@ -0,0 +1,29 @@ +name: autofix.ci +on: + pull_request: + types: [opened, synchronize, reopened, auto_merge_enabled, auto_merge_disabled] + paths: + - "poetry.lock" + - "pyproject.toml" + - "src/backend/**" + - "tests/**" +env: + POETRY_VERSION: "1.8.2" + +jobs: + lint: + name: Run Mypy + runs-on: ubuntu-latest + strategy: + matrix: + python-version: + - "3.12" + - "3.11" + - "3.10" + steps: + - uses: actions/checkout@v4 + - uses: install-pinned/ruff@6b463d795ce39011cc004438ae507ae56235e12a + - run: ruff --fix-only . + - run: ruff format . + + - uses: autofix-ci/action@dd55f44df8f7cdb7a6bf74c78677eb8acd40cd0a \ No newline at end of file diff --git a/.github/workflows/python_test.yml b/.github/workflows/python_test.yml index 9a8ef15c8..ae2c87714 100644 --- a/.github/workflows/python_test.yml +++ b/.github/workflows/python_test.yml @@ -1,24 +1,17 @@ -name: test +name: Python tests on: - push: - branches: [main] - paths: - - "poetry.lock" - - "pyproject.toml" - - "src/backend/**" pull_request: - branches: [dev] - paths: - - "poetry.lock" - - "pyproject.toml" - - "src/backend/**" - + types: [opened, synchronize, reopened] + branches: [dev, main] + merge_group: + types: [checks_requested] env: POETRY_VERSION: "1.8.2" jobs: build: + name: Run Unit Tests runs-on: ubuntu-latest strategy: matrix: @@ -43,3 +36,19 @@ jobs: - name: Run unit tests run: | make unit_tests args="-n auto" + - name: Test CLI + run: | + poetry run python -m langflow run --host 127.0.0.1 --port 7860 --backend-only & + SERVER_PID=$! + # Wait for the server to start + timeout 120 bash -c 'until curl -f http://127.0.0.1:7860/api/v1/auto_login; do sleep 5; done' || (echo "Server did not start in time" && kill $SERVER_PID && exit 1) + # Terminate the server + kill $SERVER_PID || (echo "Failed to terminate the server" && exit 1) + sleep 10 # give the server some time to terminate + # Check if the server is still running + if kill -0 $SERVER_PID 2>/dev/null; then + echo "Failed to terminate the server" + exit 1 + else + echo "Server terminated successfully" + fi diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e27836ee3..1617561a0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,21 +1,31 @@ -name: release +name: Langflow Release +run-name: Langflow Release by @${{ github.actor }} on: - pull_request: - types: - - closed - branches: - - main - paths: - - "pyproject.toml" + workflow_dispatch: + inputs: + release_package: + description: "Release package" + required: true + type: boolean + default: false + pre_release: + description: "Pre-release" + required: false + type: boolean + default: true + env: POETRY_VERSION: "1.8.2" jobs: - if_release: - if: ${{ (github.event.pull_request.merged == true) && contains(github.event.pull_request.labels.*.name, 'Release') }} + release-base: + name: Release Langflow Base + if: inputs.release_package == true runs-on: ubuntu-latest + outputs: + version: ${{ steps.check-version.outputs.version }} steps: - uses: actions/checkout@v4 - name: Install poetry @@ -25,64 +35,138 @@ jobs: with: python-version: "3.10" cache: "poetry" - - name: Build project for distribution - run: make build + - name: Set up Nodejs 20 + uses: actions/setup-node@v4 + with: + node-version: "20" - name: Check Version id: check-version run: | - echo version=$(poetry version --short) >> $GITHUB_OUTPUT + version=$(cd src/backend/base && poetry version --short) + last_released_version=$(curl -s "https://pypi.org/pypi/langflow-base/json" | jq -r '.releases | keys | .[]' | sort -V | tail -n 1) + if [ "$version" = "$last_released_version" ]; then + echo "Version $version is already released. Skipping release." + exit 1 + else + echo version=$version >> $GITHUB_OUTPUT + fi + - name: Build project for distribution + run: make build base=true + - name: Test CLI + run: | + python -m pip install src/backend/base/dist/*.whl + python -m langflow run --host 127.0.0.1 --port 7860 & + SERVER_PID=$! + # Wait for the server to start + timeout 120 bash -c 'until curl -f http://127.0.0.1:7860/api/v1/auto_login; do sleep 2; done' || (echo "Server did not start in time" && kill $SERVER_PID && exit 1) + # Terminate the server + kill $SERVER_PID || (echo "Failed to terminate the server" && exit 1) + sleep 10 # give the server some time to terminate + # Check if the server is still running + if kill -0 $SERVER_PID 2>/dev/null; then + echo "Failed to terminate the server" + exit 1 + else + echo "Server terminated successfully" + fi - name: Publish to PyPI env: POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_API_TOKEN }} + run: make publish base=true + - name: Upload Artifact + uses: actions/upload-artifact@v4 + with: + name: dist-base + path: src/backend/base/dist + + release-main: + name: Release Langflow Main + if: inputs.release_package == true + needs: release-base + runs-on: ubuntu-latest + outputs: + version: ${{ steps.check-version.outputs.version }} + steps: + - uses: actions/checkout@v4 + - name: Install poetry + run: pipx install poetry==${{ env.POETRY_VERSION }} + - name: Set up Python 3.10 + uses: actions/setup-python@v5 + with: + python-version: "3.10" + cache: "poetry" + - name: Set up Nodejs 20 + uses: actions/setup-node@v4 + with: + node-version: "20" + - name: Check Version + id: check-version run: | - poetry publish - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - id: qemu - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Login to Docker Hub - uses: docker/login-action@v3 + version=$(poetry version --short) + last_released_version=$(curl -s "https://pypi.org/pypi/langflow/json" | jq -r '.releases | keys | .[]' | sort -V | tail -n 1) + if [ "$version" = "$last_released_version" ]; then + echo "Version $version is already released. Skipping release." + exit 1 + else + echo version=$version >> $GITHUB_OUTPUT + fi + - name: Wait for PyPI Propagation + run: sleep 300 # wait for 5 minutes to ensure PyPI propagation + - name: Build project for distribution + run: make build main=true + - name: Test CLI + run: | + python -m pip install dist/*.whl + python -m langflow run --host 127.0.0.1 --port 7860 & + SERVER_PID=$! + # Wait for the server to start + timeout 120 bash -c 'until curl -f http://127.0.0.1:7860/api/v1/auto_login; do sleep 2; done' || (echo "Server did not start in time" && kill $SERVER_PID && exit 1) + # Terminate the server + kill $SERVER_PID || (echo "Failed to terminate the server" && exit 1) + sleep 10 # give the server some time to terminate + # Check if the server is still running + if kill -0 $SERVER_PID 2>/dev/null; then + echo "Failed to terminate the server" + exit 1 + else + echo "Server terminated successfully" + fi + - name: Publish to PyPI + env: + POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_API_TOKEN }} + run: make publish main=true + - name: Upload Artifact + uses: actions/upload-artifact@v4 with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Build and push - uses: docker/build-push-action@v5 + name: dist-main + path: dist + + call_docker_build: + name: Call Docker Build Workflow + needs: [release-base, release-main] + uses: langflow-ai/langflow/.github/workflows/docker-build.yml@main + strategy: + matrix: + release_type: + - base + - main + with: + # version should be needs.release-base.outputs.version if release_type is base + # version should be needs.release-main.outputs.version if release_type is main + version: ${{ matrix.release_type == 'base' && needs.release-base.outputs.version || matrix.release_type == 'main' && needs.release-main.outputs.version }} + release_type: ${{ matrix.release_type }} + pre_release: ${{ inputs.pre_release }} + secrets: inherit + + create_release: + name: Create Release + runs-on: ubuntu-latest + needs: release-main + steps: + - uses: actions/download-artifact@v4 with: - context: . - push: true - file: ./docker/build_and_push.Dockerfile - # provenance: false will result in a single manifest for all platforms which makes the image pullable from arm64 machines via the emulation (e.g. Apple Silicon machines) - provenance: false - tags: | - langflowai/langflow:${{ steps.check-version.outputs.version }} - langflowai/langflow:latest - - name: Wait for Docker Hub to propagate - run: sleep 120 - - name: Build and push (backend) - uses: docker/build-push-action@v5 - with: - context: . - push: true - file: ./docker/build_and_push_backend.Dockerfile - # provenance: false will result in a single manifest for all platforms which makes the image pullable from arm64 machines via the emulation (e.g. Apple Silicon machines) - provenance: false - build-args: | - LANGFLOW_IMAGE=langflowai/langflow:${{ steps.check-version.outputs.version }} - tags: | - langflowai/langflow-backend:${{ steps.check-version.outputs.version }} - langflowai/langflow-backend:latest - - name: Build and push (frontend) - uses: docker/build-push-action@v5 - with: - context: . - push: true - file: ./docker/frontend/build_and_push_frontend.Dockerfile - # provenance: false will result in a single manifest for all platforms which makes the image pullable from arm64 machines via the emulation (e.g. Apple Silicon machines) - provenance: false - tags: | - langflowai/langflow-frontend:${{ steps.check-version.outputs.version }} - langflowai/langflow-frontend:latest + name: dist-main + path: dist - name: Create Release uses: ncipollo/release-action@v1 with: @@ -90,5 +174,6 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} draft: false generateReleaseNotes: true - tag: v${{ steps.check-version.outputs.version }} - commit: main + prerelease: ${{ inputs.pre_release }} + tag: v${{ needs.release-main.outputs.version }} + commit: ${{ github.ref }} \ No newline at end of file diff --git a/.github/workflows/style-check-py.yml b/.github/workflows/style-check-py.yml index 3255aa31d..2aa4db470 100644 --- a/.github/workflows/style-check-py.yml +++ b/.github/workflows/style-check-py.yml @@ -1,12 +1,9 @@ name: Ruff Style Check on: - pull_request: - paths: - - "poetry.lock" - - "pyproject.toml" - - "src/backend/**" - - "tests/**" + pull_request: {} + merge_group: + branches: [dev] env: POETRY_VERSION: "1.8.2" @@ -33,14 +30,8 @@ jobs: poetry install - name: Register problem matcher run: echo "::add-matcher::.github/workflows/matchers/ruff.json" - - name: Run Ruff + - name: Run Ruff Check run: poetry run ruff check --output-format=github . - - name: Run Ruff format - run: poetry run ruff format . - - name: Commit changes - uses: stefanzweifel/git-auto-commit-action@v5 - with: - commit_message: Apply Ruff formatting - branch: ${{ github.head_ref }} + diff --git a/.github/workflows/typescript_test.yml b/.github/workflows/typescript_test.yml index be081bec6..763f4ffce 100644 --- a/.github/workflows/typescript_test.yml +++ b/.github/workflows/typescript_test.yml @@ -2,11 +2,10 @@ name: Run Frontend Tests on: pull_request: - paths: - - "src/frontend/**" + merge_group: env: - POETRY_VERSION: "1.8.2" + POETRY_VERSION: "1.8.3" NODE_VERSION: "21" PYTHON_VERSION: "3.12" # Define the directory where Playwright browsers will be installed. @@ -15,12 +14,16 @@ env: jobs: setup-and-test: + name: Run Playwright Tests runs-on: ubuntu-latest strategy: fail-fast: false matrix: - shardIndex: [1, 2, 3, 4] - shardTotal: [4] + shardIndex: [1, 2, 3, 4, 5, 6, 7, 8] + shardTotal: [8] + env: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + STORE_API_KEY: ${{ secrets.STORE_API_KEY }} steps: - name: Checkout code uses: actions/checkout@v4 @@ -45,14 +48,15 @@ jobs: cd src/frontend npm ci if: ${{ steps.setup-node.outputs.cache-hit != 'true' }} - - - name: Cache playwright binaries - uses: actions/cache@v4 + - name: Get Playwright version + run: echo "PLAYWRIGHT_VERSION=$(jq '.devDependencies["@playwright/test"]' src/frontend/package.json -r)" >> $GITHUB_ENV + - name: Cache Playwright binaries id: playwright-cache + uses: actions/cache@v4 with: - path: | - ~/.cache/ms-playwright - key: ${{ runner.os }}-playwright-${{ hashFiles('src/frontend/package-lock.json') }} + path: ~/.cache/ms-playwright + key: playwright-browsers-${{ runner.os }}-${{ env.PLAYWRIGHT_VERSION }} + - name: Install Frontend dependencies run: | cd src/frontend @@ -88,7 +92,7 @@ jobs: - name: Run Playwright Tests run: | cd src/frontend - npx playwright test --shard ${{ matrix.shardIndex }}/${{ matrix.shardTotal }} --workers 2 + npx playwright test --trace on --shard ${{ matrix.shardIndex }}/${{ matrix.shardTotal }} --workers 2 - name: Upload blob report to GitHub Actions Artifacts if: always() diff --git a/.vscode/launch.json b/.vscode/launch.json index a2a38dcba..eaaf23f33 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -34,14 +34,12 @@ "args": [ "run", "--path", - "${workspaceFolder}/src/backend/base/langflow/frontend" + "${workspaceFolder}/src/backend/base/langflow/frontend", + "--env-file", + "${workspaceFolder}/.env" ], "jinja": true, - "justMyCode": false, - "env": { - "LANGFLOW_LOG_LEVEL": "debug" - }, - "envFile": "${workspaceFolder}/.env" + "justMyCode": false }, { "name": "Python: Remote Attach", diff --git a/Makefile b/Makefile index 853fe6196..0b03489ab 100644 --- a/Makefile +++ b/Makefile @@ -47,20 +47,22 @@ init: coverage: ## run the tests and generate a coverage report - poetry run pytest --cov \ - --cov-config=.coveragerc \ - --cov-report xml \ - --cov-report term-missing:skip-covered \ - --cov-report lcov:coverage/lcov-pytest.info + @poetry run coverage run + @poetry run coverage erase # allow passing arguments to pytest unit_tests: - poetry run pytest --ignore=tests/integration --instafail -ra -n auto -m "not api_key_required" $(args) + poetry run pytest \ + --ignore=tests/integration \ + --instafail -ra -n auto -m "not api_key_required" \ + $(args) integration_tests: - poetry run pytest tests/integration --instafail -ra -n auto $(args) + poetry run pytest tests/integration \ + --instafail -ra -n auto \ + $(args) format: ## run code formatters poetry run ruff check . --fix @@ -129,9 +131,20 @@ start: @echo 'Running the CLI' ifeq ($(open_browser),false) - @make install_backend && poetry run langflow run --path $(path) --log-level $(log_level) --host $(host) --port $(port) --env-file $(env) --no-open-browser + @make install_backend && poetry run langflow run \ + --path $(path) \ + --log-level $(log_level) \ + --host $(host) \ + --port $(port) \ + --env-file $(env) \ + --no-open-browser else - @make install_backend && poetry run langflow run --path $(path) --log-level $(log_level) --host $(host) --port $(port) --env-file $(env) + @make install_backend && poetry run langflow run \ + --path $(path) \ + --log-level $(log_level) \ + --host $(host) \ + --port $(port) \ + --env-file $(env) endif @@ -166,13 +179,27 @@ backend: ## run the backend in development mode @echo 'Setting up the environment' @make setup_env make install_backend - @-kill -9 $(lsof -t -i:7860) + @-kill -9 $$(lsof -t -i:7860) ifdef login @echo "Running backend autologin is $(login)"; - LANGFLOW_AUTO_LOGIN=$(login) poetry run uvicorn --factory langflow.main:create_app --host 0.0.0.0 --port 7860 --reload --env-file .env --loop asyncio --workers $(workers) + LANGFLOW_AUTO_LOGIN=$(login) poetry run uvicorn \ + --factory langflow.main:create_app \ + --host 0.0.0.0 \ + --port $(port) \ + --reload \ + --env-file $(env) \ + --loop asyncio \ + --workers $(workers) else - @echo "Running backend respecting the .env file"; - poetry run uvicorn --factory langflow.main:create_app --host 0.0.0.0 --port 7860 --reload --env-file .env --loop asyncio --workers $(workers) + @echo "Running backend respecting the $(env) file"; + poetry run uvicorn \ + --factory langflow.main:create_app \ + --host 0.0.0.0 \ + --port $(port) \ + --reload \ + --env-file $(env) \ + --loop asyncio \ + --workers $(workers) endif diff --git a/README.PT.md b/README.PT.md index 8d3197dd7..6f7a93609 100644 --- a/README.PT.md +++ b/README.PT.md @@ -73,7 +73,7 @@ Você também pode visualizar o Langflow no [HuggingFace Spaces](https://hugging # 🎨 Criar Fluxos -Criar fluxos com Langflow é fácil. Basta arrastar componentes da barra lateral para o canvas e conectá-los para começar a construir sua aplicação. +Criar fluxos com Langflow é fácil. Basta arrastar componentes da barra lateral para o workspace e conectá-los para começar a construir sua aplicação. Explore editando os parâmetros do prompt, agrupando componentes e construindo seus próprios componentes personalizados (Custom Components). diff --git a/README.md b/README.md index 64fa185ea..6a15027aa 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ +
+

Langflow 1.0 is OUT! 🎉

+

Read all about it here!

+
+ # [![Langflow](./docs/static/img/hero.png)](https://www.langflow.org) @@ -37,6 +42,7 @@ # 📝 Content +- [](#) - [📝 Content](#-content) - [📦 Get Started](#-get-started) - [🎨 Create Flows](#-create-flows) @@ -44,6 +50,7 @@ - [Deploy Langflow on Google Cloud Platform](#deploy-langflow-on-google-cloud-platform) - [Deploy on Railway](#deploy-on-railway) - [Deploy on Render](#deploy-on-render) + - [Deploy on Kubernetes](#deploy-on-kubernetes) - [🖥️ Command Line Interface (CLI)](#️-command-line-interface-cli) - [Usage](#usage) - [Environment Variables](#environment-variables) @@ -57,10 +64,6 @@ You can install Langflow with pip: ```shell # Make sure you have >=Python 3.10 installed on your system. -# Install the pre-release version (recommended for the latest updates) -python -m pip install langflow --pre --force-reinstall - -# or stable version python -m pip install langflow -U ``` @@ -74,7 +77,7 @@ You can also preview Langflow in [HuggingFace Spaces](https://huggingface.co/spa # 🎨 Create Flows -Creating flows with Langflow is easy. Simply drag components from the sidebar onto the canvas and connect them to start building your application. +Creating flows with Langflow is easy. Simply drag components from the sidebar onto the workspace and connect them to start building your application. Explore by editing prompt parameters, grouping components into a single high-level component, and building your own Custom Components. @@ -100,11 +103,7 @@ Alternatively, click the **"Open in Cloud Shell"** button below to launch Google ## Deploy on Railway -Use this template to deploy Langflow 1.0 Preview on Railway: - -[![Deploy 1.0 Preview on Railway](https://railway.app/button.svg)](https://railway.app/template/UsJ1uB?referralCode=MnPSdg) - -Or this one to deploy Langflow 0.6.x: +Use this template to deploy Langflow 1.0 on Railway: [![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/template/JMXEWp?referralCode=MnPSdg) diff --git a/docker/build_and_push.Dockerfile b/docker/build_and_push.Dockerfile index 79f6ac8d7..448a802e6 100644 --- a/docker/build_and_push.Dockerfile +++ b/docker/build_and_push.Dockerfile @@ -93,5 +93,7 @@ ENV PATH="/app/.venv/bin:${PATH}" USER user WORKDIR /app -ENTRYPOINT ["python", "-m", "langflow", "run"] -CMD ["--host", "0.0.0.0", "--port", "7860"] \ No newline at end of file +ENV LANGFLOW_HOST=0.0.0.0 +ENV LANGFLOW_PORT=7860 + +ENTRYPOINT ["python", "-m", "langflow", "run"] \ No newline at end of file diff --git a/docker/build_and_push_backend.Dockerfile b/docker/build_and_push_backend.Dockerfile index 8b82da524..2efbefb10 100644 --- a/docker/build_and_push_backend.Dockerfile +++ b/docker/build_and_push_backend.Dockerfile @@ -5,4 +5,4 @@ ARG LANGFLOW_IMAGE FROM $LANGFLOW_IMAGE RUN rm -rf /app/.venv/langflow/frontend -CMD ["--host", "0.0.0.0", "--port", "7860", "--backend-only"] +CMD ["--backend-only"] diff --git a/docker/build_and_push_base.Dockerfile b/docker/build_and_push_base.Dockerfile index 916531df2..d539c1ae8 100644 --- a/docker/build_and_push_base.Dockerfile +++ b/docker/build_and_push_base.Dockerfile @@ -95,6 +95,7 @@ USER user # Install the package from the .tar.gz RUN python -m pip install /app/src/backend/base/dist/*.tar.gz --user +ENV LANGFLOW_HOST=0.0.0.0 +ENV LANGFLOW_PORT=7860 ENTRYPOINT ["python", "-m", "langflow", "run"] -CMD ["--host", "0.0.0.0", "--port", "7860"] diff --git a/docker_example/docker-compose.yml b/docker_example/docker-compose.yml index a8fddac71..61c02e65e 100644 --- a/docker_example/docker-compose.yml +++ b/docker_example/docker-compose.yml @@ -10,9 +10,9 @@ services: environment: - LANGFLOW_DATABASE_URL=postgresql://langflow:langflow@postgres:5432/langflow # This variable defines where the logs, file storage, monitor data and secret keys are stored. - - LANGFLOW_CONFIG_DIR=/var/lib/langflow + - LANGFLOW_CONFIG_DIR=/app/langflow volumes: - - langflow-data:/var/lib/langflow + - langflow-data:/app/langflow postgres: image: postgres:16 diff --git a/docs/docs/administration/api.mdx b/docs/docs/administration/api.mdx index db279ed80..737213cfd 100644 --- a/docs/docs/administration/api.mdx +++ b/docs/docs/administration/api.mdx @@ -4,6 +4,10 @@ import Admonition from "@theme/Admonition"; # API Keys + +This page may contain outdated information. It will be updated as soon as possible. + + Langflow provides an API key functionality that allows users to access their individual components and flows without traditional login authentication. The API key is a user-specific token that can be included in the request header or query parameter to authenticate API calls. This documentation outlines how to generate, use, and manage API keys in Langflow. @@ -172,7 +176,7 @@ print(run_flow(inputs, flow_id=FLOW_ID, tweaks=TWEAKS, apiKey=api_key)) ## Custom API endpoint -As of Langflow v1.0 alpha, under **Project Settings** > **Endpoint Name**, you can pick a custom name for the endpoint used to call your flow from the API. +Under **Project Settings** > **Endpoint Name**, you can pick a custom name for the endpoint used to call your flow from the API. ## Revoke an API Key diff --git a/docs/docs/administration/chat-widget.mdx b/docs/docs/administration/chat-widget.mdx index 0a6669cdd..e4d744a40 100644 --- a/docs/docs/administration/chat-widget.mdx +++ b/docs/docs/administration/chat-widget.mdx @@ -6,6 +6,10 @@ import Admonition from "@theme/Admonition"; # Chat Widget + +This page may contain outdated information. It will be updated as soon as possible. + +
The Langflow Chat Widget is a powerful web component that enables communication with a Langflow project. This widget allows for a chat interface diff --git a/docs/docs/administration/cli.mdx b/docs/docs/administration/cli.mdx index 4f11cc721..2a54c1fca 100644 --- a/docs/docs/administration/cli.mdx +++ b/docs/docs/administration/cli.mdx @@ -1,5 +1,11 @@ +import Admonition from "@theme/Admonition"; + # Command Line Interface (CLI) + +This page may contain outdated information. It will be updated as soon as possible. + + Langflow's Command Line Interface (CLI) is a powerful tool that allows you to interact with the Langflow server from the command line. The CLI provides a wide range of commands to help you shape Langflow to your needs. The available commands are below. Navigate to their individual sections of this page to see the parameters. diff --git a/docs/docs/administration/collections-projects.mdx b/docs/docs/administration/collections-projects.mdx new file mode 100644 index 000000000..f0ef70ee4 --- /dev/null +++ b/docs/docs/administration/collections-projects.mdx @@ -0,0 +1,105 @@ +import ThemedImage from "@theme/ThemedImage"; +import useBaseUrl from "@docusaurus/useBaseUrl"; +import ZoomableImage from "/src/theme/ZoomableImage.js"; +import ReactPlayer from "react-player"; +import Admonition from "@theme/Admonition"; + +# Collections and Projects + + +This page may contain outdated information. It will be updated as soon as possible. + + +My Collection is a space in Langflow where users can manage, organize, and access their flows and components. +Flows and components are displayed as individual cards that provide relevant information. + + + +* **Folders**: Users can organize their projects into folders. Default folders include "My Projects" and the ability to create new folders. Hover over a folder to access options to download or delete it. + +* **Search Bar** Enables users to quickly search through their flows and components. + +* **Select All**: This feature allows users to select all projects displayed on the page for batch actions like moving, deleting, or exporting. + +Click on a flow card to open it in Langflow Workspace or use the **Playground Button** for direct access to execute and interact with the flow’s chatbot interface. + +## Collections + +Components created or imported by the user are also displayed in **My Collection** and can be directly removed from here. + +A collection is a snapshot of flows available in a database. + +Collections can be downloaded to local storage and uploaded for future use. + +
+ +
+ +## Project + +A **Project** can be a flow or a component. To view your saved projects, select **My Collection**. + +Your **Projects** are displayed. + +Click the **![Playground icon](/logos/botmessage.svg) Playground** button to run a flow from the **My Collection** screen. + +In the top left corner of the screen are options for **Download Collection**, **Upload Collection**, and **New Project**. + +Select **Download Collection** to save your project to your local machine. This downloads all flows and components as a `.json` file. + +Select **Upload Collection** to upload a flow or component `.json` file from your local machine. + +Select **New Project** to create a new project. In addition to a blank workspace, [starter projects](../starter-projects/basic-prompting) are also available. + +## Project options menu + +To see options for your project, in the upper left corner of the workspace, select the dropdown menu. + + + +* **New** - Start a new project. + +* **Duplicate** - Duplicate the current flow as a new project. + +* **Settings** - Modify the project's **Name** or **Description**. + +* **Import** - Upload a flow `.json` file from your local machine. + +* **Export** - Download your current project to your local machine as a `.json` file. + +* **Undo** or **Redo** - Undo or redo your last action. + +## Project folders + +Multiple projects can be stored in **folders**. + +Folders allow you to categorize flows and components into manageable groups. This makes it easier to find and access specific projects quickly. + +**My Projects** is a default folder where all new projects and components are initially stored unless specified otherwise. Users can create custom folders to better organize their work according to specific needs. + +Hovering over a folder in Langflow provides options to either remove or download the entire folder, allowing you to keep an offline copy or migrate projects between environments + +Create new folders with the **New folder** button. One folder can store multiple projects (as the default My Projects folder does). + +You can download folders of projects as a single JSON file, and upload files and flows to your folder. + +Click the **Trash** icon to delete a folder. + + + diff --git a/docs/docs/administration/global-env.mdx b/docs/docs/administration/global-env.mdx index 06ef488a8..fa8f7ff5d 100644 --- a/docs/docs/administration/global-env.mdx +++ b/docs/docs/administration/global-env.mdx @@ -6,6 +6,10 @@ import Admonition from "@theme/Admonition"; # Global Variables + +This page may contain outdated information. It will be updated as soon as possible. + + Global Variables are a useful feature of Langflow, allowing you to define reusable variables accessed from any Text field in your project. **TL;DR** diff --git a/docs/docs/administration/login.mdx b/docs/docs/administration/login.mdx index 9f3c12cf9..65ed2c178 100644 --- a/docs/docs/administration/login.mdx +++ b/docs/docs/administration/login.mdx @@ -6,6 +6,10 @@ import Admonition from "@theme/Admonition"; # Sign Up and Sign In + +This page may contain outdated information. It will be updated as soon as possible. + + The login functionality in Langflow serves to authenticate users and protect sensitive routes in the application. Starting from version 0.5, Langflow introduces an enhanced login mechanism that is governed by a few environment variables. This allows new secure features. ## Environment variables diff --git a/docs/docs/administration/logs.mdx b/docs/docs/administration/logs.mdx new file mode 100644 index 000000000..85c1497be --- /dev/null +++ b/docs/docs/administration/logs.mdx @@ -0,0 +1,28 @@ +import ThemedImage from "@theme/ThemedImage"; +import useBaseUrl from "@docusaurus/useBaseUrl"; +import ZoomableImage from "/src/theme/ZoomableImage.js"; +import ReactPlayer from "react-player"; +import Admonition from "@theme/Admonition"; + +# Logs + + +This page may contain outdated information. It will be updated as soon as possible. + + +To view logs, go to **Project Options** > **Logs**. + +The **Logs** page provides a detailed record of all component executions within a workspace. + +It is designed to help you track actions, debug issues, and understand the flow of data through various components. + +Each log entry includes an execution with source and target components, and displays the data and parameters passed from one component to another. The status of each execution is indicated and errors encountered are easily detected. + + \ No newline at end of file diff --git a/docs/docs/administration/memories.mdx b/docs/docs/administration/memories.mdx new file mode 100644 index 000000000..5946590ec --- /dev/null +++ b/docs/docs/administration/memories.mdx @@ -0,0 +1,38 @@ +import ThemedImage from "@theme/ThemedImage"; +import useBaseUrl from "@docusaurus/useBaseUrl"; +import ZoomableImage from "/src/theme/ZoomableImage.js"; +import Admonition from "@theme/Admonition"; + +# Chat Memory + + +This page may contain outdated information. It will be updated as soon as possible. + + +Langflow allows every chat message to be stored, and a single flow can have multiple memory sessions. This enables you to create multiple “memories” for agents to store and recall specific information as needed. You can edit and remove previous messages to inspect and validate a model’s response behavior. Control, explore, and manage conversation histories to get your models acting just right. + +The **Chat Memory** component retrieves message histories by session ID. Users can change the session ID in the advanced settings, with the default session ID set to match the flow ID. These memories are accessible and manageable directly from the Playground; modifications to them directly affect the behavior of chatbot responses. Users can remove or edit previous messages to manipulate and explore model responses further. + + + +By default, chat conversations store Message objects categorized by session ID. A a single flow can host multiple session IDs, and different flows can also share the same session ID. + +Memories can be visualized and managed directly from the Playground. Modifying these memories will influence the behavior of the chatbot responses, as long as an agent uses them. Here you have the ability to remove or edit previous messages, allowing them to manipulate and explore how these changes affect model responses. + + + +You can also display all messages stored across every flow in your workspace by going to **Settings** > **Messages**. \ No newline at end of file diff --git a/docs/docs/administration/playground.mdx b/docs/docs/administration/playground.mdx index c3ed5c4b7..1ef59e08b 100644 --- a/docs/docs/administration/playground.mdx +++ b/docs/docs/administration/playground.mdx @@ -6,13 +6,20 @@ import Admonition from "@theme/Admonition"; # Playground -In Langflow 1.0 alpha, the **Playground** replaces the **Interaction Panel**. + +This page may contain outdated information. It will be updated as soon as possible. + -The **Playground** provides an interface for interacting with flows without opening them in the flow editor. + + From the **My Collection** page, click the Playground button in one of your flow cards. + It will directly open up a window with that project's Playground, without even showing the flow (this also works for flows hosted on the Langflow Store!). + + +The **Playground** is a dynamic interface designed for real-time interaction with agents, allowing users to access and manage memories and monitor the inputs and outputs. Here, users can directly prototype and experiment with their configured components or AI models, making adjustments and observing different outcomes in real-time. It even works for flows hosted on the Langflow store! -As long as you have a flow's environment variables set, you can run it by clicking the **Playground** button. +As long as you have a flow properly working, you can interact with it by clicking the Playground button. 1. From your **Collections** page, click the **![Playground icon](/logos/botmessage.svg)Playground** in one of your flows. The **Playground** window opens. @@ -36,7 +43,7 @@ As long as you have a flow's environment variables set, you can run it by clicki ## Playground I/O -The Playground's appearance changes depending on what components are in your canvas. +The Playground's window arrangement changes depending on what components are being used. Adding or removing any of the below components modifies your Playground so you can monitor the inputs and outputs. @@ -59,3 +66,4 @@ Langflow allows every chat message to be stored, and a single flow can have mult You can edit and remove previous messages to inspect and validate a model’s response behavior. +For more information, see [Memories](./memories). diff --git a/docs/docs/administration/prompt-customization.mdx b/docs/docs/administration/prompt-customization.mdx index 2a1b1f210..42036f88b 100644 --- a/docs/docs/administration/prompt-customization.mdx +++ b/docs/docs/administration/prompt-customization.mdx @@ -2,9 +2,14 @@ import ThemedImage from "@theme/ThemedImage"; import useBaseUrl from "@docusaurus/useBaseUrl"; import ZoomableImage from "/src/theme/ZoomableImage.js"; import ReactPlayer from "react-player"; +import Admonition from "@theme/Admonition"; # Prompt Customization + +This page may contain outdated information. It will be updated as soon as possible. + + The prompt template allows users to create prompts and define variables that provide control over instructing the model. {" "} diff --git a/docs/docs/administration/settings.mdx b/docs/docs/administration/settings.mdx index 39c6081c7..dba6da78b 100644 --- a/docs/docs/administration/settings.mdx +++ b/docs/docs/administration/settings.mdx @@ -1,5 +1,12 @@ +import Admonition from "@theme/Admonition"; + # Settings + +This page may contain outdated information. It will be updated as soon as possible. + + +Change the **Project Settings** or **General Settings** for Langflow. ## Project Settings diff --git a/docs/docs/components/agents.mdx b/docs/docs/components/agents.mdx index 00d597804..4482c0637 100644 --- a/docs/docs/components/agents.mdx +++ b/docs/docs/components/agents.mdx @@ -2,6 +2,10 @@ import Admonition from "@theme/Admonition"; # Agents + +This page may contain outdated information. It will be updated as soon as possible. + + Agents are components that use reasoning to make decisions and take actions, designed to autonomously perform tasks or provide services with some degree of agency. LLM chains can only perform hardcoded sequences of actions, while agents use LLMs to reason through which actions to take, and in which order. --- diff --git a/docs/docs/components/chains.mdx b/docs/docs/components/chains.mdx index a57f442e3..3d4b60b6a 100644 --- a/docs/docs/components/chains.mdx +++ b/docs/docs/components/chains.mdx @@ -5,6 +5,10 @@ import Admonition from "@theme/Admonition"; # Chains + +This page may contain outdated information. It will be updated as soon as possible. + + Chains, in the context of language models, refer to a series of calls made to a language model. This approach allows for using the output of one call as the input for another. Different chain types facilitate varying complexity levels, making them useful for creating pipelines and executing specific scenarios. --- diff --git a/docs/docs/components/custom.mdx b/docs/docs/components/custom.mdx index e17b9db8d..10b45c9b7 100644 --- a/docs/docs/components/custom.mdx +++ b/docs/docs/components/custom.mdx @@ -1,105 +1,227 @@ +import ThemedImage from "@theme/ThemedImage"; +import useBaseUrl from "@docusaurus/useBaseUrl"; +import ZoomableImage from "/src/theme/ZoomableImage.js"; +import ReactPlayer from "react-player"; import Admonition from "@theme/Admonition"; # Custom Components - - Read the [Custom Component Tutorial](../tutorials/custom_components) for - detailed information on custom components. + +This page may contain outdated information. It will be updated as soon as possible. -Custom components let you extend Langflow by creating reusable and configurable components from a Python script. +Build custom components in Langflow for various data processing and transformation tasks. -## Usage +This guide provides a comprehensive overview of how to create custom components using Langflow. -To create a custom component: +## Basic Structure of a Custom Component -1. Define a class that inherits from `langflow.CustomComponent`. -2. Implement a `build` method in your class. -3. Use type annotations in the `build` method to define component fields. -4. Optionally, use the `build_config` method to customize field appearance and behavior. +A custom component in Langflow typically includes the following parts: -**Parameters** +1. **Class Definition**: Inherits from the `Component` class. +2. **Component Metadata**: Defines display name, description, and icon. +3. **Inputs and Outputs**: Specifies the inputs and outputs for the component. +4. **Processing Logic**: Implements the logic for processing data within the component. -- **Code:** The Python code that defines the component. +A custom component in Python looks like this: -## CustomComponent Class +```python +from langflow.custom import Component +from langflow.inputs import MessageTextInput, IntInput, BoolInput, DropdownInput, HandleInput +from langflow.template import Output +from langflow.schema import Data, Message +from typing import List, Optional -This class is the foundation for creating custom components. It allows users to create new, configurable components tailored to their needs. +class ExampleComponent(Component): + display_name = "Example Component" + description = "A template for creating custom components." + icon = "icon-name" -### Methods + inputs = [ + MessageTextInput( + name="input_text", + display_name="Input Text", + info="Text input for the component.", + ), + IntInput( + name="input_number", + display_name="Input Number", + info="Numeric input for the component.", + ), + BoolInput( + name="input_boolean", + display_name="Input Boolean", + info="Boolean input for the component.", + ), + DropdownInput( + name="input_choice", + display_name="Input Choice", + options=["Option1", "Option2", "Option3"], + info="Dropdown input for the component.", + ), + ] -**build:** This method is essential in a `CustomComponent` class. It defines the component's functionality and how it processes input data. The build method is invoked when you click the **Build** button on the canvas. + outputs = [ + Output(display_name="Output Data", name="output_data", method="process_data"), + ] -The following types are supported in the build method: + def process_data(self) -> Data: + input_text = self.input_text + input_number = self.input_number + input_boolean = self.input_boolean + input_choice = self.input_choice -| Supported Types | -| ----------------------------------------------------------------- | -| _`str`_, _`int`_, _`float`_, _`bool`_, _`list`_, _`dict`_ | -| _`langflow.field_typing.NestedDict`_ | -| _`langflow.field_typing.Prompt`_ | -| _`langchain.chains.base.Chain`_ | -| _`langchain.PromptTemplate`_ | -| _`from langchain.schema.language_model import BaseLanguageModel`_ | -| _`langchain.Tool`_ | -| _`langchain.document_loaders.base.BaseLoader`_ | -| _`langchain.schema.Document`_ | -| _`langchain.text_splitters.TextSplitter`_ | -| _`langchain.vectorstores.base.VectorStore`_ | -| _`langchain.embeddings.base.Embeddings`_ | -| _`langchain.schema.BaseRetriever`_ | + # Implement your processing logic here + result = f"Processed: {input_text}, {input_number}, {input_boolean}, {input_choice}" -The difference between _`dict`_ and _`langflow.field_typing.NestedDict`_ is that one adds a simple key-value pair field, while the other opens a more robust dictionary editor. + self.status = result + return Data(data={"result": result}) - - Use the `Prompt` type by adding **kwargs to the build method. If you want to - add the values of the variables to the template you defined, format the - `PromptTemplate` inside the `CustomComponent` class. - +``` - - Use base Python types without a handle by default. To add handles, use the - `input_types` key in the `build_config` method. - +## Create a Custom Component Step-by-Step -**build_config:** Defines the configuration fields of the component. This method returns a dictionary where each key represents a field name and each value defines the field's behavior. +1. Create a class that inherits from the `Component` class. -Supported keys for configuring fields: +```python +class ExampleComponent(Component): + # Class content +``` -| Key | Description | -| ------------------- | --------------------------------------------------------- | -| `is_list` | Boolean indicating if the field can hold multiple values. | -| `options` | Dropdown menu options. | -| `multiline` | Boolean indicating if a field allows multiline input. | -| `input_types` | Allows connection handles for string fields. | -| `display_name` | Field name displayed in the UI. | -| `advanced` | Hides the field in the default UI view. | -| `password` | Masks input, useful for sensitive data. | -| `required` | Overrides the default behavior to make a field mandatory. | -| `info` | Tooltip for the field. | -| `file_types` | Accepted file types, useful for file fields. | -| `range_spec` | Defines valid ranges for float fields. | -| `title_case` | Boolean that controls field name capitalization. | -| `refresh_button` | Adds a refresh button that updates field values. | -| `real_time_refresh` | Updates the configuration as field values change. | -| `field_type` | Automatically set based on the build method's type hint. | +2. Define metadata such as `display_name`, `description`, and `icon`. - - Use the `update_build_config` method to dynamically update configurations - based on field values. - +```python +display_name = "Example Component" +description = "A template for creating custom components." +icon = "icon-name" +``` -## Additional methods and attributes +3. Define the inputs and outputs for the component using the `inputs` and `outputs` lists. -The `CustomComponent` class also provides helpful methods for specific tasks (e.g., to load and use other flows from the Langflow platform): +**Inputs** can be of various types such as `TextInput`, `IntInput`, `BoolInput`, `DropdownInput`, etc. -### Methods +```python +inputs = [ + MessageTextInput( + name="input_text", + display_name="Input Text", + info="Text input for the component.", + ), + IntInput( + name="input_number", + display_name="Input Number", + info="Numeric input for the component.", + ), + BoolInput( + name="input_boolean", + display_name="Input Boolean", + info="Boolean input for the component.", + ), + DropdownInput( + name="input_choice", + display_name="Input Choice", + options=["Option1", "Option2", "Option3"], + info="Dropdown input for the component.", + ), +] -- `list_flows`: Lists available flows. -- `get_flow`: Retrieves a specific flow by name or ID. -- `load_flow`: Loads a flow by ID. +``` -### Attributes +**Outputs** define the output methods for the component. -- `status`: Shows values from the `build` method, useful for debugging. -- `field_order`: Controls the display order of fields. -- `icon`: Sets the canvas display icon. +```python +outputs = [ + Output(display_name="Output Data", name="output_data", method="process_data"), +] +``` + +4. Implement the logic for processing data within the component. Define methods for processing data and returning results. + +```python +def process_data(self) -> Data: + input_text = self.input_text + input_number = self.input_number + input_boolean = self.input_boolean + input_choice = self.input_choice + + # Implement your processing logic here + result = f"Processed: {input_text}, {input_number}, {input_boolean}, {input_choice}" + + self.status = result + return Data(data={"result": result}) + +``` + +## Advanced Example: Create a Conditional Router Component + +This example demonstrates a more complex component that routes data based on a condition. + +Notice that this component has two outputs associated with the methods `true_response` and `false_response`. + +These methods trigger `self.stop` to block the transmission for the selected output, allowing for logic operations to be implemented visually. + +```python +from langflow.custom import Component +from langflow.inputs import MessageTextInput, DropdownInput, BoolInput +from langflow.template import Output +from langflow.field_typing import Text + +class ConditionalRouterComponent(Component): + display_name = "Conditional Router" + description = "Routes input based on a specified condition." + icon = "router" + + inputs = [ + MessageTextInput( + name="input_value", + display_name="Input Value", + info="Value to be evaluated.", + ), + MessageTextInput( + name="comparison_value", + display_name="Comparison Value", + info="Value to compare against.", + ), + DropdownInput( + name="operator", + display_name="Operator", + options=["equals", "not equals", "contains"], + info="Comparison operator.", + ), + ] + + outputs = [ + Output(display_name="True Output", name="true_output", method="true_response"), + Output(display_name="False Output", name="false_response", method="false_response"), + ] + + def evaluate_condition(self, input_value: str, comparison_value: str, operator: str) -> bool: + if operator == "equals": + return input_value == comparison_value + elif operator == "not equals": + return input_value != comparison_value + elif operator == "contains": + return comparison_value in input_value + return False + + def true_response(self) -> Text: + if self.evaluate_condition(self.input_value, self.comparison_value, self.operator): + self.stop("false_response") + return self.input_value + else: + self.stop("true_response") + return "" + + def false_response(self) -> Text: + if not self.evaluate_condition(self.input_value, self.comparison_value, self.operator): + self.stop("true_response") + return self.input_value + else: + self.stop("false_response") + return "" + +``` + +By following these steps and examples, you can create custom components in Langflow tailored to your specific needs. The modular structure of Custom Components allows for flexible and reusable components that can be easily integrated into your workflows. + +--- diff --git a/docs/docs/components/data.mdx b/docs/docs/components/data.mdx index d7f525d7d..2c62b2664 100644 --- a/docs/docs/components/data.mdx +++ b/docs/docs/components/data.mdx @@ -2,6 +2,10 @@ import Admonition from "@theme/Admonition"; # Data + +This page may contain outdated information. It will be updated as soon as possible. + + ## API Request This component sends HTTP requests to the specified URLs. diff --git a/docs/docs/components/embeddings.mdx b/docs/docs/components/embeddings.mdx index 24743ec1c..9a224b048 100644 --- a/docs/docs/components/embeddings.mdx +++ b/docs/docs/components/embeddings.mdx @@ -1,5 +1,11 @@ +import Admonition from "@theme/Admonition"; + # Embeddings + +This page may contain outdated information. It will be updated as soon as possible. + + ## Amazon Bedrock Embeddings Used to load embedding models from [Amazon Bedrock](https://aws.amazon.com/bedrock/). diff --git a/docs/docs/components/experimental.mdx b/docs/docs/components/experimental.mdx index a6f35d024..5abee146d 100644 --- a/docs/docs/components/experimental.mdx +++ b/docs/docs/components/experimental.mdx @@ -2,6 +2,10 @@ import Admonition from "@theme/Admonition"; # Experimental + +This page may contain outdated information. It will be updated as soon as possible. + + Components in the experimental phase are currently in beta. They have been initially developed and tested but haven't yet achieved a stable or fully supported status. We encourage users to explore these components, provide feedback, and report any issues encountered. --- diff --git a/docs/docs/components/helpers.mdx b/docs/docs/components/helpers.mdx index 59fb63564..c30315a42 100644 --- a/docs/docs/components/helpers.mdx +++ b/docs/docs/components/helpers.mdx @@ -2,6 +2,10 @@ import Admonition from "@theme/Admonition"; # Helpers + +This page may contain outdated information. It will be updated as soon as possible. + + ### Chat memory This component retrieves stored chat messages based on a specific session ID. diff --git a/docs/docs/components/inputs-and-outputs.mdx b/docs/docs/components/inputs-and-outputs.mdx index f5592e7fd..8b78d8567 100644 --- a/docs/docs/components/inputs-and-outputs.mdx +++ b/docs/docs/components/inputs-and-outputs.mdx @@ -4,6 +4,10 @@ import useBaseUrl from "@docusaurus/useBaseUrl"; # Inputs and Outputs + +This page may contain outdated information. It will be updated as soon as possible. + + Inputs and Outputs are a category of components that are used to define where data comes in and out of your flow. They also dynamically change the Playground and can be renamed to facilitate building and maintaining your flows. diff --git a/docs/docs/components/loaders.mdx b/docs/docs/components/loaders.mdx index b7f2d11fb..66c0c3a31 100644 --- a/docs/docs/components/loaders.mdx +++ b/docs/docs/components/loaders.mdx @@ -2,6 +2,10 @@ import Admonition from '@theme/Admonition'; # Loaders + +This page may contain outdated information. It will be updated as soon as possible. + +

We appreciate your understanding as we polish our documentation – it may contain some rough edges. Share your feedback or report issues to help us improve! 🛠️📝 diff --git a/docs/docs/components/memories.mdx b/docs/docs/components/memories.mdx index a133c6a6a..3fdf61066 100644 --- a/docs/docs/components/memories.mdx +++ b/docs/docs/components/memories.mdx @@ -2,6 +2,10 @@ import Admonition from "@theme/Admonition"; # Memories + +This page may contain outdated information. It will be updated as soon as possible. + +

Thanks for your patience as we improve our documentation—it might have some diff --git a/docs/docs/components/model_specs.mdx b/docs/docs/components/model_specs.mdx index 21ee1849b..d5835e9d7 100644 --- a/docs/docs/components/model_specs.mdx +++ b/docs/docs/components/model_specs.mdx @@ -2,6 +2,10 @@ import Admonition from "@theme/Admonition"; # Large Language Models (LLMs) + +This page may contain outdated information. It will be updated as soon as possible. + + A Large Language Model (LLM) is a foundational component of Langflow. It provides a uniform interface for interacting with LLMs from various providers, including OpenAI, Cohere, and HuggingFace. Langflow extensively uses LLMs across its chains and agents, employing them to generate text based on specific prompts or inputs. --- diff --git a/docs/docs/components/models.mdx b/docs/docs/components/models.mdx index f02c1654b..4d739b59e 100644 --- a/docs/docs/components/models.mdx +++ b/docs/docs/components/models.mdx @@ -2,6 +2,10 @@ import Admonition from "@theme/Admonition"; # Models + +This page may contain outdated information. It will be updated as soon as possible. + + ## Amazon Bedrock This component facilitates the generation of text using the LLM (Large Language Model) model from Amazon Bedrock. diff --git a/docs/docs/components/retrievers.mdx b/docs/docs/components/retrievers.mdx index 792b9e20b..e13ed2d89 100644 --- a/docs/docs/components/retrievers.mdx +++ b/docs/docs/components/retrievers.mdx @@ -2,6 +2,10 @@ import Admonition from "@theme/Admonition"; # Retrievers + +This page may contain outdated information. It will be updated as soon as possible. + + A retriever is an interface that returns documents in response to an unstructured query. It's broader than a vector store because it doesn't need to store documents; it only needs to retrieve them. --- diff --git a/docs/docs/components/text-and-record.mdx b/docs/docs/components/text-and-record.mdx index fe2e61644..ab3f9302f 100644 --- a/docs/docs/components/text-and-record.mdx +++ b/docs/docs/components/text-and-record.mdx @@ -1,6 +1,12 @@ +import Admonition from "@theme/Admonition"; + # Text and Data -In Langflow 1.0, we added two main input and output types: `Text` and `Data`. + +This page may contain outdated information. It will be updated as soon as possible. + + +There are two main input and output types: `Text` and `Data`. `Text` is a simple string input and output type, while `Data` is a structure very similar to a dictionary in Python. It is a key-value pair data structure. diff --git a/docs/docs/components/text-splitters.mdx b/docs/docs/components/text-splitters.mdx index 02e7a311b..b438d9c21 100644 --- a/docs/docs/components/text-splitters.mdx +++ b/docs/docs/components/text-splitters.mdx @@ -2,6 +2,10 @@ import Admonition from "@theme/Admonition"; # Text Splitters + +This page may contain outdated information. It will be updated as soon as possible. + + A text splitter is a tool that divides a document or text into smaller chunks or segments. This helps make large texts more manageable for analysis or processing. --- diff --git a/docs/docs/components/toolkits.mdx b/docs/docs/components/toolkits.mdx index 3ba7ed7c7..f4b2004ba 100644 --- a/docs/docs/components/toolkits.mdx +++ b/docs/docs/components/toolkits.mdx @@ -2,6 +2,10 @@ import Admonition from "@theme/Admonition"; # Toolkits + +This page may contain outdated information. It will be updated as soon as possible. + +

We appreciate your understanding as we polish our documentation - it may diff --git a/docs/docs/components/tools.mdx b/docs/docs/components/tools.mdx index 6460db860..a7daae919 100644 --- a/docs/docs/components/tools.mdx +++ b/docs/docs/components/tools.mdx @@ -2,6 +2,10 @@ import Admonition from "@theme/Admonition"; # Tools + +This page may contain outdated information. It will be updated as soon as possible. + + ## SearchApi SearchApi offers a real-time search engine results API that returns structured JSON data, including answer boxes, knowledge graphs, organic results, and more. diff --git a/docs/docs/components/utilities.mdx b/docs/docs/components/utilities.mdx index 44263f583..e0e95aa78 100644 --- a/docs/docs/components/utilities.mdx +++ b/docs/docs/components/utilities.mdx @@ -2,6 +2,10 @@ import Admonition from "@theme/Admonition"; # Utilities + +This page may contain outdated information. It will be updated as soon as possible. + + Utilities are a set of actions that can be used to perform common tasks in a flow. They are available in the **Utilities** section in the sidebar. --- diff --git a/docs/docs/components/vector-stores.mdx b/docs/docs/components/vector-stores.mdx index 56e4e094a..cf4dc1668 100644 --- a/docs/docs/components/vector-stores.mdx +++ b/docs/docs/components/vector-stores.mdx @@ -2,6 +2,10 @@ import Admonition from "@theme/Admonition"; # Vector Stores + +This page may contain outdated information. It will be updated as soon as possible. + + ### Astra DB The `Astra DB` initializes a vector store using Astra DB from Data. It creates Astra DB-based vector indexes to efficiently store and retrieve documents. diff --git a/docs/docs/contributing/community.md b/docs/docs/contributing/community.mdx similarity index 85% rename from docs/docs/contributing/community.md rename to docs/docs/contributing/community.mdx index 5c95718ec..964abf277 100644 --- a/docs/docs/contributing/community.md +++ b/docs/docs/contributing/community.mdx @@ -1,5 +1,11 @@ +import Admonition from "@theme/Admonition"; + # Community + +This page may contain outdated information. It will be updated as soon as possible. + + ## 🤖 Join **Langflow** Discord server Join us to ask questions and showcase your projects. diff --git a/docs/docs/contributing/contribute-component.md b/docs/docs/contributing/contribute-component.mdx similarity index 84% rename from docs/docs/contributing/contribute-component.md rename to docs/docs/contributing/contribute-component.mdx index d252a0929..4ad8072f3 100644 --- a/docs/docs/contributing/contribute-component.md +++ b/docs/docs/contributing/contribute-component.mdx @@ -1,8 +1,13 @@ import ZoomableImage from "/src/theme/ZoomableImage.js"; +import Admonition from "@theme/Admonition"; # How to Contribute Components? -As of Langflow 1.0 alpha, new components are added as objects of the [CustomComponent](https://github.com/langflow-ai/langflow/blob/dev/src/backend/base/langflow/interface/custom/custom_component/custom_component.py) class and any dependencies are added to the [pyproject.toml](https://github.com/langflow-ai/langflow/blob/dev/pyproject.toml#L27) file. + +This page may contain outdated information. It will be updated as soon as possible. + + +New components are added as objects of the [CustomComponent](https://github.com/langflow-ai/langflow/blob/dev/src/backend/base/langflow/interface/custom/custom_component/custom_component.py) class and any dependencies are added to the [pyproject.toml](https://github.com/langflow-ai/langflow/blob/dev/pyproject.toml#L27) file. ## Add an example component diff --git a/docs/docs/contributing/github-issues.md b/docs/docs/contributing/github-issues.mdx similarity index 88% rename from docs/docs/contributing/github-issues.md rename to docs/docs/contributing/github-issues.mdx index 269c976cd..84d049849 100644 --- a/docs/docs/contributing/github-issues.md +++ b/docs/docs/contributing/github-issues.mdx @@ -1,5 +1,11 @@ +import Admonition from "@theme/Admonition"; + # GitHub Issues + +This page may contain outdated information. It will be updated as soon as possible. + + Our [issues](https://github.com/langflow-ai/langflow/issues) page is kept up to date with bugs, improvements, and feature requests. There is a taxonomy of labels to help with sorting and discovery of issues of interest. diff --git a/docs/docs/contributing/how-contribute.md b/docs/docs/contributing/how-contribute.mdx similarity index 92% rename from docs/docs/contributing/how-contribute.md rename to docs/docs/contributing/how-contribute.mdx index ff0df55a6..6776be0b1 100644 --- a/docs/docs/contributing/how-contribute.md +++ b/docs/docs/contributing/how-contribute.mdx @@ -1,5 +1,11 @@ +import Admonition from "@theme/Admonition"; + # How to Contribute? + +This page may contain outdated information. It will be updated as soon as possible. + + 👋 Hello there! We welcome contributions from developers of all levels to our open-source project on [GitHub](https://github.com/langflow-ai/langflow). If you'd like to contribute, please check our contributing guidelines and help make Langflow more accessible. As an open-source project in a rapidly developing field, we are extremely open diff --git a/docs/docs/deployment/backend-only.md b/docs/docs/deployment/backend-only.mdx similarity index 96% rename from docs/docs/deployment/backend-only.md rename to docs/docs/deployment/backend-only.mdx index 4122373f3..1fc16de2f 100644 --- a/docs/docs/deployment/backend-only.md +++ b/docs/docs/deployment/backend-only.mdx @@ -1,5 +1,11 @@ +import Admonition from "@theme/Admonition"; + # Backend-only + +This page may contain outdated information. It will be updated as soon as possible. + + You can run Langflow in `--backend-only` mode to expose your Langflow app as an API, without running the frontend UI. Start langflow in backend-only mode with `python3 -m langflow run --backend-only`. diff --git a/docs/docs/deployment/docker.md b/docs/docs/deployment/docker.mdx similarity index 90% rename from docs/docs/deployment/docker.md rename to docs/docs/deployment/docker.mdx index a8864db55..e734d6210 100644 --- a/docs/docs/deployment/docker.md +++ b/docs/docs/deployment/docker.mdx @@ -1,5 +1,11 @@ +import Admonition from "@theme/Admonition"; + # Docker + +This page may contain outdated information. It will be updated as soon as possible. + + This guide will help you get LangFlow up and running using Docker and Docker Compose. ## Prerequisites diff --git a/docs/docs/deployment/gcp-deployment.md b/docs/docs/deployment/gcp-deployment.mdx similarity index 93% rename from docs/docs/deployment/gcp-deployment.md rename to docs/docs/deployment/gcp-deployment.mdx index e126e785c..e2abace6b 100644 --- a/docs/docs/deployment/gcp-deployment.md +++ b/docs/docs/deployment/gcp-deployment.mdx @@ -1,5 +1,11 @@ +import Admonition from "@theme/Admonition"; + # Deploy on Google Cloud Platform + +This page may contain outdated information. It will be updated as soon as possible. + + ## Run Langflow from a New Google Cloud Project This guide will help you set up a Langflow development VM in a Google Cloud Platform project using Google Cloud Shell. diff --git a/docs/docs/examples/chat-memory.mdx b/docs/docs/examples/chat-memory.mdx index 88dbbca2b..4fa2775aa 100644 --- a/docs/docs/examples/chat-memory.mdx +++ b/docs/docs/examples/chat-memory.mdx @@ -6,9 +6,13 @@ import Admonition from "@theme/Admonition"; # Chat Memory + +This page may contain outdated information. It will be updated as soon as possible. + + The **Chat Memory** component restores previous messages given a Session ID, which can be any string. -This component is available under the **Helpers** tab of the Langflow preview. +This component is available under the **Helpers** tab of the Langflow sidebar.

+This page may contain outdated information. It will be updated as soon as possible. + + With LLM pipelines, combining text from different sources may be as important as splitting text. The **Combine Text** component concatenates two text inputs into a single chunk using a specified delimiter, such as whitespace or a newline. Also, check out **Combine Texts (Unsorted)** as a similar alternative. -This component is available under the **Helpers** tab of the Langflow preview. +This component is available under the **Helpers** tab of the Langflow sidebar.
+This page may contain outdated information. It will be updated as soon as possible. + + In Langflow, a `Data` has a structure very similar to a Python dictionary. It is a key-value pair data structure. The **Create Data** component allows you to dynamically create a `Data` from a specified number of inputs. You can add as many key-value pairs as you want (as long as it is less than 15 😅). Once you've chosen the number of `Data`, add keys and fill up values, or pass on values from other components to the component using the input handles. diff --git a/docs/docs/examples/pass.mdx b/docs/docs/examples/pass.mdx index ddfe35cca..5f75adac1 100644 --- a/docs/docs/examples/pass.mdx +++ b/docs/docs/examples/pass.mdx @@ -6,6 +6,10 @@ import Admonition from "@theme/Admonition"; # Pass + +This page may contain outdated information. It will be updated as soon as possible. + + Sometimes all you need to do is… nothing! The **Pass** component enables you to ignore one input and move forward with another one. This is super helpful to swap routes for A/B testing! diff --git a/docs/docs/examples/store-message.mdx b/docs/docs/examples/store-message.mdx index 75ff0bd46..df2cb3c39 100644 --- a/docs/docs/examples/store-message.mdx +++ b/docs/docs/examples/store-message.mdx @@ -6,6 +6,10 @@ import Admonition from "@theme/Admonition"; # Store Message + +This page may contain outdated information. It will be updated as soon as possible. + + The **Store Message** component allows you to save information under a specified Session ID and sender type. The **Message History** component can then be used to retrieve stored messages. diff --git a/docs/docs/examples/sub-flow.mdx b/docs/docs/examples/sub-flow.mdx index d2b9674ad..31cc7448e 100644 --- a/docs/docs/examples/sub-flow.mdx +++ b/docs/docs/examples/sub-flow.mdx @@ -6,6 +6,10 @@ import Admonition from "@theme/Admonition"; # Sub Flow + +This page may contain outdated information. It will be updated as soon as possible. + + The **Sub Flow** component enables a user to select a previously built flow and dynamically generate a component out of it.
+This page may contain outdated information. It will be updated as soon as possible. + + The **Text Operator** component simplifies logic. It evaluates the results from another component (for example, if the input text exactly equals `Tuna`) and runs another component based on the results. Basically, the text operator is an if/else component for your flow.
**Basic prompting** to open a canvas with the flow pre-built. - -## Flows, components, collections, and projects - -A [flow](#flow) is a pipeline of components connected together in the Langflow canvas. - -A [component](#component) is a single building block within a flow. A component has inputs, outputs, and parameters that define its functionality. - -A [collection](#collection) is a snapshot of the flows available in your database. Collections can be downloaded to local storage and uploaded for future use. - -A [project](#project) can be a component or a flow. Projects are saved as part of your collection. - -For example, the **OpenAI LLM** is a **component** of the **Basic prompting** flow, and the **flow** is stored in a **collection**. - -## Flow - -A **flow** is a pipeline of components connected together in the Langflow canvas. - -For example, the [Basic prompting](../starter-projects/basic-prompting) flow is a pipeline of four components: - - - -In this flow, the **OpenAI LLM component** receives input (left side) and produces output (right side) - in this case, receiving input from the **Chat Input** and **Prompt** components and producing output to the **Chat Output** component. - -## Component - -Components are the building blocks of flows. They consist of inputs, outputs, and parameters that define their functionality. These elements provide a convenient and straightforward way to compose LLM-based applications. Learn more about components and how they work in the LangChain [documentation](https://python.langchain.com/docs/integrations/components). - -
- During the flow creation process, you will notice handles (colored circles) - attached to one or both sides of a component. These handles represent the - availability to connect to other components. Hover over a handle to see - connection details. -
- -
- For example, if you select a ConversationChain component, you - will see orange o and purple{" "} - o input handles. They indicate that - this component accepts an LLM and a Memory component as inputs. The red - asterisk * means that at least one input - of that type is required. -
- -{" "} - - - -
-In the top right corner of the component, you'll find the component status icon (![Status icon](/logos/playbutton.svg)). -Build the flow by clicking the **![Playground icon](/logos/botmessage.svg)Playground** at the bottom right of the canvas. - -Once the validation is complete, the status of each validated component should turn green (![Status icon](/logos/greencheck.svg)). -To debug, hover over the component status to see the outputs. - -
- -### Multiple outputs - -A component can have multiple outputs. For example, this one Chat Input component routes through three prompt chains, and returns three different responses to a single question in the Playground. - - - -### Output Preview - -Langflow now includes an output visualizer for components that opens a pop-up screen. This allows you to easily inspect and monitor transmissions between components, providing instant feedback on your workflows. - -### Component Parameters - -Langflow components can be edited by clicking the component settings button. - -
- -
- -Hide parameters with the **SHOW** button to reduce complexity and keep the canvas clean and intuitive for experimentation. - -Double-click the component name to rename it. - -### Component menu - -Each component is a little unique, but they will all have a menu bar on top that looks something like this. -The menu options are **Code**, **Advanced Settings**, **Freeze**, and **More**. - - - -### Code menu - -The **Code** button displays your component's Python code. -You can modify the code and save it. - -### Advanced Settings - -Modify the parameters of your component. - -#### Freeze - -After a component runs, lock its previous output state to prevent it from re-running. - -This avoids spending tokens when consistent output is expected. - -#### More - -**Code** - Modify your component's Python code. -**Advanced** - modify the parameters of your component. - -
- -
- -**Copy** - copy your component. - -**Share** - share your component to the Langflow store. - -**Docs** - view documentation for your component. - -**Delete** - delete your component. - -### Group multiple components - -Components without input or output nodes can be grouped into a single component for reuse. -This is useful for combining large flows into single components (like RAG with a vector database, for example) and saves space in the canvas. - -1. Hold **Shift** and drag to select the **Prompt** and **OpenAI** components. -2. Select **Group**. -3. The components merge into a single component. -4. To save the new component, select **Save**. It can now be reused from the **Saved** components folder. - -### Update component version - -Canvas component state is stored in a database, while sidebar components are like starter templates. - -As soon as you drag a component from the sidebar to the canvas, the two components are no longer in parity. - -The canvas component will keep the version number it was initilized to the canvas with. Click the **Update Component** icon to bring the component up to the `latest` version. - -## Playground - -Run your flow by clicking the **![Playground icon](/logos/botmessage.svg)Playground** button. - -For more, see [Playground](../administration/playground). - -## API - -The **API** button opens the API window, where Langflow presents code for integrating your flow into external applications. - -Modify the call's parameters in the **Tweaks** window, click the **Copy Code** or **Download** buttons, and paste your code where you want to use it. - - - -### curl - -The **curl** tab displays sample code for posting a query to your flow. -Modify the `input_value` to change your input message. -Copy the code and run it to post a query to your flow and get the result. - -```curl -curl -X POST \ - http://127.0.0.1:7863/api/v1/run/f2eefd80-bb91-4190-9279-0d6ffafeaac4\?stream\=false \ - -H 'Content-Type: application/json'\ - -d '{"input_value": "is anybody there?", - "output_type": "chat", - "input_type": "chat", - "tweaks": { - "Prompt-uxBqP": {}, - "OpenAIModel-k39HS": {}, - "ChatOutput-njtka": {}, - "ChatInput-P3fgL": {} -}}' -``` - -Result: - -``` -{"session_id":"f2eefd80-bb91-4190-9279-0d6ffafeaac4:53856a772b8e1cfcb3dd2e71576b5215399e95bae318d3c02101c81b7c252da3","outputs":[{"inputs":{"input_value":"is anybody there?"},"outputs":[{"results":{"result":"Arrr, me hearties! Aye, this be Captain [Your Name] speakin'. What be ye needin', matey?"},"artifacts":{"message":"Arrr, me hearties! Aye, this be Captain [Your Name] speakin'. What be ye needin', matey?","sender":"Machine","sender_name":"AI"},"messages":[{"message":"Arrr, me hearties! Aye, this be Captain [Your Name] speakin'. What be ye needin', matey?","sender":"Machine","sender_name":"AI","component_id":"ChatOutput-njtka"}],"component_display_name":"Chat Output","component_id":"ChatOutput-njtka"}]}]}% -``` - -### Python API - -The **Python API** tab displays code to interact with your flow using the Python HTTP requests library. - -### Python Code - -The **Python Code** tab displays code to interact with your flow's `.json` file using the Langflow runtime. - -### Chat Widget HTML - -The **Chat Widget HTML** tab displays code that can be inserted in the `` of your HTML to interact with your flow. -For more, see the [Chat widget documentation](../administration/chat-widget). - -### Tweaks - -The **Tweaks** tab displays the available parameters for your flow. -Modifying the parameters changes the code parameters across all windows. -For example, changing the **Chat Input** component's `input_value` will change that value across all API calls. - -
- -
- -## Collection - -A collection is a snapshot of flows available in a database. - -Collections can be downloaded to local storage and uploaded for future use. - -
- -
- -## Project - -A **Project** can be a flow or a component. To view your saved projects, select **My Collection**. - -Your **Projects** are displayed. - -Click the **![Playground icon](/logos/botmessage.svg) Playground** button to run a flow from the **My Collection** screen. - -In the top left corner of the screen are options for **Download Collection**, **Upload Collection**, and **New Project**. - -Select **Download Collection** to save your project to your local machine. This downloads all flows and components as a `.json` file. - -Select **Upload Collection** to upload a flow or component `.json` file from your local machine. - -Select **New Project** to create a new project. In addition to a blank canvas, [starter projects](../starter-projects/basic-prompting) are also available. - -## Project options menu - -To see options for your project, in the upper left corner of the canvas, select the dropdown menu. - - - -**New** - Start a new project. - -**Duplicate** - Duplicate the current flow as a new project. - -**Settings** - Modify the project's **Name** or **Description**. - -**Import** - Upload a flow `.json` file from your local machine. - -**Export** - Download your current project to your local machine as a `.json` file. - -**Undo** or **Redo** - Undo or redo your last action. - -## Project folders - -As of Langflow 1.0 alpha, more options are available for storing projects with **folders**. - -Create new folders with the **New folder** button. One folder can store multiple projects (as the default My Projects folder does). - -You can download folders of projects as a single JSON file, and upload files and flows to your folder. - -Click the **Trash** icon to delete a folder. - diff --git a/docs/docs/getting-started/install-langflow.mdx b/docs/docs/getting-started/install-langflow.mdx index 4e9e7860b..58bd2fca0 100644 --- a/docs/docs/getting-started/install-langflow.mdx +++ b/docs/docs/getting-started/install-langflow.mdx @@ -6,11 +6,12 @@ import Admonition from "@theme/Admonition"; # 📦 Install Langflow - Langflow **requires** Python version 3.10 or greater. + Langflow **requires** Python version 3.10 or greater and + [pip](https://pypi.org/project/pip/) or + [pipx](https://pipx.pypa.io/stable/installation/) to be installed on your + system. -Langflow **requires** [Python >=3.10](https://www.python.org/downloads/release/python-3100/) and [pip](https://pypi.org/project/pip/) or [pipx](https://pipx.pypa.io/stable/installation/) to be installed on your system. - Install Langflow with pip: ```bash @@ -23,29 +24,11 @@ Install Langflow with pipx: pipx install langflow --python python3.10 --fetch-missing-python ``` -Pipx can fetch the missing Python version for you with `--fetch-missing-python`, but you can also install the Python version manually. - -## Install Langflow pre-release - -To install a pre-release version of Langflow: - -pip: - -```bash -python -m pip install langflow --pre --force-reinstall -``` - -pipx: - -```bash -pipx install langflow --python python3.10 --fetch-missing-python --pip-args="--pre --force-reinstall" -``` - -Use `--force-reinstall` to ensure you have the latest version of Langflow and its dependencies. +Pipx can fetch the missing Python version for you with `--fetch-missing-python`, but you can also install the Python version manually. Use `--force-reinstall` to ensure you have the latest version of Langflow and its dependencies. ## Having a problem? -If you encounter a problem, see [Common Installation Issues](/migration/possible-installation-issues). +If you encounter a problem, see [Common Installation Issues](/getting-started/possible-installation-issues). To get help in the Langflow CLI: @@ -63,25 +46,30 @@ python -m langflow run 2. Confirm that a local Langflow instance starts by visiting `http://127.0.0.1:7860` in a Chromium-based browser. -```bash -│ Welcome to ⛓ Langflow │ -│ │ -│ Access http://127.0.0.1:7860 │ -│ Collaborate, and contribute at our GitHub Repo 🚀 │ -``` + 3. Continue on to the [Quickstart](./quickstart). ## HuggingFace Spaces -HuggingFace provides a great alternative for running Langflow in their Spaces environment. This means you can run Langflow without any local installation required. +HuggingFace provides a great alternative for running Langflow in their Spaces environment. This means you can run Langflow in the cloud without any local installation required. Here's how you can get Langflow up and running on HuggingFace Spaces: -In a Chromium-based browser, go to the [Langflow Space](https://huggingface.co/spaces/Langflow/Langflow?duplicate=true) or [Langflow v1.0 alpha Preview Space](https://huggingface.co/spaces/Langflow/Langflow-Preview?duplicate=true). +1. **Access Langflow Space**: Open a Chromium-based browser and navigate to the [Langflow Space](https://huggingface.co/spaces/Langflow/Langflow?duplicate=true). This link directs you to a pre-configured environment for Langflow. -You'll be presented with the following screen: +2. **Duplicate the Space**: You'll encounter an option to duplicate the Langflow space. This step involves a few simple decisions: + - **Naming Your Space**: Assign a unique name to your new Space. + - **Visibility Settings**: Choose between Public or Private visibility for your Space. + - After setting these parameters, click on **Duplicate Space** to initiate the setup. -Name your Space, define the visibility (Public or Private), and click on **Duplicate Space** to start the installation process. When installation is finished, you'll be redirected to the Space's main page to start using Langflow right away! +3. **Complete Installation**: The duplication and setup process begins immediately after you click **Duplicate Space**. Once completed, you will be automatically redirected to the main page of your new Space. + +4. **Start Exploring Langflow**: With the setup complete, Langflow is now ready for use in your Space and you can start exploring its features and capabilities right away! diff --git a/docs/docs/getting-started/new-to-llms.mdx b/docs/docs/getting-started/new-to-llms.mdx index bce3c1ec6..c6a73e96d 100644 --- a/docs/docs/getting-started/new-to-llms.mdx +++ b/docs/docs/getting-started/new-to-llms.mdx @@ -4,7 +4,9 @@ Large Language Models, or LLMs, are part of an exciting new world in computing. We made Langflow for anyone to create with LLMs, and hope you'll feel comfortable installing Langflow and [getting started](./quickstart). -If you want to learn more about LLMs, prompt engineering, and AI models, Langflow recommends [promptingguide.ai](https://promptingguide.ai), an open-source repository of prompt engineering content maintained by AI experts. +If you want to learn the basics of LLMs, prompt engineering, and AI models, Langflow recommends [promptingguide.ai](https://promptingguide.ai), an open-source repository of prompt engineering content maintained by AI experts. PromptingGuide offers content for [beginners](https://www.promptingguide.ai/introduction/basics) and [experts](https://www.promptingguide.ai/techniques/cot), as well as the latest [research papers](https://www.promptingguide.ai/papers) and [test results](https://www.promptingguide.ai/research) fueling AI's progress. -Wherever you are on your AI journey, it's helpful to keep Prompting Guide open in a tab. +For an in depth readings, we recommend [Awesome LLM Books](https://github.com/Hannibal046/Awesome-LLM?tab=readme-ov-file#llm-books), a curated list of resources for learning about LLMs and their applications. + +{/* Wherever you are on your AI journey, it's helpful to keep Prompting Guide open in a tab. */} diff --git a/docs/docs/migration/possible-installation-issues.mdx b/docs/docs/getting-started/possible-installation-issues.mdx similarity index 95% rename from docs/docs/migration/possible-installation-issues.mdx rename to docs/docs/getting-started/possible-installation-issues.mdx index 203996f39..0d4de5175 100644 --- a/docs/docs/migration/possible-installation-issues.mdx +++ b/docs/docs/getting-started/possible-installation-issues.mdx @@ -1,6 +1,8 @@ +import Admonition from "@theme/Admonition"; + # ❗️ Common Installation Issues -This is a list of possible issues that you may encounter when installing Langflow 1.0 alpha and how to solve them. +This is a list of possible issues that you may encounter when installing Langflow and how to solve them. ## _`No module named 'langflow.__main__'`_ diff --git a/docs/docs/getting-started/quickstart.mdx b/docs/docs/getting-started/quickstart.mdx index c64abdbc4..7d4f15573 100644 --- a/docs/docs/getting-started/quickstart.mdx +++ b/docs/docs/getting-started/quickstart.mdx @@ -6,7 +6,7 @@ import Admonition from "@theme/Admonition"; # ⚡️ Quickstart -This guide demonstrates how to build a basic prompt flow and modify that prompt for different outcomes. +This guide demonstrates how to build a basic flow and modify the prompt for different outcomes. ## Prerequisites @@ -16,27 +16,21 @@ This guide demonstrates how to build a basic prompt flow and modify that prompt - [OpenAI API key](https://platform.openai.com) - - Langflow v1.0 alpha is also available in HuggingFace Spaces. [Clone the space - using this - link](https://huggingface.co/spaces/Langflow/Langflow-Preview?duplicate=true) - to create your own Langflow workspace in minutes. - - ## Hello World - Basic Prompting Let's start with a Prompt component to instruct an OpenAI Model. -Prompts serve as the inputs to a large language model (LLM), acting as the interface between human instructions and computational tasks. +Prompts serve as the inputs to a large language model (LLM), acting as the interface between human instructions and computational tasks. By submitting natural language requests in a prompt to an LLM, you can obtain answers, generate text, and solve problems. -By submitting natural language requests in a prompt to an LLM, you can obtain answers, generate text, and solve problems. +
1. From the Langflow dashboard, click **New Project**. 2. Select **Basic Prompting**. -3. The **Basic Prompting** flow is created. + +
-This flow allows you to chat with the **OpenAI** component via a **Prompt**. +This flow allows you to chat with the **OpenAI** model by using a **Prompt** to send instructions. + Examine the **Prompt** component. The **Template** field instructs the LLM to `Answer the user as if you were a pirate.` This should be interesting... -4. To create an environment variable for the **OpenAI** component, in the **OpenAI API Key** field, click the **Globe** button, and then click **Add New Variable**. - 1. In the **Variable Name** field, enter `openai_api_key`. - 2. In the **Value** field, paste your OpenAI API Key (`sk-...`). - 3. Click **Save Variable**. +To use the **OpenAI** component, you have two options for providing your OpenAI API Key: directly passing it to the component or creating an environment variable. For better security and manageability, creating an environment variable is recommended. Here's how to set it up: + +In the **OpenAI API Key** field, click the **Globe** button to access environment variables, and then click **Add New Variable**. + +1. In the **Variable Name** field, enter `openai_api_key`. +2. In the **Value** field, paste your OpenAI API Key (`sk-...`). +3. Click **Save Variable**. + +By creating an environment variable, you keep your API key secure and make it easier to manage across different components or projects. ## Run the basic prompting flow -1. Click the **Run** button. - The **Interaction Panel** opens, where you can chat with your bot. -2. Type a message and press Enter. +1. Click the **Playground** button. This where you can interact with your bot. +2. Type any message and press Enter. And... Ahoy! 🏴‍☠️ The bot responds in a piratical manner! @@ -73,10 +72,8 @@ This should be interesting... Well done! You've built your first prompt in Langflow. 🎉 -By adding Langflow components to your flow, you can create all sorts of interesting behaviors. +By dragging Langflow components to your workspace, you can create all sorts of interesting behaviors. Here are a couple of examples: -Here are a couple of examples: - -- [Memory chatbot](/starter-projects/memory-chatbot) -- [Blog writer](/starter-projects/blog-writer) -- [Document QA](/starter-projects/document-qa) \ No newline at end of file +- [Memory Chatbot](/starter-projects/memory-chatbot) +- [Blog Writer](/starter-projects/blog-writer) +- [Document QA](/starter-projects/document-qa) diff --git a/docs/docs/getting-started/rag-with-astradb.mdx b/docs/docs/getting-started/rag-with-astradb.mdx deleted file mode 100644 index d1766c57a..000000000 --- a/docs/docs/getting-started/rag-with-astradb.mdx +++ /dev/null @@ -1,195 +0,0 @@ -import ThemedImage from "@theme/ThemedImage"; -import useBaseUrl from "@docusaurus/useBaseUrl"; -import ZoomableImage from "/src/theme/ZoomableImage.js"; -import Admonition from "@theme/Admonition"; - -# 🌟 RAG with Astra DB - -This guide will walk you through how to build a RAG (Retrieval Augmented Generation) application using **Astra DB** and **Langflow**. - -[Astra DB](https://www.datastax.com/products/datastax-astra?utm_source=langflow-pre-release&utm_medium=referral&utm_campaign=langflow-announcement&utm_content=astradb) is a cloud-native database built on Apache Cassandra that is optimized for the cloud. It is a fully managed database-as-a-service that simplifies operations and reduces costs. Astra DB is built on the same technology that powers the largest Cassandra deployments in the world. - -In this guide, we will use Astra DB as a vector store to store and retrieve the documents that will be used by the RAG application to generate responses. - - - This guide assumes that you have Langflow up and running. If you are new to - Langflow, you can check out the [Getting Started](/) guide. - - -TLDR; - -- [Create a free Astra DB account](https://astra.datastax.com/signup?utm_source=langflow-pre-release&utm_medium=referral&utm_campaign=langflow-announcement&utm_content=create-a-free-astra-db-account) -- Duplicate our [Langflow 1.0 Space](https://huggingface.co/spaces/Langflow/Langflow-Preview?duplicate=true) -- Create a new database, get a **Token** and the **API Endpoint** -- Click on the **New Project** button and look for Vector Store RAG. This will create a new project with the necessary components -- Import the project into Langflow by dropping it on the Canvas or My Collection page -- Update the **Token** and **API Endpoint** in the **Astra DB** components -- Update the OpenAI API key in the **OpenAI** components -- Run the ingestion flow which is the one that uses the **Astra DB** component -- Click on the ⚡ _Run_ button and start interacting with your RAG application - -# First things first - -## Create an Astra DB Database - -To get started, you will need to [create an Astra DB database](https://astra.datastax.com/signup?utm_source=langflow-pre-release&utm_medium=referral&utm_campaign=langflow-announcement&utm_content=create-an-astradb-database). - -Once you have created an account, you will be taken to the Astra DB dashboard. Click on the **Create Database** button. - - - -Now you will need to configure your database. Choose the **Serverless (Vector)** deployment type, and pick a Database name, provider and region. - -After you have configured your database, click on the **Create Database** button. - - - -Once your database is initialized, to the right of the page, you will see the _Database Details_ section which contains a button for you to copy the **API Endpoint** and another to generate a **Token**. - - - -Now we are all set to start building our RAG application using Astra DB and Langflow. - -## (Optional) Duplicate the Langflow 1.0 HuggingFace Space - -If you haven't already, now is the time to launch Langflow. To make things easier, you can duplicate our [Langflow 1.0 Space](https://huggingface.co/spaces/Langflow/Langflow-Preview?duplicate=true) which sets up a Langflow instance just for you. - -## Open the Vector Store RAG Project - -To get started, click on the **New Project** button and look for the **Vector Store RAG** project. This will open a starter project with the necessary components to run a RAG application using Astra DB. - - - -This project consists of two flows. The simpler one is the **Ingestion Flow** which is responsible for ingesting the documents into the Astra DB database. - -Your first step should be to understand what each flow does and how they interact with each other. - -The ingestion flow consists of: - -- **Files** component that uploads a text file to Langflow -- **Recursive Character Text Splitter** component that splits the text into smaller chunks -- **OpenAIEmbeddings** component that generates embeddings for the text chunks -- **Astra DB** component that stores the text chunks in the Astra DB database - - - -Now, let's update the **Astra DB** and **Astra DB Search** components with the **Token** and **API Endpoint** that we generated earlier, and the OpenAI Embeddings components with your OpenAI API key. - - - -And run it! This will ingest the Text data from your file into the Astra DB database. - - - -Now, on to the **RAG Flow**. This flow is responsible for generating responses to your queries. It will define all of the steps from getting the User's input to generating a response and displaying it in the Playground. - -The RAG flow is a bit more complex. It consists of: - -- **Chat Input** component that defines where to put the user input coming from the Playground -- **OpenAI Embeddings** component that generates embeddings from the user input -- **Astra DB Search** component that retrieves the most relevant Data from the Astra DB database -- **Text Output** component that turns the Data into Text by concatenating them and also displays it in the Playground - - One interesting point you'll see here is that this component is named `Extracted Chunks`, and that is how it will appear in the Playground -- **Prompt** component that takes in the user input and the retrieved Data as text and builds a prompt for the OpenAI model -- **OpenAI** component that generates a response to the prompt -- **Chat Output** component that displays the response in the Playground - - - -To run it all we have to do is click on the ⚡ _Run_ button and start interacting with your RAG application. - - - -This opens the Playground where you can chat your data. - -Because this flow has a **Chat Input** and a **Text Output** component, the Panel displays a chat input at the bottom and the Extracted Chunks section on the left. - - - -Once we interact with it we get a response and the Extracted Chunks section is updated with the retrieved data. - - - -And that's it! You have successfully ran a RAG application using Astra DB and Langflow. - -# Conclusion - -In this guide, we have learned how to run a RAG application using Astra DB and Langflow. -We have seen how to create an Astra DB database, import the Astra DB RAG Flows project into Langflow, and run the ingestion and RAG flows. diff --git a/docs/docs/getting-started/workspace.mdx b/docs/docs/getting-started/workspace.mdx new file mode 100644 index 000000000..374faca74 --- /dev/null +++ b/docs/docs/getting-started/workspace.mdx @@ -0,0 +1,275 @@ +import ThemedImage from "@theme/ThemedImage"; +import useBaseUrl from "@docusaurus/useBaseUrl"; +import ZoomableImage from "/src/theme/ZoomableImage.js"; +import ReactPlayer from "react-player"; +import Admonition from "@theme/Admonition"; + +# 🎨 Langflow Workspace + +## The Langflow Workspace Interface + +The **Langflow Workspace** is where you assemble new flows and create AIs by connecting and running components. To get started, click on **New Project**. You can either build a flow from scratch (Blank Flow) or choose from pre-built starter examples. + +### Sidebar Menu + +Located on the left, this menu includes several collapsible sections that categorize the different types of pre-built components available in Langflow. + +### Workspace Area + +The large central area where users can visually assemble and connect components to create flows. + +## Top Navigation Bar + +- **Project Options**: Indicates the name of the current project or document. Clicking here allows users to rename the project or access project settings. +- **My Collection**: Provides access to saved or user-defined collections of components or flows. +- **Store**: Opens the component store where users can browse and add new components to their workspace. + +In the top navigation bar, the dropdown menu labeled with the project name offers several management and customization options for the current flow in the Langflow Workspace. + + + +- **New**: Create a new flow from scratch. + +- **Settings**: Adjust settings specific to the current flow, such as its Name, Description, and Endpoint Name. + +- **Logs**: View logs for the current project, including execution history, errors, and other runtime events. + +- **Import**: Import a flow or component from a JSON file into the Workspace. + +- **Export**: Export the current flow as a JSON file. + +- **Undo (⌘Z)**: Revert the last action taken in the project. + +- **Redo (⌘Y)**: Reapply a previously undone action. + +- **Refresh All**: Refresh all components and delete cache. + +## Control Panel + +- **Playground**: Button that executes the current flow in the workspace. +- **API**: Provides API access details and integration options for the current flow. +- **Share**: Allows users to share their AI with others. + +## Flows & Components + +A [flow](#flow) is a pipeline of components connected together in the Langflow Workspace. + +A [component](#component) is a single building block within a flow. It has inputs, outputs, and parameters that define its functionality. + +For example, the **OpenAI Model** is a **component** of the **Basic Prompting** flow. + +## Flow + +A **Flow** is a sequence of components that are connected to perform a series of operations or tasks. Each flow is essentially a pipeline where data functions travel through various components, each modifying or analyzing the data according to its specific functionality. + +For example, the [Basic Prompting](../starter-projects/basic-prompting) flow is a pipeline of four components: + + + +{" "} + +In this flow, the **OpenAI Model** receives input (left side) and produces output (right side) - in this case, receiving input from the **Chat Input** and **Prompt** components and passing the output to the **Chat Output** component. + +## Component + +Components are the building blocks of flows. They consist of inputs, outputs, and parameters that define their functionality. These elements provide a convenient and straightforward way to compose LLM-based applications. Learn more about components and how they work below. + +
+ During the flow creation process, you will notice handles (colored circles) + attached to one or both sides of a component. These handles use distinct + colors to indicate the types of inputs and outputs that can be interconnected. + Hover over a handle to see connection details. +
+ +{" "} + + + +{/*
*/} + +On the top right corner of the component, you'll find the a play button to run a component. Once it runs, a status icon appears and you can hover over that to visualize success or error messages. + +Start interacting with your AI by clicking the **![Playground icon](/logos/botmessage.svg)Playground** at the bottom right of the workspace. + +### Output Preview + +Langflow includes an output visualizer for components that opens a pop-up screen. This allows you to easily inspect and monitor transmissions between components, providing instant feedback on your workflows. + + + +### Component Menu + +Each component is a little unique, but they will all have a menu bar on top that looks something like this. + + + +It consists of options such as: + +**Code** - displays component's Python code. You can modify the code and save it. + +**Advanced** - See and adjust all parameters of a component. + +**Freeze** - After a component runs, lock its previous output state to prevent it from re-running. + +Click **All** (the "..." button) to see all options. + +
+ +
+ +### Advanced Settings + +Langflow components can be edited by clicking the **Advanced Settings** button. + +
+ +
+ +Hide parameters with the **SHOW** button to reduce complexity and keep the workspace clean and intuitive for experimentation. + +You can also double-click a component's name and description to modify those. Component descriptions accept markdown syntax. + +### Group Components + +Multiple components can be grouped into a single component for reuse. This is useful when combining large flows into single components (like RAG with a vector database, for example) and saving space. + +1. Hold **Shift** and drag to select components. +2. Select **Group**. +3. The components merge into a single component. +4. Double click name and description to change them. +5. Save your grouped component to in the sidebar for later use! + +### Update component version + +A component's state is stored in a database, while sidebar components are like starter templates. + +As soon as you drag a component from the sidebar to the workspace, the two components are no longer in parity. + +The component will keep the version number it was initilized to the workspace with. Click the **Update Component** icon (exclamation mark) to bring the component up to the `latest` version. This will change the code of the component in place so you can validate that the component was updated by checking its Python code before and after updating it. + + + +## Playground + +Run your AI by clicking the **![Playground icon](/logos/botmessage.svg)Playground** button. + +For more, see [Playground](../administration/playground). + +## API + +{/* rsn */} +The **API** session presents code templates for integrating your flow into external applications. + +{/* Modify parameters in the **Tweaks** window, click **Copy Code** or **Download** buttons, and paste your code where you want to use it. */} + + + +### cURL + +The **cURL** tab displays sample code for posting a query to your flow. +Modify the `input_value` to change your input message. +Copy the code and run it to post a query to your flow and get the result. + +```bash +curl -X POST \ + http://127.0.0.1:7863/api/v1/run/f2eefd80-bb91-4190-9279-0d6ffafeaac4\?stream\=false \ + -H 'Content-Type: application/json'\ + -d '{"input_value": "is anybody there?", + "output_type": "chat", + "input_type": "chat", + "tweaks": { + "Prompt-uxBqP": {}, + "OpenAIModel-k39HS": {}, + "ChatOutput-njtka": {}, + "ChatInput-P3fgL": {} +}}' +``` + +Result: + +``` +{"session_id":"f2eefd80-bb91-4190-9279-0d6ffafeaac4:53856a772b8e1cfcb3dd2e71576b5215399e95bae318d3c02101c81b7c252da3","outputs":[{"inputs":{"input_value":"is anybody there?"},"outputs":[{"results":{"result":"Arrr, me hearties! Aye, this be Captain [Your Name] speakin'. What be ye needin', matey?"},"artifacts":{"message":"Arrr, me hearties! Aye, this be Captain [Your Name] speakin'. What be ye needin', matey?","sender":"Machine","sender_name":"AI"},"messages":[{"message":"Arrr, me hearties! Aye, this be Captain [Your Name] speakin'. What be ye needin', matey?","sender":"Machine","sender_name":"AI","component_id":"ChatOutput-njtka"}],"component_display_name":"Chat Output","component_id":"ChatOutput-njtka"}]}]}% +``` + +### Python API + +The **Python API** tab displays code to interact with your flow using the Python HTTP requests library. + +### Python Code + +The **Python Code** tab displays code to interact with your flow's `.json` file using the Langflow runtime. + +### Chat Widget HTML + +The **Chat Widget HTML** tab displays code that can be inserted in the `` of your HTML to interact with your flow. +For more, see the [Chat widget documentation](../administration/chat-widget). + +### Tweaks + +The **Tweaks** tab displays the available parameters for your flow. +Modifying the parameters changes the code parameters across all windows. +For example, changing the **Chat Input** component's `input_value` will change that value across all API calls. + +
+ +
diff --git a/docs/docs/index.mdx b/docs/docs/index.mdx index e762142f0..64946d6ad 100644 --- a/docs/docs/index.mdx +++ b/docs/docs/index.mdx @@ -5,14 +5,15 @@ import Admonition from "@theme/Admonition"; # 👋 Welcome to Langflow -Langflow is a new, visual way to build, iterate, and deploy AI applications. +Langflow is a new, visual framework for building multi-agent and RAG applications. It is open-source, Python-powered, fully customizable, LLM and vector store agnostic. Its intuitive interface allows for easy manipulation of AI building blocks, enabling developers to quickly prototype and turn their ideas into powerful, real-world solutions. {" "} +{/* rsn */} - Langflow v1.0 alpha is also available in HuggingFace Spaces. [Clone the space - using this - link](https://huggingface.co/spaces/Langflow/Langflow-Preview?duplicate=true) - to create your own Langflow workspace in minutes. - +- [Langflow Workspace](/getting-started/workspace) - Learn more about the Langflow Workspace. ## Learn more about Langflow 1.0 diff --git a/docs/docs/integrations/langsmith/intro.mdx b/docs/docs/integrations/langsmith/intro.mdx new file mode 100644 index 000000000..68f28a891 --- /dev/null +++ b/docs/docs/integrations/langsmith/intro.mdx @@ -0,0 +1,46 @@ +import Admonition from "@theme/Admonition"; +import ThemedImage from "@theme/ThemedImage"; +import useBaseUrl from "@docusaurus/useBaseUrl"; +import ZoomableImage from "/src/theme/ZoomableImage.js"; + +# LangSmith + +LangSmith is a full-lifecycle DevOps service from LangChain that provides monitoring and observability. To integrate with Langflow, just add your LangChain API key as a Langflow environment variable and you are good to go! + +## Step-by-step Configuration + +1. Obtain your LangChain API key from https://smith.langchain.com +2. Add the following keys to Langflow .env file: + +```bash +LANGCHAIN_API_KEY="your-api-key" +LANGCHAIN_PROJECT="your-project-name" +``` + +or export the environment variables in your terminal: + +```bash +export LANGCHAIN_API_KEY="your-api-key" +export LANGCHAIN_PROJECT="your-project-name" +``` + +3. Restart Langflow using `langflow run --env-file .env` +4. Run any project and check the LangSmith dashboard for monitoring and observability. + + + + diff --git a/docs/docs/integrations/notion/add-content-to-page.md b/docs/docs/integrations/notion/add-content-to-page.md index ace43e103..197046922 100644 --- a/docs/docs/integrations/notion/add-content-to-page.md +++ b/docs/docs/integrations/notion/add-content-to-page.md @@ -5,6 +5,10 @@ import ZoomableImage from "/src/theme/ZoomableImage.js"; # Add Content To Page + +This page may contain outdated information. It will be updated as soon as possible. + + The `AddContentToPage` component converts markdown text to Notion blocks and appends them to a Notion page. [Notion Reference](https://developers.notion.com/reference/patch-block-children) diff --git a/docs/docs/integrations/notion/intro.md b/docs/docs/integrations/notion/intro.md index 293038d4f..77f09e5b6 100644 --- a/docs/docs/integrations/notion/intro.md +++ b/docs/docs/integrations/notion/intro.md @@ -5,6 +5,10 @@ import ZoomableImage from "/src/theme/ZoomableImage.js"; # Introduction to Notion in Langflow + +This page may contain outdated information. It will be updated as soon as possible. + + The Notion integration in Langflow enables seamless connectivity with Notion databases, pages, and users, facilitating automation and improving productivity. +This page may contain outdated information. It will be updated as soon as possible. + + The `NotionDatabaseProperties` component retrieves properties of a Notion database. It provides a convenient way to integrate Notion database information into your Langflow workflows. [Notion Reference](https://developers.notion.com/reference/post-database-query) diff --git a/docs/docs/integrations/notion/list-pages.md b/docs/docs/integrations/notion/list-pages.md index e1f6603b3..a232a594f 100644 --- a/docs/docs/integrations/notion/list-pages.md +++ b/docs/docs/integrations/notion/list-pages.md @@ -5,6 +5,10 @@ import ZoomableImage from "/src/theme/ZoomableImage.js"; # List Pages + +This page may contain outdated information. It will be updated as soon as possible. + + The `NotionListPages` component queries a Notion database with filtering and sorting. It provides a convenient way to integrate Notion database querying capabilities into your Langflow workflows. [Notion Reference](https://developers.notion.com/reference/post-database-query) diff --git a/docs/docs/integrations/notion/list-users.md b/docs/docs/integrations/notion/list-users.md index 17352c0c2..c3cd6696b 100644 --- a/docs/docs/integrations/notion/list-users.md +++ b/docs/docs/integrations/notion/list-users.md @@ -5,6 +5,10 @@ import ZoomableImage from "/src/theme/ZoomableImage.js"; # User List + +This page may contain outdated information. It will be updated as soon as possible. + + The `NotionUserList` component retrieves users from Notion. It provides a convenient way to integrate Notion user data into your Langflow workflows. [Notion Reference](https://developers.notion.com/reference/get-users) diff --git a/docs/docs/integrations/notion/page-content-viewer.md b/docs/docs/integrations/notion/page-content-viewer.md index 070d71800..df3ebdf60 100644 --- a/docs/docs/integrations/notion/page-content-viewer.md +++ b/docs/docs/integrations/notion/page-content-viewer.md @@ -5,6 +5,10 @@ import ZoomableImage from "/src/theme/ZoomableImage.js"; # Page Content + +This page may contain outdated information. It will be updated as soon as possible. + + The `NotionPageContent` component retrieves the content of a Notion page as plain text. It provides a convenient way to integrate Notion page content into your Langflow workflows. [Notion Reference](https://developers.notion.com/reference/get-page) diff --git a/docs/docs/integrations/notion/page-create.md b/docs/docs/integrations/notion/page-create.md index f942f257b..f2e7534d1 100644 --- a/docs/docs/integrations/notion/page-create.md +++ b/docs/docs/integrations/notion/page-create.md @@ -5,6 +5,10 @@ import ZoomableImage from "/src/theme/ZoomableImage.js"; # Page Create + +This page may contain outdated information. It will be updated as soon as possible. + + The `NotionPageCreator` component creates pages in a Notion database. It provides a convenient way to integrate Notion page creation into your Langflow workflows. [Notion Reference](https://developers.notion.com/reference/patch-block-children) diff --git a/docs/docs/integrations/notion/page-update.md b/docs/docs/integrations/notion/page-update.md index 3ed8f7740..3f9709f0a 100644 --- a/docs/docs/integrations/notion/page-update.md +++ b/docs/docs/integrations/notion/page-update.md @@ -5,6 +5,10 @@ import ZoomableImage from "/src/theme/ZoomableImage.js"; # Page Update + +This page may contain outdated information. It will be updated as soon as possible. + + The `NotionPageUpdate` component updates the properties of a Notion page. It provides a convenient way to integrate updating Notion page properties into your Langflow workflows. [Notion Reference](https://developers.notion.com/reference/patch-page) @@ -13,7 +17,7 @@ The `NotionPageUpdate` component updates the properties of a Notion page. It pro To use the `NotionPageUpdate` component in your Langflow flow: -1. Drag and drop the `NotionPageUpdate` component onto the canvas. +1. Drag and drop the `NotionPageUpdate` component onto the workspace. 2. Double-click the component to open its configuration. 3. Provide the required parameters as defined in the component's `build_config` method. 4. Connect the component to other nodes in your flow as needed. diff --git a/docs/docs/integrations/notion/search.md b/docs/docs/integrations/notion/search.md index 1e9b8c529..f7092fdb9 100644 --- a/docs/docs/integrations/notion/search.md +++ b/docs/docs/integrations/notion/search.md @@ -5,6 +5,10 @@ import ZoomableImage from "/src/theme/ZoomableImage.js"; # Notion Search + +This page may contain outdated information. It will be updated as soon as possible. + + The `NotionSearch` component is designed to search all pages and databases that have been shared with an integration in Notion. It provides a convenient way to integrate Notion search capabilities into your Langflow workflows. [Notion Reference](https://developers.notion.com/reference/search) diff --git a/docs/docs/integrations/notion/setup.md b/docs/docs/integrations/notion/setup.md index 72bb8f3b4..4ff81dd30 100644 --- a/docs/docs/integrations/notion/setup.md +++ b/docs/docs/integrations/notion/setup.md @@ -2,6 +2,10 @@ import Admonition from "@theme/Admonition"; # Setting up a Notion App + +This page may contain outdated information. It will be updated as soon as possible. + + To use Notion components in Langflow, you first need to create a Notion integration and configure it with the necessary capabilities. This guide will walk you through the process of setting up a Notion integration and granting it access to your Notion databases. ## Prerequisites diff --git a/docs/docs/migration/compatibility.mdx b/docs/docs/migration/compatibility.mdx index 0e18e4900..268214c4b 100644 --- a/docs/docs/migration/compatibility.mdx +++ b/docs/docs/migration/compatibility.mdx @@ -3,6 +3,10 @@ import ZoomableImage from "/src/theme/ZoomableImage.js"; # Compatibility with Previous Versions + +This page may contain outdated information. It will be updated as soon as possible. + + ## TLDR; - You'll need to add a few components to your flow to make it compatible with the new version of Langflow. diff --git a/docs/docs/migration/migrating-to-one-point-zero.mdx b/docs/docs/migration/migrating-to-one-point-zero.mdx index 8ff848def..2fd1fe935 100644 --- a/docs/docs/migration/migrating-to-one-point-zero.mdx +++ b/docs/docs/migration/migrating-to-one-point-zero.mdx @@ -2,6 +2,10 @@ import Admonition from "@theme/Admonition"; # Migrating to Langflow 1.0: A Guide + +This page may contain outdated information. It will be updated as soon as possible. + + Langflow 1.0 is a significant update that brings many exciting changes and improvements to the platform. This guide will walk you through the key improvements and help you migrate your existing projects to the new version. @@ -19,7 +23,7 @@ We have a special channel in our Discord server dedicated to Langflow 1.0 migrat - Improved user experience with Text and Data modes - CustomComponent for all components - Compatibility with previous versions using Runnable Executor -- Multiple flows in the canvas +- Multiple flows in the workspace - Improved component status - Ability to connect Output components to any other Component - Rename and edit component descriptions @@ -76,9 +80,9 @@ To use flows built in previous versions of Langflow, you can utilize the experim [Learn more about Compatibility with Previous Versions](./compatibility) -## Multiple Flows in the Canvas +## Multiple Flows in the Workspace -Langflow 1.0 allows you to have more than one flow in the canvas and run them separately. Discover how to create and manage multiple flows within a single project. +Langflow 1.0 allows you to have more than one flow in the workspace and run them separately. Discover how to create and manage multiple flows within a single project. **Guide coming soon** @@ -86,7 +90,7 @@ Langflow 1.0 allows you to have more than one flow in the canvas and run them se Each component now displays its status more clearly, allowing you to quickly identify any issues or errors. Explore how to use the new component status feature to troubleshoot and optimize your flows. -[Learn more about Component Status](../getting-started/canvas#component) +[Learn more about Component Status](../getting-started/workspace#component) ## Connecting Output Components @@ -98,13 +102,13 @@ You can now connect Output components to any other component (that has a Text ou Langflow 1.0 allows you to rename and edit the description of each component, making it easier to understand and interact with the flow. Learn how to customize your component names and descriptions for improved clarity. -[Learn more about Component Descriptions](../getting-started/canvas#component-parameters) +[Learn more about Component Descriptions](../getting-started/workspace#flows--components) ## Passing Tweaks and Inputs in the API Things got a whole lot easier. You can now pass tweaks and inputs in the API by referencing the Display Name of the component. Discover how to leverage this feature to dynamically control your flow's behavior. -[Learn more about Tweaks and API inputs](../getting-started/canvas#tweaks) +[Learn more about Tweaks and API inputs](../getting-started/workspace#tweaks) ## Global Variables for Text Fields diff --git a/docs/docs/starter-projects/basic-prompting.mdx b/docs/docs/starter-projects/basic-prompting.mdx index 59519c91d..dc5fc8c0f 100644 --- a/docs/docs/starter-projects/basic-prompting.mdx +++ b/docs/docs/starter-projects/basic-prompting.mdx @@ -6,6 +6,10 @@ import Admonition from "@theme/Admonition"; # Basic Prompting + +This page may contain outdated information. It will be updated as soon as possible. + + Prompts serve as the inputs to a large language model (LLM), acting as the interface between human instructions and computational tasks. By submitting natural language requests in a prompt to an LLM, you can obtain answers, generate text, and solve problems. @@ -18,13 +22,6 @@ This article demonstrates how to use Langflow's prompt tools to issue basic prom - [OpenAI API key created](https://platform.openai.com) - - Langflow v1.0 alpha is also available in HuggingFace Spaces. [Clone the space - using this - link](https://huggingface.co/spaces/Langflow/Langflow-Preview?duplicate=true) - to create your own Langflow workspace in minutes. - - ## Create the basic prompting project 1. From the Langflow dashboard, click **New Project**. @@ -62,4 +59,4 @@ This should be interesting... The **Edit Prompt** window opens. 2. Change `Answer the user as if you were a pirate` to a different character, perhaps `Answer the user as if you were Harold Abelson.` 3. Run the basic prompting flow again. - The response will be markedly different. \ No newline at end of file + The response will be markedly different. diff --git a/docs/docs/starter-projects/blog-writer.mdx b/docs/docs/starter-projects/blog-writer.mdx index ab8a600b6..1fb1a52d0 100644 --- a/docs/docs/starter-projects/blog-writer.mdx +++ b/docs/docs/starter-projects/blog-writer.mdx @@ -6,6 +6,10 @@ import Admonition from "@theme/Admonition"; # Blog Writer + +This page may contain outdated information. It will be updated as soon as possible. + + Build a blog writer with OpenAI that uses URLs for reference content. ## Prerequisites @@ -14,13 +18,6 @@ Build a blog writer with OpenAI that uses URLs for reference content. - [OpenAI API key created](https://platform.openai.com) - - Langflow v1.0 alpha is also available in HuggingFace Spaces. [Clone the space - using this - link](https://huggingface.co/spaces/Langflow/Langflow-Preview?duplicate=true) - to create your own Langflow workspace in minutes. - - ## Create the Blog Writer project 1. From the Langflow dashboard, click **New Project**. diff --git a/docs/docs/starter-projects/document-qa.mdx b/docs/docs/starter-projects/document-qa.mdx index 0d64ed515..25f5d1234 100644 --- a/docs/docs/starter-projects/document-qa.mdx +++ b/docs/docs/starter-projects/document-qa.mdx @@ -6,6 +6,10 @@ import Admonition from "@theme/Admonition"; # Document QA + +This page may contain outdated information. It will be updated as soon as possible. + + Build a question-and-answer chatbot with a document loaded from local memory. ## Prerequisites @@ -14,13 +18,6 @@ Build a question-and-answer chatbot with a document loaded from local memory. - [OpenAI API key created](https://platform.openai.com) - - Langflow v1.0 alpha is also available in HuggingFace Spaces. [Clone the space - using this - link](https://huggingface.co/spaces/Langflow/Langflow-Preview?duplicate=true) - to create your own Langflow workspace in minutes. - - ## Create the Document QA project 1. From the Langflow dashboard, click **New Project**. diff --git a/docs/docs/starter-projects/memory-chatbot.mdx b/docs/docs/starter-projects/memory-chatbot.mdx index e980cc8a1..a620dd714 100644 --- a/docs/docs/starter-projects/memory-chatbot.mdx +++ b/docs/docs/starter-projects/memory-chatbot.mdx @@ -6,6 +6,10 @@ import Admonition from "@theme/Admonition"; # Memory Chatbot + +This page may contain outdated information. It will be updated as soon as possible. + + This flow extends the [basic prompting flow](./basic-prompting) to include chat memory for unique SessionIDs. ## Prerequisites @@ -14,13 +18,6 @@ This flow extends the [basic prompting flow](./basic-prompting) to include chat - [OpenAI API key created](https://platform.openai.com) - - Langflow v1.0 alpha is also available in HuggingFace Spaces. [Clone the space - using this - link](https://huggingface.co/spaces/Langflow/Langflow-Preview?duplicate=true) - to create your own Langflow workspace in minutes. - - ## Create the memory chatbot project 1. From the Langflow dashboard, click **New Project**. @@ -81,4 +78,4 @@ To store **Session ID** as a Langflow variable, in the **Session ID** field, cli 1. In the **Variable Name** field, enter a name like `customer_chat_emea`. 2. In the **Value** field, enter a value like `1B5EBD79-6E9C-4533-B2C8-7E4FF29E983B`. 3. Click **Save Variable**. -4. Apply this variable to **Chat Input**. \ No newline at end of file +4. Apply this variable to **Chat Input**. diff --git a/docs/docs/starter-projects/vector-store-rag.mdx b/docs/docs/starter-projects/vector-store-rag.mdx index 7cc4b3691..6fb514d9a 100644 --- a/docs/docs/starter-projects/vector-store-rag.mdx +++ b/docs/docs/starter-projects/vector-store-rag.mdx @@ -6,6 +6,10 @@ import Admonition from "@theme/Admonition"; # Vector Store RAG + +This page may contain outdated information. It will be updated as soon as possible. + + Retrieval Augmented Generation, or RAG, is a pattern for training LLMs on your data and querying it. RAG is backed by a **vector store**, a vector database which stores embeddings of the ingested data. @@ -16,13 +20,6 @@ We've chosen [Astra DB](https://astra.datastax.com/signup?utm_source=langflow-pr ## Prerequisites - - Langflow v1.0 alpha is also available in HuggingFace Spaces. [Clone the space - using this - link](https://huggingface.co/spaces/Langflow/Langflow-Preview?duplicate=true) - to create your own Langflow workspace in minutes. - - - [Langflow installed and running](../getting-started/install-langflow) - [OpenAI API key](https://platform.openai.com) diff --git a/docs/docs/tutorials/chatprompttemplate_guide.mdx b/docs/docs/tutorials/chatprompttemplate_guide.mdx index a01fec1ca..9fd6ca1ea 100644 --- a/docs/docs/tutorials/chatprompttemplate_guide.mdx +++ b/docs/docs/tutorials/chatprompttemplate_guide.mdx @@ -2,9 +2,14 @@ import ThemedImage from "@theme/ThemedImage"; import useBaseUrl from "@docusaurus/useBaseUrl"; import ZoomableImage from "/src/theme/ZoomableImage.js"; import ReactPlayer from "react-player"; +import Admonition from "@theme/Admonition"; # Build Chatbots with the System Message Component + +This page may contain outdated information. It will be updated as soon as possible. + + ## Overview In this guide, we will modify the "Basic Chat with Prompt and History" example, integrating the ChatPromptTemplate with the SystemMessagePromptTemplate and HumanMessagePromptTemplate components. By following these steps, you'll be able to build a personalized chatbot that can interpret and respond based on user-defined System messages. @@ -62,7 +67,7 @@ In this guide, we will modify the "Basic Chat with Prompt and History" example, 16. You should now be able to see and use the defined variables in the chat interface. -17. Click on 'role' to examine the variable you established in the canvas. +17. Click on 'role' to examine the variable you established in the workspace. 18. Now, let's define the 'behavior' variable. diff --git a/docs/docs/tutorials/custom_components.mdx b/docs/docs/tutorials/custom_components.mdx index b6a32d048..6996bea72 100644 --- a/docs/docs/tutorials/custom_components.mdx +++ b/docs/docs/tutorials/custom_components.mdx @@ -8,6 +8,10 @@ import Admonition from "@theme/Admonition"; # Custom Components + +This page may contain outdated information. It will be updated as soon as possible. + + In Langflow, a Custom Component is a special component type that allows users to extend the platform's functionality by creating their own reusable and configurable components. A Custom Component is created from a user-defined Python script that uses the _`CustomComponent`_ class provided by the Langflow library. These components can be as simple as a basic function that takes and returns a string or as complex as a combination of multiple sub-components and API calls. @@ -196,7 +200,7 @@ Let's create a custom component that processes a document (_`langchain.schema.Do ### Pick a display name -To start, let's choose a name for our component by adding a _`display_name`_ attribute. This name will appear on the canvas. The name of the class is not relevant, but let's call it _`DocumentProcessor`_. +To start, let's choose a name for our component by adding a _`display_name`_ attribute. This name will appear on the workspace. The name of the class is not relevant, but let's call it _`DocumentProcessor`_. ```python from langflow.custom import CustomComponent @@ -267,7 +271,7 @@ class DocumentProcessor(CustomComponent): Here, the build method takes two input parameters: _`document`_, representing the input document to be processed, and _`function`_, a string representing the selected text transformation to be applied (either "Uppercase," "Lowercase," or "Titlecase"). The method processes the text content of the input Document based on the selected function. -The attribute _`repr_value`_ is used to display the result of the component on the canvas. It is optional and can be used to display any string value. +The attribute _`repr_value`_ is used to display the result of the component on the workspace. It is optional and can be used to display any string value. The return type is _`Document`_. @@ -399,6 +403,6 @@ Langflow will attempt to load all of the components found in the specified direc ### Interact with Custom Components -Once your custom components have been loaded successfully, they will appear in Langflow's sidebar. From there, you can add them to your Langflow canvas for use. However, please note that components with errors will not be available for addition to the canvas. Always ensure your code is error-free before attempting to load components. +Once your custom components have been loaded successfully, they will appear in Langflow's sidebar. From there, you can add them to your Langflow workspace for use. However, please note that components with errors will not be available for addition to the workspace. Always ensure your code is error-free before attempting to load components. Remember, creating custom components allows you to extend the functionality of Langflow to better suit your unique needs. Happy coding! diff --git a/docs/docs/tutorials/loading_document.mdx b/docs/docs/tutorials/loading_document.mdx index c123624c1..592332eee 100644 --- a/docs/docs/tutorials/loading_document.mdx +++ b/docs/docs/tutorials/loading_document.mdx @@ -2,9 +2,14 @@ import ThemedImage from "@theme/ThemedImage"; import useBaseUrl from "@docusaurus/useBaseUrl"; import ZoomableImage from "/src/theme/ZoomableImage.js"; import ReactPlayer from "react-player"; +import Admonition from "@theme/Admonition"; # Integrate Documents with Prompt Variables + +This page may contain outdated information. It will be updated as soon as possible. + + ## Overview This guide takes you through the process of augmenting the "Basic Chat with Prompt and History" example. You'll learn how to embed documents as context into the PromptTemplate component utilizing a WebBaseLoader. @@ -39,7 +44,7 @@ This guide takes you through the process of augmenting the "Basic Chat with Prom 6. Next, open the search bar and type "web". -7. Drag and drop a WebBaseLoader (or any other loader of your choice) onto the canvas. +7. Drag and drop a WebBaseLoader (or any other loader of your choice) onto the workspace. 8. Connect this loader to the `{context}` variable that we just added. diff --git a/docs/docs/tutorials/rag-with-astradb.mdx b/docs/docs/tutorials/rag-with-astradb.mdx index 8d0fbd41e..0aa0dafe8 100644 --- a/docs/docs/tutorials/rag-with-astradb.mdx +++ b/docs/docs/tutorials/rag-with-astradb.mdx @@ -5,6 +5,10 @@ import Admonition from "@theme/Admonition"; # 🌟 RAG with Astra DB + +This page may contain outdated information. It will be updated as soon as possible. + + This guide will walk you through how to build a RAG (Retrieval Augmented Generation) application using **Astra DB** and **Langflow**. [Astra DB](https://www.datastax.com/products/datastax-astra?utm_source=langflow-pre-release&utm_medium=referral&utm_campaign=langflow-announcement&utm_content=astradb) is a cloud-native database built on Apache Cassandra that is optimized for the cloud. It is a fully managed database-as-a-service that simplifies operations and reduces costs. Astra DB is built on the same technology that powers the largest Cassandra deployments in the world. @@ -20,10 +24,9 @@ In this guide, we will use Astra DB as a vector store to store and retrieve the TLDR; - [Create a free Astra DB account](https://astra.datastax.com/signup?utm_source=langflow-pre-release&utm_medium=referral&utm_campaign=langflow-announcement&utm_content=create-a-free-astra-db-account) -- Duplicate our [Langflow 1.0 Space](https://huggingface.co/spaces/Langflow/Langflow-Preview?duplicate=true) - Create a new database, get a **Token** and the **API Endpoint** -- Click on the **New Project** button and look for Vector Store RAG. This will create a new project with the necessary components -- Import the project into Langflow by dropping it on the Canvas or My Collection page +- Start Langflow and click on the **New Project** button and look for Vector Store RAG. This will create a new project with the necessary components +- Import the project into Langflow by dropping it on the Workspace or My Collection page - Update the **Token** and **API Endpoint** in the **Astra DB** components - Update the OpenAI API key in the **OpenAI** components - Run the ingestion flow which is the one that uses the **Astra DB** component diff --git a/docs/docs/whats-new/a-new-chapter-langflow.mdx b/docs/docs/whats-new/a-new-chapter-langflow.mdx index bdc0f178b..6e1356c61 100644 --- a/docs/docs/whats-new/a-new-chapter-langflow.mdx +++ b/docs/docs/whats-new/a-new-chapter-langflow.mdx @@ -1,96 +1,193 @@ -# A new chapter for Langflow +import ZoomableImage from "/src/theme/ZoomableImage.js"; -# First things first +# 1.0 - A new chapter for Langflow -**Thank you all for being part of the Langflow community**. The journey so far has been amazing and we are happy to have you with us. + -We have some exciting news to share with you. Langflow is changing, and we want to tell you all about it. +## First things first -## Where have we been? +**Thank you all for being part of the Langflow community**. The journey so far has been amazing, and we are thrilled to have you with us. -We spent the last few months working on a new version of Langflow. We wanted to make it more powerful, more flexible, and easier to use. -We're moving from version 0.6 straight to 1.0 (preview). This is a big change, and we want to explain why we're doing it and what it means for you. +We have some exciting news to share with you. Langflow is evolving, and we want to tell you all about it! -## Why? +## What's new? -In the past year, we learned a lot from the community and our users. We saw the potential of Langflow and the need for a more powerful and flexible tool for building conversational AI applications (and beyond). -We realized that Langflow was hiding things from you that would really help you build better and more complex conversational AI applications. So we decided to make a big change. +In the past year, we learned a lot from the community and our users. We saw the potential of Langflow and the need for a visual, interactive platform for building conversational AI applications (and beyond). You thought us the importance of a platform that is easy to use, but also powerful and controllable, and that made clear to us how Langflow's transparency could be improved. -## The only way to go is forward +Below are some of the new features we included to make that happen! -From all the people we talked to, we learned that the most important thing for (most of) them is to have a tool that is easy to use, but also powerful and controllable. They also told us that Langflow's transparency could be improved. +### Same Component, Multiple Outputs -In those points, we saw an opportunity to make Langflow much more powerful and flexible, while also making it easier to use and understand. +Components can now have more than a single output, allowing for unique flexibility in creating complex flows. The game-changer is output routing — it allows for so many new capabilities it’s almost silly to describe! -One key change you'll notice is that projects now require you to define Inputs and Outputs. -This is a big change, but it's also a big improvement. -It allows you to define the structure of your conversation and the data that flows through it. -This makes it easier to understand and control your conversation. +1. Branch to one or more subsequent components; +2. Apply logic operations like if/else and exploit decision-making; +3. Create classification models that choose between paths; +4. Enable the development of agent architectures from scratch; +5. Build an orchestrator that routes between agents. -This change comes with a new way of visualizing your projects. Before 1.0 you would connect Components to ultimately build one final Component that was processed behind the scenes. -Now, each step of the process is defined by you, is visible on the canvas, and can be monitored and controlled by you. This makes it so that Composition is now just another way of building in Langflow. **Now data flows through your project more transparently**. + -The caveat is existing projects may need some new Components to get them back to their full functionality. -[We've made this as easy as possible](../migration/compatibility), and there will be improvements to it as we get feedback in our Discord server and on GitHub. +### Flow + Composition -## Custom Interactions +One key change you'll notice is that projects now require you to define **Inputs** and **Outputs**. They allow you to define the structure of your conversation and how data flows through it. This change comes with a new way of visualizing your projects. -The moment we decided to make this change, we saw the potential to make Langflow even more yours. -By having a clear definition of Inputs and Outputs, we could build the experience around that which led us to create the **Playground**. +Before 1.0 you would connect components to ultimately build one final component that was processed behind the scenes. Now, each step of the process is defined by you, is visible on the workspace, and can be monitored and controlled. -When building a project testing and debugging is crucial. The Playground is a tool that changes dynamically based on the Inputs and Outputs you defined in your project. +This makes it so that composition is now just **another way** of building in Langflow and **data flows through your project more transparently**. This means that the easy stuff is *really* easy and the complex parts are still possible! -For example, let's say you are building a simple RAG application. Generally, you have an Input, some references that come from a Vector Store Search, a Prompt and the answer. -Now, you could plug the output of your Prompt into a [Text Output](../components/inputs-and-outputs), rename that to "Prompt Result" and see the output of your Prompt in the Playground. +- **Flow:** Data is processed by one component and then passed to the next component in line for immediate execution. +- **Composition**: Allows components to not only forward data but also share states for modular building. -{/* Add image here of the described above */} +For example, a flow can sequentially process text, and after a few steps, trigger an agent. It can access functions that wait to be called or to respond. This blend of flow and composition brings an unprecedented level of flexibility and control to data workflows in LLM-based apps and agents that use multiple models and APIs working together to achieve tasks. -This is just one example of how the Playground can help you build and debug your projects. + -We have many planned features for the Playground, and we're excited to see how you use it and what you think of it. +### Memory Management -## An easier start +Langflow 1.0 natively allows every chat message to be stored, and a single flow can have multiple memory sessions. This enables you to create multiple “memories” for agents to store and recall specific information as needed. -The experience for the first-time user is also something we wanted to improve. +You can edit and remove previous messages to inspect and validate a model’s response behavior. Control, explore, and manage conversation histories to get your models acting just right. -Meet the new and improved **New Project** screen. It's now easier to start a new project, and you can choose from a list of starter projects to get you started. + -{/* Add new project image */} +### Component Freeze 🥶 -We wanted to create start projects that would help you learn about new features and also give you a head start on your projects. +Component output freezing is back in Langflow, and it’s cooler than ever! + +Once a component runs, you can now lock its previous output state to prevent it from re-running. + +Avoid spending extra tokens and remove repetition when output should be constant — plus it's great for debugging and prototyping! + + + +### Output Preview + +Each component now includes an output visualizer that opens a pop-up screen, allowing you to easily inspect and monitor transmissions between components. It provides instant feedback on your workflows, letting you see results as they are processed. 🔍 + + + +### Inputs and Outputs Handling + +Inputs and outputs finally make more sense to us, and hopefully to you too. + +We’re proposing Langflow-native types to keep things consistent, but not limited to use any Python type. For instance, a Chat Input component sends out what we call a Message object (text + metadata like date, time, and sender), but maybe you want to introduce external types from your favorite Python package? Go wild. Each native type will have their own visualization modes and will evolve according to new integrations added. + +### Custom Endpoint Name + +Now you can pick a custom name for your endpoint used to call your flow from the API. + + + +### Logs & Monitoring + +A new logs page has been added! Now, both component executions and message history from the chat can be inspected in an interactive table. This will make it easier to debug, inspect, and manage messages passing through components. + + + +### Folders 📁 + +We introduced folders on the home page to help categorize flows and components. Create, remove and edit them to keep your work organized. + +### Playground + +By having a clear definition of Inputs and Outputs, we could build the experience around that, which led us to create the Playground. When building a project, testing and debugging are crucial. The Playground is an interface that changes dynamically based on the Inputs and Outputs you defined in your project. + +For example, let's say you are building a simple RAG application. Generally, you have an Input, some references that come from a Vector Store Search, a Prompt, and the answer. Now, you could plug the output of your Prompt into a Text Output, rename that to "Prompt Result," and see the output of your Prompt in the Playground. We have many planned features for the Playground, and we're excited to see how you'll explore it! + +### Multi-Modal + +Langflow is now multi-modal! It can now handle images and more soon! + + + +We’ve also improved project organization, global variables and overall settings, added Python 3.12 compatibility, keyboard shortcuts and a lot of new and fun experimental components! + +## An Easier Start + +The experience for first-time users is something we wanted to improve. For that we created a couple of Starter Projects. It's now much easier to start a new project, and you can choose from a list of starter projects to get you going. For now, we have: -- **[Basic Prompting (Hello, World)](/starter-projects/basic-prompting)**: A simple flow that shows you how to use the Prompt Component and how to talk like a pirate. -- **[Vector Store RAG](/tutorials/rag-with-astradb)**: A flow that shows you how to ingest data into a Vector Store and then use it to run a RAG application. -- **[Memory Chatbot](/starter-projects/memory-chatbot)**: This one shows you how to create a simple chatbot that can remember things about the user. -- **[Document QA](/starter-projects/document-qa)**: This flow shows you how to build a simple flow that helps you get answers about a document. -- **[Blog Writer](/starter-projects/blog-writer)**: Shows you how you can expand on the Prompt variables and be creative about what inputs you add to it. +- **Basic Prompting (Hello, World)**: Learn the basics of a Prompt Component. +- **Vector Store RAG**: Ingest data into a Vector Store and then use it to run a RAG application. +- **Memory Chatbot**: Create a simple chatbot that can remember things about the user. +- **Document QA**: Build a simple flow that helps you get answers about a document. +- **Blog Writer**: Expand on the Prompt variables and be creative about what inputs you add to it. -As always, your feedback is invaluable, so please let us know what you think of the new starter projects and what you would like to see in the future. +Please let us know what other starter projects you would like to see in the future! -## Less is more +--- -We added many new Components to Langflow and updated some of the existing ones, and we will deprecate some of them. +## What's Next? -The idea is that Langflow has evolved, and we want to make sure that the Components you use are the best they can be. -Some of them don't work well with the others, and some of them are just not needed anymore. +Langflow has gone through a big change, and we are excited to see how you use it and what you think of it. We plan to add more types of Input and Output like Image and Audio, and we also plan to add more Components to help you build more complex projects. -We are working on a list of Components that will be deprecated. -In the preview stages of 1.0, we will have a smaller list of Components so that we make sure that the ones we have are the best they can be. -Regardless, community feedback is very important in this matter, so please let us know what you think of the new Components and which ones you miss. +We are excited to see the community embracing Langflow as their number one AI builder and eagerly wait to see what new inspiring projects will come out of this release! A big thanks to everyone who's supporting or being part of this community in any way. ✨ -We are aiming at having a more stable and reliable set of Components that helps you get quickly to useful results. -This also means that your contributions in the [Langflow Store](https://langflow.store) and throughout the community are more important than ever. +Sincerely, -## What's next? - -Langflow went through a big change, and we are excited to see how you use it and what you think of it. - -We plan to add more types of Input and Output like Image and Audio, and we also plan to add more Components to help you build more complex projects. - -We also have some experimental features like a State Management System (so cool!) and a new way of building Grouped Components that we are excited to show you. - -## Reach out - -One last time, we want to thank you for being part of the Langflow community. Your feedback is invaluable, and we want to hear from you. +**The Langflow Team 🚀** \ No newline at end of file diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 9580d7835..e42512b91 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -122,13 +122,6 @@ module.exports = { /* Respect user preferences, such as low light mode in the evening */ respectPrefersColorScheme: true, }, - announcementBar: { - content: - '⭐️ If you like ⛓️Langflow, star it on GitHub! ⭐️', - backgroundColor: "#E8EBF1", //Mustard Yellow #D19900 #D4B20B - Salmon #E9967A - textColor: "#1C1E21", - isCloseable: false, - }, zoom: { selector: ".markdown :not(a) > img:not(.no-zoom)", background: { diff --git a/docs/package-lock.json b/docs/package-lock.json index 8709daa59..9de415c12 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -2571,6 +2571,343 @@ "react-dom": "^18.0.0" } }, + "node_modules/@docusaurus/plugin-google-gtag/node_modules/@docusaurus/core": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.2.0.tgz", + "integrity": "sha512-WTO6vW4404nhTmK9NL+95nd13I1JveFwZ8iOBYxb4xt+N2S3KzY+mm+1YtWw2vV37FbYfH+w+KrlrRaWuy5Hzw==", + "dependencies": { + "@babel/core": "^7.23.3", + "@babel/generator": "^7.23.3", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-runtime": "^7.22.9", + "@babel/preset-env": "^7.22.9", + "@babel/preset-react": "^7.22.5", + "@babel/preset-typescript": "^7.22.5", + "@babel/runtime": "^7.22.6", + "@babel/runtime-corejs3": "^7.22.6", + "@babel/traverse": "^7.22.8", + "@docusaurus/cssnano-preset": "3.2.0", + "@docusaurus/logger": "3.2.0", + "@docusaurus/mdx-loader": "3.2.0", + "@docusaurus/react-loadable": "5.5.2", + "@docusaurus/utils": "3.2.0", + "@docusaurus/utils-common": "3.2.0", + "@docusaurus/utils-validation": "3.2.0", + "@svgr/webpack": "^6.5.1", + "autoprefixer": "^10.4.14", + "babel-loader": "^9.1.3", + "babel-plugin-dynamic-import-node": "^2.3.3", + "boxen": "^6.2.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "clean-css": "^5.3.2", + "cli-table3": "^0.6.3", + "combine-promises": "^1.1.0", + "commander": "^5.1.0", + "copy-webpack-plugin": "^11.0.0", + "core-js": "^3.31.1", + "css-loader": "^6.8.1", + "css-minimizer-webpack-plugin": "^4.2.2", + "cssnano": "^5.1.15", + "del": "^6.1.1", + "detect-port": "^1.5.1", + "escape-html": "^1.0.3", + "eta": "^2.2.0", + "eval": "^0.1.8", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "html-minifier-terser": "^7.2.0", + "html-tags": "^3.3.1", + "html-webpack-plugin": "^5.5.3", + "leven": "^3.1.0", + "lodash": "^4.17.21", + "mini-css-extract-plugin": "^2.7.6", + "p-map": "^4.0.0", + "postcss": "^8.4.26", + "postcss-loader": "^7.3.3", + "prompts": "^2.4.2", + "react-dev-utils": "^12.0.1", + "react-helmet-async": "^1.3.0", + "react-loadable": "npm:@docusaurus/react-loadable@5.5.2", + "react-loadable-ssr-addon-v5-slorber": "^1.0.1", + "react-router": "^5.3.4", + "react-router-config": "^5.1.1", + "react-router-dom": "^5.3.4", + "rtl-detect": "^1.0.4", + "semver": "^7.5.4", + "serve-handler": "^6.1.5", + "shelljs": "^0.8.5", + "terser-webpack-plugin": "^5.3.9", + "tslib": "^2.6.0", + "update-notifier": "^6.0.2", + "url-loader": "^4.1.1", + "webpack": "^5.88.1", + "webpack-bundle-analyzer": "^4.9.0", + "webpack-dev-server": "^4.15.1", + "webpack-merge": "^5.9.0", + "webpackbar": "^5.0.2" + }, + "bin": { + "docusaurus": "bin/docusaurus.mjs" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-gtag/node_modules/@docusaurus/cssnano-preset": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.2.0.tgz", + "integrity": "sha512-H88RXGUia7r/VF3XfyoA4kbwgpUZcKsObF6VvwBOP91EdArTf6lnHbJ/x8Ca79KS/zf98qaWyBGzW+5ez58Iyw==", + "dependencies": { + "cssnano-preset-advanced": "^5.3.10", + "postcss": "^8.4.26", + "postcss-sort-media-queries": "^4.4.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@docusaurus/plugin-google-gtag/node_modules/@docusaurus/logger": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.2.0.tgz", + "integrity": "sha512-Z1R1NcOGXZ8CkIJSvjvyxnuDDSlx/+1xlh20iVTw1DZRjonFmI3T3tTgk40YpXyWUYQpIgAoqqPMpuseMMdgRQ==", + "dependencies": { + "chalk": "^4.1.2", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@docusaurus/plugin-google-gtag/node_modules/@docusaurus/mdx-loader": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.2.0.tgz", + "integrity": "sha512-JtkI5o6R/rJSr1Y23cHKz085aBJCvJw3AYHihJ7r+mBX+O8EuQIynG0e6/XpbSCpr7Ino0U50UtxaXcEbFwg9Q==", + "dependencies": { + "@docusaurus/logger": "3.2.0", + "@docusaurus/utils": "3.2.0", + "@docusaurus/utils-validation": "3.2.0", + "@mdx-js/mdx": "^3.0.0", + "@slorber/remark-comment": "^1.0.0", + "escape-html": "^1.0.3", + "estree-util-value-to-estree": "^3.0.1", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "image-size": "^1.0.2", + "mdast-util-mdx": "^3.0.0", + "mdast-util-to-string": "^4.0.0", + "rehype-raw": "^7.0.0", + "remark-directive": "^3.0.0", + "remark-emoji": "^4.0.0", + "remark-frontmatter": "^5.0.0", + "remark-gfm": "^4.0.0", + "stringify-object": "^3.3.0", + "tslib": "^2.6.0", + "unified": "^11.0.3", + "unist-util-visit": "^5.0.0", + "url-loader": "^4.1.1", + "vfile": "^6.0.1", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-gtag/node_modules/@docusaurus/types": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.2.0.tgz", + "integrity": "sha512-uG3FfTkkkbZIPPNYx6xRfZHKeGyRd/inIT1cqvYt1FobFLd+7WhRXrSBqwJ9JajJjEAjNioRMVFgGofGf/Wdww==", + "dependencies": { + "@mdx-js/mdx": "^3.0.0", + "@types/history": "^4.7.11", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "^1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.88.1", + "webpack-merge": "^5.9.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-gtag/node_modules/@docusaurus/utils": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.2.0.tgz", + "integrity": "sha512-3rgrE7iL60yV2JQivlcoxUNNTK2APmn+OHLUmTvX2pueIM8DEOCEFHpJO4MiWjFO7V/Wq3iA/W1M03JnjdugVw==", + "dependencies": { + "@docusaurus/logger": "3.2.0", + "@docusaurus/utils-common": "3.2.0", + "@svgr/webpack": "^6.5.1", + "escape-string-regexp": "^4.0.0", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", + "gray-matter": "^4.0.3", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", + "prompts": "^2.4.2", + "resolve-pathname": "^3.0.0", + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "@docusaurus/types": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/types": { + "optional": true + } + } + }, + "node_modules/@docusaurus/plugin-google-gtag/node_modules/@docusaurus/utils-common": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.2.0.tgz", + "integrity": "sha512-WEQT5L2lT/tBQgDRgeZQAIi9YJBrwEILb1BuObQn1St3T/4K1gx5fWwOT8qdLOov296XLd1FQg9Ywu27aE9svw==", + "dependencies": { + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "@docusaurus/types": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/types": { + "optional": true + } + } + }, + "node_modules/@docusaurus/plugin-google-gtag/node_modules/@docusaurus/utils-validation": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.2.0.tgz", + "integrity": "sha512-rCzMTqwNrBrEOyU8EaD1fYWdig4TDhfj+YLqB8DY68VUAqSIgbY+yshpqFKB0bznFYNBJbn0bGpvVuImQOa/vA==", + "dependencies": { + "@docusaurus/logger": "3.2.0", + "@docusaurus/utils": "3.2.0", + "@docusaurus/utils-common": "3.2.0", + "joi": "^17.9.2", + "js-yaml": "^4.1.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@docusaurus/plugin-google-gtag/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@docusaurus/plugin-google-gtag/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@docusaurus/plugin-google-gtag/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-gtag/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/@docusaurus/plugin-google-gtag/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@docusaurus/plugin-google-gtag/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@docusaurus/plugin-google-gtag/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@docusaurus/plugin-google-gtag/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@docusaurus/plugin-google-gtag/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/@docusaurus/plugin-google-tag-manager": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.4.0.tgz", @@ -22888,4 +23225,4 @@ } } } -} +} \ No newline at end of file diff --git a/docs/sidebars.js b/docs/sidebars.js index 322a23050..40f07baa0 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -14,8 +14,8 @@ module.exports = { "index", "getting-started/install-langflow", "getting-started/quickstart", - "getting-started/canvas", - "migration/possible-installation-issues", + "getting-started/workspace", + "getting-started/possible-installation-issues", "getting-started/new-to-llms", ], }, @@ -40,6 +40,9 @@ module.exports = { "administration/login", "administration/cli", "administration/playground", + "administration/memories", + "administration/logs", + "administration/collections-projects", "administration/settings", "administration/global-env", "administration/chat-widget", @@ -47,7 +50,7 @@ module.exports = { }, { type: "category", - label: "Core Components", + label: "Components", collapsed: false, items: [ "components/inputs-and-outputs", @@ -60,46 +63,48 @@ module.exports = { "components/custom", ], }, - { - type: "category", - label: "Extended Components", - collapsed: true, - items: [ - "components/agents", - "components/chains", - "components/experimental", - "components/utilities", - "components/model_specs", - "components/retrievers", - "components/text-splitters", - "components/toolkits", - "components/tools", - ], - }, - { - type: "category", - label: "Example Components", - collapsed: true, - items: [ - "examples/chat-memory", - "examples/combine-text", - "examples/create-record", - "examples/pass", - "examples/store-message", - "examples/sub-flow", - "examples/text-operator", - ], - }, - { - type: "category", - label: "Migration", - collapsed: false, - items: [ - "migration/possible-installation-issues", - "migration/migrating-to-one-point-zero", - "migration/compatibility", - ], - }, + // RSN - Check if we need this + // { + // type: "category", + // label: "Extended Components", + // collapsed: true, + // items: [ + // "components/agents", + // "components/chains", + // "components/experimental", + // "components/utilities", + // "components/model_specs", + // "components/retrievers", + // "components/text-splitters", + // "components/toolkits", + // "components/tools", + // ], + // }, + // RSN - Check if we need this + // { + // type: "category", + // label: "Example Components", + // collapsed: true, + // items: [ + // "examples/chat-memory", + // "examples/combine-text", + // "examples/create-record", + // "examples/pass", + // "examples/store-message", + // "examples/sub-flow", + // "examples/text-operator", + // ], + // }, + // RSN - Check if we need this + // { + // type: "category", + // label: "Migration", + // collapsed: false, + // items: [ + // "migration/migrating-to-one-point-zero", + // "migration/compatibility", + // ], + // }, { type: "category", label: "Tutorials", @@ -139,6 +144,7 @@ module.exports = { label: "Integrations", collapsed: false, items: [ + "integrations/langsmith/intro", { type: "category", label: "Notion", @@ -155,6 +161,13 @@ module.exports = { "integrations/notion/page-content-viewer", ], }, + // { + // type: "category", + // label: "LangSmith", + // items: [ + // , + // ], + // }, ], }, ], diff --git a/docs/src/css/custom.css b/docs/src/css/custom.css index ee3962703..68d901e07 100644 --- a/docs/src/css/custom.css +++ b/docs/src/css/custom.css @@ -240,3 +240,7 @@ body { .ch-scrollycoding-step-content { min-height: 70px; } + +.theme-doc-sidebar-item-category.theme-doc-sidebar-item-category-level-2.menu__list-item:not(:first-child) { + margin-top: 0.25rem!important; +} \ No newline at end of file diff --git a/docs/static/data/AstraDB-RAG-Flows.json b/docs/static/data/AstraDB-RAG-Flows.json index 9a26ceb50..88c4a22a0 100644 --- a/docs/static/data/AstraDB-RAG-Flows.json +++ b/docs/static/data/AstraDB-RAG-Flows.json @@ -1,30 +1,31 @@ { - "id": "c9e0cb46-c474-451a-8496-413f58481d92", + "id": "152a031a-a41a-4df1-a161-19800f686776", "data": { "nodes": [ { "data": { - "id": "ChatInput-IY8UK", + "description": "Get chat inputs from the Playground.", + "display_name": "Chat Input", + "edited": false, + "id": "ChatInput-8ZRjI", "node": { "base_classes": [ - "Text", - "str", - "object", - "Record" + "Message" ], "beta": false, - "custom_fields": { - "input_value": null, - "return_record": null, - "sender": null, - "sender_name": null, - "session_id": null - }, + "conditional_paths": [], + "custom_fields": {}, "description": "Get chat inputs from the Playground.", "display_name": "Chat Input", "documentation": "", - "field_formatters": {}, - "field_order": [], + "edited": true, + "field_order": [ + "input_value", + "sender", + "sender_name", + "session_id", + "files" + ], "frozen": false, "icon": "ChatInput", "output_types": [], @@ -32,16 +33,17 @@ { "cache": true, "display_name": "Message", + "hidden": false, "method": "message_response", "name": "message", "selected": "Message", "types": [ "Message" ], - "value": "__UNDEFINED__", - "hidden": false + "value": "__UNDEFINED__" } ], + "pinned": false, "template": { "_type": "Component", "code": { @@ -60,28 +62,67 @@ "show": true, "title_case": false, "type": "code", - "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.io import DropdownInput, FileInput, MultilineInput, Output, MessageTextInput\nfrom langflow.schema.message import Message\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\"],\n value=\"User\",\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=\"User\",\n advanced=True,\n ),\n MessageTextInput(name=\"session_id\", display_name=\"Session ID\", info=\"Session ID for the message.\", advanced=True),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n )\n if self.session_id and isinstance(message, Message) and isinstance(message.text, str):\n self.store_message(message)\n self.message.value = message\n\n self.status = message\n return message\n" + "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.schema.message import Message\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\"],\n value=\"User\",\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=\"User\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\", display_name=\"Session ID\", info=\"Session ID for the message.\", advanced=True\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n )\n if self.session_id and isinstance(message, Message) and isinstance(message.text, str):\n self.store_message(message)\n self.message.value = message\n\n self.status = message\n return message\n" + }, + "files": { + "advanced": true, + "display_name": "Files", + "dynamic": false, + "fileTypes": [ + "txt", + "md", + "mdx", + "csv", + "json", + "yaml", + "yml", + "xml", + "html", + "htm", + "pdf", + "docx", + "py", + "sh", + "sql", + "js", + "ts", + "tsx", + "jpg", + "jpeg", + "png", + "bmp", + "image" + ], + "file_path": "", + "info": "Files to be sent with the message.", + "list": true, + "name": "files", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "file", + "value": "" }, "input_value": { "advanced": false, "display_name": "Text", "dynamic": false, - "fileTypes": [], - "file_path": "", "info": "Message to be passed as input.", "input_types": [ - "Message", - "str" + "Message" ], "list": false, "load_from_db": false, "multiline": true, "name": "input_value", - "password": false, "placeholder": "", "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" }, @@ -89,25 +130,17 @@ "advanced": true, "display_name": "Sender Type", "dynamic": false, - "fileTypes": [], - "file_path": "", "info": "Type of sender.", - "input_types": [ - "Text" - ], - "list": true, - "load_from_db": false, - "multiline": false, "name": "sender", "options": [ "Machine", "User" ], - "password": false, "placeholder": "", "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "str", "value": "User" }, @@ -115,22 +148,19 @@ "advanced": true, "display_name": "Sender Name", "dynamic": false, - "fileTypes": [], - "file_path": "", "info": "Name of the sender.", "input_types": [ - "Message", - "str" + "Message" ], "list": false, "load_from_db": false, - "multiline": true, "name": "sender_name", - "password": false, "placeholder": "", "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "User" }, @@ -138,22 +168,19 @@ "advanced": true, "display_name": "Session ID", "dynamic": false, - "fileTypes": [], - "file_path": "", "info": "Session ID for the message.", "input_types": [ - "Message", - "str" + "Message" ], "list": false, "load_from_db": false, - "multiline": true, "name": "session_id", - "password": false, "placeholder": "", "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" } @@ -163,14 +190,14 @@ }, "dragging": false, "height": 309, - "id": "ChatInput-IY8UK", + "id": "ChatInput-8ZRjI", "position": { - "x": 702.4571951501161, - "y": 119.7726926425525 + "x": 682.002772470747, + "y": 253.67030039648512 }, "positionAbsolute": { - "x": 702.4571951501161, - "y": 119.7726926425525 + "x": 682.002772470747, + "y": 253.67030039648512 }, "selected": false, "type": "genericNode", @@ -178,101 +205,7 @@ }, { "data": { - "description": "Display a text output in the Playground.", - "display_name": "Extracted Chunks", - "edited": false, - "id": "TextOutput-IxTee", - "node": { - "template": { - "_type": "Component", - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from langflow.base.io.text import TextComponent\nfrom langflow.io import Output, MessageTextInput\nfrom langflow.schema.message import Message\n\n\nclass TextOutputComponent(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\n icon = \"type\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Text to be passed as output.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Text\", name=\"text\", method=\"text_response\"),\n ]\n\n def text_response(self) -> Message:\n message = Message(\n text=self.input_value,\n )\n self.status = self.input_value\n return message\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "load_from_db": false, - "list": false, - "required": false, - "placeholder": "", - "show": true, - "value": "", - "name": "input_value", - "display_name": "Text", - "advanced": false, - "input_types": [ - "Message" - ], - "dynamic": false, - "info": "Text to be passed as output.", - "title_case": false, - "type": "str" - } - }, - "description": "Display a text output in the Playground.", - "icon": "type", - "base_classes": [ - "Message" - ], - "display_name": "Extracted Chunks", - "documentation": "", - "custom_fields": {}, - "output_types": [], - "pinned": false, - "conditional_paths": [], - "frozen": false, - "outputs": [ - { - "types": [ - "Message" - ], - "selected": "Message", - "name": "text", - "display_name": "Text", - "method": "text_response", - "value": "__UNDEFINED__", - "cache": true - } - ], - "field_order": [ - "input_value" - ], - "beta": false, - "edited": true - }, - "type": "TextOutput" - }, - "dragging": false, - "height": 309, - "id": "TextOutput-IxTee", - "position": { - "x": 2439.792450398153, - "y": 661.149562774499 - }, - "positionAbsolute": { - "x": 2439.792450398153, - "y": 661.149562774499 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "id": "OpenAIEmbeddings-HoSp5", + "id": "OpenAIEmbeddings-hNOwh", "node": { "base_classes": [ "Embeddings" @@ -314,14 +247,14 @@ { "cache": true, "display_name": "Embeddings", + "hidden": false, "method": "build_embeddings", "name": "embeddings", "selected": "Embeddings", "types": [ "Embeddings" ], - "value": "__UNDEFINED__", - "hidden": false + "value": "__UNDEFINED__" } ], "template": { @@ -375,7 +308,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langchain_openai.embeddings.base import OpenAIEmbeddings\n\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.field_typing import Embeddings\nfrom langflow.io import BoolInput, DictInput, DropdownInput, FloatInput, IntInput, Output, SecretStrInput, MessageTextInput\n\n\nclass OpenAIEmbeddingsComponent(LCModelComponent):\n display_name = \"OpenAI Embeddings\"\n description = \"Generate embeddings using OpenAI models.\"\n icon = \"OpenAI\"\n inputs = [\n DictInput(\n name=\"default_headers\",\n display_name=\"Default Headers\",\n advanced=True,\n info=\"Default headers to use for the API request.\",\n ),\n DictInput(\n name=\"default_query\",\n display_name=\"Default Query\",\n advanced=True,\n info=\"Default query parameters to use for the API request.\",\n ),\n IntInput(name=\"chunk_size\", display_name=\"Chunk Size\", advanced=True, value=1000),\n MessageTextInput(name=\"client\", display_name=\"Client\", advanced=True),\n MessageTextInput(name=\"deployment\", display_name=\"Deployment\", advanced=True),\n IntInput(name=\"embedding_ctx_length\", display_name=\"Embedding Context Length\", advanced=True, value=1536),\n IntInput(name=\"max_retries\", display_name=\"Max Retries\", value=3, advanced=True),\n DropdownInput(\n name=\"model\",\n display_name=\"Model\",\n advanced=False,\n options=[\n \"text-embedding-3-small\",\n \"text-embedding-3-large\",\n \"text-embedding-ada-002\",\n ],\n value=\"text-embedding-3-small\",\n ),\n DictInput(name=\"model_kwargs\", display_name=\"Model Kwargs\", advanced=True),\n SecretStrInput(name=\"openai_api_base\", display_name=\"OpenAI API Base\", advanced=True),\n SecretStrInput(name=\"openai_api_key\", display_name=\"OpenAI API Key\"),\n SecretStrInput(name=\"openai_api_type\", display_name=\"OpenAI API Type\", advanced=True),\n MessageTextInput(name=\"openai_api_version\", display_name=\"OpenAI API Version\", advanced=True),\n MessageTextInput(\n name=\"openai_organization\",\n display_name=\"OpenAI Organization\",\n advanced=True,\n ),\n MessageTextInput(name=\"openai_proxy\", display_name=\"OpenAI Proxy\", advanced=True),\n FloatInput(name=\"request_timeout\", display_name=\"Request Timeout\", advanced=True),\n BoolInput(name=\"show_progress_bar\", display_name=\"Show Progress Bar\", advanced=True),\n BoolInput(name=\"skip_empty\", display_name=\"Skip Empty\", advanced=True),\n MessageTextInput(\n name=\"tiktoken_model_name\",\n display_name=\"TikToken Model Name\",\n advanced=True,\n ),\n BoolInput(\n name=\"tiktoken_enable\",\n display_name=\"TikToken Enable\",\n advanced=True,\n value=True,\n info=\"If False, you must have transformers installed.\",\n ),\n ]\n\n outputs = [\n Output(display_name=\"Embeddings\", name=\"embeddings\", method=\"build_embeddings\"),\n ]\n\n def build_embeddings(self) -> Embeddings:\n return OpenAIEmbeddings(\n tiktoken_enabled=self.tiktoken_enable,\n default_headers=self.default_headers,\n default_query=self.default_query,\n allowed_special=\"all\",\n disallowed_special=\"all\",\n chunk_size=self.chunk_size,\n deployment=self.deployment,\n embedding_ctx_length=self.embedding_ctx_length,\n max_retries=self.max_retries,\n model=self.model,\n model_kwargs=self.model_kwargs,\n base_url=self.openai_api_base,\n api_key=self.openai_api_key,\n openai_api_type=self.openai_api_type,\n api_version=self.openai_api_version,\n organization=self.openai_organization,\n openai_proxy=self.openai_proxy,\n timeout=self.request_timeout or None,\n show_progress_bar=self.show_progress_bar,\n skip_empty=self.skip_empty,\n tiktoken_model_name=self.tiktoken_model_name,\n )\n" + "value": "from langchain_openai.embeddings.base import OpenAIEmbeddings\n\nfrom langflow.base.embeddings.model import LCEmbeddingsModel\nfrom langflow.field_typing import Embeddings\nfrom langflow.io import BoolInput, DictInput, DropdownInput, FloatInput, IntInput, SecretStrInput, MessageTextInput\n\n\nclass OpenAIEmbeddingsComponent(LCEmbeddingsModel):\n display_name = \"OpenAI Embeddings\"\n description = \"Generate embeddings using OpenAI models.\"\n icon = \"OpenAI\"\n inputs = [\n DictInput(\n name=\"default_headers\",\n display_name=\"Default Headers\",\n advanced=True,\n info=\"Default headers to use for the API request.\",\n ),\n DictInput(\n name=\"default_query\",\n display_name=\"Default Query\",\n advanced=True,\n info=\"Default query parameters to use for the API request.\",\n ),\n IntInput(name=\"chunk_size\", display_name=\"Chunk Size\", advanced=True, value=1000),\n MessageTextInput(name=\"client\", display_name=\"Client\", advanced=True),\n MessageTextInput(name=\"deployment\", display_name=\"Deployment\", advanced=True),\n IntInput(name=\"embedding_ctx_length\", display_name=\"Embedding Context Length\", advanced=True, value=1536),\n IntInput(name=\"max_retries\", display_name=\"Max Retries\", value=3, advanced=True),\n DropdownInput(\n name=\"model\",\n display_name=\"Model\",\n advanced=False,\n options=[\n \"text-embedding-3-small\",\n \"text-embedding-3-large\",\n \"text-embedding-ada-002\",\n ],\n value=\"text-embedding-3-small\",\n ),\n DictInput(name=\"model_kwargs\", display_name=\"Model Kwargs\", advanced=True),\n SecretStrInput(name=\"openai_api_base\", display_name=\"OpenAI API Base\", advanced=True),\n SecretStrInput(name=\"openai_api_key\", display_name=\"OpenAI API Key\"),\n SecretStrInput(name=\"openai_api_type\", display_name=\"OpenAI API Type\", advanced=True),\n MessageTextInput(name=\"openai_api_version\", display_name=\"OpenAI API Version\", advanced=True),\n MessageTextInput(\n name=\"openai_organization\",\n display_name=\"OpenAI Organization\",\n advanced=True,\n ),\n MessageTextInput(name=\"openai_proxy\", display_name=\"OpenAI Proxy\", advanced=True),\n FloatInput(name=\"request_timeout\", display_name=\"Request Timeout\", advanced=True),\n BoolInput(name=\"show_progress_bar\", display_name=\"Show Progress Bar\", advanced=True),\n BoolInput(name=\"skip_empty\", display_name=\"Skip Empty\", advanced=True),\n MessageTextInput(\n name=\"tiktoken_model_name\",\n display_name=\"TikToken Model Name\",\n advanced=True,\n ),\n BoolInput(\n name=\"tiktoken_enable\",\n display_name=\"TikToken Enable\",\n advanced=True,\n value=True,\n info=\"If False, you must have transformers installed.\",\n ),\n ]\n\n def build_embeddings(self) -> Embeddings:\n return OpenAIEmbeddings(\n tiktoken_enabled=self.tiktoken_enable,\n default_headers=self.default_headers,\n default_query=self.default_query,\n allowed_special=\"all\",\n disallowed_special=\"all\",\n chunk_size=self.chunk_size,\n deployment=self.deployment,\n embedding_ctx_length=self.embedding_ctx_length,\n max_retries=self.max_retries,\n model=self.model,\n model_kwargs=self.model_kwargs,\n base_url=self.openai_api_base,\n api_key=self.openai_api_key,\n openai_api_type=self.openai_api_type,\n api_version=self.openai_api_version,\n organization=self.openai_organization,\n openai_proxy=self.openai_proxy,\n timeout=self.request_timeout or None,\n show_progress_bar=self.show_progress_bar,\n skip_empty=self.skip_empty,\n tiktoken_model_name=self.tiktoken_model_name,\n )\n" }, "default_headers": { "advanced": true, @@ -506,7 +439,7 @@ "dynamic": false, "info": "", "input_types": [], - "load_from_db": true, + "load_from_db": false, "name": "openai_api_key", "password": true, "placeholder": "", @@ -669,15 +602,15 @@ "type": "OpenAIEmbeddings" }, "dragging": false, - "height": 395, - "id": "OpenAIEmbeddings-HoSp5", + "height": 393, + "id": "OpenAIEmbeddings-hNOwh", "position": { - "x": 690.5967478991026, - "y": 597.6680004855787 + "x": 672.1192980997866, + "y": 786.6985113716086 }, "positionAbsolute": { - "x": 690.5967478991026, - "y": 597.6680004855787 + "x": 672.1192980997866, + "y": 786.6985113716086 }, "selected": false, "type": "genericNode", @@ -685,235 +618,22 @@ }, { "data": { - "id": "OpenAIModel-ickkA", + "description": "Generates text using OpenAI LLMs.", + "display_name": "OpenAI", + "edited": false, + "id": "OpenAIModel-euVNy", "node": { - "template": { - "_type": "Component", - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "import operator\nfrom functools import reduce\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import LanguageModel\nfrom langflow.inputs import (\n BoolInput,\n DictInput,\n DropdownInput,\n FloatInput,\n IntInput,\n MessageInput,\n SecretStrInput,\n StrInput,\n)\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n inputs = [\n MessageInput(name=\"input_value\", display_name=\"Input\"),\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n info=\"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n ),\n DictInput(name=\"model_kwargs\", display_name=\"Model Kwargs\", advanced=True),\n DictInput(\n name=\"output_schema\",\n is_list=True,\n display_name=\"Schema\",\n advanced=True,\n info=\"The schema for the Output of the model. You must pass the word JSON in the prompt. If left blank, JSON mode will be disabled.\",\n ),\n DropdownInput(\n name=\"model_name\", display_name=\"Model Name\", advanced=False, options=MODEL_NAMES, value=MODEL_NAMES[0]\n ),\n StrInput(\n name=\"openai_api_base\",\n display_name=\"OpenAI API Base\",\n advanced=True,\n info=\"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.\",\n ),\n SecretStrInput(\n name=\"openai_api_key\",\n display_name=\"OpenAI API Key\",\n info=\"The OpenAI API Key to use for the OpenAI model.\",\n advanced=False,\n value=\"OPENAI_API_KEY\",\n ),\n FloatInput(name=\"temperature\", display_name=\"Temperature\", value=0.1),\n BoolInput(name=\"stream\", display_name=\"Stream\", info=STREAM_INFO_TEXT, advanced=True),\n StrInput(\n name=\"system_message\",\n display_name=\"System Message\",\n info=\"System message to pass to the model.\",\n advanced=True,\n ),\n IntInput(\n name=\"seed\",\n display_name=\"Seed\",\n info=\"The seed controls the reproducibility of the job.\",\n advanced=True,\n value=1,\n ),\n ]\n\n def build_model(self) -> LanguageModel:\n # self.output_schea is a list of dictionaries\n # let's convert it to a dictionary\n output_schema_dict: dict[str, str] = reduce(operator.ior, self.output_schema or {}, {})\n openai_api_key = self.openai_api_key\n temperature = self.temperature\n model_name: str = self.model_name\n max_tokens = self.max_tokens\n model_kwargs = self.model_kwargs or {}\n openai_api_base = self.openai_api_base or \"https://api.openai.com/v1\"\n json_mode = bool(output_schema_dict)\n seed = self.seed\n model_kwargs[\"seed\"] = seed\n\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature or 0.1,\n )\n if json_mode:\n output = output.with_structured_output(schema=output_schema_dict, method=\"json_mode\") # type: ignore\n\n return output\n\n def _get_exception_message(self, e: Exception):\n \"\"\"\n Get a message from an OpenAI exception.\n\n Args:\n exception (Exception): The exception to get the message from.\n\n Returns:\n str: The message from the exception.\n \"\"\"\n\n try:\n from openai import BadRequestError\n except ImportError:\n return\n if isinstance(e, BadRequestError):\n message = e.body.get(\"message\") # type: ignore\n if message:\n return message\n return\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "load_from_db": false, - "list": false, - "required": false, - "placeholder": "", - "show": true, - "value": "", - "name": "input_value", - "display_name": "Input", - "advanced": false, - "input_types": [ - "Message" - ], - "dynamic": false, - "info": "", - "title_case": false, - "type": "str" - }, - "max_tokens": { - "list": false, - "required": false, - "placeholder": "", - "show": true, - "value": "", - "name": "max_tokens", - "display_name": "Max Tokens", - "advanced": true, - "dynamic": false, - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "title_case": false, - "type": "int" - }, - "model_kwargs": { - "list": false, - "required": false, - "placeholder": "", - "show": true, - "value": {}, - "name": "model_kwargs", - "display_name": "Model Kwargs", - "advanced": true, - "dynamic": false, - "info": "", - "title_case": false, - "type": "dict" - }, - "model_name": { - "options": [ - "gpt-4o", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125" - ], - "required": false, - "placeholder": "", - "show": true, - "value": "gpt-3.5-turbo", - "name": "model_name", - "display_name": "Model Name", - "advanced": false, - "dynamic": false, - "info": "", - "title_case": false, - "type": "str" - }, - "openai_api_base": { - "load_from_db": false, - "list": false, - "required": false, - "placeholder": "", - "show": true, - "value": "", - "name": "openai_api_base", - "display_name": "OpenAI API Base", - "advanced": true, - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", - "title_case": false, - "type": "str" - }, - "openai_api_key": { - "load_from_db": true, - "required": false, - "placeholder": "", - "show": true, - "value": "", - "name": "openai_api_key", - "display_name": "OpenAI API Key", - "advanced": false, - "input_types": [], - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "title_case": false, - "password": true, - "type": "str" - }, - "output_schema": { - "list": true, - "required": false, - "placeholder": "", - "show": true, - "value": {}, - "name": "output_schema", - "display_name": "Schema", - "advanced": true, - "dynamic": false, - "info": "The schema for the Output of the model. You must pass the word JSON in the prompt. If left blank, JSON mode will be disabled.", - "title_case": false, - "type": "dict" - }, - "seed": { - "list": false, - "required": false, - "placeholder": "", - "show": true, - "value": 1, - "name": "seed", - "display_name": "Seed", - "advanced": true, - "dynamic": false, - "info": "The seed controls the reproducibility of the job.", - "title_case": false, - "type": "int" - }, - "stream": { - "list": false, - "required": false, - "placeholder": "", - "show": true, - "value": false, - "name": "stream", - "display_name": "Stream", - "advanced": true, - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "title_case": false, - "type": "bool" - }, - "system_message": { - "load_from_db": false, - "list": false, - "required": false, - "placeholder": "", - "show": true, - "value": "", - "name": "system_message", - "display_name": "System Message", - "advanced": true, - "dynamic": false, - "info": "System message to pass to the model.", - "title_case": false, - "type": "str" - }, - "temperature": { - "list": false, - "required": false, - "placeholder": "", - "show": true, - "value": 0.1, - "name": "temperature", - "display_name": "Temperature", - "advanced": false, - "dynamic": false, - "info": "", - "title_case": false, - "type": "float" - } - }, - "description": "Generates text using OpenAI LLMs.", - "icon": "OpenAI", "base_classes": [ "LanguageModel", "Message" ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Generates text using OpenAI LLMs.", "display_name": "OpenAI", "documentation": "", - "custom_fields": {}, - "output_types": [], - "pinned": false, - "conditional_paths": [], - "frozen": false, - "outputs": [ - { - "types": [ - "Message" - ], - "selected": "Message", - "name": "text_output", - "display_name": "Text", - "method": "text_response", - "value": "__UNDEFINED__", - "cache": true, - "hidden": false - }, - { - "types": [ - "LanguageModel" - ], - "selected": "LanguageModel", - "name": "model_output", - "display_name": "Language Model", - "method": "build_model", - "value": "__UNDEFINED__", - "cache": true - } - ], + "edited": true, "field_order": [ "input_value", "max_tokens", @@ -927,73 +647,32 @@ "system_message", "seed" ], - "beta": false, - "edited": true - }, - "type": "OpenAIModel", - "description": "Generates text using OpenAI LLMs.", - "display_name": "OpenAI", - "edited": false - }, - "dragging": false, - "height": 623, - "id": "OpenAIModel-ickkA", - "position": { - "x": 3410.117202077183, - "y": 431.2038048137648 - }, - "positionAbsolute": { - "x": 3410.117202077183, - "y": 431.2038048137648 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt", - "id": "Prompt-jzPqb", - "node": { - "base_classes": [ - "object", - "str", - "Text" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": { - "template": [ - "context", - "question" - ] - }, - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt", - "documentation": "", - "error": null, - "field_order": [], "frozen": false, - "full_path": null, - "icon": "prompts", - "is_composition": null, - "is_input": null, - "is_output": null, - "name": "", + "icon": "OpenAI", "output_types": [], "outputs": [ { "cache": true, - "display_name": "Prompt Message", - "method": "build_prompt", - "name": "prompt", + "display_name": "Text", + "hidden": false, + "method": "text_response", + "name": "text_output", "selected": "Message", "types": [ "Message" ], - "value": "__UNDEFINED__", - "hidden": false + "value": "__UNDEFINED__" + }, + { + "cache": true, + "display_name": "Language Model", + "method": "build_model", + "name": "model_output", + "selected": "LanguageModel", + "types": [ + "LanguageModel" + ], + "value": "__UNDEFINED__" } ], "pinned": false, @@ -1015,25 +694,19 @@ "show": true, "title_case": false, "type": "code", - "value": "from langflow.custom import Component\nfrom langflow.io import Output, PromptInput\nfrom langflow.schema.message import Message\n\n\nclass PromptComponent(Component):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n prompt = await Message.from_template_and_variables(**self._attributes)\n self.status = prompt.text\n return prompt\n" + "value": "import operator\nfrom functools import reduce\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import LanguageModel\nfrom langflow.inputs import (\n BoolInput,\n DictInput,\n DropdownInput,\n FloatInput,\n IntInput,\n MessageInput,\n SecretStrInput,\n StrInput,\n)\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n inputs = [\n MessageInput(name=\"input_value\", display_name=\"Input\"),\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n info=\"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n ),\n DictInput(name=\"model_kwargs\", display_name=\"Model Kwargs\", advanced=True),\n DictInput(\n name=\"output_schema\",\n is_list=True,\n display_name=\"Schema\",\n advanced=True,\n info=\"The schema for the Output of the model. You must pass the word JSON in the prompt. If left blank, JSON mode will be disabled.\",\n ),\n DropdownInput(\n name=\"model_name\", display_name=\"Model Name\", advanced=False, options=MODEL_NAMES, value=MODEL_NAMES[0]\n ),\n StrInput(\n name=\"openai_api_base\",\n display_name=\"OpenAI API Base\",\n advanced=True,\n info=\"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.\",\n ),\n SecretStrInput(\n name=\"openai_api_key\",\n display_name=\"OpenAI API Key\",\n info=\"The OpenAI API Key to use for the OpenAI model.\",\n advanced=False,\n value=\"OPENAI_API_KEY\",\n ),\n FloatInput(name=\"temperature\", display_name=\"Temperature\", value=0.1),\n BoolInput(name=\"stream\", display_name=\"Stream\", info=STREAM_INFO_TEXT, advanced=True),\n StrInput(\n name=\"system_message\",\n display_name=\"System Message\",\n info=\"System message to pass to the model.\",\n advanced=True,\n ),\n IntInput(\n name=\"seed\",\n display_name=\"Seed\",\n info=\"The seed controls the reproducibility of the job.\",\n advanced=True,\n value=1,\n ),\n ]\n\n def build_model(self) -> LanguageModel:\n # self.output_schea is a list of dictionaries\n # let's convert it to a dictionary\n output_schema_dict: dict[str, str] = reduce(operator.ior, self.output_schema or {}, {})\n openai_api_key = self.openai_api_key\n temperature = self.temperature\n model_name: str = self.model_name\n max_tokens = self.max_tokens\n model_kwargs = self.model_kwargs or {}\n openai_api_base = self.openai_api_base or \"https://api.openai.com/v1\"\n json_mode = bool(output_schema_dict)\n seed = self.seed\n model_kwargs[\"seed\"] = seed\n\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature or 0.1,\n )\n if json_mode:\n output = output.with_structured_output(schema=output_schema_dict, method=\"json_mode\") # type: ignore\n\n return output\n\n def _get_exception_message(self, e: Exception):\n \"\"\"\n Get a message from an OpenAI exception.\n\n Args:\n exception (Exception): The exception to get the message from.\n\n Returns:\n str: The message from the exception.\n \"\"\"\n\n try:\n from openai import BadRequestError\n except ImportError:\n return\n if isinstance(e, BadRequestError):\n message = e.body.get(\"message\") # type: ignore\n if message:\n return message\n return\n" }, - "context": { + "input_value": { "advanced": false, - "display_name": "context", + "display_name": "Input", "dynamic": false, - "field_type": "str", - "fileTypes": [], - "file_path": "", "info": "", "input_types": [ - "Message", - "Text" + "Message" ], "list": false, "load_from_db": false, - "multiline": true, - "name": "context", - "password": false, + "name": "input_value", "placeholder": "", "required": false, "show": true, @@ -1041,23 +714,62 @@ "type": "str", "value": "" }, - "question": { - "advanced": false, - "display_name": "question", + "max_tokens": { + "advanced": true, + "display_name": "Max Tokens", + "dynamic": false, + "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", + "list": false, + "name": "max_tokens", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": "" + }, + "model_kwargs": { + "advanced": true, + "display_name": "Model Kwargs", "dynamic": false, - "field_type": "str", - "fileTypes": [], - "file_path": "", "info": "", - "input_types": [ - "Message", - "Text" + "list": false, + "name": "model_kwargs", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "dict", + "value": {} + }, + "model_name": { + "advanced": false, + "display_name": "Model Name", + "dynamic": false, + "info": "", + "name": "model_name", + "options": [ + "gpt-4o", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-3.5-turbo", + "gpt-3.5-turbo-0125" ], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "gpt-4-turbo" + }, + "openai_api_base": { + "advanced": true, + "display_name": "OpenAI API Base", + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", "list": false, "load_from_db": false, - "multiline": true, - "name": "question", - "password": false, + "name": "openai_api_base", "placeholder": "", "required": false, "show": true, @@ -1065,42 +777,107 @@ "type": "str", "value": "" }, - "template": { + "openai_api_key": { "advanced": false, - "display_name": "Template", + "display_name": "OpenAI API Key", "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Text" - ], - "list": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "input_types": [], "load_from_db": false, - "multiline": false, - "name": "template", - "password": false, + "name": "openai_api_key", + "password": true, "placeholder": "", "required": false, "show": true, "title_case": false, - "type": "prompt", - "value": "{context}\n\n---\n\nGiven the context above, answer the question as best as possible.\n\nQuestion: {question}\n\nAnswer: " + "type": "str", + "value": "" + }, + "output_schema": { + "advanced": true, + "display_name": "Schema", + "dynamic": false, + "info": "The schema for the Output of the model. You must pass the word JSON in the prompt. If left blank, JSON mode will be disabled.", + "list": true, + "name": "output_schema", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "dict", + "value": {} + }, + "seed": { + "advanced": true, + "display_name": "Seed", + "dynamic": false, + "info": "The seed controls the reproducibility of the job.", + "list": false, + "name": "seed", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": 1 + }, + "stream": { + "advanced": true, + "display_name": "Stream", + "dynamic": false, + "info": "Stream the response from the model. Streaming works only in Chat.", + "list": false, + "name": "stream", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "bool", + "value": false + }, + "system_message": { + "advanced": true, + "display_name": "System Message", + "dynamic": false, + "info": "System message to pass to the model.", + "list": false, + "load_from_db": false, + "name": "system_message", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "temperature": { + "advanced": false, + "display_name": "Temperature", + "dynamic": false, + "info": "", + "list": false, + "name": "temperature", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "float", + "value": 0.1 } } }, - "type": "Prompt" + "type": "OpenAIModel" }, "dragging": false, - "height": 525, - "id": "Prompt-jzPqb", + "height": 623, + "id": "OpenAIModel-euVNy", "position": { - "x": 2941.2776396951576, - "y": 446.43037366459487 + "x": 3243.967394111999, + "y": 392.861541437184 }, "positionAbsolute": { - "x": 2941.2776396951576, - "y": 446.43037366459487 + "x": 3243.967394111999, + "y": 392.861541437184 }, "selected": false, "type": "genericNode", @@ -1108,28 +885,28 @@ }, { "data": { - "id": "ChatOutput-Zy354", + "description": "Display a chat message in the Playground.", + "display_name": "Chat Output", + "edited": false, + "id": "ChatOutput-1eddV", "node": { "base_classes": [ - "object", - "Text", - "Record", - "str" + "Message" ], "beta": false, - "custom_fields": { - "input_value": null, - "record_template": null, - "return_record": null, - "sender": null, - "sender_name": null, - "session_id": null - }, + "conditional_paths": [], + "custom_fields": {}, "description": "Display a chat message in the Playground.", "display_name": "Chat Output", "documentation": "", - "field_formatters": {}, - "field_order": [], + "edited": true, + "field_order": [ + "input_value", + "sender", + "sender_name", + "session_id", + "data_template" + ], "frozen": false, "icon": "ChatOutput", "output_types": [], @@ -1146,6 +923,7 @@ "value": "__UNDEFINED__" } ], + "pinned": false, "template": { "_type": "Component", "code": { @@ -1164,28 +942,45 @@ "show": true, "title_case": false, "type": "code", - "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.io import DropdownInput, Output, MessageTextInput\nfrom langflow.schema.message import Message\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\"],\n value=\"Machine\",\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\", display_name=\"Sender Name\", info=\"Name of the sender.\", value=\"AI\", advanced=True\n ),\n MessageTextInput(name=\"session_id\", display_name=\"Session ID\", info=\"Session ID for the message.\", advanced=True),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n )\n if self.session_id and isinstance(message, Message) and isinstance(message.text, str):\n self.store_message(message)\n self.message.value = message\n\n self.status = message\n return message\n" + "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\"],\n value=\"Machine\",\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\", display_name=\"Sender Name\", info=\"Name of the sender.\", value=\"AI\", advanced=True\n ),\n MessageTextInput(\n name=\"session_id\", display_name=\"Session ID\", info=\"Session ID for the message.\", advanced=True\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n )\n if self.session_id and isinstance(message, Message) and isinstance(message.text, str):\n self.store_message(message)\n self.message.value = message\n\n self.status = message\n return message\n" + }, + "data_template": { + "advanced": true, + "display_name": "Data Template", + "dynamic": false, + "info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "name": "data_template", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "{text}" }, "input_value": { "advanced": false, "display_name": "Text", "dynamic": false, - "fileTypes": [], - "file_path": "", "info": "Message to be passed as output.", "input_types": [ - "Message", - "str" + "Message" ], "list": false, "load_from_db": false, - "multiline": true, "name": "input_value", - "password": false, "placeholder": "", "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" }, @@ -1193,25 +988,17 @@ "advanced": true, "display_name": "Sender Type", "dynamic": false, - "fileTypes": [], - "file_path": "", "info": "Type of sender.", - "input_types": [ - "Text" - ], - "list": true, - "load_from_db": false, - "multiline": false, "name": "sender", "options": [ "Machine", "User" ], - "password": false, "placeholder": "", "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "str", "value": "Machine" }, @@ -1219,22 +1006,19 @@ "advanced": true, "display_name": "Sender Name", "dynamic": false, - "fileTypes": [], - "file_path": "", "info": "Name of the sender.", "input_types": [ - "Message", - "str" + "Message" ], "list": false, "load_from_db": false, - "multiline": true, "name": "sender_name", - "password": false, "placeholder": "", "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "AI" }, @@ -1242,22 +1026,19 @@ "advanced": true, "display_name": "Session ID", "dynamic": false, - "fileTypes": [], - "file_path": "", "info": "Session ID for the message.", "input_types": [ - "Message", - "str" + "Message" ], "list": false, "load_from_db": false, - "multiline": true, "name": "session_id", - "password": false, "placeholder": "", "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" } @@ -1267,14 +1048,14 @@ }, "dragging": false, "height": 309, - "id": "ChatOutput-Zy354", + "id": "ChatOutput-1eddV", "position": { - "x": 3998.201592537035, - "y": 603.4216529723935 + "x": 3788.786948642587, + "y": 608.4077159222614 }, "positionAbsolute": { - "x": 3998.201592537035, - "y": 603.4216529723935 + "x": 3788.786948642587, + "y": 608.4077159222614 }, "selected": false, "type": "genericNode", @@ -1282,7 +1063,7 @@ }, { "data": { - "id": "File-28ckd", + "id": "File-p2YBf", "node": { "base_classes": [ "Record" @@ -1304,14 +1085,14 @@ { "cache": true, "display_name": "Data", + "hidden": false, "method": "load_file", "name": "data", "selected": "Data", "types": [ "Data" ], - "value": "__UNDEFINED__", - "hidden": false + "value": "__UNDEFINED__" } ], "template": { @@ -1358,7 +1139,7 @@ "ts", "tsx" ], - "file_path": "c9e0cb46-c474-451a-8496-413f58481d92/Context Once.json", + "file_path": "bba1609b-3af2-431d-a884-322cc253c69d/flatland.pdf", "info": "Supported file types: txt, md, mdx, csv, json, yaml, yml, xml, html, htm, pdf, docx, py, sh, sql, js, ts, tsx", "list": false, "name": "path", @@ -1389,574 +1170,14 @@ }, "dragging": false, "height": 301, - "id": "File-28ckd", + "id": "File-p2YBf", "position": { - "x": 2257.233450682836, - "y": 1747.5389618367233 + "x": 1435.8917804347734, + "y": 1603.546667861399 }, "positionAbsolute": { - "x": 2257.233450682836, - "y": 1747.5389618367233 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "id": "OpenAIEmbeddings-YeYtt", - "node": { - "base_classes": [ - "Embeddings" - ], - "beta": false, - "custom_fields": { - "allowed_special": null, - "chunk_size": null, - "client": null, - "default_headers": null, - "default_query": null, - "deployment": null, - "disallowed_special": null, - "embedding_ctx_length": null, - "max_retries": null, - "model": null, - "model_kwargs": null, - "openai_api_base": null, - "openai_api_key": null, - "openai_api_type": null, - "openai_api_version": null, - "openai_organization": null, - "openai_proxy": null, - "request_timeout": null, - "show_progress_bar": null, - "skip_empty": null, - "tiktoken_enable": null, - "tiktoken_model_name": null - }, - "description": "Generate embeddings using OpenAI models.", - "display_name": "OpenAI Embeddings", - "documentation": "", - "field_formatters": {}, - "field_order": [], - "frozen": false, - "icon": "OpenAI", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Embeddings", - "method": "build_embeddings", - "name": "embeddings", - "selected": "Embeddings", - "types": [ - "Embeddings" - ], - "value": "__UNDEFINED__", - "hidden": false - } - ], - "template": { - "_type": "Component", - "chunk_size": { - "advanced": true, - "display_name": "Chunk Size", - "dynamic": false, - "info": "", - "list": false, - "name": "chunk_size", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": 1000 - }, - "client": { - "advanced": true, - "display_name": "Client", - "dynamic": false, - "info": "", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "name": "client", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langchain_openai.embeddings.base import OpenAIEmbeddings\n\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.field_typing import Embeddings\nfrom langflow.io import BoolInput, DictInput, DropdownInput, FloatInput, IntInput, Output, SecretStrInput, MessageTextInput\n\n\nclass OpenAIEmbeddingsComponent(LCModelComponent):\n display_name = \"OpenAI Embeddings\"\n description = \"Generate embeddings using OpenAI models.\"\n icon = \"OpenAI\"\n inputs = [\n DictInput(\n name=\"default_headers\",\n display_name=\"Default Headers\",\n advanced=True,\n info=\"Default headers to use for the API request.\",\n ),\n DictInput(\n name=\"default_query\",\n display_name=\"Default Query\",\n advanced=True,\n info=\"Default query parameters to use for the API request.\",\n ),\n IntInput(name=\"chunk_size\", display_name=\"Chunk Size\", advanced=True, value=1000),\n MessageTextInput(name=\"client\", display_name=\"Client\", advanced=True),\n MessageTextInput(name=\"deployment\", display_name=\"Deployment\", advanced=True),\n IntInput(name=\"embedding_ctx_length\", display_name=\"Embedding Context Length\", advanced=True, value=1536),\n IntInput(name=\"max_retries\", display_name=\"Max Retries\", value=3, advanced=True),\n DropdownInput(\n name=\"model\",\n display_name=\"Model\",\n advanced=False,\n options=[\n \"text-embedding-3-small\",\n \"text-embedding-3-large\",\n \"text-embedding-ada-002\",\n ],\n value=\"text-embedding-3-small\",\n ),\n DictInput(name=\"model_kwargs\", display_name=\"Model Kwargs\", advanced=True),\n SecretStrInput(name=\"openai_api_base\", display_name=\"OpenAI API Base\", advanced=True),\n SecretStrInput(name=\"openai_api_key\", display_name=\"OpenAI API Key\"),\n SecretStrInput(name=\"openai_api_type\", display_name=\"OpenAI API Type\", advanced=True),\n MessageTextInput(name=\"openai_api_version\", display_name=\"OpenAI API Version\", advanced=True),\n MessageTextInput(\n name=\"openai_organization\",\n display_name=\"OpenAI Organization\",\n advanced=True,\n ),\n MessageTextInput(name=\"openai_proxy\", display_name=\"OpenAI Proxy\", advanced=True),\n FloatInput(name=\"request_timeout\", display_name=\"Request Timeout\", advanced=True),\n BoolInput(name=\"show_progress_bar\", display_name=\"Show Progress Bar\", advanced=True),\n BoolInput(name=\"skip_empty\", display_name=\"Skip Empty\", advanced=True),\n MessageTextInput(\n name=\"tiktoken_model_name\",\n display_name=\"TikToken Model Name\",\n advanced=True,\n ),\n BoolInput(\n name=\"tiktoken_enable\",\n display_name=\"TikToken Enable\",\n advanced=True,\n value=True,\n info=\"If False, you must have transformers installed.\",\n ),\n ]\n\n outputs = [\n Output(display_name=\"Embeddings\", name=\"embeddings\", method=\"build_embeddings\"),\n ]\n\n def build_embeddings(self) -> Embeddings:\n return OpenAIEmbeddings(\n tiktoken_enabled=self.tiktoken_enable,\n default_headers=self.default_headers,\n default_query=self.default_query,\n allowed_special=\"all\",\n disallowed_special=\"all\",\n chunk_size=self.chunk_size,\n deployment=self.deployment,\n embedding_ctx_length=self.embedding_ctx_length,\n max_retries=self.max_retries,\n model=self.model,\n model_kwargs=self.model_kwargs,\n base_url=self.openai_api_base,\n api_key=self.openai_api_key,\n openai_api_type=self.openai_api_type,\n api_version=self.openai_api_version,\n organization=self.openai_organization,\n openai_proxy=self.openai_proxy,\n timeout=self.request_timeout or None,\n show_progress_bar=self.show_progress_bar,\n skip_empty=self.skip_empty,\n tiktoken_model_name=self.tiktoken_model_name,\n )\n" - }, - "default_headers": { - "advanced": true, - "display_name": "Default Headers", - "dynamic": false, - "info": "Default headers to use for the API request.", - "list": false, - "name": "default_headers", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "dict", - "value": {} - }, - "default_query": { - "advanced": true, - "display_name": "Default Query", - "dynamic": false, - "info": "Default query parameters to use for the API request.", - "list": false, - "name": "default_query", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "dict", - "value": {} - }, - "deployment": { - "advanced": true, - "display_name": "Deployment", - "dynamic": false, - "info": "", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "name": "deployment", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "embedding_ctx_length": { - "advanced": true, - "display_name": "Embedding Context Length", - "dynamic": false, - "info": "", - "list": false, - "name": "embedding_ctx_length", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": 1536 - }, - "max_retries": { - "advanced": true, - "display_name": "Max Retries", - "dynamic": false, - "info": "", - "list": false, - "name": "max_retries", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": 3 - }, - "model": { - "advanced": false, - "display_name": "Model", - "dynamic": false, - "info": "", - "name": "model", - "options": [ - "text-embedding-3-small", - "text-embedding-3-large", - "text-embedding-ada-002" - ], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "text-embedding-3-small" - }, - "model_kwargs": { - "advanced": true, - "display_name": "Model Kwargs", - "dynamic": false, - "info": "", - "list": false, - "name": "model_kwargs", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "dict", - "value": {} - }, - "openai_api_base": { - "advanced": true, - "display_name": "OpenAI API Base", - "dynamic": false, - "info": "", - "input_types": [], - "load_from_db": true, - "name": "openai_api_base", - "password": true, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "openai_api_key": { - "advanced": false, - "display_name": "OpenAI API Key", - "dynamic": false, - "info": "", - "input_types": [], - "load_from_db": true, - "name": "openai_api_key", - "password": true, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "openai_api_type": { - "advanced": true, - "display_name": "OpenAI API Type", - "dynamic": false, - "info": "", - "input_types": [], - "load_from_db": true, - "name": "openai_api_type", - "password": true, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "openai_api_version": { - "advanced": true, - "display_name": "OpenAI API Version", - "dynamic": false, - "info": "", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "name": "openai_api_version", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "openai_organization": { - "advanced": true, - "display_name": "OpenAI Organization", - "dynamic": false, - "info": "", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "name": "openai_organization", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "openai_proxy": { - "advanced": true, - "display_name": "OpenAI Proxy", - "dynamic": false, - "info": "", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "name": "openai_proxy", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "request_timeout": { - "advanced": true, - "display_name": "Request Timeout", - "dynamic": false, - "info": "", - "list": false, - "name": "request_timeout", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "float", - "value": "" - }, - "show_progress_bar": { - "advanced": true, - "display_name": "Show Progress Bar", - "dynamic": false, - "info": "", - "list": false, - "name": "show_progress_bar", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "bool", - "value": false - }, - "skip_empty": { - "advanced": true, - "display_name": "Skip Empty", - "dynamic": false, - "info": "", - "list": false, - "name": "skip_empty", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "bool", - "value": false - }, - "tiktoken_enable": { - "advanced": true, - "display_name": "TikToken Enable", - "dynamic": false, - "info": "If False, you must have transformers installed.", - "list": false, - "name": "tiktoken_enable", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "bool", - "value": true - }, - "tiktoken_model_name": { - "advanced": true, - "display_name": "TikToken Model Name", - "dynamic": false, - "info": "", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "name": "tiktoken_model_name", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - } - } - }, - "type": "OpenAIEmbeddings" - }, - "dragging": false, - "height": 395, - "id": "OpenAIEmbeddings-YeYtt", - "position": { - "x": 2781.1922529351923, - "y": 2206.267872396239 - }, - "positionAbsolute": { - "x": 2781.1922529351923, - "y": 2206.267872396239 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "description": "Split text into chunks of a specified length.", - "display_name": "Recursive Character Text Splitter", - "id": "RecursiveCharacterTextSplitter-HVESL", - "node": { - "base_classes": [ - "Data" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Split text into chunks of a specified length.", - "display_name": "Recursive Character Text Splitter", - "documentation": "https://docs.langflow.org/components/text-splitters#recursivecharactertextsplitter", - "edited": false, - "field_order": [ - "chunk_size", - "chunk_overlap", - "data_input", - "separators" - ], - "frozen": false, - "output_types": [ - "Data" - ], - "outputs": [ - { - "cache": true, - "display_name": "Data", - "method": "build", - "name": "data", - "selected": "Data", - "types": [ - "Data" - ], - "value": "__UNDEFINED__", - "hidden": false - } - ], - "pinned": false, - "template": { - "_type": "Component", - "chunk_overlap": { - "advanced": false, - "display_name": "Chunk Overlap", - "dynamic": false, - "info": "The amount of overlap between chunks.", - "list": false, - "name": "chunk_overlap", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": 200 - }, - "chunk_size": { - "advanced": false, - "display_name": "Chunk Size", - "dynamic": false, - "info": "The maximum length of each chunk.", - "list": false, - "name": "chunk_size", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": 1000 - }, - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langchain_text_splitters import RecursiveCharacterTextSplitter\n\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DataInput, IntInput, MessageTextInput\nfrom langflow.schema import Data\nfrom langflow.template.field.base import Output\nfrom langflow.utils.util import build_loader_repr_from_data, unescape_string\n\n\nclass RecursiveCharacterTextSplitterComponent(Component):\n display_name: str = \"Recursive Character Text Splitter\"\n description: str = \"Split text into chunks of a specified length.\"\n documentation: str = \"https://docs.langflow.org/components/text-splitters#recursivecharactertextsplitter\"\n\n inputs = [\n IntInput(\n name=\"chunk_size\",\n display_name=\"Chunk Size\",\n info=\"The maximum length of each chunk.\",\n value=1000,\n ),\n IntInput(\n name=\"chunk_overlap\",\n display_name=\"Chunk Overlap\",\n info=\"The amount of overlap between chunks.\",\n value=200,\n ),\n DataInput(\n name=\"data_input\",\n display_name=\"Input\",\n info=\"The texts to split.\",\n input_types=[\"Document\", \"Data\"],\n ),\n MessageTextInput(\n name=\"separators\",\n display_name=\"Separators\",\n info='The characters to split on.\\nIf left empty defaults to [\"\\\\n\\\\n\", \"\\\\n\", \" \", \"\"].',\n is_list=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Data\", name=\"data\", method=\"split_data\"),\n ]\n\n def split_data(self) -> list[Data]:\n \"\"\"\n Split text into chunks of a specified length.\n\n Args:\n separators (list[str]): The characters to split on.\n chunk_size (int): The maximum length of each chunk.\n chunk_overlap (int): The amount of overlap between chunks.\n\n Returns:\n list[str]: The chunks of text.\n \"\"\"\n\n if self.separators == \"\":\n self.separators = None\n elif self.separators:\n # check if the separators list has escaped characters\n # if there are escaped characters, unescape them\n self.separators = [unescape_string(x) for x in self.separators]\n\n # Make sure chunk_size and chunk_overlap are ints\n if isinstance(self.chunk_size, str):\n self.chunk_size = int(self.chunk_size)\n if isinstance(self.chunk_overlap, str):\n self.chunk_overlap = int(self.chunk_overlap)\n splitter = RecursiveCharacterTextSplitter(\n separators=self.separators,\n chunk_size=self.chunk_size,\n chunk_overlap=self.chunk_overlap,\n )\n documents = []\n if not isinstance(self.data_input, list):\n self.data_input = [self.data_input]\n for _input in self.data_input:\n if isinstance(_input, Data):\n documents.append(_input.to_lc_document())\n else:\n documents.append(_input)\n docs = splitter.split_documents(documents)\n data = self.to_data(docs)\n self.repr_value = build_loader_repr_from_data(data)\n return data\n" - }, - "data_input": { - "advanced": false, - "display_name": "Input", - "dynamic": false, - "info": "The texts to split.", - "input_types": [ - "Document", - "Data" - ], - "list": false, - "name": "data_input", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "other", - "value": "" - }, - "separators": { - "advanced": false, - "display_name": "Separators", - "dynamic": false, - "info": "The characters to split on.\nIf left empty defaults to [\"\\n\\n\", \"\\n\", \" \", \"\"].", - "input_types": [ - "Message", - "str" - ], - "list": true, - "load_from_db": false, - "name": "separators", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": [ - "\\n" - ] - } - } - }, - "type": "RecursiveCharacterTextSplitter" - }, - "dragging": false, - "height": 529, - "id": "RecursiveCharacterTextSplitter-HVESL", - "position": { - "x": 2726.46405760335, - "y": 1530.1666819162674 - }, - "positionAbsolute": { - "x": 2726.46405760335, - "y": 1530.1666819162674 + "x": 1435.8917804347734, + "y": 1603.546667861399 }, "selected": false, "type": "genericNode", @@ -1966,7 +1187,7 @@ "data": { "description": "Implementation of Vector Store using Astra DB with search capabilities", "display_name": "Astra DB Vector Store", - "id": "AstraDB-irvai", + "id": "AstraDB-p6135", "node": { "base_classes": [ "Data" @@ -2018,6 +1239,7 @@ { "cache": true, "display_name": "Search Results", + "hidden": false, "method": "search_documents", "name": "search_results", "selected": "Data", @@ -2042,7 +1264,7 @@ "show": true, "title_case": false, "type": "bool", - "value": true + "value": false }, "api_endpoint": { "advanced": false, @@ -2050,7 +1272,7 @@ "dynamic": false, "info": "API endpoint URL for the Astra DB service.", "input_types": [], - "load_from_db": true, + "load_from_db": false, "name": "api_endpoint", "password": true, "placeholder": "", @@ -2333,7 +1555,7 @@ "dynamic": false, "info": "Authentication token for accessing Astra DB.", "input_types": [], - "load_from_db": true, + "load_from_db": false, "name": "token", "password": true, "placeholder": "", @@ -2367,426 +1589,7 @@ }, "dragging": false, "height": 917, - "id": "AstraDB-irvai", - "position": { - "x": 3329.7211874614477, - "y": 1559.774393811144 - }, - "positionAbsolute": { - "x": 3329.7211874614477, - "y": 1559.774393811144 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "description": "Implementation of Vector Store using Astra DB with search capabilities", - "display_name": "Astra DB Vector Store", - "id": "AstraDB-wANQu", - "node": { - "base_classes": [ - "Data" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Implementation of Vector Store using Astra DB with search capabilities", - "display_name": "Astra DB Vector Store", - "documentation": "https://python.langchain.com/docs/integrations/vectorstores/astradb", - "edited": false, - "field_order": [ - "collection_name", - "token", - "api_endpoint", - "vector_store_inputs", - "embedding", - "namespace", - "metric", - "batch_size", - "bulk_insert_batch_concurrency", - "bulk_insert_overwrite_concurrency", - "bulk_delete_concurrency", - "setup_mode", - "pre_delete_collection", - "metadata_indexing_include", - "metadata_indexing_exclude", - "collection_indexing_policy", - "add_to_vector_store", - "search_input", - "search_type", - "number_of_results" - ], - "frozen": false, - "icon": "AstraDB", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Retriever", - "method": "build_base_retriever", - "name": "base_retriever", - "selected": "Data", - "types": [ - "Data" - ], - "value": "__UNDEFINED__" - }, - { - "cache": true, - "display_name": "Search Results", - "method": "search_documents", - "name": "search_results", - "selected": "Data", - "types": [ - "Data" - ], - "value": "__UNDEFINED__", - "hidden": false - } - ], - "pinned": false, - "template": { - "_type": "Component", - "add_to_vector_store": { - "advanced": false, - "display_name": "Add to Vector Store", - "dynamic": false, - "info": "If true, the Vector Store Inputs will be added to the Vector Store.", - "list": false, - "name": "add_to_vector_store", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "bool", - "value": true - }, - "api_endpoint": { - "advanced": false, - "display_name": "API Endpoint", - "dynamic": false, - "info": "API endpoint URL for the Astra DB service.", - "input_types": [], - "load_from_db": true, - "name": "api_endpoint", - "password": true, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "batch_size": { - "advanced": true, - "display_name": "Batch Size", - "dynamic": false, - "info": "Optional number of data to process in a single batch.", - "list": false, - "name": "batch_size", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": "" - }, - "bulk_delete_concurrency": { - "advanced": true, - "display_name": "Bulk Delete Concurrency", - "dynamic": false, - "info": "Optional concurrency level for bulk delete operations.", - "list": false, - "name": "bulk_delete_concurrency", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": "" - }, - "bulk_insert_batch_concurrency": { - "advanced": true, - "display_name": "Bulk Insert Batch Concurrency", - "dynamic": false, - "info": "Optional concurrency level for bulk insert operations.", - "list": false, - "name": "bulk_insert_batch_concurrency", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": "" - }, - "bulk_insert_overwrite_concurrency": { - "advanced": true, - "display_name": "Bulk Insert Overwrite Concurrency", - "dynamic": false, - "info": "Optional concurrency level for bulk insert operations that overwrite existing data.", - "list": false, - "name": "bulk_insert_overwrite_concurrency", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": "" - }, - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from loguru import logger\n\nfrom langflow.base.vectorstores.model import LCVectorStoreComponent\nfrom langflow.io import BoolInput, DropdownInput, HandleInput, IntInput, MultilineInput, SecretStrInput, StrInput\nfrom langflow.schema import Data\n\n\nclass AstraVectorStoreComponent(LCVectorStoreComponent):\n display_name: str = \"Astra DB Vector Store\"\n description: str = \"Implementation of Vector Store using Astra DB with search capabilities\"\n documentation: str = \"https://python.langchain.com/docs/integrations/vectorstores/astradb\"\n icon: str = \"AstraDB\"\n\n inputs = [\n StrInput(\n name=\"collection_name\",\n display_name=\"Collection Name\",\n info=\"The name of the collection within Astra DB where the vectors will be stored.\",\n ),\n SecretStrInput(\n name=\"token\",\n display_name=\"Astra DB Application Token\",\n info=\"Authentication token for accessing Astra DB.\",\n value=\"ASTRA_DB_APPLICATION_TOKEN\",\n ),\n SecretStrInput(\n name=\"api_endpoint\",\n display_name=\"API Endpoint\",\n info=\"API endpoint URL for the Astra DB service.\",\n value=\"ASTRA_DB_API_ENDPOINT\",\n ),\n HandleInput(\n name=\"vector_store_inputs\",\n display_name=\"Vector Store Inputs\",\n input_types=[\"Document\", \"Data\"],\n is_list=True,\n ),\n HandleInput(\n name=\"embedding\",\n display_name=\"Embedding\",\n input_types=[\"Embeddings\"],\n ),\n StrInput(\n name=\"namespace\",\n display_name=\"Namespace\",\n info=\"Optional namespace within Astra DB to use for the collection.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"metric\",\n display_name=\"Metric\",\n info=\"Optional distance metric for vector comparisons in the vector store.\",\n options=[\"cosine\", \"dot_product\", \"euclidean\"],\n advanced=True,\n ),\n IntInput(\n name=\"batch_size\",\n display_name=\"Batch Size\",\n info=\"Optional number of data to process in a single batch.\",\n advanced=True,\n ),\n IntInput(\n name=\"bulk_insert_batch_concurrency\",\n display_name=\"Bulk Insert Batch Concurrency\",\n info=\"Optional concurrency level for bulk insert operations.\",\n advanced=True,\n ),\n IntInput(\n name=\"bulk_insert_overwrite_concurrency\",\n display_name=\"Bulk Insert Overwrite Concurrency\",\n info=\"Optional concurrency level for bulk insert operations that overwrite existing data.\",\n advanced=True,\n ),\n IntInput(\n name=\"bulk_delete_concurrency\",\n display_name=\"Bulk Delete Concurrency\",\n info=\"Optional concurrency level for bulk delete operations.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"setup_mode\",\n display_name=\"Setup Mode\",\n info=\"Configuration mode for setting up the vector store, with options like 'Sync', 'Async', or 'Off'.\",\n options=[\"Sync\", \"Async\", \"Off\"],\n advanced=True,\n value=\"Sync\",\n ),\n BoolInput(\n name=\"pre_delete_collection\",\n display_name=\"Pre Delete Collection\",\n info=\"Boolean flag to determine whether to delete the collection before creating a new one.\",\n advanced=True,\n ),\n StrInput(\n name=\"metadata_indexing_include\",\n display_name=\"Metadata Indexing Include\",\n info=\"Optional list of metadata fields to include in the indexing.\",\n advanced=True,\n ),\n StrInput(\n name=\"metadata_indexing_exclude\",\n display_name=\"Metadata Indexing Exclude\",\n info=\"Optional list of metadata fields to exclude from the indexing.\",\n advanced=True,\n ),\n StrInput(\n name=\"collection_indexing_policy\",\n display_name=\"Collection Indexing Policy\",\n info=\"Optional dictionary defining the indexing policy for the collection.\",\n advanced=True,\n ),\n BoolInput(\n name=\"add_to_vector_store\",\n display_name=\"Add to Vector Store\",\n info=\"If true, the Vector Store Inputs will be added to the Vector Store.\",\n ),\n MultilineInput(\n name=\"search_input\",\n display_name=\"Search Input\",\n ),\n DropdownInput(\n name=\"search_type\",\n display_name=\"Search Type\",\n options=[\"Similarity\", \"MMR\"],\n value=\"Similarity\",\n ),\n IntInput(\n name=\"number_of_results\",\n display_name=\"Number of Results\",\n info=\"Number of results to return.\",\n advanced=True,\n value=4,\n ),\n ]\n\n def build_vector_store(self):\n try:\n from langchain_astradb import AstraDBVectorStore\n from langchain_astradb.utils.astradb import SetupMode\n except ImportError:\n raise ImportError(\n \"Could not import langchain Astra DB integration package. \"\n \"Please install it with `pip install langchain-astradb`.\"\n )\n\n try:\n if not self.setup_mode:\n self.setup_mode = self._inputs[\"setup_mode\"].options[0]\n\n setup_mode_value = SetupMode[self.setup_mode.upper()]\n except KeyError:\n raise ValueError(f\"Invalid setup mode: {self.setup_mode}\")\n\n vector_store_kwargs = {\n \"embedding\": self.embedding,\n \"collection_name\": self.collection_name,\n \"token\": self.token,\n \"api_endpoint\": self.api_endpoint,\n \"namespace\": self.namespace or None,\n \"metric\": self.metric or None,\n \"batch_size\": self.batch_size or None,\n \"bulk_insert_batch_concurrency\": self.bulk_insert_batch_concurrency or None,\n \"bulk_insert_overwrite_concurrency\": self.bulk_insert_overwrite_concurrency or None,\n \"bulk_delete_concurrency\": self.bulk_delete_concurrency or None,\n \"setup_mode\": setup_mode_value,\n \"pre_delete_collection\": self.pre_delete_collection or False,\n }\n\n if self.metadata_indexing_include:\n vector_store_kwargs[\"metadata_indexing_include\"] = self.metadata_indexing_include\n elif self.metadata_indexing_exclude:\n vector_store_kwargs[\"metadata_indexing_exclude\"] = self.metadata_indexing_exclude\n elif self.collection_indexing_policy:\n vector_store_kwargs[\"collection_indexing_policy\"] = self.collection_indexing_policy\n\n try:\n vector_store = AstraDBVectorStore(**vector_store_kwargs)\n except Exception as e:\n raise ValueError(f\"Error initializing AstraDBVectorStore: {str(e)}\") from e\n\n if self.add_to_vector_store:\n self._add_documents_to_vector_store(vector_store)\n\n return vector_store\n\n def build_base_retriever(self):\n vector_store = self.build_vector_store()\n self.status = self._astradb_collection_to_data(vector_store.collection)\n return vector_store\n\n def _add_documents_to_vector_store(self, vector_store):\n documents = []\n for _input in self.vector_store_inputs or []:\n if isinstance(_input, Data):\n documents.append(_input.to_lc_document())\n else:\n raise ValueError(\"Vector Store Inputs must be Data objects.\")\n\n if documents and self.embedding is not None:\n logger.debug(f\"Adding {len(documents)} documents to the Vector Store.\")\n try:\n vector_store.add_documents(documents)\n except Exception as e:\n raise ValueError(f\"Error adding documents to AstraDBVectorStore: {str(e)}\") from e\n else:\n logger.debug(\"No documents to add to the Vector Store.\")\n\n def search_documents(self):\n vector_store = self.build_vector_store()\n\n logger.debug(f\"Search input: {self.search_input}\")\n logger.debug(f\"Search type: {self.search_type}\")\n logger.debug(f\"Number of results: {self.number_of_results}\")\n\n if self.search_input and isinstance(self.search_input, str) and self.search_input.strip():\n try:\n if self.search_type == \"Similarity\":\n docs = vector_store.similarity_search(\n query=self.search_input,\n k=self.number_of_results,\n )\n elif self.search_type == \"MMR\":\n docs = vector_store.max_marginal_relevance_search(\n query=self.search_input,\n k=self.number_of_results,\n )\n else:\n raise ValueError(f\"Invalid search type: {self.search_type}\")\n except Exception as e:\n raise ValueError(f\"Error performing search in AstraDBVectorStore: {str(e)}\") from e\n\n logger.debug(f\"Retrieved documents: {len(docs)}\")\n\n data = [Data.from_document(doc) for doc in docs]\n logger.debug(f\"Converted documents to data: {len(data)}\")\n self.status = data\n return data\n else:\n logger.debug(\"No search input provided. Skipping search.\")\n return []\n\n def _astradb_collection_to_data(self, collection):\n data = []\n data_dict = collection.find()\n if data_dict and \"data\" in data_dict:\n data_dict = data_dict[\"data\"].get(\"documents\", [])\n\n for item in data_dict:\n data.append(Data(content=item[\"content\"]))\n return data\n" - }, - "collection_indexing_policy": { - "advanced": true, - "display_name": "Collection Indexing Policy", - "dynamic": false, - "info": "Optional dictionary defining the indexing policy for the collection.", - "list": false, - "load_from_db": false, - "name": "collection_indexing_policy", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "collection_name": { - "advanced": false, - "display_name": "Collection Name", - "dynamic": false, - "info": "The name of the collection within Astra DB where the vectors will be stored.", - "list": false, - "load_from_db": false, - "name": "collection_name", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "langflow" - }, - "embedding": { - "advanced": false, - "display_name": "Embedding", - "dynamic": false, - "info": "", - "input_types": [ - "Embeddings" - ], - "list": false, - "name": "embedding", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "other", - "value": "" - }, - "metadata_indexing_exclude": { - "advanced": true, - "display_name": "Metadata Indexing Exclude", - "dynamic": false, - "info": "Optional list of metadata fields to exclude from the indexing.", - "list": false, - "load_from_db": false, - "name": "metadata_indexing_exclude", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "metadata_indexing_include": { - "advanced": true, - "display_name": "Metadata Indexing Include", - "dynamic": false, - "info": "Optional list of metadata fields to include in the indexing.", - "list": false, - "load_from_db": false, - "name": "metadata_indexing_include", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "metric": { - "advanced": true, - "display_name": "Metric", - "dynamic": false, - "info": "Optional distance metric for vector comparisons in the vector store.", - "name": "metric", - "options": [ - "cosine", - "dot_product", - "euclidean" - ], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "namespace": { - "advanced": true, - "display_name": "Namespace", - "dynamic": false, - "info": "Optional namespace within Astra DB to use for the collection.", - "list": false, - "load_from_db": false, - "name": "namespace", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "number_of_results": { - "advanced": true, - "display_name": "Number of Results", - "dynamic": false, - "info": "Number of results to return.", - "list": false, - "name": "number_of_results", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": 4 - }, - "pre_delete_collection": { - "advanced": true, - "display_name": "Pre Delete Collection", - "dynamic": false, - "info": "Boolean flag to determine whether to delete the collection before creating a new one.", - "list": false, - "name": "pre_delete_collection", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "bool", - "value": false - }, - "search_input": { - "advanced": false, - "display_name": "Search Input", - "dynamic": false, - "info": "", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "search_input", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "search_type": { - "advanced": false, - "display_name": "Search Type", - "dynamic": false, - "info": "", - "name": "search_type", - "options": [ - "Similarity", - "MMR" - ], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "Similarity" - }, - "setup_mode": { - "advanced": true, - "display_name": "Setup Mode", - "dynamic": false, - "info": "Configuration mode for setting up the vector store, with options like 'Sync', 'Async', or 'Off'.", - "name": "setup_mode", - "options": [ - "Sync", - "Async", - "Off" - ], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "Sync" - }, - "token": { - "advanced": false, - "display_name": "Astra DB Application Token", - "dynamic": false, - "info": "Authentication token for accessing Astra DB.", - "input_types": [], - "load_from_db": true, - "name": "token", - "password": true, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "vector_store_inputs": { - "advanced": false, - "display_name": "Vector Store Inputs", - "dynamic": false, - "info": "", - "input_types": [ - "Document", - "Data" - ], - "list": true, - "name": "vector_store_inputs", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "other", - "value": "" - } - } - }, - "type": "AstraDB" - }, - "dragging": false, - "height": 917, - "id": "AstraDB-wANQu", + "id": "AstraDB-p6135", "position": { "x": 1298.4611042465333, "y": 160.7181472642742 @@ -2801,7 +1604,7 @@ }, { "data": { - "id": "ParseData-C9tUn", + "id": "ParseData-9DrmC", "node": { "base_classes": [ "Message" @@ -2824,14 +1627,14 @@ { "cache": true, "display_name": "Text", + "hidden": false, "method": "parse_data", "name": "text", "selected": "Message", "types": [ "Message" ], - "value": "__UNDEFINED__", - "hidden": false + "value": "__UNDEFINED__" } ], "pinned": false, @@ -2913,7 +1716,7 @@ }, "dragging": false, "height": 385, - "id": "ParseData-C9tUn", + "id": "ParseData-9DrmC", "position": { "x": 1911.4866480237615, "y": 566.903831987901 @@ -2925,156 +1728,1142 @@ "selected": false, "type": "genericNode", "width": 384 + }, + { + "data": { + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt", + "id": "Prompt-EEXgw", + "node": { + "base_classes": [ + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": { + "template": [ + "context", + "question" + ] + }, + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt", + "documentation": "", + "edited": false, + "error": null, + "field_order": [ + "template" + ], + "frozen": false, + "full_path": null, + "icon": "prompts", + "is_composition": null, + "is_input": null, + "is_output": null, + "name": "", + "output_types": [], + "outputs": [ + { + "cache": true, + "display_name": "Prompt Message", + "hidden": false, + "method": "build_prompt", + "name": "prompt", + "selected": "Message", + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "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.io import 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\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n prompt = await Message.from_template_and_variables(**self._attributes)\n self.status = prompt.text\n return prompt\n\n def post_code_processing(self, new_build_config: dict, current_build_config: dict):\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(new_build_config, current_build_config)\n template = frontend_node[\"template\"][\"template\"][\"value\"]\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_build_config\n # and update the frontend_node with those values\n update_template_values(frontend_template=frontend_node, raw_template=current_build_config[\"template\"])\n return frontend_node\n" + }, + "context": { + "advanced": false, + "display_name": "context", + "dynamic": false, + "field_type": "str", + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Message", + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "context", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "question": { + "advanced": false, + "display_name": "question", + "dynamic": false, + "field_type": "str", + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Message", + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "question", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "template": { + "advanced": false, + "display_name": "Template", + "dynamic": false, + "info": "", + "list": false, + "name": "template", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "type": "prompt", + "value": "{context}\n\n---\n\nGiven the context above, answer the question as best as possible.\n\nQuestion: {question}\n\nAnswer: " + } + } + }, + "type": "Prompt" + }, + "dragging": false, + "height": 517, + "id": "Prompt-EEXgw", + "position": { + "x": 2537.8054430938064, + "y": 442.35183727527414 + }, + "positionAbsolute": { + "x": 2537.8054430938064, + "y": 442.35183727527414 + }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { + "data": { + "id": "SplitText-qI0jS", + "node": { + "base_classes": [ + "Data" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Split text into chunks based on specified criteria.", + "display_name": "Split Text", + "documentation": "", + "edited": false, + "field_order": [ + "data_inputs", + "chunk_overlap", + "chunk_size", + "separator" + ], + "frozen": false, + "icon": "scissors-line-dashed", + "output_types": [], + "outputs": [ + { + "cache": true, + "display_name": "Chunks", + "hidden": false, + "method": "split_text", + "name": "chunks", + "selected": "Data", + "types": [ + "Data" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "chunk_overlap": { + "advanced": false, + "display_name": "Chunk Overlap", + "dynamic": false, + "info": "Number of characters to overlap between chunks.", + "list": false, + "name": "chunk_overlap", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "int", + "value": 200 + }, + "chunk_size": { + "advanced": false, + "display_name": "Chunk Size", + "dynamic": false, + "info": "The maximum number of characters in each chunk.", + "list": false, + "name": "chunk_size", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "int", + "value": 1000 + }, + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import List\n\nfrom langchain_text_splitters import CharacterTextSplitter\n\nfrom langflow.custom import Component\nfrom langflow.io import HandleInput, IntInput, MessageTextInput, Output\nfrom langflow.schema import Data\nfrom langflow.utils.util import unescape_string\n\n\nclass SplitTextComponent(Component):\n display_name: str = \"Split Text\"\n description: str = \"Split text into chunks based on specified criteria.\"\n icon = \"scissors-line-dashed\"\n\n inputs = [\n HandleInput(\n name=\"data_inputs\",\n display_name=\"Data Inputs\",\n info=\"The data to split.\",\n input_types=[\"Data\"],\n is_list=True,\n ),\n IntInput(\n name=\"chunk_overlap\",\n display_name=\"Chunk Overlap\",\n info=\"Number of characters to overlap between chunks.\",\n value=200,\n ),\n IntInput(\n name=\"chunk_size\",\n display_name=\"Chunk Size\",\n info=\"The maximum number of characters in each chunk.\",\n value=1000,\n ),\n MessageTextInput(\n name=\"separator\",\n display_name=\"Separator\",\n info=\"The character to split on. Defaults to newline.\",\n value=\"\\n\",\n ),\n ]\n\n outputs = [\n Output(display_name=\"Chunks\", name=\"chunks\", method=\"split_text\"),\n ]\n\n def _docs_to_data(self, docs):\n data = []\n for doc in docs:\n data.append(Data(text=doc.page_content, data=doc.metadata))\n return data\n\n def split_text(self) -> List[Data]:\n separator = unescape_string(self.separator)\n\n documents = []\n for _input in self.data_inputs:\n if isinstance(_input, Data):\n documents.append(_input.to_lc_document())\n\n splitter = CharacterTextSplitter(\n chunk_overlap=self.chunk_overlap,\n chunk_size=self.chunk_size,\n separator=separator,\n )\n docs = splitter.split_documents(documents)\n data = self._docs_to_data(docs)\n self.status = data\n return data\n" + }, + "data_inputs": { + "advanced": false, + "display_name": "Data Inputs", + "dynamic": false, + "info": "The data to split.", + "input_types": [ + "Data" + ], + "list": true, + "name": "data_inputs", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "other", + "value": "" + }, + "separator": { + "advanced": false, + "display_name": "Separator", + "dynamic": false, + "info": "The character to split on. Defaults to newline.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "name": "separator", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "\n" + } + } + }, + "type": "SplitText" + }, + "dragging": false, + "height": 557, + "id": "SplitText-qI0jS", + "position": { + "x": 1992.5159478772907, + "y": 1190.8288727494814 + }, + "positionAbsolute": { + "x": 1992.5159478772907, + "y": 1190.8288727494814 + }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { + "id": "AstraDB-AX2Xz", + "type": "genericNode", + "position": { + "x": 2773.0562333179937, + "y": 1160.0660495763536 + }, + "data": { + "description": "Implementation of Vector Store using Astra DB with search capabilities", + "display_name": "Astra DB Vector Store", + "id": "AstraDB-AX2Xz", + "node": { + "base_classes": [ + "Data" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Implementation of Vector Store using Astra DB with search capabilities", + "display_name": "Astra DB Vector Store", + "documentation": "https://python.langchain.com/docs/integrations/vectorstores/astradb", + "edited": false, + "field_order": [ + "collection_name", + "token", + "api_endpoint", + "vector_store_inputs", + "embedding", + "namespace", + "metric", + "batch_size", + "bulk_insert_batch_concurrency", + "bulk_insert_overwrite_concurrency", + "bulk_delete_concurrency", + "setup_mode", + "pre_delete_collection", + "metadata_indexing_include", + "metadata_indexing_exclude", + "collection_indexing_policy", + "add_to_vector_store", + "search_input", + "search_type", + "number_of_results" + ], + "frozen": false, + "icon": "AstraDB", + "output_types": [], + "outputs": [ + { + "cache": true, + "display_name": "Retriever", + "method": "build_base_retriever", + "name": "base_retriever", + "selected": "Data", + "types": [ + "Data" + ], + "value": "__UNDEFINED__" + }, + { + "cache": true, + "display_name": "Search Results", + "hidden": false, + "method": "search_documents", + "name": "search_results", + "selected": "Data", + "types": [ + "Data" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "add_to_vector_store": { + "advanced": false, + "display_name": "Add to Vector Store", + "dynamic": false, + "info": "If true, the Vector Store Inputs will be added to the Vector Store.", + "list": false, + "name": "add_to_vector_store", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "bool", + "value": true + }, + "api_endpoint": { + "advanced": false, + "display_name": "API Endpoint", + "dynamic": false, + "info": "API endpoint URL for the Astra DB service.", + "input_types": [], + "load_from_db": false, + "name": "api_endpoint", + "password": true, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "batch_size": { + "advanced": true, + "display_name": "Batch Size", + "dynamic": false, + "info": "Optional number of data to process in a single batch.", + "list": false, + "name": "batch_size", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": "" + }, + "bulk_delete_concurrency": { + "advanced": true, + "display_name": "Bulk Delete Concurrency", + "dynamic": false, + "info": "Optional concurrency level for bulk delete operations.", + "list": false, + "name": "bulk_delete_concurrency", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": "" + }, + "bulk_insert_batch_concurrency": { + "advanced": true, + "display_name": "Bulk Insert Batch Concurrency", + "dynamic": false, + "info": "Optional concurrency level for bulk insert operations.", + "list": false, + "name": "bulk_insert_batch_concurrency", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": "" + }, + "bulk_insert_overwrite_concurrency": { + "advanced": true, + "display_name": "Bulk Insert Overwrite Concurrency", + "dynamic": false, + "info": "Optional concurrency level for bulk insert operations that overwrite existing data.", + "list": false, + "name": "bulk_insert_overwrite_concurrency", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": "" + }, + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from loguru import logger\n\nfrom langflow.base.vectorstores.model import LCVectorStoreComponent\nfrom langflow.io import BoolInput, DropdownInput, HandleInput, IntInput, MultilineInput, SecretStrInput, StrInput\nfrom langflow.schema import Data\n\n\nclass AstraVectorStoreComponent(LCVectorStoreComponent):\n display_name: str = \"Astra DB Vector Store\"\n description: str = \"Implementation of Vector Store using Astra DB with search capabilities\"\n documentation: str = \"https://python.langchain.com/docs/integrations/vectorstores/astradb\"\n icon: str = \"AstraDB\"\n\n inputs = [\n StrInput(\n name=\"collection_name\",\n display_name=\"Collection Name\",\n info=\"The name of the collection within Astra DB where the vectors will be stored.\",\n ),\n SecretStrInput(\n name=\"token\",\n display_name=\"Astra DB Application Token\",\n info=\"Authentication token for accessing Astra DB.\",\n value=\"ASTRA_DB_APPLICATION_TOKEN\",\n ),\n SecretStrInput(\n name=\"api_endpoint\",\n display_name=\"API Endpoint\",\n info=\"API endpoint URL for the Astra DB service.\",\n value=\"ASTRA_DB_API_ENDPOINT\",\n ),\n HandleInput(\n name=\"vector_store_inputs\",\n display_name=\"Vector Store Inputs\",\n input_types=[\"Document\", \"Data\"],\n is_list=True,\n ),\n HandleInput(\n name=\"embedding\",\n display_name=\"Embedding\",\n input_types=[\"Embeddings\"],\n ),\n StrInput(\n name=\"namespace\",\n display_name=\"Namespace\",\n info=\"Optional namespace within Astra DB to use for the collection.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"metric\",\n display_name=\"Metric\",\n info=\"Optional distance metric for vector comparisons in the vector store.\",\n options=[\"cosine\", \"dot_product\", \"euclidean\"],\n advanced=True,\n ),\n IntInput(\n name=\"batch_size\",\n display_name=\"Batch Size\",\n info=\"Optional number of data to process in a single batch.\",\n advanced=True,\n ),\n IntInput(\n name=\"bulk_insert_batch_concurrency\",\n display_name=\"Bulk Insert Batch Concurrency\",\n info=\"Optional concurrency level for bulk insert operations.\",\n advanced=True,\n ),\n IntInput(\n name=\"bulk_insert_overwrite_concurrency\",\n display_name=\"Bulk Insert Overwrite Concurrency\",\n info=\"Optional concurrency level for bulk insert operations that overwrite existing data.\",\n advanced=True,\n ),\n IntInput(\n name=\"bulk_delete_concurrency\",\n display_name=\"Bulk Delete Concurrency\",\n info=\"Optional concurrency level for bulk delete operations.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"setup_mode\",\n display_name=\"Setup Mode\",\n info=\"Configuration mode for setting up the vector store, with options like 'Sync', 'Async', or 'Off'.\",\n options=[\"Sync\", \"Async\", \"Off\"],\n advanced=True,\n value=\"Sync\",\n ),\n BoolInput(\n name=\"pre_delete_collection\",\n display_name=\"Pre Delete Collection\",\n info=\"Boolean flag to determine whether to delete the collection before creating a new one.\",\n advanced=True,\n ),\n StrInput(\n name=\"metadata_indexing_include\",\n display_name=\"Metadata Indexing Include\",\n info=\"Optional list of metadata fields to include in the indexing.\",\n advanced=True,\n ),\n StrInput(\n name=\"metadata_indexing_exclude\",\n display_name=\"Metadata Indexing Exclude\",\n info=\"Optional list of metadata fields to exclude from the indexing.\",\n advanced=True,\n ),\n StrInput(\n name=\"collection_indexing_policy\",\n display_name=\"Collection Indexing Policy\",\n info=\"Optional dictionary defining the indexing policy for the collection.\",\n advanced=True,\n ),\n BoolInput(\n name=\"add_to_vector_store\",\n display_name=\"Add to Vector Store\",\n info=\"If true, the Vector Store Inputs will be added to the Vector Store.\",\n ),\n MultilineInput(\n name=\"search_input\",\n display_name=\"Search Input\",\n ),\n DropdownInput(\n name=\"search_type\",\n display_name=\"Search Type\",\n options=[\"Similarity\", \"MMR\"],\n value=\"Similarity\",\n ),\n IntInput(\n name=\"number_of_results\",\n display_name=\"Number of Results\",\n info=\"Number of results to return.\",\n advanced=True,\n value=4,\n ),\n ]\n\n def build_vector_store(self):\n try:\n from langchain_astradb import AstraDBVectorStore\n from langchain_astradb.utils.astradb import SetupMode\n except ImportError:\n raise ImportError(\n \"Could not import langchain Astra DB integration package. \"\n \"Please install it with `pip install langchain-astradb`.\"\n )\n\n try:\n if not self.setup_mode:\n self.setup_mode = self._inputs[\"setup_mode\"].options[0]\n\n setup_mode_value = SetupMode[self.setup_mode.upper()]\n except KeyError:\n raise ValueError(f\"Invalid setup mode: {self.setup_mode}\")\n\n vector_store_kwargs = {\n \"embedding\": self.embedding,\n \"collection_name\": self.collection_name,\n \"token\": self.token,\n \"api_endpoint\": self.api_endpoint,\n \"namespace\": self.namespace or None,\n \"metric\": self.metric or None,\n \"batch_size\": self.batch_size or None,\n \"bulk_insert_batch_concurrency\": self.bulk_insert_batch_concurrency or None,\n \"bulk_insert_overwrite_concurrency\": self.bulk_insert_overwrite_concurrency or None,\n \"bulk_delete_concurrency\": self.bulk_delete_concurrency or None,\n \"setup_mode\": setup_mode_value,\n \"pre_delete_collection\": self.pre_delete_collection or False,\n }\n\n if self.metadata_indexing_include:\n vector_store_kwargs[\"metadata_indexing_include\"] = self.metadata_indexing_include\n elif self.metadata_indexing_exclude:\n vector_store_kwargs[\"metadata_indexing_exclude\"] = self.metadata_indexing_exclude\n elif self.collection_indexing_policy:\n vector_store_kwargs[\"collection_indexing_policy\"] = self.collection_indexing_policy\n\n try:\n vector_store = AstraDBVectorStore(**vector_store_kwargs)\n except Exception as e:\n raise ValueError(f\"Error initializing AstraDBVectorStore: {str(e)}\") from e\n\n if self.add_to_vector_store:\n self._add_documents_to_vector_store(vector_store)\n\n return vector_store\n\n def build_base_retriever(self):\n vector_store = self.build_vector_store()\n self.status = self._astradb_collection_to_data(vector_store.collection)\n return vector_store\n\n def _add_documents_to_vector_store(self, vector_store):\n documents = []\n for _input in self.vector_store_inputs or []:\n if isinstance(_input, Data):\n documents.append(_input.to_lc_document())\n else:\n raise ValueError(\"Vector Store Inputs must be Data objects.\")\n\n if documents and self.embedding is not None:\n logger.debug(f\"Adding {len(documents)} documents to the Vector Store.\")\n try:\n vector_store.add_documents(documents)\n except Exception as e:\n raise ValueError(f\"Error adding documents to AstraDBVectorStore: {str(e)}\") from e\n else:\n logger.debug(\"No documents to add to the Vector Store.\")\n\n def search_documents(self):\n vector_store = self.build_vector_store()\n\n logger.debug(f\"Search input: {self.search_input}\")\n logger.debug(f\"Search type: {self.search_type}\")\n logger.debug(f\"Number of results: {self.number_of_results}\")\n\n if self.search_input and isinstance(self.search_input, str) and self.search_input.strip():\n try:\n if self.search_type == \"Similarity\":\n docs = vector_store.similarity_search(\n query=self.search_input,\n k=self.number_of_results,\n )\n elif self.search_type == \"MMR\":\n docs = vector_store.max_marginal_relevance_search(\n query=self.search_input,\n k=self.number_of_results,\n )\n else:\n raise ValueError(f\"Invalid search type: {self.search_type}\")\n except Exception as e:\n raise ValueError(f\"Error performing search in AstraDBVectorStore: {str(e)}\") from e\n\n logger.debug(f\"Retrieved documents: {len(docs)}\")\n\n data = [Data.from_document(doc) for doc in docs]\n logger.debug(f\"Converted documents to data: {len(data)}\")\n self.status = data\n return data\n else:\n logger.debug(\"No search input provided. Skipping search.\")\n return []\n\n def _astradb_collection_to_data(self, collection):\n data = []\n data_dict = collection.find()\n if data_dict and \"data\" in data_dict:\n data_dict = data_dict[\"data\"].get(\"documents\", [])\n\n for item in data_dict:\n data.append(Data(content=item[\"content\"]))\n return data\n" + }, + "collection_indexing_policy": { + "advanced": true, + "display_name": "Collection Indexing Policy", + "dynamic": false, + "info": "Optional dictionary defining the indexing policy for the collection.", + "list": false, + "load_from_db": false, + "name": "collection_indexing_policy", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "collection_name": { + "advanced": false, + "display_name": "Collection Name", + "dynamic": false, + "info": "The name of the collection within Astra DB where the vectors will be stored.", + "list": false, + "load_from_db": false, + "name": "collection_name", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "langflow" + }, + "embedding": { + "advanced": false, + "display_name": "Embedding", + "dynamic": false, + "info": "", + "input_types": [ + "Embeddings" + ], + "list": false, + "name": "embedding", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "other", + "value": "" + }, + "metadata_indexing_exclude": { + "advanced": true, + "display_name": "Metadata Indexing Exclude", + "dynamic": false, + "info": "Optional list of metadata fields to exclude from the indexing.", + "list": false, + "load_from_db": false, + "name": "metadata_indexing_exclude", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "metadata_indexing_include": { + "advanced": true, + "display_name": "Metadata Indexing Include", + "dynamic": false, + "info": "Optional list of metadata fields to include in the indexing.", + "list": false, + "load_from_db": false, + "name": "metadata_indexing_include", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "metric": { + "advanced": true, + "display_name": "Metric", + "dynamic": false, + "info": "Optional distance metric for vector comparisons in the vector store.", + "name": "metric", + "options": [ + "cosine", + "dot_product", + "euclidean" + ], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "namespace": { + "advanced": true, + "display_name": "Namespace", + "dynamic": false, + "info": "Optional namespace within Astra DB to use for the collection.", + "list": false, + "load_from_db": false, + "name": "namespace", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "number_of_results": { + "advanced": true, + "display_name": "Number of Results", + "dynamic": false, + "info": "Number of results to return.", + "list": false, + "name": "number_of_results", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": 4 + }, + "pre_delete_collection": { + "advanced": true, + "display_name": "Pre Delete Collection", + "dynamic": false, + "info": "Boolean flag to determine whether to delete the collection before creating a new one.", + "list": false, + "name": "pre_delete_collection", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "bool", + "value": false + }, + "search_input": { + "advanced": false, + "display_name": "Search Input", + "dynamic": false, + "info": "", + "input_types": [ + "Message", + "str" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "search_input", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "search_type": { + "advanced": false, + "display_name": "Search Type", + "dynamic": false, + "info": "", + "name": "search_type", + "options": [ + "Similarity", + "MMR" + ], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "Similarity" + }, + "setup_mode": { + "advanced": true, + "display_name": "Setup Mode", + "dynamic": false, + "info": "Configuration mode for setting up the vector store, with options like 'Sync', 'Async', or 'Off'.", + "name": "setup_mode", + "options": [ + "Sync", + "Async", + "Off" + ], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "Sync" + }, + "token": { + "advanced": false, + "display_name": "Astra DB Application Token", + "dynamic": false, + "info": "Authentication token for accessing Astra DB.", + "input_types": [], + "load_from_db": false, + "name": "token", + "password": true, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "vector_store_inputs": { + "advanced": false, + "display_name": "Vector Store Inputs", + "dynamic": false, + "info": "", + "input_types": [ + "Document", + "Data" + ], + "list": true, + "name": "vector_store_inputs", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "other", + "value": "" + } + } + }, + "type": "AstraDB" + }, + "selected": false, + "width": 384, + "height": 917, + "positionAbsolute": { + "x": 2773.0562333179937, + "y": 1160.0660495763536 + }, + "dragging": false + }, + { + "id": "OpenAIEmbeddings-PQc6x", + "type": "genericNode", + "position": { + "x": 1992.590633037642, + "y": 1850.2707576021312 + }, + "data": { + "id": "OpenAIEmbeddings-PQc6x", + "node": { + "base_classes": [ + "Embeddings" + ], + "beta": false, + "custom_fields": { + "allowed_special": null, + "chunk_size": null, + "client": null, + "default_headers": null, + "default_query": null, + "deployment": null, + "disallowed_special": null, + "embedding_ctx_length": null, + "max_retries": null, + "model": null, + "model_kwargs": null, + "openai_api_base": null, + "openai_api_key": null, + "openai_api_type": null, + "openai_api_version": null, + "openai_organization": null, + "openai_proxy": null, + "request_timeout": null, + "show_progress_bar": null, + "skip_empty": null, + "tiktoken_enable": null, + "tiktoken_model_name": null + }, + "description": "Generate embeddings using OpenAI models.", + "display_name": "OpenAI Embeddings", + "documentation": "", + "field_formatters": {}, + "field_order": [], + "frozen": false, + "icon": "OpenAI", + "output_types": [], + "outputs": [ + { + "cache": true, + "display_name": "Embeddings", + "hidden": false, + "method": "build_embeddings", + "name": "embeddings", + "selected": "Embeddings", + "types": [ + "Embeddings" + ], + "value": "__UNDEFINED__" + } + ], + "template": { + "_type": "Component", + "chunk_size": { + "advanced": true, + "display_name": "Chunk Size", + "dynamic": false, + "info": "", + "list": false, + "name": "chunk_size", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": 1000 + }, + "client": { + "advanced": true, + "display_name": "Client", + "dynamic": false, + "info": "", + "input_types": [ + "Message", + "str" + ], + "list": false, + "load_from_db": false, + "name": "client", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from langchain_openai.embeddings.base import OpenAIEmbeddings\n\nfrom langflow.base.embeddings.model import LCEmbeddingsModel\nfrom langflow.field_typing import Embeddings\nfrom langflow.io import BoolInput, DictInput, DropdownInput, FloatInput, IntInput, SecretStrInput, MessageTextInput\n\n\nclass OpenAIEmbeddingsComponent(LCEmbeddingsModel):\n display_name = \"OpenAI Embeddings\"\n description = \"Generate embeddings using OpenAI models.\"\n icon = \"OpenAI\"\n inputs = [\n DictInput(\n name=\"default_headers\",\n display_name=\"Default Headers\",\n advanced=True,\n info=\"Default headers to use for the API request.\",\n ),\n DictInput(\n name=\"default_query\",\n display_name=\"Default Query\",\n advanced=True,\n info=\"Default query parameters to use for the API request.\",\n ),\n IntInput(name=\"chunk_size\", display_name=\"Chunk Size\", advanced=True, value=1000),\n MessageTextInput(name=\"client\", display_name=\"Client\", advanced=True),\n MessageTextInput(name=\"deployment\", display_name=\"Deployment\", advanced=True),\n IntInput(name=\"embedding_ctx_length\", display_name=\"Embedding Context Length\", advanced=True, value=1536),\n IntInput(name=\"max_retries\", display_name=\"Max Retries\", value=3, advanced=True),\n DropdownInput(\n name=\"model\",\n display_name=\"Model\",\n advanced=False,\n options=[\n \"text-embedding-3-small\",\n \"text-embedding-3-large\",\n \"text-embedding-ada-002\",\n ],\n value=\"text-embedding-3-small\",\n ),\n DictInput(name=\"model_kwargs\", display_name=\"Model Kwargs\", advanced=True),\n SecretStrInput(name=\"openai_api_base\", display_name=\"OpenAI API Base\", advanced=True),\n SecretStrInput(name=\"openai_api_key\", display_name=\"OpenAI API Key\"),\n SecretStrInput(name=\"openai_api_type\", display_name=\"OpenAI API Type\", advanced=True),\n MessageTextInput(name=\"openai_api_version\", display_name=\"OpenAI API Version\", advanced=True),\n MessageTextInput(\n name=\"openai_organization\",\n display_name=\"OpenAI Organization\",\n advanced=True,\n ),\n MessageTextInput(name=\"openai_proxy\", display_name=\"OpenAI Proxy\", advanced=True),\n FloatInput(name=\"request_timeout\", display_name=\"Request Timeout\", advanced=True),\n BoolInput(name=\"show_progress_bar\", display_name=\"Show Progress Bar\", advanced=True),\n BoolInput(name=\"skip_empty\", display_name=\"Skip Empty\", advanced=True),\n MessageTextInput(\n name=\"tiktoken_model_name\",\n display_name=\"TikToken Model Name\",\n advanced=True,\n ),\n BoolInput(\n name=\"tiktoken_enable\",\n display_name=\"TikToken Enable\",\n advanced=True,\n value=True,\n info=\"If False, you must have transformers installed.\",\n ),\n ]\n\n def build_embeddings(self) -> Embeddings:\n return OpenAIEmbeddings(\n tiktoken_enabled=self.tiktoken_enable,\n default_headers=self.default_headers,\n default_query=self.default_query,\n allowed_special=\"all\",\n disallowed_special=\"all\",\n chunk_size=self.chunk_size,\n deployment=self.deployment,\n embedding_ctx_length=self.embedding_ctx_length,\n max_retries=self.max_retries,\n model=self.model,\n model_kwargs=self.model_kwargs,\n base_url=self.openai_api_base,\n api_key=self.openai_api_key,\n openai_api_type=self.openai_api_type,\n api_version=self.openai_api_version,\n organization=self.openai_organization,\n openai_proxy=self.openai_proxy,\n timeout=self.request_timeout or None,\n show_progress_bar=self.show_progress_bar,\n skip_empty=self.skip_empty,\n tiktoken_model_name=self.tiktoken_model_name,\n )\n" + }, + "default_headers": { + "advanced": true, + "display_name": "Default Headers", + "dynamic": false, + "info": "Default headers to use for the API request.", + "list": false, + "name": "default_headers", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "dict", + "value": {} + }, + "default_query": { + "advanced": true, + "display_name": "Default Query", + "dynamic": false, + "info": "Default query parameters to use for the API request.", + "list": false, + "name": "default_query", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "dict", + "value": {} + }, + "deployment": { + "advanced": true, + "display_name": "Deployment", + "dynamic": false, + "info": "", + "input_types": [ + "Message", + "str" + ], + "list": false, + "load_from_db": false, + "name": "deployment", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "embedding_ctx_length": { + "advanced": true, + "display_name": "Embedding Context Length", + "dynamic": false, + "info": "", + "list": false, + "name": "embedding_ctx_length", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": 1536 + }, + "max_retries": { + "advanced": true, + "display_name": "Max Retries", + "dynamic": false, + "info": "", + "list": false, + "name": "max_retries", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": 3 + }, + "model": { + "advanced": false, + "display_name": "Model", + "dynamic": false, + "info": "", + "name": "model", + "options": [ + "text-embedding-3-small", + "text-embedding-3-large", + "text-embedding-ada-002" + ], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "text-embedding-3-small" + }, + "model_kwargs": { + "advanced": true, + "display_name": "Model Kwargs", + "dynamic": false, + "info": "", + "list": false, + "name": "model_kwargs", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "dict", + "value": {} + }, + "openai_api_base": { + "advanced": true, + "display_name": "OpenAI API Base", + "dynamic": false, + "info": "", + "input_types": [], + "load_from_db": true, + "name": "openai_api_base", + "password": true, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "openai_api_key": { + "advanced": false, + "display_name": "OpenAI API Key", + "dynamic": false, + "info": "", + "input_types": [], + "load_from_db": false, + "name": "openai_api_key", + "password": true, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "openai_api_type": { + "advanced": true, + "display_name": "OpenAI API Type", + "dynamic": false, + "info": "", + "input_types": [], + "load_from_db": true, + "name": "openai_api_type", + "password": true, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "openai_api_version": { + "advanced": true, + "display_name": "OpenAI API Version", + "dynamic": false, + "info": "", + "input_types": [ + "Message", + "str" + ], + "list": false, + "load_from_db": false, + "name": "openai_api_version", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "openai_organization": { + "advanced": true, + "display_name": "OpenAI Organization", + "dynamic": false, + "info": "", + "input_types": [ + "Message", + "str" + ], + "list": false, + "load_from_db": false, + "name": "openai_organization", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "openai_proxy": { + "advanced": true, + "display_name": "OpenAI Proxy", + "dynamic": false, + "info": "", + "input_types": [ + "Message", + "str" + ], + "list": false, + "load_from_db": false, + "name": "openai_proxy", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "request_timeout": { + "advanced": true, + "display_name": "Request Timeout", + "dynamic": false, + "info": "", + "list": false, + "name": "request_timeout", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "float", + "value": "" + }, + "show_progress_bar": { + "advanced": true, + "display_name": "Show Progress Bar", + "dynamic": false, + "info": "", + "list": false, + "name": "show_progress_bar", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "bool", + "value": false + }, + "skip_empty": { + "advanced": true, + "display_name": "Skip Empty", + "dynamic": false, + "info": "", + "list": false, + "name": "skip_empty", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "bool", + "value": false + }, + "tiktoken_enable": { + "advanced": true, + "display_name": "TikToken Enable", + "dynamic": false, + "info": "If False, you must have transformers installed.", + "list": false, + "name": "tiktoken_enable", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "bool", + "value": true + }, + "tiktoken_model_name": { + "advanced": true, + "display_name": "TikToken Model Name", + "dynamic": false, + "info": "", + "input_types": [ + "Message", + "str" + ], + "list": false, + "load_from_db": false, + "name": "tiktoken_model_name", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + } + } + }, + "type": "OpenAIEmbeddings" + }, + "selected": true, + "width": 384, + "height": 395, + "positionAbsolute": { + "x": 1992.590633037642, + "y": 1850.2707576021312 + }, + "dragging": true } ], "edges": [ - { - "className": "", - "data": { - "sourceHandle": { - "dataType": "Prompt", - "id": "Prompt-jzPqb", - "name": "prompt", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-ickkA", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-Prompt-jzPqb{œdataTypeœ:œPromptœ,œidœ:œPrompt-jzPqbœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-ickkA{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-ickkAœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "Prompt-jzPqb", - "sourceHandle": "{œdataTypeœ:œPromptœ,œidœ:œPrompt-jzPqbœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}", - "style": { - "stroke": "#555" - }, - "target": "OpenAIModel-ickkA", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-ickkAœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}" - }, - { - "className": "", - "data": { - "sourceHandle": { - "dataType": "OpenAIModel", - "id": "OpenAIModel-ickkA", - "name": "text_output", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-Zy354", - "inputTypes": [ - "Message", - "str" - ], - "type": "str" - } - }, - "id": "reactflow__edge-OpenAIModel-ickkA{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-ickkAœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-Zy354{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-Zy354œ,œinputTypesœ:[œMessageœ,œstrœ],œtypeœ:œstrœ}", - "selected": false, - "source": "OpenAIModel-ickkA", - "sourceHandle": "{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-ickkAœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}", - "style": { - "stroke": "#555" - }, - "target": "ChatOutput-Zy354", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-Zy354œ,œinputTypesœ:[œMessageœ,œstrœ],œtypeœ:œstrœ}" - }, - { - "className": "", - "data": { - "sourceHandle": { - "dataType": "File", - "id": "File-28ckd", - "name": "data", - "output_types": [ - "Data" - ] - }, - "targetHandle": { - "fieldName": "data_input", - "id": "RecursiveCharacterTextSplitter-HVESL", - "inputTypes": [ - "Document", - "Data" - ], - "type": "other" - } - }, - "id": "reactflow__edge-File-28ckd{œdataTypeœ:œFileœ,œidœ:œFile-28ckdœ,œnameœ:œdataœ,œoutput_typesœ:[œDataœ]}-RecursiveCharacterTextSplitter-HVESL{œfieldNameœ:œdata_inputœ,œidœ:œRecursiveCharacterTextSplitter-HVESLœ,œinputTypesœ:[œDocumentœ,œDataœ],œtypeœ:œotherœ}", - "source": "File-28ckd", - "sourceHandle": "{œdataTypeœ:œFileœ,œidœ:œFile-28ckdœ,œnameœ:œdataœ,œoutput_typesœ:[œDataœ]}", - "target": "RecursiveCharacterTextSplitter-HVESL", - "targetHandle": "{œfieldNameœ:œdata_inputœ,œidœ:œRecursiveCharacterTextSplitter-HVESLœ,œinputTypesœ:[œDocumentœ,œDataœ],œtypeœ:œotherœ}" - }, - { - "className": "", - "data": { - "sourceHandle": { - "dataType": "RecursiveCharacterTextSplitter", - "id": "RecursiveCharacterTextSplitter-HVESL", - "name": "data", - "output_types": [ - "Data" - ] - }, - "targetHandle": { - "fieldName": "vector_store_inputs", - "id": "AstraDB-irvai", - "inputTypes": [ - "Document", - "Data" - ], - "type": "other" - } - }, - "id": "reactflow__edge-RecursiveCharacterTextSplitter-HVESL{œdataTypeœ:œRecursiveCharacterTextSplitterœ,œidœ:œRecursiveCharacterTextSplitter-HVESLœ,œnameœ:œdataœ,œoutput_typesœ:[œDataœ]}-AstraDB-irvai{œfieldNameœ:œvector_store_inputsœ,œidœ:œAstraDB-irvaiœ,œinputTypesœ:[œDocumentœ,œDataœ],œtypeœ:œotherœ}", - "source": "RecursiveCharacterTextSplitter-HVESL", - "sourceHandle": "{œdataTypeœ:œRecursiveCharacterTextSplitterœ,œidœ:œRecursiveCharacterTextSplitter-HVESLœ,œnameœ:œdataœ,œoutput_typesœ:[œDataœ]}", - "target": "AstraDB-irvai", - "targetHandle": "{œfieldNameœ:œvector_store_inputsœ,œidœ:œAstraDB-irvaiœ,œinputTypesœ:[œDocumentœ,œDataœ],œtypeœ:œotherœ}" - }, - { - "className": "", - "data": { - "sourceHandle": { - "dataType": "OpenAIEmbeddings", - "id": "OpenAIEmbeddings-YeYtt", - "name": "embeddings", - "output_types": [ - "Embeddings" - ] - }, - "targetHandle": { - "fieldName": "embedding", - "id": "AstraDB-irvai", - "inputTypes": [ - "Embeddings" - ], - "type": "other" - } - }, - "id": "reactflow__edge-OpenAIEmbeddings-YeYtt{œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-YeYttœ,œnameœ:œembeddingsœ,œoutput_typesœ:[œEmbeddingsœ]}-AstraDB-irvai{œfieldNameœ:œembeddingœ,œidœ:œAstraDB-irvaiœ,œinputTypesœ:[œEmbeddingsœ],œtypeœ:œotherœ}", - "source": "OpenAIEmbeddings-YeYtt", - "sourceHandle": "{œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-YeYttœ,œnameœ:œembeddingsœ,œoutput_typesœ:[œEmbeddingsœ]}", - "target": "AstraDB-irvai", - "targetHandle": "{œfieldNameœ:œembeddingœ,œidœ:œAstraDB-irvaiœ,œinputTypesœ:[œEmbeddingsœ],œtypeœ:œotherœ}" - }, { "className": "", "data": { "sourceHandle": { "dataType": "ChatInput", - "id": "ChatInput-IY8UK", + "id": "ChatInput-8ZRjI", "name": "message", "output_types": [ "Message" @@ -3082,7 +2871,7 @@ }, "targetHandle": { "fieldName": "search_input", - "id": "AstraDB-wANQu", + "id": "AstraDB-p6135", "inputTypes": [ "Message", "str" @@ -3090,19 +2879,19 @@ "type": "str" } }, - "id": "reactflow__edge-ChatInput-IY8UK{œdataTypeœ:œChatInputœ,œidœ:œChatInput-IY8UKœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-AstraDB-wANQu{œfieldNameœ:œsearch_inputœ,œidœ:œAstraDB-wANQuœ,œinputTypesœ:[œMessageœ,œstrœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-ChatInput-8ZRjI{œdataTypeœ:œChatInputœ,œidœ:œChatInput-8ZRjIœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-AstraDB-p6135{œfieldNameœ:œsearch_inputœ,œidœ:œAstraDB-p6135œ,œinputTypesœ:[œMessageœ,œstrœ],œtypeœ:œstrœ}", "selected": false, - "source": "ChatInput-IY8UK", - "sourceHandle": "{œdataTypeœ:œChatInputœ,œidœ:œChatInput-IY8UKœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}", - "target": "AstraDB-wANQu", - "targetHandle": "{œfieldNameœ:œsearch_inputœ,œidœ:œAstraDB-wANQuœ,œinputTypesœ:[œMessageœ,œstrœ],œtypeœ:œstrœ}" + "source": "ChatInput-8ZRjI", + "sourceHandle": "{œdataTypeœ:œChatInputœ,œidœ:œChatInput-8ZRjIœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}", + "target": "AstraDB-p6135", + "targetHandle": "{œfieldNameœ:œsearch_inputœ,œidœ:œAstraDB-p6135œ,œinputTypesœ:[œMessageœ,œstrœ],œtypeœ:œstrœ}" }, { "className": "", "data": { "sourceHandle": { "dataType": "OpenAIEmbeddings", - "id": "OpenAIEmbeddings-HoSp5", + "id": "OpenAIEmbeddings-hNOwh", "name": "embeddings", "output_types": [ "Embeddings" @@ -3110,26 +2899,26 @@ }, "targetHandle": { "fieldName": "embedding", - "id": "AstraDB-wANQu", + "id": "AstraDB-p6135", "inputTypes": [ "Embeddings" ], "type": "other" } }, - "id": "reactflow__edge-OpenAIEmbeddings-HoSp5{œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-HoSp5œ,œnameœ:œembeddingsœ,œoutput_typesœ:[œEmbeddingsœ]}-AstraDB-wANQu{œfieldNameœ:œembeddingœ,œidœ:œAstraDB-wANQuœ,œinputTypesœ:[œEmbeddingsœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-OpenAIEmbeddings-hNOwh{œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-hNOwhœ,œnameœ:œembeddingsœ,œoutput_typesœ:[œEmbeddingsœ]}-AstraDB-p6135{œfieldNameœ:œembeddingœ,œidœ:œAstraDB-p6135œ,œinputTypesœ:[œEmbeddingsœ],œtypeœ:œotherœ}", "selected": false, - "source": "OpenAIEmbeddings-HoSp5", - "sourceHandle": "{œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-HoSp5œ,œnameœ:œembeddingsœ,œoutput_typesœ:[œEmbeddingsœ]}", - "target": "AstraDB-wANQu", - "targetHandle": "{œfieldNameœ:œembeddingœ,œidœ:œAstraDB-wANQuœ,œinputTypesœ:[œEmbeddingsœ],œtypeœ:œotherœ}" + "source": "OpenAIEmbeddings-hNOwh", + "sourceHandle": "{œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-hNOwhœ,œnameœ:œembeddingsœ,œoutput_typesœ:[œEmbeddingsœ]}", + "target": "AstraDB-p6135", + "targetHandle": "{œfieldNameœ:œembeddingœ,œidœ:œAstraDB-p6135œ,œinputTypesœ:[œEmbeddingsœ],œtypeœ:œotherœ}" }, { "className": "", "data": { "sourceHandle": { "dataType": "AstraDB", - "id": "AstraDB-wANQu", + "id": "AstraDB-p6135", "name": "search_results", "output_types": [ "Data" @@ -3137,79 +2926,26 @@ }, "targetHandle": { "fieldName": "data", - "id": "ParseData-C9tUn", + "id": "ParseData-9DrmC", "inputTypes": [ "Data" ], "type": "other" } }, - "id": "reactflow__edge-AstraDB-wANQu{œdataTypeœ:œAstraDBœ,œidœ:œAstraDB-wANQuœ,œnameœ:œsearch_resultsœ,œoutput_typesœ:[œDataœ]}-ParseData-C9tUn{œfieldNameœ:œdataœ,œidœ:œParseData-C9tUnœ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-AstraDB-p6135{œdataTypeœ:œAstraDBœ,œidœ:œAstraDB-p6135œ,œnameœ:œsearch_resultsœ,œoutput_typesœ:[œDataœ]}-ParseData-9DrmC{œfieldNameœ:œdataœ,œidœ:œParseData-9DrmCœ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}", "selected": false, - "source": "AstraDB-wANQu", - "sourceHandle": "{œdataTypeœ:œAstraDBœ,œidœ:œAstraDB-wANQuœ,œnameœ:œsearch_resultsœ,œoutput_typesœ:[œDataœ]}", - "target": "ParseData-C9tUn", - "targetHandle": "{œfieldNameœ:œdataœ,œidœ:œParseData-C9tUnœ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}" - }, - { - "className": "", - "data": { - "sourceHandle": { - "dataType": "ParseData", - "id": "ParseData-C9tUn", - "name": "text", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "TextOutput-IxTee", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-ParseData-C9tUn{œdataTypeœ:œParseDataœ,œidœ:œParseData-C9tUnœ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-TextOutput-IxTee{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-IxTeeœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "source": "ParseData-C9tUn", - "sourceHandle": "{œdataTypeœ:œParseDataœ,œidœ:œParseData-C9tUnœ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}", - "target": "TextOutput-IxTee", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-IxTeeœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}" - }, - { - "className": "", - "data": { - "sourceHandle": { - "dataType": "TextOutput", - "id": "TextOutput-IxTee", - "name": "text", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "context", - "id": "Prompt-jzPqb", - "inputTypes": [ - "Message", - "Text" - ], - "type": "str" - } - }, - "id": "reactflow__edge-TextOutput-IxTee{œdataTypeœ:œTextOutputœ,œidœ:œTextOutput-IxTeeœ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-Prompt-jzPqb{œfieldNameœ:œcontextœ,œidœ:œPrompt-jzPqbœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", - "source": "TextOutput-IxTee", - "sourceHandle": "{œdataTypeœ:œTextOutputœ,œidœ:œTextOutput-IxTeeœ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}", - "target": "Prompt-jzPqb", - "targetHandle": "{œfieldNameœ:œcontextœ,œidœ:œPrompt-jzPqbœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}" + "source": "AstraDB-p6135", + "sourceHandle": "{œdataTypeœ:œAstraDBœ,œidœ:œAstraDB-p6135œ,œnameœ:œsearch_resultsœ,œoutput_typesœ:[œDataœ]}", + "target": "ParseData-9DrmC", + "targetHandle": "{œfieldNameœ:œdataœ,œidœ:œParseData-9DrmCœ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}" }, { "className": "", "data": { "sourceHandle": { "dataType": "ChatInput", - "id": "ChatInput-IY8UK", + "id": "ChatInput-8ZRjI", "name": "message", "output_types": [ "Message" @@ -3217,7 +2953,7 @@ }, "targetHandle": { "fieldName": "question", - "id": "Prompt-jzPqb", + "id": "Prompt-EEXgw", "inputTypes": [ "Message", "Text" @@ -3225,22 +2961,182 @@ "type": "str" } }, - "id": "reactflow__edge-ChatInput-IY8UK{œdataTypeœ:œChatInputœ,œidœ:œChatInput-IY8UKœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Prompt-jzPqb{œfieldNameœ:œquestionœ,œidœ:œPrompt-jzPqbœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", - "source": "ChatInput-IY8UK", - "sourceHandle": "{œdataTypeœ:œChatInputœ,œidœ:œChatInput-IY8UKœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}", - "target": "Prompt-jzPqb", - "targetHandle": "{œfieldNameœ:œquestionœ,œidœ:œPrompt-jzPqbœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}" + "id": "reactflow__edge-ChatInput-8ZRjI{œdataTypeœ:œChatInputœ,œidœ:œChatInput-8ZRjIœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Prompt-EEXgw{œfieldNameœ:œquestionœ,œidœ:œPrompt-EEXgwœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", + "source": "ChatInput-8ZRjI", + "sourceHandle": "{œdataTypeœ:œChatInputœ,œidœ:œChatInput-8ZRjIœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}", + "target": "Prompt-EEXgw", + "targetHandle": "{œfieldNameœ:œquestionœ,œidœ:œPrompt-EEXgwœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}" + }, + { + "className": "", + "data": { + "sourceHandle": { + "dataType": "File", + "id": "File-p2YBf", + "name": "data", + "output_types": [ + "Data" + ] + }, + "targetHandle": { + "fieldName": "data_inputs", + "id": "SplitText-qI0jS", + "inputTypes": [ + "Data" + ], + "type": "other" + } + }, + "id": "reactflow__edge-File-p2YBf{œdataTypeœ:œFileœ,œidœ:œFile-p2YBfœ,œnameœ:œdataœ,œoutput_typesœ:[œDataœ]}-SplitText-qI0jS{œfieldNameœ:œdata_inputsœ,œidœ:œSplitText-qI0jSœ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}", + "source": "File-p2YBf", + "sourceHandle": "{œdataTypeœ:œFileœ,œidœ:œFile-p2YBfœ,œnameœ:œdataœ,œoutput_typesœ:[œDataœ]}", + "target": "SplitText-qI0jS", + "targetHandle": "{œfieldNameœ:œdata_inputsœ,œidœ:œSplitText-qI0jSœ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}", + "selected": false + }, + { + "className": "", + "data": { + "sourceHandle": { + "dataType": "ParseData", + "id": "ParseData-9DrmC", + "name": "text", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "context", + "id": "Prompt-EEXgw", + "inputTypes": [ + "Message", + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-ParseData-9DrmC{œdataTypeœ:œParseDataœ,œidœ:œParseData-9DrmCœ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-Prompt-EEXgw{œfieldNameœ:œcontextœ,œidœ:œPrompt-EEXgwœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", + "source": "ParseData-9DrmC", + "sourceHandle": "{œdataTypeœ:œParseDataœ,œidœ:œParseData-9DrmCœ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}", + "target": "Prompt-EEXgw", + "targetHandle": "{œfieldNameœ:œcontextœ,œidœ:œPrompt-EEXgwœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}" + }, + { + "className": "", + "data": { + "sourceHandle": { + "dataType": "Prompt", + "id": "Prompt-EEXgw", + "name": "prompt", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "OpenAIModel-euVNy", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "reactflow__edge-Prompt-EEXgw{œdataTypeœ:œPromptœ,œidœ:œPrompt-EEXgwœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-euVNy{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-euVNyœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "source": "Prompt-EEXgw", + "sourceHandle": "{œdataTypeœ:œPromptœ,œidœ:œPrompt-EEXgwœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}", + "target": "OpenAIModel-euVNy", + "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-euVNyœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}" + }, + { + "className": "", + "data": { + "sourceHandle": { + "dataType": "OpenAIModel", + "id": "OpenAIModel-euVNy", + "name": "text_output", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-1eddV", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "reactflow__edge-OpenAIModel-euVNy{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-euVNyœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-1eddV{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-1eddVœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "source": "OpenAIModel-euVNy", + "sourceHandle": "{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-euVNyœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}", + "target": "ChatOutput-1eddV", + "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-1eddVœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}" + }, + { + "className": "", + "data": { + "sourceHandle": { + "dataType": "SplitText", + "id": "SplitText-qI0jS", + "name": "chunks", + "output_types": [ + "Data" + ] + }, + "targetHandle": { + "fieldName": "vector_store_inputs", + "id": "AstraDB-AX2Xz", + "inputTypes": [ + "Document", + "Data" + ], + "type": "other" + } + }, + "source": "SplitText-qI0jS", + "sourceHandle": "{œdataTypeœ:œSplitTextœ,œidœ:œSplitText-qI0jSœ,œnameœ:œchunksœ,œoutput_typesœ:[œDataœ]}", + "target": "AstraDB-AX2Xz", + "targetHandle": "{œfieldNameœ:œvector_store_inputsœ,œidœ:œAstraDB-AX2Xzœ,œinputTypesœ:[œDocumentœ,œDataœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-SplitText-qI0jS{œdataTypeœ:œSplitTextœ,œidœ:œSplitText-qI0jSœ,œnameœ:œchunksœ,œoutput_typesœ:[œDataœ]}-AstraDB-AX2Xz{œfieldNameœ:œvector_store_inputsœ,œidœ:œAstraDB-AX2Xzœ,œinputTypesœ:[œDocumentœ,œDataœ],œtypeœ:œotherœ}", + "selected": false + }, + { + "source": "OpenAIEmbeddings-PQc6x", + "sourceHandle": "{œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-PQc6xœ,œnameœ:œembeddingsœ,œoutput_typesœ:[œEmbeddingsœ]}", + "target": "AstraDB-AX2Xz", + "targetHandle": "{œfieldNameœ:œembeddingœ,œidœ:œAstraDB-AX2Xzœ,œinputTypesœ:[œEmbeddingsœ],œtypeœ:œotherœ}", + "data": { + "targetHandle": { + "fieldName": "embedding", + "id": "AstraDB-AX2Xz", + "inputTypes": [ + "Embeddings" + ], + "type": "other" + }, + "sourceHandle": { + "dataType": "OpenAIEmbeddings", + "id": "OpenAIEmbeddings-PQc6x", + "name": "embeddings", + "output_types": [ + "Embeddings" + ] + } + }, + "id": "reactflow__edge-OpenAIEmbeddings-PQc6x{œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-PQc6xœ,œnameœ:œembeddingsœ,œoutput_typesœ:[œEmbeddingsœ]}-AstraDB-AX2Xz{œfieldNameœ:œembeddingœ,œidœ:œAstraDB-AX2Xzœ,œinputTypesœ:[œEmbeddingsœ],œtypeœ:œotherœ}", + "selected": false } ], "viewport": { - "x": -124.92057698887993, - "y": 126.80996053902413, - "zoom": 0.370642160653555 + "x": -173.2239134973895, + "y": 90.45548562382544, + "zoom": 0.32281188532359306 } }, - "description": "Visit https://pre-release.langflow.org/tutorials/rag-with-astradb for a detailed guide of this project.\nThis project give you both Ingestion and RAG in a single file. You'll need to visit https://astra.datastax.com/ to create an Astra DB instance, your Token and grab an API Endpoint.\nRunning this project requires you to add a file in the Files component, then define a Collection Name and click on the Play icon on the Astra DB component. \n\nAfter the ingestion ends you are ready to click on the Run button at the lower left corner and start asking questions about your data.", + "description": "Visit https://docs.langflow.org/tutorials/rag-with-astradb for a detailed guide of this project.\nThis project give you both Ingestion and RAG in a single file. You'll need to visit https://astra.datastax.com/ to create an Astra DB instance, your Token and grab an API Endpoint.\nRunning this project requires you to add a file in the Files component, then define a Collection Name and click on the Play icon on the Astra DB component. \n\nAfter the ingestion ends you are ready to click on the Run button at the lower left corner and start asking questions about your data.", "name": "Vector Store RAG", - "last_tested_version": "1.0.0a61", + "last_tested_version": "1.0.0rc1", "endpoint_name": null, "is_component": false } \ No newline at end of file diff --git a/docs/static/img/basic-prompting.png b/docs/static/img/basic-prompting.png index 76d658a2d..b56696f44 100644 Binary files a/docs/static/img/basic-prompting.png and b/docs/static/img/basic-prompting.png differ diff --git a/docs/static/img/chat-memory-component.png b/docs/static/img/chat-memory-component.png new file mode 100644 index 000000000..3c9c7c92d Binary files /dev/null and b/docs/static/img/chat-memory-component.png differ diff --git a/docs/static/img/component-freeze.jpeg b/docs/static/img/component-freeze.jpeg new file mode 100644 index 000000000..d06b8000b Binary files /dev/null and b/docs/static/img/component-freeze.jpeg differ diff --git a/docs/static/img/component-menu.png b/docs/static/img/component-menu.png new file mode 100644 index 000000000..350e5dfbf Binary files /dev/null and b/docs/static/img/component-menu.png differ diff --git a/docs/static/img/component-update.png b/docs/static/img/component-update.png new file mode 100644 index 000000000..88ba32d2c Binary files /dev/null and b/docs/static/img/component-update.png differ diff --git a/docs/static/img/custom-endpoint.webp b/docs/static/img/custom-endpoint.webp new file mode 100644 index 000000000..f6b1a88ed Binary files /dev/null and b/docs/static/img/custom-endpoint.webp differ diff --git a/docs/static/img/flow-composition.webp b/docs/static/img/flow-composition.webp new file mode 100644 index 000000000..f3075512d Binary files /dev/null and b/docs/static/img/flow-composition.webp differ diff --git a/docs/static/img/inspect-output.png b/docs/static/img/inspect-output.png new file mode 100644 index 000000000..14418f74c Binary files /dev/null and b/docs/static/img/inspect-output.png differ diff --git a/docs/static/img/langflow-1-0.png b/docs/static/img/langflow-1-0.png new file mode 100644 index 000000000..54779b853 Binary files /dev/null and b/docs/static/img/langflow-1-0.png differ diff --git a/docs/static/img/langsmith-flow.png b/docs/static/img/langsmith-flow.png new file mode 100644 index 000000000..c7e44edd5 Binary files /dev/null and b/docs/static/img/langsmith-flow.png differ diff --git a/docs/static/img/langsmith-trace.png b/docs/static/img/langsmith-trace.png new file mode 100644 index 000000000..47e007a78 Binary files /dev/null and b/docs/static/img/langsmith-trace.png differ diff --git a/docs/static/img/logs-monitoring.webp b/docs/static/img/logs-monitoring.webp new file mode 100644 index 000000000..02b6877d4 Binary files /dev/null and b/docs/static/img/logs-monitoring.webp differ diff --git a/docs/static/img/menu-options.png b/docs/static/img/menu-options.png new file mode 100644 index 000000000..ecfc13332 Binary files /dev/null and b/docs/static/img/menu-options.png differ diff --git a/docs/static/img/multi-modal.png b/docs/static/img/multi-modal.png new file mode 100644 index 000000000..1b42c3d47 Binary files /dev/null and b/docs/static/img/multi-modal.png differ diff --git a/docs/static/img/multiple_outputs.webp b/docs/static/img/multiple_outputs.webp new file mode 100644 index 000000000..72c71f96c Binary files /dev/null and b/docs/static/img/multiple_outputs.webp differ diff --git a/docs/static/img/my-collection.png b/docs/static/img/my-collection.png new file mode 100644 index 000000000..201b22a87 Binary files /dev/null and b/docs/static/img/my-collection.png differ diff --git a/docs/static/img/output-preview.gif b/docs/static/img/output-preview.gif new file mode 100644 index 000000000..b200ffba7 Binary files /dev/null and b/docs/static/img/output-preview.gif differ diff --git a/docs/static/img/playground-logs.png b/docs/static/img/playground-logs.png new file mode 100644 index 000000000..3345deb97 Binary files /dev/null and b/docs/static/img/playground-logs.png differ diff --git a/docs/static/img/playground-memories.png b/docs/static/img/playground-memories.png new file mode 100644 index 000000000..90fc00cae Binary files /dev/null and b/docs/static/img/playground-memories.png differ diff --git a/docs/static/img/playground.png b/docs/static/img/playground.png new file mode 100644 index 000000000..a1ae092ff Binary files /dev/null and b/docs/static/img/playground.png differ diff --git a/docs/static/img/single-component.png b/docs/static/img/single-component.png new file mode 100644 index 000000000..cdfe8bc46 Binary files /dev/null and b/docs/static/img/single-component.png differ diff --git a/docs/static/img/topnav.png b/docs/static/img/topnav.png new file mode 100644 index 000000000..c129156c1 Binary files /dev/null and b/docs/static/img/topnav.png differ diff --git a/docs/static/img/welcome-to-langflow.png b/docs/static/img/welcome-to-langflow.png new file mode 100644 index 000000000..b4903e7da Binary files /dev/null and b/docs/static/img/welcome-to-langflow.png differ diff --git a/poetry.lock b/poetry.lock index 3c816a29a..411b285a4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -123,13 +123,13 @@ frozenlist = ">=1.1.0" [[package]] name = "alembic" -version = "1.13.1" +version = "1.13.2" description = "A database migration tool for SQLAlchemy." optional = false python-versions = ">=3.8" files = [ - {file = "alembic-1.13.1-py3-none-any.whl", hash = "sha256:2edcc97bed0bd3272611ce3a98d98279e9c209e7186e43e75bbb1b2bdfdbcc43"}, - {file = "alembic-1.13.1.tar.gz", hash = "sha256:4932c8558bf68f2ee92b9bbcb8218671c627064d5b08939437af6d77dc05e595"}, + {file = "alembic-1.13.2-py3-none-any.whl", hash = "sha256:6b8733129a6224a9a711e17c99b08462dbf7cc9670ba8f2e2ae9af860ceb1953"}, + {file = "alembic-1.13.2.tar.gz", hash = "sha256:1ff0ae32975f4fd96028c39ed9bb3c867fe3af956bd7bb37343b54c9fe7445ef"}, ] [package.dependencies] @@ -167,13 +167,13 @@ files = [ [[package]] name = "anthropic" -version = "0.29.0" +version = "0.30.0" description = "The official Python library for the anthropic API" optional = false python-versions = ">=3.7" files = [ - {file = "anthropic-0.29.0-py3-none-any.whl", hash = "sha256:d16010715129c8bc3295b74fbf4da73cfb156618bf0abb2d007255983266b76a"}, - {file = "anthropic-0.29.0.tar.gz", hash = "sha256:3eb558a232d83bdf7cdedb75663bf7ff7a8b50cc10acaa9ce6494ff295b8506a"}, + {file = "anthropic-0.30.0-py3-none-any.whl", hash = "sha256:061bf58c9c64968361e6c21c76ff5016a6f7fdd9a5f6b7f2280ede2c3b44bfd5"}, + {file = "anthropic-0.30.0.tar.gz", hash = "sha256:9e9ee2bfce833370eac74d7de433db97a0bf141f9118c40ac0e2f4c39bc2b76f"}, ] [package.dependencies] @@ -368,13 +368,13 @@ files = [ [[package]] name = "bce-python-sdk" -version = "0.9.14" +version = "0.9.17" description = "BCE SDK for python" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,<4,>=2.7" files = [ - {file = "bce_python_sdk-0.9.14-py3-none-any.whl", hash = "sha256:5704aa454151ee608b01ddda7531457433f9b4bb8afbd00706dd368f3b4339a1"}, - {file = "bce_python_sdk-0.9.14.tar.gz", hash = "sha256:7cbd182ec1e21034f10d3cdb812f3171d31908f1a783d6cf643039272942d8e8"}, + {file = "bce_python_sdk-0.9.17-py3-none-any.whl", hash = "sha256:6c5995d60edad3f6771b83ccd79197fc00d88081e3175ca8eecad8a29551ad75"}, + {file = "bce_python_sdk-0.9.17.tar.gz", hash = "sha256:aaece4c590b859ad6bc2d6a04b4a01308ac781ef1d539116b299ec50d62e1ca1"}, ] [package.dependencies] @@ -461,17 +461,17 @@ files = [ [[package]] name = "boto3" -version = "1.34.131" +version = "1.34.133" description = "The AWS SDK for Python" optional = false python-versions = ">=3.8" files = [ - {file = "boto3-1.34.131-py3-none-any.whl", hash = "sha256:05e388cb937e82be70bfd7eb0c84cf8011ff35cf582a593873ac21675268683b"}, - {file = "boto3-1.34.131.tar.gz", hash = "sha256:dab8f72a6c4e62b4fd70da09e08a6b2a65ea2115b27dd63737142005776ef216"}, + {file = "boto3-1.34.133-py3-none-any.whl", hash = "sha256:da7e78c03270be872ad78301892396ffea56647efcb2c3a8621ef46a905541ab"}, + {file = "boto3-1.34.133.tar.gz", hash = "sha256:7071f8ce1f09113ca5630860fd590464e6325a4df55faae83c956225941016fc"}, ] [package.dependencies] -botocore = ">=1.34.131,<1.35.0" +botocore = ">=1.34.133,<1.35.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.10.0,<0.11.0" @@ -480,13 +480,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.34.131" +version = "1.34.133" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.8" files = [ - {file = "botocore-1.34.131-py3-none-any.whl", hash = "sha256:13b011d7b206ce00727dcee26548fa3b550db9046d5a0e90ac25a6e6c8fde6ef"}, - {file = "botocore-1.34.131.tar.gz", hash = "sha256:502ddafe1d627fcf1e4c007c86454e5dd011dba7c58bd8e8a5368a79f3e387dc"}, + {file = "botocore-1.34.133-py3-none-any.whl", hash = "sha256:f269dad8e17432d2527b97ed9f1fd30ec8dc705f8b818957170d1af484680ef2"}, + {file = "botocore-1.34.133.tar.gz", hash = "sha256:5ea609aa4831a6589e32eef052a359ad8d7311733b4d86a9d35dab4bd3ec80ff"}, ] [package.dependencies] @@ -1501,33 +1501,33 @@ vision = ["Pillow (>=6.2.1)"] [[package]] name = "debugpy" -version = "1.8.1" +version = "1.8.2" description = "An implementation of the Debug Adapter Protocol for Python" optional = false python-versions = ">=3.8" files = [ - {file = "debugpy-1.8.1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:3bda0f1e943d386cc7a0e71bfa59f4137909e2ed947fb3946c506e113000f741"}, - {file = "debugpy-1.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dda73bf69ea479c8577a0448f8c707691152e6c4de7f0c4dec5a4bc11dee516e"}, - {file = "debugpy-1.8.1-cp310-cp310-win32.whl", hash = "sha256:3a79c6f62adef994b2dbe9fc2cc9cc3864a23575b6e387339ab739873bea53d0"}, - {file = "debugpy-1.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:7eb7bd2b56ea3bedb009616d9e2f64aab8fc7000d481faec3cd26c98a964bcdd"}, - {file = "debugpy-1.8.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:016a9fcfc2c6b57f939673c874310d8581d51a0fe0858e7fac4e240c5eb743cb"}, - {file = "debugpy-1.8.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd97ed11a4c7f6d042d320ce03d83b20c3fb40da892f994bc041bbc415d7a099"}, - {file = "debugpy-1.8.1-cp311-cp311-win32.whl", hash = "sha256:0de56aba8249c28a300bdb0672a9b94785074eb82eb672db66c8144fff673146"}, - {file = "debugpy-1.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:1a9fe0829c2b854757b4fd0a338d93bc17249a3bf69ecf765c61d4c522bb92a8"}, - {file = "debugpy-1.8.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3ebb70ba1a6524d19fa7bb122f44b74170c447d5746a503e36adc244a20ac539"}, - {file = "debugpy-1.8.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2e658a9630f27534e63922ebf655a6ab60c370f4d2fc5c02a5b19baf4410ace"}, - {file = "debugpy-1.8.1-cp312-cp312-win32.whl", hash = "sha256:caad2846e21188797a1f17fc09c31b84c7c3c23baf2516fed5b40b378515bbf0"}, - {file = "debugpy-1.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:edcc9f58ec0fd121a25bc950d4578df47428d72e1a0d66c07403b04eb93bcf98"}, - {file = "debugpy-1.8.1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:7a3afa222f6fd3d9dfecd52729bc2e12c93e22a7491405a0ecbf9e1d32d45b39"}, - {file = "debugpy-1.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d915a18f0597ef685e88bb35e5d7ab968964b7befefe1aaea1eb5b2640b586c7"}, - {file = "debugpy-1.8.1-cp38-cp38-win32.whl", hash = "sha256:92116039b5500633cc8d44ecc187abe2dfa9b90f7a82bbf81d079fcdd506bae9"}, - {file = "debugpy-1.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:e38beb7992b5afd9d5244e96ad5fa9135e94993b0c551ceebf3fe1a5d9beb234"}, - {file = "debugpy-1.8.1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:bfb20cb57486c8e4793d41996652e5a6a885b4d9175dd369045dad59eaacea42"}, - {file = "debugpy-1.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efd3fdd3f67a7e576dd869c184c5dd71d9aaa36ded271939da352880c012e703"}, - {file = "debugpy-1.8.1-cp39-cp39-win32.whl", hash = "sha256:58911e8521ca0c785ac7a0539f1e77e0ce2df753f786188f382229278b4cdf23"}, - {file = "debugpy-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:6df9aa9599eb05ca179fb0b810282255202a66835c6efb1d112d21ecb830ddd3"}, - {file = "debugpy-1.8.1-py2.py3-none-any.whl", hash = "sha256:28acbe2241222b87e255260c76741e1fbf04fdc3b6d094fcf57b6c6f75ce1242"}, - {file = "debugpy-1.8.1.zip", hash = "sha256:f696d6be15be87aef621917585f9bb94b1dc9e8aced570db1b8a6fc14e8f9b42"}, + {file = "debugpy-1.8.2-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:7ee2e1afbf44b138c005e4380097d92532e1001580853a7cb40ed84e0ef1c3d2"}, + {file = "debugpy-1.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f8c3f7c53130a070f0fc845a0f2cee8ed88d220d6b04595897b66605df1edd6"}, + {file = "debugpy-1.8.2-cp310-cp310-win32.whl", hash = "sha256:f179af1e1bd4c88b0b9f0fa153569b24f6b6f3de33f94703336363ae62f4bf47"}, + {file = "debugpy-1.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:0600faef1d0b8d0e85c816b8bb0cb90ed94fc611f308d5fde28cb8b3d2ff0fe3"}, + {file = "debugpy-1.8.2-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:8a13417ccd5978a642e91fb79b871baded925d4fadd4dfafec1928196292aa0a"}, + {file = "debugpy-1.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acdf39855f65c48ac9667b2801234fc64d46778021efac2de7e50907ab90c634"}, + {file = "debugpy-1.8.2-cp311-cp311-win32.whl", hash = "sha256:2cbd4d9a2fc5e7f583ff9bf11f3b7d78dfda8401e8bb6856ad1ed190be4281ad"}, + {file = "debugpy-1.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:d3408fddd76414034c02880e891ea434e9a9cf3a69842098ef92f6e809d09afa"}, + {file = "debugpy-1.8.2-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:5d3ccd39e4021f2eb86b8d748a96c766058b39443c1f18b2dc52c10ac2757835"}, + {file = "debugpy-1.8.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62658aefe289598680193ff655ff3940e2a601765259b123dc7f89c0239b8cd3"}, + {file = "debugpy-1.8.2-cp312-cp312-win32.whl", hash = "sha256:bd11fe35d6fd3431f1546d94121322c0ac572e1bfb1f6be0e9b8655fb4ea941e"}, + {file = "debugpy-1.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:15bc2f4b0f5e99bf86c162c91a74c0631dbd9cef3c6a1d1329c946586255e859"}, + {file = "debugpy-1.8.2-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:5a019d4574afedc6ead1daa22736c530712465c0c4cd44f820d803d937531b2d"}, + {file = "debugpy-1.8.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40f062d6877d2e45b112c0bbade9a17aac507445fd638922b1a5434df34aed02"}, + {file = "debugpy-1.8.2-cp38-cp38-win32.whl", hash = "sha256:c78ba1680f1015c0ca7115671fe347b28b446081dada3fedf54138f44e4ba031"}, + {file = "debugpy-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:cf327316ae0c0e7dd81eb92d24ba8b5e88bb4d1b585b5c0d32929274a66a5210"}, + {file = "debugpy-1.8.2-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:1523bc551e28e15147815d1397afc150ac99dbd3a8e64641d53425dba57b0ff9"}, + {file = "debugpy-1.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e24ccb0cd6f8bfaec68d577cb49e9c680621c336f347479b3fce060ba7c09ec1"}, + {file = "debugpy-1.8.2-cp39-cp39-win32.whl", hash = "sha256:7f8d57a98c5a486c5c7824bc0b9f2f11189d08d73635c326abef268f83950326"}, + {file = "debugpy-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:16c8dcab02617b75697a0a925a62943e26a0330da076e2a10437edd9f0bf3755"}, + {file = "debugpy-1.8.2-py2.py3-none-any.whl", hash = "sha256:16e16df3a98a35c63c3ab1e4d19be4cbc7fdda92d9ddc059294f18910928e0ca"}, + {file = "debugpy-1.8.2.zip", hash = "sha256:95378ed08ed2089221896b9b3a8d021e642c24edc8fef20e5d4342ca8be65c00"}, ] [[package]] @@ -1952,41 +1952,37 @@ tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipyth [[package]] name = "faiss-cpu" -version = "1.8.0" +version = "1.8.0.post1" description = "A library for efficient similarity search and clustering of dense vectors." optional = false python-versions = ">=3.8" files = [ - {file = "faiss-cpu-1.8.0.tar.gz", hash = "sha256:3ee1549491728f37b65267c192a94661a907154a8ae0546ad50a564b8be0d82e"}, - {file = "faiss_cpu-1.8.0-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:134a064c7411acf7d1d863173a9d2605c5a59bd573639ab39a5ded5ca983b1b2"}, - {file = "faiss_cpu-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ba8e6202d561ac57394c9d691ff17f8fa6eb9a077913a993fce0a154ec0176f1"}, - {file = "faiss_cpu-1.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a66e9fa7b70556a39681f06e0652f4124c8ddb0a1924afe4f0e40b6924dc845b"}, - {file = "faiss_cpu-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51aaef5a1255d0ea88ea7e52a2415f98c5dd2dd9cec10348d55136541eeec99f"}, - {file = "faiss_cpu-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:38152761242870ec7019e0397cbd0ed0b0716562029ce41a71bb38448bd6d5bc"}, - {file = "faiss_cpu-1.8.0-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:c9e6ad94b86626be1a0faff3e53c4ca169eba88aa156d7e90c5a2e9ba30558fb"}, - {file = "faiss_cpu-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4601dbd81733bf1bc3bff690aac981289fb386dc8e60d0c4eec8a37ba6856d20"}, - {file = "faiss_cpu-1.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa943d3b5e8c5c77cdd629d9c3c6f78d7da616e586fdd1b94aecbf2e5fa9ba06"}, - {file = "faiss_cpu-1.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b644b366c3b239b34fa3e08bf65bfc78a24eda1e1ea5b2b6d9be3e8fc73d8179"}, - {file = "faiss_cpu-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:f85ecf3514850f93985be238351f5a70736133cfae784b372640aa17c6343a1b"}, - {file = "faiss_cpu-1.8.0-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:61abc0129a357ac00f17f5167f14dff41480de2cc852f306c3d4cd36b893ccbd"}, - {file = "faiss_cpu-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b788186d6eb94e6333e1aa8bb6c84b66e967458ecdd1cee22e16f04c43ee674c"}, - {file = "faiss_cpu-1.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5658d90a202c62e4a69c5b065785e9ddcaf6986cb395c16afed8dbe4c58c31a2"}, - {file = "faiss_cpu-1.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d460a372efce547e53d3c47d2c2a8a90b186ad245969048c10c1d7a1e5cf21b"}, - {file = "faiss_cpu-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:9e6520324f0a6764dd267b3c32c76958bf2b1ec36752950f6fab31a7295980a0"}, - {file = "faiss_cpu-1.8.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:fc44be179d5b7f690484ef0d0caf817fea2698a5275a0c7fb6cbf406e5b2e4d1"}, - {file = "faiss_cpu-1.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bbd6f0bc2e1424a12dc7e19d2cc95b53124867966b21110d26f909227e7ed1f1"}, - {file = "faiss_cpu-1.8.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06e7add0c8a06ce8fb0443c38fcaf49c45fb74527ea633b819e56452608e64f5"}, - {file = "faiss_cpu-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b864e23c1817fa6cfe9bbec096fd7140d596002934f71aa89b196ffb1b9cd846"}, - {file = "faiss_cpu-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:655433755845adbb6f0961e2f8980703640cb9faa96f1cd1ea190252149e0d0a"}, - {file = "faiss_cpu-1.8.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:e81fc376a3bcda213ffb395dda1018c953ce927c587731ad582f4e6c2b225363"}, - {file = "faiss_cpu-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8c6fa6b7eaf558307b4ab118a236e8d1da79a8685222928e4dd52e277dba144a"}, - {file = "faiss_cpu-1.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:652f6812ef2e8b0f9b18209828c590bc618aca82e7f1c1b1888f52928258e406"}, - {file = "faiss_cpu-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:304da4e0d19044374b63a5b6467028572eac4bd3f32bc9e8783d800a03fb1f02"}, - {file = "faiss_cpu-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:cb475d3f25f08c97ac64dfe026f113e2aeb9829b206b3b046256c3b40dd7eb62"}, + {file = "faiss_cpu-1.8.0.post1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b78ff9079d15fd0f156bf5dd8a2975a8abffac1854a86ece263eec1500a2e836"}, + {file = "faiss_cpu-1.8.0.post1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9de25c943d1789e35fe06a20884c88cd32aedbb1a33bb8da2238cdea7bd9633f"}, + {file = "faiss_cpu-1.8.0.post1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:adae0f1b144e7216da696f14bc4991ca4300c94baaa59247c3d322588e661c95"}, + {file = "faiss_cpu-1.8.0.post1-cp310-cp310-win_amd64.whl", hash = "sha256:00345290680a444a4b4cb2d98a3844bb5c401a2160fee547c7631d759fd2ec3e"}, + {file = "faiss_cpu-1.8.0.post1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:20bd43eca3b7d77e71ea56b7a558cc28e900d8abff417eb285e2d92e95d934d4"}, + {file = "faiss_cpu-1.8.0.post1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8542a87743a7f94ac656fd3e9592ad57e58b04d961ad2fe654a22a8ca59defdb"}, + {file = "faiss_cpu-1.8.0.post1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed46928de3dc20170b10fec89c54075a11383c2aaf4f119c63e0f6ae5a507d74"}, + {file = "faiss_cpu-1.8.0.post1-cp311-cp311-win_amd64.whl", hash = "sha256:4fa5fc8ea210b919aa469e27d6687e50052db906e7fec3f2257178b1384fa18b"}, + {file = "faiss_cpu-1.8.0.post1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:92b06147fa84732ecdc965922e8ef50dc7011ef8be65821ff4abb2118cb5dce0"}, + {file = "faiss_cpu-1.8.0.post1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:709ef9394d1148aef70dbe890edbde8c282a4a2e06a8b69ab64f65e90f5ba572"}, + {file = "faiss_cpu-1.8.0.post1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:327a9c30971bf72cd8392b15eb4aff5d898c453212eae656dfaa3ba555b9ca0c"}, + {file = "faiss_cpu-1.8.0.post1-cp312-cp312-win_amd64.whl", hash = "sha256:8756f1d93faba56349883fa2f5d47fe36bb2f11f789200c6b1c691ef805485f2"}, + {file = "faiss_cpu-1.8.0.post1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8842b7fc921ca1fafdb0845f2ba029e79df04eebae72ab135239f93478a9b7a2"}, + {file = "faiss_cpu-1.8.0.post1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d5a9799634e32c3862d5436d1e78112ed9a38f319e4523f5916e55d86adda8f"}, + {file = "faiss_cpu-1.8.0.post1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a70923b0fbbb40f647e20bcbcbfd472277e6d84bb23ff12d2a94b6841806b55"}, + {file = "faiss_cpu-1.8.0.post1-cp38-cp38-win_amd64.whl", hash = "sha256:ce652df3c4dd50c88ac9235d072f30ce60694dc422c5f523bbbcab320e8f3097"}, + {file = "faiss_cpu-1.8.0.post1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c50c8697077470ede7f1939ef8dc8a846ec19cf1893b543f6b67f9af03b0a122"}, + {file = "faiss_cpu-1.8.0.post1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98ce428a7a67fe5c64047280e5e12a8dbdecf7002f9d127b26cf1db354e9fe76"}, + {file = "faiss_cpu-1.8.0.post1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f3b36b80380bae523e3198cfb4a137867055945ce7bf10d18fe9f0284f2fb47"}, + {file = "faiss_cpu-1.8.0.post1-cp39-cp39-win_amd64.whl", hash = "sha256:4fcc67a2353f08a20c1ab955de3cde14ef3b447761b26244a5aa849c15cbc9b3"}, + {file = "faiss_cpu-1.8.0.post1.tar.gz", hash = "sha256:5686af34414678c3d49c4fa8d774df7156e9cb48d7029071e56230e74b01cc13"}, ] [package.dependencies] -numpy = "*" +numpy = ">=1.0,<2.0" +packaging = "*" [[package]] name = "fake-useragent" @@ -2116,6 +2112,20 @@ files = [ {file = "filetype-1.2.0.tar.gz", hash = "sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb"}, ] +[[package]] +name = "firecrawl-py" +version = "0.0.16" +description = "Python SDK for Firecrawl API" +optional = false +python-versions = ">=3.8" +files = [ + {file = "firecrawl_py-0.0.16-py3-none-any.whl", hash = "sha256:9024f483b501852a6b9c4e6cdfc9e8dde452d922afac357080bb278a0c9c2a26"}, + {file = "firecrawl_py-0.0.16.tar.gz", hash = "sha256:6c662fa0a549bc7f5c0acb704baba6731869ca0451094034264dfc1b4eb086e4"}, +] + +[package.dependencies] +requests = "*" + [[package]] name = "flaml" version = "2.1.2" @@ -2436,8 +2446,8 @@ files = [ [package.dependencies] cffi = {version = ">=1.12.2", markers = "platform_python_implementation == \"CPython\" and sys_platform == \"win32\""} greenlet = [ - {version = ">=2.0.0", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.11\""}, {version = ">=3.0rc3", markers = "platform_python_implementation == \"CPython\" and python_version >= \"3.11\""}, + {version = ">=2.0.0", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.11\""}, ] "zope.event" = "*" "zope.interface" = "*" @@ -2566,13 +2576,13 @@ test = ["coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", [[package]] name = "google-ai-generativelanguage" -version = "0.6.4" +version = "0.6.5" description = "Google Ai Generativelanguage API client library" optional = false python-versions = ">=3.7" files = [ - {file = "google-ai-generativelanguage-0.6.4.tar.gz", hash = "sha256:1750848c12af96cb24ae1c3dd05e4bfe24867dc4577009ed03e1042d8421e874"}, - {file = "google_ai_generativelanguage-0.6.4-py3-none-any.whl", hash = "sha256:730e471aa549797118fb1c88421ba1957741433ada575cf5dd08d3aebf903ab1"}, + {file = "google-ai-generativelanguage-0.6.5.tar.gz", hash = "sha256:c4089c277fa4e26722f76ab03ee3039f28be8bf1c9be282948b9583a154c6d79"}, + {file = "google_ai_generativelanguage-0.6.5-py3-none-any.whl", hash = "sha256:236875bb4a6d6ebdba2f12bd9d5e776100fd913402157a47b5e9fb80a13f25a7"}, ] [package.dependencies] @@ -2583,28 +2593,28 @@ protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4 [[package]] name = "google-api-core" -version = "2.19.0" +version = "2.19.1" description = "Google API client core library" optional = false python-versions = ">=3.7" files = [ - {file = "google-api-core-2.19.0.tar.gz", hash = "sha256:cf1b7c2694047886d2af1128a03ae99e391108a08804f87cfd35970e49c9cd10"}, - {file = "google_api_core-2.19.0-py3-none-any.whl", hash = "sha256:8661eec4078c35428fd3f69a2c7ee29e342896b70f01d1a1cbcb334372dd6251"}, + {file = "google-api-core-2.19.1.tar.gz", hash = "sha256:f4695f1e3650b316a795108a76a1c416e6afb036199d1c1f1f110916df479ffd"}, + {file = "google_api_core-2.19.1-py3-none-any.whl", hash = "sha256:f12a9b8309b5e21d92483bbd47ce2c445861ec7d269ef6784ecc0ea8c1fa6125"}, ] [package.dependencies] google-auth = ">=2.14.1,<3.0.dev0" googleapis-common-protos = ">=1.56.2,<2.0.dev0" grpcio = [ - {version = ">=1.33.2,<2.0dev", optional = true, markers = "python_version < \"3.11\" and extra == \"grpc\""}, {version = ">=1.49.1,<2.0dev", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}, + {version = ">=1.33.2,<2.0dev", optional = true, markers = "python_version < \"3.11\" and extra == \"grpc\""}, ] grpcio-status = [ - {version = ">=1.33.2,<2.0.dev0", optional = true, markers = "python_version < \"3.11\" and extra == \"grpc\""}, {version = ">=1.49.1,<2.0.dev0", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}, + {version = ">=1.33.2,<2.0.dev0", optional = true, markers = "python_version < \"3.11\" and extra == \"grpc\""}, ] proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0" +protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" requests = ">=2.18.0,<3.0.0.dev0" [package.extras] @@ -2886,16 +2896,16 @@ testing = ["pytest"] [[package]] name = "google-generativeai" -version = "0.5.4" +version = "0.7.0" description = "Google Generative AI High level API client library and tools." optional = false python-versions = ">=3.9" files = [ - {file = "google_generativeai-0.5.4-py3-none-any.whl", hash = "sha256:036d63ee35e7c8aedceda4f81c390a5102808af09ff3a6e57e27ed0be0708f3c"}, + {file = "google_generativeai-0.7.0-py3-none-any.whl", hash = "sha256:7be4b634afeb8b6bebde1af7271e94d2af84d2d28b5988c7ed9921733c40fe63"}, ] [package.dependencies] -google-ai-generativelanguage = "0.6.4" +google-ai-generativelanguage = "0.6.5" google-api-core = "*" google-api-python-client = "*" google-auth = ">=2.15.0" @@ -2940,18 +2950,18 @@ requests = "*" [[package]] name = "googleapis-common-protos" -version = "1.63.1" +version = "1.63.2" description = "Common protobufs used in Google APIs" optional = false python-versions = ">=3.7" files = [ - {file = "googleapis-common-protos-1.63.1.tar.gz", hash = "sha256:c6442f7a0a6b2a80369457d79e6672bb7dcbaab88e0848302497e3ec80780a6a"}, - {file = "googleapis_common_protos-1.63.1-py2.py3-none-any.whl", hash = "sha256:0e1c2cdfcbc354b76e4a211a35ea35d6926a835cba1377073c4861db904a1877"}, + {file = "googleapis-common-protos-1.63.2.tar.gz", hash = "sha256:27c5abdffc4911f28101e635de1533fb4cfd2c37fbaa9174587c799fac90aa87"}, + {file = "googleapis_common_protos-1.63.2-py2.py3-none-any.whl", hash = "sha256:27a2499c7e8aff199665b22741997e485eccc8645aa9176c7c988e6fae507945"}, ] [package.dependencies] grpcio = {version = ">=1.44.0,<2.0.0.dev0", optional = true, markers = "extra == \"grpc\""} -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" +protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" [package.extras] grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] @@ -3074,19 +3084,19 @@ typing-extensions = ">=4.7,<5" [[package]] name = "grpc-google-iam-v1" -version = "0.13.0" +version = "0.13.1" description = "IAM API client library" optional = false python-versions = ">=3.7" files = [ - {file = "grpc-google-iam-v1-0.13.0.tar.gz", hash = "sha256:fad318608b9e093258fbf12529180f400d1c44453698a33509cc6ecf005b294e"}, - {file = "grpc_google_iam_v1-0.13.0-py2.py3-none-any.whl", hash = "sha256:53902e2af7de8df8c1bd91373d9be55b0743ec267a7428ea638db3775becae89"}, + {file = "grpc-google-iam-v1-0.13.1.tar.gz", hash = "sha256:3ff4b2fd9d990965e410965253c0da6f66205d5a8291c4c31c6ebecca18a9001"}, + {file = "grpc_google_iam_v1-0.13.1-py2.py3-none-any.whl", hash = "sha256:c3e86151a981811f30d5e7330f271cee53e73bb87755e88cc3b6f0c7b5fe374e"}, ] [package.dependencies] googleapis-common-protos = {version = ">=1.56.0,<2.0.0dev", extras = ["grpc"]} grpcio = ">=1.44.0,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" +protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0dev" [[package]] name = "grpcio" @@ -3802,72 +3812,72 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "jiter" -version = "0.4.2" +version = "0.5.0" description = "Fast iterable JSON parser." optional = false python-versions = ">=3.8" files = [ - {file = "jiter-0.4.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:c2b003ff58d14f5e182b875acd5177b2367245c19a03be9a2230535d296f7550"}, - {file = "jiter-0.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b48c77c25f094707731cd5bad6b776046846b60a27ee20efc8fadfb10a89415f"}, - {file = "jiter-0.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f50ad6b172bde4d45f4d4ea10c49282a337b8bb735afc99763dfa55ea84a743"}, - {file = "jiter-0.4.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:95f6001e86f525fbbc9706db2078dc22be078b0950de55b92d37041930f5f940"}, - {file = "jiter-0.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16646ef23b62b007de80460d303ebb2d81e355dac9389c787cec87cdd7ffef2f"}, - {file = "jiter-0.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b4e847c13b0bf1255c711a92330e7a8cb8b5cdd1e37d7db309627bcdd3367ff"}, - {file = "jiter-0.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c536589be60e4c5f2b20fadc4db7e9f55d4c9df3551f29ddf1c4a18dcc9dd54"}, - {file = "jiter-0.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b3b2763996167830889a854b4ded30bb90897f9b76be78069c50c3ec4540950e"}, - {file = "jiter-0.4.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:675e8ab98c99495091af6b6e9bf2b6353bcf81f25ab6ce27d36127e315b4505d"}, - {file = "jiter-0.4.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e48e43d9d999aaf55f53406b8846ff8cbe3e47ee4b9dc37e5a10a65ce760809f"}, - {file = "jiter-0.4.2-cp310-none-win32.whl", hash = "sha256:881b6e67c50bc36acb3570eda693763c8cd77d590940e06fa6d325d0da52ec1b"}, - {file = "jiter-0.4.2-cp310-none-win_amd64.whl", hash = "sha256:bb8f7b43259efc6add0d721ade2953e064b24e2026d26d979bc09ec080844cef"}, - {file = "jiter-0.4.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:24ad336ac47f274fa83f6fbedcabff9d3387c80f67c66b992688e6a8ba2c47e9"}, - {file = "jiter-0.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fc392a220095730afe365ce1516f2f88bb085a2fd29ea191be9c6e3c71713d9a"}, - {file = "jiter-0.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1fdc408de36c81460896de0176f2f7b9f3574dcd35693a0b2c00f4ca34c98e4"}, - {file = "jiter-0.4.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c10ad76722ee6a8c820b0db06a793c08b7d679e5201b9563015bd1e06c959a09"}, - {file = "jiter-0.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dbb46d1e9c82bba87f0cbda38413e49448a7df35b1e55917124bff9f38974a23"}, - {file = "jiter-0.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:194e28ef4b5f3b61408cb2ee6b6dcbcdb0c9063d01b92b01345b7605692849f5"}, - {file = "jiter-0.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f0a447533eccd62748a727e058efa10a8d7cf1de8ffe1a4d705ecb41dad9090"}, - {file = "jiter-0.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5f7704d7260bbb88cca3453951af739589132b26e896a3144fa2dae2263716d7"}, - {file = "jiter-0.4.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:01427458bc9550f2eda09d425755330e7d0eb09adce099577433bebf05d28d59"}, - {file = "jiter-0.4.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:159b8416879c0053b17c352f70b67b749ef5b2924c6154318ecf71918aab0905"}, - {file = "jiter-0.4.2-cp311-none-win32.whl", hash = "sha256:f2445234acfb79048ce1a0d5d0e181abb9afd9e4a29d8d9988fe26cc5773a81a"}, - {file = "jiter-0.4.2-cp311-none-win_amd64.whl", hash = "sha256:e15a65f233b6b0e5ac10ddf3b97ceb18aa9ffba096259961641d78b4ee321bd5"}, - {file = "jiter-0.4.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:d61d59521aea9745447ce50f74d39a16ef74ec9d6477d9350d77e75a3d774ad2"}, - {file = "jiter-0.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eef607dc0acc251923427808dbd017f1998ae3c1a0430a261527aa5cbb3a942"}, - {file = "jiter-0.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af6bf39954646e374fc47429c656372ac731a6a26b644158a5a84bcdbed33a47"}, - {file = "jiter-0.4.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8f509d23606e476852ee46a2b65b5c4ad3905f17424d9cc19c1dffa1c94ba3c6"}, - {file = "jiter-0.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59672774daa44ee140aada0c781c82bee4d9ac5e522966186cfb6b3c217d8a51"}, - {file = "jiter-0.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:24a0458efac5afeca254cf557b8a654e17013075a69905c78f88d557f129d871"}, - {file = "jiter-0.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8860766d1c293e75c1bb4e25b74fa987e3adf199cac3f5f9e6e49c2bebf092f"}, - {file = "jiter-0.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a109f3281b72bbf4921fe43db1005c004a38559ca0b6c4985add81777dfe0a44"}, - {file = "jiter-0.4.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:faa7e667454b77ad2f0ef87db39f4944de759617aadf210ea2b73f26bb24755f"}, - {file = "jiter-0.4.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3512f8b00cafb6780b427cb6282800d2bf8277161d9c917830661bd4ed1d3528"}, - {file = "jiter-0.4.2-cp312-none-win32.whl", hash = "sha256:853b35d508ee5b66d06630473c1c0b7bb5e29bf4785c9d2202437116c94f7e21"}, - {file = "jiter-0.4.2-cp312-none-win_amd64.whl", hash = "sha256:4a3a8197784278eb8b24cb02c45e1cad67c2ce5b5b758adfb19b87f74bbdff9c"}, - {file = "jiter-0.4.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:ca2a4d750aed3154b89f2efb148609fc985fad8db739460797aaf9b478acedda"}, - {file = "jiter-0.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0e6c304b3cc6896256727e1fb8991c7179a345eca8224e201795e9cacf4683b0"}, - {file = "jiter-0.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7cc34ac708ae1750d077e490321761ec4b9a055b994cbdd1d6fbd37099e4aa7b"}, - {file = "jiter-0.4.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8c93383875ab8d2e4f760aaff335b4a12ff32d4f9cf49c4498d657734f611466"}, - {file = "jiter-0.4.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce197ee044add576afca0955b42142dd0312639adb6ebadbdbe4277f2855614f"}, - {file = "jiter-0.4.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a427716813ff65480ca5b5117cfa099f49b49cd38051f8609bd0d5493013ca0"}, - {file = "jiter-0.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:479990218353356234669e70fac53e5eb6f739a10db25316171aede2c97d9364"}, - {file = "jiter-0.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d35a91ec5ac74cf33234c431505299fa91c0a197c2dbafd47400aca7c69489d4"}, - {file = "jiter-0.4.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b27189847193708c94ad10ca0d891309342ae882725d2187cf5d2db02bde8d1b"}, - {file = "jiter-0.4.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:76c255308cd1093fb411a03756b7bb220e48d4a98c30cbc79ed448bf3978e27d"}, - {file = "jiter-0.4.2-cp38-none-win32.whl", hash = "sha256:bb77438060bad49cc251941e6701b31138365c8a0ddaf10cdded2fcc6dd30701"}, - {file = "jiter-0.4.2-cp38-none-win_amd64.whl", hash = "sha256:ce858af19f7ce0d4b51c9f6c0c9d08f1e9dcef1986c5875efd0674a7054292ca"}, - {file = "jiter-0.4.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:6128838a2f357b3921b2a3242d5dc002ae4255ecc8f9f05c20d56d7d2d79c5ad"}, - {file = "jiter-0.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f2420cebb9ba856cb57dcab1d2d8def949b464b0db09c22a4e4dbd52fff7b200"}, - {file = "jiter-0.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5d13d8128e853b320e00bb18bd4bb8b136cc0936091dc87633648fc688eb705"}, - {file = "jiter-0.4.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eba5d6e54f149c508ba88677f97d3dc7dd75e9980d234bbac8027ac6db0763a3"}, - {file = "jiter-0.4.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0fad5d64af0bc0545237419bf4150d8de56f0bd217434bdd1a59730327252bef"}, - {file = "jiter-0.4.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d179e7bca89cf5719bd761dd37a341ff0f98199ecaa9c14af09792e47e977cc"}, - {file = "jiter-0.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36353caee9f103d8ee7bda077f6400505b0f370e27eabcab33a33d21de12a2a6"}, - {file = "jiter-0.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dd146c25bce576ca5db64fc7eccb8862af00f1f0e30108796953f12a53660e4c"}, - {file = "jiter-0.4.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:14b7c08cadbcd703041c66dc30e24e17de2f340281cac0e69374223ecf153aa4"}, - {file = "jiter-0.4.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a90f1a8b3d29aea198f8ea2b01148276ced8056e5103f32525266b3d880e65c9"}, - {file = "jiter-0.4.2-cp39-none-win32.whl", hash = "sha256:25b174997c780337b61ae57b1723455eecae9a17a9659044fd3c3b369190063f"}, - {file = "jiter-0.4.2-cp39-none-win_amd64.whl", hash = "sha256:bef62cea18521c5b99368147040c7e560c55098a35c93456f110678a2d34189a"}, - {file = "jiter-0.4.2.tar.gz", hash = "sha256:29b9d44f23f0c05f46d482f4ebf03213ee290d77999525d0975a17f875bf1eea"}, + {file = "jiter-0.5.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b599f4e89b3def9a94091e6ee52e1d7ad7bc33e238ebb9c4c63f211d74822c3f"}, + {file = "jiter-0.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a063f71c4b06225543dddadbe09d203dc0c95ba352d8b85f1221173480a71d5"}, + {file = "jiter-0.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:acc0d5b8b3dd12e91dd184b87273f864b363dfabc90ef29a1092d269f18c7e28"}, + {file = "jiter-0.5.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c22541f0b672f4d741382a97c65609332a783501551445ab2df137ada01e019e"}, + {file = "jiter-0.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:63314832e302cc10d8dfbda0333a384bf4bcfce80d65fe99b0f3c0da8945a91a"}, + {file = "jiter-0.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a25fbd8a5a58061e433d6fae6d5298777c0814a8bcefa1e5ecfff20c594bd749"}, + {file = "jiter-0.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:503b2c27d87dfff5ab717a8200fbbcf4714516c9d85558048b1fc14d2de7d8dc"}, + {file = "jiter-0.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6d1f3d27cce923713933a844872d213d244e09b53ec99b7a7fdf73d543529d6d"}, + {file = "jiter-0.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c95980207b3998f2c3b3098f357994d3fd7661121f30669ca7cb945f09510a87"}, + {file = "jiter-0.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:afa66939d834b0ce063f57d9895e8036ffc41c4bd90e4a99631e5f261d9b518e"}, + {file = "jiter-0.5.0-cp310-none-win32.whl", hash = "sha256:f16ca8f10e62f25fd81d5310e852df6649af17824146ca74647a018424ddeccf"}, + {file = "jiter-0.5.0-cp310-none-win_amd64.whl", hash = "sha256:b2950e4798e82dd9176935ef6a55cf6a448b5c71515a556da3f6b811a7844f1e"}, + {file = "jiter-0.5.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d4c8e1ed0ef31ad29cae5ea16b9e41529eb50a7fba70600008e9f8de6376d553"}, + {file = "jiter-0.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c6f16e21276074a12d8421692515b3fd6d2ea9c94fd0734c39a12960a20e85f3"}, + {file = "jiter-0.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5280e68e7740c8c128d3ae5ab63335ce6d1fb6603d3b809637b11713487af9e6"}, + {file = "jiter-0.5.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:583c57fc30cc1fec360e66323aadd7fc3edeec01289bfafc35d3b9dcb29495e4"}, + {file = "jiter-0.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:26351cc14507bdf466b5f99aba3df3143a59da75799bf64a53a3ad3155ecded9"}, + {file = "jiter-0.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4829df14d656b3fb87e50ae8b48253a8851c707da9f30d45aacab2aa2ba2d614"}, + {file = "jiter-0.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a42a4bdcf7307b86cb863b2fb9bb55029b422d8f86276a50487982d99eed7c6e"}, + {file = "jiter-0.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04d461ad0aebf696f8da13c99bc1b3e06f66ecf6cfd56254cc402f6385231c06"}, + {file = "jiter-0.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e6375923c5f19888c9226582a124b77b622f8fd0018b843c45eeb19d9701c403"}, + {file = "jiter-0.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2cec323a853c24fd0472517113768c92ae0be8f8c384ef4441d3632da8baa646"}, + {file = "jiter-0.5.0-cp311-none-win32.whl", hash = "sha256:aa1db0967130b5cab63dfe4d6ff547c88b2a394c3410db64744d491df7f069bb"}, + {file = "jiter-0.5.0-cp311-none-win_amd64.whl", hash = "sha256:aa9d2b85b2ed7dc7697597dcfaac66e63c1b3028652f751c81c65a9f220899ae"}, + {file = "jiter-0.5.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9f664e7351604f91dcdd557603c57fc0d551bc65cc0a732fdacbf73ad335049a"}, + {file = "jiter-0.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:044f2f1148b5248ad2c8c3afb43430dccf676c5a5834d2f5089a4e6c5bbd64df"}, + {file = "jiter-0.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:702e3520384c88b6e270c55c772d4bd6d7b150608dcc94dea87ceba1b6391248"}, + {file = "jiter-0.5.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:528d742dcde73fad9d63e8242c036ab4a84389a56e04efd854062b660f559544"}, + {file = "jiter-0.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8cf80e5fe6ab582c82f0c3331df27a7e1565e2dcf06265afd5173d809cdbf9ba"}, + {file = "jiter-0.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:44dfc9ddfb9b51a5626568ef4e55ada462b7328996294fe4d36de02fce42721f"}, + {file = "jiter-0.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c451f7922992751a936b96c5f5b9bb9312243d9b754c34b33d0cb72c84669f4e"}, + {file = "jiter-0.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:308fce789a2f093dca1ff91ac391f11a9f99c35369117ad5a5c6c4903e1b3e3a"}, + {file = "jiter-0.5.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7f5ad4a7c6b0d90776fdefa294f662e8a86871e601309643de30bf94bb93a64e"}, + {file = "jiter-0.5.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ea189db75f8eca08807d02ae27929e890c7d47599ce3d0a6a5d41f2419ecf338"}, + {file = "jiter-0.5.0-cp312-none-win32.whl", hash = "sha256:e3bbe3910c724b877846186c25fe3c802e105a2c1fc2b57d6688b9f8772026e4"}, + {file = "jiter-0.5.0-cp312-none-win_amd64.whl", hash = "sha256:a586832f70c3f1481732919215f36d41c59ca080fa27a65cf23d9490e75b2ef5"}, + {file = "jiter-0.5.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:f04bc2fc50dc77be9d10f73fcc4e39346402ffe21726ff41028f36e179b587e6"}, + {file = "jiter-0.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6f433a4169ad22fcb550b11179bb2b4fd405de9b982601914ef448390b2954f3"}, + {file = "jiter-0.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad4a6398c85d3a20067e6c69890ca01f68659da94d74c800298581724e426c7e"}, + {file = "jiter-0.5.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6baa88334e7af3f4d7a5c66c3a63808e5efbc3698a1c57626541ddd22f8e4fbf"}, + {file = "jiter-0.5.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ece0a115c05efca597c6d938f88c9357c843f8c245dbbb53361a1c01afd7148"}, + {file = "jiter-0.5.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:335942557162ad372cc367ffaf93217117401bf930483b4b3ebdb1223dbddfa7"}, + {file = "jiter-0.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:649b0ee97a6e6da174bffcb3c8c051a5935d7d4f2f52ea1583b5b3e7822fbf14"}, + {file = "jiter-0.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f4be354c5de82157886ca7f5925dbda369b77344b4b4adf2723079715f823989"}, + {file = "jiter-0.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5206144578831a6de278a38896864ded4ed96af66e1e63ec5dd7f4a1fce38a3a"}, + {file = "jiter-0.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8120c60f8121ac3d6f072b97ef0e71770cc72b3c23084c72c4189428b1b1d3b6"}, + {file = "jiter-0.5.0-cp38-none-win32.whl", hash = "sha256:6f1223f88b6d76b519cb033a4d3687ca157c272ec5d6015c322fc5b3074d8a5e"}, + {file = "jiter-0.5.0-cp38-none-win_amd64.whl", hash = "sha256:c59614b225d9f434ea8fc0d0bec51ef5fa8c83679afedc0433905994fb36d631"}, + {file = "jiter-0.5.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:0af3838cfb7e6afee3f00dc66fa24695199e20ba87df26e942820345b0afc566"}, + {file = "jiter-0.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:550b11d669600dbc342364fd4adbe987f14d0bbedaf06feb1b983383dcc4b961"}, + {file = "jiter-0.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:489875bf1a0ffb3cb38a727b01e6673f0f2e395b2aad3c9387f94187cb214bbf"}, + {file = "jiter-0.5.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b250ca2594f5599ca82ba7e68785a669b352156260c5362ea1b4e04a0f3e2389"}, + {file = "jiter-0.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ea18e01f785c6667ca15407cd6dabbe029d77474d53595a189bdc813347218e"}, + {file = "jiter-0.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:462a52be85b53cd9bffd94e2d788a09984274fe6cebb893d6287e1c296d50653"}, + {file = "jiter-0.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92cc68b48d50fa472c79c93965e19bd48f40f207cb557a8346daa020d6ba973b"}, + {file = "jiter-0.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1c834133e59a8521bc87ebcad773608c6fa6ab5c7a022df24a45030826cf10bc"}, + {file = "jiter-0.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab3a71ff31cf2d45cb216dc37af522d335211f3a972d2fe14ea99073de6cb104"}, + {file = "jiter-0.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cccd3af9c48ac500c95e1bcbc498020c87e1781ff0345dd371462d67b76643eb"}, + {file = "jiter-0.5.0-cp39-none-win32.whl", hash = "sha256:368084d8d5c4fc40ff7c3cc513c4f73e02c85f6009217922d0823a48ee7adf61"}, + {file = "jiter-0.5.0-cp39-none-win_amd64.whl", hash = "sha256:ce03f7b4129eb72f1687fa11300fbf677b02990618428934662406d2a76742a1"}, + {file = "jiter-0.5.0.tar.gz", hash = "sha256:1d916ba875bcab5c5f7d927df998c4cb694d27dceddf3392e58beaf10563368a"}, ] [[package]] @@ -4112,19 +4122,19 @@ adal = ["adal (>=1.0.2)"] [[package]] name = "langchain" -version = "0.2.5" +version = "0.2.6" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain-0.2.5-py3-none-any.whl", hash = "sha256:9aded9a65348254e1c93dcdaacffe4d1b6a5e7f74ef80c160c88ff78ad299228"}, - {file = "langchain-0.2.5.tar.gz", hash = "sha256:ffdbf4fcea46a10d461bcbda2402220fcfd72a0c70e9f4161ae0510067b9b3bd"}, + {file = "langchain-0.2.6-py3-none-any.whl", hash = "sha256:f86e8a7afd3e56f8eb5ba47f01dd00144fb9fc2f1db9873bd197347be2857aa4"}, + {file = "langchain-0.2.6.tar.gz", hash = "sha256:867f6add370c1e3911b0e87d3dd0e36aec1e8f513bf06131340fe8f151d89dc5"}, ] [package.dependencies] aiohttp = ">=3.8.3,<4.0.0" async-timeout = {version = ">=4.0.0,<5.0.0", markers = "python_version < \"3.11\""} -langchain-core = ">=0.2.7,<0.3.0" +langchain-core = ">=0.2.10,<0.3.0" langchain-text-splitters = ">=0.2.0,<0.3.0" langsmith = ">=0.1.17,<0.2.0" numpy = [ @@ -4135,7 +4145,7 @@ pydantic = ">=1,<3" PyYAML = ">=5.3" requests = ">=2,<3" SQLAlchemy = ">=1.4,<3" -tenacity = ">=8.1.0,<9.0.0" +tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<9.0.0" [[package]] name = "langchain-anthropic" @@ -4171,18 +4181,18 @@ numpy = ">=1,<2" [[package]] name = "langchain-aws" -version = "0.1.7" +version = "0.1.8" description = "An integration package connecting AWS and LangChain" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_aws-0.1.7-py3-none-any.whl", hash = "sha256:413f88cbb120cc1d6ca0e9f6d72b89c1d930b78ce071fef5b03e1595fc4d6029"}, - {file = "langchain_aws-0.1.7.tar.gz", hash = "sha256:aa0bbd3e530e21fdc1d0459e97ee14fa387ce9bb2d00d721cf526e9c3ecea78f"}, + {file = "langchain_aws-0.1.8-py3-none-any.whl", hash = "sha256:d1ade6d01af7d86f42c106bb32c08a99a38c84f54a3d669201362f42fd2684b8"}, + {file = "langchain_aws-0.1.8.tar.gz", hash = "sha256:d1e5edbda092ddbeda45ef8245a494b5b4f6bef79ed5afd56054c7d348dfed74"}, ] [package.dependencies] -boto3 = ">=1.34.51,<1.35.0" -langchain-core = ">=0.2.2,<0.3" +boto3 = ">=1.34.127,<1.35.0" +langchain-core = ">=0.2.6,<0.3" numpy = ">=1,<2" [[package]] @@ -4219,20 +4229,20 @@ langchain-core = ">=0.2.0,<0.3" [[package]] name = "langchain-community" -version = "0.2.5" +version = "0.2.6" description = "Community contributed LangChain integrations." optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_community-0.2.5-py3-none-any.whl", hash = "sha256:bf37a334952e42c7676d083cf2d2c4cbfbb7de1949c4149fe19913e2b06c485f"}, - {file = "langchain_community-0.2.5.tar.gz", hash = "sha256:476787b8c8c213b67e7b0eceb53346e787f00fbae12d8e680985bd4f93b0bf64"}, + {file = "langchain_community-0.2.6-py3-none-any.whl", hash = "sha256:758cc800acfe5dd396bf8ba1b57c4792639ead0eab48ed0367f0732ec6ee1f68"}, + {file = "langchain_community-0.2.6.tar.gz", hash = "sha256:40ce09a50ed798aa651ddb34c8978200fa8589b9813c7a28ce8af027bbf249f0"}, ] [package.dependencies] aiohttp = ">=3.8.3,<4.0.0" dataclasses-json = ">=0.5.7,<0.7" -langchain = ">=0.2.5,<0.3.0" -langchain-core = ">=0.2.7,<0.3.0" +langchain = ">=0.2.6,<0.3.0" +langchain-core = ">=0.2.10,<0.3.0" langsmith = ">=0.1.0,<0.2.0" numpy = [ {version = ">=1,<2", markers = "python_version < \"3.12\""}, @@ -4241,17 +4251,17 @@ numpy = [ PyYAML = ">=5.3" requests = ">=2,<3" SQLAlchemy = ">=1.4,<3" -tenacity = ">=8.1.0,<9.0.0" +tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<9.0.0" [[package]] name = "langchain-core" -version = "0.2.9" +version = "0.2.10" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_core-0.2.9-py3-none-any.whl", hash = "sha256:426a5a4fea95a5db995ba5ab560b76edd4998fb6fe52ccc28ac987092a4cbfcd"}, - {file = "langchain_core-0.2.9.tar.gz", hash = "sha256:f1c59082642921727844e1cd0eb36d451edd1872c20e193aa3142aac03495986"}, + {file = "langchain_core-0.2.10-py3-none-any.whl", hash = "sha256:6eb72086b6bc86db9812da98f79e507c2209a15c0112aefd214a04182ada8586"}, + {file = "langchain_core-0.2.10.tar.gz", hash = "sha256:33d1fc234ab58c80476eb5bbde2107ef522a2ce8f46bdf47d9e1bd21e054208f"}, ] [package.dependencies] @@ -4267,55 +4277,55 @@ tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<9.0.0" [[package]] name = "langchain-experimental" -version = "0.0.61" +version = "0.0.62" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_experimental-0.0.61-py3-none-any.whl", hash = "sha256:f9c516f528f55919743bd56fe1689a53bf74ae7f8902d64b9d8aebc61249cbe2"}, - {file = "langchain_experimental-0.0.61.tar.gz", hash = "sha256:e9538efb994be5db3045cc582cddb9787c8299c86ffeee9d3779b7f58eef2226"}, + {file = "langchain_experimental-0.0.62-py3-none-any.whl", hash = "sha256:9240f9e3490e819976f20a37863970036e7baacb7104b9eb6833d19ab6d518c9"}, + {file = "langchain_experimental-0.0.62.tar.gz", hash = "sha256:9737fbc8429d24457ea4d368e3c9ba9ed1cace0564fb5f1a96a3027a588bd0ac"}, ] [package.dependencies] -langchain-community = ">=0.2.5,<0.3.0" -langchain-core = ">=0.2.7,<0.3.0" +langchain-community = ">=0.2.6,<0.3.0" +langchain-core = ">=0.2.10,<0.3.0" [[package]] name = "langchain-google-genai" -version = "1.0.6" +version = "1.0.7" description = "An integration package connecting Google's genai package and LangChain" optional = false python-versions = "<4.0,>=3.9" files = [ - {file = "langchain_google_genai-1.0.6-py3-none-any.whl", hash = "sha256:65188b3c2867efda78e09c29371499ab0d25c6a111b175365fdae2b5be1502e6"}, - {file = "langchain_google_genai-1.0.6.tar.gz", hash = "sha256:7c964117fa385c490b323ee50ab46907229823d3678b80bfacc8fa0a237fb0b9"}, + {file = "langchain_google_genai-1.0.7-py3-none-any.whl", hash = "sha256:8fc03a0b5f635d369d1eec25076921ea7a472a1cb96dbea8e8ff2c2cdce58650"}, + {file = "langchain_google_genai-1.0.7.tar.gz", hash = "sha256:6522da59720ad551867e278d63c053e0fb65fa4fa1d65382aacedca5293930fa"}, ] [package.dependencies] -google-generativeai = ">=0.5.2,<0.6.0" -langchain-core = ">=0.2.2,<0.3" +google-generativeai = ">=0.7.0,<0.8.0" +langchain-core = ">=0.2.9,<0.3" [package.extras] images = ["pillow (>=10.1.0,<11.0.0)"] [[package]] name = "langchain-google-vertexai" -version = "1.0.5" +version = "1.0.6" description = "An integration package connecting Google VertexAI and LangChain" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_google_vertexai-1.0.5-py3-none-any.whl", hash = "sha256:38f4a39bf35927d744d0883907c4d4a59eef059e9b36f28bb5c737c2aae6963b"}, - {file = "langchain_google_vertexai-1.0.5.tar.gz", hash = "sha256:50005dc12ff9d66bbbab9e1ab660574b1584eee3e7b5a647dc8a009a94f0c500"}, + {file = "langchain_google_vertexai-1.0.6-py3-none-any.whl", hash = "sha256:240a9be3ae749335ec9a495502ca8f2bff60a432b8400a21cbd93b415e4d166d"}, + {file = "langchain_google_vertexai-1.0.6.tar.gz", hash = "sha256:000c4cfd0dee73317e1752dfeec76a08c5bf24f7a134d79b9905a720ac886b11"}, ] [package.dependencies] -google-cloud-aiplatform = ">=1.47.0,<2.0.0" -google-cloud-storage = ">=2.14.0,<3.0.0" -langchain-core = ">=0.2.2,<0.3" +google-cloud-aiplatform = ">=1.56.0,<2.0.0" +google-cloud-storage = ">=2.17.0,<3.0.0" +langchain-core = ">=0.2.9,<0.3" [package.extras] -anthropic = ["anthropic[vertexai] (>=0.23.0,<1)"] +anthropic = ["anthropic[vertexai] (>=0.29.0,<1)"] [[package]] name = "langchain-groq" @@ -4367,13 +4377,13 @@ pymongo = ">=4.6.1,<5.0" [[package]] name = "langchain-openai" -version = "0.1.9" +version = "0.1.10" description = "An integration package connecting OpenAI and LangChain" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_openai-0.1.9-py3-none-any.whl", hash = "sha256:afae71ef315c967685e53fe061470438000946739a9492d5f2d53bd4ae9d495a"}, - {file = "langchain_openai-0.1.9.tar.gz", hash = "sha256:730a94d68208678b9b9f64e4959a87057e021d6600754ea8b954e7765c7a62f1"}, + {file = "langchain_openai-0.1.10-py3-none-any.whl", hash = "sha256:62eb000980eb45e4f16c88acdbaeccf3d59266554b0dd3ce6bebea1bbe8143dd"}, + {file = "langchain_openai-0.1.10.tar.gz", hash = "sha256:30f881f8ccaec28c054759837c41fd2a2264fcc5564728ce12e1715891a9ce3c"}, ] [package.dependencies] @@ -4399,20 +4409,17 @@ pinecone-client = ">=3.2.2,<4.0.0" [[package]] name = "langchain-text-splitters" -version = "0.2.1" +version = "0.2.2" description = "LangChain text splitting utilities" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_text_splitters-0.2.1-py3-none-any.whl", hash = "sha256:c2774a85f17189eaca50339629d2316d13130d4a8d9f1a1a96f3a03670c4a138"}, - {file = "langchain_text_splitters-0.2.1.tar.gz", hash = "sha256:06853d17d7241ecf5c97c7b6ef01f600f9b0fb953dd997838142a527a4f32ea4"}, + {file = "langchain_text_splitters-0.2.2-py3-none-any.whl", hash = "sha256:1c80d4b11b55e2995f02d2a326c0323ee1eeff24507329bb22924e420c782dff"}, + {file = "langchain_text_splitters-0.2.2.tar.gz", hash = "sha256:a1e45de10919fa6fb080ef0525deab56557e9552083600455cb9fa4238076140"}, ] [package.dependencies] -langchain-core = ">=0.2.0,<0.3.0" - -[package.extras] -extended-testing = ["beautifulsoup4 (>=4.12.3,<5.0.0)", "lxml (>=4.9.3,<6.0)"] +langchain-core = ">=0.2.10,<0.3.0" [[package]] name = "langchainhub" @@ -4446,7 +4453,7 @@ six = "*" [[package]] name = "langflow-base" -version = "0.0.74" +version = "0.0.81" description = "A Python package with a built-in web application" optional = false python-versions = ">=3.10,<3.13" @@ -4464,6 +4471,7 @@ docstring-parser = "^0.15" duckdb = "^1.0.0" emoji = "^2.12.0" fastapi = "^0.111.0" +firecrawl-py = "^0.0.16" gunicorn = "^22.0.0" httpx = "*" jq = {version = "^1.7.0", markers = "sys_platform != \"win32\""} @@ -4528,29 +4536,32 @@ openai = ["openai (>=0.27.8)"] [[package]] name = "langsmith" -version = "0.1.81" +version = "0.1.82" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langsmith-0.1.81-py3-none-any.whl", hash = "sha256:3251d823225eef23ee541980b9d9e506367eabbb7f985a086b5d09e8f78ba7e9"}, - {file = "langsmith-0.1.81.tar.gz", hash = "sha256:585ef3a2251380bd2843a664c9a28da4a7d28432e3ee8bcebf291ffb8e1f0af0"}, + {file = "langsmith-0.1.82-py3-none-any.whl", hash = "sha256:9b3653e7d316036b0c60bf0bc3e280662d660f485a4ebd8e5c9d84f9831ae79c"}, + {file = "langsmith-0.1.82.tar.gz", hash = "sha256:c02e2bbc488c10c13b52c69d271eb40bd38da078d37b6ae7ae04a18bd48140be"}, ] [package.dependencies] orjson = ">=3.9.14,<4.0.0" -pydantic = ">=1,<3" +pydantic = [ + {version = ">=1,<3", markers = "python_full_version < \"3.12.4\""}, + {version = ">=2.7.4,<3.0.0", markers = "python_full_version >= \"3.12.4\""}, +] requests = ">=2,<3" [[package]] name = "litellm" -version = "1.40.25" +version = "1.40.27" description = "Library to easily interface with LLM API providers" optional = false python-versions = "!=2.7.*,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*,>=3.8" files = [ - {file = "litellm-1.40.25-py3-none-any.whl", hash = "sha256:94bff834ca92338223bed474fe614ab30a706681a596e1e38ea60fe8a574a7a8"}, - {file = "litellm-1.40.25.tar.gz", hash = "sha256:437d515274b8cc901d527fbf14ce46599700225f4e1dae2d19b46b446e402b08"}, + {file = "litellm-1.40.27-py3-none-any.whl", hash = "sha256:f6906e5260d784e7e31d579f5b28545e87517268cb96dd0dcaf31e4c5d34073f"}, + {file = "litellm-1.40.27.tar.gz", hash = "sha256:a13a04168be5a8e52d43c34c2e657ca2521da61039ac39a17abc233a1875923f"}, ] [package.dependencies] @@ -4594,13 +4605,13 @@ test = ["httpx (>=0.24.1)", "pytest (>=7.4.0)", "scipy (>=1.10)"] [[package]] name = "locust" -version = "2.29.0" +version = "2.29.1" description = "Developer-friendly load testing framework" optional = false python-versions = ">=3.9" files = [ - {file = "locust-2.29.0-py3-none-any.whl", hash = "sha256:aa9d94d3604ed9f2aab3248460d91e55d3de980a821dffdf8658b439b049d03f"}, - {file = "locust-2.29.0.tar.gz", hash = "sha256:649c99ce49d00720a3084c0109547035ad9021222835386599a8b545d31ebe51"}, + {file = "locust-2.29.1-py3-none-any.whl", hash = "sha256:8b15daab44cdf50eef1860a32bb30969423e3795247115e5a37446da3240c6d6"}, + {file = "locust-2.29.1.tar.gz", hash = "sha256:2e0628a59e2689a50cb4735a9a43709e30f2da7ed276c15d877c5325507f44b1"}, ] [package.dependencies] @@ -4615,10 +4626,11 @@ psutil = ">=5.9.1" pywin32 = {version = "*", markers = "platform_system == \"Windows\""} pyzmq = ">=25.0.0" requests = [ - {version = ">=2.26.0", markers = "python_version <= \"3.11\""}, {version = ">=2.32.2", markers = "python_version > \"3.11\""}, + {version = ">=2.26.0", markers = "python_version <= \"3.11\""}, ] tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.11\""} Werkzeug = ">=2.0.0" [[package]] @@ -5325,38 +5337,38 @@ dill = ">=0.3.8" [[package]] name = "mypy" -version = "1.10.0" +version = "1.10.1" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:da1cbf08fb3b851ab3b9523a884c232774008267b1f83371ace57f412fe308c2"}, - {file = "mypy-1.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:12b6bfc1b1a66095ab413160a6e520e1dc076a28f3e22f7fb25ba3b000b4ef99"}, - {file = "mypy-1.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e36fb078cce9904c7989b9693e41cb9711e0600139ce3970c6ef814b6ebc2b2"}, - {file = "mypy-1.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2b0695d605ddcd3eb2f736cd8b4e388288c21e7de85001e9f85df9187f2b50f9"}, - {file = "mypy-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:cd777b780312ddb135bceb9bc8722a73ec95e042f911cc279e2ec3c667076051"}, - {file = "mypy-1.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3be66771aa5c97602f382230165b856c231d1277c511c9a8dd058be4784472e1"}, - {file = "mypy-1.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8b2cbaca148d0754a54d44121b5825ae71868c7592a53b7292eeb0f3fdae95ee"}, - {file = "mypy-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ec404a7cbe9fc0e92cb0e67f55ce0c025014e26d33e54d9e506a0f2d07fe5de"}, - {file = "mypy-1.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e22e1527dc3d4aa94311d246b59e47f6455b8729f4968765ac1eacf9a4760bc7"}, - {file = "mypy-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:a87dbfa85971e8d59c9cc1fcf534efe664d8949e4c0b6b44e8ca548e746a8d53"}, - {file = "mypy-1.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a781f6ad4bab20eef8b65174a57e5203f4be627b46291f4589879bf4e257b97b"}, - {file = "mypy-1.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b808e12113505b97d9023b0b5e0c0705a90571c6feefc6f215c1df9381256e30"}, - {file = "mypy-1.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f55583b12156c399dce2df7d16f8a5095291354f1e839c252ec6c0611e86e2e"}, - {file = "mypy-1.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4cf18f9d0efa1b16478c4c129eabec36148032575391095f73cae2e722fcf9d5"}, - {file = "mypy-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:bc6ac273b23c6b82da3bb25f4136c4fd42665f17f2cd850771cb600bdd2ebeda"}, - {file = "mypy-1.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9fd50226364cd2737351c79807775136b0abe084433b55b2e29181a4c3c878c0"}, - {file = "mypy-1.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f90cff89eea89273727d8783fef5d4a934be2fdca11b47def50cf5d311aff727"}, - {file = "mypy-1.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fcfc70599efde5c67862a07a1aaf50e55bce629ace26bb19dc17cece5dd31ca4"}, - {file = "mypy-1.10.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:075cbf81f3e134eadaf247de187bd604748171d6b79736fa9b6c9685b4083061"}, - {file = "mypy-1.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:3f298531bca95ff615b6e9f2fc0333aae27fa48052903a0ac90215021cdcfa4f"}, - {file = "mypy-1.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fa7ef5244615a2523b56c034becde4e9e3f9b034854c93639adb667ec9ec2976"}, - {file = "mypy-1.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3236a4c8f535a0631f85f5fcdffba71c7feeef76a6002fcba7c1a8e57c8be1ec"}, - {file = "mypy-1.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a2b5cdbb5dd35aa08ea9114436e0d79aceb2f38e32c21684dcf8e24e1e92821"}, - {file = "mypy-1.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92f93b21c0fe73dc00abf91022234c79d793318b8a96faac147cd579c1671746"}, - {file = "mypy-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:28d0e038361b45f099cc086d9dd99c15ff14d0188f44ac883010e172ce86c38a"}, - {file = "mypy-1.10.0-py3-none-any.whl", hash = "sha256:f8c083976eb530019175aabadb60921e73b4f45736760826aa1689dda8208aee"}, - {file = "mypy-1.10.0.tar.gz", hash = "sha256:3d087fcbec056c4ee34974da493a826ce316947485cef3901f511848e687c131"}, + {file = "mypy-1.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e36f229acfe250dc660790840916eb49726c928e8ce10fbdf90715090fe4ae02"}, + {file = "mypy-1.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:51a46974340baaa4145363b9e051812a2446cf583dfaeba124af966fa44593f7"}, + {file = "mypy-1.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:901c89c2d67bba57aaaca91ccdb659aa3a312de67f23b9dfb059727cce2e2e0a"}, + {file = "mypy-1.10.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0cd62192a4a32b77ceb31272d9e74d23cd88c8060c34d1d3622db3267679a5d9"}, + {file = "mypy-1.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:a2cbc68cb9e943ac0814c13e2452d2046c2f2b23ff0278e26599224cf164e78d"}, + {file = "mypy-1.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bd6f629b67bb43dc0d9211ee98b96d8dabc97b1ad38b9b25f5e4c4d7569a0c6a"}, + {file = "mypy-1.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a1bbb3a6f5ff319d2b9d40b4080d46cd639abe3516d5a62c070cf0114a457d84"}, + {file = "mypy-1.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8edd4e9bbbc9d7b79502eb9592cab808585516ae1bcc1446eb9122656c6066f"}, + {file = "mypy-1.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6166a88b15f1759f94a46fa474c7b1b05d134b1b61fca627dd7335454cc9aa6b"}, + {file = "mypy-1.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:5bb9cd11c01c8606a9d0b83ffa91d0b236a0e91bc4126d9ba9ce62906ada868e"}, + {file = "mypy-1.10.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d8681909f7b44d0b7b86e653ca152d6dff0eb5eb41694e163c6092124f8246d7"}, + {file = "mypy-1.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:378c03f53f10bbdd55ca94e46ec3ba255279706a6aacaecac52ad248f98205d3"}, + {file = "mypy-1.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bacf8f3a3d7d849f40ca6caea5c055122efe70e81480c8328ad29c55c69e93e"}, + {file = "mypy-1.10.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:701b5f71413f1e9855566a34d6e9d12624e9e0a8818a5704d74d6b0402e66c04"}, + {file = "mypy-1.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:3c4c2992f6ea46ff7fce0072642cfb62af7a2484efe69017ed8b095f7b39ef31"}, + {file = "mypy-1.10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:604282c886497645ffb87b8f35a57ec773a4a2721161e709a4422c1636ddde5c"}, + {file = "mypy-1.10.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37fd87cab83f09842653f08de066ee68f1182b9b5282e4634cdb4b407266bade"}, + {file = "mypy-1.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8addf6313777dbb92e9564c5d32ec122bf2c6c39d683ea64de6a1fd98b90fe37"}, + {file = "mypy-1.10.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5cc3ca0a244eb9a5249c7c583ad9a7e881aa5d7b73c35652296ddcdb33b2b9c7"}, + {file = "mypy-1.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:1b3a2ffce52cc4dbaeee4df762f20a2905aa171ef157b82192f2e2f368eec05d"}, + {file = "mypy-1.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe85ed6836165d52ae8b88f99527d3d1b2362e0cb90b005409b8bed90e9059b3"}, + {file = "mypy-1.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c2ae450d60d7d020d67ab440c6e3fae375809988119817214440033f26ddf7bf"}, + {file = "mypy-1.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6be84c06e6abd72f960ba9a71561c14137a583093ffcf9bbfaf5e613d63fa531"}, + {file = "mypy-1.10.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2189ff1e39db399f08205e22a797383613ce1cb0cb3b13d8bcf0170e45b96cc3"}, + {file = "mypy-1.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:97a131ee36ac37ce9581f4220311247ab6cba896b4395b9c87af0675a13a755f"}, + {file = "mypy-1.10.1-py3-none-any.whl", hash = "sha256:71d8ac0b906354ebda8ef1673e5fde785936ac1f29ff6987c7483cfbd5a4235a"}, + {file = "mypy-1.10.1.tar.gz", hash = "sha256:1f8f492d7db9e3593ef42d4f115f04e556130f2819ad33ab84551403e97dd4c0"}, ] [package.dependencies] @@ -5734,13 +5746,13 @@ sympy = "*" [[package]] name = "openai" -version = "1.35.3" +version = "1.35.5" description = "The official Python library for the openai API" optional = false python-versions = ">=3.7.1" files = [ - {file = "openai-1.35.3-py3-none-any.whl", hash = "sha256:7b26544cef80f125431c073ffab3811d2421fbb9e30d3bd5c2436aba00b042d5"}, - {file = "openai-1.35.3.tar.gz", hash = "sha256:d6177087f150b381d49499be782d764213fdf638d391b29ca692b84dd675a389"}, + {file = "openai-1.35.5-py3-none-any.whl", hash = "sha256:28d92503c6e4b6a32a89277b36693023ef41f60922a4b5c8c621e8c5697ae3a6"}, + {file = "openai-1.35.5.tar.gz", hash = "sha256:67ef289ae22d350cbf9381d83ae82c4e3596d71b7ad1cc886143554ee12fe0c9"}, ] [package.dependencies] @@ -6080,9 +6092,9 @@ files = [ [package.dependencies] numpy = [ + {version = ">=1.26.0,<2", markers = "python_version >= \"3.12\""}, {version = ">=1.22.4,<2", markers = "python_version < \"3.11\""}, {version = ">=1.23.2,<2", markers = "python_version == \"3.11\""}, - {version = ">=1.26.0,<2", markers = "python_version >= \"3.12\""}, ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" @@ -7020,13 +7032,13 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pydantic-settings" -version = "2.3.3" +version = "2.3.4" description = "Settings management using Pydantic" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_settings-2.3.3-py3-none-any.whl", hash = "sha256:e4ed62ad851670975ec11285141db888fd24947f9440bd4380d7d8788d4965de"}, - {file = "pydantic_settings-2.3.3.tar.gz", hash = "sha256:87fda838b64b5039b970cd47c3e8a1ee460ce136278ff672980af21516f6e6ce"}, + {file = "pydantic_settings-2.3.4-py3-none-any.whl", hash = "sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a"}, + {file = "pydantic_settings-2.3.4.tar.gz", hash = "sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7"}, ] [package.dependencies] @@ -7053,71 +7065,61 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pymongo" -version = "4.7.3" +version = "4.8.0" description = "Python driver for MongoDB " optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pymongo-4.7.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e9580b4537b3cc5d412070caabd1dabdf73fdce249793598792bac5782ecf2eb"}, - {file = "pymongo-4.7.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:517243b2b189c98004570dd8fc0e89b1a48363d5578b3b99212fa2098b2ea4b8"}, - {file = "pymongo-4.7.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23b1e9dabd61da1c7deb54d888f952f030e9e35046cebe89309b28223345b3d9"}, - {file = "pymongo-4.7.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03e0f9901ad66c6fb7da0d303461377524d61dab93a4e4e5af44164c5bb4db76"}, - {file = "pymongo-4.7.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9a870824aa54453aee030bac08c77ebcf2fe8999400f0c2a065bebcbcd46b7f8"}, - {file = "pymongo-4.7.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfd7b3d3f4261bddbb74a332d87581bc523353e62bb9da4027cc7340f6fcbebc"}, - {file = "pymongo-4.7.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4d719a643ea6da46d215a3ba51dac805a773b611c641319558d8576cbe31cef8"}, - {file = "pymongo-4.7.3-cp310-cp310-win32.whl", hash = "sha256:d8b1e06f361f3c66ee694cb44326e1a2e4f93bc9c3a4849ae8547889fca71154"}, - {file = "pymongo-4.7.3-cp310-cp310-win_amd64.whl", hash = "sha256:c450ab2f9397e2d5caa7fddeb4feb30bf719c47c13ae02c0bbb3b71bf4099c1c"}, - {file = "pymongo-4.7.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:79cc6459209e885ba097779eaa0fe7f2fa049db39ab43b1731cf8d065a4650e8"}, - {file = "pymongo-4.7.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6e2287f1e2cc35e73cd74a4867e398a97962c5578a3991c730ef78d276ca8e46"}, - {file = "pymongo-4.7.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:413506bd48d8c31ee100645192171e4773550d7cb940b594d5175ac29e329ea1"}, - {file = "pymongo-4.7.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cc1febf17646d52b7561caa762f60bdfe2cbdf3f3e70772f62eb624269f9c05"}, - {file = "pymongo-4.7.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8dfcf18a49955d50a16c92b39230bd0668ffc9c164ccdfe9d28805182b48fa72"}, - {file = "pymongo-4.7.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89872041196c008caddf905eb59d3dc2d292ae6b0282f1138418e76f3abd3ad6"}, - {file = "pymongo-4.7.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3ed97b89de62ea927b672ad524de0d23f3a6b4a01c8d10e3d224abec973fbc3"}, - {file = "pymongo-4.7.3-cp311-cp311-win32.whl", hash = "sha256:d2f52b38151e946011d888a8441d3d75715c663fc5b41a7ade595e924e12a90a"}, - {file = "pymongo-4.7.3-cp311-cp311-win_amd64.whl", hash = "sha256:4a4cc91c28e81c0ce03d3c278e399311b0af44665668a91828aec16527082676"}, - {file = "pymongo-4.7.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cb30c8a78f5ebaca98640943447b6a0afcb146f40b415757c9047bf4a40d07b4"}, - {file = "pymongo-4.7.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9cf2069f5d37c398186453589486ea98bb0312214c439f7d320593b61880dc05"}, - {file = "pymongo-4.7.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3564f423958fced8a8c90940fd2f543c27adbcd6c7c6ed6715d847053f6200a0"}, - {file = "pymongo-4.7.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7a8af8a38fa6951fff73e6ff955a6188f829b29fed7c5a1b739a306b4aa56fe8"}, - {file = "pymongo-4.7.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a0e81c8dba6d825272867d487f18764cfed3c736d71d7d4ff5b79642acbed42"}, - {file = "pymongo-4.7.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88fc1d146feabac4385ea8ddb1323e584922922641303c8bf392fe1c36803463"}, - {file = "pymongo-4.7.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4225100b2c5d1f7393d7c5d256ceb8b20766830eecf869f8ae232776347625a6"}, - {file = "pymongo-4.7.3-cp312-cp312-win32.whl", hash = "sha256:5f3569ed119bf99c0f39ac9962fb5591eff02ca210fe80bb5178d7a1171c1b1e"}, - {file = "pymongo-4.7.3-cp312-cp312-win_amd64.whl", hash = "sha256:eb383c54c0c8ba27e7712b954fcf2a0905fee82a929d277e2e94ad3a5ba3c7db"}, - {file = "pymongo-4.7.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a46cffe91912570151617d866a25d07b9539433a32231ca7e7cf809b6ba1745f"}, - {file = "pymongo-4.7.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c3cba427dac50944c050c96d958c5e643c33a457acee03bae27c8990c5b9c16"}, - {file = "pymongo-4.7.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a7a5fd893edbeb7fa982f8d44b6dd0186b6cd86c89e23f6ef95049ff72bffe46"}, - {file = "pymongo-4.7.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c168a2fadc8b19071d0a9a4f85fe38f3029fe22163db04b4d5c046041c0b14bd"}, - {file = "pymongo-4.7.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c59c2c9e70f63a7f18a31e367898248c39c068c639b0579623776f637e8f482"}, - {file = "pymongo-4.7.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d08165fd82c89d372e82904c3268bd8fe5de44f92a00e97bb1db1785154397d9"}, - {file = "pymongo-4.7.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:397fed21afec4fdaecf72f9c4344b692e489756030a9c6d864393e00c7e80491"}, - {file = "pymongo-4.7.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:f903075f8625e2d228f1b9b9a0cf1385f1c41e93c03fd7536c91780a0fb2e98f"}, - {file = "pymongo-4.7.3-cp37-cp37m-win32.whl", hash = "sha256:8ed1132f58c38add6b6138b771d0477a3833023c015c455d9a6e26f367f9eb5c"}, - {file = "pymongo-4.7.3-cp37-cp37m-win_amd64.whl", hash = "sha256:8d00a5d8fc1043a4f641cbb321da766699393f1b6f87c70fae8089d61c9c9c54"}, - {file = "pymongo-4.7.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9377b868c38700c7557aac1bc4baae29f47f1d279cc76b60436e547fd643318c"}, - {file = "pymongo-4.7.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:da4a6a7b4f45329bb135aa5096823637bd5f760b44d6224f98190ee367b6b5dd"}, - {file = "pymongo-4.7.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:487e2f9277f8a63ac89335ec4f1699ae0d96ebd06d239480d69ed25473a71b2c"}, - {file = "pymongo-4.7.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6db3d608d541a444c84f0bfc7bad80b0b897e0f4afa580a53f9a944065d9b633"}, - {file = "pymongo-4.7.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e90af2ad3a8a7c295f4d09a2fbcb9a350c76d6865f787c07fe843b79c6e821d1"}, - {file = "pymongo-4.7.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e28feb18dc559d50ededba27f9054c79f80c4edd70a826cecfe68f3266807b3"}, - {file = "pymongo-4.7.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f21ecddcba2d9132d5aebd8e959de8d318c29892d0718420447baf2b9bccbb19"}, - {file = "pymongo-4.7.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:26140fbb3f6a9a74bd73ed46d0b1f43d5702e87a6e453a31b24fad9c19df9358"}, - {file = "pymongo-4.7.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:94baa5fc7f7d22c3ce2ac7bd92f7e03ba7a6875f2480e3b97a400163d6eaafc9"}, - {file = "pymongo-4.7.3-cp38-cp38-win32.whl", hash = "sha256:92dd247727dd83d1903e495acc743ebd757f030177df289e3ba4ef8a8c561fad"}, - {file = "pymongo-4.7.3-cp38-cp38-win_amd64.whl", hash = "sha256:1c90c848a5e45475731c35097f43026b88ef14a771dfd08f20b67adc160a3f79"}, - {file = "pymongo-4.7.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f598be401b416319a535c386ac84f51df38663f7a9d1071922bda4d491564422"}, - {file = "pymongo-4.7.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:35ba90477fae61c65def6e7d09e8040edfdd3b7fd47c3c258b4edded60c4d625"}, - {file = "pymongo-4.7.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9aa8735955c70892634d7e61b0ede9b1eefffd3cd09ccabee0ffcf1bdfe62254"}, - {file = "pymongo-4.7.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:82a97d8f7f138586d9d0a0cff804a045cdbbfcfc1cd6bba542b151e284fbbec5"}, - {file = "pymongo-4.7.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de3b9db558930efab5eaef4db46dcad8bf61ac3ddfd5751b3e5ac6084a25e366"}, - {file = "pymongo-4.7.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0e149217ef62812d3c2401cf0e2852b0c57fd155297ecc4dcd67172c4eca402"}, - {file = "pymongo-4.7.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3a8a1ef4a824f5feb793b3231526d0045eadb5eb01080e38435dfc40a26c3e5"}, - {file = "pymongo-4.7.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d14e5e89a4be1f10efc3d9dcb13eb7a3b2334599cb6bb5d06c6a9281b79c8e22"}, - {file = "pymongo-4.7.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c6bfa29f032fd4fd7b129520f8cdb51ab71d88c2ba0567cccd05d325f963acb5"}, - {file = "pymongo-4.7.3-cp39-cp39-win32.whl", hash = "sha256:1421d0bd2ce629405f5157bd1aaa9b83f12d53a207cf68a43334f4e4ee312b66"}, - {file = "pymongo-4.7.3-cp39-cp39-win_amd64.whl", hash = "sha256:f7ee974f8b9370a998919c55b1050889f43815ab588890212023fecbc0402a6d"}, - {file = "pymongo-4.7.3.tar.gz", hash = "sha256:6354a66b228f2cd399be7429685fb68e07f19110a3679782ecb4fdb68da03831"}, + {file = "pymongo-4.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f2b7bec27e047e84947fbd41c782f07c54c30c76d14f3b8bf0c89f7413fac67a"}, + {file = "pymongo-4.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3c68fe128a171493018ca5c8020fc08675be130d012b7ab3efe9e22698c612a1"}, + {file = "pymongo-4.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:920d4f8f157a71b3cb3f39bc09ce070693d6e9648fb0e30d00e2657d1dca4e49"}, + {file = "pymongo-4.8.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52b4108ac9469febba18cea50db972605cc43978bedaa9fea413378877560ef8"}, + {file = "pymongo-4.8.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:180d5eb1dc28b62853e2f88017775c4500b07548ed28c0bd9c005c3d7bc52526"}, + {file = "pymongo-4.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aec2b9088cdbceb87e6ca9c639d0ff9b9d083594dda5ca5d3c4f6774f4c81b33"}, + {file = "pymongo-4.8.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0cf61450feadca81deb1a1489cb1a3ae1e4266efd51adafecec0e503a8dcd84"}, + {file = "pymongo-4.8.0-cp310-cp310-win32.whl", hash = "sha256:8b18c8324809539c79bd6544d00e0607e98ff833ca21953df001510ca25915d1"}, + {file = "pymongo-4.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:e5df28f74002e37bcbdfdc5109799f670e4dfef0fb527c391ff84f078050e7b5"}, + {file = "pymongo-4.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6b50040d9767197b77ed420ada29b3bf18a638f9552d80f2da817b7c4a4c9c68"}, + {file = "pymongo-4.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:417369ce39af2b7c2a9c7152c1ed2393edfd1cbaf2a356ba31eb8bcbd5c98dd7"}, + {file = "pymongo-4.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf821bd3befb993a6db17229a2c60c1550e957de02a6ff4dd0af9476637b2e4d"}, + {file = "pymongo-4.8.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9365166aa801c63dff1a3cb96e650be270da06e3464ab106727223123405510f"}, + {file = "pymongo-4.8.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc8b8582f4209c2459b04b049ac03c72c618e011d3caa5391ff86d1bda0cc486"}, + {file = "pymongo-4.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e5019f75f6827bb5354b6fef8dfc9d6c7446894a27346e03134d290eb9e758"}, + {file = "pymongo-4.8.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b5802151fc2b51cd45492c80ed22b441d20090fb76d1fd53cd7760b340ff554"}, + {file = "pymongo-4.8.0-cp311-cp311-win32.whl", hash = "sha256:4bf58e6825b93da63e499d1a58de7de563c31e575908d4e24876234ccb910eba"}, + {file = "pymongo-4.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:b747c0e257b9d3e6495a018309b9e0c93b7f0d65271d1d62e572747f4ffafc88"}, + {file = "pymongo-4.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e6a720a3d22b54183352dc65f08cd1547204d263e0651b213a0a2e577e838526"}, + {file = "pymongo-4.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:31e4d21201bdf15064cf47ce7b74722d3e1aea2597c6785882244a3bb58c7eab"}, + {file = "pymongo-4.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6b804bb4f2d9dc389cc9e827d579fa327272cdb0629a99bfe5b83cb3e269ebf"}, + {file = "pymongo-4.8.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f2fbdb87fe5075c8beb17a5c16348a1ea3c8b282a5cb72d173330be2fecf22f5"}, + {file = "pymongo-4.8.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd39455b7ee70aabee46f7399b32ab38b86b236c069ae559e22be6b46b2bbfc4"}, + {file = "pymongo-4.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:940d456774b17814bac5ea7fc28188c7a1338d4a233efbb6ba01de957bded2e8"}, + {file = "pymongo-4.8.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:236bbd7d0aef62e64caf4b24ca200f8c8670d1a6f5ea828c39eccdae423bc2b2"}, + {file = "pymongo-4.8.0-cp312-cp312-win32.whl", hash = "sha256:47ec8c3f0a7b2212dbc9be08d3bf17bc89abd211901093e3ef3f2adea7de7a69"}, + {file = "pymongo-4.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:e84bc7707492f06fbc37a9f215374d2977d21b72e10a67f1b31893ec5a140ad8"}, + {file = "pymongo-4.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:519d1bab2b5e5218c64340b57d555d89c3f6c9d717cecbf826fb9d42415e7750"}, + {file = "pymongo-4.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:87075a1feb1e602e539bdb1ef8f4324a3427eb0d64208c3182e677d2c0718b6f"}, + {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f53429515d2b3e86dcc83dadecf7ff881e538c168d575f3688698a8707b80a"}, + {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fdc20cd1e1141b04696ffcdb7c71e8a4a665db31fe72e51ec706b3bdd2d09f36"}, + {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:284d0717d1a7707744018b0b6ee7801b1b1ff044c42f7be7a01bb013de639470"}, + {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5bf0eb8b6ef40fa22479f09375468c33bebb7fe49d14d9c96c8fd50355188b0"}, + {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ecd71b9226bd1d49416dc9f999772038e56f415a713be51bf18d8676a0841c8"}, + {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0061af6e8c5e68b13f1ec9ad5251247726653c5af3c0bbdfbca6cf931e99216"}, + {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:658d0170f27984e0d89c09fe5c42296613b711a3ffd847eb373b0dbb5b648d5f"}, + {file = "pymongo-4.8.0-cp38-cp38-win32.whl", hash = "sha256:3ed1c316718a2836f7efc3d75b4b0ffdd47894090bc697de8385acd13c513a70"}, + {file = "pymongo-4.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:7148419eedfea9ecb940961cfe465efaba90595568a1fb97585fb535ea63fe2b"}, + {file = "pymongo-4.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e8400587d594761e5136a3423111f499574be5fd53cf0aefa0d0f05b180710b0"}, + {file = "pymongo-4.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af3e98dd9702b73e4e6fd780f6925352237f5dce8d99405ff1543f3771201704"}, + {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de3a860f037bb51f968de320baef85090ff0bbb42ec4f28ec6a5ddf88be61871"}, + {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0fc18b3a093f3db008c5fea0e980dbd3b743449eee29b5718bc2dc15ab5088bb"}, + {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18c9d8f975dd7194c37193583fd7d1eb9aea0c21ee58955ecf35362239ff31ac"}, + {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:408b2f8fdbeca3c19e4156f28fff1ab11c3efb0407b60687162d49f68075e63c"}, + {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6564780cafd6abeea49759fe661792bd5a67e4f51bca62b88faab497ab5fe89"}, + {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d18d86bc9e103f4d3d4f18b85a0471c0e13ce5b79194e4a0389a224bb70edd53"}, + {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9097c331577cecf8034422956daaba7ec74c26f7b255d718c584faddd7fa2e3c"}, + {file = "pymongo-4.8.0-cp39-cp39-win32.whl", hash = "sha256:d5428dbcd43d02f6306e1c3c95f692f68b284e6ee5390292242f509004c9e3a8"}, + {file = "pymongo-4.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:ef7225755ed27bfdb18730c68f6cb023d06c28f2b734597480fb4c0e500feb6f"}, + {file = "pymongo-4.8.0.tar.gz", hash = "sha256:454f2295875744dc70f1881e4b2eb99cdad008a33574bc8aaf120530f66c0cde"}, ] [package.dependencies] @@ -7125,6 +7127,7 @@ dnspython = ">=1.16.0,<3.0.0" [package.extras] aws = ["pymongo-auth-aws (>=1.1.0,<2.0.0)"] +docs = ["furo (==2023.9.10)", "readthedocs-sphinx-search (>=0.3,<1.0)", "sphinx (>=5.3,<8)", "sphinx-rtd-theme (>=2,<3)", "sphinxcontrib-shellcheck (>=1,<2)"] encryption = ["certifi", "pymongo-auth-aws (>=1.1.0,<2.0.0)", "pymongocrypt (>=1.6.0,<2.0.0)"] gssapi = ["pykerberos", "winkerberos (>=0.5.0)"] ocsp = ["certifi", "cryptography (>=2.5)", "pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)"] @@ -7866,13 +7869,13 @@ websockets = ">=11,<13" [[package]] name = "redis" -version = "5.0.6" +version = "5.0.7" description = "Python client for Redis database and key-value store" optional = false python-versions = ">=3.7" files = [ - {file = "redis-5.0.6-py3-none-any.whl", hash = "sha256:c0d6d990850c627bbf7be01c5c4cbaadf67b48593e913bb71c9819c30df37eee"}, - {file = "redis-5.0.6.tar.gz", hash = "sha256:38473cd7c6389ad3e44a91f4c3eaf6bcb8a9f746007f29bf4fb20824ff0b2197"}, + {file = "redis-5.0.7-py3-none-any.whl", hash = "sha256:0e479e24da960c690be5d9b96d21f7b918a98c0cf49af3b6fafaa0753f93a0db"}, + {file = "redis-5.0.7.tar.gz", hash = "sha256:8f611490b93c8109b50adc317b31bfd84fff31def3475b92e7e80bf39f48175b"}, ] [package.dependencies] @@ -8097,13 +8100,13 @@ files = [ [[package]] name = "s3transfer" -version = "0.10.1" +version = "0.10.2" description = "An Amazon S3 Transfer Manager" optional = false -python-versions = ">= 3.8" +python-versions = ">=3.8" files = [ - {file = "s3transfer-0.10.1-py3-none-any.whl", hash = "sha256:ceb252b11bcf87080fb7850a224fb6e05c8a776bab8f2b64b7f25b969464839d"}, - {file = "s3transfer-0.10.1.tar.gz", hash = "sha256:5683916b4c724f799e600f41dd9e10a9ff19871bf87623cc8f491cb4f5fa0a19"}, + {file = "s3transfer-0.10.2-py3-none-any.whl", hash = "sha256:eca1c20de70a39daee580aef4986996620f365c4e0fda6a86100231d62f1bf69"}, + {file = "s3transfer-0.10.2.tar.gz", hash = "sha256:0711534e9356d3cc692fdde846b4a1e4b0cb6519971860796e6bc4c7aea00ef6"}, ] [package.dependencies] @@ -8281,45 +8284,45 @@ tests = ["black (>=24.3.0)", "matplotlib (>=3.3.4)", "mypy (>=1.9)", "numpydoc ( [[package]] name = "scipy" -version = "1.13.1" +version = "1.14.0" description = "Fundamental algorithms for scientific computing in Python" optional = true -python-versions = ">=3.9" +python-versions = ">=3.10" files = [ - {file = "scipy-1.13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:20335853b85e9a49ff7572ab453794298bcf0354d8068c5f6775a0eabf350aca"}, - {file = "scipy-1.13.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:d605e9c23906d1994f55ace80e0125c587f96c020037ea6aa98d01b4bd2e222f"}, - {file = "scipy-1.13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfa31f1def5c819b19ecc3a8b52d28ffdcc7ed52bb20c9a7589669dd3c250989"}, - {file = "scipy-1.13.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26264b282b9da0952a024ae34710c2aff7d27480ee91a2e82b7b7073c24722f"}, - {file = "scipy-1.13.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:eccfa1906eacc02de42d70ef4aecea45415f5be17e72b61bafcfd329bdc52e94"}, - {file = "scipy-1.13.1-cp310-cp310-win_amd64.whl", hash = "sha256:2831f0dc9c5ea9edd6e51e6e769b655f08ec6db6e2e10f86ef39bd32eb11da54"}, - {file = "scipy-1.13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:27e52b09c0d3a1d5b63e1105f24177e544a222b43611aaf5bc44d4a0979e32f9"}, - {file = "scipy-1.13.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:54f430b00f0133e2224c3ba42b805bfd0086fe488835effa33fa291561932326"}, - {file = "scipy-1.13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e89369d27f9e7b0884ae559a3a956e77c02114cc60a6058b4e5011572eea9299"}, - {file = "scipy-1.13.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a78b4b3345f1b6f68a763c6e25c0c9a23a9fd0f39f5f3d200efe8feda560a5fa"}, - {file = "scipy-1.13.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45484bee6d65633752c490404513b9ef02475b4284c4cfab0ef946def50b3f59"}, - {file = "scipy-1.13.1-cp311-cp311-win_amd64.whl", hash = "sha256:5713f62f781eebd8d597eb3f88b8bf9274e79eeabf63afb4a737abc6c84ad37b"}, - {file = "scipy-1.13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5d72782f39716b2b3509cd7c33cdc08c96f2f4d2b06d51e52fb45a19ca0c86a1"}, - {file = "scipy-1.13.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:017367484ce5498445aade74b1d5ab377acdc65e27095155e448c88497755a5d"}, - {file = "scipy-1.13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:949ae67db5fa78a86e8fa644b9a6b07252f449dcf74247108c50e1d20d2b4627"}, - {file = "scipy-1.13.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de3ade0e53bc1f21358aa74ff4830235d716211d7d077e340c7349bc3542e884"}, - {file = "scipy-1.13.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2ac65fb503dad64218c228e2dc2d0a0193f7904747db43014645ae139c8fad16"}, - {file = "scipy-1.13.1-cp312-cp312-win_amd64.whl", hash = "sha256:cdd7dacfb95fea358916410ec61bbc20440f7860333aee6d882bb8046264e949"}, - {file = "scipy-1.13.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:436bbb42a94a8aeef855d755ce5a465479c721e9d684de76bf61a62e7c2b81d5"}, - {file = "scipy-1.13.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:8335549ebbca860c52bf3d02f80784e91a004b71b059e3eea9678ba994796a24"}, - {file = "scipy-1.13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d533654b7d221a6a97304ab63c41c96473ff04459e404b83275b60aa8f4b7004"}, - {file = "scipy-1.13.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:637e98dcf185ba7f8e663e122ebf908c4702420477ae52a04f9908707456ba4d"}, - {file = "scipy-1.13.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a014c2b3697bde71724244f63de2476925596c24285c7a637364761f8710891c"}, - {file = "scipy-1.13.1-cp39-cp39-win_amd64.whl", hash = "sha256:392e4ec766654852c25ebad4f64e4e584cf19820b980bc04960bca0b0cd6eaa2"}, - {file = "scipy-1.13.1.tar.gz", hash = "sha256:095a87a0312b08dfd6a6155cbbd310a8c51800fc931b8c0b84003014b874ed3c"}, + {file = "scipy-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7e911933d54ead4d557c02402710c2396529540b81dd554fc1ba270eb7308484"}, + {file = "scipy-1.14.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:687af0a35462402dd851726295c1a5ae5f987bd6e9026f52e9505994e2f84ef6"}, + {file = "scipy-1.14.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:07e179dc0205a50721022344fb85074f772eadbda1e1b3eecdc483f8033709b7"}, + {file = "scipy-1.14.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:6a9c9a9b226d9a21e0a208bdb024c3982932e43811b62d202aaf1bb59af264b1"}, + {file = "scipy-1.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:076c27284c768b84a45dcf2e914d4000aac537da74236a0d45d82c6fa4b7b3c0"}, + {file = "scipy-1.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42470ea0195336df319741e230626b6225a740fd9dce9642ca13e98f667047c0"}, + {file = "scipy-1.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:176c6f0d0470a32f1b2efaf40c3d37a24876cebf447498a4cefb947a79c21e9d"}, + {file = "scipy-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ad36af9626d27a4326c8e884917b7ec321d8a1841cd6dacc67d2a9e90c2f0359"}, + {file = "scipy-1.14.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6d056a8709ccda6cf36cdd2eac597d13bc03dba38360f418560a93050c76a16e"}, + {file = "scipy-1.14.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:f0a50da861a7ec4573b7c716b2ebdcdf142b66b756a0d392c236ae568b3a93fb"}, + {file = "scipy-1.14.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:94c164a9e2498e68308e6e148646e486d979f7fcdb8b4cf34b5441894bdb9caf"}, + {file = "scipy-1.14.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:a7d46c3e0aea5c064e734c3eac5cf9eb1f8c4ceee756262f2c7327c4c2691c86"}, + {file = "scipy-1.14.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9eee2989868e274aae26125345584254d97c56194c072ed96cb433f32f692ed8"}, + {file = "scipy-1.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e3154691b9f7ed73778d746da2df67a19d046a6c8087c8b385bc4cdb2cfca74"}, + {file = "scipy-1.14.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c40003d880f39c11c1edbae8144e3813904b10514cd3d3d00c277ae996488cdb"}, + {file = "scipy-1.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:5b083c8940028bb7e0b4172acafda6df762da1927b9091f9611b0bcd8676f2bc"}, + {file = "scipy-1.14.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bff2438ea1330e06e53c424893ec0072640dac00f29c6a43a575cbae4c99b2b9"}, + {file = "scipy-1.14.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:bbc0471b5f22c11c389075d091d3885693fd3f5e9a54ce051b46308bc787e5d4"}, + {file = "scipy-1.14.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:64b2ff514a98cf2bb734a9f90d32dc89dc6ad4a4a36a312cd0d6327170339eb0"}, + {file = "scipy-1.14.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:7d3da42fbbbb860211a811782504f38ae7aaec9de8764a9bef6b262de7a2b50f"}, + {file = "scipy-1.14.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d91db2c41dd6c20646af280355d41dfa1ec7eead235642178bd57635a3f82209"}, + {file = "scipy-1.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a01cc03bcdc777c9da3cfdcc74b5a75caffb48a6c39c8450a9a05f82c4250a14"}, + {file = "scipy-1.14.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:65df4da3c12a2bb9ad52b86b4dcf46813e869afb006e58be0f516bc370165159"}, + {file = "scipy-1.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:4c4161597c75043f7154238ef419c29a64ac4a7c889d588ea77690ac4d0d9b20"}, + {file = "scipy-1.14.0.tar.gz", hash = "sha256:b5923f48cb840380f9854339176ef21763118a7300a88203ccd0bdd26e58527b"}, ] [package.dependencies] -numpy = ">=1.22.4,<2.3" +numpy = ">=1.23.5,<2.3" [package.extras] -dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy", "pycodestyle", "pydevtool", "rich-click", "ruff", "types-psutil", "typing_extensions"] -doc = ["jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.12.0)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0)", "sphinx-design (>=0.4.0)"] -test = ["array-api-strict", "asv", "gmpy2", "hypothesis (>=6.30)", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] +dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy (==1.10.0)", "pycodestyle", "pydevtool", "rich-click", "ruff (>=0.0.292)", "types-psutil", "typing_extensions"] +doc = ["jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.13.1)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0)", "sphinx-design (>=0.4.0)"] +test = ["Cython", "array-api-strict", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] [[package]] name = "sentence-transformers" @@ -8347,13 +8350,13 @@ dev = ["pre-commit", "pytest", "ruff (>=0.3.0)"] [[package]] name = "sentry-sdk" -version = "2.6.0" +version = "2.7.0" description = "Python client for Sentry (https://sentry.io)" optional = false python-versions = ">=3.6" files = [ - {file = "sentry_sdk-2.6.0-py2.py3-none-any.whl", hash = "sha256:422b91cb49378b97e7e8d0e8d5a1069df23689d45262b86f54988a7db264e874"}, - {file = "sentry_sdk-2.6.0.tar.gz", hash = "sha256:65cc07e9c6995c5e316109f138570b32da3bd7ff8d0d0ee4aaf2628c3dd8127d"}, + {file = "sentry_sdk-2.7.0-py2.py3-none-any.whl", hash = "sha256:db9594c27a4d21c1ebad09908b1f0dc808ef65c2b89c1c8e7e455143262e37c1"}, + {file = "sentry_sdk-2.7.0.tar.gz", hash = "sha256:d846a211d4a0378b289ced3c434480945f110d0ede00450ba631fc2852e7a0d4"}, ] [package.dependencies] @@ -8385,7 +8388,7 @@ langchain = ["langchain (>=0.0.210)"] loguru = ["loguru (>=0.5)"] openai = ["openai (>=1.0.0)", "tiktoken (>=0.3.0)"] opentelemetry = ["opentelemetry-distro (>=0.35b0)"] -opentelemetry-experimental = ["opentelemetry-distro (>=0.40b0,<1.0)", "opentelemetry-instrumentation-aiohttp-client (>=0.40b0,<1.0)", "opentelemetry-instrumentation-django (>=0.40b0,<1.0)", "opentelemetry-instrumentation-fastapi (>=0.40b0,<1.0)", "opentelemetry-instrumentation-flask (>=0.40b0,<1.0)", "opentelemetry-instrumentation-requests (>=0.40b0,<1.0)", "opentelemetry-instrumentation-sqlite3 (>=0.40b0,<1.0)", "opentelemetry-instrumentation-urllib (>=0.40b0,<1.0)"] +opentelemetry-experimental = ["opentelemetry-instrumentation-aio-pika (==0.46b0)", "opentelemetry-instrumentation-aiohttp-client (==0.46b0)", "opentelemetry-instrumentation-aiopg (==0.46b0)", "opentelemetry-instrumentation-asgi (==0.46b0)", "opentelemetry-instrumentation-asyncio (==0.46b0)", "opentelemetry-instrumentation-asyncpg (==0.46b0)", "opentelemetry-instrumentation-aws-lambda (==0.46b0)", "opentelemetry-instrumentation-boto (==0.46b0)", "opentelemetry-instrumentation-boto3sqs (==0.46b0)", "opentelemetry-instrumentation-botocore (==0.46b0)", "opentelemetry-instrumentation-cassandra (==0.46b0)", "opentelemetry-instrumentation-celery (==0.46b0)", "opentelemetry-instrumentation-confluent-kafka (==0.46b0)", "opentelemetry-instrumentation-dbapi (==0.46b0)", "opentelemetry-instrumentation-django (==0.46b0)", "opentelemetry-instrumentation-elasticsearch (==0.46b0)", "opentelemetry-instrumentation-falcon (==0.46b0)", "opentelemetry-instrumentation-fastapi (==0.46b0)", "opentelemetry-instrumentation-flask (==0.46b0)", "opentelemetry-instrumentation-grpc (==0.46b0)", "opentelemetry-instrumentation-httpx (==0.46b0)", "opentelemetry-instrumentation-jinja2 (==0.46b0)", "opentelemetry-instrumentation-kafka-python (==0.46b0)", "opentelemetry-instrumentation-logging (==0.46b0)", "opentelemetry-instrumentation-mysql (==0.46b0)", "opentelemetry-instrumentation-mysqlclient (==0.46b0)", "opentelemetry-instrumentation-pika (==0.46b0)", "opentelemetry-instrumentation-psycopg (==0.46b0)", "opentelemetry-instrumentation-psycopg2 (==0.46b0)", "opentelemetry-instrumentation-pymemcache (==0.46b0)", "opentelemetry-instrumentation-pymongo (==0.46b0)", "opentelemetry-instrumentation-pymysql (==0.46b0)", "opentelemetry-instrumentation-pyramid (==0.46b0)", "opentelemetry-instrumentation-redis (==0.46b0)", "opentelemetry-instrumentation-remoulade (==0.46b0)", "opentelemetry-instrumentation-requests (==0.46b0)", "opentelemetry-instrumentation-sklearn (==0.46b0)", "opentelemetry-instrumentation-sqlalchemy (==0.46b0)", "opentelemetry-instrumentation-sqlite3 (==0.46b0)", "opentelemetry-instrumentation-starlette (==0.46b0)", "opentelemetry-instrumentation-system-metrics (==0.46b0)", "opentelemetry-instrumentation-threading (==0.46b0)", "opentelemetry-instrumentation-tornado (==0.46b0)", "opentelemetry-instrumentation-tortoiseorm (==0.46b0)", "opentelemetry-instrumentation-urllib (==0.46b0)", "opentelemetry-instrumentation-urllib3 (==0.46b0)", "opentelemetry-instrumentation-wsgi (==0.46b0)"] pure-eval = ["asttokens", "executing", "pure-eval"] pymongo = ["pymongo (>=3.1)"] pyspark = ["pyspark (>=2.4.4)"] @@ -8399,13 +8402,13 @@ tornado = ["tornado (>=5)"] [[package]] name = "setuptools" -version = "70.1.0" +version = "70.1.1" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-70.1.0-py3-none-any.whl", hash = "sha256:d9b8b771455a97c8a9f3ab3448ebe0b29b5e105f1228bba41028be116985a267"}, - {file = "setuptools-70.1.0.tar.gz", hash = "sha256:01a1e793faa5bd89abc851fa15d0a0db26f160890c7102cd8dce643e886b47f5"}, + {file = "setuptools-70.1.1-py3-none-any.whl", hash = "sha256:a58a8fde0541dab0419750bcc521fbdf8585f6e5cb41909df3a472ef7b81ca95"}, + {file = "setuptools-70.1.1.tar.gz", hash = "sha256:937a48c7cdb7a21eb53cd7f9b59e525503aa8abaf3584c730dc5f7a5bec3a650"}, ] [package.extras] @@ -8787,13 +8790,13 @@ files = [ [[package]] name = "tenacity" -version = "8.4.1" +version = "8.4.2" description = "Retry code until it succeeds" optional = false python-versions = ">=3.8" files = [ - {file = "tenacity-8.4.1-py3-none-any.whl", hash = "sha256:28522e692eda3e1b8f5e99c51464efcc0b9fc86933da92415168bc1c4e2308fa"}, - {file = "tenacity-8.4.1.tar.gz", hash = "sha256:54b1412b878ddf7e1f1577cd49527bad8cdef32421bd599beac0c6c3f10582fd"}, + {file = "tenacity-8.4.2-py3-none-any.whl", hash = "sha256:9e6f7cf7da729125c7437222f8a522279751cdfbe6b67bfe64f75d3a348661b2"}, + {file = "tenacity-8.4.2.tar.gz", hash = "sha256:cd80a53a79336edba8489e767f729e4f391c896956b57140b5d7511a64bbd3ef"}, ] [package.extras] @@ -9395,13 +9398,13 @@ urllib3 = ">=2" [[package]] name = "types-setuptools" -version = "70.0.0.20240524" +version = "70.1.0.20240625" description = "Typing stubs for setuptools" optional = false python-versions = ">=3.8" files = [ - {file = "types-setuptools-70.0.0.20240524.tar.gz", hash = "sha256:e31fee7b9d15ef53980526579ac6089b3ae51a005a281acf97178e90ac71aff6"}, - {file = "types_setuptools-70.0.0.20240524-py3-none-any.whl", hash = "sha256:8f5379b9948682d72a9ab531fbe52932e84c4f38deda570255f9bae3edd766bc"}, + {file = "types-setuptools-70.1.0.20240625.tar.gz", hash = "sha256:eb7175c9a304de4de9f4dfd0f299c754ac94cd9e30a262fbb5ff3047a0a6c517"}, + {file = "types_setuptools-70.1.0.20240625-py3-none-any.whl", hash = "sha256:181986729bdae9fa7efc7d37f1578361739e35dd6ec456d37de8e8f3bd2be1ef"}, ] [[package]] @@ -9545,13 +9548,13 @@ six = "*" [[package]] name = "unstructured" -version = "0.14.7" +version = "0.14.8" description = "A library that prepares raw documents for downstream ML tasks." optional = false python-versions = "<3.13,>=3.9.0" files = [ - {file = "unstructured-0.14.7-py3-none-any.whl", hash = "sha256:78e029eb2dd3dc792989af2133cb5472e6a17a501cf415cd8c095f1a88763738"}, - {file = "unstructured-0.14.7.tar.gz", hash = "sha256:219f6ae8a8c5a23e5e6944d3a78d1c7f162ee01e7c6034afe2e5052eef679918"}, + {file = "unstructured-0.14.8-py3-none-any.whl", hash = "sha256:eb97a0754d9f1a90134af45e4ee2e17f12aced57fda4f73ca4875090fef396a5"}, + {file = "unstructured-0.14.8.tar.gz", hash = "sha256:2a39fd2e92a986c45f9686b1115cce56a022d2600a1aae67b8e09eb0373d85b3"}, ] [package.dependencies] @@ -9580,7 +9583,7 @@ wrapt = "*" [package.extras] airtable = ["pyairtable"] -all-docs = ["effdet", "google-cloud-vision", "markdown", "networkx", "onnx", "openpyxl", "pandas", "pdf2image", "pdfminer.six", "pikepdf", "pillow-heif", "pypandoc", "pypdf", "pytesseract", "python-docx (>=1.1.2)", "python-oxmsg", "python-pptx (<=0.6.23)", "unstructured-inference (==0.7.35)", "unstructured.pytesseract (>=0.3.12)", "xlrd"] +all-docs = ["effdet", "google-cloud-vision", "markdown", "networkx", "onnx", "openpyxl", "pandas", "pdf2image", "pdfminer.six", "pikepdf", "pillow-heif", "pypandoc", "pypdf", "pytesseract", "python-docx (>=1.1.2)", "python-oxmsg", "python-pptx (<=0.6.23)", "unstructured-inference (==0.7.36)", "unstructured.pytesseract (>=0.3.12)", "xlrd"] astra = ["astrapy"] azure = ["adlfs", "fsspec"] azure-cognitive-search = ["azure-search-documents"] @@ -9609,9 +9612,10 @@ gitlab = ["python-gitlab"] google-drive = ["google-api-python-client"] hubspot = ["hubspot-api-client", "urllib3"] huggingface = ["langdetect", "sacremoses", "sentencepiece", "torch", "transformers"] -image = ["effdet", "google-cloud-vision", "onnx", "pdf2image", "pdfminer.six", "pikepdf", "pillow-heif", "pypdf", "pytesseract", "unstructured-inference (==0.7.35)", "unstructured.pytesseract (>=0.3.12)"] +image = ["effdet", "google-cloud-vision", "onnx", "pdf2image", "pdfminer.six", "pikepdf", "pillow-heif", "pypdf", "pytesseract", "unstructured-inference (==0.7.36)", "unstructured.pytesseract (>=0.3.12)"] jira = ["atlassian-python-api"] -local-inference = ["effdet", "google-cloud-vision", "markdown", "networkx", "onnx", "openpyxl", "pandas", "pdf2image", "pdfminer.six", "pikepdf", "pillow-heif", "pypandoc", "pypdf", "pytesseract", "python-docx (>=1.1.2)", "python-oxmsg", "python-pptx (<=0.6.23)", "unstructured-inference (==0.7.35)", "unstructured.pytesseract (>=0.3.12)", "xlrd"] +kafka = ["confluent-kafka"] +local-inference = ["effdet", "google-cloud-vision", "markdown", "networkx", "onnx", "openpyxl", "pandas", "pdf2image", "pdfminer.six", "pikepdf", "pillow-heif", "pypandoc", "pypdf", "pytesseract", "python-docx (>=1.1.2)", "python-oxmsg", "python-pptx (<=0.6.23)", "unstructured-inference (==0.7.36)", "unstructured.pytesseract (>=0.3.12)", "xlrd"] md = ["markdown"] mongodb = ["pymongo"] msg = ["python-oxmsg"] @@ -9623,7 +9627,7 @@ opensearch = ["opensearch-py"] org = ["pypandoc"] outlook = ["Office365-REST-Python-Client", "msal"] paddleocr = ["unstructured.paddleocr (==2.6.1.3)"] -pdf = ["effdet", "google-cloud-vision", "onnx", "pdf2image", "pdfminer.six", "pikepdf", "pillow-heif", "pypdf", "pytesseract", "unstructured-inference (==0.7.35)", "unstructured.pytesseract (>=0.3.12)"] +pdf = ["effdet", "google-cloud-vision", "onnx", "pdf2image", "pdfminer.six", "pikepdf", "pillow-heif", "pypdf", "pytesseract", "unstructured-inference (==0.7.36)", "unstructured.pytesseract (>=0.3.12)"] pinecone = ["pinecone-client (>=3.7.1)"] postgres = ["psycopg2-binary"] ppt = ["python-pptx (<=0.6.23)"] @@ -10551,4 +10555,4 @@ local = ["ctransformers", "llama-cpp-python", "sentence-transformers"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.13" -content-hash = "f7377e3a997651cbcec2b9227b0bcde2507afc7d6236b708f4dc62857f150578" +content-hash = "3e72b6faa1c674615a7e5dec3e7d962349e736bf6675c08a49080b7f336cc75b" diff --git a/pyproject.toml b/pyproject.toml index 1275c54ed..5e3744a89 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langflow" -version = "1.0.0rc1" +version = "1.0.5" description = "A Python package with a built-in web application" authors = ["Langflow "] maintainers = [ @@ -92,6 +92,7 @@ unstructured = {extras = ["docx", "md", "pptx"], version = "^0.14.4"} langchain-aws = "^0.1.6" langchain-mongodb = "^0.1.6" kubernetes = "^30.1.0" +firecrawl-py = "^0.0.16" [tool.poetry.group.dev.dependencies] @@ -146,11 +147,33 @@ ignore-regex = '.*(Stati Uniti|Tense=Pres).*' minversion = "6.0" testpaths = ["tests", "integration"] console_output_style = "progress" -filterwarnings = ["ignore::DeprecationWarning"] +filterwarnings = ["ignore::DeprecationWarning", "ignore::ResourceWarning"] log_cli = true markers = ["async_test", "api_key_required"] +[tool.coverage.run] +command_line = """ + -m pytest + --cov --cov-report=term --cov-report=html + --instafail -ra -n auto -m "not api_key_required" + tests/unit +""" +source = ["src/backend/base/langflow/"] +omit = ["*/alembic/*", "tests/*", "*/__init__.py"] + + +[tool.coverage.report] +sort = "Stmts" +skip_empty = true +show_missing = false +ignore_errors = true + + +[tool.coverage.html] +directory = "coverage" + + [tool.ruff] exclude = ["src/backend/langflow/alembic/*"] line-length = 120 diff --git a/src/backend/base/langflow/__main__.py b/src/backend/base/langflow/__main__.py index 730d31ea7..256b614c2 100644 --- a/src/backend/base/langflow/__main__.py +++ b/src/backend/base/langflow/__main__.py @@ -4,12 +4,12 @@ import sys import time import warnings from pathlib import Path -from typing import Optional +from typing import Any, Callable, Optional import click import httpx import typer -from dotenv import load_dotenv +from dotenv import dotenv_values, load_dotenv from multiprocess import Process, cpu_count # type: ignore from packaging import version as pkg_version from rich import box @@ -130,6 +130,29 @@ def run( if env_file: load_dotenv(env_file, override=True) + env_vars = dotenv_values(env_file) + + # Define a mapping of environment variables to their corresponding variables and types + env_var_mapping: dict[str, tuple[str, type | Callable[[Any], bool]]] = { + "LANGFLOW_HOST": ("host", str), + "LANGFLOW_PORT": ("port", int), + "LANGFLOW_WORKERS": ("workers", int), + "LANGFLOW_WORKER_TIMEOUT": ("timeout", int), + "LANGFLOW_COMPONENTS_PATH": ("components_path", Path), + "LANGFLOW_LOG_LEVEL": ("log_level", str), + "LANGFLOW_LOG_FILE": ("log_file", Path), + "LANGFLOW_LANGCHAIN_CACHE": ("cache", str), + "LANGFLOW_FRONTEND_PATH": ("path", str), + "LANGFLOW_OPEN_BROWSER": ("open_browser", lambda x: x.lower() == "true"), + "LANGFLOW_REMOVE_API_KEYS": ("remove_api_keys", lambda x: x.lower() == "true"), + "LANGFLOW_BACKEND_ONLY": ("backend_only", lambda x: x.lower() == "true"), + "LANGFLOW_STORE": ("store", lambda x: x.lower() == "true"), + } + + # Update variables based on environment variables + for env_var, (var_name, var_type) in env_var_mapping.items(): + if env_var in env_vars: + locals()[var_name] = var_type(env_vars[env_var]) update_settings( dev=dev, diff --git a/src/backend/base/langflow/alembic/versions/b2fa308044b5_add_unique_constraints.py b/src/backend/base/langflow/alembic/versions/b2fa308044b5_add_unique_constraints.py index ed5317bf5..11ba1a113 100644 --- a/src/backend/base/langflow/alembic/versions/b2fa308044b5_add_unique_constraints.py +++ b/src/backend/base/langflow/alembic/versions/b2fa308044b5_add_unique_constraints.py @@ -11,6 +11,7 @@ from typing import Sequence, Union import sqlalchemy as sa import sqlmodel from alembic import op +from loguru import logger # noqa from sqlalchemy.engine.reflection import Inspector # revision identifiers, used by Alembic. @@ -46,9 +47,9 @@ def upgrade() -> None: if "fk_flow_user_id_user" not in indices_names: batch_op.create_foreign_key("fk_flow_user_id_user", "user", ["user_id"], ["id"]) - except Exception: + except Exception as e: + logger.exception(f"Error during upgrade: {e}") pass - # ### end Alembic commands ### def downgrade() -> None: diff --git a/src/backend/base/langflow/alembic/versions/d066bfd22890_add_message_table.py b/src/backend/base/langflow/alembic/versions/d066bfd22890_add_message_table.py new file mode 100644 index 000000000..dd63398b7 --- /dev/null +++ b/src/backend/base/langflow/alembic/versions/d066bfd22890_add_message_table.py @@ -0,0 +1,52 @@ +"""Add message table + +Revision ID: 325180f0c4e1 +Revises: 631faacf5da2 +Create Date: 2024-06-23 21:29:28.220100 + +""" + +from typing import Sequence, Union + +import sqlalchemy as sa +import sqlmodel +from alembic import op + +from langflow.utils import migration + +# revision identifiers, used by Alembic. +revision: str = "325180f0c4e1" +down_revision: Union[str, None] = "631faacf5da2" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + conn = op.get_bind() + # ### commands auto generated by Alembic - please adjust! ### + if not migration.table_exists("message", conn): + op.create_table( + "message", + sa.Column("timestamp", sa.DateTime(), nullable=False), + sa.Column("sender", sqlmodel.sql.sqltypes.AutoString(), nullable=False), + sa.Column("sender_name", sqlmodel.sql.sqltypes.AutoString(), nullable=False), + sa.Column("session_id", sqlmodel.sql.sqltypes.AutoString(), nullable=False), + sa.Column("text", sqlmodel.sql.sqltypes.AutoString(), nullable=False), + sa.Column("id", sqlmodel.sql.sqltypes.GUID(), nullable=False), + sa.Column("flow_id", sqlmodel.sql.sqltypes.GUID(), nullable=True), + sa.Column("files", sa.JSON(), nullable=True), + sa.ForeignKeyConstraint( + ["flow_id"], + ["flow.id"], + ), + sa.PrimaryKeyConstraint("id"), + ) + # ### end Alembic commands ### + + +def downgrade() -> None: + conn = op.get_bind() + # ### commands auto generated by Alembic - please adjust! ### + if migration.table_exists("message", conn): + op.drop_table("message") + # ### end Alembic commands ### diff --git a/src/backend/base/langflow/api/v1/chat.py b/src/backend/base/langflow/api/v1/chat.py index dc44d498b..e19342568 100644 --- a/src/backend/base/langflow/api/v1/chat.py +++ b/src/backend/base/langflow/api/v1/chat.py @@ -121,9 +121,9 @@ async def retrieve_vertices_order( background_tasks.add_task( telemetry_service.log_package_playground, PlaygroundPayload( - seconds=int(time.perf_counter() - start_time), - componentCount=components_count, - success=True, + playgroundSeconds=int(time.perf_counter() - start_time), + playgroundComponentCount=components_count, + playgroundSuccess=True, ), ) return VerticesOrderResponse(ids=first_layer, run_id=graph._run_id, vertices_to_run=vertices_to_run) @@ -131,10 +131,10 @@ async def retrieve_vertices_order( background_tasks.add_task( telemetry_service.log_package_playground, PlaygroundPayload( - seconds=int(time.perf_counter() - start_time), - componentCount=components_count, - success=False, - errorMessage=str(exc), + playgroundSeconds=int(time.perf_counter() - start_time), + playgroundComponentCount=components_count, + playgroundSuccess=False, + playgroundErrorMessage=str(exc), ), ) if "stream or streaming set to True" in str(exc): @@ -280,10 +280,10 @@ async def build_vertex( background_tasks.add_task( telemetry_service.log_package_component, ComponentPayload( - name=vertex_id, - seconds=int(time.perf_counter() - start_time), - success=valid, - errorMessage=params, + componentName=vertex_id, + componentSeconds=int(time.perf_counter() - start_time), + componentSuccess=valid, + componentErrorMessage=params, ), ) return build_response @@ -291,10 +291,10 @@ async def build_vertex( background_tasks.add_task( telemetry_service.log_package_component, ComponentPayload( - name=vertex_id, - seconds=int(time.perf_counter() - start_time), - success=False, - errorMessage=str(exc), + componentName=vertex_id, + componentSeconds=int(time.perf_counter() - start_time), + componentSuccess=False, + componentErrorMessage=str(exc), ), ) logger.error(f"Error building Component:\n\n{exc}") diff --git a/src/backend/base/langflow/api/v1/endpoints.py b/src/backend/base/langflow/api/v1/endpoints.py index e5c648d1f..35a8f6637 100644 --- a/src/backend/base/langflow/api/v1/endpoints.py +++ b/src/backend/base/langflow/api/v1/endpoints.py @@ -116,11 +116,29 @@ async def simple_run_flow( return RunResponse(outputs=task_result, session_id=session_id) except sa.exc.StatementError as exc: - # StatementError('(builtins.ValueError) badly formed hexadecimal UUID string') - if "badly formed hexadecimal UUID string" in str(exc): - logger.error(f"Flow ID {flow_id_str} is not a valid UUID") - # This means the Flow ID is not a valid UUID which means it can't find the flow - raise ValueError(str(exc)) from exc + raise ValueError(str(exc)) from exc + + +async def simple_run_flow_task( + flow: Flow, + input_request: SimplifiedAPIRequest, + stream: bool = False, + api_key_user: Optional[User] = None, +): + """ + Run a flow task as a BackgroundTask, therefore it should not throw exceptions. + """ + try: + result = await simple_run_flow( + flow=flow, + input_request=input_request, + stream=stream, + api_key_user=api_key_user, + ) + return result + + except Exception as exc: + logger.exception(f"Error running flow {flow.id} task: {exc}") @router.post("/run/{flow_id_or_name}", response_model=RunResponse, response_model_exclude_none=True) @@ -191,7 +209,7 @@ async def simplified_run_flow( end_time = time.perf_counter() background_tasks.add_task( telemetry_service.log_package_run, - RunPayload(IsWebhook=False, seconds=int(end_time - start_time), success=True, errorMessage=""), + RunPayload(runIsWebhook=False, runSeconds=int(end_time - start_time), runSuccess=True, runErrorMessage=""), ) return result @@ -199,7 +217,9 @@ async def simplified_run_flow( end_time = time.perf_counter() background_tasks.add_task( telemetry_service.log_package_run, - RunPayload(IsWebhook=False, seconds=int(end_time - start_time), success=False, errorMessage=str(exc)), + RunPayload( + runIsWebhook=False, runSeconds=int(end_time - start_time), runSuccess=False, runErrorMessage=str(exc) + ), ) if "badly formed hexadecimal UUID string" in str(exc): # This means the Flow ID is not a valid UUID which means it can't find the flow @@ -213,7 +233,9 @@ async def simplified_run_flow( logger.exception(exc) background_tasks.add_task( telemetry_service.log_package_run, - RunPayload(IsWebhook=False, seconds=int(end_time - start_time), success=False, errorMessage=str(exc)), + RunPayload( + runIsWebhook=False, runSeconds=int(end_time - start_time), runSuccess=False, runErrorMessage=str(exc) + ), ) raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(exc)) from exc @@ -254,32 +276,37 @@ async def webhook_run_flow( # get all webhook components in the flow webhook_components = get_all_webhook_components_in_flow(flow.data) tweaks = {} - data_dict = await request.json() + for component in webhook_components: tweaks[component["id"]] = {"data": data.decode() if isinstance(data, bytes) else data} input_request = SimplifiedAPIRequest( - input_value=data_dict.get("input_value", ""), - input_type=data_dict.get("input_type", "chat"), - output_type=data_dict.get("output_type", "chat"), + input_value="", + input_type="chat", + output_type="chat", tweaks=tweaks, - session_id=data_dict.get("session_id"), + session_id=None, ) logger.debug("Starting background task") background_tasks.add_task( # type: ignore - simple_run_flow, + simple_run_flow_task, flow=flow, input_request=input_request, ) background_tasks.add_task( telemetry_service.log_package_run, - RunPayload(IsWebhook=True, seconds=int(time.perf_counter() - start_time), success=True, errorMessage=""), + RunPayload( + runIsWebhook=True, runSeconds=int(time.perf_counter() - start_time), runSuccess=True, runErrorMessage="" + ), ) return {"message": "Task started in the background", "status": "in progress"} except Exception as exc: background_tasks.add_task( telemetry_service.log_package_run, RunPayload( - IsWebhook=True, seconds=int(time.perf_counter() - start_time), success=False, errorMessage=str(exc) + runIsWebhook=True, + runSeconds=int(time.perf_counter() - start_time), + runSuccess=False, + runErrorMessage=str(exc), ), ) if "Flow ID is required" in str(exc) or "Request body is empty" in str(exc): diff --git a/src/backend/base/langflow/api/v1/files.py b/src/backend/base/langflow/api/v1/files.py index a96397e08..1e3d828b2 100644 --- a/src/backend/base/langflow/api/v1/files.py +++ b/src/backend/base/langflow/api/v1/files.py @@ -131,8 +131,8 @@ async def list_profile_pictures(storage_service: StorageService = Depends(get_st people = await storage_service.list_files(flow_id=people_path) # type: ignore space = await storage_service.list_files(flow_id=space_path) # type: ignore - files = [Path("People") / i for i in people] - files += [Path("Space") / i for i in space] + files = [f"People/{i}" for i in people] + files += [f"Space/{i}" for i in space] return {"files": files} diff --git a/src/backend/base/langflow/api/v1/flows.py b/src/backend/base/langflow/api/v1/flows.py index 800e2c088..e01af05ac 100644 --- a/src/backend/base/langflow/api/v1/flows.py +++ b/src/backend/base/langflow/api/v1/flows.py @@ -1,3 +1,4 @@ +import re from datetime import datetime, timezone from typing import List from uuid import UUID @@ -46,8 +47,14 @@ def create_flow( select(Flow).where(Flow.name.like(f"{flow.name} (%")).where(Flow.user_id == current_user.id) # type: ignore ).all() if flows: - numbers = [int(flow.name.split("(")[1].split(")")[0]) for flow in flows] - flow.name = f"{flow.name} ({max(numbers) + 1})" + extract_number = re.compile(r"\((\d+)\)$") + numbers = [] + for _flow in flows: + result = extract_number.search(_flow.name) + if result: + numbers.append(int(result.groups(1)[0])) + if numbers: + flow.name = f"{flow.name} ({max(numbers) + 1})" else: flow.name = f"{flow.name} (1)" # Now check if the endpoint is unique @@ -204,11 +211,11 @@ def update_flow( if settings_service.settings.remove_api_keys: flow_data = remove_api_keys(flow_data) for key, value in flow_data.items(): - if value is not None: - setattr(db_flow, key, value) + setattr(db_flow, key, value) webhook_component = get_webhook_component_in_flow(db_flow.data) db_flow.webhook = webhook_component is not None db_flow.updated_at = datetime.now(timezone.utc) + if db_flow.folder_id is None: default_folder = session.exec(select(Folder).where(Folder.name == DEFAULT_FOLDER_NAME)).first() if default_folder: diff --git a/src/backend/base/langflow/api/v1/monitor.py b/src/backend/base/langflow/api/v1/monitor.py index a99c86bf8..f6c1fc4ac 100644 --- a/src/backend/base/langflow/api/v1/monitor.py +++ b/src/backend/base/langflow/api/v1/monitor.py @@ -1,15 +1,15 @@ from typing import List, Optional - +from uuid import UUID from fastapi import APIRouter, Depends, HTTPException, Query +from sqlalchemy import delete +from sqlmodel import Session, col, select -from langflow.services.deps import get_monitor_service -from langflow.services.monitor.schema import ( - MessageModelRequest, - MessageModelResponse, - TransactionModelResponse, - VertexBuildMapModel, -) +from langflow.services.auth.utils import get_current_active_user +from langflow.services.database.models.message.model import MessageRead, MessageTable, MessageUpdate +from langflow.services.database.models.user.model import User +from langflow.services.deps import get_monitor_service, get_session +from langflow.services.monitor.schema import MessageModelResponse, TransactionModelResponse, VertexBuildMapModel from langflow.services.monitor.service import MonitorService router = APIRouter(prefix="/monitor", tags=["Monitor"]) @@ -52,45 +52,58 @@ async def get_messages( sender: Optional[str] = Query(None), sender_name: Optional[str] = Query(None), order_by: Optional[str] = Query("timestamp"), - monitor_service: MonitorService = Depends(get_monitor_service), + session: Session = Depends(get_session), ): try: - df = monitor_service.get_messages( - flow_id=flow_id, - sender=sender, - sender_name=sender_name, - session_id=session_id, - order_by=order_by, - ) - dicts = df.to_dict(orient="records") - return [MessageModelResponse(**d) for d in dicts] + stmt = select(MessageTable) + if flow_id: + stmt = stmt.where(MessageTable.flow_id == flow_id) + if session_id: + stmt = stmt.where(MessageTable.session_id == session_id) + if sender: + stmt = stmt.where(MessageTable.sender == sender) + if sender_name: + stmt = stmt.where(MessageTable.sender_name == sender_name) + if order_by: + col = getattr(MessageTable, order_by).asc() + stmt = stmt.order_by(col) + messages = session.exec(stmt) + return [MessageModelResponse.model_validate(d, from_attributes=True) for d in messages] except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @router.delete("/messages", status_code=204) async def delete_messages( - message_ids: List[int], - monitor_service: MonitorService = Depends(get_monitor_service), + message_ids: List[UUID], + session: Session = Depends(get_session), + current_user: User = Depends(get_current_active_user), ): try: - monitor_service.delete_messages(message_ids=message_ids) + session.exec(select(MessageTable).where(MessageTable.id.in_(message_ids))) # type: ignore except Exception as e: raise HTTPException(status_code=500, detail=str(e)) -@router.post("/messages/{message_id}", response_model=MessageModelResponse) +@router.put("/messages/{message_id}", response_model=MessageRead) async def update_message( - message_id: int, - message: MessageModelRequest, - monitor_service: MonitorService = Depends(get_monitor_service), + message_id: UUID, + message: MessageUpdate, + session: Session = Depends(get_session), + user: User = Depends(get_current_active_user), ): try: - message_dict = message.model_dump(exclude_none=True) - message_dict.pop("index", None) - monitor_service.update_message(message_id=message_id, **message_dict) # type: ignore - return MessageModelResponse(index=message_id, **message_dict) - + db_message = session.get(MessageTable, message_id) + if not db_message: + raise HTTPException(status_code=404, detail="Message not found") + message_dict = message.model_dump(exclude_unset=True, exclude_none=True) + db_message.sqlmodel_update(message_dict) + session.add(db_message) + session.commit() + session.refresh(db_message) + return db_message + except HTTPException as e: + raise e except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @@ -98,10 +111,16 @@ async def update_message( @router.delete("/messages/session/{session_id}", status_code=204) async def delete_messages_session( session_id: str, - monitor_service: MonitorService = Depends(get_monitor_service), + session: Session = Depends(get_session), ): try: - monitor_service.delete_messages_session(session_id=session_id) + session.exec( # type: ignore + delete(MessageTable) + .where(col(MessageTable.session_id) == session_id) + .execution_options(synchronize_session="fetch") + ) + session.commit() + return {"message": "Messages deleted successfully"} except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @@ -137,4 +156,3 @@ async def get_transactions( return result except Exception as e: raise HTTPException(status_code=500, detail=str(e)) - raise HTTPException(status_code=500, detail=str(e)) diff --git a/src/backend/base/langflow/base/models/model.py b/src/backend/base/langflow/base/models/model.py index 81f124fd7..bea9c88d8 100644 --- a/src/backend/base/langflow/base/models/model.py +++ b/src/backend/base/langflow/base/models/model.py @@ -119,7 +119,11 @@ class LCModelComponent(Component): return status_message def get_chat_result( - self, runnable: LanguageModel, stream: bool, input_value: str | Message, system_message: Optional[str] = None + self, + runnable: LanguageModel, + stream: bool, + input_value: str | Message, + system_message: Optional[str] = None, ): messages: list[Union[BaseMessage]] = [] if not input_value and not system_message: diff --git a/src/backend/base/langflow/components/agents/ToolCallingAgent.py b/src/backend/base/langflow/components/agents/ToolCallingAgent.py index 8c08d489b..407ab333d 100644 --- a/src/backend/base/langflow/components/agents/ToolCallingAgent.py +++ b/src/backend/base/langflow/components/agents/ToolCallingAgent.py @@ -1,4 +1,4 @@ -from typing import List, cast +from typing import Dict, List, cast from langchain.agents import AgentExecutor, BaseSingleActionAgent from langchain.agents.tool_calling_agent.base import create_tool_calling_agent @@ -14,6 +14,7 @@ class ToolCallingAgentComponent(Component): display_name: str = "Tool Calling Agent" description: str = "Agent that uses tools. Only models that are compatible with function calling are supported." icon = "LangChain" + beta = True inputs = [ MessageTextInput( @@ -85,7 +86,7 @@ class ToolCallingAgentComponent(Component): verbose=True, handle_parsing_errors=self.handle_parsing_errors, ) - input_dict: dict[str, str | list[dict[str, str]]] = {"input": self.input_value} + input_dict: dict[str, str | list[Dict[str, str]]] = {"input": self.input_value} if hasattr(self, "memory") and self.memory: input_dict["chat_history"] = self.convert_chat_history(self.memory) result = await runnable.ainvoke(input_dict) @@ -98,7 +99,7 @@ class ToolCallingAgentComponent(Component): return Message(text=result_string) - def convert_chat_history(self, chat_history: List[Data]) -> List[dict[str, str]]: + def convert_chat_history(self, chat_history: List[Data]) -> List[Dict[str, str]]: messages = [] for item in chat_history: role = "user" if item.sender == "User" else "assistant" diff --git a/src/backend/base/langflow/components/experimental/AgentComponent.py b/src/backend/base/langflow/components/deactivated/AgentComponent.py similarity index 100% rename from src/backend/base/langflow/components/experimental/AgentComponent.py rename to src/backend/base/langflow/components/deactivated/AgentComponent.py diff --git a/src/backend/base/langflow/components/models/ChatLiteLLMModel.py b/src/backend/base/langflow/components/deactivated/ChatLiteLLMModel.py similarity index 99% rename from src/backend/base/langflow/components/models/ChatLiteLLMModel.py rename to src/backend/base/langflow/components/deactivated/ChatLiteLLMModel.py index e43854bc7..cd487c4a0 100644 --- a/src/backend/base/langflow/components/models/ChatLiteLLMModel.py +++ b/src/backend/base/langflow/components/deactivated/ChatLiteLLMModel.py @@ -22,7 +22,7 @@ class ChatLiteLLMModelComponent(LCModelComponent): display_name = "LiteLLM" description = "`LiteLLM` collection of large language models." documentation = "https://python.langchain.com/docs/integrations/chat/litellm" - icon = "LiteLLM" + icon = "🚄" inputs = [ MessageInput(name="input_value", display_name="Input"), diff --git a/src/backend/base/langflow/components/helpers/CodeBlockExtractor.py b/src/backend/base/langflow/components/deactivated/CodeBlockExtractor.py similarity index 100% rename from src/backend/base/langflow/components/helpers/CodeBlockExtractor.py rename to src/backend/base/langflow/components/deactivated/CodeBlockExtractor.py diff --git a/src/backend/base/langflow/components/helpers/DocumentsToData.py b/src/backend/base/langflow/components/deactivated/DocumentsToData.py similarity index 100% rename from src/backend/base/langflow/components/helpers/DocumentsToData.py rename to src/backend/base/langflow/components/deactivated/DocumentsToData.py diff --git a/src/backend/base/langflow/components/experimental/Embed.py b/src/backend/base/langflow/components/deactivated/Embed.py similarity index 100% rename from src/backend/base/langflow/components/experimental/Embed.py rename to src/backend/base/langflow/components/deactivated/Embed.py diff --git a/src/backend/base/langflow/components/experimental/ExtractKeyFromData.py b/src/backend/base/langflow/components/deactivated/ExtractKeyFromData.py similarity index 100% rename from src/backend/base/langflow/components/experimental/ExtractKeyFromData.py rename to src/backend/base/langflow/components/deactivated/ExtractKeyFromData.py diff --git a/src/backend/base/langflow/components/experimental/ListFlows.py b/src/backend/base/langflow/components/deactivated/ListFlows.py similarity index 100% rename from src/backend/base/langflow/components/experimental/ListFlows.py rename to src/backend/base/langflow/components/deactivated/ListFlows.py diff --git a/src/backend/base/langflow/components/experimental/MergeData.py b/src/backend/base/langflow/components/deactivated/MergeData.py similarity index 100% rename from src/backend/base/langflow/components/experimental/MergeData.py rename to src/backend/base/langflow/components/deactivated/MergeData.py diff --git a/src/backend/base/langflow/components/experimental/Message.py b/src/backend/base/langflow/components/deactivated/Message.py similarity index 100% rename from src/backend/base/langflow/components/experimental/Message.py rename to src/backend/base/langflow/components/deactivated/Message.py diff --git a/src/backend/base/langflow/components/experimental/SelectivePassThrough.py b/src/backend/base/langflow/components/deactivated/SelectivePassThrough.py similarity index 100% rename from src/backend/base/langflow/components/experimental/SelectivePassThrough.py rename to src/backend/base/langflow/components/deactivated/SelectivePassThrough.py diff --git a/src/backend/base/langflow/components/helpers/ShouldRunNext.py b/src/backend/base/langflow/components/deactivated/ShouldRunNext.py similarity index 100% rename from src/backend/base/langflow/components/helpers/ShouldRunNext.py rename to src/backend/base/langflow/components/deactivated/ShouldRunNext.py diff --git a/src/backend/base/langflow/components/experimental/SplitText.py b/src/backend/base/langflow/components/deactivated/SplitText.py similarity index 100% rename from src/backend/base/langflow/components/experimental/SplitText.py rename to src/backend/base/langflow/components/deactivated/SplitText.py diff --git a/src/backend/base/langflow/components/experimental/StoreMessage.py b/src/backend/base/langflow/components/deactivated/StoreMessage.py similarity index 100% rename from src/backend/base/langflow/components/experimental/StoreMessage.py rename to src/backend/base/langflow/components/deactivated/StoreMessage.py diff --git a/src/backend/base/langflow/components/experimental/SubFlow.py b/src/backend/base/langflow/components/deactivated/SubFlow.py similarity index 100% rename from src/backend/base/langflow/components/experimental/SubFlow.py rename to src/backend/base/langflow/components/deactivated/SubFlow.py diff --git a/src/backend/base/langflow/components/experimental/__init__.py b/src/backend/base/langflow/components/deactivated/__init__.py similarity index 61% rename from src/backend/base/langflow/components/experimental/__init__.py rename to src/backend/base/langflow/components/deactivated/__init__.py index 28cf78d1b..51ef2e465 100644 --- a/src/backend/base/langflow/components/experimental/__init__.py +++ b/src/backend/base/langflow/components/deactivated/__init__.py @@ -1,17 +1,8 @@ from .AgentComponent import AgentComponent -from .ConditionalRouter import ConditionalRouterComponent from .ExtractKeyFromData import ExtractKeyFromDataComponent -from .FlowTool import FlowToolComponent -from .Listen import ListenComponent from .ListFlows import ListFlowsComponent from .MergeData import MergeDataComponent -from .Notify import NotifyComponent -from .PythonFunction import PythonFunctionComponent -from .RunFlow import RunFlowComponent -from .RunnableExecutor import RunnableExecComponent from .SelectivePassThrough import SelectivePassThroughComponent -from .SplitText import SplitTextComponent -from .SQLExecutor import SQLExecutorComponent from .SubFlow import SubFlowComponent __all__ = [ @@ -25,7 +16,6 @@ __all__ = [ "NotifyComponent", "PythonFunctionComponent", "RunFlowComponent", - "RunnableExecComponent", "SplitTextComponent", "SQLExecutorComponent", "SubFlowComponent", diff --git a/src/backend/base/langflow/components/embeddings/AstraVectorize.py b/src/backend/base/langflow/components/embeddings/AstraVectorize.py index f098828a1..cd618f346 100644 --- a/src/backend/base/langflow/components/embeddings/AstraVectorize.py +++ b/src/backend/base/langflow/components/embeddings/AstraVectorize.py @@ -1,6 +1,6 @@ from typing import Any from langflow.custom import Component -from langflow.inputs.inputs import DictInput, SecretStrInput, StrInput, MessageTextInput +from langflow.inputs.inputs import DictInput, SecretStrInput, MessageTextInput, DropdownInput from langflow.template.field.base import Output @@ -10,34 +10,79 @@ class AstraVectorize(Component): documentation: str = "https://docs.datastax.com/en/astra-db-serverless/databases/embedding-generation.html" icon = "AstraDB" + VECTORIZE_PROVIDERS_MAPPING = { + "Azure OpenAI": ["azureOpenAI", ["text-embedding-3-small", "text-embedding-3-large", "text-embedding-ada-002"]], + "Hugging Face - Dedicated": ["huggingfaceDedicated", ["endpoint-defined-model"]], + "Hugging Face - Serverless": [ + "huggingface", + [ + "sentence-transformers/all-MiniLM-L6-v2", + "intfloat/multilingual-e5-large", + "intfloat/multilingual-e5-large-instruct", + "BAAI/bge-small-en-v1.5", + "BAAI/bge-base-en-v1.5", + "BAAI/bge-large-en-v1.5", + ], + ], + "Jina AI": [ + "jinaAI", + [ + "jina-embeddings-v2-base-en", + "jina-embeddings-v2-base-de", + "jina-embeddings-v2-base-es", + "jina-embeddings-v2-base-code", + "jina-embeddings-v2-base-zh", + ], + ], + "Mistral AI": ["mistral", ["mistral-embed"]], + "NVIDIA": ["nvidia", ["NV-Embed-QA"]], + "OpenAI": ["openai", ["text-embedding-3-small", "text-embedding-3-large", "text-embedding-ada-002"]], + "Upstage": ["upstageAI", ["solar-embedding-1-large"]], + "Voyage AI": [ + "voyageAI", + ["voyage-large-2-instruct", "voyage-law-2", "voyage-code-2", "voyage-large-2", "voyage-2"], + ], + } + VECTORIZE_MODELS_STR = "\n\n".join( + [provider + ": " + (", ".join(models[1])) for provider, models in VECTORIZE_PROVIDERS_MAPPING.items()] + ) + inputs = [ - MessageTextInput( + DropdownInput( name="provider", display_name="Provider name", - info='The embedding provider to use.', + options=VECTORIZE_PROVIDERS_MAPPING.keys(), + value="", ), MessageTextInput( name="model_name", display_name="Model name", - info='The embedding model to use.', + info=f"The embedding model to use for the selected provider. Each provider has a different set of models " + f"available (full list at https://docs.datastax.com/en/astra-db-serverless/databases/embedding-generation.html):\n\n{VECTORIZE_MODELS_STR}", + required=True, + ), + MessageTextInput( + name="api_key_name", + display_name="API Key name", + info="The name of the embeddings provider API key stored on Astra. If set, it will override the 'ProviderKey' in the authentication parameters.", ), DictInput( name="authentication", - display_name="Authentication", - info='Authentication parameters. Use the Astra Portal to add the embedding provider integration to your Astra organization.', - is_list=True + display_name="Authentication parameters", + is_list=True, + advanced=True, ), SecretStrInput( name="provider_api_key", display_name="Provider API Key", - info='An alternative to the Astra Authentication that let you use directly the API key of the provider.' + info="An alternative to the Astra Authentication that let you use directly the API key of the provider.", + advanced=True, ), DictInput( name="model_parameters", display_name="Model parameters", - info='Additional model parameters.', advanced=True, - is_list=True + is_list=True, ), ] outputs = [ @@ -45,13 +90,18 @@ class AstraVectorize(Component): ] def build_options(self) -> dict[str, Any]: + provider_value = self.VECTORIZE_PROVIDERS_MAPPING[self.provider][0] + authentication = {**self.authentication} + api_key_name = self.api_key_name + if api_key_name: + authentication["providerKey"] = api_key_name return { # must match exactly astra CollectionVectorServiceOptions "collection_vector_service_options": { - "provider": self.provider, + "provider": provider_value, "modelName": self.model_name, - "authentication": self.authentication, - "parameters": self.model_parameters + "authentication": authentication, + "parameters": self.model_parameters, }, - "collection_embedding_api_key": self.provider_api_key + "collection_embedding_api_key": self.provider_api_key, } diff --git a/src/backend/base/langflow/components/embeddings/OllamaEmbeddings.py b/src/backend/base/langflow/components/embeddings/OllamaEmbeddings.py index 430a8de29..103ca3f1b 100644 --- a/src/backend/base/langflow/components/embeddings/OllamaEmbeddings.py +++ b/src/backend/base/langflow/components/embeddings/OllamaEmbeddings.py @@ -25,6 +25,7 @@ class OllamaEmbeddingsComponent(LCModelComponent): FloatInput( name="temperature", display_name="Model Temperature", + value=0.1, advanced=True, ), ] diff --git a/src/backend/base/langflow/components/helpers/FilterData.py b/src/backend/base/langflow/components/helpers/FilterData.py index e589c2aa5..94551854d 100644 --- a/src/backend/base/langflow/components/helpers/FilterData.py +++ b/src/backend/base/langflow/components/helpers/FilterData.py @@ -9,6 +9,7 @@ class FilterDataComponent(Component): display_name = "Filter Data" description = "Filters a Data object based on a list of keys." icon = "filter" + beta = True inputs = [ DataInput( diff --git a/src/backend/base/langflow/components/helpers/IDGenerator.py b/src/backend/base/langflow/components/helpers/IDGenerator.py index 1e4e223b1..72a944f71 100644 --- a/src/backend/base/langflow/components/helpers/IDGenerator.py +++ b/src/backend/base/langflow/components/helpers/IDGenerator.py @@ -2,18 +2,15 @@ import uuid from typing import Any, Optional from langflow.custom import CustomComponent +from langflow.schema.dotdict import dotdict class UUIDGeneratorComponent(CustomComponent): - documentation: str = "http://docs.langflow.org/components/custom" display_name = "ID Generator" description = "Generates a unique ID." - def update_build_config( - self, - build_config: dict, - field_value: Any, - field_name: Optional[str] = None, + def update_build_config( # type: ignore + self, build_config: dotdict, field_value: Any, field_name: Optional[str] = None ): if field_name == "unique_id": build_config[field_name]["value"] = str(uuid.uuid4()) diff --git a/src/backend/base/langflow/components/helpers/MergeData.py b/src/backend/base/langflow/components/helpers/MergeData.py new file mode 100644 index 000000000..5d434d3cf --- /dev/null +++ b/src/backend/base/langflow/components/helpers/MergeData.py @@ -0,0 +1,26 @@ +from langflow.custom import CustomComponent +from langflow.schema import Data + + +class MergeDataComponent(CustomComponent): + display_name = "Merge Data" + description = "Combines multiple data sources into a single unified Data object." + beta: bool = True + + field_config = { + "data": {"display_name": "Data"}, + } + + def build(self, data: list[Data]) -> Data: + if not data: + return Data() + if len(data) == 1: + return data[0] + merged_data = Data() + for value in data: + if merged_data is None: + merged_data = value + else: + merged_data += value + self.status = merged_data + return merged_data diff --git a/src/backend/base/langflow/components/helpers/SplitText.py b/src/backend/base/langflow/components/helpers/SplitText.py new file mode 100644 index 000000000..f3529baf3 --- /dev/null +++ b/src/backend/base/langflow/components/helpers/SplitText.py @@ -0,0 +1,70 @@ +from typing import List + +from langchain_text_splitters import CharacterTextSplitter + +from langflow.custom import Component +from langflow.io import HandleInput, IntInput, MessageTextInput, Output +from langflow.schema import Data +from langflow.utils.util import unescape_string + + +class SplitTextComponent(Component): + display_name: str = "Split Text" + description: str = "Split text into chunks based on specified criteria." + icon = "scissors-line-dashed" + + inputs = [ + HandleInput( + name="data_inputs", + display_name="Data Inputs", + info="The data to split.", + input_types=["Data"], + is_list=True, + ), + IntInput( + name="chunk_overlap", + display_name="Chunk Overlap", + info="Number of characters to overlap between chunks.", + value=200, + ), + IntInput( + name="chunk_size", + display_name="Chunk Size", + info="The maximum number of characters in each chunk.", + value=1000, + ), + MessageTextInput( + name="separator", + display_name="Separator", + info="The character to split on. Defaults to newline.", + value="\n", + ), + ] + + outputs = [ + Output(display_name="Chunks", name="chunks", method="split_text"), + ] + + def _docs_to_data(self, docs): + data = [] + for doc in docs: + data.append(Data(text=doc.page_content, data=doc.metadata)) + return data + + def split_text(self) -> List[Data]: + separator = unescape_string(self.separator) + + documents = [] + for _input in self.data_inputs: + if isinstance(_input, Data): + documents.append(_input.to_lc_document()) + + splitter = CharacterTextSplitter( + chunk_overlap=self.chunk_overlap, + chunk_size=self.chunk_size, + separator=separator, + ) + docs = splitter.split_documents(documents) + data = self._docs_to_data(docs) + self.status = data + return data diff --git a/src/backend/base/langflow/components/helpers/StoreMessage.py b/src/backend/base/langflow/components/helpers/StoreMessage.py new file mode 100644 index 000000000..5d0abfbb9 --- /dev/null +++ b/src/backend/base/langflow/components/helpers/StoreMessage.py @@ -0,0 +1,22 @@ +from langflow.custom import CustomComponent +from langflow.memory import get_messages, store_message +from langflow.schema.message import Message + + +class StoreMessageComponent(CustomComponent): + display_name = "Store Message" + description = "Stores a chat message." + + def build_config(self): + return { + "message": {"display_name": "Message"}, + } + + def build( + self, + message: Message, + ) -> Message: + store_message(message, flow_id=self.graph.flow_id) + self.status = get_messages() + + return message diff --git a/src/backend/base/langflow/components/helpers/__init__.py b/src/backend/base/langflow/components/helpers/__init__.py index 1337aebd4..1941e38b8 100644 --- a/src/backend/base/langflow/components/helpers/__init__.py +++ b/src/backend/base/langflow/components/helpers/__init__.py @@ -1,15 +1,22 @@ -from .CreateData import CreateDataComponent -from .CustomComponent import Component -from .ParseData import ParseDataComponent -from .DocumentsToData import DocumentsToDataComponent +from .CombineText import CombineTextComponent +from .CustomComponent import CustomComponent +from .FilterData import FilterDataComponent from .IDGenerator import UUIDGeneratorComponent -from .UpdateData import UpdateDataComponent +from .Memory import MemoryComponent +from .MergeData import MergeDataComponent +from .ParseData import ParseDataComponent +from .SplitText import SplitTextComponent +from .StoreMessage import StoreMessageComponent + __all__ = [ - "Component", - "UpdateDataComponent", - "DocumentsToDataComponent", + "CombineTextComponent", + "CustomComponent", + "FilterDataComponent", "UUIDGeneratorComponent", + "MemoryComponent", + "MergeDataComponent", "ParseDataComponent", - "CreateDataComponent", + "SplitTextComponent", + "StoreMessageComponent", ] diff --git a/src/backend/base/langflow/components/langchain_utilities/FirecrawlCrawlApi.py b/src/backend/base/langflow/components/langchain_utilities/FirecrawlCrawlApi.py new file mode 100644 index 000000000..ea5a3918e --- /dev/null +++ b/src/backend/base/langflow/components/langchain_utilities/FirecrawlCrawlApi.py @@ -0,0 +1,89 @@ +import uuid +from typing import Optional + +from langflow.custom import CustomComponent +from langflow.schema import Data + + +class FirecrawlCrawlApi(CustomComponent): + display_name: str = "FirecrawlCrawlApi" + description: str = "Firecrawl Crawl API." + output_types: list[str] = ["Document"] + documentation: str = "https://docs.firecrawl.dev/api-reference/endpoint/crawl" + field_config = { + "api_key": { + "display_name": "API Key", + "field_type": "str", + "required": True, + "password": True, + "info": "The API key to use Firecrawl API.", + }, + "url": { + "display_name": "URL", + "field_type": "str", + "required": True, + "info": "The base URL to start crawling from.", + }, + "timeout": { + "display_name": "Timeout", + "field_type": "int", + "info": "The timeout in milliseconds.", + }, + "crawlerOptions": { + "display_name": "Crawler Options", + "info": "Options for the crawler behavior.", + }, + "pageOptions": { + "display_name": "Page Options", + "info": "The page options to send with the request.", + }, + "idempotency_key": { + "display_name": "Idempotency Key", + "field_type": "str", + "info": "Optional idempotency key to ensure unique requests.", + }, + } + + def build( + self, + api_key: str, + url: str, + timeout: int = 30000, + crawlerOptions: Optional[Data] = None, + pageOptions: Optional[Data] = None, + idempotency_key: Optional[str] = None, + ) -> Data: + try: + from firecrawl.firecrawl import FirecrawlApp # type: ignore + except ImportError: + raise ImportError( + "Could not import firecrawl integration package. " "Please install it with `pip install firecrawl-py`." + ) + + if crawlerOptions: + crawler_options_dict = crawlerOptions.__dict__["data"]["text"] + else: + crawler_options_dict = {} + + if pageOptions: + page_options_dict = pageOptions.__dict__["data"]["text"] + else: + page_options_dict = {} + + if not idempotency_key: + idempotency_key = str(uuid.uuid4()) + + app = FirecrawlApp(api_key=api_key) + crawl_result = app.crawl_url( + url, + { + "crawlerOptions": crawler_options_dict, + "pageOptions": page_options_dict, + }, + True, + int(timeout / 1000), + idempotency_key, + ) + + records = Data(data={"results": crawl_result}) + return records diff --git a/src/backend/base/langflow/components/langchain_utilities/FirecrawlScrapeApi.py b/src/backend/base/langflow/components/langchain_utilities/FirecrawlScrapeApi.py new file mode 100644 index 000000000..a2bc6829b --- /dev/null +++ b/src/backend/base/langflow/components/langchain_utilities/FirecrawlScrapeApi.py @@ -0,0 +1,77 @@ +from typing import Optional + +from langflow.custom import CustomComponent +from langflow.schema import Data + + +class FirecrawlScrapeApi(CustomComponent): + display_name: str = "FirecrawlScrapeApi" + description: str = "Firecrawl Scrape API." + output_types: list[str] = ["Document"] + documentation: str = "https://docs.firecrawl.dev/api-reference/endpoint/scrape" + field_config = { + "api_key": { + "display_name": "API Key", + "field_type": "str", + "required": True, + "password": True, + "info": "The API key to use Firecrawl API.", + }, + "url": { + "display_name": "URL", + "field_type": "str", + "required": True, + "info": "The URL to scrape.", + }, + "timeout": { + "display_name": "Timeout", + "info": "Timeout in milliseconds for the request.", + "field_type": "int", + "default_value": 10000, + }, + "pageOptions": { + "display_name": "Page Options", + "info": "The page options to send with the request.", + }, + "extractorOptions": { + "display_name": "Extractor Options", + "info": "The extractor options to send with the request.", + }, + } + + def build( + self, + api_key: str, + url: str, + timeout: Optional[int] = 10000, + pageOptions: Optional[Data] = None, + extractorOptions: Optional[Data] = None, + ) -> Data: + try: + from firecrawl.firecrawl import FirecrawlApp # type: ignore + except ImportError: + raise ImportError( + "Could not import firecrawl integration package. " "Please install it with `pip install firecrawl-py`." + ) + if extractorOptions: + extractor_options_dict = extractorOptions.__dict__["data"]["text"] + else: + extractor_options_dict = {} + + if pageOptions: + page_options_dict = pageOptions.__dict__["data"]["text"] + else: + page_options_dict = {} + + app = FirecrawlApp(api_key=api_key) + results = app.scrape_url( + url, + { + "timeout": str(timeout), + "extractorOptions": extractor_options_dict, + "pageOptions": page_options_dict, + }, + ) + + record = Data(data=results) + return record diff --git a/src/backend/base/langflow/components/models/GoogleGenerativeAIModel.py b/src/backend/base/langflow/components/models/GoogleGenerativeAIModel.py index 377e307a9..d4e75e54b 100644 --- a/src/backend/base/langflow/components/models/GoogleGenerativeAIModel.py +++ b/src/backend/base/langflow/components/models/GoogleGenerativeAIModel.py @@ -3,44 +3,40 @@ from pydantic.v1 import SecretStr from langflow.base.constants import STREAM_INFO_TEXT from langflow.base.models.model import LCModelComponent from langflow.field_typing import LanguageModel -from langflow.io import BoolInput, DropdownInput, FloatInput, IntInput, MessageInput, Output, SecretStrInput, StrInput +from langflow.inputs import ( + BoolInput, + DropdownInput, + FloatInput, + IntInput, + MessageInput, + SecretStrInput, + StrInput, +) class GoogleGenerativeAIComponent(LCModelComponent): - display_name: str = "Google Generative AI" - description: str = "Generate text using Google Generative AI." + display_name = "Google Generative AI" + description = "Generate text using Google Generative AI." icon = "GoogleGenerativeAI" inputs = [ - SecretStrInput( - name="google_api_key", - display_name="Google API Key", - info="The Google API Key to use for the Google Generative AI.", + MessageInput(name="input_value", display_name="Input"), + IntInput( + name="max_output_tokens", + display_name="Max Output Tokens", + info="The maximum number of tokens to generate.", ), DropdownInput( name="model", display_name="Model", info="The name of the model to use.", - options=["gemini-1.5-pro", "gemini-1.5-flash"], + options=["gemini-1.5-pro", "gemini-1.5-flash", "gemini-1.0-pro", "gemini-1.0-pro-vision"], value="gemini-1.5-pro", ), - IntInput( - name="max_output_tokens", - display_name="Max Output Tokens", - info="The maximum number of tokens to generate.", - advanced=True, - ), - FloatInput( - name="temperature", - display_name="Temperature", - info="Run inference with this temperature. Must by in the closed interval [0.0, 1.0].", - value=0.1, - ), - IntInput( - name="top_k", - display_name="Top K", - info="Decode using top-k sampling: consider the set of top_k most probable tokens. Must be positive.", - advanced=True, + SecretStrInput( + name="google_api_key", + display_name="Google API Key", + info="The Google API Key to use for the Google Generative AI.", ), FloatInput( name="top_p", @@ -48,29 +44,26 @@ class GoogleGenerativeAIComponent(LCModelComponent): info="The maximum cumulative probability of tokens to consider when sampling.", advanced=True, ), + FloatInput(name="temperature", display_name="Temperature", value=0.1), + BoolInput(name="stream", display_name="Stream", info=STREAM_INFO_TEXT, advanced=True), IntInput( name="n", display_name="N", info="Number of chat completions to generate for each prompt. Note that the API may not return the full n completions if duplicates are generated.", advanced=True, ), - MessageInput( - name="input_value", - display_name="Input", - info="The input to the model.", - input_types=["Text", "Data", "Prompt"], - ), - BoolInput(name="stream", display_name="Stream", info=STREAM_INFO_TEXT, advanced=True), StrInput( name="system_message", display_name="System Message", info="System message to pass to the model.", advanced=True, ), - ] - outputs = [ - Output(display_name="Text", name="text_output", method="text_response"), - Output(display_name="Language Model", name="model_output", method="build_model"), + IntInput( + name="top_k", + display_name="Top K", + info="Decode using top-k sampling: consider the set of top_k most probable tokens. Must be positive.", + advanced=True, + ), ] def build_model(self) -> LanguageModel: diff --git a/src/backend/base/langflow/components/models/OpenAIModel.py b/src/backend/base/langflow/components/models/OpenAIModel.py index 6545cf3dc..480205fdb 100644 --- a/src/backend/base/langflow/components/models/OpenAIModel.py +++ b/src/backend/base/langflow/components/models/OpenAIModel.py @@ -34,6 +34,12 @@ class OpenAIModelComponent(LCModelComponent): info="The maximum number of tokens to generate. Set to 0 for unlimited tokens.", ), DictInput(name="model_kwargs", display_name="Model Kwargs", advanced=True), + BoolInput( + name="json_mode", + display_name="JSON Mode", + advanced=True, + info="If True, it will output JSON regardless of passing a schema.", + ), DictInput( name="output_schema", is_list=True, @@ -84,7 +90,7 @@ class OpenAIModelComponent(LCModelComponent): max_tokens = self.max_tokens model_kwargs = self.model_kwargs or {} openai_api_base = self.openai_api_base or "https://api.openai.com/v1" - json_mode = bool(output_schema_dict) + json_mode = bool(output_schema_dict) or self.json_mode seed = self.seed model_kwargs["seed"] = seed @@ -101,7 +107,10 @@ class OpenAIModelComponent(LCModelComponent): temperature=temperature or 0.1, ) if json_mode: - output = output.with_structured_output(schema=output_schema_dict, method="json_mode") # type: ignore + if output_schema_dict: + output = output.with_structured_output(schema=output_schema_dict, method="json_mode") # type: ignore + else: + output = output.bind(response_format={"type": "json_object"}) # type: ignore return output diff --git a/src/backend/base/langflow/components/models/__init__.py b/src/backend/base/langflow/components/models/__init__.py index a348f230a..70e1ab10c 100644 --- a/src/backend/base/langflow/components/models/__init__.py +++ b/src/backend/base/langflow/components/models/__init__.py @@ -2,7 +2,6 @@ from .AmazonBedrockModel import AmazonBedrockComponent from .AnthropicModel import AnthropicModelComponent from .AzureOpenAIModel import AzureChatOpenAIComponent from .BaiduQianfanChatModel import QianfanChatEndpointComponent -from .ChatLiteLLMModel import ChatLiteLLMModelComponent from .CohereModel import CohereComponent from .GoogleGenerativeAIModel import GoogleGenerativeAIComponent from .HuggingFaceModel import HuggingFaceEndpointsComponent @@ -11,7 +10,6 @@ from .OpenAIModel import OpenAIModelComponent from .VertexAiModel import ChatVertexAIComponent __all__ = [ - "ChatLiteLLMModelComponent", "AmazonBedrockComponent", "AnthropicModelComponent", "AzureChatOpenAIComponent", diff --git a/src/backend/base/langflow/components/experimental/ConditionalRouter.py b/src/backend/base/langflow/components/prototypes/ConditionalRouter.py similarity index 100% rename from src/backend/base/langflow/components/experimental/ConditionalRouter.py rename to src/backend/base/langflow/components/prototypes/ConditionalRouter.py diff --git a/src/backend/base/langflow/components/helpers/CreateData.py b/src/backend/base/langflow/components/prototypes/CreateData.py similarity index 100% rename from src/backend/base/langflow/components/helpers/CreateData.py rename to src/backend/base/langflow/components/prototypes/CreateData.py diff --git a/src/backend/base/langflow/components/experimental/FlowTool.py b/src/backend/base/langflow/components/prototypes/FlowTool.py similarity index 99% rename from src/backend/base/langflow/components/experimental/FlowTool.py rename to src/backend/base/langflow/components/prototypes/FlowTool.py index 103cd3c1f..a1c9bc4eb 100644 --- a/src/backend/base/langflow/components/experimental/FlowTool.py +++ b/src/backend/base/langflow/components/prototypes/FlowTool.py @@ -16,6 +16,7 @@ class FlowToolComponent(CustomComponent): description = "Construct a Tool from a function that runs the loaded Flow." field_order = ["flow_name", "name", "description", "return_direct"] trace_type = "tool" + beta = True def get_flow_names(self) -> List[str]: flow_datas = self.list_flows() diff --git a/src/backend/base/langflow/components/experimental/Listen.py b/src/backend/base/langflow/components/prototypes/Listen.py similarity index 100% rename from src/backend/base/langflow/components/experimental/Listen.py rename to src/backend/base/langflow/components/prototypes/Listen.py diff --git a/src/backend/base/langflow/components/experimental/Notify.py b/src/backend/base/langflow/components/prototypes/Notify.py similarity index 100% rename from src/backend/base/langflow/components/experimental/Notify.py rename to src/backend/base/langflow/components/prototypes/Notify.py diff --git a/src/backend/base/langflow/components/experimental/Pass.py b/src/backend/base/langflow/components/prototypes/Pass.py similarity index 98% rename from src/backend/base/langflow/components/experimental/Pass.py rename to src/backend/base/langflow/components/prototypes/Pass.py index d21fe0887..4e2f234c9 100644 --- a/src/backend/base/langflow/components/experimental/Pass.py +++ b/src/backend/base/langflow/components/prototypes/Pass.py @@ -9,6 +9,7 @@ class PassComponent(CustomComponent): display_name = "Pass" description = "A pass-through component that forwards the second input while ignoring the first, used for controlling workflow direction." field_order = ["ignored_input", "forwarded_input"] + beta = True def build_config(self) -> dict: return { diff --git a/src/backend/base/langflow/components/experimental/PythonFunction.py b/src/backend/base/langflow/components/prototypes/PythonFunction.py similarity index 97% rename from src/backend/base/langflow/components/experimental/PythonFunction.py rename to src/backend/base/langflow/components/prototypes/PythonFunction.py index d832e2f5c..f0f238636 100644 --- a/src/backend/base/langflow/components/experimental/PythonFunction.py +++ b/src/backend/base/langflow/components/prototypes/PythonFunction.py @@ -9,6 +9,7 @@ class PythonFunctionComponent(CustomComponent): display_name = "Python Function" description = "Define a Python function." icon = "Python" + beta = True def build_config(self): return { diff --git a/src/backend/base/langflow/components/experimental/RunFlow.py b/src/backend/base/langflow/components/prototypes/RunFlow.py similarity index 100% rename from src/backend/base/langflow/components/experimental/RunFlow.py rename to src/backend/base/langflow/components/prototypes/RunFlow.py diff --git a/src/backend/base/langflow/components/experimental/RunnableExecutor.py b/src/backend/base/langflow/components/prototypes/RunnableExecutor.py similarity index 100% rename from src/backend/base/langflow/components/experimental/RunnableExecutor.py rename to src/backend/base/langflow/components/prototypes/RunnableExecutor.py diff --git a/src/backend/base/langflow/components/experimental/SQLExecutor.py b/src/backend/base/langflow/components/prototypes/SQLExecutor.py similarity index 100% rename from src/backend/base/langflow/components/experimental/SQLExecutor.py rename to src/backend/base/langflow/components/prototypes/SQLExecutor.py diff --git a/src/backend/base/langflow/components/prototypes/SubFlow.py b/src/backend/base/langflow/components/prototypes/SubFlow.py new file mode 100644 index 000000000..b0631ee99 --- /dev/null +++ b/src/backend/base/langflow/components/prototypes/SubFlow.py @@ -0,0 +1,115 @@ +from typing import Any, List, Optional + +from langflow.base.flow_processing.utils import build_data_from_result_data +from langflow.custom import CustomComponent +from langflow.graph.graph.base import Graph +from langflow.graph.schema import RunOutputs +from langflow.graph.vertex.base import Vertex +from langflow.helpers.flow import get_flow_inputs +from langflow.schema import Data +from langflow.schema.dotdict import dotdict +from langflow.template.field.base import Input +from loguru import logger + + +class SubFlowComponent(CustomComponent): + display_name = "Sub Flow" + description = ( + "Dynamically Generates a Component from a Flow. The output is a list of data with keys 'result' and 'message'." + ) + beta: bool = True + field_order = ["flow_name"] + + def get_flow_names(self) -> List[str]: + flow_datas = self.list_flows() + return [flow_data.data["name"] for flow_data in flow_datas] + + def get_flow(self, flow_name: str) -> Optional[Data]: + flow_datas = self.list_flows() + for flow_data in flow_datas: + if flow_data.data["name"] == flow_name: + return flow_data + return None + + def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None): + logger.debug(f"Updating build config with field value {field_value} and field name {field_name}") + if field_name == "flow_name": + build_config["flow_name"]["options"] = self.get_flow_names() + # Clean up the build config + for key in list(build_config.keys()): + if key not in self.field_order + ["code", "_type", "get_final_results_only"]: + del build_config[key] + if field_value is not None and field_name == "flow_name": + try: + flow_data = self.get_flow(field_value) + if not flow_data: + raise ValueError(f"Flow {field_value} not found.") + graph = Graph.from_payload(flow_data.data["data"]) + # Get all inputs from the graph + inputs = get_flow_inputs(graph) + # Add inputs to the build config + build_config = self.add_inputs_to_build_config(inputs, build_config) + except Exception as e: + logger.error(f"Error getting flow {field_value}: {str(e)}") + + return build_config + + def add_inputs_to_build_config(self, inputs: List[Vertex], build_config: dotdict): + new_fields: list[Input] = [] + for vertex in inputs: + field = Input( + display_name=vertex.display_name, + name=vertex.id, + info=vertex.description, + field_type="str", + value=None, + ) + new_fields.append(field) + logger.debug(new_fields) + for field in new_fields: + build_config[field.name] = field.to_dict() + return build_config + + def build_config(self): + return { + "input_value": { + "display_name": "Input Value", + "multiline": True, + }, + "flow_name": { + "display_name": "Flow Name", + "info": "The name of the flow to run.", + "options": [], + "real_time_refresh": True, + "refresh_button": True, + }, + "tweaks": { + "display_name": "Tweaks", + "info": "Tweaks to apply to the flow.", + }, + "get_final_results_only": { + "display_name": "Get Final Results Only", + "info": "If False, the output will contain all outputs from the flow.", + "advanced": True, + }, + } + + async def build(self, flow_name: str, get_final_results_only: bool = True, **kwargs) -> List[Data]: + tweaks = {key: {"input_value": value} for key, value in kwargs.items()} + run_outputs: List[Optional[RunOutputs]] = await self.run_flow( + tweaks=tweaks, + flow_name=flow_name, + ) + if not run_outputs: + return [] + run_output = run_outputs[0] + + data = [] + if run_output is not None: + for output in run_output.outputs: + if output: + data.extend(build_data_from_result_data(output, get_final_results_only)) + + self.status = data + logger.debug(data) + return data diff --git a/src/backend/base/langflow/components/helpers/UpdateData.py b/src/backend/base/langflow/components/prototypes/UpdateData.py similarity index 100% rename from src/backend/base/langflow/components/helpers/UpdateData.py rename to src/backend/base/langflow/components/prototypes/UpdateData.py diff --git a/src/backend/base/langflow/components/prototypes/__init__.py b/src/backend/base/langflow/components/prototypes/__init__.py new file mode 100644 index 000000000..89c14f7e9 --- /dev/null +++ b/src/backend/base/langflow/components/prototypes/__init__.py @@ -0,0 +1,27 @@ +from .ConditionalRouter import ConditionalRouterComponent +from .FlowTool import FlowToolComponent +from .Listen import ListenComponent +from .Notify import NotifyComponent +from .Pass import PassComponent +from .PythonFunction import PythonFunctionComponent +from .RunFlow import RunFlowComponent +from .RunnableExecutor import RunnableExecComponent +from .SQLExecutor import SQLExecutorComponent +from .SubFlow import SubFlowComponent +from .CreateData import CreateDataComponent +from .UpdateData import UpdateDataComponent + +__all__ = [ + "ConditionalRouterComponent", + "FlowToolComponent", + "ListenComponent", + "NotifyComponent", + "PassComponent", + "PythonFunctionComponent", + "RunFlowComponent", + "RunnableExecComponent", + "SQLExecutorComponent", + "SubFlowComponent", + "CreateDataComponent", + "UpdateDataComponent", +] diff --git a/src/backend/base/langflow/components/vectorstores/AstraDB.py b/src/backend/base/langflow/components/vectorstores/AstraDB.py index adcd546de..aabbb91a7 100644 --- a/src/backend/base/langflow/components/vectorstores/AstraDB.py +++ b/src/backend/base/langflow/components/vectorstores/AstraDB.py @@ -3,13 +3,13 @@ from loguru import logger from langflow.base.vectorstores.model import LCVectorStoreComponent from langflow.io import ( BoolInput, + DataInput, DropdownInput, HandleInput, IntInput, MultilineInput, SecretStrInput, StrInput, - DataInput, ) from langflow.schema import Data @@ -159,10 +159,12 @@ class AstraVectorStoreComponent(LCVectorStoreComponent): embedding_dict = {"embedding": self.embedding} else: from astrapy.info import CollectionVectorServiceOptions + dict_options = self.embedding.get("collection_vector_service_options", {}) - dict_options["authentication"] = {k: v for k, v in dict_options.get("authentication", {}).items() if k and v} - dict_options["parameters"] = {k: v for k, v in dict_options.get("parameters", {}).items() if - k and v} + dict_options["authentication"] = { + k: v for k, v in dict_options.get("authentication", {}).items() if k and v + } + dict_options["parameters"] = {k: v for k, v in dict_options.get("parameters", {}).items() if k and v} embedding_dict = { "collection_vector_service_options": CollectionVectorServiceOptions.from_dict(dict_options), "collection_embedding_api_key": self.embedding.get("collection_embedding_api_key"), @@ -194,6 +196,10 @@ class AstraVectorStoreComponent(LCVectorStoreComponent): except Exception as e: raise ValueError(f"Error initializing AstraDBVectorStore: {str(e)}") from e + if hasattr(self, "ingest_data") and self.ingest_data: + logger.debug("Ingesting data into the Vector Store.") + self._add_documents_to_vector_store(vector_store) + self.status = self._astradb_collection_to_data(vector_store.collection) return vector_store @@ -214,7 +220,7 @@ class AstraVectorStoreComponent(LCVectorStoreComponent): else: logger.debug("No documents to add to the Vector Store.") - def search_documents(self): + def search_documents(self) -> list[Data]: vector_store = self.build_vector_store() logger.debug(f"Search input: {self.search_input}") diff --git a/src/backend/base/langflow/components/vectorstores/Cassandra.py b/src/backend/base/langflow/components/vectorstores/Cassandra.py index 0e4e9eb84..ee6b83972 100644 --- a/src/backend/base/langflow/components/vectorstores/Cassandra.py +++ b/src/backend/base/langflow/components/vectorstores/Cassandra.py @@ -4,6 +4,7 @@ from langchain_community.vectorstores import Cassandra from langflow.base.vectorstores.model import LCVectorStoreComponent from langflow.helpers.data import docs_to_data +from langflow.inputs import DictInput from langflow.io import ( DataInput, DropdownInput, @@ -23,24 +24,32 @@ class CassandraVectorStoreComponent(LCVectorStoreComponent): icon = "Cassandra" inputs = [ - SecretStrInput( - name="token", - display_name="Token", - info="Authentication token for accessing Cassandra on Astra DB.", + MessageTextInput( + name="database_ref", + display_name="Contact Points / Astra Database ID", + info="Contact points for the database (or AstraDB database ID)", required=True, ), - MessageTextInput(name="database_id", display_name="Database ID", info="The Astra database ID.", required=True), MessageTextInput( - name="table_name", - display_name="Table Name", - info="The name of the table where vectors will be stored.", + name="username", display_name="Username", info="Username for the database (leave empty for AstraDB)." + ), + SecretStrInput( + name="token", + display_name="Password / AstraDB Token", + info="User password for the database (or AstraDB token).", required=True, ), MessageTextInput( name="keyspace", display_name="Keyspace", - info="Optional key space within Astra DB. The keyspace should already be created.", - advanced=False, + info="Table Keyspace (or AstraDB namespace).", + required=True, + ), + MessageTextInput( + name="table_name", + display_name="Table Name", + info="The name of the table (or AstraDB collection) where vectors will be stored.", + required=True, ), IntInput( name="ttl_seconds", @@ -69,6 +78,13 @@ class CassandraVectorStoreComponent(LCVectorStoreComponent): value="Sync", advanced=True, ), + DictInput( + name="cluster_kwargs", + display_name="Cluster arguments", + info="Optional dictionary of additional keyword arguments for the Cassandra cluster.", + advanced=True, + is_list=True, + ), MultilineInput(name="search_query", display_name="Search Query"), DataInput( name="ingest_data", @@ -96,10 +112,35 @@ class CassandraVectorStoreComponent(LCVectorStoreComponent): "Could not import cassio integration package. " "Please install it with `pip install cassio`." ) - cassio.init( - database_id=self.database_id, - token=self.token, - ) + from uuid import UUID + + database_ref = self.database_ref + + try: + UUID(self.database_ref) + is_astra = True + except ValueError: + is_astra = False + if "," in self.database_ref: + # use a copy because we can't change the type of the parameter + database_ref = self.database_ref.split(",") + + if is_astra: + cassio.init( + database_id=database_ref, + token=self.token, + cluster_kwargs=self.cluster_kwargs, + ) + else: + cassio.init( + contact_points=database_ref, + username=self.username, + password=self.token, + cluster_kwargs=self.cluster_kwargs, + ) + + if not self.ttl_seconds: # type: ignore + self.ttl_seconds = None documents = [] diff --git a/src/backend/base/langflow/components/vectorstores/Vectara.py b/src/backend/base/langflow/components/vectorstores/Vectara.py index 674a35ff5..4945eb902 100644 --- a/src/backend/base/langflow/components/vectorstores/Vectara.py +++ b/src/backend/base/langflow/components/vectorstores/Vectara.py @@ -1,30 +1,46 @@ -from typing import List +from typing import TYPE_CHECKING, List -from langchain_community.embeddings import FakeEmbeddings from langchain_community.vectorstores import Vectara +from loguru import logger from langflow.base.vectorstores.model import LCVectorStoreComponent from langflow.helpers.data import docs_to_data -from langflow.io import IntInput, StrInput, SecretStrInput, DataInput, MultilineInput +from langflow.io import HandleInput, IntInput, MessageTextInput, SecretStrInput, StrInput from langflow.schema import Data +if TYPE_CHECKING: + from langchain_community.vectorstores import Vectara + class VectaraVectorStoreComponent(LCVectorStoreComponent): - display_name = "Vectara" - description = "Vectara Vector Store with search capabilities" - documentation = "https://python.langchain.com/v0.2/docs/integrations/vectorstores/vectara/" + """ + Vectara Vector Store with search capabilities + """ + + display_name: str = "Vectara" + description: str = "Vectara Vector Store with search capabilities" + documentation = "https://python.langchain.com/docs/modules/data_connection/vectorstores/integrations/vectara" icon = "Vectara" inputs = [ StrInput(name="vectara_customer_id", display_name="Vectara Customer ID", required=True), StrInput(name="vectara_corpus_id", display_name="Vectara Corpus ID", required=True), SecretStrInput(name="vectara_api_key", display_name="Vectara API Key", required=True), - MultilineInput(name="search_query", display_name="Search Query"), - DataInput( + HandleInput( + name="embedding", + display_name="Embedding", + input_types=["Embeddings"], + ), + HandleInput( name="ingest_data", - display_name="Vector Store Inputs", + display_name="Ingest Data", + input_types=["Document", "Data"], is_list=True, ), + MessageTextInput( + name="search_query", + display_name="Search Query", + ), IntInput( name="number_of_results", display_name="Number of Results", @@ -34,11 +50,31 @@ class VectaraVectorStoreComponent(LCVectorStoreComponent): ), ] - def build_vector_store(self) -> Vectara: - return self._build_vectara() + def build_vector_store(self) -> "Vectara": + """ + Builds the Vectara object. + """ + try: + from langchain_community.vectorstores import Vectara + except ImportError: + raise ImportError("Could not import Vectara. Please install it with `pip install langchain-community`.") - def _build_vectara(self) -> Vectara: - source = "Langflow" + vectara = Vectara( + vectara_customer_id=self.vectara_customer_id, + vectara_corpus_id=self.vectara_corpus_id, + vectara_api_key=self.vectara_api_key, + ) + + self._add_documents_to_vector_store(vectara) + return vectara + + def _add_documents_to_vector_store(self, vector_store: "Vectara") -> None: + """ + Adds documents to the Vector Store. + """ + if not self.ingest_data: + self.status = "No documents to add to Vectara" + return documents = [] for _input in self.ingest_data or []: @@ -48,24 +84,15 @@ class VectaraVectorStoreComponent(LCVectorStoreComponent): documents.append(_input) if documents: - return Vectara.from_documents( - documents=documents, - embedding=FakeEmbeddings(size=768), - vectara_customer_id=self.vectara_customer_id, - vectara_corpus_id=self.vectara_corpus_id, - vectara_api_key=self.vectara_api_key, - source=source, - ) - - return Vectara( - vectara_customer_id=self.vectara_customer_id, - vectara_corpus_id=self.vectara_corpus_id, - vectara_api_key=self.vectara_api_key, - source=source, - ) + logger.debug(f"Adding {len(documents)} documents to Vectara.") + vector_store.add_documents(documents) + self.status = f"Added {len(documents)} documents to Vectara" + else: + logger.debug("No documents to add to Vectara.") + self.status = "No valid documents to add to Vectara" def search_documents(self) -> List[Data]: - vector_store = self._build_vectara() + vector_store = self.build_vector_store() if self.search_query and isinstance(self.search_query, str) and self.search_query.strip(): docs = vector_store.similarity_search( @@ -74,7 +101,8 @@ class VectaraVectorStoreComponent(LCVectorStoreComponent): ) data = docs_to_data(docs) - self.status = data + self.status = f"Found {len(data)} results for the query: {self.search_query}" return data else: + self.status = "No search query provided" return [] diff --git a/src/backend/base/langflow/custom/custom_component/custom_component.py b/src/backend/base/langflow/custom/custom_component/custom_component.py index 5505ae132..24df42894 100644 --- a/src/backend/base/langflow/custom/custom_component/custom_component.py +++ b/src/backend/base/langflow/custom/custom_component/custom_component.py @@ -96,7 +96,7 @@ class CustomComponent(BaseComponent): def stop(self, output_name: str | None = None): if not output_name and self.vertex and len(self.vertex.outputs) == 1: output_name = self.vertex.outputs[0]["name"] - else: + elif not output_name: raise ValueError("You must specify an output name to call stop") if not self.vertex: raise ValueError("Vertex is not set") diff --git a/src/backend/base/langflow/graph/graph/base.py b/src/backend/base/langflow/graph/graph/base.py index 46f562c95..22af2a68f 100644 --- a/src/backend/base/langflow/graph/graph/base.py +++ b/src/backend/base/langflow/graph/graph/base.py @@ -343,10 +343,10 @@ class Graph: except Exception as exc: logger.exception(exc) tb = traceback.format_exc() - await self.end_all_traces(error=f"{exc.__class__.__name__}: {exc}\n\n{tb}") + asyncio.create_task(self.end_all_traces(error=f"{exc.__class__.__name__}: {exc}\n\n{tb}")) raise ValueError(f"Error running graph: {exc}") from exc finally: - await self.end_all_traces() + asyncio.create_task(self.end_all_traces()) # Get the outputs vertex_outputs = [] for vertex in self.vertices: @@ -1208,6 +1208,7 @@ class Graph: except ValueError: stop_or_start_vertex = self.get_root_of_group_node(vertex_id) stack = [stop_or_start_vertex.id] + vertex_id = stop_or_start_vertex.id stop_predecessors = [pre.id for pre in stop_or_start_vertex.predecessors] # DFS to collect all vertices that can reach the specified vertex while stack: @@ -1443,7 +1444,7 @@ class Graph: def is_vertex_runnable(self, vertex_id: str) -> bool: """Returns whether a vertex is runnable.""" - return self.run_manager.is_vertex_runnable(vertex_id) + return self.run_manager.is_vertex_runnable(vertex_id, self.inactivated_vertices) def build_run_map(self): """ @@ -1463,7 +1464,7 @@ class Graph: This checks the direct predecessors of each successor to identify any that are immediately runnable, expanding the search to ensure progress can be made. """ - return self.run_manager.find_runnable_predecessors_for_successors(vertex_id) + return self.run_manager.find_runnable_predecessors_for_successors(vertex_id, self.inactivated_vertices) def remove_from_predecessors(self, vertex_id: str): self.run_manager.remove_from_predecessors(vertex_id) diff --git a/src/backend/base/langflow/graph/graph/runnable_vertices_manager.py b/src/backend/base/langflow/graph/graph/runnable_vertices_manager.py index 63b0aacaf..46d59066e 100644 --- a/src/backend/base/langflow/graph/graph/runnable_vertices_manager.py +++ b/src/backend/base/langflow/graph/graph/runnable_vertices_manager.py @@ -1,6 +1,6 @@ import asyncio from collections import defaultdict -from typing import TYPE_CHECKING, Callable, List, Coroutine +from typing import TYPE_CHECKING, Callable, Coroutine, List if TYPE_CHECKING: from langflow.graph.graph.base import Graph @@ -40,19 +40,23 @@ class RunnableVerticesManager: self.run_predecessors = state["run_predecessors"] self.vertices_to_run = state["vertices_to_run"] - def is_vertex_runnable(self, vertex_id: str) -> bool: + def is_vertex_runnable(self, vertex_id: str, inactivated_vertices: set[str]) -> bool: """Determines if a vertex is runnable.""" - return vertex_id in self.vertices_to_run and not self.run_predecessors.get(vertex_id) + return ( + vertex_id in self.vertices_to_run + and not self.run_predecessors.get(vertex_id) + and vertex_id not in inactivated_vertices + ) - def find_runnable_predecessors_for_successors(self, vertex_id: str) -> List[str]: + def find_runnable_predecessors_for_successors(self, vertex_id: str, inactivated_vertices: set[str]) -> List[str]: """Finds runnable predecessors for the successors of a given vertex.""" runnable_vertices = [] visited = set() for successor_id in self.run_map.get(vertex_id, []): for predecessor_id in self.run_predecessors.get(successor_id, []): - if predecessor_id not in visited and self.is_vertex_runnable(predecessor_id): + if predecessor_id not in visited and self.is_vertex_runnable(predecessor_id, inactivated_vertices): runnable_vertices.append(predecessor_id) visited.add(predecessor_id) return runnable_vertices @@ -104,10 +108,14 @@ class RunnableVerticesManager: """ async with lock: self.remove_from_predecessors(vertex.id) - direct_successors_ready = [v for v in vertex.successors_ids if self.is_vertex_runnable(v)] + direct_successors_ready = [ + v for v in vertex.successors_ids if self.is_vertex_runnable(v, graph.inactivated_vertices) + ] if not direct_successors_ready: # No direct successors ready, look for runnable predecessors of successors - next_runnable_vertices = self.find_runnable_predecessors_for_successors(vertex.id) + next_runnable_vertices = self.find_runnable_predecessors_for_successors( + vertex.id, graph.inactivated_vertices + ) else: next_runnable_vertices = direct_successors_ready diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, world!).json b/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, World).json similarity index 77% rename from src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, world!).json rename to src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, World).json index 5e1b80c3e..163384b2c 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, world!).json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, World).json @@ -1,38 +1,11 @@ { "data": { "edges": [ - { - "className": "", - "data": { - "sourceHandle": { - "dataType": "OpenAIModel", - "id": "OpenAIModel-dqnxm", - "name": "text_output", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-3k2BV", - "inputTypes": [ - "Message", - "str" - ], - "type": "str" - } - }, - "id": "reactflow__edge-OpenAIModel-dqnxm{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-dqnxmœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-3k2BV{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-3k2BVœ,œinputTypesœ:[œMessageœ,œstrœ],œtypeœ:œstrœ}", - "source": "OpenAIModel-dqnxm", - "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-dqnxmœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-3k2BV", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-3k2BVœ, œinputTypesœ: [œMessageœ, œstrœ], œtypeœ: œstrœ}" - }, { "data": { "sourceHandle": { "dataType": "ChatInput", - "id": "ChatInput-j8yVK", + "id": "ChatInput-pxptT", "name": "message", "output_types": [ "Message" @@ -40,7 +13,7 @@ }, "targetHandle": { "fieldName": "user_input", - "id": "Prompt-669fA", + "id": "Prompt-1S5SU", "inputTypes": [ "Message", "Text" @@ -48,17 +21,17 @@ "type": "str" } }, - "id": "reactflow__edge-ChatInput-j8yVK{œdataTypeœ:œChatInputœ,œidœ:œChatInput-j8yVKœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Prompt-669fA{œfieldNameœ:œuser_inputœ,œidœ:œPrompt-669fAœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", - "source": "ChatInput-j8yVK", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-j8yVKœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-669fA", - "targetHandle": "{œfieldNameœ: œuser_inputœ, œidœ: œPrompt-669fAœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" + "id": "reactflow__edge-ChatInput-pxptT{œdataTypeœ:œChatInputœ,œidœ:œChatInput-pxptTœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Prompt-1S5SU{œfieldNameœ:œuser_inputœ,œidœ:œPrompt-1S5SUœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", + "source": "ChatInput-pxptT", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-pxptTœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "Prompt-1S5SU", + "targetHandle": "{œfieldNameœ: œuser_inputœ, œidœ: œPrompt-1S5SUœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" }, { "data": { "sourceHandle": { "dataType": "Prompt", - "id": "Prompt-669fA", + "id": "Prompt-1S5SU", "name": "prompt", "output_types": [ "Message" @@ -66,218 +39,67 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "OpenAIModel-dqnxm", + "id": "OpenAIModel-nJXWj", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-Prompt-669fA{œdataTypeœ:œPromptœ,œidœ:œPrompt-669fAœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-dqnxm{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-dqnxmœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "source": "Prompt-669fA", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-669fAœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "target": "OpenAIModel-dqnxm", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-dqnxmœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "id": "reactflow__edge-Prompt-1S5SU{œdataTypeœ:œPromptœ,œidœ:œPrompt-1S5SUœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-nJXWj{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-nJXWjœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "source": "Prompt-1S5SU", + "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-1S5SUœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", + "target": "OpenAIModel-nJXWj", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-nJXWjœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "OpenAIModel", + "id": "OpenAIModel-nJXWj", + "name": "text_output", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-XP4bj", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "reactflow__edge-OpenAIModel-nJXWj{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-nJXWjœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-XP4bj{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-XP4bjœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "source": "OpenAIModel-nJXWj", + "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-nJXWjœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-XP4bj", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-XP4bjœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" } ], "nodes": [ { "data": { - "id": "ChatOutput-3k2BV", + "id": "ChatInput-pxptT", "node": { "base_classes": [ - "Record", - "Text", - "str", - "object" + "Message" ], "beta": false, - "custom_fields": { - "input_value": null, - "record_template": null, - "return_record": null, - "sender": null, - "sender_name": null, - "session_id": null - }, - "description": "Display a chat message in the Playground.", - "display_name": "Chat Output", - "documentation": "", - "field_formatters": {}, - "field_order": [], - "frozen": false, - "icon": "ChatOutput", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Message", - "method": "message_response", - "name": "message", - "selected": "Message", - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.io import DropdownInput, Output, MessageTextInput\nfrom langflow.schema.message import Message\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\"],\n value=\"Machine\",\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\", display_name=\"Sender Name\", info=\"Name of the sender.\", value=\"AI\", advanced=True\n ),\n MessageTextInput(name=\"session_id\", display_name=\"Session ID\", info=\"Session ID for the message.\", advanced=True),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n )\n if self.session_id and isinstance(message, Message) and isinstance(message.text, str):\n self.store_message(message)\n self.message.value = message\n\n self.status = message\n return message\n" - }, - "input_value": { - "advanced": false, - "display_name": "Text", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Message to be passed as output.", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "input_value", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "sender": { - "advanced": true, - "display_name": "Sender Type", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Type of sender.", - "input_types": [ - "Text" - ], - "list": true, - "load_from_db": false, - "multiline": false, - "name": "sender", - "options": [ - "Machine", - "User" - ], - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "Machine" - }, - "sender_name": { - "advanced": true, - "display_name": "Sender Name", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Name of the sender.", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "sender_name", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "AI" - }, - "session_id": { - "advanced": true, - "display_name": "Session ID", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Session ID for the message.", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "session_id", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - } - } - }, - "type": "ChatOutput" - }, - "dragging": false, - "height": 309, - "id": "ChatOutput-3k2BV", - "position": { - "x": 1193.250417197867, - "y": 71.88476890163852 - }, - "positionAbsolute": { - "x": 1193.250417197867, - "y": 71.88476890163852 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "id": "ChatInput-j8yVK", - "node": { - "base_classes": [ - "object", - "Record", - "str", - "Text" - ], - "beta": false, - "custom_fields": { - "input_value": null, - "return_record": null, - "sender": null, - "sender_name": null, - "session_id": null - }, + "conditional_paths": [], + "custom_fields": {}, "description": "Get chat inputs from the Playground.", "display_name": "Chat Input", "documentation": "", - "field_formatters": {}, - "field_order": [], + "edited": false, + "field_order": [ + "input_value", + "sender", + "sender_name", + "session_id", + "files" + ], "frozen": false, "icon": "ChatInput", "output_types": [], @@ -295,199 +117,6 @@ "value": "__UNDEFINED__" } ], - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.io import DropdownInput, FileInput, MultilineInput, Output, MessageTextInput\nfrom langflow.schema.message import Message\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\"],\n value=\"User\",\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=\"User\",\n advanced=True,\n ),\n MessageTextInput(name=\"session_id\", display_name=\"Session ID\", info=\"Session ID for the message.\", advanced=True),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n )\n if self.session_id and isinstance(message, Message) and isinstance(message.text, str):\n self.store_message(message)\n self.message.value = message\n\n self.status = message\n return message\n" - }, - "input_value": { - "advanced": false, - "display_name": "Text", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Message to be passed as input.", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "input_value", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "hello!" - }, - "sender": { - "advanced": true, - "display_name": "Sender Type", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Type of sender.", - "input_types": [ - "Text" - ], - "list": true, - "load_from_db": false, - "multiline": false, - "name": "sender", - "options": [ - "Machine", - "User" - ], - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "User" - }, - "sender_name": { - "advanced": true, - "display_name": "Sender Name", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Name of the sender.", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "sender_name", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "User" - }, - "session_id": { - "advanced": true, - "display_name": "Session ID", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Session ID for the message.", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "session_id", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - } - } - }, - "type": "ChatInput" - }, - "dragging": false, - "height": 309, - "id": "ChatInput-j8yVK", - "position": { - "x": -495.2223093083827, - "y": -232.56998443685862 - }, - "positionAbsolute": { - "x": -495.2223093083827, - "y": -232.56998443685862 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "description": "Generates text using OpenAI LLMs.", - "display_name": "OpenAI", - "edited": false, - "id": "OpenAIModel-dqnxm", - "node": { - "base_classes": [ - "LanguageModel", - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Generates text using OpenAI LLMs.", - "display_name": "OpenAI", - "documentation": "", - "edited": true, - "field_order": [ - "input_value", - "max_tokens", - "model_kwargs", - "output_schema", - "model_name", - "openai_api_base", - "openai_api_key", - "temperature", - "stream", - "system_message", - "seed" - ], - "frozen": false, - "icon": "OpenAI", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Text", - "hidden": false, - "method": "text_response", - "name": "text_output", - "selected": "Message", - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - }, - { - "cache": true, - "display_name": "Language Model", - "method": "build_model", - "name": "model_output", - "selected": "LanguageModel", - "types": [ - "LanguageModel" - ], - "value": "__UNDEFINED__" - } - ], "pinned": false, "template": { "_type": "Component", @@ -507,190 +136,142 @@ "show": true, "title_case": false, "type": "code", - "value": "import operator\nfrom functools import reduce\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import LanguageModel\nfrom langflow.inputs import (\n BoolInput,\n DictInput,\n DropdownInput,\n FloatInput,\n IntInput,\n MessageInput,\n SecretStrInput,\n StrInput,\n)\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n inputs = [\n MessageInput(name=\"input_value\", display_name=\"Input\"),\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n info=\"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n ),\n DictInput(name=\"model_kwargs\", display_name=\"Model Kwargs\", advanced=True),\n DictInput(\n name=\"output_schema\",\n is_list=True,\n display_name=\"Schema\",\n advanced=True,\n info=\"The schema for the Output of the model. You must pass the word JSON in the prompt. If left blank, JSON mode will be disabled.\",\n ),\n DropdownInput(\n name=\"model_name\", display_name=\"Model Name\", advanced=False, options=MODEL_NAMES, value=MODEL_NAMES[0]\n ),\n StrInput(\n name=\"openai_api_base\",\n display_name=\"OpenAI API Base\",\n advanced=True,\n info=\"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.\",\n ),\n SecretStrInput(\n name=\"openai_api_key\",\n display_name=\"OpenAI API Key\",\n info=\"The OpenAI API Key to use for the OpenAI model.\",\n advanced=False,\n value=\"OPENAI_API_KEY\",\n ),\n FloatInput(name=\"temperature\", display_name=\"Temperature\", value=0.1),\n BoolInput(name=\"stream\", display_name=\"Stream\", info=STREAM_INFO_TEXT, advanced=True),\n StrInput(\n name=\"system_message\",\n display_name=\"System Message\",\n info=\"System message to pass to the model.\",\n advanced=True,\n ),\n IntInput(\n name=\"seed\",\n display_name=\"Seed\",\n info=\"The seed controls the reproducibility of the job.\",\n advanced=True,\n value=1,\n ),\n ]\n\n def build_model(self) -> LanguageModel:\n # self.output_schea is a list of dictionaries\n # let's convert it to a dictionary\n output_schema_dict: dict[str, str] = reduce(operator.ior, self.output_schema or {}, {})\n openai_api_key = self.openai_api_key\n temperature = self.temperature\n model_name: str = self.model_name\n max_tokens = self.max_tokens\n model_kwargs = self.model_kwargs or {}\n openai_api_base = self.openai_api_base or \"https://api.openai.com/v1\"\n json_mode = bool(output_schema_dict)\n seed = self.seed\n model_kwargs[\"seed\"] = seed\n\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature or 0.1,\n )\n if json_mode:\n output = output.with_structured_output(schema=output_schema_dict, method=\"json_mode\") # type: ignore\n\n return output\n\n def _get_exception_message(self, e: Exception):\n \"\"\"\n Get a message from an OpenAI exception.\n\n Args:\n exception (Exception): The exception to get the message from.\n\n Returns:\n str: The message from the exception.\n \"\"\"\n\n try:\n from openai import BadRequestError\n except ImportError:\n return\n if isinstance(e, BadRequestError):\n message = e.body.get(\"message\") # type: ignore\n if message:\n return message\n return\n" + "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.schema.message import Message\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\"],\n value=\"User\",\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=\"User\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\", display_name=\"Session ID\", info=\"Session ID for the message.\", advanced=True\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n )\n if self.session_id and isinstance(message, Message) and isinstance(message.text, str):\n self.store_message(message)\n self.message.value = message\n\n self.status = message\n return message\n" + }, + "files": { + "advanced": true, + "display_name": "Files", + "dynamic": false, + "fileTypes": [ + "txt", + "md", + "mdx", + "csv", + "json", + "yaml", + "yml", + "xml", + "html", + "htm", + "pdf", + "docx", + "py", + "sh", + "sql", + "js", + "ts", + "tsx", + "jpg", + "jpeg", + "png", + "bmp", + "image" + ], + "file_path": "", + "info": "Files to be sent with the message.", + "list": true, + "name": "files", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "file", + "value": "" }, "input_value": { "advanced": false, - "display_name": "Input", + "display_name": "Text", "dynamic": false, - "info": "", + "info": "Message to be passed as input.", "input_types": [ "Message" ], "list": false, "load_from_db": false, + "multiline": true, "name": "input_value", "placeholder": "", "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" }, - "max_tokens": { + "sender": { "advanced": true, - "display_name": "Max Tokens", + "display_name": "Sender Type", "dynamic": false, - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "list": false, - "name": "max_tokens", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": "" - }, - "model_kwargs": { - "advanced": true, - "display_name": "Model Kwargs", - "dynamic": false, - "info": "", - "list": false, - "name": "model_kwargs", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "dict", - "value": {} - }, - "model_name": { - "advanced": false, - "display_name": "Model Name", - "dynamic": false, - "info": "", - "name": "model_name", + "info": "Type of sender.", + "name": "sender", "options": [ - "gpt-4o", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125" + "Machine", + "User" ], "placeholder": "", "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "str", - "value": "gpt-4o" + "value": "User" }, - "openai_api_base": { + "sender_name": { "advanced": true, - "display_name": "OpenAI API Base", + "display_name": "Sender Name", "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", + "info": "Name of the sender.", + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, - "name": "openai_api_base", + "name": "sender_name", "placeholder": "", "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", - "value": "" + "value": "User" }, - "openai_api_key": { - "advanced": false, - "display_name": "OpenAI API Key", - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "input_types": [], - "load_from_db": false, - "name": "openai_api_key", - "password": true, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "output_schema": { + "session_id": { "advanced": true, - "display_name": "Schema", + "display_name": "Session ID", "dynamic": false, - "info": "The schema for the Output of the model. You must pass the word JSON in the prompt. If left blank, JSON mode will be disabled.", - "list": true, - "name": "output_schema", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "dict", - "value": {} - }, - "seed": { - "advanced": true, - "display_name": "Seed", - "dynamic": false, - "info": "The seed controls the reproducibility of the job.", - "list": false, - "name": "seed", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": 1 - }, - "stream": { - "advanced": true, - "display_name": "Stream", - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "list": false, - "name": "stream", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "bool", - "value": false - }, - "system_message": { - "advanced": true, - "display_name": "System Message", - "dynamic": false, - "info": "System message to pass to the model.", + "info": "Session ID for the message.", + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, - "name": "system_message", + "name": "session_id", "placeholder": "", "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" - }, - "temperature": { - "advanced": false, - "display_name": "Temperature", - "dynamic": false, - "info": "", - "list": false, - "name": "temperature", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "float", - "value": 0.1 } } }, - "type": "OpenAIModel" + "type": "ChatInput" }, "dragging": false, - "height": 623, - "id": "OpenAIModel-dqnxm", + "height": 308, + "id": "ChatInput-pxptT", "position": { - "x": 576.388859357137, - "y": 131.1662189663108 + "x": -493.6459512396177, + "y": 1083.200545525551 }, "positionAbsolute": { - "x": 576.388859357137, - "y": 131.1662189663108 + "x": -493.6459512396177, + "y": 1083.200545525551 }, "selected": false, "type": "genericNode", @@ -700,7 +281,7 @@ "data": { "description": "Create a prompt template with dynamic variables.", "display_name": "Prompt", - "id": "Prompt-669fA", + "id": "Prompt-1S5SU", "node": { "base_classes": [ "Message" @@ -807,31 +388,481 @@ "type": "Prompt" }, "dragging": false, - "height": 423, - "id": "Prompt-669fA", + "height": 422, + "id": "Prompt-1S5SU", "position": { - "x": 33.573076589480024, - "y": -103.0780954474625 + "x": 56.354011530798516, + "y": 1157.2005405164796 }, "positionAbsolute": { - "x": 33.573076589480024, - "y": -103.0780954474625 + "x": 56.354011530798516, + "y": 1157.2005405164796 }, - "selected": true, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { + "data": { + "id": "OpenAIModel-nJXWj", + "node": { + "base_classes": [ + "LanguageModel", + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Generates text using OpenAI LLMs.", + "display_name": "OpenAI", + "documentation": "", + "edited": false, + "field_order": [ + "input_value", + "max_tokens", + "model_kwargs", + "output_schema", + "model_name", + "openai_api_base", + "openai_api_key", + "temperature", + "stream", + "system_message", + "seed" + ], + "frozen": false, + "icon": "OpenAI", + "output_types": [], + "outputs": [ + { + "cache": true, + "display_name": "Text", + "hidden": false, + "method": "text_response", + "name": "text_output", + "selected": "Message", + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + }, + { + "cache": true, + "display_name": "Language Model", + "method": "build_model", + "name": "model_output", + "selected": "LanguageModel", + "types": [ + "LanguageModel" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "import operator\nfrom functools import reduce\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import LanguageModel\nfrom langflow.inputs import (\n BoolInput,\n DictInput,\n DropdownInput,\n FloatInput,\n IntInput,\n MessageInput,\n SecretStrInput,\n StrInput,\n)\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n inputs = [\n MessageInput(name=\"input_value\", display_name=\"Input\"),\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n info=\"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n ),\n DictInput(name=\"model_kwargs\", display_name=\"Model Kwargs\", advanced=True),\n DictInput(\n name=\"output_schema\",\n is_list=True,\n display_name=\"Schema\",\n advanced=True,\n info=\"The schema for the Output of the model. You must pass the word JSON in the prompt. If left blank, JSON mode will be disabled.\",\n ),\n DropdownInput(\n name=\"model_name\", display_name=\"Model Name\", advanced=False, options=MODEL_NAMES, value=MODEL_NAMES[0]\n ),\n StrInput(\n name=\"openai_api_base\",\n display_name=\"OpenAI API Base\",\n advanced=True,\n info=\"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.\",\n ),\n SecretStrInput(\n name=\"openai_api_key\",\n display_name=\"OpenAI API Key\",\n info=\"The OpenAI API Key to use for the OpenAI model.\",\n advanced=False,\n value=\"OPENAI_API_KEY\",\n ),\n FloatInput(name=\"temperature\", display_name=\"Temperature\", value=0.1),\n BoolInput(name=\"stream\", display_name=\"Stream\", info=STREAM_INFO_TEXT, advanced=True),\n StrInput(\n name=\"system_message\",\n display_name=\"System Message\",\n info=\"System message to pass to the model.\",\n advanced=True,\n ),\n IntInput(\n name=\"seed\",\n display_name=\"Seed\",\n info=\"The seed controls the reproducibility of the job.\",\n advanced=True,\n value=1,\n ),\n ]\n\n def build_model(self) -> LanguageModel:\n # self.output_schea is a list of dictionaries\n # let's convert it to a dictionary\n output_schema_dict: dict[str, str] = reduce(operator.ior, self.output_schema or {}, {})\n openai_api_key = self.openai_api_key\n temperature = self.temperature\n model_name: str = self.model_name\n max_tokens = self.max_tokens\n model_kwargs = self.model_kwargs or {}\n openai_api_base = self.openai_api_base or \"https://api.openai.com/v1\"\n json_mode = bool(output_schema_dict)\n seed = self.seed\n model_kwargs[\"seed\"] = seed\n\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature or 0.1,\n )\n if json_mode:\n output = output.with_structured_output(schema=output_schema_dict, method=\"json_mode\") # type: ignore\n\n return output\n\n def _get_exception_message(self, e: Exception):\n \"\"\"\n Get a message from an OpenAI exception.\n\n Args:\n exception (Exception): The exception to get the message from.\n\n Returns:\n str: The message from the exception.\n \"\"\"\n\n try:\n from openai import BadRequestError\n except ImportError:\n return\n if isinstance(e, BadRequestError):\n message = e.body.get(\"message\") # type: ignore\n if message:\n return message\n return\n" + }, + "input_value": { + "advanced": false, + "display_name": "Input", + "dynamic": false, + "info": "", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "name": "input_value", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "max_tokens": { + "advanced": true, + "display_name": "Max Tokens", + "dynamic": false, + "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", + "list": false, + "name": "max_tokens", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "int", + "value": "" + }, + "model_kwargs": { + "advanced": true, + "display_name": "Model Kwargs", + "dynamic": false, + "info": "", + "list": false, + "name": "model_kwargs", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "type": "dict", + "value": {} + }, + "model_name": { + "advanced": false, + "display_name": "Model Name", + "dynamic": false, + "info": "", + "name": "model_name", + "options": [ + "gpt-4o", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-3.5-turbo", + "gpt-3.5-turbo-0125" + ], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "gpt-4-turbo" + }, + "openai_api_base": { + "advanced": true, + "display_name": "OpenAI API Base", + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", + "list": false, + "load_from_db": false, + "name": "openai_api_base", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "openai_api_key": { + "advanced": false, + "display_name": "OpenAI API Key", + "dynamic": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "input_types": [], + "load_from_db": false, + "name": "openai_api_key", + "password": true, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "output_schema": { + "advanced": true, + "display_name": "Schema", + "dynamic": false, + "info": "The schema for the Output of the model. You must pass the word JSON in the prompt. If left blank, JSON mode will be disabled.", + "list": true, + "name": "output_schema", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "type": "dict", + "value": {} + }, + "seed": { + "advanced": true, + "display_name": "Seed", + "dynamic": false, + "info": "The seed controls the reproducibility of the job.", + "list": false, + "name": "seed", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "int", + "value": 1 + }, + "stream": { + "advanced": true, + "display_name": "Stream", + "dynamic": false, + "info": "Stream the response from the model. Streaming works only in Chat.", + "list": false, + "name": "stream", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "bool", + "value": false + }, + "system_message": { + "advanced": true, + "display_name": "System Message", + "dynamic": false, + "info": "System message to pass to the model.", + "list": false, + "load_from_db": false, + "name": "system_message", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "temperature": { + "advanced": false, + "display_name": "Temperature", + "dynamic": false, + "info": "", + "list": false, + "name": "temperature", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "float", + "value": 0.1 + } + } + }, + "type": "OpenAIModel" + }, + "dragging": false, + "height": 621, + "id": "OpenAIModel-nJXWj", + "position": { + "x": 624.3539730827923, + "y": 1053.2005475562555 + }, + "positionAbsolute": { + "x": 624.3539730827923, + "y": 1053.2005475562555 + }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { + "data": { + "id": "ChatOutput-XP4bj", + "node": { + "base_classes": [ + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Display a chat message in the Playground.", + "display_name": "Chat Output", + "documentation": "", + "edited": false, + "field_order": [ + "input_value", + "sender", + "sender_name", + "session_id", + "data_template" + ], + "frozen": false, + "icon": "ChatOutput", + "output_types": [], + "outputs": [ + { + "cache": true, + "display_name": "Message", + "method": "message_response", + "name": "message", + "selected": "Message", + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\"],\n value=\"Machine\",\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\", display_name=\"Sender Name\", info=\"Name of the sender.\", value=\"AI\", advanced=True\n ),\n MessageTextInput(\n name=\"session_id\", display_name=\"Session ID\", info=\"Session ID for the message.\", advanced=True\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n )\n if self.session_id and isinstance(message, Message) and isinstance(message.text, str):\n self.store_message(message)\n self.message.value = message\n\n self.status = message\n return message\n" + }, + "data_template": { + "advanced": true, + "display_name": "Data Template", + "dynamic": false, + "info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "name": "data_template", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "{text}" + }, + "input_value": { + "advanced": false, + "display_name": "Text", + "dynamic": false, + "info": "Message to be passed as output.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "name": "input_value", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "sender": { + "advanced": true, + "display_name": "Sender Type", + "dynamic": false, + "info": "Type of sender.", + "name": "sender", + "options": [ + "Machine", + "User" + ], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "Machine" + }, + "sender_name": { + "advanced": true, + "display_name": "Sender Name", + "dynamic": false, + "info": "Name of the sender.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "name": "sender_name", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "AI" + }, + "session_id": { + "advanced": true, + "display_name": "Session ID", + "dynamic": false, + "info": "Session ID for the message.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "name": "session_id", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + } + } + }, + "type": "ChatOutput" + }, + "dragging": false, + "height": 308, + "id": "ChatOutput-XP4bj", + "position": { + "x": 1219.477374823274, + "y": 1200.950216973985 + }, + "positionAbsolute": { + "x": 1219.477374823274, + "y": 1200.950216973985 + }, + "selected": false, "type": "genericNode", "width": 384 } ], "viewport": { - "x": 397.70356097447427, - "y": 260.7996290400466, - "zoom": 0.664116646149498 + "x": 392.1085223509972, + "y": -327.49805229761307, + "zoom": 0.5000000676901589 } }, "description": "This flow will get you experimenting with the basics of the UI, the Chat and the Prompt component. \n\nTry changing the Template in it to see how the model behaves. \nYou can change it to this and a Text Input into the `type_of_person` variable : \"Answer the user as if you were a pirate.\n\nUser: {user_input}\n\nAnswer: \" ", "endpoint_name": null, - "id": "a501072c-37ed-44cf-84ee-b1844d4bc3de", + "id": "f652abdc-7ef2-4e52-a00b-847b7aa32cee", "is_component": false, - "last_tested_version": "1.0.0a61", + "last_tested_version": "1.0.0rc1", "name": "Basic Prompting (Hello, World)" } \ No newline at end of file diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Blog Writer.json b/src/backend/base/langflow/initial_setup/starter_projects/Blog Writer.json new file mode 100644 index 000000000..ec4a19aac --- /dev/null +++ b/src/backend/base/langflow/initial_setup/starter_projects/Blog Writer.json @@ -0,0 +1,1069 @@ +{ + "data": { + "edges": [ + { + "data": { + "sourceHandle": { + "dataType": "URL", + "id": "URL-k9NkE", + "name": "data", + "output_types": [ + "Data" + ] + }, + "targetHandle": { + "fieldName": "data", + "id": "ParseData-EwWXd", + "inputTypes": [ + "Data" + ], + "type": "other" + } + }, + "id": "reactflow__edge-URL-k9NkE{œdataTypeœ:œURLœ,œidœ:œURL-k9NkEœ,œnameœ:œdataœ,œoutput_typesœ:[œDataœ]}-ParseData-EwWXd{œfieldNameœ:œdataœ,œidœ:œParseData-EwWXdœ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}", + "source": "URL-k9NkE", + "sourceHandle": "{œdataTypeœ: œURLœ, œidœ: œURL-k9NkEœ, œnameœ: œdataœ, œoutput_typesœ: [œDataœ]}", + "target": "ParseData-EwWXd", + "targetHandle": "{œfieldNameœ: œdataœ, œidœ: œParseData-EwWXdœ, œinputTypesœ: [œDataœ], œtypeœ: œotherœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "ParseData", + "id": "ParseData-EwWXd", + "name": "text", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "references", + "id": "Prompt-B9Mq6", + "inputTypes": [ + "Message", + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-ParseData-EwWXd{œdataTypeœ:œParseDataœ,œidœ:œParseData-EwWXdœ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-Prompt-B9Mq6{œfieldNameœ:œreferencesœ,œidœ:œPrompt-B9Mq6œ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", + "source": "ParseData-EwWXd", + "sourceHandle": "{œdataTypeœ: œParseDataœ, œidœ: œParseData-EwWXdœ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}", + "target": "Prompt-B9Mq6", + "targetHandle": "{œfieldNameœ: œreferencesœ, œidœ: œPrompt-B9Mq6œ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "TextInput", + "id": "TextInput-uf6ij", + "name": "text", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "instructions", + "id": "Prompt-B9Mq6", + "inputTypes": [ + "Message", + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-TextInput-uf6ij{œdataTypeœ:œTextInputœ,œidœ:œTextInput-uf6ijœ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-Prompt-B9Mq6{œfieldNameœ:œinstructionsœ,œidœ:œPrompt-B9Mq6œ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", + "source": "TextInput-uf6ij", + "sourceHandle": "{œdataTypeœ: œTextInputœ, œidœ: œTextInput-uf6ijœ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}", + "target": "Prompt-B9Mq6", + "targetHandle": "{œfieldNameœ: œinstructionsœ, œidœ: œPrompt-B9Mq6œ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "Prompt", + "id": "Prompt-B9Mq6", + "name": "prompt", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "OpenAIModel-X9ukk", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "reactflow__edge-Prompt-B9Mq6{œdataTypeœ:œPromptœ,œidœ:œPrompt-B9Mq6œ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-X9ukk{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-X9ukkœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "source": "Prompt-B9Mq6", + "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-B9Mq6œ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", + "target": "OpenAIModel-X9ukk", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-X9ukkœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "OpenAIModel", + "id": "OpenAIModel-X9ukk", + "name": "text_output", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-5r5Iw", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "reactflow__edge-OpenAIModel-X9ukk{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-X9ukkœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-5r5Iw{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-5r5Iwœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "source": "OpenAIModel-X9ukk", + "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-X9ukkœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-5r5Iw", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-5r5Iwœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + } + ], + "nodes": [ + { + "data": { + "id": "URL-k9NkE", + "node": { + "base_classes": [ + "Data" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Fetch content from one or more URLs.", + "display_name": "URL", + "documentation": "", + "edited": false, + "field_order": [ + "urls" + ], + "frozen": false, + "icon": "layout-template", + "output_types": [], + "outputs": [ + { + "cache": true, + "display_name": "Data", + "hidden": false, + "method": "fetch_content", + "name": "data", + "selected": "Data", + "types": [ + "Data" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "import re\n\nfrom langchain_community.document_loaders.web_base import WebBaseLoader\n\nfrom langflow.custom import Component\nfrom langflow.io import MessageTextInput, Output\nfrom langflow.schema import Data\n\n\nclass URLComponent(Component):\n display_name = \"URL\"\n description = \"Fetch content from one or more URLs.\"\n icon = \"layout-template\"\n\n inputs = [\n MessageTextInput(\n name=\"urls\",\n display_name=\"URLs\",\n info=\"Enter one or more URLs, separated by commas.\",\n is_list=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Data\", name=\"data\", method=\"fetch_content\"),\n ]\n\n def ensure_url(self, string: str) -> str:\n \"\"\"\n Ensures the given string is a URL by adding 'http://' if it doesn't start with 'http://' or 'https://'.\n Raises an error if the string is not a valid URL.\n\n Parameters:\n string (str): The string to be checked and possibly modified.\n\n Returns:\n str: The modified string that is ensured to be a URL.\n\n Raises:\n ValueError: If the string is not a valid URL.\n \"\"\"\n if not string.startswith((\"http://\", \"https://\")):\n string = \"http://\" + string\n\n # Basic URL validation regex\n url_regex = re.compile(\n r\"^(https?:\\/\\/)?\" # optional protocol\n r\"(www\\.)?\" # optional www\n r\"([a-zA-Z0-9.-]+)\" # domain\n r\"(\\.[a-zA-Z]{2,})?\" # top-level domain\n r\"(:\\d+)?\" # optional port\n r\"(\\/[^\\s]*)?$\", # optional path\n re.IGNORECASE,\n )\n\n if not url_regex.match(string):\n raise ValueError(f\"Invalid URL: {string}\")\n\n return string\n\n def fetch_content(self) -> list[Data]:\n urls = [self.ensure_url(url.strip()) for url in self.urls if url.strip()]\n loader = WebBaseLoader(web_paths=urls, encoding=\"utf-8\")\n docs = loader.load()\n data = [Data(text=doc.page_content, **doc.metadata) for doc in docs]\n self.status = data\n return data\n" + }, + "urls": { + "advanced": false, + "display_name": "URLs", + "dynamic": false, + "info": "Enter one or more URLs, separated by commas.", + "input_types": [ + "Message" + ], + "list": true, + "load_from_db": false, + "name": "urls", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": [ + "langflow.org/", + "docs.langflow.org/" + ] + } + } + }, + "type": "URL" + }, + "dragging": false, + "height": 358, + "id": "URL-k9NkE", + "position": { + "x": 220.79156431407534, + "y": 498.8186168722667 + }, + "positionAbsolute": { + "x": 220.79156431407534, + "y": 498.8186168722667 + }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { + "data": { + "id": "ParseData-EwWXd", + "node": { + "base_classes": [ + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Convert Data into plain text following a specified template.", + "display_name": "Parse Data", + "documentation": "", + "edited": false, + "field_order": [ + "data", + "template", + "sep" + ], + "frozen": false, + "icon": "braces", + "output_types": [], + "outputs": [ + { + "cache": true, + "display_name": "Text", + "hidden": false, + "method": "parse_data", + "name": "text", + "selected": "Message", + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Parse Data\"\n description = \"Convert Data into plain text following a specified template.\"\n icon = \"braces\"\n\n inputs = [\n DataInput(name=\"data\", display_name=\"Data\", info=\"The data to convert to text.\"),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(display_name=\"Text\", name=\"text\", method=\"parse_data\"),\n ]\n\n def parse_data(self) -> Message:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n\n result_string = data_to_text(template, data, sep=self.sep)\n self.status = result_string\n return Message(text=result_string)\n" + }, + "data": { + "advanced": false, + "display_name": "Data", + "dynamic": false, + "info": "The data to convert to text.", + "input_types": [ + "Data" + ], + "list": false, + "name": "data", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "other", + "value": "" + }, + "sep": { + "advanced": true, + "display_name": "Separator", + "dynamic": false, + "info": "", + "list": false, + "load_from_db": false, + "name": "sep", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "\n" + }, + "template": { + "advanced": false, + "display_name": "Template", + "dynamic": false, + "info": "The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "template", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "{text}" + } + } + }, + "type": "ParseData" + }, + "dragging": false, + "height": 384, + "id": "ParseData-EwWXd", + "position": { + "x": 754.3607306709101, + "y": 736.8516961537598 + }, + "positionAbsolute": { + "x": 754.3607306709101, + "y": 736.8516961537598 + }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { + "data": { + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt", + "id": "Prompt-B9Mq6", + "node": { + "base_classes": [ + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": { + "template": [ + "references", + "instructions" + ] + }, + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt", + "documentation": "", + "edited": false, + "error": null, + "field_order": [ + "template" + ], + "frozen": false, + "full_path": null, + "icon": "prompts", + "is_composition": null, + "is_input": null, + "is_output": null, + "name": "", + "output_types": [], + "outputs": [ + { + "cache": true, + "display_name": "Prompt Message", + "hidden": false, + "method": "build_prompt", + "name": "prompt", + "selected": "Message", + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "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.io import 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\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n prompt = await Message.from_template_and_variables(**self._attributes)\n self.status = prompt.text\n return prompt\n\n def post_code_processing(self, new_build_config: dict, current_build_config: dict):\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(new_build_config, current_build_config)\n template = frontend_node[\"template\"][\"template\"][\"value\"]\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_build_config\n # and update the frontend_node with those values\n update_template_values(frontend_template=frontend_node, raw_template=current_build_config[\"template\"])\n return frontend_node\n" + }, + "instructions": { + "advanced": false, + "display_name": "instructions", + "dynamic": false, + "field_type": "str", + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Message", + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "instructions", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "references": { + "advanced": false, + "display_name": "references", + "dynamic": false, + "field_type": "str", + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Message", + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "references", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "template": { + "advanced": false, + "display_name": "Template", + "dynamic": false, + "info": "", + "list": false, + "name": "template", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "type": "prompt", + "value": "Reference 1:\n\n{references}\n\n---\n\n{instructions}\n\nBlog: \n\n" + } + } + }, + "type": "Prompt" + }, + "dragging": false, + "height": 515, + "id": "Prompt-B9Mq6", + "position": { + "x": 1368.0633591447076, + "y": 467.19448061224284 + }, + "positionAbsolute": { + "x": 1368.0633591447076, + "y": 467.19448061224284 + }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { + "data": { + "id": "TextInput-uf6ij", + "node": { + "base_classes": [ + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Get text inputs from the Playground.", + "display_name": "Instructions", + "documentation": "", + "edited": false, + "field_order": [ + "input_value" + ], + "frozen": false, + "icon": "type", + "output_types": [], + "outputs": [ + { + "cache": true, + "display_name": "Text", + "hidden": false, + "method": "text_response", + "name": "text", + "selected": "Message", + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from langflow.base.io.text import TextComponent\nfrom langflow.io import MessageTextInput, Output\nfrom langflow.schema.message import Message\n\n\nclass TextInputComponent(TextComponent):\n display_name = \"Text Input\"\n description = \"Get text inputs from the Playground.\"\n icon = \"type\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Text to be passed as input.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Text\", name=\"text\", method=\"text_response\"),\n ]\n\n def text_response(self) -> Message:\n message = Message(\n text=self.input_value,\n )\n return message\n" + }, + "input_value": { + "advanced": false, + "display_name": "Text", + "dynamic": false, + "info": "Text to be passed as input.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "name": "input_value", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "Use the references above for style to write a new blog/tutorial about Langflow and AI. Suggest non-covered topics." + } + } + }, + "type": "TextInput" + }, + "dragging": false, + "height": 308, + "id": "TextInput-uf6ij", + "position": { + "x": 743.7338453293725, + "y": 301.58775454952183 + }, + "positionAbsolute": { + "x": 743.7338453293725, + "y": 301.58775454952183 + }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { + "data": { + "id": "OpenAIModel-X9ukk", + "node": { + "base_classes": [ + "LanguageModel", + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Generates text using OpenAI LLMs.", + "display_name": "OpenAI", + "documentation": "", + "edited": false, + "field_order": [ + "input_value", + "max_tokens", + "model_kwargs", + "output_schema", + "model_name", + "openai_api_base", + "openai_api_key", + "temperature", + "stream", + "system_message", + "seed" + ], + "frozen": false, + "icon": "OpenAI", + "output_types": [], + "outputs": [ + { + "cache": true, + "display_name": "Text", + "hidden": false, + "method": "text_response", + "name": "text_output", + "selected": "Message", + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + }, + { + "cache": true, + "display_name": "Language Model", + "method": "build_model", + "name": "model_output", + "selected": "LanguageModel", + "types": [ + "LanguageModel" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "import operator\nfrom functools import reduce\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import LanguageModel\nfrom langflow.inputs import (\n BoolInput,\n DictInput,\n DropdownInput,\n FloatInput,\n IntInput,\n MessageInput,\n SecretStrInput,\n StrInput,\n)\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n inputs = [\n MessageInput(name=\"input_value\", display_name=\"Input\"),\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n info=\"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n ),\n DictInput(name=\"model_kwargs\", display_name=\"Model Kwargs\", advanced=True),\n DictInput(\n name=\"output_schema\",\n is_list=True,\n display_name=\"Schema\",\n advanced=True,\n info=\"The schema for the Output of the model. You must pass the word JSON in the prompt. If left blank, JSON mode will be disabled.\",\n ),\n DropdownInput(\n name=\"model_name\", display_name=\"Model Name\", advanced=False, options=MODEL_NAMES, value=MODEL_NAMES[0]\n ),\n StrInput(\n name=\"openai_api_base\",\n display_name=\"OpenAI API Base\",\n advanced=True,\n info=\"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.\",\n ),\n SecretStrInput(\n name=\"openai_api_key\",\n display_name=\"OpenAI API Key\",\n info=\"The OpenAI API Key to use for the OpenAI model.\",\n advanced=False,\n value=\"OPENAI_API_KEY\",\n ),\n FloatInput(name=\"temperature\", display_name=\"Temperature\", value=0.1),\n BoolInput(name=\"stream\", display_name=\"Stream\", info=STREAM_INFO_TEXT, advanced=True),\n StrInput(\n name=\"system_message\",\n display_name=\"System Message\",\n info=\"System message to pass to the model.\",\n advanced=True,\n ),\n IntInput(\n name=\"seed\",\n display_name=\"Seed\",\n info=\"The seed controls the reproducibility of the job.\",\n advanced=True,\n value=1,\n ),\n ]\n\n def build_model(self) -> LanguageModel:\n # self.output_schea is a list of dictionaries\n # let's convert it to a dictionary\n output_schema_dict: dict[str, str] = reduce(operator.ior, self.output_schema or {}, {})\n openai_api_key = self.openai_api_key\n temperature = self.temperature\n model_name: str = self.model_name\n max_tokens = self.max_tokens\n model_kwargs = self.model_kwargs or {}\n openai_api_base = self.openai_api_base or \"https://api.openai.com/v1\"\n json_mode = bool(output_schema_dict)\n seed = self.seed\n model_kwargs[\"seed\"] = seed\n\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature or 0.1,\n )\n if json_mode:\n output = output.with_structured_output(schema=output_schema_dict, method=\"json_mode\") # type: ignore\n\n return output\n\n def _get_exception_message(self, e: Exception):\n \"\"\"\n Get a message from an OpenAI exception.\n\n Args:\n exception (Exception): The exception to get the message from.\n\n Returns:\n str: The message from the exception.\n \"\"\"\n\n try:\n from openai import BadRequestError\n except ImportError:\n return\n if isinstance(e, BadRequestError):\n message = e.body.get(\"message\") # type: ignore\n if message:\n return message\n return\n" + }, + "input_value": { + "advanced": false, + "display_name": "Input", + "dynamic": false, + "info": "", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "name": "input_value", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "max_tokens": { + "advanced": true, + "display_name": "Max Tokens", + "dynamic": false, + "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", + "list": false, + "name": "max_tokens", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "int", + "value": "" + }, + "model_kwargs": { + "advanced": true, + "display_name": "Model Kwargs", + "dynamic": false, + "info": "", + "list": false, + "name": "model_kwargs", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "type": "dict", + "value": {} + }, + "model_name": { + "advanced": false, + "display_name": "Model Name", + "dynamic": false, + "info": "", + "name": "model_name", + "options": [ + "gpt-4o", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-3.5-turbo", + "gpt-3.5-turbo-0125" + ], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "gpt-4-turbo" + }, + "openai_api_base": { + "advanced": true, + "display_name": "OpenAI API Base", + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", + "list": false, + "load_from_db": false, + "name": "openai_api_base", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "openai_api_key": { + "advanced": false, + "display_name": "OpenAI API Key", + "dynamic": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "input_types": [], + "load_from_db": false, + "name": "openai_api_key", + "password": true, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "output_schema": { + "advanced": true, + "display_name": "Schema", + "dynamic": false, + "info": "The schema for the Output of the model. You must pass the word JSON in the prompt. If left blank, JSON mode will be disabled.", + "list": true, + "name": "output_schema", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "type": "dict", + "value": {} + }, + "seed": { + "advanced": true, + "display_name": "Seed", + "dynamic": false, + "info": "The seed controls the reproducibility of the job.", + "list": false, + "name": "seed", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "int", + "value": 1 + }, + "stream": { + "advanced": true, + "display_name": "Stream", + "dynamic": false, + "info": "Stream the response from the model. Streaming works only in Chat.", + "list": false, + "name": "stream", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "bool", + "value": false + }, + "system_message": { + "advanced": true, + "display_name": "System Message", + "dynamic": false, + "info": "System message to pass to the model.", + "list": false, + "load_from_db": false, + "name": "system_message", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "temperature": { + "advanced": false, + "display_name": "Temperature", + "dynamic": false, + "info": "", + "list": false, + "name": "temperature", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "float", + "value": 0.1 + } + } + }, + "type": "OpenAIModel" + }, + "dragging": false, + "height": 621, + "id": "OpenAIModel-X9ukk", + "position": { + "x": 1899.407626221589, + "y": 395.9013619556682 + }, + "positionAbsolute": { + "x": 1899.407626221589, + "y": 395.9013619556682 + }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { + "data": { + "id": "ChatOutput-5r5Iw", + "node": { + "base_classes": [ + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Display a chat message in the Playground.", + "display_name": "Chat Output", + "documentation": "", + "edited": false, + "field_order": [ + "input_value", + "sender", + "sender_name", + "session_id", + "data_template" + ], + "frozen": false, + "icon": "ChatOutput", + "output_types": [], + "outputs": [ + { + "cache": true, + "display_name": "Message", + "method": "message_response", + "name": "message", + "selected": "Message", + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\"],\n value=\"Machine\",\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\", display_name=\"Sender Name\", info=\"Name of the sender.\", value=\"AI\", advanced=True\n ),\n MessageTextInput(\n name=\"session_id\", display_name=\"Session ID\", info=\"Session ID for the message.\", advanced=True\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n )\n if self.session_id and isinstance(message, Message) and isinstance(message.text, str):\n self.store_message(message)\n self.message.value = message\n\n self.status = message\n return message\n" + }, + "data_template": { + "advanced": true, + "display_name": "Data Template", + "dynamic": false, + "info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "name": "data_template", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "{text}" + }, + "input_value": { + "advanced": false, + "display_name": "Text", + "dynamic": false, + "info": "Message to be passed as output.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "name": "input_value", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "sender": { + "advanced": true, + "display_name": "Sender Type", + "dynamic": false, + "info": "Type of sender.", + "name": "sender", + "options": [ + "Machine", + "User" + ], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "Machine" + }, + "sender_name": { + "advanced": true, + "display_name": "Sender Name", + "dynamic": false, + "info": "Name of the sender.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "name": "sender_name", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "AI" + }, + "session_id": { + "advanced": true, + "display_name": "Session ID", + "dynamic": false, + "info": "Session ID for the message.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "name": "session_id", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + } + } + }, + "type": "ChatOutput" + }, + "dragging": false, + "height": 308, + "id": "ChatOutput-5r5Iw", + "position": { + "x": 2449.3489426461606, + "y": 571.2449700910389 + }, + "positionAbsolute": { + "x": 2449.3489426461606, + "y": 571.2449700910389 + }, + "selected": false, + "type": "genericNode", + "width": 384 + } + ], + "viewport": { + "x": -63.94787944982488, + "y": -16.004163894553585, + "zoom": 0.47423908935061165 + } + }, + "description": "This flow can be used to create a blog post following instructions from the user, using two other blogs as reference.", + "endpoint_name": null, + "id": "13da3150-95b9-4d81-9ad2-f635dcdce7ab", + "is_component": false, + "last_tested_version": "1.0.0rc1", + "name": "Blog Writer" +} \ No newline at end of file diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Document QA.json b/src/backend/base/langflow/initial_setup/starter_projects/Document QA.json new file mode 100644 index 000000000..d66c6b22b --- /dev/null +++ b/src/backend/base/langflow/initial_setup/starter_projects/Document QA.json @@ -0,0 +1,1202 @@ +{ + "data": { + "edges": [ + { + "data": { + "sourceHandle": { + "dataType": "File", + "id": "File-h46aK", + "name": "data", + "output_types": [ + "Data" + ] + }, + "targetHandle": { + "fieldName": "data", + "id": "ParseData-sqVr1", + "inputTypes": [ + "Data" + ], + "type": "other" + } + }, + "id": "reactflow__edge-File-h46aK{œdataTypeœ:œFileœ,œidœ:œFile-h46aKœ,œnameœ:œdataœ,œoutput_typesœ:[œDataœ]}-ParseData-sqVr1{œfieldNameœ:œdataœ,œidœ:œParseData-sqVr1œ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}", + "source": "File-h46aK", + "sourceHandle": "{œdataTypeœ: œFileœ, œidœ: œFile-h46aKœ, œnameœ: œdataœ, œoutput_typesœ: [œDataœ]}", + "target": "ParseData-sqVr1", + "targetHandle": "{œfieldNameœ: œdataœ, œidœ: œParseData-sqVr1œ, œinputTypesœ: [œDataœ], œtypeœ: œotherœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "ParseData", + "id": "ParseData-sqVr1", + "name": "text", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "Document", + "id": "Prompt-mQ7w2", + "inputTypes": [ + "Message", + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-ParseData-sqVr1{œdataTypeœ:œParseDataœ,œidœ:œParseData-sqVr1œ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-Prompt-mQ7w2{œfieldNameœ:œDocumentœ,œidœ:œPrompt-mQ7w2œ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", + "source": "ParseData-sqVr1", + "sourceHandle": "{œdataTypeœ: œParseDataœ, œidœ: œParseData-sqVr1œ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}", + "target": "Prompt-mQ7w2", + "targetHandle": "{œfieldNameœ: œDocumentœ, œidœ: œPrompt-mQ7w2œ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "ChatInput", + "id": "ChatInput-cMXe0", + "name": "message", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "Question", + "id": "Prompt-mQ7w2", + "inputTypes": [ + "Message", + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-ChatInput-cMXe0{œdataTypeœ:œChatInputœ,œidœ:œChatInput-cMXe0œ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Prompt-mQ7w2{œfieldNameœ:œQuestionœ,œidœ:œPrompt-mQ7w2œ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", + "source": "ChatInput-cMXe0", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-cMXe0œ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "Prompt-mQ7w2", + "targetHandle": "{œfieldNameœ: œQuestionœ, œidœ: œPrompt-mQ7w2œ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "Prompt", + "id": "Prompt-mQ7w2", + "name": "prompt", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "OpenAIModel-O0AGC", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "reactflow__edge-Prompt-mQ7w2{œdataTypeœ:œPromptœ,œidœ:œPrompt-mQ7w2œ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-O0AGC{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-O0AGCœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "source": "Prompt-mQ7w2", + "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-mQ7w2œ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", + "target": "OpenAIModel-O0AGC", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-O0AGCœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "OpenAIModel", + "id": "OpenAIModel-O0AGC", + "name": "text_output", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-efggd", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "reactflow__edge-OpenAIModel-O0AGC{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-O0AGCœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-efggd{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-efggdœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "source": "OpenAIModel-O0AGC", + "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-O0AGCœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-efggd", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-efggdœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + } + ], + "nodes": [ + { + "data": { + "id": "File-h46aK", + "node": { + "base_classes": [ + "Data" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "A generic file loader.", + "display_name": "File", + "documentation": "", + "edited": false, + "field_order": [ + "path", + "silent_errors" + ], + "frozen": false, + "icon": "file-text", + "output_types": [], + "outputs": [ + { + "cache": true, + "display_name": "Data", + "hidden": false, + "method": "load_file", + "name": "data", + "selected": "Data", + "types": [ + "Data" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from pathlib import Path\n\nfrom langflow.base.data.utils import TEXT_FILE_TYPES, parse_text_file_to_data\nfrom langflow.custom import Component\nfrom langflow.io import BoolInput, FileInput, Output\nfrom langflow.schema import Data\n\n\nclass FileComponent(Component):\n display_name = \"File\"\n description = \"A generic file loader.\"\n icon = \"file-text\"\n\n inputs = [\n FileInput(\n name=\"path\",\n display_name=\"Path\",\n file_types=TEXT_FILE_TYPES,\n info=f\"Supported file types: {', '.join(TEXT_FILE_TYPES)}\",\n ),\n BoolInput(\n name=\"silent_errors\",\n display_name=\"Silent Errors\",\n advanced=True,\n info=\"If true, errors will not raise an exception.\",\n ),\n ]\n\n outputs = [\n Output(display_name=\"Data\", name=\"data\", method=\"load_file\"),\n ]\n\n def load_file(self) -> Data:\n if not self.path:\n raise ValueError(\"Please, upload a file to use this component.\")\n resolved_path = self.resolve_path(self.path)\n silent_errors = self.silent_errors\n\n extension = Path(resolved_path).suffix[1:].lower()\n\n if extension == \"doc\":\n raise ValueError(\"doc files are not supported. Please save as .docx\")\n if extension not in TEXT_FILE_TYPES:\n raise ValueError(f\"Unsupported file type: {extension}\")\n\n data = parse_text_file_to_data(resolved_path, silent_errors)\n self.status = data if data else \"No data\"\n return data or Data()\n" + }, + "path": { + "advanced": false, + "display_name": "Path", + "dynamic": false, + "fileTypes": [ + "txt", + "md", + "mdx", + "csv", + "json", + "yaml", + "yml", + "xml", + "html", + "htm", + "pdf", + "docx", + "py", + "sh", + "sql", + "js", + "ts", + "tsx" + ], + "file_path": "", + "info": "Supported file types: txt, md, mdx, csv, json, yaml, yml, xml, html, htm, pdf, docx, py, sh, sql, js, ts, tsx", + "list": false, + "name": "path", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "file", + "value": "" + }, + "silent_errors": { + "advanced": true, + "display_name": "Silent Errors", + "dynamic": false, + "info": "If true, errors will not raise an exception.", + "list": false, + "name": "silent_errors", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "bool", + "value": false + } + } + }, + "type": "File" + }, + "dragging": false, + "height": 300, + "id": "File-h46aK", + "position": { + "x": -449.0807503257012, + "y": -253.5304920926106 + }, + "positionAbsolute": { + "x": -449.0807503257012, + "y": -253.5304920926106 + }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { + "data": { + "id": "ParseData-sqVr1", + "node": { + "base_classes": [ + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Convert Data into plain text following a specified template.", + "display_name": "Parse Data", + "documentation": "", + "edited": false, + "field_order": [ + "data", + "template", + "sep" + ], + "frozen": false, + "icon": "braces", + "output_types": [], + "outputs": [ + { + "cache": true, + "display_name": "Text", + "hidden": false, + "method": "parse_data", + "name": "text", + "selected": "Message", + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Parse Data\"\n description = \"Convert Data into plain text following a specified template.\"\n icon = \"braces\"\n\n inputs = [\n DataInput(name=\"data\", display_name=\"Data\", info=\"The data to convert to text.\"),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(display_name=\"Text\", name=\"text\", method=\"parse_data\"),\n ]\n\n def parse_data(self) -> Message:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n\n result_string = data_to_text(template, data, sep=self.sep)\n self.status = result_string\n return Message(text=result_string)\n" + }, + "data": { + "advanced": false, + "display_name": "Data", + "dynamic": false, + "info": "The data to convert to text.", + "input_types": [ + "Data" + ], + "list": false, + "name": "data", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "other", + "value": "" + }, + "sep": { + "advanced": true, + "display_name": "Separator", + "dynamic": false, + "info": "", + "list": false, + "load_from_db": false, + "name": "sep", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "\n" + }, + "template": { + "advanced": false, + "display_name": "Template", + "dynamic": false, + "info": "The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "template", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "{text}" + } + } + }, + "type": "ParseData" + }, + "dragging": false, + "height": 384, + "id": "ParseData-sqVr1", + "position": { + "x": 73.79471204296345, + "y": -186.9430114986888 + }, + "positionAbsolute": { + "x": 73.79471204296345, + "y": -186.9430114986888 + }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { + "data": { + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt", + "id": "Prompt-mQ7w2", + "node": { + "base_classes": [ + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": { + "template": [ + "Document", + "Question" + ] + }, + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt", + "documentation": "", + "edited": false, + "error": null, + "field_order": [ + "template" + ], + "frozen": false, + "full_path": null, + "icon": "prompts", + "is_composition": null, + "is_input": null, + "is_output": null, + "name": "", + "output_types": [], + "outputs": [ + { + "cache": true, + "display_name": "Prompt Message", + "hidden": false, + "method": "build_prompt", + "name": "prompt", + "selected": "Message", + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "Document": { + "advanced": false, + "display_name": "Document", + "dynamic": false, + "field_type": "str", + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Message", + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "Document", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "Question": { + "advanced": false, + "display_name": "Question", + "dynamic": false, + "field_type": "str", + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Message", + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "Question", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "_type": "Component", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "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.io import 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\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n prompt = await Message.from_template_and_variables(**self._attributes)\n self.status = prompt.text\n return prompt\n\n def post_code_processing(self, new_build_config: dict, current_build_config: dict):\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(new_build_config, current_build_config)\n template = frontend_node[\"template\"][\"template\"][\"value\"]\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_build_config\n # and update the frontend_node with those values\n update_template_values(frontend_template=frontend_node, raw_template=current_build_config[\"template\"])\n return frontend_node\n" + }, + "template": { + "advanced": false, + "display_name": "Template", + "dynamic": false, + "info": "", + "list": false, + "name": "template", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "type": "prompt", + "value": "Answer user's questions based on the document below:\n\n---\n\n{Document}\n\n---\n\nQuestion:\n{Question}\n\nAnswer:\n" + } + } + }, + "type": "Prompt" + }, + "dragging": false, + "height": 515, + "id": "Prompt-mQ7w2", + "position": { + "x": 637.3518652087848, + "y": 47.191730368560215 + }, + "positionAbsolute": { + "x": 637.3518652087848, + "y": 47.191730368560215 + }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { + "data": { + "id": "ChatInput-cMXe0", + "node": { + "base_classes": [ + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Get chat inputs from the Playground.", + "display_name": "Chat Input", + "documentation": "", + "edited": false, + "field_order": [ + "input_value", + "sender", + "sender_name", + "session_id", + "files" + ], + "frozen": false, + "icon": "ChatInput", + "output_types": [], + "outputs": [ + { + "cache": true, + "display_name": "Message", + "hidden": false, + "method": "message_response", + "name": "message", + "selected": "Message", + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.schema.message import Message\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\"],\n value=\"User\",\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=\"User\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\", display_name=\"Session ID\", info=\"Session ID for the message.\", advanced=True\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n )\n if self.session_id and isinstance(message, Message) and isinstance(message.text, str):\n self.store_message(message)\n self.message.value = message\n\n self.status = message\n return message\n" + }, + "files": { + "advanced": true, + "display_name": "Files", + "dynamic": false, + "fileTypes": [ + "txt", + "md", + "mdx", + "csv", + "json", + "yaml", + "yml", + "xml", + "html", + "htm", + "pdf", + "docx", + "py", + "sh", + "sql", + "js", + "ts", + "tsx", + "jpg", + "jpeg", + "png", + "bmp", + "image" + ], + "file_path": "", + "info": "Files to be sent with the message.", + "list": true, + "name": "files", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "file", + "value": "" + }, + "input_value": { + "advanced": false, + "display_name": "Text", + "dynamic": false, + "info": "Message to be passed as input.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "input_value", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "sender": { + "advanced": true, + "display_name": "Sender Type", + "dynamic": false, + "info": "Type of sender.", + "name": "sender", + "options": [ + "Machine", + "User" + ], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "User" + }, + "sender_name": { + "advanced": true, + "display_name": "Sender Name", + "dynamic": false, + "info": "Name of the sender.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "name": "sender_name", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "User" + }, + "session_id": { + "advanced": true, + "display_name": "Session ID", + "dynamic": false, + "info": "Session ID for the message.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "name": "session_id", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + } + } + }, + "type": "ChatInput" + }, + "dragging": false, + "height": 308, + "id": "ChatInput-cMXe0", + "position": { + "x": 50.08709924122684, + "y": 320.88186720121615 + }, + "positionAbsolute": { + "x": 50.08709924122684, + "y": 320.88186720121615 + }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { + "data": { + "id": "OpenAIModel-O0AGC", + "node": { + "base_classes": [ + "LanguageModel", + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Generates text using OpenAI LLMs.", + "display_name": "OpenAI", + "documentation": "", + "edited": false, + "field_order": [ + "input_value", + "max_tokens", + "model_kwargs", + "output_schema", + "model_name", + "openai_api_base", + "openai_api_key", + "temperature", + "stream", + "system_message", + "seed" + ], + "frozen": false, + "icon": "OpenAI", + "output_types": [], + "outputs": [ + { + "cache": true, + "display_name": "Text", + "hidden": false, + "method": "text_response", + "name": "text_output", + "selected": "Message", + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + }, + { + "cache": true, + "display_name": "Language Model", + "method": "build_model", + "name": "model_output", + "selected": "LanguageModel", + "types": [ + "LanguageModel" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "import operator\nfrom functools import reduce\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import LanguageModel\nfrom langflow.inputs import (\n BoolInput,\n DictInput,\n DropdownInput,\n FloatInput,\n IntInput,\n MessageInput,\n SecretStrInput,\n StrInput,\n)\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n inputs = [\n MessageInput(name=\"input_value\", display_name=\"Input\"),\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n info=\"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n ),\n DictInput(name=\"model_kwargs\", display_name=\"Model Kwargs\", advanced=True),\n DictInput(\n name=\"output_schema\",\n is_list=True,\n display_name=\"Schema\",\n advanced=True,\n info=\"The schema for the Output of the model. You must pass the word JSON in the prompt. If left blank, JSON mode will be disabled.\",\n ),\n DropdownInput(\n name=\"model_name\", display_name=\"Model Name\", advanced=False, options=MODEL_NAMES, value=MODEL_NAMES[0]\n ),\n StrInput(\n name=\"openai_api_base\",\n display_name=\"OpenAI API Base\",\n advanced=True,\n info=\"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.\",\n ),\n SecretStrInput(\n name=\"openai_api_key\",\n display_name=\"OpenAI API Key\",\n info=\"The OpenAI API Key to use for the OpenAI model.\",\n advanced=False,\n value=\"OPENAI_API_KEY\",\n ),\n FloatInput(name=\"temperature\", display_name=\"Temperature\", value=0.1),\n BoolInput(name=\"stream\", display_name=\"Stream\", info=STREAM_INFO_TEXT, advanced=True),\n StrInput(\n name=\"system_message\",\n display_name=\"System Message\",\n info=\"System message to pass to the model.\",\n advanced=True,\n ),\n IntInput(\n name=\"seed\",\n display_name=\"Seed\",\n info=\"The seed controls the reproducibility of the job.\",\n advanced=True,\n value=1,\n ),\n ]\n\n def build_model(self) -> LanguageModel:\n # self.output_schea is a list of dictionaries\n # let's convert it to a dictionary\n output_schema_dict: dict[str, str] = reduce(operator.ior, self.output_schema or {}, {})\n openai_api_key = self.openai_api_key\n temperature = self.temperature\n model_name: str = self.model_name\n max_tokens = self.max_tokens\n model_kwargs = self.model_kwargs or {}\n openai_api_base = self.openai_api_base or \"https://api.openai.com/v1\"\n json_mode = bool(output_schema_dict)\n seed = self.seed\n model_kwargs[\"seed\"] = seed\n\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature or 0.1,\n )\n if json_mode:\n output = output.with_structured_output(schema=output_schema_dict, method=\"json_mode\") # type: ignore\n\n return output\n\n def _get_exception_message(self, e: Exception):\n \"\"\"\n Get a message from an OpenAI exception.\n\n Args:\n exception (Exception): The exception to get the message from.\n\n Returns:\n str: The message from the exception.\n \"\"\"\n\n try:\n from openai import BadRequestError\n except ImportError:\n return\n if isinstance(e, BadRequestError):\n message = e.body.get(\"message\") # type: ignore\n if message:\n return message\n return\n" + }, + "input_value": { + "advanced": false, + "display_name": "Input", + "dynamic": false, + "info": "", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "name": "input_value", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "max_tokens": { + "advanced": true, + "display_name": "Max Tokens", + "dynamic": false, + "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", + "list": false, + "name": "max_tokens", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "int", + "value": "" + }, + "model_kwargs": { + "advanced": true, + "display_name": "Model Kwargs", + "dynamic": false, + "info": "", + "list": false, + "name": "model_kwargs", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "type": "dict", + "value": {} + }, + "model_name": { + "advanced": false, + "display_name": "Model Name", + "dynamic": false, + "info": "", + "name": "model_name", + "options": [ + "gpt-4o", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-3.5-turbo", + "gpt-3.5-turbo-0125" + ], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "gpt-4-turbo" + }, + "openai_api_base": { + "advanced": true, + "display_name": "OpenAI API Base", + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", + "list": false, + "load_from_db": false, + "name": "openai_api_base", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "openai_api_key": { + "advanced": false, + "display_name": "OpenAI API Key", + "dynamic": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "input_types": [], + "load_from_db": false, + "name": "openai_api_key", + "password": true, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "output_schema": { + "advanced": true, + "display_name": "Schema", + "dynamic": false, + "info": "The schema for the Output of the model. You must pass the word JSON in the prompt. If left blank, JSON mode will be disabled.", + "list": true, + "name": "output_schema", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "type": "dict", + "value": {} + }, + "seed": { + "advanced": true, + "display_name": "Seed", + "dynamic": false, + "info": "The seed controls the reproducibility of the job.", + "list": false, + "name": "seed", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "int", + "value": 1 + }, + "stream": { + "advanced": true, + "display_name": "Stream", + "dynamic": false, + "info": "Stream the response from the model. Streaming works only in Chat.", + "list": false, + "name": "stream", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "bool", + "value": false + }, + "system_message": { + "advanced": true, + "display_name": "System Message", + "dynamic": false, + "info": "System message to pass to the model.", + "list": false, + "load_from_db": false, + "name": "system_message", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "temperature": { + "advanced": false, + "display_name": "Temperature", + "dynamic": false, + "info": "", + "list": false, + "name": "temperature", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "float", + "value": 0.1 + } + } + }, + "type": "OpenAIModel" + }, + "dragging": false, + "height": 621, + "id": "OpenAIModel-O0AGC", + "position": { + "x": 1227.3672858178775, + "y": 11.61201090144857 + }, + "positionAbsolute": { + "x": 1227.3672858178775, + "y": 11.61201090144857 + }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { + "data": { + "id": "ChatOutput-efggd", + "node": { + "base_classes": [ + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Display a chat message in the Playground.", + "display_name": "Chat Output", + "documentation": "", + "edited": false, + "field_order": [ + "input_value", + "sender", + "sender_name", + "session_id", + "data_template" + ], + "frozen": false, + "icon": "ChatOutput", + "output_types": [], + "outputs": [ + { + "cache": true, + "display_name": "Message", + "method": "message_response", + "name": "message", + "selected": "Message", + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\"],\n value=\"Machine\",\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\", display_name=\"Sender Name\", info=\"Name of the sender.\", value=\"AI\", advanced=True\n ),\n MessageTextInput(\n name=\"session_id\", display_name=\"Session ID\", info=\"Session ID for the message.\", advanced=True\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n )\n if self.session_id and isinstance(message, Message) and isinstance(message.text, str):\n self.store_message(message)\n self.message.value = message\n\n self.status = message\n return message\n" + }, + "data_template": { + "advanced": true, + "display_name": "Data Template", + "dynamic": false, + "info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "name": "data_template", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "{text}" + }, + "input_value": { + "advanced": false, + "display_name": "Text", + "dynamic": false, + "info": "Message to be passed as output.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "name": "input_value", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "sender": { + "advanced": true, + "display_name": "Sender Type", + "dynamic": false, + "info": "Type of sender.", + "name": "sender", + "options": [ + "Machine", + "User" + ], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "Machine" + }, + "sender_name": { + "advanced": true, + "display_name": "Sender Name", + "dynamic": false, + "info": "Name of the sender.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "name": "sender_name", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "AI" + }, + "session_id": { + "advanced": true, + "display_name": "Session ID", + "dynamic": false, + "info": "Session ID for the message.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "name": "session_id", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + } + } + }, + "type": "ChatOutput" + }, + "dragging": false, + "height": 308, + "id": "ChatOutput-efggd", + "position": { + "x": 1831.1359796346408, + "y": 139.5174517327903 + }, + "positionAbsolute": { + "x": 1831.1359796346408, + "y": 139.5174517327903 + }, + "selected": false, + "type": "genericNode", + "width": 384 + } + ], + "viewport": { + "x": 249.03047748371796, + "y": 251.71203687916693, + "zoom": 0.4580440916596844 + } + }, + "description": "This flow integrates PDF reading with a language model to answer document-specific questions. Ideal for small-scale texts, it facilitates direct queries with immediate insights.", + "endpoint_name": null, + "id": "4b4cbf9e-34fe-4613-a460-3b7af89b7788", + "is_component": false, + "last_tested_version": "1.0.0rc1", + "name": "Document QA" +} \ No newline at end of file diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Blog Writer.json b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Blog Writer.json deleted file mode 100644 index e137b567a..000000000 --- a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Blog Writer.json +++ /dev/null @@ -1,1337 +0,0 @@ -{ - "data": { - "edges": [ - { - "className": "", - "data": { - "sourceHandle": { - "dataType": "TextInput", - "id": "TextInput-DbgJ3", - "name": "text", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "instructions", - "id": "Prompt-jJ1i7", - "inputTypes": [ - "Message", - "Text" - ], - "type": "str" - } - }, - "id": "reactflow__edge-TextInput-DbgJ3{œdataTypeœ:œTextInputœ,œidœ:œTextInput-DbgJ3œ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-Prompt-jJ1i7{œfieldNameœ:œinstructionsœ,œidœ:œPrompt-jJ1i7œ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", - "source": "TextInput-DbgJ3", - "sourceHandle": "{œdataTypeœ: œTextInputœ, œidœ: œTextInput-DbgJ3œ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-jJ1i7", - "targetHandle": "{œfieldNameœ: œinstructionsœ, œidœ: œPrompt-jJ1i7œ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" - }, - { - "className": "", - "data": { - "sourceHandle": { - "dataType": "URL", - "id": "URL-43SB8", - "name": "data", - "output_types": [ - "Data" - ] - }, - "targetHandle": { - "fieldName": "data", - "id": "ParseData-34pEF", - "inputTypes": [ - "Data" - ], - "type": "other" - } - }, - "id": "reactflow__edge-URL-43SB8{œdataTypeœ:œURLœ,œidœ:œURL-43SB8œ,œnameœ:œdataœ,œoutput_typesœ:[œDataœ]}-ParseData-34pEF{œfieldNameœ:œdataœ,œidœ:œParseData-34pEFœ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}", - "selected": false, - "source": "URL-43SB8", - "sourceHandle": "{œdataTypeœ: œURLœ, œidœ: œURL-43SB8œ, œnameœ: œdataœ, œoutput_typesœ: [œDataœ]}", - "target": "ParseData-34pEF", - "targetHandle": "{œfieldNameœ: œdataœ, œidœ: œParseData-34pEFœ, œinputTypesœ: [œDataœ], œtypeœ: œotherœ}" - }, - { - "className": "", - "data": { - "sourceHandle": { - "dataType": "URL", - "id": "URL-eFIqb", - "name": "data", - "output_types": [ - "Data" - ] - }, - "targetHandle": { - "fieldName": "data", - "id": "ParseData-iAHWq", - "inputTypes": [ - "Data" - ], - "type": "other" - } - }, - "id": "reactflow__edge-URL-eFIqb{œdataTypeœ:œURLœ,œidœ:œURL-eFIqbœ,œnameœ:œdataœ,œoutput_typesœ:[œDataœ]}-ParseData-iAHWq{œfieldNameœ:œdataœ,œidœ:œParseData-iAHWqœ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}", - "source": "URL-eFIqb", - "sourceHandle": "{œdataTypeœ: œURLœ, œidœ: œURL-eFIqbœ, œnameœ: œdataœ, œoutput_typesœ: [œDataœ]}", - "target": "ParseData-iAHWq", - "targetHandle": "{œfieldNameœ: œdataœ, œidœ: œParseData-iAHWqœ, œinputTypesœ: [œDataœ], œtypeœ: œotherœ}" - }, - { - "className": "", - "data": { - "sourceHandle": { - "dataType": "ParseData", - "id": "ParseData-34pEF", - "name": "text", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "reference_2", - "id": "Prompt-jJ1i7", - "inputTypes": [ - "Message", - "Text" - ], - "type": "str" - } - }, - "id": "reactflow__edge-ParseData-34pEF{œdataTypeœ:œParseDataœ,œidœ:œParseData-34pEFœ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-Prompt-jJ1i7{œfieldNameœ:œreference_2œ,œidœ:œPrompt-jJ1i7œ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", - "source": "ParseData-34pEF", - "sourceHandle": "{œdataTypeœ: œParseDataœ, œidœ: œParseData-34pEFœ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-jJ1i7", - "targetHandle": "{œfieldNameœ: œreference_2œ, œidœ: œPrompt-jJ1i7œ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" - }, - { - "className": "", - "data": { - "sourceHandle": { - "dataType": "ParseData", - "id": "ParseData-iAHWq", - "name": "text", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "reference_1", - "id": "Prompt-jJ1i7", - "inputTypes": [ - "Message", - "Text" - ], - "type": "str" - } - }, - "id": "reactflow__edge-ParseData-iAHWq{œdataTypeœ:œParseDataœ,œidœ:œParseData-iAHWqœ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-Prompt-jJ1i7{œfieldNameœ:œreference_1œ,œidœ:œPrompt-jJ1i7œ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", - "source": "ParseData-iAHWq", - "sourceHandle": "{œdataTypeœ: œParseDataœ, œidœ: œParseData-iAHWqœ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-jJ1i7", - "targetHandle": "{œfieldNameœ: œreference_1œ, œidœ: œPrompt-jJ1i7œ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" - }, - { - "className": "", - "data": { - "sourceHandle": { - "dataType": "OpenAIModel", - "id": "OpenAIModel-slJZS", - "name": "text_output", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-LkJX7", - "inputTypes": [ - "Message", - "str" - ], - "type": "str" - } - }, - "id": "reactflow__edge-OpenAIModel-slJZS{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-slJZSœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-LkJX7{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-LkJX7œ,œinputTypesœ:[œMessageœ,œstrœ],œtypeœ:œstrœ}", - "source": "OpenAIModel-slJZS", - "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-slJZSœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-LkJX7", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-LkJX7œ, œinputTypesœ: [œMessageœ, œstrœ], œtypeœ: œstrœ}" - }, - { - "className": "", - "data": { - "sourceHandle": { - "dataType": "Prompt", - "id": "Prompt-jJ1i7", - "name": "prompt", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-slJZS", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-Prompt-jJ1i7{œdataTypeœ:œPromptœ,œidœ:œPrompt-jJ1i7œ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-slJZS{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-slJZSœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "source": "Prompt-jJ1i7", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-jJ1i7œ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "target": "OpenAIModel-slJZS", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-slJZSœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - } - ], - "nodes": [ - { - "data": { - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt", - "id": "Prompt-jJ1i7", - "node": { - "base_classes": [ - "object", - "str", - "Text" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": { - "template": [ - "reference_1", - "reference_2", - "instructions" - ] - }, - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt", - "documentation": "", - "error": null, - "field_order": [], - "frozen": false, - "full_path": null, - "icon": "prompts", - "is_composition": null, - "is_input": null, - "is_output": null, - "name": "", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Prompt Message", - "method": "build_prompt", - "name": "prompt", - "selected": "Message", - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langflow.custom import Component\nfrom langflow.io import Output, PromptInput\nfrom langflow.schema.message import Message\n\n\nclass PromptComponent(Component):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n prompt = await Message.from_template_and_variables(**self._attributes)\n self.status = prompt.text\n return prompt\n" - }, - "instructions": { - "advanced": false, - "display_name": "instructions", - "dynamic": false, - "field_type": "str", - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Message", - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "instructions", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "reference_1": { - "advanced": false, - "display_name": "reference_1", - "dynamic": false, - "field_type": "str", - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Message", - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "reference_1", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "reference_2": { - "advanced": false, - "display_name": "reference_2", - "dynamic": false, - "field_type": "str", - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Message", - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "reference_2", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "template": { - "advanced": false, - "display_name": "Template", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": false, - "name": "template", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "prompt", - "value": "Reference 1:\n\n{reference_1}\n\n---\n\nReference 2:\n\n{reference_2}\n\n---\n\n{instructions}\n\nBlog: \n\n\n" - } - } - }, - "type": "Prompt" - }, - "dragging": false, - "height": 619, - "id": "Prompt-jJ1i7", - "position": { - "x": 1378.0386633467044, - "y": 547.0254869963999 - }, - "positionAbsolute": { - "x": 1378.0386633467044, - "y": 547.0254869963999 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "id": "URL-43SB8", - "node": { - "base_classes": [ - "Record" - ], - "beta": false, - "custom_fields": { - "urls": null - }, - "description": "Fetch content from one or more URLs.", - "display_name": "URL", - "documentation": "", - "field_formatters": {}, - "field_order": [], - "frozen": false, - "icon": "layout-template", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Data", - "method": "fetch_content", - "name": "data", - "selected": "Data", - "types": [ - "Data" - ], - "value": "__UNDEFINED__" - } - ], - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "import re\n\nfrom langchain_community.document_loaders.web_base import WebBaseLoader\n\nfrom langflow.custom import Component\nfrom langflow.io import Output, MessageTextInput\nfrom langflow.schema import Data\n\n\nclass URLComponent(Component):\n display_name = \"URL\"\n description = \"Fetch content from one or more URLs.\"\n icon = \"layout-template\"\n\n inputs = [\n MessageTextInput(\n name=\"urls\",\n display_name=\"URLs\",\n info=\"Enter one or more URLs, separated by commas.\",\n is_list=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Data\", name=\"data\", method=\"fetch_content\"),\n ]\n\n def ensure_url(self, string: str) -> str:\n \"\"\"\n Ensures the given string is a URL by adding 'http://' if it doesn't start with 'http://' or 'https://'.\n Raises an error if the string is not a valid URL.\n\n Parameters:\n string (str): The string to be checked and possibly modified.\n\n Returns:\n str: The modified string that is ensured to be a URL.\n\n Raises:\n ValueError: If the string is not a valid URL.\n \"\"\"\n if not string.startswith((\"http://\", \"https://\")):\n string = \"http://\" + string\n\n # Basic URL validation regex\n url_regex = re.compile(\n r\"^(http://|https://)?\" # http:// or https://\n r\"(([a-zA-Z0-9\\.-]+)\" # domain\n r\"(\\.[a-zA-Z]{2,}))\" # top-level domain\n r\"(:[0-9]{1,5})?\" # optional port\n r\"(\\/.*)?$\" # optional path\n )\n\n if not re.match(url_regex, string):\n raise ValueError(f\"Invalid URL: {string}\")\n\n return string\n\n def fetch_content(self) -> list[Data]:\n urls = [self.ensure_url(url.strip()) for url in self.urls if url.strip()]\n loader = WebBaseLoader(web_paths=urls, encoding=\"utf-8\")\n docs = loader.load()\n data = [Data(text=doc.page_content, **doc.metadata) for doc in docs]\n self.status = data\n return data\n" - }, - "urls": { - "advanced": false, - "display_name": "URLs", - "dynamic": false, - "info": "Enter one or more URLs, separated by commas.", - "list": true, - "load_from_db": false, - "name": "urls", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": [ - "https://www.promptingguide.ai/introduction/basics" - ] - } - } - }, - "type": "URL" - }, - "dragging": false, - "height": 301, - "id": "URL-43SB8", - "position": { - "x": 129.9069887328102, - "y": 1026.1629590683015 - }, - "positionAbsolute": { - "x": 129.9069887328102, - "y": 1026.1629590683015 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "id": "URL-eFIqb", - "node": { - "base_classes": [ - "Record" - ], - "beta": false, - "custom_fields": { - "urls": null - }, - "description": "Fetch content from one or more URLs.", - "display_name": "URL", - "documentation": "", - "field_formatters": {}, - "field_order": [], - "frozen": false, - "icon": "layout-template", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Data", - "method": "fetch_content", - "name": "data", - "selected": "Data", - "types": [ - "Data" - ], - "value": "__UNDEFINED__" - } - ], - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "import re\n\nfrom langchain_community.document_loaders.web_base import WebBaseLoader\n\nfrom langflow.custom import Component\nfrom langflow.io import Output, MessageTextInput\nfrom langflow.schema import Data\n\n\nclass URLComponent(Component):\n display_name = \"URL\"\n description = \"Fetch content from one or more URLs.\"\n icon = \"layout-template\"\n\n inputs = [\n MessageTextInput(\n name=\"urls\",\n display_name=\"URLs\",\n info=\"Enter one or more URLs, separated by commas.\",\n is_list=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Data\", name=\"data\", method=\"fetch_content\"),\n ]\n\n def ensure_url(self, string: str) -> str:\n \"\"\"\n Ensures the given string is a URL by adding 'http://' if it doesn't start with 'http://' or 'https://'.\n Raises an error if the string is not a valid URL.\n\n Parameters:\n string (str): The string to be checked and possibly modified.\n\n Returns:\n str: The modified string that is ensured to be a URL.\n\n Raises:\n ValueError: If the string is not a valid URL.\n \"\"\"\n if not string.startswith((\"http://\", \"https://\")):\n string = \"http://\" + string\n\n # Basic URL validation regex\n url_regex = re.compile(\n r\"^(http://|https://)?\" # http:// or https://\n r\"(([a-zA-Z0-9\\.-]+)\" # domain\n r\"(\\.[a-zA-Z]{2,}))\" # top-level domain\n r\"(:[0-9]{1,5})?\" # optional port\n r\"(\\/.*)?$\" # optional path\n )\n\n if not re.match(url_regex, string):\n raise ValueError(f\"Invalid URL: {string}\")\n\n return string\n\n def fetch_content(self) -> list[Data]:\n urls = [self.ensure_url(url.strip()) for url in self.urls if url.strip()]\n loader = WebBaseLoader(web_paths=urls, encoding=\"utf-8\")\n docs = loader.load()\n data = [Data(text=doc.page_content, **doc.metadata) for doc in docs]\n self.status = data\n return data\n" - }, - "urls": { - "advanced": false, - "display_name": "URLs", - "dynamic": false, - "info": "Enter one or more URLs, separated by commas.", - "list": true, - "load_from_db": false, - "name": "urls", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": [ - "https://www.promptingguide.ai/techniques/prompt_chaining" - ] - } - } - }, - "type": "URL" - }, - "dragging": false, - "height": 301, - "id": "URL-eFIqb", - "position": { - "x": 109.01828882212544, - "y": 635.7038211214808 - }, - "positionAbsolute": { - "x": 109.01828882212544, - "y": 635.7038211214808 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "description": "Get text inputs from the Playground.", - "display_name": "Instructions", - "edited": false, - "id": "TextInput-DbgJ3", - "node": { - "base_classes": [ - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Get text inputs from the Playground.", - "display_name": "Instructions", - "documentation": "", - "edited": true, - "field_order": [ - "input_value" - ], - "frozen": false, - "icon": "type", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Text", - "method": "text_response", - "name": "text", - "selected": "Message", - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langflow.base.io.text import TextComponent\nfrom langflow.io import Output, MessageTextInput\nfrom langflow.schema.message import Message\n\n\nclass TextInputComponent(TextComponent):\n display_name = \"Text Input\"\n description = \"Get text inputs from the Playground.\"\n icon = \"type\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Text to be passed as input.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Text\", name=\"text\", method=\"text_response\"),\n ]\n\n def text_response(self) -> Message:\n message = Message(\n text=self.input_value,\n )\n return message\n" - }, - "input_value": { - "advanced": false, - "display_name": "Text", - "dynamic": false, - "info": "Text to be passed as input.", - "input_types": [ - "Message" - ], - "list": false, - "load_from_db": false, - "name": "input_value", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "Use the references above for style to write a new blog/tutorial about prompt engineering techniques. Suggest non-covered topics." - } - } - }, - "type": "TextInput" - }, - "dragging": false, - "height": 309, - "id": "TextInput-DbgJ3", - "position": { - "x": 668.3436449795839, - "y": 213.40493638517057 - }, - "positionAbsolute": { - "x": 668.3436449795839, - "y": 213.40493638517057 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "id": "ParseData-34pEF", - "node": { - "base_classes": [ - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Convert Data into plain text following a specified template.", - "display_name": "Parse Data", - "documentation": "", - "field_order": [ - "data", - "template", - "sep" - ], - "frozen": false, - "icon": "braces", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Text", - "method": "parse_data", - "name": "text", - "selected": "Message", - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Parse Data\"\n description = \"Convert Data into plain text following a specified template.\"\n icon = \"braces\"\n\n inputs = [\n DataInput(name=\"data\", display_name=\"Data\", info=\"The data to convert to text.\"),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(display_name=\"Text\", name=\"text\", method=\"parse_data\"),\n ]\n\n def parse_data(self) -> Message:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n\n result_string = data_to_text(template, data, sep=self.sep)\n self.status = result_string\n return Message(text=result_string)\n" - }, - "data": { - "advanced": false, - "display_name": "Data", - "dynamic": false, - "info": "The data to convert to text.", - "input_types": [ - "Data" - ], - "list": false, - "name": "data", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "other", - "value": "" - }, - "sep": { - "advanced": true, - "display_name": "Separator", - "dynamic": false, - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "sep", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "---" - }, - "template": { - "advanced": false, - "display_name": "Template", - "dynamic": false, - "info": "The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.", - "multiline": true, - "name": "template", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "{text}" - } - } - }, - "type": "ParseData" - }, - "dragging": false, - "height": 377, - "id": "ParseData-34pEF", - "position": { - "x": 697.109388389247, - "y": 993.1273555676513 - }, - "positionAbsolute": { - "x": 697.109388389247, - "y": 993.1273555676513 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "id": "ParseData-iAHWq", - "node": { - "base_classes": [ - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Convert Data into plain text following a specified template.", - "display_name": "Parse Data", - "documentation": "", - "field_order": [ - "data", - "template", - "sep" - ], - "frozen": false, - "icon": "braces", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Text", - "method": "parse_data", - "name": "text", - "selected": "Message", - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Parse Data\"\n description = \"Convert Data into plain text following a specified template.\"\n icon = \"braces\"\n\n inputs = [\n DataInput(name=\"data\", display_name=\"Data\", info=\"The data to convert to text.\"),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(display_name=\"Text\", name=\"text\", method=\"parse_data\"),\n ]\n\n def parse_data(self) -> Message:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n\n result_string = data_to_text(template, data, sep=self.sep)\n self.status = result_string\n return Message(text=result_string)\n" - }, - "data": { - "advanced": false, - "display_name": "Data", - "dynamic": false, - "info": "The data to convert to text.", - "input_types": [ - "Data" - ], - "list": false, - "name": "data", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "other", - "value": "" - }, - "sep": { - "advanced": true, - "display_name": "Separator", - "dynamic": false, - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "sep", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "---" - }, - "template": { - "advanced": false, - "display_name": "Template", - "dynamic": false, - "info": "The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.", - "multiline": true, - "name": "template", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "{text}" - } - } - }, - "type": "ParseData" - }, - "dragging": false, - "height": 377, - "id": "ParseData-iAHWq", - "position": { - "x": 674.3059180422167, - "y": 594.1081812719365 - }, - "positionAbsolute": { - "x": 674.3059180422167, - "y": 594.1081812719365 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "description": "Generates text using OpenAI LLMs.", - "display_name": "OpenAI", - "edited": false, - "id": "OpenAIModel-slJZS", - "node": { - "base_classes": [ - "LanguageModel", - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Generates text using OpenAI LLMs.", - "display_name": "OpenAI", - "documentation": "", - "edited": true, - "field_order": [ - "input_value", - "max_tokens", - "model_kwargs", - "output_schema", - "model_name", - "openai_api_base", - "openai_api_key", - "temperature", - "stream", - "system_message", - "seed" - ], - "frozen": false, - "icon": "OpenAI", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Text", - "method": "text_response", - "name": "text_output", - "selected": "Message", - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - }, - { - "cache": true, - "display_name": "Language Model", - "method": "build_model", - "name": "model_output", - "selected": "LanguageModel", - "types": [ - "LanguageModel" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "import operator\nfrom functools import reduce\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import LanguageModel\nfrom langflow.inputs import (\n BoolInput,\n DictInput,\n DropdownInput,\n FloatInput,\n IntInput,\n MessageInput,\n SecretStrInput,\n StrInput,\n)\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n inputs = [\n MessageInput(name=\"input_value\", display_name=\"Input\"),\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n info=\"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n ),\n DictInput(name=\"model_kwargs\", display_name=\"Model Kwargs\", advanced=True),\n DictInput(\n name=\"output_schema\",\n is_list=True,\n display_name=\"Schema\",\n advanced=True,\n info=\"The schema for the Output of the model. You must pass the word JSON in the prompt. If left blank, JSON mode will be disabled.\",\n ),\n DropdownInput(\n name=\"model_name\", display_name=\"Model Name\", advanced=False, options=MODEL_NAMES, value=MODEL_NAMES[0]\n ),\n StrInput(\n name=\"openai_api_base\",\n display_name=\"OpenAI API Base\",\n advanced=True,\n info=\"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.\",\n ),\n SecretStrInput(\n name=\"openai_api_key\",\n display_name=\"OpenAI API Key\",\n info=\"The OpenAI API Key to use for the OpenAI model.\",\n advanced=False,\n value=\"OPENAI_API_KEY\",\n ),\n FloatInput(name=\"temperature\", display_name=\"Temperature\", value=0.1),\n BoolInput(name=\"stream\", display_name=\"Stream\", info=STREAM_INFO_TEXT, advanced=True),\n StrInput(\n name=\"system_message\",\n display_name=\"System Message\",\n info=\"System message to pass to the model.\",\n advanced=True,\n ),\n IntInput(\n name=\"seed\",\n display_name=\"Seed\",\n info=\"The seed controls the reproducibility of the job.\",\n advanced=True,\n value=1,\n ),\n ]\n\n def build_model(self) -> LanguageModel:\n # self.output_schea is a list of dictionaries\n # let's convert it to a dictionary\n output_schema_dict: dict[str, str] = reduce(operator.ior, self.output_schema or {}, {})\n openai_api_key = self.openai_api_key\n temperature = self.temperature\n model_name: str = self.model_name\n max_tokens = self.max_tokens\n model_kwargs = self.model_kwargs or {}\n openai_api_base = self.openai_api_base or \"https://api.openai.com/v1\"\n json_mode = bool(output_schema_dict)\n seed = self.seed\n model_kwargs[\"seed\"] = seed\n\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature or 0.1,\n )\n if json_mode:\n output = output.with_structured_output(schema=output_schema_dict, method=\"json_mode\") # type: ignore\n\n return output\n\n def _get_exception_message(self, e: Exception):\n \"\"\"\n Get a message from an OpenAI exception.\n\n Args:\n exception (Exception): The exception to get the message from.\n\n Returns:\n str: The message from the exception.\n \"\"\"\n\n try:\n from openai import BadRequestError\n except ImportError:\n return\n if isinstance(e, BadRequestError):\n message = e.body.get(\"message\") # type: ignore\n if message:\n return message\n return\n" - }, - "input_value": { - "advanced": false, - "display_name": "Input", - "dynamic": false, - "info": "", - "input_types": [ - "Message" - ], - "list": false, - "load_from_db": false, - "name": "input_value", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "max_tokens": { - "advanced": true, - "display_name": "Max Tokens", - "dynamic": false, - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "list": false, - "name": "max_tokens", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": "" - }, - "model_kwargs": { - "advanced": true, - "display_name": "Model Kwargs", - "dynamic": false, - "info": "", - "list": false, - "name": "model_kwargs", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "dict", - "value": {} - }, - "model_name": { - "advanced": false, - "display_name": "Model Name", - "dynamic": false, - "info": "", - "name": "model_name", - "options": [ - "gpt-4o", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125" - ], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "gpt-3.5-turbo" - }, - "openai_api_base": { - "advanced": true, - "display_name": "OpenAI API Base", - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", - "list": false, - "load_from_db": false, - "name": "openai_api_base", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "openai_api_key": { - "advanced": false, - "display_name": "OpenAI API Key", - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "input_types": [], - "load_from_db": true, - "name": "openai_api_key", - "password": true, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "output_schema": { - "advanced": true, - "display_name": "Schema", - "dynamic": false, - "info": "The schema for the Output of the model. You must pass the word JSON in the prompt. If left blank, JSON mode will be disabled.", - "list": true, - "name": "output_schema", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "dict", - "value": {} - }, - "seed": { - "advanced": true, - "display_name": "Seed", - "dynamic": false, - "info": "The seed controls the reproducibility of the job.", - "list": false, - "name": "seed", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": 1 - }, - "stream": { - "advanced": true, - "display_name": "Stream", - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "list": false, - "name": "stream", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "bool", - "value": false - }, - "system_message": { - "advanced": true, - "display_name": "System Message", - "dynamic": false, - "info": "System message to pass to the model.", - "list": false, - "load_from_db": false, - "name": "system_message", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "temperature": { - "advanced": false, - "display_name": "Temperature", - "dynamic": false, - "info": "", - "list": false, - "name": "temperature", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "float", - "value": 0.1 - } - } - }, - "type": "OpenAIModel" - }, - "dragging": false, - "height": 623, - "id": "OpenAIModel-slJZS", - "position": { - "x": 1968.999112433115, - "y": 528.8142375467121 - }, - "positionAbsolute": { - "x": 1968.999112433115, - "y": 528.8142375467121 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "id": "ChatOutput-LkJX7", - "node": { - "base_classes": [ - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Display a chat message in the Playground.", - "display_name": "Chat Output", - "documentation": "", - "field_order": [ - "input_value", - "sender", - "sender_name", - "session_id", - "data_template" - ], - "frozen": false, - "icon": "ChatOutput", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Message", - "method": "message_response", - "name": "message", - "selected": "Message", - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.io import DropdownInput, Output, MessageTextInput\nfrom langflow.schema.message import Message\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\"],\n value=\"Machine\",\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\", display_name=\"Sender Name\", info=\"Name of the sender.\", value=\"AI\", advanced=True\n ),\n MessageTextInput(name=\"session_id\", display_name=\"Session ID\", info=\"Session ID for the message.\", advanced=True),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n )\n if self.session_id and isinstance(message, Message) and isinstance(message.text, str):\n self.store_message(message)\n self.message.value = message\n\n self.status = message\n return message\n" - }, - "data_template": { - "advanced": true, - "display_name": "Data Template", - "dynamic": false, - "info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "data_template", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "{text}" - }, - "input_value": { - "advanced": false, - "display_name": "Text", - "dynamic": false, - "info": "Message to be passed as output.", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "input_value", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "sender": { - "advanced": true, - "display_name": "Sender Type", - "dynamic": false, - "info": "Type of sender.", - "name": "sender", - "options": [ - "Machine", - "User" - ], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "Machine" - }, - "sender_name": { - "advanced": true, - "display_name": "Sender Name", - "dynamic": false, - "info": "Name of the sender.", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "sender_name", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "AI" - }, - "session_id": { - "advanced": true, - "display_name": "Session ID", - "dynamic": false, - "info": "Session ID for the message.", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "session_id", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - } - } - }, - "type": "ChatOutput" - }, - "dragging": false, - "height": 309, - "id": "ChatOutput-LkJX7", - "position": { - "x": 2668.5087497211402, - "y": 859.3268817022193 - }, - "positionAbsolute": { - "x": 2668.5087497211402, - "y": 859.3268817022193 - }, - "selected": false, - "type": "genericNode", - "width": 384 - } - ], - "viewport": { - "x": 40.848461446679266, - "y": 89.0650521913791, - "zoom": 0.3782109149354305 - } - }, - "description": "This flow can be used to create a blog post following instructions from the user, using two other blogs as reference.", - "endpoint_name": null, - "id": "abcd5472-71fb-431c-9a08-6fd7781ffaa4", - "is_component": false, - "last_tested_version": "1.0.0a61", - "name": "Blog Writer" -} \ No newline at end of file diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Document QA.json b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Document QA.json deleted file mode 100644 index 2a937cc4c..000000000 --- a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Document QA.json +++ /dev/null @@ -1,1026 +0,0 @@ -{ - "data": { - "edges": [ - { - "className": "", - "data": { - "sourceHandle": { - "dataType": "File", - "id": "File-z24tW", - "name": "data", - "output_types": [ - "Data" - ] - }, - "targetHandle": { - "fieldName": "Document", - "id": "Prompt-ws12t", - "inputTypes": [ - "Document", - "Message", - "Data", - "Text" - ], - "type": "str" - } - }, - "id": "reactflow__edge-File-z24tW{œdataTypeœ:œFileœ,œidœ:œFile-z24tWœ,œnameœ:œdataœ,œoutput_typesœ:[œDataœ]}-Prompt-ws12t{œfieldNameœ:œDocumentœ,œidœ:œPrompt-ws12tœ,œinputTypesœ:[œDocumentœ,œMessageœ,œDataœ,œTextœ],œtypeœ:œstrœ}", - "source": "File-z24tW", - "sourceHandle": "{œdataTypeœ: œFileœ, œidœ: œFile-z24tWœ, œnameœ: œdataœ, œoutput_typesœ: [œDataœ]}", - "target": "Prompt-ws12t", - "targetHandle": "{œfieldNameœ: œDocumentœ, œidœ: œPrompt-ws12tœ, œinputTypesœ: [œDocumentœ, œMessageœ, œDataœ, œTextœ], œtypeœ: œstrœ}" - }, - { - "className": "", - "data": { - "sourceHandle": { - "dataType": "ChatInput", - "id": "ChatInput-YMjNE", - "name": "message", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "Question", - "id": "Prompt-ws12t", - "inputTypes": [ - "Document", - "Message", - "Data", - "Text" - ], - "type": "str" - } - }, - "id": "reactflow__edge-ChatInput-YMjNE{œdataTypeœ:œChatInputœ,œidœ:œChatInput-YMjNEœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Prompt-ws12t{œfieldNameœ:œQuestionœ,œidœ:œPrompt-ws12tœ,œinputTypesœ:[œDocumentœ,œMessageœ,œDataœ,œTextœ],œtypeœ:œstrœ}", - "source": "ChatInput-YMjNE", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-YMjNEœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-ws12t", - "targetHandle": "{œfieldNameœ: œQuestionœ, œidœ: œPrompt-ws12tœ, œinputTypesœ: [œDocumentœ, œMessageœ, œDataœ, œTextœ], œtypeœ: œstrœ}" - }, - { - "className": "", - "data": { - "sourceHandle": { - "dataType": "Prompt", - "id": "Prompt-ws12t", - "name": "prompt", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-AdQdh", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-Prompt-ws12t{œdataTypeœ:œPromptœ,œidœ:œPrompt-ws12tœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-AdQdh{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-AdQdhœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "source": "Prompt-ws12t", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-ws12tœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "target": "OpenAIModel-AdQdh", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-AdQdhœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - }, - { - "className": "", - "data": { - "sourceHandle": { - "dataType": "OpenAIModel", - "id": "OpenAIModel-AdQdh", - "name": "text_output", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-bSlkp", - "inputTypes": [ - "Message", - "str" - ], - "type": "str" - } - }, - "id": "reactflow__edge-OpenAIModel-AdQdh{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-AdQdhœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-bSlkp{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-bSlkpœ,œinputTypesœ:[œMessageœ,œstrœ],œtypeœ:œstrœ}", - "source": "OpenAIModel-AdQdh", - "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-AdQdhœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-bSlkp", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-bSlkpœ, œinputTypesœ: [œMessageœ, œstrœ], œtypeœ: œstrœ}" - } - ], - "nodes": [ - { - "data": { - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt", - "id": "Prompt-ws12t", - "node": { - "base_classes": [ - "object", - "str", - "Text" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": { - "template": [ - "Document", - "Question" - ] - }, - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt", - "documentation": "", - "error": null, - "field_order": [], - "frozen": false, - "full_path": null, - "icon": "prompts", - "is_composition": null, - "is_input": null, - "is_output": null, - "name": "", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Prompt Message", - "method": "build_prompt", - "name": "prompt", - "selected": "Message", - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "Document": { - "advanced": false, - "display_name": "Document", - "dynamic": false, - "field_type": "str", - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Document", - "Message", - "Data", - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "Document", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "Question": { - "advanced": false, - "display_name": "Question", - "dynamic": false, - "field_type": "str", - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Document", - "Message", - "Data", - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "Question", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langflow.custom import Component\nfrom langflow.io import Output, PromptInput\nfrom langflow.schema.message import Message\n\n\nclass PromptComponent(Component):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n prompt = await Message.from_template_and_variables(**self._attributes)\n self.status = prompt.text\n return prompt\n" - }, - "template": { - "advanced": false, - "display_name": "Template", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": false, - "name": "template", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "prompt", - "value": "Answer user's questions based on the document below:\n\n---\n\n{Document}\n\n---\n\nQuestion:\n{Question}\n\nAnswer:\n" - } - } - }, - "type": "Prompt" - }, - "dragging": false, - "height": 525, - "id": "Prompt-ws12t", - "position": { - "x": 585.7906101139403, - "y": 117.52115876762832 - }, - "positionAbsolute": { - "x": 585.7906101139403, - "y": 117.52115876762832 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "id": "ChatInput-YMjNE", - "node": { - "base_classes": [ - "str", - "Record", - "Text", - "object" - ], - "beta": false, - "custom_fields": { - "input_value": null, - "return_record": null, - "sender": null, - "sender_name": null, - "session_id": null - }, - "description": "Get chat inputs from the Playground.", - "display_name": "Chat Input", - "documentation": "", - "field_formatters": {}, - "field_order": [], - "frozen": false, - "icon": "ChatInput", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Message", - "method": "message_response", - "name": "message", - "selected": "Message", - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.io import DropdownInput, FileInput, MultilineInput, Output, MessageTextInput\nfrom langflow.schema.message import Message\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\"],\n value=\"User\",\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=\"User\",\n advanced=True,\n ),\n MessageTextInput(name=\"session_id\", display_name=\"Session ID\", info=\"Session ID for the message.\", advanced=True),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n )\n if self.session_id and isinstance(message, Message) and isinstance(message.text, str):\n self.store_message(message)\n self.message.value = message\n\n self.status = message\n return message\n" - }, - "input_value": { - "advanced": false, - "display_name": "Text", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Message to be passed as input.", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "input_value", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "what is this?" - }, - "sender": { - "advanced": true, - "display_name": "Sender Type", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Type of sender.", - "input_types": [ - "Text" - ], - "list": true, - "load_from_db": false, - "multiline": false, - "name": "sender", - "options": [ - "Machine", - "User" - ], - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "User" - }, - "sender_name": { - "advanced": true, - "display_name": "Sender Name", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Name of the sender.", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "sender_name", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "User" - }, - "session_id": { - "advanced": true, - "display_name": "Session ID", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Session ID for the message.", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "session_id", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - } - } - }, - "type": "ChatInput" - }, - "dragging": false, - "height": 309, - "id": "ChatInput-YMjNE", - "position": { - "x": -38.501719080514135, - "y": 379.81180230285355 - }, - "positionAbsolute": { - "x": -38.501719080514135, - "y": 379.81180230285355 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "id": "ChatOutput-bSlkp", - "node": { - "base_classes": [ - "str", - "Record", - "Text", - "object" - ], - "beta": false, - "custom_fields": { - "input_value": null, - "return_record": null, - "sender": null, - "sender_name": null, - "session_id": null - }, - "description": "Display a chat message in the Playground.", - "display_name": "Chat Output", - "documentation": "", - "field_formatters": {}, - "field_order": [], - "frozen": false, - "icon": "ChatOutput", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Message", - "method": "message_response", - "name": "message", - "selected": "Message", - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.io import DropdownInput, Output, MessageTextInput\nfrom langflow.schema.message import Message\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\"],\n value=\"Machine\",\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\", display_name=\"Sender Name\", info=\"Name of the sender.\", value=\"AI\", advanced=True\n ),\n MessageTextInput(name=\"session_id\", display_name=\"Session ID\", info=\"Session ID for the message.\", advanced=True),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n )\n if self.session_id and isinstance(message, Message) and isinstance(message.text, str):\n self.store_message(message)\n self.message.value = message\n\n self.status = message\n return message\n" - }, - "input_value": { - "advanced": false, - "display_name": "Text", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Message to be passed as output.", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "input_value", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "sender": { - "advanced": true, - "display_name": "Sender Type", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Type of sender.", - "input_types": [ - "Text" - ], - "list": true, - "load_from_db": false, - "multiline": false, - "name": "sender", - "options": [ - "Machine", - "User" - ], - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "Machine" - }, - "sender_name": { - "advanced": true, - "display_name": "Sender Name", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Name of the sender.", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "sender_name", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "AI" - }, - "session_id": { - "advanced": true, - "display_name": "Session ID", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Session ID for the message.", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "session_id", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - } - } - }, - "type": "ChatOutput" - }, - "dragging": false, - "height": 309, - "id": "ChatOutput-bSlkp", - "position": { - "x": 1733.3012915204283, - "y": 168.76098809939327 - }, - "positionAbsolute": { - "x": 1733.3012915204283, - "y": 168.76098809939327 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "description": "A generic file loader.", - "display_name": "File", - "id": "File-z24tW", - "node": { - "base_classes": [ - "Data" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "A generic file loader.", - "display_name": "File", - "documentation": "", - "edited": false, - "field_order": [ - "path", - "silent_errors" - ], - "frozen": false, - "icon": "file-text", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Data", - "method": "load_file", - "name": "data", - "selected": "Data", - "types": [ - "Data" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from pathlib import Path\n\nfrom langflow.base.data.utils import TEXT_FILE_TYPES, parse_text_file_to_data\nfrom langflow.custom import Component\nfrom langflow.io import BoolInput, FileInput, Output\nfrom langflow.schema import Data\n\n\nclass FileComponent(Component):\n display_name = \"File\"\n description = \"A generic file loader.\"\n icon = \"file-text\"\n\n inputs = [\n FileInput(\n name=\"path\",\n display_name=\"Path\",\n file_types=TEXT_FILE_TYPES,\n info=f\"Supported file types: {', '.join(TEXT_FILE_TYPES)}\",\n ),\n BoolInput(\n name=\"silent_errors\",\n display_name=\"Silent Errors\",\n advanced=True,\n info=\"If true, errors will not raise an exception.\",\n ),\n ]\n\n outputs = [\n Output(display_name=\"Data\", name=\"data\", method=\"load_file\"),\n ]\n\n def load_file(self) -> Data:\n if not self.path:\n raise ValueError(\"Please, upload a file to use this component.\")\n resolved_path = self.resolve_path(self.path)\n silent_errors = self.silent_errors\n\n extension = Path(resolved_path).suffix[1:].lower()\n\n if extension == \"doc\":\n raise ValueError(\"doc files are not supported. Please save as .docx\")\n if extension not in TEXT_FILE_TYPES:\n raise ValueError(f\"Unsupported file type: {extension}\")\n\n data = parse_text_file_to_data(resolved_path, silent_errors)\n self.status = data if data else \"No data\"\n return data or Data()\n" - }, - "path": { - "advanced": false, - "display_name": "Path", - "dynamic": false, - "fileTypes": [ - "txt", - "md", - "mdx", - "csv", - "json", - "yaml", - "yml", - "xml", - "html", - "htm", - "pdf", - "docx", - "py", - "sh", - "sql", - "js", - "ts", - "tsx" - ], - "file_path": "e56e0529-7225-4f6c-9144-5ad0806f5fed/Math Router.json", - "info": "Supported file types: txt, md, mdx, csv, json, yaml, yml, xml, html, htm, pdf, docx, py, sh, sql, js, ts, tsx", - "list": false, - "name": "path", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "file", - "value": "" - }, - "silent_errors": { - "advanced": true, - "display_name": "Silent Errors", - "dynamic": false, - "info": "If true, errors will not raise an exception.", - "list": false, - "name": "silent_errors", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "bool", - "value": false - } - } - }, - "type": "File" - }, - "dragging": false, - "height": 301, - "id": "File-z24tW", - "position": { - "x": -37.064128418041946, - "y": 39.0475820447775 - }, - "positionAbsolute": { - "x": -37.064128418041946, - "y": 39.0475820447775 - }, - "selected": true, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "description": "Generates text using OpenAI LLMs.", - "display_name": "OpenAI", - "edited": false, - "id": "OpenAIModel-AdQdh", - "node": { - "base_classes": [ - "LanguageModel", - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Generates text using OpenAI LLMs.", - "display_name": "OpenAI", - "documentation": "", - "edited": true, - "field_order": [ - "input_value", - "max_tokens", - "model_kwargs", - "output_schema", - "model_name", - "openai_api_base", - "openai_api_key", - "temperature", - "stream", - "system_message", - "seed" - ], - "frozen": false, - "icon": "OpenAI", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Text", - "method": "text_response", - "name": "text_output", - "selected": "Message", - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - }, - { - "cache": true, - "display_name": "Language Model", - "method": "build_model", - "name": "model_output", - "selected": "LanguageModel", - "types": [ - "LanguageModel" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "import operator\nfrom functools import reduce\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import LanguageModel\nfrom langflow.inputs import (\n BoolInput,\n DictInput,\n DropdownInput,\n FloatInput,\n IntInput,\n MessageInput,\n SecretStrInput,\n StrInput,\n)\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n inputs = [\n MessageInput(name=\"input_value\", display_name=\"Input\"),\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n info=\"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n ),\n DictInput(name=\"model_kwargs\", display_name=\"Model Kwargs\", advanced=True),\n DictInput(\n name=\"output_schema\",\n is_list=True,\n display_name=\"Schema\",\n advanced=True,\n info=\"The schema for the Output of the model. You must pass the word JSON in the prompt. If left blank, JSON mode will be disabled.\",\n ),\n DropdownInput(\n name=\"model_name\", display_name=\"Model Name\", advanced=False, options=MODEL_NAMES, value=MODEL_NAMES[0]\n ),\n StrInput(\n name=\"openai_api_base\",\n display_name=\"OpenAI API Base\",\n advanced=True,\n info=\"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.\",\n ),\n SecretStrInput(\n name=\"openai_api_key\",\n display_name=\"OpenAI API Key\",\n info=\"The OpenAI API Key to use for the OpenAI model.\",\n advanced=False,\n value=\"OPENAI_API_KEY\",\n ),\n FloatInput(name=\"temperature\", display_name=\"Temperature\", value=0.1),\n BoolInput(name=\"stream\", display_name=\"Stream\", info=STREAM_INFO_TEXT, advanced=True),\n StrInput(\n name=\"system_message\",\n display_name=\"System Message\",\n info=\"System message to pass to the model.\",\n advanced=True,\n ),\n IntInput(\n name=\"seed\",\n display_name=\"Seed\",\n info=\"The seed controls the reproducibility of the job.\",\n advanced=True,\n value=1,\n ),\n ]\n\n def build_model(self) -> LanguageModel:\n # self.output_schea is a list of dictionaries\n # let's convert it to a dictionary\n output_schema_dict: dict[str, str] = reduce(operator.ior, self.output_schema or {}, {})\n openai_api_key = self.openai_api_key\n temperature = self.temperature\n model_name: str = self.model_name\n max_tokens = self.max_tokens\n model_kwargs = self.model_kwargs or {}\n openai_api_base = self.openai_api_base or \"https://api.openai.com/v1\"\n json_mode = bool(output_schema_dict)\n seed = self.seed\n model_kwargs[\"seed\"] = seed\n\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature or 0.1,\n )\n if json_mode:\n output = output.with_structured_output(schema=output_schema_dict, method=\"json_mode\") # type: ignore\n\n return output\n\n def _get_exception_message(self, e: Exception):\n \"\"\"\n Get a message from an OpenAI exception.\n\n Args:\n exception (Exception): The exception to get the message from.\n\n Returns:\n str: The message from the exception.\n \"\"\"\n\n try:\n from openai import BadRequestError\n except ImportError:\n return\n if isinstance(e, BadRequestError):\n message = e.body.get(\"message\") # type: ignore\n if message:\n return message\n return\n" - }, - "input_value": { - "advanced": false, - "display_name": "Input", - "dynamic": false, - "info": "", - "input_types": [ - "Message" - ], - "list": false, - "load_from_db": false, - "name": "input_value", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "max_tokens": { - "advanced": true, - "display_name": "Max Tokens", - "dynamic": false, - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "list": false, - "name": "max_tokens", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": "" - }, - "model_kwargs": { - "advanced": true, - "display_name": "Model Kwargs", - "dynamic": false, - "info": "", - "list": false, - "name": "model_kwargs", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "dict", - "value": {} - }, - "model_name": { - "advanced": false, - "display_name": "Model Name", - "dynamic": false, - "info": "", - "name": "model_name", - "options": [ - "gpt-4o", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125" - ], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "gpt-3.5-turbo" - }, - "openai_api_base": { - "advanced": true, - "display_name": "OpenAI API Base", - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", - "list": false, - "load_from_db": false, - "name": "openai_api_base", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "openai_api_key": { - "advanced": false, - "display_name": "OpenAI API Key", - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "input_types": [], - "load_from_db": true, - "name": "openai_api_key", - "password": true, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "output_schema": { - "advanced": true, - "display_name": "Schema", - "dynamic": false, - "info": "The schema for the Output of the model. You must pass the word JSON in the prompt. If left blank, JSON mode will be disabled.", - "list": true, - "name": "output_schema", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "dict", - "value": {} - }, - "seed": { - "advanced": true, - "display_name": "Seed", - "dynamic": false, - "info": "The seed controls the reproducibility of the job.", - "list": false, - "name": "seed", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": 1 - }, - "stream": { - "advanced": true, - "display_name": "Stream", - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "list": false, - "name": "stream", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "bool", - "value": false - }, - "system_message": { - "advanced": true, - "display_name": "System Message", - "dynamic": false, - "info": "System message to pass to the model.", - "list": false, - "load_from_db": false, - "name": "system_message", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "temperature": { - "advanced": false, - "display_name": "Temperature", - "dynamic": false, - "info": "", - "list": false, - "name": "temperature", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "float", - "value": 0.1 - } - } - }, - "type": "OpenAIModel" - }, - "dragging": false, - "height": 623, - "id": "OpenAIModel-AdQdh", - "position": { - "x": 1141.7303854551026, - "y": -51.19892217231286 - }, - "positionAbsolute": { - "x": 1141.7303854551026, - "y": -51.19892217231286 - }, - "selected": false, - "type": "genericNode", - "width": 384 - } - ], - "viewport": { - "x": 91.58014849142035, - "y": 287.8736279905512, - "zoom": 0.5335671198494703 - } - }, - "description": "This flow integrates PDF reading with a language model to answer document-specific questions. Ideal for small-scale texts, it facilitates direct queries with immediate insights.", - "endpoint_name": null, - "id": "e56e0529-7225-4f6c-9144-5ad0806f5fed", - "is_component": false, - "last_tested_version": "1.0.0a61", - "name": "Document QA" -} \ No newline at end of file diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Prompt Chaining.json b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Prompt Chaining.json deleted file mode 100644 index b2ecbd035..000000000 --- a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Prompt Chaining.json +++ /dev/null @@ -1,1776 +0,0 @@ -{ - "data": { - "edges": [ - { - "className": "stroke-gray-900 stroke-connection", - "data": { - "sourceHandle": { - "dataType": "TextInput", - "id": "TextInput-sptaH", - "name": "text", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "document", - "id": "Prompt-amqBu", - "inputTypes": [ - "Document", - "Message", - "Record", - "Text" - ], - "type": "str" - } - }, - "id": "reactflow__edge-TextInput-sptaH{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œTextInputœ,œidœ:œTextInput-sptaHœ}-Prompt-amqBu{œfieldNameœ:œdocumentœ,œidœ:œPrompt-amqBuœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "source": "TextInput-sptaH", - "sourceHandle": "{œdataTypeœ: œTextInputœ, œidœ: œTextInput-sptaHœ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}", - "style": { - "stroke": "#555" - }, - "target": "Prompt-amqBu", - "targetHandle": "{œfieldNameœ: œdocumentœ, œidœ: œPrompt-amqBuœ, œinputTypesœ: [œDocumentœ, œMessageœ, œRecordœ, œTextœ], œtypeœ: œstrœ}" - }, - { - "className": "stroke-gray-900 stroke-connection", - "data": { - "sourceHandle": { - "dataType": "Prompt", - "id": "Prompt-amqBu", - "name": "text", - "output_types": [] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "TextOutput-2MS4a", - "inputTypes": [ - "Record", - "Text" - ], - "type": "str" - } - }, - "id": "reactflow__edge-Prompt-amqBu{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-amqBuœ}-TextOutput-2MS4a{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-2MS4aœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}", - "source": "Prompt-amqBu", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-amqBuœ, œnameœ: œtextœ, œoutput_typesœ: []}", - "style": { - "stroke": "#555" - }, - "target": "TextOutput-2MS4a", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œTextOutput-2MS4aœ, œinputTypesœ: [œRecordœ, œTextœ], œtypeœ: œstrœ}" - }, - { - "className": "stroke-gray-900 stroke-connection", - "data": { - "sourceHandle": { - "dataType": "Prompt", - "id": "Prompt-amqBu", - "name": "prompt", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-uYXZJ", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-Prompt-amqBu{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-amqBuœ}-OpenAIModel-uYXZJ{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-uYXZJœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "source": "Prompt-amqBu", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-amqBuœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "style": { - "stroke": "#555" - }, - "target": "OpenAIModel-uYXZJ", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-uYXZJœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - }, - { - "className": "stroke-gray-900 stroke-connection", - "data": { - "sourceHandle": { - "dataType": "OpenAIModel", - "id": "OpenAIModel-uYXZJ", - "name": "text_output", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "summary", - "id": "Prompt-gTNiz", - "inputTypes": [ - "Document", - "Message", - "Record", - "Text" - ], - "type": "str" - } - }, - "id": "reactflow__edge-OpenAIModel-uYXZJ{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-uYXZJœ}-Prompt-gTNiz{œfieldNameœ:œsummaryœ,œidœ:œPrompt-gTNizœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "source": "OpenAIModel-uYXZJ", - "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-uYXZJœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", - "style": { - "stroke": "#555" - }, - "target": "Prompt-gTNiz", - "targetHandle": "{œfieldNameœ: œsummaryœ, œidœ: œPrompt-gTNizœ, œinputTypesœ: [œDocumentœ, œMessageœ, œRecordœ, œTextœ], œtypeœ: œstrœ}" - }, - { - "className": "stroke-gray-900 stroke-connection", - "data": { - "sourceHandle": { - "dataType": "OpenAIModel", - "id": "OpenAIModel-uYXZJ", - "name": "text_output", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-EJkG3", - "inputTypes": [ - "Message", - "str" - ], - "type": "str" - } - }, - "id": "reactflow__edge-OpenAIModel-uYXZJ{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-uYXZJœ}-ChatOutput-EJkG3{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-EJkG3œ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "source": "OpenAIModel-uYXZJ", - "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-uYXZJœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", - "style": { - "stroke": "#555" - }, - "target": "ChatOutput-EJkG3", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-EJkG3œ, œinputTypesœ: [œMessageœ, œstrœ], œtypeœ: œstrœ}" - }, - { - "className": "stroke-gray-900 stroke-connection", - "data": { - "sourceHandle": { - "dataType": "Prompt", - "id": "Prompt-gTNiz", - "name": "text", - "output_types": [] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "TextOutput-MUDOR", - "inputTypes": [ - "Record", - "Text" - ], - "type": "str" - } - }, - "id": "reactflow__edge-Prompt-gTNiz{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-gTNizœ}-TextOutput-MUDOR{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-MUDORœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}", - "source": "Prompt-gTNiz", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-gTNizœ, œnameœ: œtextœ, œoutput_typesœ: []}", - "style": { - "stroke": "#555" - }, - "target": "TextOutput-MUDOR", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œTextOutput-MUDORœ, œinputTypesœ: [œRecordœ, œTextœ], œtypeœ: œstrœ}" - }, - { - "className": "stroke-gray-900 stroke-connection", - "data": { - "sourceHandle": { - "dataType": "Prompt", - "id": "Prompt-gTNiz", - "name": "prompt", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-XawYB", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-Prompt-gTNiz{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-gTNizœ}-OpenAIModel-XawYB{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-XawYBœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "source": "Prompt-gTNiz", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-gTNizœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "style": { - "stroke": "#555" - }, - "target": "OpenAIModel-XawYB", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-XawYBœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - }, - { - "className": "stroke-gray-900 stroke-connection", - "data": { - "sourceHandle": { - "dataType": "OpenAIModel", - "id": "OpenAIModel-XawYB", - "name": "text_output", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-DNmvg", - "inputTypes": [ - "Message", - "str" - ], - "type": "str" - } - }, - "id": "reactflow__edge-OpenAIModel-XawYB{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-XawYBœ}-ChatOutput-DNmvg{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-DNmvgœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "source": "OpenAIModel-XawYB", - "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-XawYBœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", - "style": { - "stroke": "#555" - }, - "target": "ChatOutput-DNmvg", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-DNmvgœ, œinputTypesœ: [œMessageœ, œstrœ], œtypeœ: œstrœ}" - } - ], - "nodes": [ - { - "data": { - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt", - "id": "Prompt-amqBu", - "node": { - "base_classes": [ - "object", - "str", - "Text" - ], - "beta": false, - "custom_fields": { - "template": [ - "document" - ] - }, - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt", - "documentation": "", - "error": null, - "field_formatters": {}, - "field_order": [], - "frozen": false, - "full_path": null, - "icon": "prompts", - "is_composition": null, - "is_input": null, - "is_output": null, - "name": "", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Prompt Message", - "method": "build_prompt", - "name": "prompt", - "selected": "Message", - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langflow.custom import Component\nfrom langflow.io import Output, PromptInput\nfrom langflow.schema.message import Message\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\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n prompt = await Message.from_template_and_variables(**self._attributes)\n self.status = prompt.text\n return prompt\n" - }, - "document": { - "advanced": false, - "display_name": "document", - "dynamic": false, - "field_type": "str", - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Document", - "Message", - "Record", - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "document", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "template": { - "advanced": false, - "display_name": "Template", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": false, - "name": "template", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "prompt", - "value": "You are a helpful assistant. Given a long document, your task is to create a concise summary that captures the main points and key details. The summary should be clear, accurate, and succinct. Please provide the summary in the format below:\n####\n{document}\n####\n" - } - } - }, - "type": "Prompt" - }, - "dragging": false, - "height": 385, - "id": "Prompt-amqBu", - "position": { - "x": 2191.5837146441663, - "y": 1047.9307944451873 - }, - "positionAbsolute": { - "x": 2191.5837146441663, - "y": 1047.9307944451873 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt", - "id": "Prompt-gTNiz", - "node": { - "base_classes": [ - "object", - "str", - "Text" - ], - "beta": false, - "custom_fields": { - "template": [ - "summary" - ] - }, - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt", - "documentation": "", - "error": null, - "field_formatters": {}, - "field_order": [], - "frozen": false, - "full_path": null, - "icon": "prompts", - "is_composition": null, - "is_input": null, - "is_output": null, - "name": "", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Prompt Message", - "method": "build_prompt", - "name": "prompt", - "selected": "Message", - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langflow.custom import Component\nfrom langflow.io import Output, PromptInput\nfrom langflow.schema.message import Message\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\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n prompt = await Message.from_template_and_variables(**self._attributes)\n self.status = prompt.text\n return prompt\n" - }, - "summary": { - "advanced": false, - "display_name": "summary", - "dynamic": false, - "field_type": "str", - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Document", - "Message", - "Record", - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "summary", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "template": { - "advanced": false, - "display_name": "Template", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": false, - "name": "template", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "prompt", - "value": "Given a summary of an article, please create two multiple-choice questions that cover the key points and details mentioned. Ensure the questions are clear and provide three options (A, B, C), with one correct answer.\n####\n{summary}\n####" - } - } - }, - "type": "Prompt" - }, - "dragging": false, - "height": 385, - "id": "Prompt-gTNiz", - "position": { - "x": 3731.0813766902447, - "y": 799.631909121391 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "id": "ChatOutput-EJkG3", - "node": { - "base_classes": [ - "object", - "Record", - "Text", - "str" - ], - "beta": false, - "custom_fields": { - "input_value": null, - "record_template": null, - "return_record": null, - "sender": null, - "sender_name": null, - "session_id": null - }, - "description": "Display a chat message in the Playground.", - "display_name": "Chat Output", - "documentation": "", - "field_formatters": {}, - "field_order": [], - "frozen": false, - "icon": "ChatOutput", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Message", - "method": "message_response", - "name": "message", - "selected": "Message", - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.io import DropdownInput, Output, MessageTextInput\nfrom langflow.schema.message import Message\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\"],\n value=\"Machine\",\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\", display_name=\"Sender Name\", info=\"Name of the sender.\", value=\"AI\", advanced=True\n ),\n MessageTextInput(name=\"session_id\", display_name=\"Session ID\", info=\"Session ID for the message.\", advanced=True),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n )\n if self.session_id and isinstance(message, Message) and isinstance(message.text, str):\n self.store_message(message)\n self.message.value = message\n\n self.status = message\n return message\n" - }, - "input_value": { - "advanced": false, - "display_name": "Text", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Message to be passed as output.", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "input_value", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "sender": { - "advanced": true, - "display_name": "Sender Type", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Type of sender.", - "input_types": [ - "Text" - ], - "list": true, - "load_from_db": false, - "multiline": false, - "name": "sender", - "options": [ - "Machine", - "User" - ], - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "Machine" - }, - "sender_name": { - "advanced": true, - "display_name": "Sender Name", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Name of the sender.", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "sender_name", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "AI" - }, - "session_id": { - "advanced": true, - "display_name": "Session ID", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Session ID for the message.", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "session_id", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - } - } - }, - "type": "ChatOutput" - }, - "dragging": false, - "height": 385, - "id": "ChatOutput-EJkG3", - "position": { - "x": 3722.1747844849388, - "y": 1283.413553222214 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "id": "ChatOutput-DNmvg", - "node": { - "base_classes": [ - "object", - "Record", - "Text", - "str" - ], - "beta": false, - "custom_fields": { - "input_value": null, - "record_template": null, - "return_record": null, - "sender": null, - "sender_name": null, - "session_id": null - }, - "description": "Display a chat message in the Playground.", - "display_name": "Chat Output", - "documentation": "", - "field_formatters": {}, - "field_order": [], - "frozen": false, - "icon": "ChatOutput", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Message", - "method": "message_response", - "name": "message", - "selected": "Message", - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.io import DropdownInput, Output, MessageTextInput\nfrom langflow.schema.message import Message\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\"],\n value=\"Machine\",\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\", display_name=\"Sender Name\", info=\"Name of the sender.\", value=\"AI\", advanced=True\n ),\n MessageTextInput(name=\"session_id\", display_name=\"Session ID\", info=\"Session ID for the message.\", advanced=True),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n )\n if self.session_id and isinstance(message, Message) and isinstance(message.text, str):\n self.store_message(message)\n self.message.value = message\n\n self.status = message\n return message\n" - }, - "input_value": { - "advanced": false, - "display_name": "Text", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Message to be passed as output.", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "input_value", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "sender": { - "advanced": true, - "display_name": "Sender Type", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Type of sender.", - "input_types": [ - "Text" - ], - "list": true, - "load_from_db": false, - "multiline": false, - "name": "sender", - "options": [ - "Machine", - "User" - ], - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "Machine" - }, - "sender_name": { - "advanced": true, - "display_name": "Sender Name", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Name of the sender.", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "sender_name", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "AI" - }, - "session_id": { - "advanced": true, - "display_name": "Session ID", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Session ID for the message.", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "session_id", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - } - } - }, - "type": "ChatOutput" - }, - "height": 385, - "id": "ChatOutput-DNmvg", - "position": { - "x": 5077.71285886074, - "y": 1232.9152769735522 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "id": "TextInput-sptaH", - "node": { - "base_classes": [ - "str", - "Text", - "object" - ], - "beta": false, - "custom_fields": { - "input_value": null, - "record_template": null - }, - "description": "Get text inputs from the Playground.", - "display_name": "Text Input", - "documentation": "", - "field_formatters": {}, - "field_order": [], - "frozen": false, - "icon": "type", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Text", - "method": "text_response", - "name": "text", - "selected": "Message", - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langflow.base.io.text import TextComponent\nfrom langflow.io import Output, MessageTextInput\nfrom langflow.schema.message import Message\n\n\nclass TextInputComponent(TextComponent):\n display_name = \"Text Input\"\n description = \"Get text inputs from the Playground.\"\n icon = \"type\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Text to be passed as input.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Text\", name=\"text\", method=\"text_response\"),\n ]\n\n def text_response(self) -> Message:\n message = Message(\n text=self.input_value,\n )\n return message\n" - }, - "input_value": { - "advanced": false, - "display_name": "Text", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Text to be passed as input.", - "input_types": [ - "Message", - "str" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "input_value", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - } - } - }, - "type": "TextInput" - }, - "dragging": false, - "height": 290, - "id": "TextInput-sptaH", - "position": { - "x": 1700.5624822024752, - "y": 1039.603088937466 - }, - "positionAbsolute": { - "x": 1700.5624822024752, - "y": 1039.603088937466 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "id": "TextOutput-2MS4a", - "node": { - "base_classes": [ - "str", - "Text", - "object" - ], - "beta": false, - "custom_fields": { - "input_value": null, - "record_template": null - }, - "description": "Display a text output in the Playground.", - "display_name": "First Prompt", - "documentation": "", - "field_formatters": {}, - "field_order": [], - "frozen": false, - "icon": "type", - "output_types": [ - "Text" - ], - "template": { - "_type": "CustomComponent", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as output.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n" - }, - "input_value": { - "advanced": false, - "display_name": "Value", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Text or Record to be passed as output.", - "input_types": [ - "Record", - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": false, - "name": "input_value", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "record_template": { - "advanced": true, - "display_name": "Record Template", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", - "input_types": [ - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "record_template", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - } - } - }, - "type": "TextOutput" - }, - "dragging": false, - "height": 290, - "id": "TextOutput-2MS4a", - "position": { - "x": 2917.216113690115, - "y": 513.0058511435552 - }, - "positionAbsolute": { - "x": 2917.216113690115, - "y": 513.0058511435552 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "id": "OpenAIModel-uYXZJ", - "node": { - "base_classes": [ - "str", - "Text", - "object" - ], - "beta": false, - "custom_fields": { - "input_value": null, - "max_tokens": null, - "model_kwargs": null, - "model_name": null, - "openai_api_base": null, - "openai_api_key": null, - "stream": null, - "system_message": null, - "temperature": null - }, - "description": "Generates text using OpenAI LLMs.", - "display_name": "OpenAI", - "documentation": "", - "field_formatters": {}, - "field_order": [ - "max_tokens", - "model_kwargs", - "model_name", - "openai_api_base", - "openai_api_key", - "temperature", - "input_value", - "system_message", - "stream" - ], - "frozen": false, - "icon": "OpenAI", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Text", - "method": "text_response", - "name": "text_output", - "selected": "Message", - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - }, - { - "cache": true, - "display_name": "Language Model", - "method": "build_model", - "name": "model_output", - "selected": "LanguageModel", - "types": [ - "LanguageModel" - ], - "value": "__UNDEFINED__" - } - ], - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "import operator\nfrom functools import reduce\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import LanguageModel\nfrom langflow.inputs import (\n BoolInput,\n DictInput,\n DropdownInput,\n FloatInput,\n IntInput,\n MessageInput,\n SecretStrInput,\n StrInput,\n)\nfrom langflow.schema.message import Message\nfrom langflow.template import Output\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n inputs = [\n MessageInput(name=\"input_value\", display_name=\"Input\"),\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n info=\"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n ),\n DictInput(name=\"model_kwargs\", display_name=\"Model Kwargs\", advanced=True),\n DictInput(\n name=\"output_schema\",\n is_list=True,\n display_name=\"Schema\",\n advanced=True,\n info=\"The schema for the Output of the model. You must pass the word JSON in the prompt. If left blank, JSON mode will be disabled.\",\n ),\n DropdownInput(\n name=\"model_name\", display_name=\"Model Name\", advanced=False, options=MODEL_NAMES, value=MODEL_NAMES[0]\n ),\n StrInput(\n name=\"openai_api_base\",\n display_name=\"OpenAI API Base\",\n advanced=True,\n info=\"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.\",\n ),\n SecretStrInput(\n name=\"openai_api_key\",\n display_name=\"OpenAI API Key\",\n info=\"The OpenAI API Key to use for the OpenAI model.\",\n advanced=False,\n value=\"OPENAI_API_KEY\",\n ),\n FloatInput(name=\"temperature\", display_name=\"Temperature\", value=0.1),\n BoolInput(name=\"stream\", display_name=\"Stream\", info=STREAM_INFO_TEXT, advanced=True),\n StrInput(\n name=\"system_message\",\n display_name=\"System Message\",\n info=\"System message to pass to the model.\",\n advanced=True,\n ),\n IntInput(\n name=\"seed\",\n display_name=\"Seed\",\n info=\"The seed controls the reproducibility of the job.\",\n advanced=True,\n value=1,\n ),\n ]\n outputs = [\n Output(display_name=\"Text\", name=\"text_output\", method=\"text_response\"),\n Output(display_name=\"Language Model\", name=\"model_output\", method=\"build_model\"),\n ]\n\n def text_response(self) -> Message:\n input_value = self.input_value\n stream = self.stream\n system_message = self.system_message\n output = self.build_model()\n result = self.get_chat_result(output, stream, input_value, system_message)\n self.status = result\n return result\n\n def build_model(self) -> LanguageModel:\n # self.output_schea is a list of dictionaries\n # let's convert it to a dictionary\n output_schema_dict: dict[str, str] = reduce(operator.ior, self.output_schema or {}, {})\n openai_api_key = self.openai_api_key\n temperature = self.temperature\n model_name: str = self.model_name\n max_tokens = self.max_tokens\n model_kwargs = self.model_kwargs\n openai_api_base = self.openai_api_base or \"https://api.openai.com/v1\"\n json_mode = bool(output_schema_dict)\n seed = self.seed\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs or {},\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature or 0.1,\n seed=seed,\n )\n if json_mode:\n output = output.with_structured_output(schema=output_schema_dict, method=\"json_mode\")\n\n return output\n" - }, - "input_value": { - "advanced": false, - "display_name": "Input", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Message" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "input_value", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "max_tokens": { - "advanced": true, - "display_name": "Max Tokens", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "input_types": [ - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": false, - "name": "max_tokens", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "model_kwargs": { - "advanced": true, - "display_name": "Model Kwargs", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": false, - "name": "model_kwargs", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "model_name": { - "advanced": false, - "display_name": "Model Name", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Text" - ], - "list": true, - "load_from_db": false, - "multiline": false, - "name": "model_name", - "options": [ - "gpt-4o", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125" - ], - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "gpt-3.5-turbo" - }, - "openai_api_base": { - "advanced": true, - "display_name": "OpenAI API Base", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", - "input_types": [ - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "openai_api_base", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "openai_api_key": { - "advanced": false, - "display_name": "OpenAI API Key", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "The OpenAI API Key to use for the OpenAI model.", - "input_types": [], - "list": false, - "load_from_db": true, - "multiline": false, - "name": "openai_api_key", - "password": true, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "OPENAI_API_KEY" - }, - "stream": { - "advanced": true, - "display_name": "Stream", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Stream the response from the model. Streaming works only in Chat.", - "input_types": [ - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": false, - "name": "stream", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": false - }, - "system_message": { - "advanced": true, - "display_name": "System Message", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "System message to pass to the model.", - "input_types": [ - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "system_message", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "temperature": { - "advanced": false, - "display_name": "Temperature", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": false, - "name": "temperature", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": 0.1 - } - } - }, - "type": "OpenAIModel" - }, - "dragging": false, - "height": 565, - "id": "OpenAIModel-uYXZJ", - "position": { - "x": 2925.784767523062, - "y": 933.6465680967775 - }, - "positionAbsolute": { - "x": 2925.784767523062, - "y": 933.6465680967775 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "id": "TextOutput-MUDOR", - "node": { - "base_classes": [ - "str", - "Text", - "object" - ], - "beta": false, - "custom_fields": { - "input_value": null, - "record_template": null - }, - "description": "Display a text output in the Playground.", - "display_name": "Second Prompt", - "documentation": "", - "field_formatters": {}, - "field_order": [], - "frozen": false, - "icon": "type", - "output_types": [ - "Text" - ], - "template": { - "_type": "CustomComponent", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as output.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n" - }, - "input_value": { - "advanced": false, - "display_name": "Value", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Text or Record to be passed as output.", - "input_types": [ - "Record", - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": false, - "name": "input_value", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "record_template": { - "advanced": true, - "display_name": "Record Template", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", - "input_types": [ - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "record_template", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - } - } - }, - "type": "TextOutput" - }, - "dragging": false, - "height": 290, - "id": "TextOutput-MUDOR", - "position": { - "x": 4446.064323520379, - "y": 633.833297518702 - }, - "positionAbsolute": { - "x": 4446.064323520379, - "y": 633.833297518702 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "id": "OpenAIModel-XawYB", - "node": { - "base_classes": [ - "str", - "Text", - "object" - ], - "beta": false, - "custom_fields": { - "input_value": null, - "max_tokens": null, - "model_kwargs": null, - "model_name": null, - "openai_api_base": null, - "openai_api_key": null, - "stream": null, - "system_message": null, - "temperature": null - }, - "description": "Generates text using OpenAI LLMs.", - "display_name": "OpenAI", - "documentation": "", - "field_formatters": {}, - "field_order": [ - "max_tokens", - "model_kwargs", - "model_name", - "openai_api_base", - "openai_api_key", - "temperature", - "input_value", - "system_message", - "stream" - ], - "frozen": false, - "icon": "OpenAI", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Text", - "method": "text_response", - "name": "text_output", - "selected": "Message", - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - }, - { - "cache": true, - "display_name": "Language Model", - "method": "build_model", - "name": "model_output", - "selected": "LanguageModel", - "types": [ - "LanguageModel" - ], - "value": "__UNDEFINED__" - } - ], - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "import operator\nfrom functools import reduce\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import LanguageModel\nfrom langflow.inputs import (\n BoolInput,\n DictInput,\n DropdownInput,\n FloatInput,\n IntInput,\n MessageInput,\n SecretStrInput,\n StrInput,\n)\nfrom langflow.schema.message import Message\nfrom langflow.template import Output\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n inputs = [\n MessageInput(name=\"input_value\", display_name=\"Input\"),\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n info=\"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n ),\n DictInput(name=\"model_kwargs\", display_name=\"Model Kwargs\", advanced=True),\n DictInput(\n name=\"output_schema\",\n is_list=True,\n display_name=\"Schema\",\n advanced=True,\n info=\"The schema for the Output of the model. You must pass the word JSON in the prompt. If left blank, JSON mode will be disabled.\",\n ),\n DropdownInput(\n name=\"model_name\", display_name=\"Model Name\", advanced=False, options=MODEL_NAMES, value=MODEL_NAMES[0]\n ),\n StrInput(\n name=\"openai_api_base\",\n display_name=\"OpenAI API Base\",\n advanced=True,\n info=\"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.\",\n ),\n SecretStrInput(\n name=\"openai_api_key\",\n display_name=\"OpenAI API Key\",\n info=\"The OpenAI API Key to use for the OpenAI model.\",\n advanced=False,\n value=\"OPENAI_API_KEY\",\n ),\n FloatInput(name=\"temperature\", display_name=\"Temperature\", value=0.1),\n BoolInput(name=\"stream\", display_name=\"Stream\", info=STREAM_INFO_TEXT, advanced=True),\n StrInput(\n name=\"system_message\",\n display_name=\"System Message\",\n info=\"System message to pass to the model.\",\n advanced=True,\n ),\n IntInput(\n name=\"seed\",\n display_name=\"Seed\",\n info=\"The seed controls the reproducibility of the job.\",\n advanced=True,\n value=1,\n ),\n ]\n outputs = [\n Output(display_name=\"Text\", name=\"text_output\", method=\"text_response\"),\n Output(display_name=\"Language Model\", name=\"model_output\", method=\"build_model\"),\n ]\n\n def text_response(self) -> Message:\n input_value = self.input_value\n stream = self.stream\n system_message = self.system_message\n output = self.build_model()\n result = self.get_chat_result(output, stream, input_value, system_message)\n self.status = result\n return result\n\n def build_model(self) -> LanguageModel:\n # self.output_schea is a list of dictionaries\n # let's convert it to a dictionary\n output_schema_dict: dict[str, str] = reduce(operator.ior, self.output_schema or {}, {})\n openai_api_key = self.openai_api_key\n temperature = self.temperature\n model_name: str = self.model_name\n max_tokens = self.max_tokens\n model_kwargs = self.model_kwargs\n openai_api_base = self.openai_api_base or \"https://api.openai.com/v1\"\n json_mode = bool(output_schema_dict)\n seed = self.seed\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs or {},\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature or 0.1,\n seed=seed,\n )\n if json_mode:\n output = output.with_structured_output(schema=output_schema_dict, method=\"json_mode\")\n\n return output\n" - }, - "input_value": { - "advanced": false, - "display_name": "Input", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Message" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "input_value", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "max_tokens": { - "advanced": true, - "display_name": "Max Tokens", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "input_types": [ - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": false, - "name": "max_tokens", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "model_kwargs": { - "advanced": true, - "display_name": "Model Kwargs", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": false, - "name": "model_kwargs", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "model_name": { - "advanced": false, - "display_name": "Model Name", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Text" - ], - "list": true, - "load_from_db": false, - "multiline": false, - "name": "model_name", - "options": [ - "gpt-4o", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125" - ], - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "gpt-4o" - }, - "openai_api_base": { - "advanced": true, - "display_name": "OpenAI API Base", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", - "input_types": [ - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "openai_api_base", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "openai_api_key": { - "advanced": false, - "display_name": "OpenAI API Key", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "The OpenAI API Key to use for the OpenAI model.", - "input_types": [], - "list": false, - "load_from_db": true, - "multiline": false, - "name": "openai_api_key", - "password": true, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "OPENAI_API_KEY" - }, - "stream": { - "advanced": true, - "display_name": "Stream", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Stream the response from the model. Streaming works only in Chat.", - "input_types": [ - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": false, - "name": "stream", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": false - }, - "system_message": { - "advanced": true, - "display_name": "System Message", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "System message to pass to the model.", - "input_types": [ - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "system_message", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "temperature": { - "advanced": false, - "display_name": "Temperature", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": false, - "name": "temperature", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": 0.1 - } - } - }, - "type": "OpenAIModel" - }, - "dragging": false, - "height": 565, - "id": "OpenAIModel-XawYB", - "position": { - "x": 4500.152018344182, - "y": 1027.7382026227656 - }, - "positionAbsolute": { - "x": 4500.152018344182, - "y": 1027.7382026227656 - }, - "selected": false, - "type": "genericNode", - "width": 384 - } - ], - "viewport": { - "x": -383.7251879618552, - "y": 69.19813933800037, - "zoom": 0.3105753483695743 - } - }, - "description": "The Prompt Chaining flow chains prompts with LLMs, refining outputs through iterative stages.", - "id": "85392e54-20f3-4ab5-a179-cb4bef16f639", - "is_component": false, - "last_tested_version": "1.0.0a0", - "name": "Prompt Chaining" -} \ No newline at end of file diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Memory Conversation.json b/src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json similarity index 79% rename from src/backend/base/langflow/initial_setup/starter_projects/Langflow Memory Conversation.json rename to src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json index 5dceb0c15..c3396f03e 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Memory Conversation.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json @@ -2,11 +2,10 @@ "data": { "edges": [ { - "className": "", "data": { "sourceHandle": { "dataType": "Memory", - "id": "Memory-rvcL5", + "id": "Memory-uy2TA", "name": "messages_text", "output_types": [ "Message" @@ -14,28 +13,25 @@ }, "targetHandle": { "fieldName": "context", - "id": "Prompt-VuDd0", + "id": "Prompt-m9rUs", "inputTypes": [ - "Document", "Message", - "Record", "Text" ], "type": "str" } }, - "id": "reactflow__edge-Memory-rvcL5{œdataTypeœ:œMemoryœ,œidœ:œMemory-rvcL5œ,œnameœ:œmessages_textœ,œoutput_typesœ:[œMessageœ]}-Prompt-VuDd0{œfieldNameœ:œcontextœ,œidœ:œPrompt-VuDd0œ,œinputTypesœ:[œDocumentœ,œMessageœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "source": "Memory-rvcL5", - "sourceHandle": "{œdataTypeœ: œMemoryœ, œidœ: œMemory-rvcL5œ, œnameœ: œmessages_textœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-VuDd0", - "targetHandle": "{œfieldNameœ: œcontextœ, œidœ: œPrompt-VuDd0œ, œinputTypesœ: [œDocumentœ, œMessageœ, œRecordœ, œTextœ], œtypeœ: œstrœ}" + "id": "reactflow__edge-Memory-uy2TA{œdataTypeœ:œMemoryœ,œidœ:œMemory-uy2TAœ,œnameœ:œmessages_textœ,œoutput_typesœ:[œMessageœ]}-Prompt-m9rUs{œfieldNameœ:œcontextœ,œidœ:œPrompt-m9rUsœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", + "source": "Memory-uy2TA", + "sourceHandle": "{œdataTypeœ: œMemoryœ, œidœ: œMemory-uy2TAœ, œnameœ: œmessages_textœ, œoutput_typesœ: [œMessageœ]}", + "target": "Prompt-m9rUs", + "targetHandle": "{œfieldNameœ: œcontextœ, œidœ: œPrompt-m9rUsœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" }, { - "className": "", "data": { "sourceHandle": { "dataType": "ChatInput", - "id": "ChatInput-9iFsd", + "id": "ChatInput-hSTqh", "name": "message", "output_types": [ "Message" @@ -43,28 +39,25 @@ }, "targetHandle": { "fieldName": "user_message", - "id": "Prompt-VuDd0", + "id": "Prompt-m9rUs", "inputTypes": [ - "Document", "Message", - "Record", "Text" ], "type": "str" } }, - "id": "reactflow__edge-ChatInput-9iFsd{œdataTypeœ:œChatInputœ,œidœ:œChatInput-9iFsdœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Prompt-VuDd0{œfieldNameœ:œuser_messageœ,œidœ:œPrompt-VuDd0œ,œinputTypesœ:[œDocumentœ,œMessageœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "source": "ChatInput-9iFsd", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-9iFsdœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-VuDd0", - "targetHandle": "{œfieldNameœ: œuser_messageœ, œidœ: œPrompt-VuDd0œ, œinputTypesœ: [œDocumentœ, œMessageœ, œRecordœ, œTextœ], œtypeœ: œstrœ}" + "id": "reactflow__edge-ChatInput-hSTqh{œdataTypeœ:œChatInputœ,œidœ:œChatInput-hSTqhœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Prompt-m9rUs{œfieldNameœ:œuser_messageœ,œidœ:œPrompt-m9rUsœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", + "source": "ChatInput-hSTqh", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-hSTqhœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "Prompt-m9rUs", + "targetHandle": "{œfieldNameœ: œuser_messageœ, œidœ: œPrompt-m9rUsœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" }, { - "className": "", "data": { "sourceHandle": { "dataType": "Prompt", - "id": "Prompt-VuDd0", + "id": "Prompt-m9rUs", "name": "prompt", "output_types": [ "Message" @@ -72,25 +65,24 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "OpenAIModel-uVOc5", + "id": "OpenAIModel-WmUtU", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-Prompt-VuDd0{œdataTypeœ:œPromptœ,œidœ:œPrompt-VuDd0œ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-uVOc5{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-uVOc5œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "source": "Prompt-VuDd0", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-VuDd0œ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "target": "OpenAIModel-uVOc5", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-uVOc5œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "id": "reactflow__edge-Prompt-m9rUs{œdataTypeœ:œPromptœ,œidœ:œPrompt-m9rUsœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-WmUtU{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-WmUtUœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "source": "Prompt-m9rUs", + "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-m9rUsœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", + "target": "OpenAIModel-WmUtU", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-WmUtUœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { - "className": "", "data": { "sourceHandle": { "dataType": "OpenAIModel", - "id": "OpenAIModel-uVOc5", + "id": "OpenAIModel-WmUtU", "name": "text_output", "output_types": [ "Message" @@ -98,186 +90,24 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "ChatOutput-R7jsA", + "id": "ChatOutput-LIvGN", "inputTypes": [ - "Message", - "str" + "Message" ], "type": "str" } }, - "id": "reactflow__edge-OpenAIModel-uVOc5{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-uVOc5œ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-R7jsA{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-R7jsAœ,œinputTypesœ:[œMessageœ,œstrœ],œtypeœ:œstrœ}", - "source": "OpenAIModel-uVOc5", - "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-uVOc5œ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-R7jsA", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-R7jsAœ, œinputTypesœ: [œMessageœ, œstrœ], œtypeœ: œstrœ}" + "id": "reactflow__edge-OpenAIModel-WmUtU{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-WmUtUœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-LIvGN{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-LIvGNœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "source": "OpenAIModel-WmUtU", + "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-WmUtUœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-LIvGN", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-LIvGNœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" } ], "nodes": [ { "data": { - "description": "A component for creating prompt templates using dynamic variables.", - "display_name": "Prompt", - "id": "Prompt-VuDd0", - "node": { - "base_classes": [ - "Text", - "str", - "object" - ], - "beta": false, - "custom_fields": { - "template": [ - "context", - "user_message" - ] - }, - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt", - "documentation": "", - "error": null, - "field_formatters": {}, - "field_order": [], - "frozen": false, - "full_path": null, - "icon": "prompts", - "is_composition": null, - "is_input": null, - "is_output": null, - "name": "", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Prompt Message", - "method": "build_prompt", - "name": "prompt", - "selected": "Message", - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langflow.custom import Component\nfrom langflow.io import Output, PromptInput\nfrom langflow.schema.message import Message\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\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n prompt = await Message.from_template_and_variables(**self._attributes)\n self.status = prompt.text\n return prompt\n" - }, - "context": { - "advanced": false, - "display_name": "context", - "dynamic": false, - "field_type": "str", - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Document", - "Message", - "Record", - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "context", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "template": { - "advanced": false, - "display_name": "Template", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": false, - "name": "template", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "prompt", - "value": "{context}\n\nUser: {user_message}\nAI: " - }, - "user_message": { - "advanced": false, - "display_name": "user_message", - "dynamic": false, - "field_type": "str", - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Document", - "Message", - "Record", - "Text" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "user_message", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - } - } - }, - "type": "Prompt" - }, - "dragging": false, - "height": 525, - "id": "Prompt-VuDd0", - "position": { - "x": 1900.7563740044732, - "y": 755.4337191022057 - }, - "positionAbsolute": { - "x": 1900.7563740044732, - "y": 755.4337191022057 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "description": "Retrieves stored chat messages.", - "display_name": "Memory", - "edited": false, - "id": "Memory-rvcL5", + "id": "Memory-uy2TA", "node": { "base_classes": [ "Data", @@ -287,9 +117,9 @@ "conditional_paths": [], "custom_fields": {}, "description": "Retrieves stored chat messages.", - "display_name": "Memory", + "display_name": "Chat Memory", "documentation": "", - "edited": true, + "edited": false, "field_order": [ "sender", "sender_name", @@ -316,6 +146,7 @@ { "cache": true, "display_name": "Messages (Text)", + "hidden": false, "method": "retrieve_messages_as_text", "name": "messages_text", "selected": "Message", @@ -344,7 +175,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.io import DropdownInput, IntInput, MultilineInput, Output, MessageTextInput\nfrom langflow.memory import get_messages\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass MemoryComponent(Component):\n display_name = \"Chat Memory\"\n description = \"Retrieves stored chat messages.\"\n icon = \"message-square-more\"\n\n inputs = [\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\", \"Machine and User\"],\n value=\"Machine and User\",\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n advanced=True,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Messages\",\n value=100,\n info=\"Number of messages to retrieve.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"Session ID of the chat history.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"order\",\n display_name=\"Order\",\n options=[\"Ascending\", \"Descending\"],\n value=\"Ascending\",\n info=\"Order of the messages.\",\n advanced=True,\n ),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. It can contain the keys {text}, {sender} or any other key in the message data.\",\n value=\"{sender_name}: {text}\",\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Chat History\", name=\"messages\", method=\"retrieve_messages\"),\n Output(display_name=\"Messages (Text)\", name=\"messages_text\", method=\"retrieve_messages_as_text\"),\n ]\n\n def retrieve_messages(self) -> Data:\n sender = self.sender\n sender_name = self.sender_name\n session_id = self.session_id\n n_messages = self.n_messages\n order = \"DESC\" if self.order == \"Descending\" else \"ASC\"\n\n if sender == \"Machine and User\":\n sender = None\n\n messages = get_messages(\n sender=sender,\n sender_name=sender_name,\n session_id=session_id,\n limit=n_messages,\n order=order,\n )\n self.status = messages\n return messages\n\n def retrieve_messages_as_text(self) -> Message:\n messages_text = data_to_text(self.template, self.retrieve_messages())\n self.status = messages_text\n return Message(text=messages_text)\n" + "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.io import DropdownInput, IntInput, MessageTextInput, MultilineInput, Output\nfrom langflow.memory import get_messages\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass MemoryComponent(Component):\n display_name = \"Chat Memory\"\n description = \"Retrieves stored chat messages.\"\n icon = \"message-square-more\"\n\n inputs = [\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\", \"Machine and User\"],\n value=\"Machine and User\",\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n advanced=True,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Messages\",\n value=100,\n info=\"Number of messages to retrieve.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"Session ID of the chat history.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"order\",\n display_name=\"Order\",\n options=[\"Ascending\", \"Descending\"],\n value=\"Ascending\",\n info=\"Order of the messages.\",\n advanced=True,\n ),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. It can contain the keys {text}, {sender} or any other key in the message data.\",\n value=\"{sender_name}: {text}\",\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Chat History\", name=\"messages\", method=\"retrieve_messages\"),\n Output(display_name=\"Messages (Text)\", name=\"messages_text\", method=\"retrieve_messages_as_text\"),\n ]\n\n def retrieve_messages(self) -> Data:\n sender = self.sender\n sender_name = self.sender_name\n session_id = self.session_id\n n_messages = self.n_messages\n order = \"DESC\" if self.order == \"Descending\" else \"ASC\"\n\n if sender == \"Machine and User\":\n sender = None\n\n messages = get_messages(\n sender=sender,\n sender_name=sender_name,\n session_id=session_id,\n limit=n_messages,\n order=order,\n )\n self.status = messages\n return messages\n\n def retrieve_messages_as_text(self) -> Message:\n messages_text = data_to_text(self.template, self.retrieve_messages())\n self.status = messages_text\n return Message(text=messages_text)\n" }, "n_messages": { "advanced": true, @@ -357,6 +188,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "int", "value": 100 }, @@ -374,6 +206,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "str", "value": "Ascending" }, @@ -392,6 +225,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "str", "value": "Machine and User" }, @@ -410,6 +244,8 @@ "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" }, @@ -428,6 +264,8 @@ "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" }, @@ -447,6 +285,8 @@ "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "{sender_name}: {text}" } @@ -455,15 +295,15 @@ "type": "Memory" }, "dragging": false, - "height": 267, - "id": "Memory-rvcL5", + "height": 266, + "id": "Memory-uy2TA", "position": { - "x": 1258.8089948698466, - "y": 547.1243849102437 + "x": 1264.7588980556088, + "y": 506.6868269980502 }, "positionAbsolute": { - "x": 1258.8089948698466, - "y": 547.1243849102437 + "x": 1264.7588980556088, + "y": 506.6868269980502 }, "selected": false, "type": "genericNode", @@ -471,7 +311,157 @@ }, { "data": { - "id": "ChatInput-9iFsd", + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt", + "id": "Prompt-m9rUs", + "node": { + "base_classes": [ + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": { + "template": [ + "context", + "user_message" + ] + }, + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt", + "documentation": "", + "edited": false, + "error": null, + "field_order": [ + "template" + ], + "frozen": false, + "full_path": null, + "icon": "prompts", + "is_composition": null, + "is_input": null, + "is_output": null, + "name": "", + "output_types": [], + "outputs": [ + { + "cache": true, + "display_name": "Prompt Message", + "hidden": false, + "method": "build_prompt", + "name": "prompt", + "selected": "Message", + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "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.io import 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\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n prompt = await Message.from_template_and_variables(**self._attributes)\n self.status = prompt.text\n return prompt\n\n def post_code_processing(self, new_build_config: dict, current_build_config: dict):\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(new_build_config, current_build_config)\n template = frontend_node[\"template\"][\"template\"][\"value\"]\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_build_config\n # and update the frontend_node with those values\n update_template_values(frontend_template=frontend_node, raw_template=current_build_config[\"template\"])\n return frontend_node\n" + }, + "context": { + "advanced": false, + "display_name": "context", + "dynamic": false, + "field_type": "str", + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Message", + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "context", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "template": { + "advanced": false, + "display_name": "Template", + "dynamic": false, + "info": "", + "list": false, + "name": "template", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "type": "prompt", + "value": "{context}\n\nUser: {user_message}\nAI: " + }, + "user_message": { + "advanced": false, + "display_name": "user_message", + "dynamic": false, + "field_type": "str", + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Message", + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "user_message", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + } + } + }, + "type": "Prompt" + }, + "dragging": false, + "height": 515, + "id": "Prompt-m9rUs", + "position": { + "x": 1880.8227904110583, + "y": 625.8049209882275 + }, + "positionAbsolute": { + "x": 1880.8227904110583, + "y": 625.8049209882275 + }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { + "data": { + "id": "ChatInput-hSTqh", "node": { "base_classes": [ "Message" @@ -482,6 +472,7 @@ "description": "Get chat inputs from the Playground.", "display_name": "Chat Input", "documentation": "", + "edited": false, "field_order": [ "input_value", "sender", @@ -496,6 +487,7 @@ { "cache": true, "display_name": "Message", + "hidden": false, "method": "message_response", "name": "message", "selected": "Message", @@ -524,7 +516,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.io import DropdownInput, FileInput, MultilineInput, Output, MessageTextInput\nfrom langflow.schema.message import Message\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\"],\n value=\"User\",\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=\"User\",\n advanced=True,\n ),\n MessageTextInput(name=\"session_id\", display_name=\"Session ID\", info=\"Session ID for the message.\", advanced=True),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n )\n if self.session_id and isinstance(message, Message) and isinstance(message.text, str):\n self.store_message(message)\n self.message.value = message\n\n self.status = message\n return message\n" + "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.schema.message import Message\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\"],\n value=\"User\",\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=\"User\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\", display_name=\"Session ID\", info=\"Session ID for the message.\", advanced=True\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n )\n if self.session_id and isinstance(message, Message) and isinstance(message.text, str):\n self.store_message(message)\n self.message.value = message\n\n self.status = message\n return message\n" }, "files": { "advanced": true, @@ -563,6 +555,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "file", "value": "" }, @@ -572,8 +565,7 @@ "dynamic": false, "info": "Message to be passed as input.", "input_types": [ - "Message", - "str" + "Message" ], "list": false, "load_from_db": false, @@ -583,6 +575,8 @@ "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" }, @@ -600,6 +594,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "str", "value": "User" }, @@ -609,17 +604,17 @@ "dynamic": false, "info": "Name of the sender.", "input_types": [ - "Message", - "str" + "Message" ], "list": false, "load_from_db": false, - "multiline": true, "name": "sender_name", "placeholder": "", "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "User" }, @@ -629,17 +624,17 @@ "dynamic": false, "info": "Session ID for the message.", "input_types": [ - "Message", - "str" + "Message" ], "list": false, "load_from_db": false, - "multiline": true, "name": "session_id", "placeholder": "", "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" } @@ -648,15 +643,15 @@ "type": "ChatInput" }, "dragging": false, - "height": 309, - "id": "ChatInput-9iFsd", + "height": 308, + "id": "ChatInput-hSTqh", "position": { - "x": 1246.4850995457527, - "y": 912.733279525042 + "x": 1275.9262193671882, + "y": 836.1228056896347 }, "positionAbsolute": { - "x": 1246.4850995457527, - "y": 912.733279525042 + "x": 1275.9262193671882, + "y": 836.1228056896347 }, "selected": false, "type": "genericNode", @@ -664,10 +659,7 @@ }, { "data": { - "description": "Generates text using OpenAI LLMs.", - "display_name": "OpenAI", - "edited": false, - "id": "OpenAIModel-uVOc5", + "id": "OpenAIModel-WmUtU", "node": { "base_classes": [ "LanguageModel", @@ -679,7 +671,7 @@ "description": "Generates text using OpenAI LLMs.", "display_name": "OpenAI", "documentation": "", - "edited": true, + "edited": false, "field_order": [ "input_value", "max_tokens", @@ -700,6 +692,7 @@ { "cache": true, "display_name": "Text", + "hidden": false, "method": "text_response", "name": "text_output", "selected": "Message", @@ -756,6 +749,8 @@ "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" }, @@ -770,6 +765,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "int", "value": "" }, @@ -784,6 +780,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_input": true, "type": "dict", "value": {} }, @@ -804,6 +801,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "str", "value": "gpt-4-turbo" }, @@ -819,6 +817,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "str", "value": "" }, @@ -828,7 +827,7 @@ "dynamic": false, "info": "The OpenAI API Key to use for the OpenAI model.", "input_types": [], - "load_from_db": true, + "load_from_db": false, "name": "openai_api_key", "password": true, "placeholder": "", @@ -849,6 +848,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_input": true, "type": "dict", "value": {} }, @@ -863,6 +863,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "int", "value": 1 }, @@ -877,6 +878,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "bool", "value": false }, @@ -892,6 +894,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "str", "value": "" }, @@ -906,6 +909,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "float", "value": 0.1 } @@ -914,15 +918,15 @@ "type": "OpenAIModel" }, "dragging": false, - "height": 623, - "id": "OpenAIModel-uVOc5", + "height": 621, + "id": "OpenAIModel-WmUtU", "position": { - "x": 2495.6628431453228, - "y": 668.0955451423632 + "x": 2428.0215346784357, + "y": 569.9683144303319 }, "positionAbsolute": { - "x": 2495.6628431453228, - "y": 668.0955451423632 + "x": 2428.0215346784357, + "y": 569.9683144303319 }, "selected": false, "type": "genericNode", @@ -930,7 +934,7 @@ }, { "data": { - "id": "ChatOutput-R7jsA", + "id": "ChatOutput-LIvGN", "node": { "base_classes": [ "Message" @@ -941,6 +945,7 @@ "description": "Display a chat message in the Playground.", "display_name": "Chat Output", "documentation": "", + "edited": false, "field_order": [ "input_value", "sender", @@ -983,7 +988,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.io import DropdownInput, Output, MessageTextInput\nfrom langflow.schema.message import Message\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\"],\n value=\"Machine\",\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\", display_name=\"Sender Name\", info=\"Name of the sender.\", value=\"AI\", advanced=True\n ),\n MessageTextInput(name=\"session_id\", display_name=\"Session ID\", info=\"Session ID for the message.\", advanced=True),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n )\n if self.session_id and isinstance(message, Message) and isinstance(message.text, str):\n self.store_message(message)\n self.message.value = message\n\n self.status = message\n return message\n" + "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\"],\n value=\"Machine\",\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\", display_name=\"Sender Name\", info=\"Name of the sender.\", value=\"AI\", advanced=True\n ),\n MessageTextInput(\n name=\"session_id\", display_name=\"Session ID\", info=\"Session ID for the message.\", advanced=True\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n )\n if self.session_id and isinstance(message, Message) and isinstance(message.text, str):\n self.store_message(message)\n self.message.value = message\n\n self.status = message\n return message\n" }, "data_template": { "advanced": true, @@ -991,17 +996,17 @@ "dynamic": false, "info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.", "input_types": [ - "Message", - "str" + "Message" ], "list": false, "load_from_db": false, - "multiline": true, "name": "data_template", "placeholder": "", "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "{text}" }, @@ -1011,17 +1016,17 @@ "dynamic": false, "info": "Message to be passed as output.", "input_types": [ - "Message", - "str" + "Message" ], "list": false, "load_from_db": false, - "multiline": true, "name": "input_value", "placeholder": "", "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" }, @@ -1039,6 +1044,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "str", "value": "Machine" }, @@ -1048,17 +1054,17 @@ "dynamic": false, "info": "Name of the sender.", "input_types": [ - "Message", - "str" + "Message" ], "list": false, "load_from_db": false, - "multiline": true, "name": "sender_name", "placeholder": "", "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "AI" }, @@ -1068,17 +1074,17 @@ "dynamic": false, "info": "Session ID for the message.", "input_types": [ - "Message", - "str" + "Message" ], "list": false, "load_from_db": false, - "multiline": true, "name": "session_id", "placeholder": "", "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" } @@ -1087,15 +1093,15 @@ "type": "ChatOutput" }, "dragging": false, - "height": 309, - "id": "ChatOutput-R7jsA", + "height": 308, + "id": "ChatOutput-LIvGN", "position": { - "x": 3129.987101578166, - "y": 888.0854888768531 + "x": 2988.248820475989, + "y": 705.837390387878 }, "positionAbsolute": { - "x": 3129.987101578166, - "y": 888.0854888768531 + "x": 2988.248820475989, + "y": 705.837390387878 }, "selected": false, "type": "genericNode", @@ -1103,15 +1109,15 @@ } ], "viewport": { - "x": -527.2609043386433, - "y": 33.26280492099636, - "zoom": 0.48650433790103115 + "x": -586.5321077101332, + "y": -103.32118023592653, + "zoom": 0.5372819347267049 } }, "description": "This project can be used as a starting point for building a Chat experience with user specific memory. You can set a different Session ID to start a new message history.", "endpoint_name": null, - "id": "4e88f957-1541-4760-8a03-6132d4b14090", + "id": "2a47bc35-69ca-4d8b-9895-2a7fab222b9f", "is_component": false, - "last_tested_version": "1.0.0a61", + "last_tested_version": "1.0.0rc1", "name": "Memory Chatbot" } \ No newline at end of file diff --git a/src/backend/base/langflow/initial_setup/starter_projects/VectorStore-RAG-Flows.json b/src/backend/base/langflow/initial_setup/starter_projects/Vector Store RAG.json similarity index 54% rename from src/backend/base/langflow/initial_setup/starter_projects/VectorStore-RAG-Flows.json rename to src/backend/base/langflow/initial_setup/starter_projects/Vector Store RAG.json index df5d8f072..ae6115c67 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/VectorStore-RAG-Flows.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Vector Store RAG.json @@ -2,278 +2,282 @@ "data": { "edges": [ { - "className": "", - "data": { - "sourceHandle": { - "dataType": "Prompt", - "id": "Prompt-VecUe", - "name": "prompt", - "output_types": ["Message"] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-PKrw7", - "inputTypes": ["Message"], - "type": "str" - } - }, - "id": "reactflow__edge-Prompt-VecUe{œdataTypeœ:œPromptœ,œidœ:œPrompt-VecUeœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-PKrw7{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-PKrw7œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "Prompt-VecUe", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-VecUeœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "style": { - "stroke": "#555" - }, - "target": "OpenAIModel-PKrw7", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-PKrw7œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - }, - { - "className": "", - "data": { - "sourceHandle": { - "dataType": "OpenAIModel", - "id": "OpenAIModel-PKrw7", - "name": "text_output", - "output_types": ["Message"] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-nUD9B", - "inputTypes": ["Message", "str"], - "type": "str" - } - }, - "id": "reactflow__edge-OpenAIModel-PKrw7{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-PKrw7œ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-nUD9B{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-nUD9Bœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "OpenAIModel-PKrw7", - "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-PKrw7œ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", - "style": { - "stroke": "#555" - }, - "target": "ChatOutput-nUD9B", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-nUD9Bœ, œinputTypesœ: [œMessageœ, œstrœ], œtypeœ: œstrœ}" - }, - { - "className": "", - "data": { - "sourceHandle": { - "dataType": "File", - "id": "File-w2zxA", - "name": "data", - "output_types": ["Data"] - }, - "targetHandle": { - "fieldName": "data_input", - "id": "RecursiveCharacterTextSplitter-CrApG", - "inputTypes": ["Document", "Data"], - "type": "other" - } - }, - "id": "reactflow__edge-File-w2zxA{œdataTypeœ:œFileœ,œidœ:œFile-w2zxAœ,œnameœ:œdataœ,œoutput_typesœ:[œDataœ]}-RecursiveCharacterTextSplitter-CrApG{œfieldNameœ:œdata_inputœ,œidœ:œRecursiveCharacterTextSplitter-CrApGœ,œinputTypesœ:[œDocumentœ,œDataœ],œtypeœ:œotherœ}", - "source": "File-w2zxA", - "sourceHandle": "{œdataTypeœ: œFileœ, œidœ: œFile-w2zxAœ, œnameœ: œdataœ, œoutput_typesœ: [œDataœ]}", - "target": "RecursiveCharacterTextSplitter-CrApG", - "targetHandle": "{œfieldNameœ: œdata_inputœ, œidœ: œRecursiveCharacterTextSplitter-CrApGœ, œinputTypesœ: [œDocumentœ, œDataœ], œtypeœ: œotherœ}" - }, - { - "className": "", - "data": { - "sourceHandle": { - "dataType": "RecursiveCharacterTextSplitter", - "id": "RecursiveCharacterTextSplitter-CrApG", - "name": "data", - "output_types": ["Data"] - }, - "targetHandle": { - "fieldName": "vector_store_inputs", - "id": "AstraDB-rXo8b", - "inputTypes": ["Data"], - "type": "other" - } - }, - "id": "reactflow__edge-RecursiveCharacterTextSplitter-CrApG{œdataTypeœ:œRecursiveCharacterTextSplitterœ,œidœ:œRecursiveCharacterTextSplitter-CrApGœ,œnameœ:œdataœ,œoutput_typesœ:[œDataœ]}-AstraDB-rXo8b{œfieldNameœ:œvector_store_inputsœ,œidœ:œAstraDB-rXo8bœ,œinputTypesœ:[œDocumentœ,œDataœ],œtypeœ:œotherœ}", - "source": "RecursiveCharacterTextSplitter-CrApG", - "sourceHandle": "{œdataTypeœ: œRecursiveCharacterTextSplitterœ, œidœ: œRecursiveCharacterTextSplitter-CrApGœ, œnameœ: œdataœ, œoutput_typesœ: [œDataœ]}", - "target": "AstraDB-rXo8b", - "targetHandle": "{œfieldNameœ: œvector_store_inputsœ, œidœ: œAstraDB-rXo8bœ, œinputTypesœ: [œDataœ], œtypeœ: œotherœ}" - }, - { - "className": "", - "data": { - "sourceHandle": { - "dataType": "OpenAIEmbeddings", - "id": "OpenAIEmbeddings-PCoh9", - "name": "embeddings", - "output_types": ["Embeddings"] - }, - "targetHandle": { - "fieldName": "embedding", - "id": "AstraDB-rXo8b", - "inputTypes": ["Embeddings", "dict"], - "type": "other" - } - }, - "id": "reactflow__edge-OpenAIEmbeddings-PCoh9{œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-PCoh9œ,œnameœ:œembeddingsœ,œoutput_typesœ:[œEmbeddingsœ]}-AstraDB-rXo8b{œfieldNameœ:œembeddingœ,œidœ:œAstraDB-rXo8bœ,œinputTypesœ:[œEmbeddingsœ],œtypeœ:œotherœ}", - "source": "OpenAIEmbeddings-PCoh9", - "sourceHandle": "{œdataTypeœ: œOpenAIEmbeddingsœ, œidœ: œOpenAIEmbeddings-PCoh9œ, œnameœ: œembeddingsœ, œoutput_typesœ: [œEmbeddingsœ]}", - "target": "AstraDB-rXo8b", - "targetHandle": "{œfieldNameœ: œembeddingœ, œidœ: œAstraDB-rXo8bœ, œinputTypesœ: [œEmbeddingsœ, œdictœ], œtypeœ: œotherœ}" - }, - { - "className": "", "data": { "sourceHandle": { "dataType": "ChatInput", - "id": "ChatInput-sn9b4", + "id": "ChatInput-c4xn9", "name": "message", - "output_types": ["Message"] + "output_types": [ + "Message" + ] }, "targetHandle": { "fieldName": "search_input", - "id": "AstraDB-61WgV", - "inputTypes": ["Message", "str"], + "id": "AstraDB-7nAHJ", + "inputTypes": [ + "Message" + ], "type": "str" } }, - "id": "reactflow__edge-ChatInput-sn9b4{œdataTypeœ:œChatInputœ,œidœ:œChatInput-sn9b4œ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-AstraDB-61WgV{œfieldNameœ:œsearch_inputœ,œidœ:œAstraDB-61WgVœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "ChatInput-sn9b4", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-sn9b4œ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "AstraDB-61WgV", - "targetHandle": "{œfieldNameœ: œsearch_inputœ, œidœ: œAstraDB-61WgVœ, œinputTypesœ: [œMessageœ, œstrœ], œtypeœ: œstrœ}" + "id": "reactflow__edge-ChatInput-c4xn9{œdataTypeœ:œChatInputœ,œidœ:œChatInput-c4xn9œ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-AstraDB-7nAHJ{œfieldNameœ:œsearch_inputœ,œidœ:œAstraDB-7nAHJœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "source": "ChatInput-c4xn9", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-c4xn9œ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "AstraDB-7nAHJ", + "targetHandle": "{œfieldNameœ: œsearch_inputœ, œidœ: œAstraDB-7nAHJœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { - "className": "", "data": { "sourceHandle": { "dataType": "OpenAIEmbeddings", - "id": "OpenAIEmbeddings-HsV7O", + "id": "OpenAIEmbeddings-BKXc6", "name": "embeddings", - "output_types": ["Embeddings"] + "output_types": [ + "Embeddings" + ] }, "targetHandle": { "fieldName": "embedding", - "id": "AstraDB-61WgV", - "inputTypes": ["Embeddings", "dict"], + "id": "AstraDB-7nAHJ", + "inputTypes": [ + "Embeddings", + "dict" + ], "type": "other" } }, - "id": "reactflow__edge-OpenAIEmbeddings-HsV7O{œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-HsV7Oœ,œnameœ:œembeddingsœ,œoutput_typesœ:[œEmbeddingsœ]}-AstraDB-61WgV{œfieldNameœ:œembeddingœ,œidœ:œAstraDB-61WgVœ,œinputTypesœ:[œEmbeddingsœ],œtypeœ:œotherœ}", - "selected": false, - "source": "OpenAIEmbeddings-HsV7O", - "sourceHandle": "{œdataTypeœ: œOpenAIEmbeddingsœ, œidœ: œOpenAIEmbeddings-HsV7Oœ, œnameœ: œembeddingsœ, œoutput_typesœ: [œEmbeddingsœ]}", - "target": "AstraDB-61WgV", - "targetHandle": "{œfieldNameœ: œembeddingœ, œidœ: œAstraDB-61WgVœ, œinputTypesœ: [œEmbeddingsœ, œdictœ], œtypeœ: œotherœ}" + "id": "reactflow__edge-OpenAIEmbeddings-BKXc6{œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-BKXc6œ,œnameœ:œembeddingsœ,œoutput_typesœ:[œEmbeddingsœ]}-AstraDB-7nAHJ{œfieldNameœ:œembeddingœ,œidœ:œAstraDB-7nAHJœ,œinputTypesœ:[œEmbeddingsœ,œdictœ],œtypeœ:œotherœ}", + "source": "OpenAIEmbeddings-BKXc6", + "sourceHandle": "{œdataTypeœ: œOpenAIEmbeddingsœ, œidœ: œOpenAIEmbeddings-BKXc6œ, œnameœ: œembeddingsœ, œoutput_typesœ: [œEmbeddingsœ]}", + "target": "AstraDB-7nAHJ", + "targetHandle": "{œfieldNameœ: œembeddingœ, œidœ: œAstraDB-7nAHJœ, œinputTypesœ: [œEmbeddingsœ, œdictœ], œtypeœ: œotherœ}" }, { - "className": "", "data": { "sourceHandle": { "dataType": "AstraDB", - "id": "AstraDB-61WgV", + "id": "AstraDB-7nAHJ", "name": "search_results", - "output_types": ["Data"] + "output_types": [ + "Data" + ] }, "targetHandle": { "fieldName": "data", - "id": "ParseData-DXlFW", - "inputTypes": ["Data"], + "id": "ParseData-d61Q0", + "inputTypes": [ + "Data" + ], "type": "other" } }, - "id": "reactflow__edge-AstraDB-61WgV{œdataTypeœ:œAstraDBœ,œidœ:œAstraDB-61WgVœ,œnameœ:œsearch_resultsœ,œoutput_typesœ:[œDataœ]}-ParseData-DXlFW{œfieldNameœ:œdataœ,œidœ:œParseData-DXlFWœ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}", - "selected": false, - "source": "AstraDB-61WgV", - "sourceHandle": "{œdataTypeœ: œAstraDBœ, œidœ: œAstraDB-61WgVœ, œnameœ: œsearch_resultsœ, œoutput_typesœ: [œDataœ]}", - "target": "ParseData-DXlFW", - "targetHandle": "{œfieldNameœ: œdataœ, œidœ: œParseData-DXlFWœ, œinputTypesœ: [œDataœ], œtypeœ: œotherœ}" + "id": "reactflow__edge-AstraDB-7nAHJ{œdataTypeœ:œAstraDBœ,œidœ:œAstraDB-7nAHJœ,œnameœ:œsearch_resultsœ,œoutput_typesœ:[œDataœ]}-ParseData-d61Q0{œfieldNameœ:œdataœ,œidœ:œParseData-d61Q0œ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}", + "source": "AstraDB-7nAHJ", + "sourceHandle": "{œdataTypeœ: œAstraDBœ, œidœ: œAstraDB-7nAHJœ, œnameœ: œsearch_resultsœ, œoutput_typesœ: [œDataœ]}", + "target": "ParseData-d61Q0", + "targetHandle": "{œfieldNameœ: œdataœ, œidœ: œParseData-d61Q0œ, œinputTypesœ: [œDataœ], œtypeœ: œotherœ}" }, { - "className": "", "data": { "sourceHandle": { "dataType": "ParseData", - "id": "ParseData-DXlFW", + "id": "ParseData-d61Q0", "name": "text", - "output_types": ["Message"] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "TextOutput-rT1Fj", - "inputTypes": ["Message"], - "type": "str" - } - }, - "id": "reactflow__edge-ParseData-DXlFW{œdataTypeœ:œParseDataœ,œidœ:œParseData-DXlFWœ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-TextOutput-rT1Fj{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-rT1Fjœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "source": "ParseData-DXlFW", - "sourceHandle": "{œdataTypeœ: œParseDataœ, œidœ: œParseData-DXlFWœ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}", - "target": "TextOutput-rT1Fj", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œTextOutput-rT1Fjœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - }, - { - "className": "", - "data": { - "sourceHandle": { - "dataType": "TextOutput", - "id": "TextOutput-rT1Fj", - "name": "text", - "output_types": ["Message"] + "output_types": [ + "Message" + ] }, "targetHandle": { "fieldName": "context", - "id": "Prompt-VecUe", - "inputTypes": ["Message", "Text"], + "id": "Prompt-vqAlG", + "inputTypes": [ + "Message", + "Text" + ], "type": "str" } }, - "id": "reactflow__edge-TextOutput-rT1Fj{œdataTypeœ:œTextOutputœ,œidœ:œTextOutput-rT1Fjœ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-Prompt-VecUe{œfieldNameœ:œcontextœ,œidœ:œPrompt-VecUeœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", - "source": "TextOutput-rT1Fj", - "sourceHandle": "{œdataTypeœ: œTextOutputœ, œidœ: œTextOutput-rT1Fjœ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-VecUe", - "targetHandle": "{œfieldNameœ: œcontextœ, œidœ: œPrompt-VecUeœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" + "id": "reactflow__edge-ParseData-d61Q0{œdataTypeœ:œParseDataœ,œidœ:œParseData-d61Q0œ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-Prompt-vqAlG{œfieldNameœ:œcontextœ,œidœ:œPrompt-vqAlGœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", + "source": "ParseData-d61Q0", + "sourceHandle": "{œdataTypeœ: œParseDataœ, œidœ: œParseData-d61Q0œ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}", + "target": "Prompt-vqAlG", + "targetHandle": "{œfieldNameœ: œcontextœ, œidœ: œPrompt-vqAlGœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" }, { - "className": "", "data": { "sourceHandle": { "dataType": "ChatInput", - "id": "ChatInput-sn9b4", + "id": "ChatInput-c4xn9", "name": "message", - "output_types": ["Message"] + "output_types": [ + "Message" + ] }, "targetHandle": { "fieldName": "question", - "id": "Prompt-VecUe", - "inputTypes": ["Message", "Text"], + "id": "Prompt-vqAlG", + "inputTypes": [ + "Message", + "Text" + ], "type": "str" } }, - "id": "reactflow__edge-ChatInput-sn9b4{œdataTypeœ:œChatInputœ,œidœ:œChatInput-sn9b4œ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Prompt-VecUe{œfieldNameœ:œquestionœ,œidœ:œPrompt-VecUeœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", - "source": "ChatInput-sn9b4", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-sn9b4œ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-VecUe", - "targetHandle": "{œfieldNameœ: œquestionœ, œidœ: œPrompt-VecUeœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" + "id": "reactflow__edge-ChatInput-c4xn9{œdataTypeœ:œChatInputœ,œidœ:œChatInput-c4xn9œ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Prompt-vqAlG{œfieldNameœ:œquestionœ,œidœ:œPrompt-vqAlGœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", + "source": "ChatInput-c4xn9", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-c4xn9œ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "Prompt-vqAlG", + "targetHandle": "{œfieldNameœ: œquestionœ, œidœ: œPrompt-vqAlGœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "Prompt", + "id": "Prompt-vqAlG", + "name": "prompt", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "OpenAIModel-ybL3k", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "reactflow__edge-Prompt-vqAlG{œdataTypeœ:œPromptœ,œidœ:œPrompt-vqAlGœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-ybL3k{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-ybL3kœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "source": "Prompt-vqAlG", + "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-vqAlGœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", + "target": "OpenAIModel-ybL3k", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-ybL3kœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "OpenAIModel", + "id": "OpenAIModel-ybL3k", + "name": "text_output", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-BpzuD", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "reactflow__edge-OpenAIModel-ybL3k{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-ybL3kœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-BpzuD{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-BpzuDœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "source": "OpenAIModel-ybL3k", + "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-ybL3kœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-BpzuD", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-BpzuDœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "File", + "id": "File-bf6wn", + "name": "data", + "output_types": [ + "Data" + ] + }, + "targetHandle": { + "fieldName": "data_inputs", + "id": "SplitText-52wBo", + "inputTypes": [ + "Data" + ], + "type": "other" + } + }, + "id": "reactflow__edge-File-bf6wn{œdataTypeœ:œFileœ,œidœ:œFile-bf6wnœ,œnameœ:œdataœ,œoutput_typesœ:[œDataœ]}-SplitText-52wBo{œfieldNameœ:œdata_inputsœ,œidœ:œSplitText-52wBoœ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}", + "source": "File-bf6wn", + "sourceHandle": "{œdataTypeœ: œFileœ, œidœ: œFile-bf6wnœ, œnameœ: œdataœ, œoutput_typesœ: [œDataœ]}", + "target": "SplitText-52wBo", + "targetHandle": "{œfieldNameœ: œdata_inputsœ, œidœ: œSplitText-52wBoœ, œinputTypesœ: [œDataœ], œtypeœ: œotherœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "SplitText", + "id": "SplitText-52wBo", + "name": "chunks", + "output_types": [ + "Data" + ] + }, + "targetHandle": { + "fieldName": "ingest_data", + "id": "AstraDB-vyd5U", + "inputTypes": [ + "Data" + ], + "type": "other" + } + }, + "id": "reactflow__edge-SplitText-52wBo{œdataTypeœ:œSplitTextœ,œidœ:œSplitText-52wBoœ,œnameœ:œchunksœ,œoutput_typesœ:[œDataœ]}-AstraDB-vyd5U{œfieldNameœ:œingest_dataœ,œidœ:œAstraDB-vyd5Uœ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}", + "source": "SplitText-52wBo", + "sourceHandle": "{œdataTypeœ: œSplitTextœ, œidœ: œSplitText-52wBoœ, œnameœ: œchunksœ, œoutput_typesœ: [œDataœ]}", + "target": "AstraDB-vyd5U", + "targetHandle": "{œfieldNameœ: œingest_dataœ, œidœ: œAstraDB-vyd5Uœ, œinputTypesœ: [œDataœ], œtypeœ: œotherœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "OpenAIEmbeddings", + "id": "OpenAIEmbeddings-sRZMc", + "name": "embeddings", + "output_types": [ + "Embeddings" + ] + }, + "targetHandle": { + "fieldName": "embedding", + "id": "AstraDB-vyd5U", + "inputTypes": [ + "Embeddings", + "dict" + ], + "type": "other" + } + }, + "id": "reactflow__edge-OpenAIEmbeddings-sRZMc{œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-sRZMcœ,œnameœ:œembeddingsœ,œoutput_typesœ:[œEmbeddingsœ]}-AstraDB-vyd5U{œfieldNameœ:œembeddingœ,œidœ:œAstraDB-vyd5Uœ,œinputTypesœ:[œEmbeddingsœ,œdictœ],œtypeœ:œotherœ}", + "source": "OpenAIEmbeddings-sRZMc", + "sourceHandle": "{œdataTypeœ: œOpenAIEmbeddingsœ, œidœ: œOpenAIEmbeddings-sRZMcœ, œnameœ: œembeddingsœ, œoutput_typesœ: [œEmbeddingsœ]}", + "target": "AstraDB-vyd5U", + "targetHandle": "{œfieldNameœ: œembeddingœ, œidœ: œAstraDB-vyd5Uœ, œinputTypesœ: [œEmbeddingsœ, œdictœ], œtypeœ: œotherœ}" } ], "nodes": [ { "data": { - "id": "ChatInput-sn9b4", + "id": "ChatInput-c4xn9", "node": { - "base_classes": ["Text", "str", "object", "Record"], + "base_classes": [ + "Message" + ], "beta": false, - "custom_fields": { - "input_value": null, - "return_record": null, - "sender": null, - "sender_name": null, - "session_id": null - }, + "conditional_paths": [], + "custom_fields": {}, "description": "Get chat inputs from the Playground.", "display_name": "Chat Input", "documentation": "", - "field_formatters": {}, - "field_order": [], + "edited": false, + "field_order": [ + "input_value", + "sender", + "sender_name", + "session_id", + "files" + ], "frozen": false, "icon": "ChatInput", "output_types": [], @@ -281,161 +285,13 @@ { "cache": true, "display_name": "Message", + "hidden": false, "method": "message_response", "name": "message", "selected": "Message", - "types": ["Message"], - "value": "__UNDEFINED__" - } - ], - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.io import DropdownInput, FileInput, Output, TextInput\nfrom langflow.schema.message import Message\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n inputs = [\n TextInput(\n name=\"input_value\",\n display_name=\"Text\",\n multiline=True,\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\"],\n value=\"User\",\n info=\"Type of sender.\",\n advanced=True,\n ),\n TextInput(\n name=\"sender_name\",\n type=str,\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=\"User\",\n advanced=True,\n ),\n TextInput(\n name=\"session_id\", type=str, display_name=\"Session ID\", info=\"Session ID for the message.\", advanced=True\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n )\n if self.session_id and isinstance(message, Message) and isinstance(message.text, str):\n self.store_message(message)\n self.message.value = message\n\n self.status = message\n return message\n" - }, - "input_value": { - "advanced": false, - "display_name": "Text", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Message to be passed as input.", - "input_types": ["Message", "str"], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "input_value", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "uau" - }, - "sender": { - "advanced": true, - "display_name": "Sender Type", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Type of sender.", - "input_types": ["Text"], - "list": true, - "load_from_db": false, - "multiline": false, - "name": "sender", - "options": ["Machine", "User"], - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "User" - }, - "sender_name": { - "advanced": true, - "display_name": "Sender Name", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Name of the sender.", - "input_types": ["Message", "str"], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "sender_name", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "User" - }, - "session_id": { - "advanced": true, - "display_name": "Session ID", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Session ID for the message.", - "input_types": ["Message", "str"], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "session_id", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - } - } - }, - "type": "ChatInput" - }, - "dragging": false, - "height": 309, - "id": "ChatInput-sn9b4", - "position": { - "x": 702.4571951501161, - "y": 119.7726926425525 - }, - "positionAbsolute": { - "x": 702.4571951501161, - "y": 119.7726926425525 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "description": "Display a text output in the Playground.", - "display_name": "Extracted Chunks", - "edited": false, - "id": "TextOutput-rT1Fj", - "node": { - "base_classes": ["Message"], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Display a text output in the Playground.", - "display_name": "Extracted Chunks", - "documentation": "", - "edited": true, - "field_order": ["input_value"], - "frozen": false, - "icon": "type", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Text", - "hidden": false, - "method": "text_response", - "name": "text", - "selected": "Message", - "types": ["Message"], + "types": [ + "Message" + ], "value": "__UNDEFINED__" } ], @@ -458,38 +314,563 @@ "show": true, "title_case": false, "type": "code", - "value": "from langflow.base.io.text import TextComponent\nfrom langflow.io import Output\nfrom langflow.io import TextInput\nfrom langflow.schema.message import Message\n\n\nclass TextOutputComponent(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\n icon = \"type\"\n\n inputs = [\n TextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Text to be passed as output.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Text\", name=\"text\", method=\"text_response\"),\n ]\n\n def text_response(self) -> Message:\n message = Message(\n text=self.input_value,\n )\n self.status = self.input_value\n return message\n" + "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.schema.message import Message\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\"],\n value=\"User\",\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=\"User\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\", display_name=\"Session ID\", info=\"Session ID for the message.\", advanced=True\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n )\n if self.session_id and isinstance(message, Message) and isinstance(message.text, str):\n self.store_message(message)\n self.message.value = message\n\n self.status = message\n return message\n" + }, + "files": { + "advanced": true, + "display_name": "Files", + "dynamic": false, + "fileTypes": [ + "txt", + "md", + "mdx", + "csv", + "json", + "yaml", + "yml", + "xml", + "html", + "htm", + "pdf", + "docx", + "py", + "sh", + "sql", + "js", + "ts", + "tsx", + "jpg", + "jpeg", + "png", + "bmp", + "image" + ], + "file_path": "", + "info": "Files to be sent with the message.", + "list": true, + "name": "files", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "file", + "value": "" }, "input_value": { "advanced": false, "display_name": "Text", "dynamic": false, - "info": "Text to be passed as output.", - "input_types": ["Message"], + "info": "Message to be passed as input.", + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, + "multiline": true, "name": "input_value", "placeholder": "", "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "sender": { + "advanced": true, + "display_name": "Sender Type", + "dynamic": false, + "info": "Type of sender.", + "name": "sender", + "options": [ + "Machine", + "User" + ], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "User" + }, + "sender_name": { + "advanced": true, + "display_name": "Sender Name", + "dynamic": false, + "info": "Name of the sender.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "name": "sender_name", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "User" + }, + "session_id": { + "advanced": true, + "display_name": "Session ID", + "dynamic": false, + "info": "Session ID for the message.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "name": "session_id", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + } + } + }, + "type": "ChatInput" + }, + "dragging": false, + "height": 308, + "id": "ChatInput-c4xn9", + "position": { + "x": 642.3545710150049, + "y": 220.22556606238678 + }, + "positionAbsolute": { + "x": 642.3545710150049, + "y": 220.22556606238678 + }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { + "data": { + "id": "AstraDB-7nAHJ", + "node": { + "base_classes": [ + "Data", + "Retriever" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Implementation of Vector Store using Astra DB with search capabilities", + "display_name": "Astra DB", + "documentation": "https://python.langchain.com/docs/integrations/vectorstores/astradb", + "edited": false, + "field_order": [ + "collection_name", + "token", + "api_endpoint", + "search_input", + "ingest_data", + "namespace", + "metric", + "batch_size", + "bulk_insert_batch_concurrency", + "bulk_insert_overwrite_concurrency", + "bulk_delete_concurrency", + "setup_mode", + "pre_delete_collection", + "metadata_indexing_include", + "embedding", + "metadata_indexing_exclude", + "collection_indexing_policy", + "search_type", + "number_of_results" + ], + "frozen": false, + "icon": "AstraDB", + "output_types": [], + "outputs": [ + { + "cache": true, + "display_name": "Retriever", + "method": "build_base_retriever", + "name": "base_retriever", + "selected": "Retriever", + "types": [ + "Retriever" + ], + "value": "__UNDEFINED__" + }, + { + "cache": true, + "display_name": "Search Results", + "hidden": false, + "method": "search_documents", + "name": "search_results", + "selected": "Data", + "types": [ + "Data" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "api_endpoint": { + "advanced": false, + "display_name": "API Endpoint", + "dynamic": false, + "info": "API endpoint URL for the Astra DB service.", + "input_types": [], + "load_from_db": false, + "name": "api_endpoint", + "password": true, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "batch_size": { + "advanced": true, + "display_name": "Batch Size", + "dynamic": false, + "info": "Optional number of data to process in a single batch.", + "list": false, + "name": "batch_size", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "int", + "value": "" + }, + "bulk_delete_concurrency": { + "advanced": true, + "display_name": "Bulk Delete Concurrency", + "dynamic": false, + "info": "Optional concurrency level for bulk delete operations.", + "list": false, + "name": "bulk_delete_concurrency", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "int", + "value": "" + }, + "bulk_insert_batch_concurrency": { + "advanced": true, + "display_name": "Bulk Insert Batch Concurrency", + "dynamic": false, + "info": "Optional concurrency level for bulk insert operations.", + "list": false, + "name": "bulk_insert_batch_concurrency", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "int", + "value": "" + }, + "bulk_insert_overwrite_concurrency": { + "advanced": true, + "display_name": "Bulk Insert Overwrite Concurrency", + "dynamic": false, + "info": "Optional concurrency level for bulk insert operations that overwrite existing data.", + "list": false, + "name": "bulk_insert_overwrite_concurrency", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "int", + "value": "" + }, + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from loguru import logger\n\nfrom langflow.base.vectorstores.model import LCVectorStoreComponent\nfrom langflow.io import (\n BoolInput,\n DropdownInput,\n HandleInput,\n IntInput,\n MultilineInput,\n SecretStrInput,\n StrInput,\n DataInput,\n)\nfrom langflow.schema import Data\n\n\nclass AstraVectorStoreComponent(LCVectorStoreComponent):\n display_name: str = \"Astra DB\"\n description: str = \"Implementation of Vector Store using Astra DB with search capabilities\"\n documentation: str = \"https://python.langchain.com/docs/integrations/vectorstores/astradb\"\n icon: str = \"AstraDB\"\n\n inputs = [\n StrInput(\n name=\"collection_name\",\n display_name=\"Collection Name\",\n info=\"The name of the collection within Astra DB where the vectors will be stored.\",\n ),\n SecretStrInput(\n name=\"token\",\n display_name=\"Astra DB Application Token\",\n info=\"Authentication token for accessing Astra DB.\",\n value=\"ASTRA_DB_APPLICATION_TOKEN\",\n ),\n SecretStrInput(\n name=\"api_endpoint\",\n display_name=\"API Endpoint\",\n info=\"API endpoint URL for the Astra DB service.\",\n value=\"ASTRA_DB_API_ENDPOINT\",\n ),\n MultilineInput(\n name=\"search_input\",\n display_name=\"Search Input\",\n ),\n DataInput(\n name=\"ingest_data\",\n display_name=\"Ingest Data\",\n is_list=True,\n ),\n StrInput(\n name=\"namespace\",\n display_name=\"Namespace\",\n info=\"Optional namespace within Astra DB to use for the collection.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"metric\",\n display_name=\"Metric\",\n info=\"Optional distance metric for vector comparisons in the vector store.\",\n options=[\"cosine\", \"dot_product\", \"euclidean\"],\n advanced=True,\n ),\n IntInput(\n name=\"batch_size\",\n display_name=\"Batch Size\",\n info=\"Optional number of data to process in a single batch.\",\n advanced=True,\n ),\n IntInput(\n name=\"bulk_insert_batch_concurrency\",\n display_name=\"Bulk Insert Batch Concurrency\",\n info=\"Optional concurrency level for bulk insert operations.\",\n advanced=True,\n ),\n IntInput(\n name=\"bulk_insert_overwrite_concurrency\",\n display_name=\"Bulk Insert Overwrite Concurrency\",\n info=\"Optional concurrency level for bulk insert operations that overwrite existing data.\",\n advanced=True,\n ),\n IntInput(\n name=\"bulk_delete_concurrency\",\n display_name=\"Bulk Delete Concurrency\",\n info=\"Optional concurrency level for bulk delete operations.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"setup_mode\",\n display_name=\"Setup Mode\",\n info=\"Configuration mode for setting up the vector store, with options like 'Sync', 'Async', or 'Off'.\",\n options=[\"Sync\", \"Async\", \"Off\"],\n advanced=True,\n value=\"Sync\",\n ),\n BoolInput(\n name=\"pre_delete_collection\",\n display_name=\"Pre Delete Collection\",\n info=\"Boolean flag to determine whether to delete the collection before creating a new one.\",\n advanced=True,\n ),\n StrInput(\n name=\"metadata_indexing_include\",\n display_name=\"Metadata Indexing Include\",\n info=\"Optional list of metadata fields to include in the indexing.\",\n advanced=True,\n ),\n HandleInput(\n name=\"embedding\",\n display_name=\"Embedding or Astra Vectorize\",\n input_types=[\"Embeddings\", \"dict\"],\n ),\n StrInput(\n name=\"metadata_indexing_exclude\",\n display_name=\"Metadata Indexing Exclude\",\n info=\"Optional list of metadata fields to exclude from the indexing.\",\n advanced=True,\n ),\n StrInput(\n name=\"collection_indexing_policy\",\n display_name=\"Collection Indexing Policy\",\n info=\"Optional dictionary defining the indexing policy for the collection.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"search_type\",\n display_name=\"Search Type\",\n options=[\"Similarity\", \"MMR\"],\n value=\"Similarity\",\n advanced=True,\n ),\n IntInput(\n name=\"number_of_results\",\n display_name=\"Number of Results\",\n info=\"Number of results to return.\",\n advanced=True,\n value=4,\n ),\n ]\n\n def build_vector_store(self):\n try:\n from langchain_astradb import AstraDBVectorStore\n from langchain_astradb.utils.astradb import SetupMode\n except ImportError:\n raise ImportError(\n \"Could not import langchain Astra DB integration package. \"\n \"Please install it with `pip install langchain-astradb`.\"\n )\n\n try:\n if not self.setup_mode:\n self.setup_mode = self._inputs[\"setup_mode\"].options[0]\n\n setup_mode_value = SetupMode[self.setup_mode.upper()]\n except KeyError:\n raise ValueError(f\"Invalid setup mode: {self.setup_mode}\")\n\n if not isinstance(self.embedding, dict):\n embedding_dict = {\"embedding\": self.embedding}\n else:\n from astrapy.info import CollectionVectorServiceOptions\n\n dict_options = self.embedding.get(\"collection_vector_service_options\", {})\n dict_options[\"authentication\"] = {\n k: v for k, v in dict_options.get(\"authentication\", {}).items() if k and v\n }\n dict_options[\"parameters\"] = {k: v for k, v in dict_options.get(\"parameters\", {}).items() if k and v}\n embedding_dict = {\n \"collection_vector_service_options\": CollectionVectorServiceOptions.from_dict(dict_options),\n \"collection_embedding_api_key\": self.embedding.get(\"collection_embedding_api_key\"),\n }\n vector_store_kwargs = {\n **embedding_dict,\n \"collection_name\": self.collection_name,\n \"token\": self.token,\n \"api_endpoint\": self.api_endpoint,\n \"namespace\": self.namespace or None,\n \"metric\": self.metric or None,\n \"batch_size\": self.batch_size or None,\n \"bulk_insert_batch_concurrency\": self.bulk_insert_batch_concurrency or None,\n \"bulk_insert_overwrite_concurrency\": self.bulk_insert_overwrite_concurrency or None,\n \"bulk_delete_concurrency\": self.bulk_delete_concurrency or None,\n \"setup_mode\": setup_mode_value,\n \"pre_delete_collection\": self.pre_delete_collection or False,\n }\n\n if self.metadata_indexing_include:\n vector_store_kwargs[\"metadata_indexing_include\"] = self.metadata_indexing_include\n elif self.metadata_indexing_exclude:\n vector_store_kwargs[\"metadata_indexing_exclude\"] = self.metadata_indexing_exclude\n elif self.collection_indexing_policy:\n vector_store_kwargs[\"collection_indexing_policy\"] = self.collection_indexing_policy\n\n try:\n vector_store = AstraDBVectorStore(**vector_store_kwargs)\n except Exception as e:\n raise ValueError(f\"Error initializing AstraDBVectorStore: {str(e)}\") from e\n\n self.status = self._astradb_collection_to_data(vector_store.collection)\n return vector_store\n\n def _add_documents_to_vector_store(self, vector_store):\n documents = []\n for _input in self.ingest_data or []:\n if isinstance(_input, Data):\n documents.append(_input.to_lc_document())\n else:\n raise ValueError(\"Vector Store Inputs must be Data objects.\")\n\n if documents and self.embedding is not None:\n logger.debug(f\"Adding {len(documents)} documents to the Vector Store.\")\n try:\n vector_store.add_documents(documents)\n except Exception as e:\n raise ValueError(f\"Error adding documents to AstraDBVectorStore: {str(e)}\") from e\n else:\n logger.debug(\"No documents to add to the Vector Store.\")\n\n def search_documents(self):\n vector_store = self.build_vector_store()\n\n logger.debug(f\"Search input: {self.search_input}\")\n logger.debug(f\"Search type: {self.search_type}\")\n logger.debug(f\"Number of results: {self.number_of_results}\")\n\n if self.search_input and isinstance(self.search_input, str) and self.search_input.strip():\n try:\n if self.search_type == \"Similarity\":\n docs = vector_store.similarity_search(\n query=self.search_input,\n k=self.number_of_results,\n )\n elif self.search_type == \"MMR\":\n docs = vector_store.max_marginal_relevance_search(\n query=self.search_input,\n k=self.number_of_results,\n )\n else:\n raise ValueError(f\"Invalid search type: {self.search_type}\")\n except Exception as e:\n raise ValueError(f\"Error performing search in AstraDBVectorStore: {str(e)}\") from e\n\n logger.debug(f\"Retrieved documents: {len(docs)}\")\n\n data = [Data.from_document(doc) for doc in docs]\n logger.debug(f\"Converted documents to data: {len(data)}\")\n self.status = data\n return data\n else:\n logger.debug(\"No search input provided. Skipping search.\")\n return []\n\n def _astradb_collection_to_data(self, collection):\n data = []\n data_dict = collection.find()\n if data_dict and \"data\" in data_dict:\n data_dict = data_dict[\"data\"].get(\"documents\", [])\n\n for item in data_dict:\n data.append(Data(content=item[\"content\"]))\n return data\n" + }, + "collection_indexing_policy": { + "advanced": true, + "display_name": "Collection Indexing Policy", + "dynamic": false, + "info": "Optional dictionary defining the indexing policy for the collection.", + "list": false, + "load_from_db": false, + "name": "collection_indexing_policy", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "collection_name": { + "advanced": false, + "display_name": "Collection Name", + "dynamic": false, + "info": "The name of the collection within Astra DB where the vectors will be stored.", + "list": false, + "load_from_db": false, + "name": "collection_name", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "langflow" + }, + "embedding": { + "advanced": false, + "display_name": "Embedding or Astra Vectorize", + "dynamic": false, + "info": "", + "input_types": [ + "Embeddings", + "dict" + ], + "list": false, + "name": "embedding", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "other", + "value": "" + }, + "ingest_data": { + "advanced": false, + "display_name": "Ingest Data", + "dynamic": false, + "info": "", + "input_types": [ + "Data" + ], + "list": true, + "name": "ingest_data", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "other", + "value": "" + }, + "metadata_indexing_exclude": { + "advanced": true, + "display_name": "Metadata Indexing Exclude", + "dynamic": false, + "info": "Optional list of metadata fields to exclude from the indexing.", + "list": false, + "load_from_db": false, + "name": "metadata_indexing_exclude", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "metadata_indexing_include": { + "advanced": true, + "display_name": "Metadata Indexing Include", + "dynamic": false, + "info": "Optional list of metadata fields to include in the indexing.", + "list": false, + "load_from_db": false, + "name": "metadata_indexing_include", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "metric": { + "advanced": true, + "display_name": "Metric", + "dynamic": false, + "info": "Optional distance metric for vector comparisons in the vector store.", + "name": "metric", + "options": [ + "cosine", + "dot_product", + "euclidean" + ], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "namespace": { + "advanced": true, + "display_name": "Namespace", + "dynamic": false, + "info": "Optional namespace within Astra DB to use for the collection.", + "list": false, + "load_from_db": false, + "name": "namespace", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "number_of_results": { + "advanced": true, + "display_name": "Number of Results", + "dynamic": false, + "info": "Number of results to return.", + "list": false, + "name": "number_of_results", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "int", + "value": 4 + }, + "pre_delete_collection": { + "advanced": true, + "display_name": "Pre Delete Collection", + "dynamic": false, + "info": "Boolean flag to determine whether to delete the collection before creating a new one.", + "list": false, + "name": "pre_delete_collection", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "bool", + "value": false + }, + "search_input": { + "advanced": false, + "display_name": "Search Input", + "dynamic": false, + "info": "", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "search_input", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "search_type": { + "advanced": true, + "display_name": "Search Type", + "dynamic": false, + "info": "", + "name": "search_type", + "options": [ + "Similarity", + "MMR" + ], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "Similarity" + }, + "setup_mode": { + "advanced": true, + "display_name": "Setup Mode", + "dynamic": false, + "info": "Configuration mode for setting up the vector store, with options like 'Sync', 'Async', or 'Off'.", + "name": "setup_mode", + "options": [ + "Sync", + "Async", + "Off" + ], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "Sync" + }, + "token": { + "advanced": false, + "display_name": "Astra DB Application Token", + "dynamic": false, + "info": "Authentication token for accessing Astra DB.", + "input_types": [], + "load_from_db": false, + "name": "token", + "password": true, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, "type": "str", "value": "" } } }, - "type": "TextOutput" + "type": "AstraDB" }, "dragging": false, - "height": 309, - "id": "TextOutput-rT1Fj", + "height": 753, + "id": "AstraDB-7nAHJ", "position": { - "x": 2439.792450398153, - "y": 661.149562774499 + "x": 1246.0381406498648, + "y": 333.25157075413966 }, "positionAbsolute": { - "x": 2439.792450398153, - "y": 661.149562774499 + "x": 1246.0381406498648, + "y": 333.25157075413966 }, "selected": false, "type": "genericNode", @@ -497,39 +878,40 @@ }, { "data": { - "id": "OpenAIEmbeddings-HsV7O", + "id": "OpenAIEmbeddings-BKXc6", "node": { - "base_classes": ["Embeddings"], + "base_classes": [ + "Embeddings" + ], "beta": false, - "custom_fields": { - "allowed_special": null, - "chunk_size": null, - "client": null, - "default_headers": null, - "default_query": null, - "deployment": null, - "disallowed_special": null, - "embedding_ctx_length": null, - "max_retries": null, - "model": null, - "model_kwargs": null, - "openai_api_base": null, - "openai_api_key": null, - "openai_api_type": null, - "openai_api_version": null, - "openai_organization": null, - "openai_proxy": null, - "request_timeout": null, - "show_progress_bar": null, - "skip_empty": null, - "tiktoken_enable": null, - "tiktoken_model_name": null - }, + "conditional_paths": [], + "custom_fields": {}, "description": "Generate embeddings using OpenAI models.", "display_name": "OpenAI Embeddings", "documentation": "", - "field_formatters": {}, - "field_order": [], + "edited": false, + "field_order": [ + "default_headers", + "default_query", + "chunk_size", + "client", + "deployment", + "embedding_ctx_length", + "max_retries", + "model", + "model_kwargs", + "openai_api_base", + "openai_api_key", + "openai_api_type", + "openai_api_version", + "openai_organization", + "openai_proxy", + "request_timeout", + "show_progress_bar", + "skip_empty", + "tiktoken_model_name", + "tiktoken_enable" + ], "frozen": false, "icon": "OpenAI", "output_types": [], @@ -537,13 +919,17 @@ { "cache": true, "display_name": "Embeddings", + "hidden": false, "method": "build_embeddings", "name": "embeddings", "selected": "Embeddings", - "types": ["Embeddings"], + "types": [ + "Embeddings" + ], "value": "__UNDEFINED__" } ], + "pinned": false, "template": { "_type": "Component", "chunk_size": { @@ -557,6 +943,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "int", "value": 1000 }, @@ -565,7 +952,9 @@ "display_name": "Client", "dynamic": false, "info": "", - "input_types": ["Message", "str"], + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, "name": "client", @@ -573,6 +962,8 @@ "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" }, @@ -592,7 +983,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langchain_openai.embeddings.base import OpenAIEmbeddings\n\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.field_typing import Embeddings\nfrom langflow.io import BoolInput, DictInput, DropdownInput, FloatInput, IntInput, Output, SecretStrInput, TextInput\n\n\nclass OpenAIEmbeddingsComponent(LCModelComponent):\n display_name = \"OpenAI Embeddings\"\n description = \"Generate embeddings using OpenAI models.\"\n icon = \"OpenAI\"\n inputs = [\n DictInput(\n name=\"default_headers\",\n display_name=\"Default Headers\",\n advanced=True,\n info=\"Default headers to use for the API request.\",\n ),\n DictInput(\n name=\"default_query\",\n display_name=\"Default Query\",\n advanced=True,\n info=\"Default query parameters to use for the API request.\",\n ),\n IntInput(name=\"chunk_size\", display_name=\"Chunk Size\", advanced=True, value=1000),\n TextInput(name=\"client\", display_name=\"Client\", advanced=True),\n TextInput(name=\"deployment\", display_name=\"Deployment\", advanced=True),\n IntInput(name=\"embedding_ctx_length\", display_name=\"Embedding Context Length\", advanced=True, value=1536),\n IntInput(name=\"max_retries\", display_name=\"Max Retries\", value=3, advanced=True),\n DropdownInput(\n name=\"model\",\n display_name=\"Model\",\n advanced=False,\n options=[\n \"text-embedding-3-small\",\n \"text-embedding-3-large\",\n \"text-embedding-ada-002\",\n ],\n value=\"text-embedding-3-small\",\n ),\n DictInput(name=\"model_kwargs\", display_name=\"Model Kwargs\", advanced=True),\n SecretStrInput(name=\"openai_api_base\", display_name=\"OpenAI API Base\", advanced=True),\n SecretStrInput(name=\"openai_api_key\", display_name=\"OpenAI API Key\"),\n SecretStrInput(name=\"openai_api_type\", display_name=\"OpenAI API Type\", advanced=True),\n TextInput(name=\"openai_api_version\", display_name=\"OpenAI API Version\", advanced=True),\n TextInput(\n name=\"openai_organization\",\n display_name=\"OpenAI Organization\",\n advanced=True,\n ),\n TextInput(name=\"openai_proxy\", display_name=\"OpenAI Proxy\", advanced=True),\n FloatInput(name=\"request_timeout\", display_name=\"Request Timeout\", advanced=True),\n BoolInput(name=\"show_progress_bar\", display_name=\"Show Progress Bar\", advanced=True),\n BoolInput(name=\"skip_empty\", display_name=\"Skip Empty\", advanced=True),\n TextInput(\n name=\"tiktoken_model_name\",\n display_name=\"TikToken Model Name\",\n advanced=True,\n ),\n BoolInput(\n name=\"tiktoken_enable\",\n display_name=\"TikToken Enable\",\n advanced=True,\n value=True,\n info=\"If False, you must have transformers installed.\",\n ),\n ]\n\n outputs = [\n Output(display_name=\"Embeddings\", name=\"embeddings\", method=\"build_embeddings\"),\n ]\n\n def build_embeddings(self) -> Embeddings:\n return OpenAIEmbeddings(\n tiktoken_enabled=self.tiktoken_enable,\n default_headers=self.default_headers,\n default_query=self.default_query,\n allowed_special=\"all\",\n disallowed_special=\"all\",\n chunk_size=self.chunk_size,\n deployment=self.deployment,\n embedding_ctx_length=self.embedding_ctx_length,\n max_retries=self.max_retries,\n model=self.model,\n model_kwargs=self.model_kwargs,\n base_url=self.openai_api_base,\n api_key=self.openai_api_key,\n openai_api_type=self.openai_api_type,\n api_version=self.openai_api_version,\n organization=self.openai_organization,\n openai_proxy=self.openai_proxy,\n timeout=self.request_timeout or None,\n show_progress_bar=self.show_progress_bar,\n skip_empty=self.skip_empty,\n tiktoken_model_name=self.tiktoken_model_name,\n )\n" + "value": "from langchain_openai.embeddings.base import OpenAIEmbeddings\n\nfrom langflow.base.embeddings.model import LCEmbeddingsModel\nfrom langflow.field_typing import Embeddings\nfrom langflow.io import BoolInput, DictInput, DropdownInput, FloatInput, IntInput, MessageTextInput, SecretStrInput\n\n\nclass OpenAIEmbeddingsComponent(LCEmbeddingsModel):\n display_name = \"OpenAI Embeddings\"\n description = \"Generate embeddings using OpenAI models.\"\n icon = \"OpenAI\"\n inputs = [\n DictInput(\n name=\"default_headers\",\n display_name=\"Default Headers\",\n advanced=True,\n info=\"Default headers to use for the API request.\",\n ),\n DictInput(\n name=\"default_query\",\n display_name=\"Default Query\",\n advanced=True,\n info=\"Default query parameters to use for the API request.\",\n ),\n IntInput(name=\"chunk_size\", display_name=\"Chunk Size\", advanced=True, value=1000),\n MessageTextInput(name=\"client\", display_name=\"Client\", advanced=True),\n MessageTextInput(name=\"deployment\", display_name=\"Deployment\", advanced=True),\n IntInput(name=\"embedding_ctx_length\", display_name=\"Embedding Context Length\", advanced=True, value=1536),\n IntInput(name=\"max_retries\", display_name=\"Max Retries\", value=3, advanced=True),\n DropdownInput(\n name=\"model\",\n display_name=\"Model\",\n advanced=False,\n options=[\n \"text-embedding-3-small\",\n \"text-embedding-3-large\",\n \"text-embedding-ada-002\",\n ],\n value=\"text-embedding-3-small\",\n ),\n DictInput(name=\"model_kwargs\", display_name=\"Model Kwargs\", advanced=True),\n SecretStrInput(name=\"openai_api_base\", display_name=\"OpenAI API Base\", advanced=True),\n SecretStrInput(name=\"openai_api_key\", display_name=\"OpenAI API Key\"),\n SecretStrInput(name=\"openai_api_type\", display_name=\"OpenAI API Type\", advanced=True),\n MessageTextInput(name=\"openai_api_version\", display_name=\"OpenAI API Version\", advanced=True),\n MessageTextInput(\n name=\"openai_organization\",\n display_name=\"OpenAI Organization\",\n advanced=True,\n ),\n MessageTextInput(name=\"openai_proxy\", display_name=\"OpenAI Proxy\", advanced=True),\n FloatInput(name=\"request_timeout\", display_name=\"Request Timeout\", advanced=True),\n BoolInput(name=\"show_progress_bar\", display_name=\"Show Progress Bar\", advanced=True),\n BoolInput(name=\"skip_empty\", display_name=\"Skip Empty\", advanced=True),\n MessageTextInput(\n name=\"tiktoken_model_name\",\n display_name=\"TikToken Model Name\",\n advanced=True,\n ),\n BoolInput(\n name=\"tiktoken_enable\",\n display_name=\"TikToken Enable\",\n advanced=True,\n value=True,\n info=\"If False, you must have transformers installed.\",\n ),\n ]\n\n def build_embeddings(self) -> Embeddings:\n return OpenAIEmbeddings(\n tiktoken_enabled=self.tiktoken_enable,\n default_headers=self.default_headers,\n default_query=self.default_query,\n allowed_special=\"all\",\n disallowed_special=\"all\",\n chunk_size=self.chunk_size,\n deployment=self.deployment,\n embedding_ctx_length=self.embedding_ctx_length,\n max_retries=self.max_retries,\n model=self.model,\n model_kwargs=self.model_kwargs,\n base_url=self.openai_api_base,\n api_key=self.openai_api_key,\n openai_api_type=self.openai_api_type,\n api_version=self.openai_api_version,\n organization=self.openai_organization,\n openai_proxy=self.openai_proxy,\n timeout=self.request_timeout or None,\n show_progress_bar=self.show_progress_bar,\n skip_empty=self.skip_empty,\n tiktoken_model_name=self.tiktoken_model_name,\n )\n" }, "default_headers": { "advanced": true, @@ -605,6 +996,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_input": true, "type": "dict", "value": {} }, @@ -619,6 +1011,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_input": true, "type": "dict", "value": {} }, @@ -627,7 +1020,9 @@ "display_name": "Deployment", "dynamic": false, "info": "", - "input_types": ["Message", "str"], + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, "name": "deployment", @@ -635,6 +1030,8 @@ "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" }, @@ -649,6 +1046,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "int", "value": 1536 }, @@ -663,6 +1061,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "int", "value": 3 }, @@ -681,6 +1080,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "str", "value": "text-embedding-3-small" }, @@ -695,6 +1095,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_input": true, "type": "dict", "value": {} }, @@ -720,7 +1121,7 @@ "dynamic": false, "info": "", "input_types": [], - "load_from_db": true, + "load_from_db": false, "name": "openai_api_key", "password": true, "placeholder": "", @@ -728,7 +1129,7 @@ "show": true, "title_case": false, "type": "str", - "value": "OPENAI_API_KEY" + "value": "" }, "openai_api_type": { "advanced": true, @@ -751,7 +1152,9 @@ "display_name": "OpenAI API Version", "dynamic": false, "info": "", - "input_types": ["Message", "str"], + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, "name": "openai_api_version", @@ -759,6 +1162,8 @@ "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" }, @@ -767,7 +1172,9 @@ "display_name": "OpenAI Organization", "dynamic": false, "info": "", - "input_types": ["Message", "str"], + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, "name": "openai_organization", @@ -775,6 +1182,8 @@ "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" }, @@ -783,7 +1192,9 @@ "display_name": "OpenAI Proxy", "dynamic": false, "info": "", - "input_types": ["Message", "str"], + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, "name": "openai_proxy", @@ -791,6 +1202,8 @@ "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" }, @@ -805,6 +1218,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "float", "value": "" }, @@ -819,6 +1233,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "bool", "value": false }, @@ -833,6 +1248,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "bool", "value": false }, @@ -847,6 +1263,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "bool", "value": true }, @@ -855,7 +1272,9 @@ "display_name": "TikToken Model Name", "dynamic": false, "info": "", - "input_types": ["Message", "str"], + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, "name": "tiktoken_model_name", @@ -863,6 +1282,8 @@ "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" } @@ -871,15 +1292,15 @@ "type": "OpenAIEmbeddings" }, "dragging": false, - "height": 395, - "id": "OpenAIEmbeddings-HsV7O", + "height": 394, + "id": "OpenAIEmbeddings-BKXc6", "position": { - "x": 690.5967478991026, - "y": 597.6680004855787 + "x": 603.2488770584523, + "y": 661.6162066128852 }, "positionAbsolute": { - "x": 690.5967478991026, - "y": 597.6680004855787 + "x": 603.2488770584523, + "y": 661.6162066128852 }, "selected": false, "type": "genericNode", @@ -887,318 +1308,37 @@ }, { "data": { - "id": "OpenAIModel-PKrw7", + "id": "ParseData-d61Q0", "node": { - "base_classes": ["object", "Text", "str"], + "base_classes": [ + "Message" + ], "beta": false, - "custom_fields": { - "input_value": null, - "max_tokens": null, - "model_kwargs": null, - "model_name": null, - "openai_api_base": null, - "openai_api_key": null, - "stream": null, - "system_message": null, - "temperature": null - }, - "description": "Generates text using OpenAI LLMs.", - "display_name": "OpenAI", + "conditional_paths": [], + "custom_fields": {}, + "description": "Convert Data into plain text following a specified template.", + "display_name": "Parse Data", "documentation": "", - "field_formatters": {}, + "edited": false, "field_order": [ - "max_tokens", - "model_kwargs", - "model_name", - "openai_api_base", - "openai_api_key", - "temperature", - "input_value", - "system_message", - "stream" + "data", + "template", + "sep" ], "frozen": false, - "icon": "OpenAI", + "icon": "braces", "output_types": [], "outputs": [ { "cache": true, "display_name": "Text", - "method": "text_response", - "name": "text_output", + "hidden": false, + "method": "parse_data", + "name": "text", "selected": "Message", - "types": ["Message"], - "value": "__UNDEFINED__" - }, - { - "cache": true, - "display_name": "Language Model", - "method": "build_model", - "name": "model_output", - "selected": "BaseLanguageModel", - "types": ["BaseLanguageModel"], - "value": "__UNDEFINED__" - } - ], - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "import operator\nfrom functools import reduce\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import BaseLanguageModel\nfrom langflow.inputs import (\n BoolInput,\n DictInput,\n DropdownInput,\n FloatInput,\n IntInput,\n MessageInput,\n SecretStrInput,\n StrInput,\n)\nfrom langflow.schema.message import Message\nfrom langflow.template import Output\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n inputs = [\n MessageInput(name=\"input_value\", display_name=\"Input\"),\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n info=\"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n ),\n DictInput(name=\"model_kwargs\", display_name=\"Model Kwargs\", advanced=True),\n DictInput(\n name=\"output_schema\",\n is_list=True,\n display_name=\"Schema\",\n advanced=True,\n info=\"The schema for the Output of the model. You must pass the word JSON in the prompt. If left blank, JSON mode will be disabled.\",\n ),\n DropdownInput(\n name=\"model_name\", display_name=\"Model Name\", advanced=False, options=MODEL_NAMES, value=MODEL_NAMES[0]\n ),\n StrInput(\n name=\"openai_api_base\",\n display_name=\"OpenAI API Base\",\n advanced=True,\n info=\"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.\",\n ),\n SecretStrInput(\n name=\"openai_api_key\",\n display_name=\"OpenAI API Key\",\n info=\"The OpenAI API Key to use for the OpenAI model.\",\n advanced=False,\n value=\"OPENAI_API_KEY\",\n ),\n FloatInput(name=\"temperature\", display_name=\"Temperature\", value=0.1),\n BoolInput(name=\"stream\", display_name=\"Stream\", info=STREAM_INFO_TEXT, advanced=True),\n StrInput(\n name=\"system_message\",\n display_name=\"System Message\",\n info=\"System message to pass to the model.\",\n advanced=True,\n ),\n IntInput(\n name=\"seed\",\n display_name=\"Seed\",\n info=\"The seed controls the reproducibility of the job.\",\n advanced=True,\n value=1,\n ),\n ]\n outputs = [\n Output(display_name=\"Text\", name=\"text_output\", method=\"text_response\"),\n Output(display_name=\"Language Model\", name=\"model_output\", method=\"build_model\"),\n ]\n\n def text_response(self) -> Message:\n input_value = self.input_value\n stream = self.stream\n system_message = self.system_message\n output = self.build_model()\n result = self.get_chat_result(output, stream, input_value, system_message)\n self.status = result\n return result\n\n def build_model(self) -> BaseLanguageModel:\n # self.output_schea is a list of dictionaries\n # let's convert it to a dictionary\n output_schema_dict = reduce(operator.ior, self.output_schema or {}, {})\n openai_api_key = self.openai_api_key\n temperature = self.temperature\n model_name = self.model_name\n max_tokens = self.max_tokens\n model_kwargs = self.model_kwargs\n openai_api_base = self.openai_api_base or \"https://api.openai.com/v1\"\n json_mode = bool(output_schema_dict)\n seed = self.seed\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs or {},\n model=model_name or None,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature or 0.1,\n seed=seed,\n )\n if json_mode:\n output = output.with_structured_output(schema=output_schema_dict, method=\"json_mode\")\n\n return output\n" - }, - "input_value": { - "advanced": false, - "display_name": "Input", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": ["Message"], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "input_value", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "max_tokens": { - "advanced": true, - "display_name": "Max Tokens", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "input_types": ["Text"], - "list": false, - "load_from_db": false, - "multiline": false, - "name": "max_tokens", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "model_kwargs": { - "advanced": true, - "display_name": "Model Kwargs", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": ["Text"], - "list": false, - "load_from_db": false, - "multiline": false, - "name": "model_kwargs", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "model_name": { - "advanced": false, - "display_name": "Model Name", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": ["Text"], - "list": true, - "load_from_db": false, - "multiline": false, - "name": "model_name", - "options": [ - "gpt-4o", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125" + "types": [ + "Message" ], - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "gpt-3.5-turbo" - }, - "openai_api_base": { - "advanced": true, - "display_name": "OpenAI API Base", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", - "input_types": ["Text"], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "openai_api_base", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "openai_api_key": { - "advanced": false, - "display_name": "OpenAI API Key", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "The OpenAI API Key to use for the OpenAI model.", - "input_types": [], - "list": false, - "load_from_db": true, - "multiline": false, - "name": "openai_api_key", - "password": true, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "OPENAI_API_KEY" - }, - "stream": { - "advanced": true, - "display_name": "Stream", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Stream the response from the model. Streaming works only in Chat.", - "input_types": ["Text"], - "list": false, - "load_from_db": false, - "multiline": false, - "name": "stream", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": false - }, - "system_message": { - "advanced": true, - "display_name": "System Message", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "System message to pass to the model.", - "input_types": ["Text"], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "system_message", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "temperature": { - "advanced": false, - "display_name": "Temperature", - "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": ["Text"], - "list": false, - "load_from_db": false, - "multiline": false, - "name": "temperature", - "password": false, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": 0.1 - } - } - }, - "type": "OpenAIModel" - }, - "dragging": false, - "height": 639, - "id": "OpenAIModel-PKrw7", - "position": { - "x": 3410.117202077183, - "y": 431.2038048137648 - }, - "positionAbsolute": { - "x": 3410.117202077183, - "y": 431.2038048137648 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt", - "id": "Prompt-VecUe", - "node": { - "base_classes": ["object", "str", "Text"], - "beta": false, - "conditional_paths": [], - "custom_fields": { - "template": ["context", "question"] - }, - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt", - "documentation": "", - "error": null, - "field_order": [], - "frozen": false, - "full_path": null, - "icon": "prompts", - "is_composition": null, - "is_input": null, - "is_output": null, - "name": "", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Prompt Message", - "method": "build_prompt", - "name": "prompt", - "selected": "Message", - "types": ["Message"], "value": "__UNDEFINED__" } ], @@ -1221,7 +1361,150 @@ "show": true, "title_case": false, "type": "code", - "value": "from langflow.custom import Component\nfrom langflow.io import Output, PromptInput\nfrom langflow.schema.message import Message\n\n\nclass PromptComponent(Component):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n prompt = await Message.from_template_and_variables(**self._arguments)\n self.status = prompt.text\n return prompt\n" + "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Parse Data\"\n description = \"Convert Data into plain text following a specified template.\"\n icon = \"braces\"\n\n inputs = [\n DataInput(name=\"data\", display_name=\"Data\", info=\"The data to convert to text.\"),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(display_name=\"Text\", name=\"text\", method=\"parse_data\"),\n ]\n\n def parse_data(self) -> Message:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n\n result_string = data_to_text(template, data, sep=self.sep)\n self.status = result_string\n return Message(text=result_string)\n" + }, + "data": { + "advanced": false, + "display_name": "Data", + "dynamic": false, + "info": "The data to convert to text.", + "input_types": [ + "Data" + ], + "list": false, + "name": "data", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "other", + "value": "" + }, + "sep": { + "advanced": true, + "display_name": "Separator", + "dynamic": false, + "info": "", + "list": false, + "load_from_db": false, + "name": "sep", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "\n" + }, + "template": { + "advanced": false, + "display_name": "Template", + "dynamic": false, + "info": "The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "template", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "{text}" + } + } + }, + "type": "ParseData" + }, + "dragging": false, + "height": 384, + "id": "ParseData-d61Q0", + "position": { + "x": 1854.1518317915907, + "y": 459.3386924128532 + }, + "positionAbsolute": { + "x": 1854.1518317915907, + "y": 459.3386924128532 + }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { + "data": { + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt", + "id": "Prompt-vqAlG", + "node": { + "base_classes": [ + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": { + "template": [ + "context", + "question" + ] + }, + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt", + "documentation": "", + "edited": false, + "error": null, + "field_order": [ + "template" + ], + "frozen": false, + "full_path": null, + "icon": "prompts", + "is_composition": null, + "is_input": null, + "is_output": null, + "name": "", + "output_types": [], + "outputs": [ + { + "cache": true, + "display_name": "Prompt Message", + "hidden": false, + "method": "build_prompt", + "name": "prompt", + "selected": "Message", + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "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.io import 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\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n prompt = await Message.from_template_and_variables(**self._attributes)\n self.status = prompt.text\n return prompt\n\n def post_code_processing(self, new_build_config: dict, current_build_config: dict):\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(new_build_config, current_build_config)\n template = frontend_node[\"template\"][\"template\"][\"value\"]\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_build_config\n # and update the frontend_node with those values\n update_template_values(frontend_template=frontend_node, raw_template=current_build_config[\"template\"])\n return frontend_node\n" }, "context": { "advanced": false, @@ -1231,7 +1514,10 @@ "fileTypes": [], "file_path": "", "info": "", - "input_types": ["Message", "Text"], + "input_types": [ + "Message", + "Text" + ], "list": false, "load_from_db": false, "multiline": true, @@ -1252,7 +1538,10 @@ "fileTypes": [], "file_path": "", "info": "", - "input_types": ["Message", "Text"], + "input_types": [ + "Message", + "Text" + ], "list": false, "load_from_db": false, "multiline": true, @@ -1269,19 +1558,14 @@ "advanced": false, "display_name": "Template", "dynamic": false, - "fileTypes": [], - "file_path": "", "info": "", - "input_types": ["Text"], "list": false, - "load_from_db": false, - "multiline": false, "name": "template", - "password": false, "placeholder": "", "required": false, "show": true, "title_case": false, + "trace_as_input": true, "type": "prompt", "value": "{context}\n\n---\n\nGiven the context above, answer the question as best as possible.\n\nQuestion: {question}\n\nAnswer: " } @@ -1290,15 +1574,15 @@ "type": "Prompt" }, "dragging": false, - "height": 525, - "id": "Prompt-VecUe", + "height": 515, + "id": "Prompt-vqAlG", "position": { - "x": 2941.2776396951576, - "y": 446.43037366459487 + "x": 2486.0988668404975, + "y": 496.5120474157301 }, "positionAbsolute": { - "x": 2941.2776396951576, - "y": 446.43037366459487 + "x": 2486.0988668404975, + "y": 496.5120474157301 }, "selected": false, "type": "genericNode", @@ -1306,37 +1590,61 @@ }, { "data": { - "id": "ChatOutput-nUD9B", + "id": "OpenAIModel-ybL3k", "node": { - "base_classes": ["object", "Text", "Record", "str"], + "base_classes": [ + "LanguageModel", + "Message" + ], "beta": false, - "custom_fields": { - "input_value": null, - "record_template": null, - "return_record": null, - "sender": null, - "sender_name": null, - "session_id": null - }, - "description": "Display a chat message in the Playground.", - "display_name": "Chat Output", + "conditional_paths": [], + "custom_fields": {}, + "description": "Generates text using OpenAI LLMs.", + "display_name": "OpenAI", "documentation": "", - "field_formatters": {}, - "field_order": [], + "edited": false, + "field_order": [ + "input_value", + "max_tokens", + "model_kwargs", + "output_schema", + "model_name", + "openai_api_base", + "openai_api_key", + "temperature", + "stream", + "system_message", + "seed" + ], "frozen": false, - "icon": "ChatOutput", + "icon": "OpenAI", "output_types": [], "outputs": [ { "cache": true, - "display_name": "Message", - "method": "message_response", - "name": "message", + "display_name": "Text", + "hidden": false, + "method": "text_response", + "name": "text_output", "selected": "Message", - "types": ["Message"], + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + }, + { + "cache": true, + "display_name": "Language Model", + "method": "build_model", + "name": "model_output", + "selected": "LanguageModel", + "types": [ + "LanguageModel" + ], "value": "__UNDEFINED__" } ], + "pinned": false, "template": { "_type": "Component", "code": { @@ -1355,21 +1663,104 @@ "show": true, "title_case": false, "type": "code", - "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.io import DropdownInput, Output, TextInput\nfrom langflow.schema.message import Message\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n inputs = [\n TextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\"],\n value=\"Machine\",\n advanced=True,\n info=\"Type of sender.\",\n ),\n TextInput(\n name=\"sender_name\", display_name=\"Sender Name\", info=\"Name of the sender.\", value=\"AI\", advanced=True\n ),\n TextInput(name=\"session_id\", display_name=\"Session ID\", info=\"Session ID for the message.\", advanced=True),\n TextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n )\n if self.session_id and isinstance(message, Message) and isinstance(message.text, str):\n self.store_message(message)\n self.message.value = message\n\n self.status = message\n return message\n" + "value": "import operator\nfrom functools import reduce\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\nfrom langflow.field_typing import LanguageModel\nfrom langflow.inputs import (\n BoolInput,\n DictInput,\n DropdownInput,\n FloatInput,\n IntInput,\n MessageInput,\n SecretStrInput,\n StrInput,\n)\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n inputs = [\n MessageInput(name=\"input_value\", display_name=\"Input\"),\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n info=\"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n ),\n DictInput(name=\"model_kwargs\", display_name=\"Model Kwargs\", advanced=True),\n DictInput(\n name=\"output_schema\",\n is_list=True,\n display_name=\"Schema\",\n advanced=True,\n info=\"The schema for the Output of the model. You must pass the word JSON in the prompt. If left blank, JSON mode will be disabled.\",\n ),\n DropdownInput(\n name=\"model_name\", display_name=\"Model Name\", advanced=False, options=MODEL_NAMES, value=MODEL_NAMES[0]\n ),\n StrInput(\n name=\"openai_api_base\",\n display_name=\"OpenAI API Base\",\n advanced=True,\n info=\"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.\",\n ),\n SecretStrInput(\n name=\"openai_api_key\",\n display_name=\"OpenAI API Key\",\n info=\"The OpenAI API Key to use for the OpenAI model.\",\n advanced=False,\n value=\"OPENAI_API_KEY\",\n ),\n FloatInput(name=\"temperature\", display_name=\"Temperature\", value=0.1),\n BoolInput(name=\"stream\", display_name=\"Stream\", info=STREAM_INFO_TEXT, advanced=True),\n StrInput(\n name=\"system_message\",\n display_name=\"System Message\",\n info=\"System message to pass to the model.\",\n advanced=True,\n ),\n IntInput(\n name=\"seed\",\n display_name=\"Seed\",\n info=\"The seed controls the reproducibility of the job.\",\n advanced=True,\n value=1,\n ),\n ]\n\n def build_model(self) -> LanguageModel:\n # self.output_schea is a list of dictionaries\n # let's convert it to a dictionary\n output_schema_dict: dict[str, str] = reduce(operator.ior, self.output_schema or {}, {})\n openai_api_key = self.openai_api_key\n temperature = self.temperature\n model_name: str = self.model_name\n max_tokens = self.max_tokens\n model_kwargs = self.model_kwargs or {}\n openai_api_base = self.openai_api_base or \"https://api.openai.com/v1\"\n json_mode = bool(output_schema_dict)\n seed = self.seed\n model_kwargs[\"seed\"] = seed\n\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature or 0.1,\n )\n if json_mode:\n output = output.with_structured_output(schema=output_schema_dict, method=\"json_mode\") # type: ignore\n\n return output\n\n def _get_exception_message(self, e: Exception):\n \"\"\"\n Get a message from an OpenAI exception.\n\n Args:\n exception (Exception): The exception to get the message from.\n\n Returns:\n str: The message from the exception.\n \"\"\"\n\n try:\n from openai import BadRequestError\n except ImportError:\n return\n if isinstance(e, BadRequestError):\n message = e.body.get(\"message\") # type: ignore\n if message:\n return message\n return\n" }, "input_value": { "advanced": false, - "display_name": "Text", + "display_name": "Input", "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Message to be passed as output.", - "input_types": ["Message", "str"], + "info": "", + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, - "multiline": true, "name": "input_value", - "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "max_tokens": { + "advanced": true, + "display_name": "Max Tokens", + "dynamic": false, + "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", + "list": false, + "name": "max_tokens", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "int", + "value": "" + }, + "model_kwargs": { + "advanced": true, + "display_name": "Model Kwargs", + "dynamic": false, + "info": "", + "list": false, + "name": "model_kwargs", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "type": "dict", + "value": {} + }, + "model_name": { + "advanced": false, + "display_name": "Model Name", + "dynamic": false, + "info": "", + "name": "model_name", + "options": [ + "gpt-4o", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-3.5-turbo", + "gpt-3.5-turbo-0125" + ], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "gpt-4-turbo" + }, + "openai_api_base": { + "advanced": true, + "display_name": "OpenAI API Base", + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", + "list": false, + "load_from_db": false, + "name": "openai_api_base", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "openai_api_key": { + "advanced": false, + "display_name": "OpenAI API Key", + "dynamic": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "input_types": [], + "load_from_db": false, + "name": "openai_api_key", + "password": true, "placeholder": "", "required": false, "show": true, @@ -1377,24 +1768,214 @@ "type": "str", "value": "" }, - "sender": { + "output_schema": { "advanced": true, - "display_name": "Sender Type", + "display_name": "Schema", "dynamic": false, - "fileTypes": [], - "file_path": "", - "info": "Type of sender.", - "input_types": ["Text"], + "info": "The schema for the Output of the model. You must pass the word JSON in the prompt. If left blank, JSON mode will be disabled.", "list": true, - "load_from_db": false, - "multiline": false, - "name": "sender", - "options": ["Machine", "User"], - "password": false, + "name": "output_schema", "placeholder": "", "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "type": "dict", + "value": {} + }, + "seed": { + "advanced": true, + "display_name": "Seed", + "dynamic": false, + "info": "The seed controls the reproducibility of the job.", + "list": false, + "name": "seed", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "int", + "value": 1 + }, + "stream": { + "advanced": true, + "display_name": "Stream", + "dynamic": false, + "info": "Stream the response from the model. Streaming works only in Chat.", + "list": false, + "name": "stream", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "bool", + "value": false + }, + "system_message": { + "advanced": true, + "display_name": "System Message", + "dynamic": false, + "info": "System message to pass to the model.", + "list": false, + "load_from_db": false, + "name": "system_message", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "temperature": { + "advanced": false, + "display_name": "Temperature", + "dynamic": false, + "info": "", + "list": false, + "name": "temperature", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "float", + "value": 0.1 + } + } + }, + "type": "OpenAIModel" + }, + "dragging": false, + "height": 621, + "id": "OpenAIModel-ybL3k", + "position": { + "x": 3145.6693008609222, + "y": 374.23955005474204 + }, + "positionAbsolute": { + "x": 3145.6693008609222, + "y": 374.23955005474204 + }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { + "data": { + "id": "ChatOutput-BpzuD", + "node": { + "base_classes": [ + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Display a chat message in the Playground.", + "display_name": "Chat Output", + "documentation": "", + "edited": false, + "field_order": [ + "input_value", + "sender", + "sender_name", + "session_id", + "data_template" + ], + "frozen": false, + "icon": "ChatOutput", + "output_types": [], + "outputs": [ + { + "cache": true, + "display_name": "Message", + "method": "message_response", + "name": "message", + "selected": "Message", + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"ChatOutput\"\n\n inputs = [\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[\"Machine\", \"User\"],\n value=\"Machine\",\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\", display_name=\"Sender Name\", info=\"Name of the sender.\", value=\"AI\", advanced=True\n ),\n MessageTextInput(\n name=\"session_id\", display_name=\"Session ID\", info=\"Session ID for the message.\", advanced=True\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n )\n if self.session_id and isinstance(message, Message) and isinstance(message.text, str):\n self.store_message(message)\n self.message.value = message\n\n self.status = message\n return message\n" + }, + "data_template": { + "advanced": true, + "display_name": "Data Template", + "dynamic": false, + "info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "name": "data_template", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "{text}" + }, + "input_value": { + "advanced": false, + "display_name": "Text", + "dynamic": false, + "info": "Message to be passed as output.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "name": "input_value", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "sender": { + "advanced": true, + "display_name": "Sender Type", + "dynamic": false, + "info": "Type of sender.", + "name": "sender", + "options": [ + "Machine", + "User" + ], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, "type": "str", "value": "Machine" }, @@ -1402,19 +1983,19 @@ "advanced": true, "display_name": "Sender Name", "dynamic": false, - "fileTypes": [], - "file_path": "", "info": "Name of the sender.", - "input_types": ["Message", "str"], + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, - "multiline": true, "name": "sender_name", - "password": false, "placeholder": "", "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "AI" }, @@ -1422,19 +2003,19 @@ "advanced": true, "display_name": "Session ID", "dynamic": false, - "fileTypes": [], - "file_path": "", "info": "Session ID for the message.", - "input_types": ["Message", "str"], + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, - "multiline": true, "name": "session_id", - "password": false, "placeholder": "", "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" } @@ -1443,15 +2024,15 @@ "type": "ChatOutput" }, "dragging": false, - "height": 309, - "id": "ChatOutput-nUD9B", + "height": 308, + "id": "ChatOutput-BpzuD", "position": { - "x": 3998.201592537035, - "y": 603.4216529723935 + "x": 3769.242086248817, + "y": 585.3403837062634 }, "positionAbsolute": { - "x": 3998.201592537035, - "y": 603.4216529723935 + "x": 3769.242086248817, + "y": 585.3403837062634 }, "selected": false, "type": "genericNode", @@ -1459,19 +2040,167 @@ }, { "data": { - "id": "File-w2zxA", + "id": "SplitText-52wBo", "node": { - "base_classes": ["Record"], + "base_classes": [ + "Data" + ], "beta": false, - "custom_fields": { - "path": null, - "silent_errors": null - }, + "conditional_paths": [], + "custom_fields": {}, + "description": "Split text into chunks based on specified criteria.", + "display_name": "Split Text", + "documentation": "", + "edited": false, + "field_order": [ + "data_inputs", + "chunk_overlap", + "chunk_size", + "separator" + ], + "frozen": false, + "icon": "scissors-line-dashed", + "output_types": [], + "outputs": [ + { + "cache": true, + "display_name": "Chunks", + "hidden": false, + "method": "split_text", + "name": "chunks", + "selected": "Data", + "types": [ + "Data" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "chunk_overlap": { + "advanced": false, + "display_name": "Chunk Overlap", + "dynamic": false, + "info": "Number of characters to overlap between chunks.", + "list": false, + "name": "chunk_overlap", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "int", + "value": 200 + }, + "chunk_size": { + "advanced": false, + "display_name": "Chunk Size", + "dynamic": false, + "info": "The maximum number of characters in each chunk.", + "list": false, + "name": "chunk_size", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "int", + "value": 1000 + }, + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import List\n\nfrom langchain_text_splitters import CharacterTextSplitter\n\nfrom langflow.custom import Component\nfrom langflow.io import HandleInput, IntInput, MessageTextInput, Output\nfrom langflow.schema import Data\nfrom langflow.utils.util import unescape_string\n\n\nclass SplitTextComponent(Component):\n display_name: str = \"Split Text\"\n description: str = \"Split text into chunks based on specified criteria.\"\n icon = \"scissors-line-dashed\"\n\n inputs = [\n HandleInput(\n name=\"data_inputs\",\n display_name=\"Data Inputs\",\n info=\"The data to split.\",\n input_types=[\"Data\"],\n is_list=True,\n ),\n IntInput(\n name=\"chunk_overlap\",\n display_name=\"Chunk Overlap\",\n info=\"Number of characters to overlap between chunks.\",\n value=200,\n ),\n IntInput(\n name=\"chunk_size\",\n display_name=\"Chunk Size\",\n info=\"The maximum number of characters in each chunk.\",\n value=1000,\n ),\n MessageTextInput(\n name=\"separator\",\n display_name=\"Separator\",\n info=\"The character to split on. Defaults to newline.\",\n value=\"\\n\",\n ),\n ]\n\n outputs = [\n Output(display_name=\"Chunks\", name=\"chunks\", method=\"split_text\"),\n ]\n\n def _docs_to_data(self, docs):\n data = []\n for doc in docs:\n data.append(Data(text=doc.page_content, data=doc.metadata))\n return data\n\n def split_text(self) -> List[Data]:\n separator = unescape_string(self.separator)\n\n documents = []\n for _input in self.data_inputs:\n if isinstance(_input, Data):\n documents.append(_input.to_lc_document())\n\n splitter = CharacterTextSplitter(\n chunk_overlap=self.chunk_overlap,\n chunk_size=self.chunk_size,\n separator=separator,\n )\n docs = splitter.split_documents(documents)\n data = self._docs_to_data(docs)\n self.status = data\n return data\n" + }, + "data_inputs": { + "advanced": false, + "display_name": "Data Inputs", + "dynamic": false, + "info": "The data to split.", + "input_types": [ + "Data" + ], + "list": true, + "name": "data_inputs", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "other", + "value": "" + }, + "separator": { + "advanced": false, + "display_name": "Separator", + "dynamic": false, + "info": "The character to split on. Defaults to newline.", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "name": "separator", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "\n" + } + } + }, + "type": "SplitText" + }, + "dragging": false, + "height": 527, + "id": "SplitText-52wBo", + "position": { + "x": 2044.2799160989089, + "y": 1185.3130355818519 + }, + "positionAbsolute": { + "x": 2044.2799160989089, + "y": 1185.3130355818519 + }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { + "data": { + "id": "File-bf6wn", + "node": { + "base_classes": [ + "Data" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, "description": "A generic file loader.", "display_name": "File", "documentation": "", - "field_formatters": {}, - "field_order": [], + "edited": false, + "field_order": [ + "path", + "silent_errors" + ], "frozen": false, "icon": "file-text", "output_types": [], @@ -1479,13 +2208,17 @@ { "cache": true, "display_name": "Data", + "hidden": false, "method": "load_file", "name": "data", "selected": "Data", - "types": ["Data"], + "types": [ + "Data" + ], "value": "__UNDEFINED__" } ], + "pinned": false, "template": { "_type": "Component", "code": { @@ -1530,7 +2263,7 @@ "ts", "tsx" ], - "file_path": "0433f955-c8cc-4d24-a2bf-e8cd0d11f99c/_Cadastro_de_Pessoa_Fisica_Editável__-_Assinado[1] (1).pdf", + "file_path": "", "info": "Supported file types: txt, md, mdx, csv, json, yaml, yml, xml, html, htm, pdf, docx, py, sh, sql, js, ts, tsx", "list": false, "name": "path", @@ -1538,6 +2271,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "file", "value": "" }, @@ -1552,6 +2286,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "bool", "value": false } @@ -1560,15 +2295,15 @@ "type": "File" }, "dragging": false, - "height": 301, - "id": "File-w2zxA", + "height": 300, + "id": "File-bf6wn", "position": { - "x": 2257.233450682836, - "y": 1747.5389618367233 + "x": 1418.981990122179, + "y": 1539.3825691184466 }, "positionAbsolute": { - "x": 2257.233450682836, - "y": 1747.5389618367233 + "x": 1418.981990122179, + "y": 1539.3825691184466 }, "selected": false, "type": "genericNode", @@ -1576,39 +2311,460 @@ }, { "data": { - "id": "OpenAIEmbeddings-PCoh9", + "id": "AstraDB-vyd5U", "node": { - "base_classes": ["Embeddings"], + "base_classes": [ + "Data", + "Retriever" + ], "beta": false, - "custom_fields": { - "allowed_special": null, - "chunk_size": null, - "client": null, - "default_headers": null, - "default_query": null, - "deployment": null, - "disallowed_special": null, - "embedding_ctx_length": null, - "max_retries": null, - "model": null, - "model_kwargs": null, - "openai_api_base": null, - "openai_api_key": null, - "openai_api_type": null, - "openai_api_version": null, - "openai_organization": null, - "openai_proxy": null, - "request_timeout": null, - "show_progress_bar": null, - "skip_empty": null, - "tiktoken_enable": null, - "tiktoken_model_name": null - }, + "conditional_paths": [], + "custom_fields": {}, + "description": "Implementation of Vector Store using Astra DB with search capabilities", + "display_name": "Astra DB", + "documentation": "https://python.langchain.com/docs/integrations/vectorstores/astradb", + "edited": false, + "field_order": [ + "collection_name", + "token", + "api_endpoint", + "search_input", + "ingest_data", + "namespace", + "metric", + "batch_size", + "bulk_insert_batch_concurrency", + "bulk_insert_overwrite_concurrency", + "bulk_delete_concurrency", + "setup_mode", + "pre_delete_collection", + "metadata_indexing_include", + "embedding", + "metadata_indexing_exclude", + "collection_indexing_policy", + "search_type", + "number_of_results" + ], + "frozen": false, + "icon": "AstraDB", + "output_types": [], + "outputs": [ + { + "cache": true, + "display_name": "Retriever", + "method": "build_base_retriever", + "name": "base_retriever", + "selected": "Retriever", + "types": [ + "Retriever" + ], + "value": "__UNDEFINED__" + }, + { + "cache": true, + "display_name": "Search Results", + "method": "search_documents", + "name": "search_results", + "selected": "Data", + "types": [ + "Data" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "api_endpoint": { + "advanced": false, + "display_name": "API Endpoint", + "dynamic": false, + "info": "API endpoint URL for the Astra DB service.", + "input_types": [], + "load_from_db": false, + "name": "api_endpoint", + "password": true, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "batch_size": { + "advanced": true, + "display_name": "Batch Size", + "dynamic": false, + "info": "Optional number of data to process in a single batch.", + "list": false, + "name": "batch_size", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "int", + "value": "" + }, + "bulk_delete_concurrency": { + "advanced": true, + "display_name": "Bulk Delete Concurrency", + "dynamic": false, + "info": "Optional concurrency level for bulk delete operations.", + "list": false, + "name": "bulk_delete_concurrency", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "int", + "value": "" + }, + "bulk_insert_batch_concurrency": { + "advanced": true, + "display_name": "Bulk Insert Batch Concurrency", + "dynamic": false, + "info": "Optional concurrency level for bulk insert operations.", + "list": false, + "name": "bulk_insert_batch_concurrency", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "int", + "value": "" + }, + "bulk_insert_overwrite_concurrency": { + "advanced": true, + "display_name": "Bulk Insert Overwrite Concurrency", + "dynamic": false, + "info": "Optional concurrency level for bulk insert operations that overwrite existing data.", + "list": false, + "name": "bulk_insert_overwrite_concurrency", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "int", + "value": "" + }, + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from loguru import logger\n\nfrom langflow.base.vectorstores.model import LCVectorStoreComponent\nfrom langflow.io import (\n BoolInput,\n DropdownInput,\n HandleInput,\n IntInput,\n MultilineInput,\n SecretStrInput,\n StrInput,\n DataInput,\n)\nfrom langflow.schema import Data\n\n\nclass AstraVectorStoreComponent(LCVectorStoreComponent):\n display_name: str = \"Astra DB\"\n description: str = \"Implementation of Vector Store using Astra DB with search capabilities\"\n documentation: str = \"https://python.langchain.com/docs/integrations/vectorstores/astradb\"\n icon: str = \"AstraDB\"\n\n inputs = [\n StrInput(\n name=\"collection_name\",\n display_name=\"Collection Name\",\n info=\"The name of the collection within Astra DB where the vectors will be stored.\",\n ),\n SecretStrInput(\n name=\"token\",\n display_name=\"Astra DB Application Token\",\n info=\"Authentication token for accessing Astra DB.\",\n value=\"ASTRA_DB_APPLICATION_TOKEN\",\n ),\n SecretStrInput(\n name=\"api_endpoint\",\n display_name=\"API Endpoint\",\n info=\"API endpoint URL for the Astra DB service.\",\n value=\"ASTRA_DB_API_ENDPOINT\",\n ),\n MultilineInput(\n name=\"search_input\",\n display_name=\"Search Input\",\n ),\n DataInput(\n name=\"ingest_data\",\n display_name=\"Ingest Data\",\n is_list=True,\n ),\n StrInput(\n name=\"namespace\",\n display_name=\"Namespace\",\n info=\"Optional namespace within Astra DB to use for the collection.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"metric\",\n display_name=\"Metric\",\n info=\"Optional distance metric for vector comparisons in the vector store.\",\n options=[\"cosine\", \"dot_product\", \"euclidean\"],\n advanced=True,\n ),\n IntInput(\n name=\"batch_size\",\n display_name=\"Batch Size\",\n info=\"Optional number of data to process in a single batch.\",\n advanced=True,\n ),\n IntInput(\n name=\"bulk_insert_batch_concurrency\",\n display_name=\"Bulk Insert Batch Concurrency\",\n info=\"Optional concurrency level for bulk insert operations.\",\n advanced=True,\n ),\n IntInput(\n name=\"bulk_insert_overwrite_concurrency\",\n display_name=\"Bulk Insert Overwrite Concurrency\",\n info=\"Optional concurrency level for bulk insert operations that overwrite existing data.\",\n advanced=True,\n ),\n IntInput(\n name=\"bulk_delete_concurrency\",\n display_name=\"Bulk Delete Concurrency\",\n info=\"Optional concurrency level for bulk delete operations.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"setup_mode\",\n display_name=\"Setup Mode\",\n info=\"Configuration mode for setting up the vector store, with options like 'Sync', 'Async', or 'Off'.\",\n options=[\"Sync\", \"Async\", \"Off\"],\n advanced=True,\n value=\"Sync\",\n ),\n BoolInput(\n name=\"pre_delete_collection\",\n display_name=\"Pre Delete Collection\",\n info=\"Boolean flag to determine whether to delete the collection before creating a new one.\",\n advanced=True,\n ),\n StrInput(\n name=\"metadata_indexing_include\",\n display_name=\"Metadata Indexing Include\",\n info=\"Optional list of metadata fields to include in the indexing.\",\n advanced=True,\n ),\n HandleInput(\n name=\"embedding\",\n display_name=\"Embedding or Astra Vectorize\",\n input_types=[\"Embeddings\", \"dict\"],\n ),\n StrInput(\n name=\"metadata_indexing_exclude\",\n display_name=\"Metadata Indexing Exclude\",\n info=\"Optional list of metadata fields to exclude from the indexing.\",\n advanced=True,\n ),\n StrInput(\n name=\"collection_indexing_policy\",\n display_name=\"Collection Indexing Policy\",\n info=\"Optional dictionary defining the indexing policy for the collection.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"search_type\",\n display_name=\"Search Type\",\n options=[\"Similarity\", \"MMR\"],\n value=\"Similarity\",\n advanced=True,\n ),\n IntInput(\n name=\"number_of_results\",\n display_name=\"Number of Results\",\n info=\"Number of results to return.\",\n advanced=True,\n value=4,\n ),\n ]\n\n def build_vector_store(self):\n try:\n from langchain_astradb import AstraDBVectorStore\n from langchain_astradb.utils.astradb import SetupMode\n except ImportError:\n raise ImportError(\n \"Could not import langchain Astra DB integration package. \"\n \"Please install it with `pip install langchain-astradb`.\"\n )\n\n try:\n if not self.setup_mode:\n self.setup_mode = self._inputs[\"setup_mode\"].options[0]\n\n setup_mode_value = SetupMode[self.setup_mode.upper()]\n except KeyError:\n raise ValueError(f\"Invalid setup mode: {self.setup_mode}\")\n\n if not isinstance(self.embedding, dict):\n embedding_dict = {\"embedding\": self.embedding}\n else:\n from astrapy.info import CollectionVectorServiceOptions\n\n dict_options = self.embedding.get(\"collection_vector_service_options\", {})\n dict_options[\"authentication\"] = {\n k: v for k, v in dict_options.get(\"authentication\", {}).items() if k and v\n }\n dict_options[\"parameters\"] = {k: v for k, v in dict_options.get(\"parameters\", {}).items() if k and v}\n embedding_dict = {\n \"collection_vector_service_options\": CollectionVectorServiceOptions.from_dict(dict_options),\n \"collection_embedding_api_key\": self.embedding.get(\"collection_embedding_api_key\"),\n }\n vector_store_kwargs = {\n **embedding_dict,\n \"collection_name\": self.collection_name,\n \"token\": self.token,\n \"api_endpoint\": self.api_endpoint,\n \"namespace\": self.namespace or None,\n \"metric\": self.metric or None,\n \"batch_size\": self.batch_size or None,\n \"bulk_insert_batch_concurrency\": self.bulk_insert_batch_concurrency or None,\n \"bulk_insert_overwrite_concurrency\": self.bulk_insert_overwrite_concurrency or None,\n \"bulk_delete_concurrency\": self.bulk_delete_concurrency or None,\n \"setup_mode\": setup_mode_value,\n \"pre_delete_collection\": self.pre_delete_collection or False,\n }\n\n if self.metadata_indexing_include:\n vector_store_kwargs[\"metadata_indexing_include\"] = self.metadata_indexing_include\n elif self.metadata_indexing_exclude:\n vector_store_kwargs[\"metadata_indexing_exclude\"] = self.metadata_indexing_exclude\n elif self.collection_indexing_policy:\n vector_store_kwargs[\"collection_indexing_policy\"] = self.collection_indexing_policy\n\n try:\n vector_store = AstraDBVectorStore(**vector_store_kwargs)\n except Exception as e:\n raise ValueError(f\"Error initializing AstraDBVectorStore: {str(e)}\") from e\n\n self.status = self._astradb_collection_to_data(vector_store.collection)\n return vector_store\n\n def _add_documents_to_vector_store(self, vector_store):\n documents = []\n for _input in self.ingest_data or []:\n if isinstance(_input, Data):\n documents.append(_input.to_lc_document())\n else:\n raise ValueError(\"Vector Store Inputs must be Data objects.\")\n\n if documents and self.embedding is not None:\n logger.debug(f\"Adding {len(documents)} documents to the Vector Store.\")\n try:\n vector_store.add_documents(documents)\n except Exception as e:\n raise ValueError(f\"Error adding documents to AstraDBVectorStore: {str(e)}\") from e\n else:\n logger.debug(\"No documents to add to the Vector Store.\")\n\n def search_documents(self):\n vector_store = self.build_vector_store()\n\n logger.debug(f\"Search input: {self.search_input}\")\n logger.debug(f\"Search type: {self.search_type}\")\n logger.debug(f\"Number of results: {self.number_of_results}\")\n\n if self.search_input and isinstance(self.search_input, str) and self.search_input.strip():\n try:\n if self.search_type == \"Similarity\":\n docs = vector_store.similarity_search(\n query=self.search_input,\n k=self.number_of_results,\n )\n elif self.search_type == \"MMR\":\n docs = vector_store.max_marginal_relevance_search(\n query=self.search_input,\n k=self.number_of_results,\n )\n else:\n raise ValueError(f\"Invalid search type: {self.search_type}\")\n except Exception as e:\n raise ValueError(f\"Error performing search in AstraDBVectorStore: {str(e)}\") from e\n\n logger.debug(f\"Retrieved documents: {len(docs)}\")\n\n data = [Data.from_document(doc) for doc in docs]\n logger.debug(f\"Converted documents to data: {len(data)}\")\n self.status = data\n return data\n else:\n logger.debug(\"No search input provided. Skipping search.\")\n return []\n\n def _astradb_collection_to_data(self, collection):\n data = []\n data_dict = collection.find()\n if data_dict and \"data\" in data_dict:\n data_dict = data_dict[\"data\"].get(\"documents\", [])\n\n for item in data_dict:\n data.append(Data(content=item[\"content\"]))\n return data\n" + }, + "collection_indexing_policy": { + "advanced": true, + "display_name": "Collection Indexing Policy", + "dynamic": false, + "info": "Optional dictionary defining the indexing policy for the collection.", + "list": false, + "load_from_db": false, + "name": "collection_indexing_policy", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "collection_name": { + "advanced": false, + "display_name": "Collection Name", + "dynamic": false, + "info": "The name of the collection within Astra DB where the vectors will be stored.", + "list": false, + "load_from_db": false, + "name": "collection_name", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "langflow" + }, + "embedding": { + "advanced": false, + "display_name": "Embedding or Astra Vectorize", + "dynamic": false, + "info": "", + "input_types": [ + "Embeddings", + "dict" + ], + "list": false, + "name": "embedding", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "other", + "value": "" + }, + "ingest_data": { + "advanced": false, + "display_name": "Ingest Data", + "dynamic": false, + "info": "", + "input_types": [ + "Data" + ], + "list": true, + "name": "ingest_data", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "other", + "value": "" + }, + "metadata_indexing_exclude": { + "advanced": true, + "display_name": "Metadata Indexing Exclude", + "dynamic": false, + "info": "Optional list of metadata fields to exclude from the indexing.", + "list": false, + "load_from_db": false, + "name": "metadata_indexing_exclude", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "metadata_indexing_include": { + "advanced": true, + "display_name": "Metadata Indexing Include", + "dynamic": false, + "info": "Optional list of metadata fields to include in the indexing.", + "list": false, + "load_from_db": false, + "name": "metadata_indexing_include", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "metric": { + "advanced": true, + "display_name": "Metric", + "dynamic": false, + "info": "Optional distance metric for vector comparisons in the vector store.", + "name": "metric", + "options": [ + "cosine", + "dot_product", + "euclidean" + ], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "namespace": { + "advanced": true, + "display_name": "Namespace", + "dynamic": false, + "info": "Optional namespace within Astra DB to use for the collection.", + "list": false, + "load_from_db": false, + "name": "namespace", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "number_of_results": { + "advanced": true, + "display_name": "Number of Results", + "dynamic": false, + "info": "Number of results to return.", + "list": false, + "name": "number_of_results", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "int", + "value": 4 + }, + "pre_delete_collection": { + "advanced": true, + "display_name": "Pre Delete Collection", + "dynamic": false, + "info": "Boolean flag to determine whether to delete the collection before creating a new one.", + "list": false, + "name": "pre_delete_collection", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "bool", + "value": false + }, + "search_input": { + "advanced": false, + "display_name": "Search Input", + "dynamic": false, + "info": "", + "input_types": [ + "Message" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "search_input", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "search_type": { + "advanced": true, + "display_name": "Search Type", + "dynamic": false, + "info": "", + "name": "search_type", + "options": [ + "Similarity", + "MMR" + ], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "Similarity" + }, + "setup_mode": { + "advanced": true, + "display_name": "Setup Mode", + "dynamic": false, + "info": "Configuration mode for setting up the vector store, with options like 'Sync', 'Async', or 'Off'.", + "name": "setup_mode", + "options": [ + "Sync", + "Async", + "Off" + ], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "str", + "value": "Sync" + }, + "token": { + "advanced": false, + "display_name": "Astra DB Application Token", + "dynamic": false, + "info": "Authentication token for accessing Astra DB.", + "input_types": [], + "load_from_db": false, + "name": "token", + "password": true, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + } + } + }, + "type": "AstraDB" + }, + "dragging": false, + "height": 753, + "id": "AstraDB-vyd5U", + "position": { + "x": 2676.4816074350247, + "y": 1269.304067004569 + }, + "positionAbsolute": { + "x": 2676.4816074350247, + "y": 1269.304067004569 + }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { + "data": { + "id": "OpenAIEmbeddings-sRZMc", + "node": { + "base_classes": [ + "Embeddings" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, "description": "Generate embeddings using OpenAI models.", "display_name": "OpenAI Embeddings", "documentation": "", - "field_formatters": {}, - "field_order": [], + "edited": false, + "field_order": [ + "default_headers", + "default_query", + "chunk_size", + "client", + "deployment", + "embedding_ctx_length", + "max_retries", + "model", + "model_kwargs", + "openai_api_base", + "openai_api_key", + "openai_api_type", + "openai_api_version", + "openai_organization", + "openai_proxy", + "request_timeout", + "show_progress_bar", + "skip_empty", + "tiktoken_model_name", + "tiktoken_enable" + ], "frozen": false, "icon": "OpenAI", "output_types": [], @@ -1616,13 +2772,17 @@ { "cache": true, "display_name": "Embeddings", + "hidden": false, "method": "build_embeddings", "name": "embeddings", "selected": "Embeddings", - "types": ["Embeddings"], + "types": [ + "Embeddings" + ], "value": "__UNDEFINED__" } ], + "pinned": false, "template": { "_type": "Component", "chunk_size": { @@ -1636,6 +2796,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "int", "value": 1000 }, @@ -1644,7 +2805,9 @@ "display_name": "Client", "dynamic": false, "info": "", - "input_types": ["Message", "str"], + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, "name": "client", @@ -1652,6 +2815,8 @@ "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" }, @@ -1671,7 +2836,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langchain_openai.embeddings.base import OpenAIEmbeddings\n\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.field_typing import Embeddings\nfrom langflow.io import BoolInput, DictInput, DropdownInput, FloatInput, IntInput, Output, SecretStrInput, TextInput\n\n\nclass OpenAIEmbeddingsComponent(LCModelComponent):\n display_name = \"OpenAI Embeddings\"\n description = \"Generate embeddings using OpenAI models.\"\n icon = \"OpenAI\"\n inputs = [\n DictInput(\n name=\"default_headers\",\n display_name=\"Default Headers\",\n advanced=True,\n info=\"Default headers to use for the API request.\",\n ),\n DictInput(\n name=\"default_query\",\n display_name=\"Default Query\",\n advanced=True,\n info=\"Default query parameters to use for the API request.\",\n ),\n IntInput(name=\"chunk_size\", display_name=\"Chunk Size\", advanced=True, value=1000),\n TextInput(name=\"client\", display_name=\"Client\", advanced=True),\n TextInput(name=\"deployment\", display_name=\"Deployment\", advanced=True),\n IntInput(name=\"embedding_ctx_length\", display_name=\"Embedding Context Length\", advanced=True, value=1536),\n IntInput(name=\"max_retries\", display_name=\"Max Retries\", value=3, advanced=True),\n DropdownInput(\n name=\"model\",\n display_name=\"Model\",\n advanced=False,\n options=[\n \"text-embedding-3-small\",\n \"text-embedding-3-large\",\n \"text-embedding-ada-002\",\n ],\n value=\"text-embedding-3-small\",\n ),\n DictInput(name=\"model_kwargs\", display_name=\"Model Kwargs\", advanced=True),\n SecretStrInput(name=\"openai_api_base\", display_name=\"OpenAI API Base\", advanced=True),\n SecretStrInput(name=\"openai_api_key\", display_name=\"OpenAI API Key\"),\n SecretStrInput(name=\"openai_api_type\", display_name=\"OpenAI API Type\", advanced=True),\n TextInput(name=\"openai_api_version\", display_name=\"OpenAI API Version\", advanced=True),\n TextInput(\n name=\"openai_organization\",\n display_name=\"OpenAI Organization\",\n advanced=True,\n ),\n TextInput(name=\"openai_proxy\", display_name=\"OpenAI Proxy\", advanced=True),\n FloatInput(name=\"request_timeout\", display_name=\"Request Timeout\", advanced=True),\n BoolInput(name=\"show_progress_bar\", display_name=\"Show Progress Bar\", advanced=True),\n BoolInput(name=\"skip_empty\", display_name=\"Skip Empty\", advanced=True),\n TextInput(\n name=\"tiktoken_model_name\",\n display_name=\"TikToken Model Name\",\n advanced=True,\n ),\n BoolInput(\n name=\"tiktoken_enable\",\n display_name=\"TikToken Enable\",\n advanced=True,\n value=True,\n info=\"If False, you must have transformers installed.\",\n ),\n ]\n\n outputs = [\n Output(display_name=\"Embeddings\", name=\"embeddings\", method=\"build_embeddings\"),\n ]\n\n def build_embeddings(self) -> Embeddings:\n return OpenAIEmbeddings(\n tiktoken_enabled=self.tiktoken_enable,\n default_headers=self.default_headers,\n default_query=self.default_query,\n allowed_special=\"all\",\n disallowed_special=\"all\",\n chunk_size=self.chunk_size,\n deployment=self.deployment,\n embedding_ctx_length=self.embedding_ctx_length,\n max_retries=self.max_retries,\n model=self.model,\n model_kwargs=self.model_kwargs,\n base_url=self.openai_api_base,\n api_key=self.openai_api_key,\n openai_api_type=self.openai_api_type,\n api_version=self.openai_api_version,\n organization=self.openai_organization,\n openai_proxy=self.openai_proxy,\n timeout=self.request_timeout or None,\n show_progress_bar=self.show_progress_bar,\n skip_empty=self.skip_empty,\n tiktoken_model_name=self.tiktoken_model_name,\n )\n" + "value": "from langchain_openai.embeddings.base import OpenAIEmbeddings\n\nfrom langflow.base.embeddings.model import LCEmbeddingsModel\nfrom langflow.field_typing import Embeddings\nfrom langflow.io import BoolInput, DictInput, DropdownInput, FloatInput, IntInput, MessageTextInput, SecretStrInput\n\n\nclass OpenAIEmbeddingsComponent(LCEmbeddingsModel):\n display_name = \"OpenAI Embeddings\"\n description = \"Generate embeddings using OpenAI models.\"\n icon = \"OpenAI\"\n inputs = [\n DictInput(\n name=\"default_headers\",\n display_name=\"Default Headers\",\n advanced=True,\n info=\"Default headers to use for the API request.\",\n ),\n DictInput(\n name=\"default_query\",\n display_name=\"Default Query\",\n advanced=True,\n info=\"Default query parameters to use for the API request.\",\n ),\n IntInput(name=\"chunk_size\", display_name=\"Chunk Size\", advanced=True, value=1000),\n MessageTextInput(name=\"client\", display_name=\"Client\", advanced=True),\n MessageTextInput(name=\"deployment\", display_name=\"Deployment\", advanced=True),\n IntInput(name=\"embedding_ctx_length\", display_name=\"Embedding Context Length\", advanced=True, value=1536),\n IntInput(name=\"max_retries\", display_name=\"Max Retries\", value=3, advanced=True),\n DropdownInput(\n name=\"model\",\n display_name=\"Model\",\n advanced=False,\n options=[\n \"text-embedding-3-small\",\n \"text-embedding-3-large\",\n \"text-embedding-ada-002\",\n ],\n value=\"text-embedding-3-small\",\n ),\n DictInput(name=\"model_kwargs\", display_name=\"Model Kwargs\", advanced=True),\n SecretStrInput(name=\"openai_api_base\", display_name=\"OpenAI API Base\", advanced=True),\n SecretStrInput(name=\"openai_api_key\", display_name=\"OpenAI API Key\"),\n SecretStrInput(name=\"openai_api_type\", display_name=\"OpenAI API Type\", advanced=True),\n MessageTextInput(name=\"openai_api_version\", display_name=\"OpenAI API Version\", advanced=True),\n MessageTextInput(\n name=\"openai_organization\",\n display_name=\"OpenAI Organization\",\n advanced=True,\n ),\n MessageTextInput(name=\"openai_proxy\", display_name=\"OpenAI Proxy\", advanced=True),\n FloatInput(name=\"request_timeout\", display_name=\"Request Timeout\", advanced=True),\n BoolInput(name=\"show_progress_bar\", display_name=\"Show Progress Bar\", advanced=True),\n BoolInput(name=\"skip_empty\", display_name=\"Skip Empty\", advanced=True),\n MessageTextInput(\n name=\"tiktoken_model_name\",\n display_name=\"TikToken Model Name\",\n advanced=True,\n ),\n BoolInput(\n name=\"tiktoken_enable\",\n display_name=\"TikToken Enable\",\n advanced=True,\n value=True,\n info=\"If False, you must have transformers installed.\",\n ),\n ]\n\n def build_embeddings(self) -> Embeddings:\n return OpenAIEmbeddings(\n tiktoken_enabled=self.tiktoken_enable,\n default_headers=self.default_headers,\n default_query=self.default_query,\n allowed_special=\"all\",\n disallowed_special=\"all\",\n chunk_size=self.chunk_size,\n deployment=self.deployment,\n embedding_ctx_length=self.embedding_ctx_length,\n max_retries=self.max_retries,\n model=self.model,\n model_kwargs=self.model_kwargs,\n base_url=self.openai_api_base,\n api_key=self.openai_api_key,\n openai_api_type=self.openai_api_type,\n api_version=self.openai_api_version,\n organization=self.openai_organization,\n openai_proxy=self.openai_proxy,\n timeout=self.request_timeout or None,\n show_progress_bar=self.show_progress_bar,\n skip_empty=self.skip_empty,\n tiktoken_model_name=self.tiktoken_model_name,\n )\n" }, "default_headers": { "advanced": true, @@ -1684,6 +2849,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_input": true, "type": "dict", "value": {} }, @@ -1698,6 +2864,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_input": true, "type": "dict", "value": {} }, @@ -1706,7 +2873,9 @@ "display_name": "Deployment", "dynamic": false, "info": "", - "input_types": ["Message", "str"], + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, "name": "deployment", @@ -1714,6 +2883,8 @@ "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" }, @@ -1728,6 +2899,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "int", "value": 1536 }, @@ -1742,6 +2914,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "int", "value": 3 }, @@ -1760,6 +2933,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "str", "value": "text-embedding-3-small" }, @@ -1774,6 +2948,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_input": true, "type": "dict", "value": {} }, @@ -1799,7 +2974,7 @@ "dynamic": false, "info": "", "input_types": [], - "load_from_db": true, + "load_from_db": false, "name": "openai_api_key", "password": true, "placeholder": "", @@ -1807,7 +2982,7 @@ "show": true, "title_case": false, "type": "str", - "value": "OPENAI_API_KEY" + "value": "" }, "openai_api_type": { "advanced": true, @@ -1830,7 +3005,9 @@ "display_name": "OpenAI API Version", "dynamic": false, "info": "", - "input_types": ["Message", "str"], + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, "name": "openai_api_version", @@ -1838,6 +3015,8 @@ "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" }, @@ -1846,7 +3025,9 @@ "display_name": "OpenAI Organization", "dynamic": false, "info": "", - "input_types": ["Message", "str"], + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, "name": "openai_organization", @@ -1854,6 +3035,8 @@ "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" }, @@ -1862,7 +3045,9 @@ "display_name": "OpenAI Proxy", "dynamic": false, "info": "", - "input_types": ["Message", "str"], + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, "name": "openai_proxy", @@ -1870,6 +3055,8 @@ "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" }, @@ -1884,6 +3071,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "float", "value": "" }, @@ -1898,6 +3086,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "bool", "value": false }, @@ -1912,6 +3101,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "bool", "value": false }, @@ -1926,6 +3116,7 @@ "required": false, "show": true, "title_case": false, + "trace_as_metadata": true, "type": "bool", "value": true }, @@ -1934,7 +3125,9 @@ "display_name": "TikToken Model Name", "dynamic": false, "info": "", - "input_types": ["Message", "str"], + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, "name": "tiktoken_model_name", @@ -1942,6 +3135,8 @@ "required": false, "show": true, "title_case": false, + "trace_as_input": true, + "trace_as_metadata": true, "type": "str", "value": "" } @@ -1950,1046 +3145,15 @@ "type": "OpenAIEmbeddings" }, "dragging": false, - "height": 395, - "id": "OpenAIEmbeddings-PCoh9", + "height": 394, + "id": "OpenAIEmbeddings-sRZMc", "position": { - "x": 2781.1922529351923, - "y": 2206.267872396239 + "x": 2050.0569098721217, + "y": 1823.5240486490072 }, "positionAbsolute": { - "x": 2781.1922529351923, - "y": 2206.267872396239 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "description": "Split text into chunks of a specified length.", - "display_name": "Recursive Character Text Splitter", - "id": "RecursiveCharacterTextSplitter-CrApG", - "node": { - "base_classes": ["Data"], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Split text into chunks of a specified length.", - "display_name": "Recursive Character Text Splitter", - "documentation": "https://docs.langflow.org/components/text-splitters#recursivecharactertextsplitter", - "edited": true, - "field_order": [ - "chunk_size", - "chunk_overlap", - "data_input", - "separators" - ], - "frozen": false, - "output_types": ["Data"], - "outputs": [ - { - "cache": true, - "display_name": "Data", - "method": "build", - "name": "data", - "selected": "Data", - "types": ["Data"], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "chunk_overlap": { - "advanced": false, - "display_name": "Chunk Overlap", - "dynamic": false, - "info": "The amount of overlap between chunks.", - "list": false, - "name": "chunk_overlap", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": 200 - }, - "chunk_size": { - "advanced": false, - "display_name": "Chunk Size", - "dynamic": false, - "info": "The maximum length of each chunk.", - "list": false, - "name": "chunk_size", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": 1000 - }, - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langchain_text_splitters import RecursiveCharacterTextSplitter\n\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DataInput, IntInput, TextInput\nfrom langflow.schema import Data\nfrom langflow.template.field.base import Output\nfrom langflow.utils.util import build_loader_repr_from_data, unescape_string\n\n\nclass RecursiveCharacterTextSplitterComponent(Component):\n display_name: str = \"Recursive Character Text Splitter\"\n description: str = \"Split text into chunks of a specified length.\"\n documentation: str = \"https://docs.langflow.org/components/text-splitters#recursivecharactertextsplitter\"\n\n inputs = [\n IntInput(\n name=\"chunk_size\",\n display_name=\"Chunk Size\",\n info=\"The maximum length of each chunk.\",\n value=1000,\n ),\n IntInput(\n name=\"chunk_overlap\",\n display_name=\"Chunk Overlap\",\n info=\"The amount of overlap between chunks.\",\n value=200,\n ),\n DataInput(\n name=\"data_input\",\n display_name=\"Input\",\n info=\"The texts to split.\",\n input_types=[\"Document\", \"Data\"],\n ),\n TextInput(\n name=\"separators\",\n display_name=\"Separators\",\n info='The characters to split on.\\nIf left empty defaults to [\"\\\\n\\\\n\", \"\\\\n\", \" \", \"\"].',\n is_list=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Data\", name=\"data\", method=\"build\"),\n ]\n\n def build(self) -> list[Data]:\n \"\"\"\n Split text into chunks of a specified length.\n\n Args:\n separators (list[str]): The characters to split on.\n chunk_size (int): The maximum length of each chunk.\n chunk_overlap (int): The amount of overlap between chunks.\n\n Returns:\n list[str]: The chunks of text.\n \"\"\"\n\n if self.separators == \"\":\n self.separators = None\n elif self.separators:\n # check if the separators list has escaped characters\n # if there are escaped characters, unescape them\n self.separators = [unescape_string(x) for x in self.separators]\n\n # Make sure chunk_size and chunk_overlap are ints\n if isinstance(self.chunk_size, str):\n self.chunk_size = int(self.chunk_size)\n if isinstance(self.chunk_overlap, str):\n self.chunk_overlap = int(self.chunk_overlap)\n splitter = RecursiveCharacterTextSplitter(\n separators=self.separators,\n chunk_size=self.chunk_size,\n chunk_overlap=self.chunk_overlap,\n )\n documents = []\n if not isinstance(self.data_input, list):\n self.data_input = [self.data_input]\n for _input in self.data_input:\n if isinstance(_input, Data):\n documents.append(_input.to_lc_document())\n else:\n documents.append(_input)\n docs = splitter.split_documents(documents)\n data = self.to_data(docs)\n self.repr_value = build_loader_repr_from_data(data)\n return data\n" - }, - "data_input": { - "advanced": false, - "display_name": "Input", - "dynamic": false, - "info": "The texts to split.", - "input_types": ["Document", "Data"], - "list": false, - "name": "data_input", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "other", - "value": "" - }, - "separators": { - "advanced": false, - "display_name": "Separators", - "dynamic": false, - "info": "The characters to split on.\nIf left empty defaults to [\"\\n\\n\", \"\\n\", \" \", \"\"].", - "input_types": ["Message", "str"], - "list": true, - "load_from_db": false, - "name": "separators", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": ["\\n"] - } - } - }, - "type": "RecursiveCharacterTextSplitter" - }, - "dragging": false, - "height": 529, - "id": "RecursiveCharacterTextSplitter-CrApG", - "position": { - "x": 2726.46405760335, - "y": 1530.1666819162674 - }, - "positionAbsolute": { - "x": 2726.46405760335, - "y": 1530.1666819162674 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "description": "Implementation of Vector Store using Astra DB with search capabilities", - "display_name": "Astra DB Vector Store", - "id": "AstraDB-rXo8b", - "node": { - "base_classes": ["Data"], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Implementation of Vector Store using Astra DB with search capabilities", - "display_name": "Astra DB Vector Store", - "documentation": "https://python.langchain.com/docs/integrations/vectorstores/astradb", - "edited": false, - "field_order": [ - "collection_name", - "token", - "api_endpoint", - "vector_store_inputs", - "embedding", - "namespace", - "metric", - "batch_size", - "bulk_insert_batch_concurrency", - "bulk_insert_overwrite_concurrency", - "bulk_delete_concurrency", - "setup_mode", - "pre_delete_collection", - "metadata_indexing_include", - "metadata_indexing_exclude", - "collection_indexing_policy", - "add_to_vector_store", - "search_input", - "search_type", - "number_of_results" - ], - "frozen": false, - "icon": "AstraDB", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Retriever", - "method": "build_base_retriever", - "name": "base_retriever", - "selected": "Data", - "types": ["Data"], - "value": "__UNDEFINED__" - }, - { - "cache": true, - "display_name": "Search Results", - "method": "search_documents", - "name": "search_results", - "selected": "Data", - "types": ["Data"], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "add_to_vector_store": { - "advanced": false, - "display_name": "Add to Vector Store", - "dynamic": false, - "info": "If true, the Vector Store Inputs will be added to the Vector Store.", - "list": false, - "name": "add_to_vector_store", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "bool", - "value": true - }, - "api_endpoint": { - "advanced": false, - "display_name": "API Endpoint", - "dynamic": false, - "info": "API endpoint URL for the Astra DB service.", - "input_types": [], - "load_from_db": true, - "name": "api_endpoint", - "password": true, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "ASTRA_DB_API_ENDPOINT" - }, - "batch_size": { - "advanced": true, - "display_name": "Batch Size", - "dynamic": false, - "info": "Optional number of data to process in a single batch.", - "list": false, - "name": "batch_size", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": "" - }, - "bulk_delete_concurrency": { - "advanced": true, - "display_name": "Bulk Delete Concurrency", - "dynamic": false, - "info": "Optional concurrency level for bulk delete operations.", - "list": false, - "name": "bulk_delete_concurrency", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": "" - }, - "bulk_insert_batch_concurrency": { - "advanced": true, - "display_name": "Bulk Insert Batch Concurrency", - "dynamic": false, - "info": "Optional concurrency level for bulk insert operations.", - "list": false, - "name": "bulk_insert_batch_concurrency", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": "" - }, - "bulk_insert_overwrite_concurrency": { - "advanced": true, - "display_name": "Bulk Insert Overwrite Concurrency", - "dynamic": false, - "info": "Optional concurrency level for bulk insert operations that overwrite existing data.", - "list": false, - "name": "bulk_insert_overwrite_concurrency", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": "" - }, - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from loguru import logger\n\nfrom langflow.base.vectorstores.model import LCVectorStoreComponent\nfrom langflow.io import BoolInput, DropdownInput, HandleInput, IntInput, MultilineInput, SecretStrInput, StrInput, DataInput\nfrom langflow.schema import Data\n\n\nclass AstraVectorStoreComponent(LCVectorStoreComponent):\n display_name: str = \"Astra DB Vector Store\"\n description: str = \"Implementation of Vector Store using Astra DB with search capabilities\"\n documentation: str = \"https://python.langchain.com/docs/integrations/vectorstores/astradb\"\n icon: str = \"AstraDB\"\n\n inputs = [\n StrInput(\n name=\"collection_name\",\n display_name=\"Collection Name\",\n info=\"The name of the collection within Astra DB where the vectors will be stored.\",\n ),\n SecretStrInput(\n name=\"token\",\n display_name=\"Astra DB Application Token\",\n info=\"Authentication token for accessing Astra DB.\",\n value=\"ASTRA_DB_APPLICATION_TOKEN\",\n ),\n SecretStrInput(\n name=\"api_endpoint\",\n display_name=\"API Endpoint\",\n info=\"API endpoint URL for the Astra DB service.\",\n value=\"ASTRA_DB_API_ENDPOINT\",\n ),\n DataInput(\n name=\"vector_store_inputs\",\n display_name=\"Vector Store Inputs\",\n is_list=True,\n ),\n HandleInput(\n name=\"embedding\",\n display_name=\"Embedding\",\n input_types=[\"Embeddings\", \"dict\"],\n ),\n StrInput(\n name=\"namespace\",\n display_name=\"Namespace\",\n info=\"Optional namespace within Astra DB to use for the collection.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"metric\",\n display_name=\"Metric\",\n info=\"Optional distance metric for vector comparisons in the vector store.\",\n options=[\"cosine\", \"dot_product\", \"euclidean\"],\n advanced=True,\n ),\n IntInput(\n name=\"batch_size\",\n display_name=\"Batch Size\",\n info=\"Optional number of data to process in a single batch.\",\n advanced=True,\n ),\n IntInput(\n name=\"bulk_insert_batch_concurrency\",\n display_name=\"Bulk Insert Batch Concurrency\",\n info=\"Optional concurrency level for bulk insert operations.\",\n advanced=True,\n ),\n IntInput(\n name=\"bulk_insert_overwrite_concurrency\",\n display_name=\"Bulk Insert Overwrite Concurrency\",\n info=\"Optional concurrency level for bulk insert operations that overwrite existing data.\",\n advanced=True,\n ),\n IntInput(\n name=\"bulk_delete_concurrency\",\n display_name=\"Bulk Delete Concurrency\",\n info=\"Optional concurrency level for bulk delete operations.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"setup_mode\",\n display_name=\"Setup Mode\",\n info=\"Configuration mode for setting up the vector store, with options like 'Sync', 'Async', or 'Off'.\",\n options=[\"Sync\", \"Async\", \"Off\"],\n advanced=True,\n value=\"Sync\",\n ),\n BoolInput(\n name=\"pre_delete_collection\",\n display_name=\"Pre Delete Collection\",\n info=\"Boolean flag to determine whether to delete the collection before creating a new one.\",\n advanced=True,\n ),\n StrInput(\n name=\"metadata_indexing_include\",\n display_name=\"Metadata Indexing Include\",\n info=\"Optional list of metadata fields to include in the indexing.\",\n advanced=True,\n ),\n StrInput(\n name=\"metadata_indexing_exclude\",\n display_name=\"Metadata Indexing Exclude\",\n info=\"Optional list of metadata fields to exclude from the indexing.\",\n advanced=True,\n ),\n StrInput(\n name=\"collection_indexing_policy\",\n display_name=\"Collection Indexing Policy\",\n info=\"Optional dictionary defining the indexing policy for the collection.\",\n advanced=True,\n ),\n BoolInput(\n name=\"add_to_vector_store\",\n display_name=\"Add to Vector Store\",\n info=\"If true, the Vector Store Inputs will be added to the Vector Store.\",\n ),\n MultilineInput(\n name=\"search_input\",\n display_name=\"Search Input\",\n ),\n DropdownInput(\n name=\"search_type\",\n display_name=\"Search Type\",\n options=[\"Similarity\", \"MMR\"],\n value=\"Similarity\",\n ),\n IntInput(\n name=\"number_of_results\",\n display_name=\"Number of Results\",\n info=\"Number of results to return.\",\n advanced=True,\n value=4,\n ),\n ]\n\n def build_vector_store(self):\n try:\n from langchain_astradb import AstraDBVectorStore\n from langchain_astradb.utils.astradb import SetupMode\n except ImportError:\n raise ImportError(\n \"Could not import langchain Astra DB integration package. \"\n \"Please install it with `pip install langchain-astradb`.\"\n )\n\n try:\n if not self.setup_mode:\n self.setup_mode = self._inputs[\"setup_mode\"].options[0]\n\n setup_mode_value = SetupMode[self.setup_mode.upper()]\n except KeyError:\n raise ValueError(f\"Invalid setup mode: {self.setup_mode}\")\n\n if isinstance(self.embedding, dict):\n embedding_dict = {\"embedding\": self.embedding}\n else:\n embedding_dict = self.embedding.to_dict()\n vector_store_kwargs = {\n **embedding_dict,\n \"collection_name\": self.collection_name,\n \"token\": self.token,\n \"api_endpoint\": self.api_endpoint,\n \"namespace\": self.namespace or None,\n \"metric\": self.metric or None,\n \"batch_size\": self.batch_size or None,\n \"bulk_insert_batch_concurrency\": self.bulk_insert_batch_concurrency or None,\n \"bulk_insert_overwrite_concurrency\": self.bulk_insert_overwrite_concurrency or None,\n \"bulk_delete_concurrency\": self.bulk_delete_concurrency or None,\n \"setup_mode\": setup_mode_value,\n \"pre_delete_collection\": self.pre_delete_collection or False,\n }\n\n if self.metadata_indexing_include:\n vector_store_kwargs[\"metadata_indexing_include\"] = self.metadata_indexing_include\n elif self.metadata_indexing_exclude:\n vector_store_kwargs[\"metadata_indexing_exclude\"] = self.metadata_indexing_exclude\n elif self.collection_indexing_policy:\n vector_store_kwargs[\"collection_indexing_policy\"] = self.collection_indexing_policy\n\n try:\n vector_store = AstraDBVectorStore(**vector_store_kwargs)\n except Exception as e:\n raise ValueError(f\"Error initializing AstraDBVectorStore: {str(e)}\") from e\n\n if self.add_to_vector_store:\n self._add_documents_to_vector_store(vector_store)\n\n return vector_store\n\n def build_base_retriever(self):\n vector_store = self.build_vector_store()\n self.status = self._astradb_collection_to_data(vector_store.collection)\n return vector_store\n\n def _add_documents_to_vector_store(self, vector_store):\n documents = []\n for _input in self.vector_store_inputs or []:\n if isinstance(_input, Data):\n documents.append(_input.to_lc_document())\n else:\n raise ValueError(\"Vector Store Inputs must be Data objects.\")\n\n if documents and self.embedding is not None:\n logger.debug(f\"Adding {len(documents)} documents to the Vector Store.\")\n try:\n vector_store.add_documents(documents)\n except Exception as e:\n raise ValueError(f\"Error adding documents to AstraDBVectorStore: {str(e)}\") from e\n else:\n logger.debug(\"No documents to add to the Vector Store.\")\n\n def search_documents(self):\n vector_store = self.build_vector_store()\n\n logger.debug(f\"Search input: {self.search_input}\")\n logger.debug(f\"Search type: {self.search_type}\")\n logger.debug(f\"Number of results: {self.number_of_results}\")\n\n if self.search_input and isinstance(self.search_input, str) and self.search_input.strip():\n try:\n if self.search_type == \"Similarity\":\n docs = vector_store.similarity_search(\n query=self.search_input,\n k=self.number_of_results,\n )\n elif self.search_type == \"MMR\":\n docs = vector_store.max_marginal_relevance_search(\n query=self.search_input,\n k=self.number_of_results,\n )\n else:\n raise ValueError(f\"Invalid search type: {self.search_type}\")\n except Exception as e:\n raise ValueError(f\"Error performing search in AstraDBVectorStore: {str(e)}\") from e\n\n logger.debug(f\"Retrieved documents: {len(docs)}\")\n\n data = [Data.from_document(doc) for doc in docs]\n logger.debug(f\"Converted documents to data: {len(data)}\")\n self.status = data\n return data\n else:\n logger.debug(\"No search input provided. Skipping search.\")\n return []\n\n def _astradb_collection_to_data(self, collection):\n data = []\n data_dict = collection.find()\n if data_dict and \"data\" in data_dict:\n data_dict = data_dict[\"data\"].get(\"documents\", [])\n\n for item in data_dict:\n data.append(Data(content=item[\"content\"]))\n return data\n" - }, - "collection_indexing_policy": { - "advanced": true, - "display_name": "Collection Indexing Policy", - "dynamic": false, - "info": "Optional dictionary defining the indexing policy for the collection.", - "list": false, - "load_from_db": false, - "name": "collection_indexing_policy", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "collection_name": { - "advanced": false, - "display_name": "Collection Name", - "dynamic": false, - "info": "The name of the collection within Astra DB where the vectors will be stored.", - "list": false, - "load_from_db": false, - "name": "collection_name", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "langflow" - }, - "embedding": { - "advanced": false, - "display_name": "Embedding", - "dynamic": false, - "info": "", - "input_types": ["Embeddings", "dict"], - "list": false, - "name": "embedding", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "other", - "value": "" - }, - "metadata_indexing_exclude": { - "advanced": true, - "display_name": "Metadata Indexing Exclude", - "dynamic": false, - "info": "Optional list of metadata fields to exclude from the indexing.", - "list": false, - "load_from_db": false, - "name": "metadata_indexing_exclude", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "metadata_indexing_include": { - "advanced": true, - "display_name": "Metadata Indexing Include", - "dynamic": false, - "info": "Optional list of metadata fields to include in the indexing.", - "list": false, - "load_from_db": false, - "name": "metadata_indexing_include", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "metric": { - "advanced": true, - "display_name": "Metric", - "dynamic": false, - "info": "Optional distance metric for vector comparisons in the vector store.", - "name": "metric", - "options": ["cosine", "dot_product", "euclidean"], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "namespace": { - "advanced": true, - "display_name": "Namespace", - "dynamic": false, - "info": "Optional namespace within Astra DB to use for the collection.", - "list": false, - "load_from_db": false, - "name": "namespace", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "number_of_results": { - "advanced": true, - "display_name": "Number of Results", - "dynamic": false, - "info": "Number of results to return.", - "list": false, - "name": "number_of_results", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": 4 - }, - "pre_delete_collection": { - "advanced": true, - "display_name": "Pre Delete Collection", - "dynamic": false, - "info": "Boolean flag to determine whether to delete the collection before creating a new one.", - "list": false, - "name": "pre_delete_collection", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "bool", - "value": false - }, - "search_input": { - "advanced": false, - "display_name": "Search Input", - "dynamic": false, - "info": "", - "input_types": ["Message", "str"], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "search_input", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "search_type": { - "advanced": false, - "display_name": "Search Type", - "dynamic": false, - "info": "", - "name": "search_type", - "options": ["Similarity", "MMR"], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "Similarity" - }, - "setup_mode": { - "advanced": true, - "display_name": "Setup Mode", - "dynamic": false, - "info": "Configuration mode for setting up the vector store, with options like 'Sync', 'Async', or 'Off'.", - "name": "setup_mode", - "options": ["Sync", "Async", "Off"], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "Sync" - }, - "token": { - "advanced": false, - "display_name": "Astra DB Application Token", - "dynamic": false, - "info": "Authentication token for accessing Astra DB.", - "input_types": [], - "load_from_db": true, - "name": "token", - "password": true, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "ASTRA_DB_APPLICATION_TOKEN" - }, - "vector_store_inputs": { - "advanced": false, - "display_name": "Vector Store Inputs", - "dynamic": false, - "info": "", - "input_types": ["Data"], - "list": true, - "name": "vector_store_inputs", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "other", - "value": "" - } - } - }, - "type": "AstraDB" - }, - "dragging": false, - "height": 917, - "id": "AstraDB-rXo8b", - "position": { - "x": 3329.7211874614477, - "y": 1559.774393811144 - }, - "positionAbsolute": { - "x": 3329.7211874614477, - "y": 1559.774393811144 - }, - "selected": true, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "description": "Implementation of Vector Store using Astra DB with search capabilities", - "display_name": "Astra DB Vector Store", - "id": "AstraDB-61WgV", - "node": { - "base_classes": ["Data"], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Implementation of Vector Store using Astra DB with search capabilities", - "display_name": "Astra DB Vector Store", - "documentation": "https://python.langchain.com/docs/integrations/vectorstores/astradb", - "edited": false, - "field_order": [ - "collection_name", - "token", - "api_endpoint", - "vector_store_inputs", - "embedding", - "namespace", - "metric", - "batch_size", - "bulk_insert_batch_concurrency", - "bulk_insert_overwrite_concurrency", - "bulk_delete_concurrency", - "setup_mode", - "pre_delete_collection", - "metadata_indexing_include", - "metadata_indexing_exclude", - "collection_indexing_policy", - "add_to_vector_store", - "search_input", - "search_type", - "number_of_results" - ], - "frozen": false, - "icon": "AstraDB", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Retriever", - "method": "build_base_retriever", - "name": "base_retriever", - "selected": "Data", - "types": ["Data"], - "value": "__UNDEFINED__" - }, - { - "cache": true, - "display_name": "Search Results", - "method": "search_documents", - "name": "search_results", - "selected": "Data", - "types": ["Data"], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "add_to_vector_store": { - "advanced": false, - "display_name": "Add to Vector Store", - "dynamic": false, - "info": "If true, the Vector Store Inputs will be added to the Vector Store.", - "list": false, - "name": "add_to_vector_store", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "bool", - "value": true - }, - "api_endpoint": { - "advanced": false, - "display_name": "API Endpoint", - "dynamic": false, - "info": "API endpoint URL for the Astra DB service.", - "input_types": [], - "load_from_db": true, - "name": "api_endpoint", - "password": true, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "ASTRA_DB_API_ENDPOINT" - }, - "batch_size": { - "advanced": true, - "display_name": "Batch Size", - "dynamic": false, - "info": "Optional number of data to process in a single batch.", - "list": false, - "name": "batch_size", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": "" - }, - "bulk_delete_concurrency": { - "advanced": true, - "display_name": "Bulk Delete Concurrency", - "dynamic": false, - "info": "Optional concurrency level for bulk delete operations.", - "list": false, - "name": "bulk_delete_concurrency", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": "" - }, - "bulk_insert_batch_concurrency": { - "advanced": true, - "display_name": "Bulk Insert Batch Concurrency", - "dynamic": false, - "info": "Optional concurrency level for bulk insert operations.", - "list": false, - "name": "bulk_insert_batch_concurrency", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": "" - }, - "bulk_insert_overwrite_concurrency": { - "advanced": true, - "display_name": "Bulk Insert Overwrite Concurrency", - "dynamic": false, - "info": "Optional concurrency level for bulk insert operations that overwrite existing data.", - "list": false, - "name": "bulk_insert_overwrite_concurrency", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": "" - }, - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from loguru import logger\n\nfrom langflow.base.vectorstores.model import LCVectorStoreComponent\nfrom langflow.io import BoolInput, DropdownInput, HandleInput, IntInput, MultilineInput, SecretStrInput, StrInput, DataInput\nfrom langflow.schema import Data\n\n\nclass AstraVectorStoreComponent(LCVectorStoreComponent):\n display_name: str = \"Astra DB Vector Store\"\n description: str = \"Implementation of Vector Store using Astra DB with search capabilities\"\n documentation: str = \"https://python.langchain.com/docs/integrations/vectorstores/astradb\"\n icon: str = \"AstraDB\"\n\n inputs = [\n StrInput(\n name=\"collection_name\",\n display_name=\"Collection Name\",\n info=\"The name of the collection within Astra DB where the vectors will be stored.\",\n ),\n SecretStrInput(\n name=\"token\",\n display_name=\"Astra DB Application Token\",\n info=\"Authentication token for accessing Astra DB.\",\n value=\"ASTRA_DB_APPLICATION_TOKEN\",\n ),\n SecretStrInput(\n name=\"api_endpoint\",\n display_name=\"API Endpoint\",\n info=\"API endpoint URL for the Astra DB service.\",\n value=\"ASTRA_DB_API_ENDPOINT\",\n ),\n DataInput(\n name=\"vector_store_inputs\",\n display_name=\"Vector Store Inputs\",\n is_list=True,\n ),\n HandleInput(\n name=\"embedding\",\n display_name=\"Embedding\",\n input_types=[\"Embeddings\", \"dict\"],\n ),\n StrInput(\n name=\"namespace\",\n display_name=\"Namespace\",\n info=\"Optional namespace within Astra DB to use for the collection.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"metric\",\n display_name=\"Metric\",\n info=\"Optional distance metric for vector comparisons in the vector store.\",\n options=[\"cosine\", \"dot_product\", \"euclidean\"],\n advanced=True,\n ),\n IntInput(\n name=\"batch_size\",\n display_name=\"Batch Size\",\n info=\"Optional number of data to process in a single batch.\",\n advanced=True,\n ),\n IntInput(\n name=\"bulk_insert_batch_concurrency\",\n display_name=\"Bulk Insert Batch Concurrency\",\n info=\"Optional concurrency level for bulk insert operations.\",\n advanced=True,\n ),\n IntInput(\n name=\"bulk_insert_overwrite_concurrency\",\n display_name=\"Bulk Insert Overwrite Concurrency\",\n info=\"Optional concurrency level for bulk insert operations that overwrite existing data.\",\n advanced=True,\n ),\n IntInput(\n name=\"bulk_delete_concurrency\",\n display_name=\"Bulk Delete Concurrency\",\n info=\"Optional concurrency level for bulk delete operations.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"setup_mode\",\n display_name=\"Setup Mode\",\n info=\"Configuration mode for setting up the vector store, with options like 'Sync', 'Async', or 'Off'.\",\n options=[\"Sync\", \"Async\", \"Off\"],\n advanced=True,\n value=\"Sync\",\n ),\n BoolInput(\n name=\"pre_delete_collection\",\n display_name=\"Pre Delete Collection\",\n info=\"Boolean flag to determine whether to delete the collection before creating a new one.\",\n advanced=True,\n ),\n StrInput(\n name=\"metadata_indexing_include\",\n display_name=\"Metadata Indexing Include\",\n info=\"Optional list of metadata fields to include in the indexing.\",\n advanced=True,\n ),\n StrInput(\n name=\"metadata_indexing_exclude\",\n display_name=\"Metadata Indexing Exclude\",\n info=\"Optional list of metadata fields to exclude from the indexing.\",\n advanced=True,\n ),\n StrInput(\n name=\"collection_indexing_policy\",\n display_name=\"Collection Indexing Policy\",\n info=\"Optional dictionary defining the indexing policy for the collection.\",\n advanced=True,\n ),\n BoolInput(\n name=\"add_to_vector_store\",\n display_name=\"Add to Vector Store\",\n info=\"If true, the Vector Store Inputs will be added to the Vector Store.\",\n ),\n MultilineInput(\n name=\"search_input\",\n display_name=\"Search Input\",\n ),\n DropdownInput(\n name=\"search_type\",\n display_name=\"Search Type\",\n options=[\"Similarity\", \"MMR\"],\n value=\"Similarity\",\n ),\n IntInput(\n name=\"number_of_results\",\n display_name=\"Number of Results\",\n info=\"Number of results to return.\",\n advanced=True,\n value=4,\n ),\n ]\n\n def build_vector_store(self):\n try:\n from langchain_astradb import AstraDBVectorStore\n from langchain_astradb.utils.astradb import SetupMode\n except ImportError:\n raise ImportError(\n \"Could not import langchain Astra DB integration package. \"\n \"Please install it with `pip install langchain-astradb`.\"\n )\n\n try:\n if not self.setup_mode:\n self.setup_mode = self._inputs[\"setup_mode\"].options[0]\n\n setup_mode_value = SetupMode[self.setup_mode.upper()]\n except KeyError:\n raise ValueError(f\"Invalid setup mode: {self.setup_mode}\")\n\n if isinstance(self.embedding, dict):\n embedding_dict = {\"embedding\": self.embedding}\n else:\n embedding_dict = self.embedding.to_dict()\n vector_store_kwargs = {\n **embedding_dict,\n \"collection_name\": self.collection_name,\n \"token\": self.token,\n \"api_endpoint\": self.api_endpoint,\n \"namespace\": self.namespace or None,\n \"metric\": self.metric or None,\n \"batch_size\": self.batch_size or None,\n \"bulk_insert_batch_concurrency\": self.bulk_insert_batch_concurrency or None,\n \"bulk_insert_overwrite_concurrency\": self.bulk_insert_overwrite_concurrency or None,\n \"bulk_delete_concurrency\": self.bulk_delete_concurrency or None,\n \"setup_mode\": setup_mode_value,\n \"pre_delete_collection\": self.pre_delete_collection or False,\n }\n\n if self.metadata_indexing_include:\n vector_store_kwargs[\"metadata_indexing_include\"] = self.metadata_indexing_include\n elif self.metadata_indexing_exclude:\n vector_store_kwargs[\"metadata_indexing_exclude\"] = self.metadata_indexing_exclude\n elif self.collection_indexing_policy:\n vector_store_kwargs[\"collection_indexing_policy\"] = self.collection_indexing_policy\n\n try:\n vector_store = AstraDBVectorStore(**vector_store_kwargs)\n except Exception as e:\n raise ValueError(f\"Error initializing AstraDBVectorStore: {str(e)}\") from e\n\n if self.add_to_vector_store:\n self._add_documents_to_vector_store(vector_store)\n\n return vector_store\n\n def build_base_retriever(self):\n vector_store = self.build_vector_store()\n self.status = self._astradb_collection_to_data(vector_store.collection)\n return vector_store\n\n def _add_documents_to_vector_store(self, vector_store):\n documents = []\n for _input in self.vector_store_inputs or []:\n if isinstance(_input, Data):\n documents.append(_input.to_lc_document())\n else:\n raise ValueError(\"Vector Store Inputs must be Data objects.\")\n\n if documents and self.embedding is not None:\n logger.debug(f\"Adding {len(documents)} documents to the Vector Store.\")\n try:\n vector_store.add_documents(documents)\n except Exception as e:\n raise ValueError(f\"Error adding documents to AstraDBVectorStore: {str(e)}\") from e\n else:\n logger.debug(\"No documents to add to the Vector Store.\")\n\n def search_documents(self):\n vector_store = self.build_vector_store()\n\n logger.debug(f\"Search input: {self.search_input}\")\n logger.debug(f\"Search type: {self.search_type}\")\n logger.debug(f\"Number of results: {self.number_of_results}\")\n\n if self.search_input and isinstance(self.search_input, str) and self.search_input.strip():\n try:\n if self.search_type == \"Similarity\":\n docs = vector_store.similarity_search(\n query=self.search_input,\n k=self.number_of_results,\n )\n elif self.search_type == \"MMR\":\n docs = vector_store.max_marginal_relevance_search(\n query=self.search_input,\n k=self.number_of_results,\n )\n else:\n raise ValueError(f\"Invalid search type: {self.search_type}\")\n except Exception as e:\n raise ValueError(f\"Error performing search in AstraDBVectorStore: {str(e)}\") from e\n\n logger.debug(f\"Retrieved documents: {len(docs)}\")\n\n data = [Data.from_document(doc) for doc in docs]\n logger.debug(f\"Converted documents to data: {len(data)}\")\n self.status = data\n return data\n else:\n logger.debug(\"No search input provided. Skipping search.\")\n return []\n\n def _astradb_collection_to_data(self, collection):\n data = []\n data_dict = collection.find()\n if data_dict and \"data\" in data_dict:\n data_dict = data_dict[\"data\"].get(\"documents\", [])\n\n for item in data_dict:\n data.append(Data(content=item[\"content\"]))\n return data\n" - }, - "collection_indexing_policy": { - "advanced": true, - "display_name": "Collection Indexing Policy", - "dynamic": false, - "info": "Optional dictionary defining the indexing policy for the collection.", - "list": false, - "load_from_db": false, - "name": "collection_indexing_policy", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "collection_name": { - "advanced": false, - "display_name": "Collection Name", - "dynamic": false, - "info": "The name of the collection within Astra DB where the vectors will be stored.", - "list": false, - "load_from_db": false, - "name": "collection_name", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "langflow" - }, - "embedding": { - "advanced": false, - "display_name": "Embedding", - "dynamic": false, - "info": "", - "input_types": ["Embeddings", "dict"], - "list": false, - "name": "embedding", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "other", - "value": "" - }, - "metadata_indexing_exclude": { - "advanced": true, - "display_name": "Metadata Indexing Exclude", - "dynamic": false, - "info": "Optional list of metadata fields to exclude from the indexing.", - "list": false, - "load_from_db": false, - "name": "metadata_indexing_exclude", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "metadata_indexing_include": { - "advanced": true, - "display_name": "Metadata Indexing Include", - "dynamic": false, - "info": "Optional list of metadata fields to include in the indexing.", - "list": false, - "load_from_db": false, - "name": "metadata_indexing_include", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "metric": { - "advanced": true, - "display_name": "Metric", - "dynamic": false, - "info": "Optional distance metric for vector comparisons in the vector store.", - "name": "metric", - "options": ["cosine", "dot_product", "euclidean"], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "namespace": { - "advanced": true, - "display_name": "Namespace", - "dynamic": false, - "info": "Optional namespace within Astra DB to use for the collection.", - "list": false, - "load_from_db": false, - "name": "namespace", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "number_of_results": { - "advanced": true, - "display_name": "Number of Results", - "dynamic": false, - "info": "Number of results to return.", - "list": false, - "name": "number_of_results", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "int", - "value": 4 - }, - "pre_delete_collection": { - "advanced": true, - "display_name": "Pre Delete Collection", - "dynamic": false, - "info": "Boolean flag to determine whether to delete the collection before creating a new one.", - "list": false, - "name": "pre_delete_collection", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "bool", - "value": false - }, - "search_input": { - "advanced": false, - "display_name": "Search Input", - "dynamic": false, - "info": "", - "input_types": ["Message", "str"], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "search_input", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "search_type": { - "advanced": false, - "display_name": "Search Type", - "dynamic": false, - "info": "", - "name": "search_type", - "options": ["Similarity", "MMR"], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "Similarity" - }, - "setup_mode": { - "advanced": true, - "display_name": "Setup Mode", - "dynamic": false, - "info": "Configuration mode for setting up the vector store, with options like 'Sync', 'Async', or 'Off'.", - "name": "setup_mode", - "options": ["Sync", "Async", "Off"], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "Sync" - }, - "token": { - "advanced": false, - "display_name": "Astra DB Application Token", - "dynamic": false, - "info": "Authentication token for accessing Astra DB.", - "input_types": [], - "load_from_db": true, - "name": "token", - "password": true, - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "ASTRA_DB_APPLICATION_TOKEN" - }, - "vector_store_inputs": { - "advanced": false, - "display_name": "Vector Store Inputs", - "dynamic": false, - "info": "", - "input_types": ["Data"], - "list": true, - "name": "vector_store_inputs", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "other", - "value": "" - } - } - }, - "type": "AstraDB" - }, - "dragging": false, - "height": 917, - "id": "AstraDB-61WgV", - "position": { - "x": 1298.4611042465333, - "y": 160.7181472642742 - }, - "positionAbsolute": { - "x": 1298.4611042465333, - "y": 160.7181472642742 - }, - "selected": false, - "type": "genericNode", - "width": 384 - }, - { - "data": { - "id": "ParseData-DXlFW", - "node": { - "base_classes": ["Message"], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Convert Data into plain text following a specified template.", - "display_name": "Parse Data", - "documentation": "", - "field_order": ["data", "template", "sep"], - "frozen": false, - "icon": "braces", - "output_types": [], - "outputs": [ - { - "cache": true, - "display_name": "Text", - "method": "parse_data", - "name": "text", - "selected": "Message", - "types": ["Message"], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Parse Data\"\n description = \"Convert Data into plain text following a specified template.\"\n icon = \"braces\"\n\n inputs = [\n DataInput(name=\"data\", display_name=\"Data\", info=\"The data to convert to text.\"),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(display_name=\"Text\", name=\"text\", method=\"parse_data\"),\n ]\n\n def parse_data(self) -> Message:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n\n result_string = data_to_text(template, data, sep=self.sep)\n self.status = result_string\n return Message(text=result_string)\n" - }, - "data": { - "advanced": false, - "display_name": "Data", - "dynamic": false, - "info": "The data to convert to text.", - "input_types": ["Data"], - "list": false, - "name": "data", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "other", - "value": "" - }, - "sep": { - "advanced": true, - "display_name": "Separator", - "dynamic": false, - "info": "", - "list": false, - "load_from_db": false, - "name": "sep", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "---" - }, - "template": { - "advanced": false, - "display_name": "Template", - "dynamic": false, - "info": "The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.", - "input_types": ["Message", "str"], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "template", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "{text}" - } - } - }, - "type": "ParseData" - }, - "dragging": false, - "height": 385, - "id": "ParseData-DXlFW", - "position": { - "x": 1911.4866480237615, - "y": 566.903831987901 - }, - "positionAbsolute": { - "x": 1911.4866480237615, - "y": 566.903831987901 + "x": 2050.0569098721217, + "y": 1823.5240486490072 }, "selected": false, "type": "genericNode", @@ -2997,15 +3161,15 @@ } ], "viewport": { - "x": -145.46470046912816, - "y": 67.11009748758056, - "zoom": 0.2936356220661912 + "x": -108.04801490857153, + "y": -44.38043074355511, + "zoom": 0.32281188532359256 } }, - "description": "Visit https://pre-release.langflow.org/tutorials/rag-with-astradb for a detailed guide of this project.\nThis project give you both Ingestion and RAG in a single file. You'll need to visit https://astra.datastax.com/ to create an Astra DB instance, your Token and grab an API Endpoint.\nRunning this project requires you to add a file in the Files component, then define a Collection Name and click on the Play icon on the Astra DB component. \n\nAfter the ingestion ends you are ready to click on the Run button at the lower left corner and start asking questions about your data.", - "endpoint_name": "None-2", - "id": "0433f955-c8cc-4d24-a2bf-e8cd0d11f99c", + "description": "Visit https://docs.langflow.org/tutorials/rag-with-astradb for a detailed guide of this project.\nThis project give you both Ingestion and RAG in a single file. You'll need to visit https://astra.datastax.com/ to create an Astra DB instance, your Token and grab an API Endpoint.\nRunning this project requires you to add a file in the Files component, then define a Collection Name and click on the Play icon on the Astra DB component. \n\nAfter the ingestion ends you are ready to click on the Run button at the lower left corner and start asking questions about your data.", + "endpoint_name": null, + "id": "7804e4a4-8e16-45e0-88ab-ed6248daa0eb", "is_component": false, - "last_tested_version": "1.0.0a59", + "last_tested_version": "1.0.0rc1", "name": "Vector Store RAG" -} +} \ No newline at end of file diff --git a/src/backend/base/langflow/main.py b/src/backend/base/langflow/main.py index 45a681ff5..5eab2f331 100644 --- a/src/backend/base/langflow/main.py +++ b/src/backend/base/langflow/main.py @@ -6,7 +6,7 @@ from typing import Optional from urllib.parse import urlencode import nest_asyncio # type: ignore -from fastapi import FastAPI, Request +from fastapi import FastAPI, Request, Response from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import FileResponse from fastapi.staticfiles import StaticFiles @@ -32,37 +32,31 @@ from langflow.utils.logger import configure warnings.filterwarnings("ignore", category=PydanticDeprecatedSince20) -class RequestCancelledMiddleware: +class RequestCancelledMiddleware(BaseHTTPMiddleware): def __init__(self, app): - self.app = app - - async def __call__(self, scope, receive, send): - if scope["type"] != "http": - await self.app(scope, receive, send) - return - - # Let's make a shared queue for the request messages - queue = asyncio.Queue() - - async def message_poller(sentinel, handler_task): - nonlocal queue - while True: - message = await receive() - if message["type"] == "http.disconnect": - handler_task.cancel() - return sentinel # Break the loop - - # Puts the message in the queue - await queue.put(message) + super().__init__(app) + async def dispatch(self, request: Request, call_next): sentinel = object() - handler_task = asyncio.create_task(self.app(scope, queue.get, send)) - asyncio.create_task(message_poller(sentinel, handler_task)) - try: + async def cancel_handler(): + while True: + if await request.is_disconnected(): + return sentinel + await asyncio.sleep(0.1) + + handler_task = asyncio.create_task(call_next(request)) + cancel_task = asyncio.create_task(cancel_handler()) + + done, pending = await asyncio.wait([handler_task, cancel_task], return_when=asyncio.FIRST_COMPLETED) + + for task in pending: + task.cancel() + + if cancel_task in done: + return Response("Request was cancelled", status_code=499) + else: return await handler_task - except asyncio.CancelledError: - pass class JavaScriptMIMETypeMiddleware(BaseHTTPMiddleware): @@ -130,7 +124,8 @@ def create_app(): allow_headers=["*"], ) app.add_middleware(JavaScriptMIMETypeMiddleware) - app.add_middleware(RequestCancelledMiddleware) + # ! Deactivating this until we find a better solution + # app.add_middleware(RequestCancelledMiddleware) @app.middleware("http") async def flatten_query_string_lists(request: Request, call_next): diff --git a/src/backend/base/langflow/memory.py b/src/backend/base/langflow/memory.py index e89682969..f052acdee 100644 --- a/src/backend/base/langflow/memory.py +++ b/src/backend/base/langflow/memory.py @@ -1,20 +1,24 @@ import warnings -from typing import List, Optional +from uuid import UUID from loguru import logger +from sqlalchemy import delete +from sqlmodel import Session, col, select from langflow.schema.message import Message -from langflow.services.deps import get_monitor_service -from langflow.services.monitor.schema import MessageModel +from langflow.services.database.models.message.model import MessageRead, MessageTable +from langflow.services.database.utils import migrate_messages_from_monitor_service_to_database +from langflow.services.deps import session_scope def get_messages( - sender: Optional[str] = None, - sender_name: Optional[str] = None, - session_id: Optional[str] = None, - order_by: Optional[str] = "timestamp", - order: Optional[str] = "DESC", - limit: Optional[int] = None, + sender: str | None = None, + sender_name: str | None = None, + session_id: str | None = None, + order_by: str | None = "timestamp", + order: str | None = "DESC", + flow_id: UUID | None = None, + limit: int | None = None, ): """ Retrieves messages from the monitor service based on the provided filters. @@ -29,42 +33,38 @@ def get_messages( Returns: List[Data]: A list of Data objects representing the retrieved messages. """ - monitor_service = get_monitor_service() - messages_df = monitor_service.get_messages( - sender=sender, - sender_name=sender_name, - session_id=session_id, - order_by=order_by, - limit=limit, - order=order, - ) + with session_scope() as session: + migrate_messages_from_monitor_service_to_database(session) + messages_read: list[Message] = [] + with session_scope() as session: + stmt = select(MessageTable) + if sender: + stmt = stmt.where(MessageTable.sender == sender) + if sender_name: + stmt = stmt.where(MessageTable.sender_name == sender_name) + if session_id: + stmt = stmt.where(MessageTable.session_id == session_id) + if flow_id: + stmt = stmt.where(MessageTable.flow_id == flow_id) + if order_by: + if order == "DESC": + col = getattr(MessageTable, order_by).desc() + else: + col = getattr(MessageTable, order_by).asc() + stmt = stmt.order_by(col) + if limit: + stmt = stmt.limit(limit) + messages = session.exec(stmt) + messages_read = [Message(**d.model_dump()) for d in messages] - messages: list[Message] = [] - # messages_df has a timestamp - # it gets the last 5 messages, for example - # but now they are ordered from most recent to least recent - # so we need to reverse the order - messages_df = messages_df[::-1] if order == "DESC" else messages_df - for row in messages_df.itertuples(): - msg = Message( - text=row.text, - sender=row.sender, - session_id=row.session_id, - sender_name=row.sender_name, - timestamp=row.timestamp, - ) - - messages.append(msg) - - return messages + return messages_read -def add_messages(messages: Message | list[Message], flow_id: Optional[str] = None): +def add_messages(messages: Message | list[Message], flow_id: str | None = None): """ Add a message to the monitor service. """ try: - monitor_service = get_monitor_service() if not isinstance(messages, list): messages = [messages] @@ -72,25 +72,29 @@ def add_messages(messages: Message | list[Message], flow_id: Optional[str] = Non types = ", ".join([str(type(message)) for message in messages]) raise ValueError(f"The messages must be instances of Message. Found: {types}") - messages_models: list[MessageModel] = [] + messages_models: list[MessageTable] = [] for msg in messages: - if not msg.timestamp: - msg.timestamp = monitor_service.get_timestamp() - messages_models.append(MessageModel.from_message(msg, flow_id=flow_id)) - - for message_model in messages_models: - try: - monitor_service.add_message(message_model) - except Exception as e: - logger.error(f"Error adding message to monitor service: {e}") - logger.exception(e) - raise e - return messages_models + messages_models.append(MessageTable.from_message(msg, flow_id=flow_id)) + with session_scope() as session: + messages_models = add_messagetables(messages_models, session) + return [Message(**message.model_dump()) for message in messages_models] except Exception as e: logger.exception(e) raise e +def add_messagetables(messages: list[MessageTable], session: Session): + for message in messages: + try: + session.add(message) + session.commit() + session.refresh(message) + except Exception as e: + logger.exception(e) + raise e + return [MessageRead.model_validate(message, from_attributes=True) for message in messages] + + def delete_messages(session_id: str): """ Delete messages from the monitor service based on the provided session ID. @@ -98,14 +102,19 @@ def delete_messages(session_id: str): Args: session_id (str): The session ID associated with the messages to delete. """ - monitor_service = get_monitor_service() - monitor_service.delete_messages_session(session_id) + with session_scope() as session: + session.exec( + delete(MessageTable) + .where(col(MessageTable.session_id) == session_id) + .execution_options(synchronize_session="fetch") + ) + session.commit() def store_message( message: Message, - flow_id: Optional[str] = None, -) -> List[Message]: + flow_id: str | None = None, +) -> list[Message]: """ Stores a message in the memory. diff --git a/src/backend/base/langflow/schema/message.py b/src/backend/base/langflow/schema/message.py index c50dab880..5ad7d1922 100644 --- a/src/backend/base/langflow/schema/message.py +++ b/src/backend/base/langflow/schema/message.py @@ -1,5 +1,6 @@ from datetime import datetime, timezone from typing import Annotated, Any, AsyncIterator, Iterator, List, Optional +from uuid import UUID from fastapi.encoders import jsonable_encoder from langchain_core.load import load @@ -31,7 +32,20 @@ class Message(Data): timestamp: Annotated[str, BeforeValidator(_timestamp_to_str)] = Field( default=datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S") ) - flow_id: Optional[str] = None + flow_id: Optional[str | UUID] = None + + @field_validator("flow_id", mode="before") + @classmethod + def validate_flow_id(cls, value): + if isinstance(value, UUID): + value = str(value) + return value + + @field_serializer("flow_id") + def serialize_flow_id(value): + if isinstance(value, str): + return UUID(value) + return value @field_validator("files", mode="before") @classmethod diff --git a/src/backend/base/langflow/services/auth/utils.py b/src/backend/base/langflow/services/auth/utils.py index b0a35e474..4c2fdbfb4 100644 --- a/src/backend/base/langflow/services/auth/utils.py +++ b/src/backend/base/langflow/services/auth/utils.py @@ -164,15 +164,15 @@ async def get_current_user_for_websocket( def get_current_active_user(current_user: Annotated[User, Depends(get_current_user)]): if not current_user.is_active: - raise HTTPException(status_code=400, detail="Inactive user") + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Inactive user") return current_user def get_current_active_superuser(current_user: Annotated[User, Depends(get_current_user)]) -> User: if not current_user.is_active: - raise HTTPException(status_code=401, detail="Inactive user") + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Inactive user") if not current_user.is_superuser: - raise HTTPException(status_code=400, detail="The user doesn't have enough privileges") + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="The user doesn't have enough privileges") return current_user @@ -324,8 +324,8 @@ def authenticate_user(username: str, password: str, db: Session = Depends(get_se if not user.is_active: if not user.last_login_at: - raise HTTPException(status_code=400, detail="Waiting for approval") - raise HTTPException(status_code=400, detail="Inactive user") + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Waiting for approval") + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Inactive user") return user if verify_password(password, user.password) else None diff --git a/src/backend/base/langflow/services/database/models/__init__.py b/src/backend/base/langflow/services/database/models/__init__.py index ce12a6fce..6e1f09fe3 100644 --- a/src/backend/base/langflow/services/database/models/__init__.py +++ b/src/backend/base/langflow/services/database/models/__init__.py @@ -1,7 +1,8 @@ from .api_key import ApiKey from .flow import Flow from .folder import Folder +from .message import MessageTable from .user import User from .variable import Variable -__all__ = ["Flow", "User", "ApiKey", "Variable", "Folder"] +__all__ = ["Flow", "User", "ApiKey", "Variable", "Folder", "MessageTable"] diff --git a/src/backend/base/langflow/services/database/models/flow/model.py b/src/backend/base/langflow/services/database/models/flow/model.py index 624ea0543..6d3e4aea8 100644 --- a/src/backend/base/langflow/services/database/models/flow/model.py +++ b/src/backend/base/langflow/services/database/models/flow/model.py @@ -3,7 +3,7 @@ import re import warnings from datetime import datetime, timezone -from typing import TYPE_CHECKING, Dict, Optional +from typing import TYPE_CHECKING, Dict, List, Optional from uuid import UUID, uuid4 import emoji @@ -17,6 +17,7 @@ from langflow.schema import Data if TYPE_CHECKING: from langflow.services.database.models.folder import Folder + from langflow.services.database.models.message import MessageTable from langflow.services.database.models.user import User @@ -141,6 +142,7 @@ class Flow(FlowBase, table=True): user: "User" = Relationship(back_populates="flows") folder_id: Optional[UUID] = Field(default=None, foreign_key="folder.id", nullable=True, index=True) folder: Optional["Folder"] = Relationship(back_populates="flows") + messages: List["MessageTable"] = Relationship(back_populates="flow") def to_data(self): serialized = self.model_dump() diff --git a/src/backend/base/langflow/services/database/models/message/__init__.py b/src/backend/base/langflow/services/database/models/message/__init__.py new file mode 100644 index 000000000..8cfb2ff4f --- /dev/null +++ b/src/backend/base/langflow/services/database/models/message/__init__.py @@ -0,0 +1,3 @@ +from .model import MessageTable, MessageCreate, MessageRead, MessageUpdate + +__all__ = ["MessageTable", "MessageCreate", "MessageRead", "MessageUpdate"] diff --git a/src/backend/base/langflow/services/database/models/message/model.py b/src/backend/base/langflow/services/database/models/message/model.py new file mode 100644 index 000000000..7c0b9dc8f --- /dev/null +++ b/src/backend/base/langflow/services/database/models/message/model.py @@ -0,0 +1,85 @@ +from datetime import datetime, timezone +from typing import TYPE_CHECKING, List, Optional +from uuid import UUID, uuid4 + +from pydantic import field_validator +from sqlmodel import JSON, Column, Field, Relationship, SQLModel + +if TYPE_CHECKING: + from langflow.schema.message import Message + from langflow.services.database.models.flow.model import Flow + + +class MessageBase(SQLModel): + timestamp: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) + sender: str + sender_name: str + session_id: str + text: str + files: list[str] = Field(default_factory=list) + + @field_validator("files", mode="before") + @classmethod + def validate_files(cls, value): + if not value: + value = [] + return value + + @classmethod + def from_message(cls, message: "Message", flow_id: str | UUID | None = None): + # first check if the record has all the required fields + if message.text is None or not message.sender or not message.sender_name: + raise ValueError("The message does not have the required fields (text, sender, sender_name).") + if isinstance(message.timestamp, str): + timestamp = datetime.fromisoformat(message.timestamp) + else: + timestamp = message.timestamp + if not flow_id and message.flow_id: + flow_id = message.flow_id + return cls( + sender=message.sender, + sender_name=message.sender_name, + text=message.text, + session_id=message.session_id, + files=message.files or [], + timestamp=timestamp, + flow_id=flow_id, + ) + + +class MessageTable(MessageBase, table=True): + __tablename__ = "message" + id: UUID = Field(default_factory=uuid4, primary_key=True) + flow_id: Optional[UUID] = Field(default=None, foreign_key="flow.id") + flow: "Flow" = Relationship(back_populates="messages") + files: List[str] = Field(sa_column=Column(JSON)) + + @field_validator("flow_id", mode="before") + @classmethod + def validate_flow_id(cls, value): + if value is None: + return value + if isinstance(value, str): + value = UUID(value) + return value + + # Needed for Column(JSON) + class Config: + arbitrary_types_allowed = True + + +class MessageRead(MessageBase): + id: UUID + flow_id: Optional[UUID] = Field() + + +class MessageCreate(MessageBase): + pass + + +class MessageUpdate(SQLModel): + text: Optional[str] = None + sender: Optional[str] = None + sender_name: Optional[str] = None + session_id: Optional[str] = None + files: Optional[list[str]] = None diff --git a/src/backend/base/langflow/services/database/service.py b/src/backend/base/langflow/services/database/service.py index ceeaf3e38..32e0b08e2 100644 --- a/src/backend/base/langflow/services/database/service.py +++ b/src/backend/base/langflow/services/database/service.py @@ -6,22 +6,24 @@ from typing import TYPE_CHECKING import sqlalchemy as sa from alembic import command, util from alembic.config import Config -from langflow.services.base import Service -from langflow.services.database import models # noqa -from langflow.services.database.models.user.crud import get_user_by_username -from langflow.services.database.utils import Result, TableResults -from langflow.services.deps import get_settings_service -from langflow.services.utils import teardown_superuser from loguru import logger from sqlalchemy import event, inspect from sqlalchemy.engine import Engine from sqlalchemy.exc import OperationalError from sqlmodel import Session, SQLModel, create_engine, select, text +from langflow.services.base import Service +from langflow.services.database import models # noqa +from langflow.services.database.models.user.crud import get_user_by_username +from langflow.services.database.utils import Result, TableResults, migrate_messages_from_monitor_service_to_database +from langflow.services.deps import get_settings_service +from langflow.services.utils import teardown_superuser + if TYPE_CHECKING: - from langflow.services.settings.service import SettingsService from sqlalchemy.engine import Engine + from langflow.services.settings.service import SettingsService + class DatabaseService(Service): name = "database_service" @@ -205,6 +207,10 @@ class DatabaseService(Service): logger.error(f"AutogenerateDiffsDetected: {exc}") if not fix: raise RuntimeError(f"There's a mismatch between the models and the database.\n{exc}") + try: + migrate_messages_from_monitor_service_to_database(session) + except Exception as exc: + logger.error(f"Error migrating messages from monitor service to database: {exc}") if fix: self.try_downgrade_upgrade_until_success(alembic_cfg) diff --git a/src/backend/base/langflow/services/database/utils.py b/src/backend/base/langflow/services/database/utils.py index cf2c92cb3..fa40c725f 100644 --- a/src/backend/base/langflow/services/database/utils.py +++ b/src/backend/base/langflow/services/database/utils.py @@ -4,11 +4,78 @@ from typing import TYPE_CHECKING from alembic.util.exc import CommandError from loguru import logger -from sqlmodel import Session, text +from sqlmodel import Session, select, text + +from langflow.services.deps import get_monitor_service if TYPE_CHECKING: from langflow.services.database.service import DatabaseService +from typing import Dict, List + + +def migrate_messages_from_monitor_service_to_database(session: Session) -> bool: + from langflow.schema.message import Message + from langflow.services.database.models.message import MessageTable + + monitor_service = get_monitor_service() + messages_df = monitor_service.get_messages() + + if messages_df.empty: + logger.info("No messages to migrate.") + return True + + original_messages: List[Dict] = messages_df.to_dict(orient="records") + + db_messages = session.exec(select(MessageTable)).all() + db_messages = [msg[0] for msg in db_messages] # type: ignore + db_msg_dict = {(msg.text, msg.timestamp.isoformat(), str(msg.flow_id), msg.session_id): msg for msg in db_messages} + # Filter out messages that already exist in the database + original_messages_filtered = [] + for message in original_messages: + key = (message["text"], message["timestamp"].isoformat(), str(message["flow_id"]), message["session_id"]) + if key not in db_msg_dict: + original_messages_filtered.append(message) + if not original_messages_filtered: + logger.info("No messages to migrate.") + return True + try: + # Bulk insert messages + session.bulk_insert_mappings( + MessageTable, # type: ignore + [MessageTable.from_message(Message(**msg)).model_dump() for msg in original_messages_filtered], + ) + session.commit() + except Exception as e: + logger.error(f"Error during message insertion: {str(e)}") + session.rollback() + return False + + # Create a dictionary for faster lookup + + all_ok = True + for orig_msg in original_messages_filtered: + key = (orig_msg["text"], orig_msg["timestamp"].isoformat(), str(orig_msg["flow_id"]), orig_msg["session_id"]) + matching_db_msg = db_msg_dict.get(key) + + if matching_db_msg is None: + logger.warning(f"Message not found in database: {orig_msg}") + all_ok = False + else: + # Validate other fields + if any(getattr(matching_db_msg, k) != v for k, v in orig_msg.items() if k != "index"): + logger.warning(f"Message mismatch in database: {orig_msg}") + all_ok = False + + if all_ok: + messages_ids = [message["index"] for message in original_messages] + monitor_service.delete_messages(messages_ids) + logger.info("Migration completed successfully. Original messages deleted.") + else: + logger.warning("Migration completed with errors. Original messages not deleted.") + + return all_ok + def initialize_database(fix_migration: bool = False): logger.debug("Initializing database") diff --git a/src/backend/base/langflow/services/monitor/schema.py b/src/backend/base/langflow/services/monitor/schema.py index 2294678fe..de0bb17bb 100644 --- a/src/backend/base/langflow/services/monitor/schema.py +++ b/src/backend/base/langflow/services/monitor/schema.py @@ -1,6 +1,7 @@ import json from datetime import datetime, timezone -from typing import Any, Optional +from typing import Any +from uuid import UUID from pydantic import BaseModel, Field, field_serializer, field_validator @@ -27,15 +28,15 @@ class DefaultModel(BaseModel): class TransactionModel(DefaultModel): - index: Optional[int] = Field(default=None) - timestamp: Optional[datetime] = Field(default_factory=datetime.now, alias="timestamp") + index: int | None = Field(default=None) + timestamp: datetime | None = Field(default_factory=datetime.now, alias="timestamp") vertex_id: str target_id: str | None = None inputs: dict - outputs: Optional[dict] = None + outputs: dict | None = None status: str - error: Optional[str] = None - flow_id: Optional[str] = Field(default=None, alias="flow_id") + error: str | None = None + flow_id: str | None = Field(default=None, alias="flow_id") # validate target_args in case it is a JSON @field_validator("outputs", "inputs", mode="before") @@ -52,16 +53,16 @@ class TransactionModel(DefaultModel): class TransactionModelResponse(DefaultModel): - index: Optional[int] = Field(default=None) - timestamp: Optional[datetime] = Field(default_factory=datetime.now, alias="timestamp") + index: int | None = Field(default=None) + timestamp: datetime | None = Field(default_factory=datetime.now, alias="timestamp") vertex_id: str inputs: dict - outputs: Optional[dict] = None + outputs: dict | None = None status: str - error: Optional[str] = None - flow_id: Optional[str] = Field(default=None, alias="flow_id") - source: Optional[str] = None - target: Optional[str] = None + error: str | None = None + flow_id: str | None = Field(default=None, alias="flow_id") + source: str | None = None + target: str | None = None # validate target_args in case it is a JSON @field_validator("outputs", "inputs", mode="before") @@ -80,9 +81,9 @@ class TransactionModelResponse(DefaultModel): return v -class MessageModel(DefaultModel): - index: Optional[int] = Field(default=None) - flow_id: Optional[str] = Field(default=None, alias="flow_id") +class DuckDbMessageModel(DefaultModel): + index: int | None = Field(default=None, alias="index") + flow_id: str | None = Field(default=None, alias="flow_id") timestamp: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) sender: str sender_name: str @@ -111,7 +112,53 @@ class MessageModel(DefaultModel): return v @classmethod - def from_message(cls, message: Message, flow_id: Optional[str] = None): + def from_message(cls, message: Message, flow_id: str | None = None): + # first check if the record has all the required fields + if message.text is None or not message.sender or not message.sender_name: + raise ValueError("The message does not have the required fields (text, sender, sender_name).") + return cls( + sender=message.sender, + sender_name=message.sender_name, + text=message.text, + session_id=message.session_id, + files=message.files or [], + timestamp=message.timestamp, + flow_id=flow_id, + ) + + +class MessageModel(DefaultModel): + id: str | UUID | None = Field(default=None) + flow_id: UUID | None = Field(default=None) + timestamp: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) + sender: str + sender_name: str + session_id: str + text: str + files: list[str] = [] + + @field_validator("files", mode="before") + @classmethod + def validate_files(cls, v): + if isinstance(v, str): + v = json.loads(v) + return v + + @field_serializer("timestamp") + @classmethod + def serialize_timestamp(cls, v): + v = v.replace(microsecond=0) + return v.strftime("%Y-%m-%d %H:%M:%S") + + @field_serializer("files") + @classmethod + def serialize_files(cls, v): + if isinstance(v, list): + return json.dumps(v) + return v + + @classmethod + def from_message(cls, message: Message, flow_id: str | None = None): # first check if the record has all the required fields if message.text is None or not message.sender or not message.sender_name: raise ValueError("The message does not have the required fields (text, sender, sender_name).") @@ -127,16 +174,7 @@ class MessageModel(DefaultModel): class MessageModelResponse(MessageModel): - index: Optional[int] = Field(default=None) - - @field_validator("index", mode="before") - def validate_id(cls, v): - if isinstance(v, float): - try: - return int(v) - except ValueError: - return None - return v + pass class MessageModelRequest(MessageModel): @@ -147,8 +185,8 @@ class MessageModelRequest(MessageModel): class VertexBuildModel(DefaultModel): - index: Optional[int] = Field(default=None, alias="index", exclude=True) - id: Optional[str] = Field(default=None, alias="id") + index: int | None = Field(default=None, alias="index", exclude=True) + id: str | None = Field(default=None, alias="id") flow_id: str valid: bool params: Any diff --git a/src/backend/base/langflow/services/monitor/service.py b/src/backend/base/langflow/services/monitor/service.py index 6b99b9760..f644fd871 100644 --- a/src/backend/base/langflow/services/monitor/service.py +++ b/src/backend/base/langflow/services/monitor/service.py @@ -1,30 +1,31 @@ from datetime import datetime from pathlib import Path -from typing import TYPE_CHECKING, List, Optional, Union +from typing import TYPE_CHECKING, Union import duckdb -from langflow.services.base import Service -from langflow.services.monitor.utils import add_row_to_table, drop_and_create_table_if_schema_mismatch from loguru import logger from platformdirs import user_cache_dir +from langflow.services.base import Service +from langflow.services.monitor.utils import add_row_to_table, drop_and_create_table_if_schema_mismatch + if TYPE_CHECKING: + from langflow.services.monitor.schema import DuckDbMessageModel, TransactionModel, VertexBuildModel from langflow.services.settings.service import SettingsService - from langflow.services.monitor.schema import MessageModel, TransactionModel, VertexBuildModel class MonitorService(Service): name = "monitor_service" def __init__(self, settings_service: "SettingsService"): - from langflow.services.monitor.schema import MessageModel, TransactionModel, VertexBuildModel + from langflow.services.monitor.schema import DuckDbMessageModel, TransactionModel, VertexBuildModel self.settings_service = settings_service self.base_cache_dir = Path(user_cache_dir("langflow")) self.db_path = self.base_cache_dir / "monitor.duckdb" - self.table_map: dict[str, type[TransactionModel | MessageModel | VertexBuildModel]] = { + self.table_map: dict[str, type[TransactionModel | DuckDbMessageModel | VertexBuildModel]] = { "transactions": TransactionModel, - "messages": MessageModel, + "messages": DuckDbMessageModel, "vertex_builds": VertexBuildModel, } @@ -47,7 +48,7 @@ class MonitorService(Service): def add_row( self, table_name: str, - data: Union[dict, "TransactionModel", "MessageModel", "VertexBuildModel"], + data: Union[dict, "TransactionModel", "DuckDbMessageModel", "VertexBuildModel"], ): # Make sure the model passed matches the table @@ -67,80 +68,15 @@ class MonitorService(Service): def get_timestamp(): return datetime.now().strftime("%Y-%m-%d %H:%M:%S") - def get_vertex_builds( - self, - flow_id: Optional[str] = None, - vertex_id: Optional[str] = None, - valid: Optional[bool] = None, - order_by: Optional[str] = "timestamp", - ): - query = "SELECT id, index,flow_id, valid, params, data, artifacts, timestamp FROM vertex_builds" - conditions = [] - if flow_id: - conditions.append(f"flow_id = '{flow_id}'") - if vertex_id: - conditions.append(f"id = '{vertex_id}'") - if valid is not None: # Check for None because valid is a boolean - valid_str = "true" if valid else "false" - conditions.append(f"valid = {valid_str}") - - if conditions: - query += " WHERE " + " AND ".join(conditions) - - if order_by: - query += f" ORDER BY {order_by}" - - with duckdb.connect(str(self.db_path), read_only=True) as conn: - df = conn.execute(query).df() - - return df.to_dict(orient="records") - - def delete_vertex_builds(self, flow_id: Optional[str] = None): - query = "DELETE FROM vertex_builds" - if flow_id: - query += f" WHERE flow_id = '{flow_id}'" - - with duckdb.connect(str(self.db_path), read_only=False) as conn: - conn.execute(query) - - def delete_messages_session(self, session_id: str): - query = f"DELETE FROM messages WHERE session_id = '{session_id}'" - - return self.exec_query(query, read_only=False) - - def delete_messages(self, message_ids: Union[List[int], str]): - if isinstance(message_ids, list): - # If message_ids is a list, join the string representations of the integers - ids_str = ",".join(map(str, message_ids)) - elif isinstance(message_ids, str): - # If message_ids is already a string, use it directly - ids_str = message_ids - else: - raise ValueError("message_ids must be a list of integers or a string") - - query = f"DELETE FROM messages WHERE index IN ({ids_str})" - - return self.exec_query(query, read_only=False) - - def update_message(self, message_id: str, **kwargs): - query = ( - f"""UPDATE messages SET {', '.join(f"{k} = '{v}'" for k, v in kwargs.items())} WHERE index = {message_id}""" - ) - - return self.exec_query(query, read_only=False) - - def add_message(self, message: "MessageModel"): - self.add_row("messages", message) - def get_messages( self, - flow_id: Optional[str] = None, - sender: Optional[str] = None, - sender_name: Optional[str] = None, - session_id: Optional[str] = None, - order_by: Optional[str] = "timestamp", - order: Optional[str] = "DESC", - limit: Optional[int] = None, + flow_id: str | None = None, + sender: str | None = None, + sender_name: str | None = None, + session_id: str | None = None, + order_by: str | None = "timestamp", + order: str | None = "DESC", + limit: int | None = None, ): query = "SELECT index, flow_id, sender_name, sender, session_id, text, files, timestamp FROM messages" conditions = [] @@ -168,13 +104,75 @@ class MonitorService(Service): return df + def get_vertex_builds( + self, + flow_id: str | None = None, + vertex_id: str | None = None, + valid: bool | None = None, + order_by: str | None = "timestamp", + ): + query = "SELECT id, index,flow_id, valid, params, data, artifacts, timestamp FROM vertex_builds" + conditions = [] + if flow_id: + conditions.append(f"flow_id = '{flow_id}'") + if vertex_id: + conditions.append(f"id = '{vertex_id}'") + if valid is not None: # Check for None because valid is a boolean + valid_str = "true" if valid else "false" + conditions.append(f"valid = {valid_str}") + + if conditions: + query += " WHERE " + " AND ".join(conditions) + + if order_by: + query += f" ORDER BY {order_by}" + + with duckdb.connect(str(self.db_path), read_only=True) as conn: + df = conn.execute(query).df() + + return df.to_dict(orient="records") + + def delete_vertex_builds(self, flow_id: str | None = None): + query = "DELETE FROM vertex_builds" + if flow_id: + query += f" WHERE flow_id = '{flow_id}'" + + with duckdb.connect(str(self.db_path), read_only=False) as conn: + conn.execute(query) + + def delete_messages_session(self, session_id: str): + query = f"DELETE FROM messages WHERE session_id = '{session_id}'" + + return self.exec_query(query, read_only=False) + + def delete_messages(self, message_ids: list[int] | str): + if isinstance(message_ids, list): + # If message_ids is a list, join the string representations of the integers + ids_str = ",".join(map(str, message_ids)) + elif isinstance(message_ids, str): + # If message_ids is already a string, use it directly + ids_str = message_ids + else: + raise ValueError("message_ids must be a list of integers or a string") + + query = f"DELETE FROM messages WHERE index IN ({ids_str})" + + return self.exec_query(query, read_only=False) + + def update_message(self, message_id: str, **kwargs): + query = ( + f"""UPDATE messages SET {', '.join(f"{k} = '{v}'" for k, v in kwargs.items())} WHERE index = {message_id}""" + ) + + return self.exec_query(query, read_only=False) + def get_transactions( self, - source: Optional[str] = None, - target: Optional[str] = None, - status: Optional[str] = None, - order_by: Optional[str] = "timestamp", - flow_id: Optional[str] = None, + source: str | None = None, + target: str | None = None, + status: str | None = None, + order_by: str | None = "timestamp", + flow_id: str | None = None, ): query = ( "SELECT index,flow_id, status, error, timestamp, vertex_id, inputs, outputs, target_id FROM transactions" diff --git a/src/backend/base/langflow/services/telemetry/schema.py b/src/backend/base/langflow/services/telemetry/schema.py index bba7a23e4..9d62e128a 100644 --- a/src/backend/base/langflow/services/telemetry/schema.py +++ b/src/backend/base/langflow/services/telemetry/schema.py @@ -2,10 +2,10 @@ from pydantic import BaseModel class RunPayload(BaseModel): - IsWebhook: bool = False - seconds: int - success: bool - errorMessage: str = "" + runIsWebhook: bool = False + runSeconds: int + runSuccess: bool + runErrorMessage: str = "" class ShutdownPayload(BaseModel): @@ -23,14 +23,14 @@ class VersionPayload(BaseModel): class PlaygroundPayload(BaseModel): - seconds: int - componentCount: int | None = None - success: bool - errorMessage: str = "" + playgroundSeconds: int + playgroundComponentCount: int | None = None + playgroundSuccess: bool + playgroundErrorMessage: str = "" class ComponentPayload(BaseModel): - name: str - seconds: int - success: bool - errorMessage: str + componentName: str + componentSeconds: int + componentSuccess: bool + componentErrorMessage: str diff --git a/src/backend/base/langflow/services/tracing/service.py b/src/backend/base/langflow/services/tracing/service.py index c23dba24b..95795c988 100644 --- a/src/backend/base/langflow/services/tracing/service.py +++ b/src/backend/base/langflow/services/tracing/service.py @@ -86,7 +86,7 @@ class TracingService(Service): await self.start() self._initialize_langsmith_tracer() except Exception as e: - logger.error(f"Error initializing tracers: {e}") + logger.debug(f"Error initializing tracers: {e}") def _initialize_langsmith_tracer(self): project_name = os.getenv("LANGCHAIN_PROJECT", "Langflow") @@ -188,15 +188,19 @@ class LangSmithTracer: self.trace_type = trace_type self.project_name = project_name self.trace_id = trace_id - self._run_tree = RunTree( - project_name=self.project_name, - name=self.trace_name, - run_type=self.trace_type, - id=self.trace_id, - ) - self._run_tree.add_event({"name": "Start", "time": datetime.now(timezone.utc).isoformat()}) - self._children: dict[str, RunTree] = {} - self._ready = self.setup_langsmith() + try: + self._run_tree = RunTree( + project_name=self.project_name, + name=self.trace_name, + run_type=self.trace_type, + id=self.trace_id, + ) + self._run_tree.add_event({"name": "Start", "time": datetime.now(timezone.utc).isoformat()}) + self._children: dict[str, RunTree] = {} + self._ready = self.setup_langsmith() + except Exception as e: + logger.debug(f"Error setting up LangSmith tracer: {e}") + self._ready = False @property def ready(self): diff --git a/src/backend/base/poetry.lock b/src/backend/base/poetry.lock index a919a0251..bc60a1fbd 100644 --- a/src/backend/base/poetry.lock +++ b/src/backend/base/poetry.lock @@ -112,13 +112,13 @@ frozenlist = ">=1.1.0" [[package]] name = "alembic" -version = "1.13.1" +version = "1.13.2" description = "A database migration tool for SQLAlchemy." optional = false python-versions = ">=3.8" files = [ - {file = "alembic-1.13.1-py3-none-any.whl", hash = "sha256:2edcc97bed0bd3272611ce3a98d98279e9c209e7186e43e75bbb1b2bdfdbcc43"}, - {file = "alembic-1.13.1.tar.gz", hash = "sha256:4932c8558bf68f2ee92b9bbcb8218671c627064d5b08939437af6d77dc05e595"}, + {file = "alembic-1.13.2-py3-none-any.whl", hash = "sha256:6b8733129a6224a9a711e17c99b08462dbf7cc9670ba8f2e2ae9af860ceb1953"}, + {file = "alembic-1.13.2.tar.gz", hash = "sha256:1ff0ae32975f4fd96028c39ed9bb3c867fe3af956bd7bb37343b54c9fe7445ef"}, ] [package.dependencies] @@ -739,6 +739,20 @@ typer = ">=0.12.3" [package.extras] standard = ["fastapi", "uvicorn[standard] (>=0.15.0)"] +[[package]] +name = "firecrawl-py" +version = "0.0.16" +description = "Python SDK for Firecrawl API" +optional = false +python-versions = ">=3.8" +files = [ + {file = "firecrawl_py-0.0.16-py3-none-any.whl", hash = "sha256:9024f483b501852a6b9c4e6cdfc9e8dde452d922afac357080bb278a0c9c2a26"}, + {file = "firecrawl_py-0.0.16.tar.gz", hash = "sha256:6c662fa0a549bc7f5c0acb704baba6731869ca0451094034264dfc1b4eb086e4"}, +] + +[package.dependencies] +requests = "*" + [[package]] name = "frozenlist" version = "1.4.1" @@ -1158,19 +1172,19 @@ files = [ [[package]] name = "langchain" -version = "0.2.5" +version = "0.2.6" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain-0.2.5-py3-none-any.whl", hash = "sha256:9aded9a65348254e1c93dcdaacffe4d1b6a5e7f74ef80c160c88ff78ad299228"}, - {file = "langchain-0.2.5.tar.gz", hash = "sha256:ffdbf4fcea46a10d461bcbda2402220fcfd72a0c70e9f4161ae0510067b9b3bd"}, + {file = "langchain-0.2.6-py3-none-any.whl", hash = "sha256:f86e8a7afd3e56f8eb5ba47f01dd00144fb9fc2f1db9873bd197347be2857aa4"}, + {file = "langchain-0.2.6.tar.gz", hash = "sha256:867f6add370c1e3911b0e87d3dd0e36aec1e8f513bf06131340fe8f151d89dc5"}, ] [package.dependencies] aiohttp = ">=3.8.3,<4.0.0" async-timeout = {version = ">=4.0.0,<5.0.0", markers = "python_version < \"3.11\""} -langchain-core = ">=0.2.7,<0.3.0" +langchain-core = ">=0.2.10,<0.3.0" langchain-text-splitters = ">=0.2.0,<0.3.0" langsmith = ">=0.1.17,<0.2.0" numpy = [ @@ -1181,24 +1195,24 @@ pydantic = ">=1,<3" PyYAML = ">=5.3" requests = ">=2,<3" SQLAlchemy = ">=1.4,<3" -tenacity = ">=8.1.0,<9.0.0" +tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<9.0.0" [[package]] name = "langchain-community" -version = "0.2.5" +version = "0.2.6" description = "Community contributed LangChain integrations." optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_community-0.2.5-py3-none-any.whl", hash = "sha256:bf37a334952e42c7676d083cf2d2c4cbfbb7de1949c4149fe19913e2b06c485f"}, - {file = "langchain_community-0.2.5.tar.gz", hash = "sha256:476787b8c8c213b67e7b0eceb53346e787f00fbae12d8e680985bd4f93b0bf64"}, + {file = "langchain_community-0.2.6-py3-none-any.whl", hash = "sha256:758cc800acfe5dd396bf8ba1b57c4792639ead0eab48ed0367f0732ec6ee1f68"}, + {file = "langchain_community-0.2.6.tar.gz", hash = "sha256:40ce09a50ed798aa651ddb34c8978200fa8589b9813c7a28ce8af027bbf249f0"}, ] [package.dependencies] aiohttp = ">=3.8.3,<4.0.0" dataclasses-json = ">=0.5.7,<0.7" -langchain = ">=0.2.5,<0.3.0" -langchain-core = ">=0.2.7,<0.3.0" +langchain = ">=0.2.6,<0.3.0" +langchain-core = ">=0.2.10,<0.3.0" langsmith = ">=0.1.0,<0.2.0" numpy = [ {version = ">=1,<2", markers = "python_version < \"3.12\""}, @@ -1207,17 +1221,17 @@ numpy = [ PyYAML = ">=5.3" requests = ">=2,<3" SQLAlchemy = ">=1.4,<3" -tenacity = ">=8.1.0,<9.0.0" +tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<9.0.0" [[package]] name = "langchain-core" -version = "0.2.9" +version = "0.2.10" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_core-0.2.9-py3-none-any.whl", hash = "sha256:426a5a4fea95a5db995ba5ab560b76edd4998fb6fe52ccc28ac987092a4cbfcd"}, - {file = "langchain_core-0.2.9.tar.gz", hash = "sha256:f1c59082642921727844e1cd0eb36d451edd1872c20e193aa3142aac03495986"}, + {file = "langchain_core-0.2.10-py3-none-any.whl", hash = "sha256:6eb72086b6bc86db9812da98f79e507c2209a15c0112aefd214a04182ada8586"}, + {file = "langchain_core-0.2.10.tar.gz", hash = "sha256:33d1fc234ab58c80476eb5bbde2107ef522a2ce8f46bdf47d9e1bd21e054208f"}, ] [package.dependencies] @@ -1233,35 +1247,32 @@ tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<9.0.0" [[package]] name = "langchain-experimental" -version = "0.0.61" +version = "0.0.62" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_experimental-0.0.61-py3-none-any.whl", hash = "sha256:f9c516f528f55919743bd56fe1689a53bf74ae7f8902d64b9d8aebc61249cbe2"}, - {file = "langchain_experimental-0.0.61.tar.gz", hash = "sha256:e9538efb994be5db3045cc582cddb9787c8299c86ffeee9d3779b7f58eef2226"}, + {file = "langchain_experimental-0.0.62-py3-none-any.whl", hash = "sha256:9240f9e3490e819976f20a37863970036e7baacb7104b9eb6833d19ab6d518c9"}, + {file = "langchain_experimental-0.0.62.tar.gz", hash = "sha256:9737fbc8429d24457ea4d368e3c9ba9ed1cace0564fb5f1a96a3027a588bd0ac"}, ] [package.dependencies] -langchain-community = ">=0.2.5,<0.3.0" -langchain-core = ">=0.2.7,<0.3.0" +langchain-community = ">=0.2.6,<0.3.0" +langchain-core = ">=0.2.10,<0.3.0" [[package]] name = "langchain-text-splitters" -version = "0.2.1" +version = "0.2.2" description = "LangChain text splitting utilities" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_text_splitters-0.2.1-py3-none-any.whl", hash = "sha256:c2774a85f17189eaca50339629d2316d13130d4a8d9f1a1a96f3a03670c4a138"}, - {file = "langchain_text_splitters-0.2.1.tar.gz", hash = "sha256:06853d17d7241ecf5c97c7b6ef01f600f9b0fb953dd997838142a527a4f32ea4"}, + {file = "langchain_text_splitters-0.2.2-py3-none-any.whl", hash = "sha256:1c80d4b11b55e2995f02d2a326c0323ee1eeff24507329bb22924e420c782dff"}, + {file = "langchain_text_splitters-0.2.2.tar.gz", hash = "sha256:a1e45de10919fa6fb080ef0525deab56557e9552083600455cb9fa4238076140"}, ] [package.dependencies] -langchain-core = ">=0.2.0,<0.3.0" - -[package.extras] -extended-testing = ["beautifulsoup4 (>=4.12.3,<5.0.0)", "lxml (>=4.9.3,<6.0)"] +langchain-core = ">=0.2.10,<0.3.0" [[package]] name = "langchainhub" @@ -1281,18 +1292,21 @@ types-requests = ">=2.31.0.2,<3.0.0.0" [[package]] name = "langsmith" -version = "0.1.81" +version = "0.1.82" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langsmith-0.1.81-py3-none-any.whl", hash = "sha256:3251d823225eef23ee541980b9d9e506367eabbb7f985a086b5d09e8f78ba7e9"}, - {file = "langsmith-0.1.81.tar.gz", hash = "sha256:585ef3a2251380bd2843a664c9a28da4a7d28432e3ee8bcebf291ffb8e1f0af0"}, + {file = "langsmith-0.1.82-py3-none-any.whl", hash = "sha256:9b3653e7d316036b0c60bf0bc3e280662d660f485a4ebd8e5c9d84f9831ae79c"}, + {file = "langsmith-0.1.82.tar.gz", hash = "sha256:c02e2bbc488c10c13b52c69d271eb40bd38da078d37b6ae7ae04a18bd48140be"}, ] [package.dependencies] orjson = ">=3.9.14,<4.0.0" -pydantic = ">=1,<3" +pydantic = [ + {version = ">=1,<3", markers = "python_full_version < \"3.12.4\""}, + {version = ">=2.7.4,<3.0.0", markers = "python_full_version >= \"3.12.4\""}, +] requests = ">=2,<3" [[package]] @@ -2199,13 +2213,13 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pydantic-settings" -version = "2.3.3" +version = "2.3.4" description = "Settings management using Pydantic" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_settings-2.3.3-py3-none-any.whl", hash = "sha256:e4ed62ad851670975ec11285141db888fd24947f9440bd4380d7d8788d4965de"}, - {file = "pydantic_settings-2.3.3.tar.gz", hash = "sha256:87fda838b64b5039b970cd47c3e8a1ee460ce136278ff672980af21516f6e6ce"}, + {file = "pydantic_settings-2.3.4-py3-none-any.whl", hash = "sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a"}, + {file = "pydantic_settings-2.3.4.tar.gz", hash = "sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7"}, ] [package.dependencies] @@ -2465,13 +2479,13 @@ pyasn1 = ">=0.1.3" [[package]] name = "sentry-sdk" -version = "2.6.0" +version = "2.7.0" description = "Python client for Sentry (https://sentry.io)" optional = false python-versions = ">=3.6" files = [ - {file = "sentry_sdk-2.6.0-py2.py3-none-any.whl", hash = "sha256:422b91cb49378b97e7e8d0e8d5a1069df23689d45262b86f54988a7db264e874"}, - {file = "sentry_sdk-2.6.0.tar.gz", hash = "sha256:65cc07e9c6995c5e316109f138570b32da3bd7ff8d0d0ee4aaf2628c3dd8127d"}, + {file = "sentry_sdk-2.7.0-py2.py3-none-any.whl", hash = "sha256:db9594c27a4d21c1ebad09908b1f0dc808ef65c2b89c1c8e7e455143262e37c1"}, + {file = "sentry_sdk-2.7.0.tar.gz", hash = "sha256:d846a211d4a0378b289ced3c434480945f110d0ede00450ba631fc2852e7a0d4"}, ] [package.dependencies] @@ -2503,7 +2517,7 @@ langchain = ["langchain (>=0.0.210)"] loguru = ["loguru (>=0.5)"] openai = ["openai (>=1.0.0)", "tiktoken (>=0.3.0)"] opentelemetry = ["opentelemetry-distro (>=0.35b0)"] -opentelemetry-experimental = ["opentelemetry-distro (>=0.40b0,<1.0)", "opentelemetry-instrumentation-aiohttp-client (>=0.40b0,<1.0)", "opentelemetry-instrumentation-django (>=0.40b0,<1.0)", "opentelemetry-instrumentation-fastapi (>=0.40b0,<1.0)", "opentelemetry-instrumentation-flask (>=0.40b0,<1.0)", "opentelemetry-instrumentation-requests (>=0.40b0,<1.0)", "opentelemetry-instrumentation-sqlite3 (>=0.40b0,<1.0)", "opentelemetry-instrumentation-urllib (>=0.40b0,<1.0)"] +opentelemetry-experimental = ["opentelemetry-instrumentation-aio-pika (==0.46b0)", "opentelemetry-instrumentation-aiohttp-client (==0.46b0)", "opentelemetry-instrumentation-aiopg (==0.46b0)", "opentelemetry-instrumentation-asgi (==0.46b0)", "opentelemetry-instrumentation-asyncio (==0.46b0)", "opentelemetry-instrumentation-asyncpg (==0.46b0)", "opentelemetry-instrumentation-aws-lambda (==0.46b0)", "opentelemetry-instrumentation-boto (==0.46b0)", "opentelemetry-instrumentation-boto3sqs (==0.46b0)", "opentelemetry-instrumentation-botocore (==0.46b0)", "opentelemetry-instrumentation-cassandra (==0.46b0)", "opentelemetry-instrumentation-celery (==0.46b0)", "opentelemetry-instrumentation-confluent-kafka (==0.46b0)", "opentelemetry-instrumentation-dbapi (==0.46b0)", "opentelemetry-instrumentation-django (==0.46b0)", "opentelemetry-instrumentation-elasticsearch (==0.46b0)", "opentelemetry-instrumentation-falcon (==0.46b0)", "opentelemetry-instrumentation-fastapi (==0.46b0)", "opentelemetry-instrumentation-flask (==0.46b0)", "opentelemetry-instrumentation-grpc (==0.46b0)", "opentelemetry-instrumentation-httpx (==0.46b0)", "opentelemetry-instrumentation-jinja2 (==0.46b0)", "opentelemetry-instrumentation-kafka-python (==0.46b0)", "opentelemetry-instrumentation-logging (==0.46b0)", "opentelemetry-instrumentation-mysql (==0.46b0)", "opentelemetry-instrumentation-mysqlclient (==0.46b0)", "opentelemetry-instrumentation-pika (==0.46b0)", "opentelemetry-instrumentation-psycopg (==0.46b0)", "opentelemetry-instrumentation-psycopg2 (==0.46b0)", "opentelemetry-instrumentation-pymemcache (==0.46b0)", "opentelemetry-instrumentation-pymongo (==0.46b0)", "opentelemetry-instrumentation-pymysql (==0.46b0)", "opentelemetry-instrumentation-pyramid (==0.46b0)", "opentelemetry-instrumentation-redis (==0.46b0)", "opentelemetry-instrumentation-remoulade (==0.46b0)", "opentelemetry-instrumentation-requests (==0.46b0)", "opentelemetry-instrumentation-sklearn (==0.46b0)", "opentelemetry-instrumentation-sqlalchemy (==0.46b0)", "opentelemetry-instrumentation-sqlite3 (==0.46b0)", "opentelemetry-instrumentation-starlette (==0.46b0)", "opentelemetry-instrumentation-system-metrics (==0.46b0)", "opentelemetry-instrumentation-threading (==0.46b0)", "opentelemetry-instrumentation-tornado (==0.46b0)", "opentelemetry-instrumentation-tortoiseorm (==0.46b0)", "opentelemetry-instrumentation-urllib (==0.46b0)", "opentelemetry-instrumentation-urllib3 (==0.46b0)", "opentelemetry-instrumentation-wsgi (==0.46b0)"] pure-eval = ["asttokens", "executing", "pure-eval"] pymongo = ["pymongo (>=3.1)"] pyspark = ["pyspark (>=2.4.4)"] @@ -2669,13 +2683,13 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7 [[package]] name = "tenacity" -version = "8.4.1" +version = "8.4.2" description = "Retry code until it succeeds" optional = false python-versions = ">=3.8" files = [ - {file = "tenacity-8.4.1-py3-none-any.whl", hash = "sha256:28522e692eda3e1b8f5e99c51464efcc0b9fc86933da92415168bc1c4e2308fa"}, - {file = "tenacity-8.4.1.tar.gz", hash = "sha256:54b1412b878ddf7e1f1577cd49527bad8cdef32421bd599beac0c6c3f10582fd"}, + {file = "tenacity-8.4.2-py3-none-any.whl", hash = "sha256:9e6f7cf7da729125c7437222f8a522279751cdfbe6b67bfe64f75d3a348661b2"}, + {file = "tenacity-8.4.2.tar.gz", hash = "sha256:cd80a53a79336edba8489e767f729e4f391c896956b57140b5d7511a64bbd3ef"}, ] [package.extras] @@ -3232,4 +3246,4 @@ local = [] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.13" -content-hash = "4f566531a8539ddc81cb91a7e7f9b723c84679f0af5bb8619f7b02f9ffc6cfaa" +content-hash = "7e46144d27c633214f00e73e496c0e4d56db1fb47032a21861677ec275b79d86" diff --git a/src/backend/base/pyproject.toml b/src/backend/base/pyproject.toml index ddf52ec06..3a07f47a5 100644 --- a/src/backend/base/pyproject.toml +++ b/src/backend/base/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langflow-base" -version = "0.0.75" +version = "0.0.81" description = "A Python package with a built-in web application" authors = ["Langflow "] maintainers = [ @@ -64,6 +64,7 @@ pyperclip = "^1.8.2" uncurl = "^0.0.11" sentry-sdk = {extras = ["fastapi", "loguru"], version = "^2.5.1"} chardet = "^5.2.0" +firecrawl-py = "^0.0.16" [tool.poetry.extras] diff --git a/src/frontend/package-lock.json b/src/frontend/package-lock.json index c73a25fee..811237487 100644 --- a/src/frontend/package-lock.json +++ b/src/frontend/package-lock.json @@ -102,7 +102,7 @@ "postcss": "^8.4.38", "prettier": "^3.3.2", "prettier-plugin-organize-imports": "^3.2.4", - "prettier-plugin-tailwindcss": "^0.6.4", + "prettier-plugin-tailwindcss": "^0.6.5", "simple-git-hooks": "^2.11.1", "tailwindcss": "^3.4.4", "tailwindcss-dotted-background": "^1.1.0", @@ -787,7 +787,6 @@ }, "node_modules/@clack/prompts/node_modules/is-unicode-supported": { "version": "1.3.0", - "extraneous": true, "inBundle": true, "license": "MIT", "engines": { diff --git a/src/frontend/package.json b/src/frontend/package.json index a4b10db6c..42752d9c4 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -83,6 +83,7 @@ "build": "vite build", "serve": "vite preview", "format": "npx prettier --write \"{tests,src}/**/*.{js,jsx,ts,tsx,json,md}\" --ignore-path .prettierignore", + "check-format": "npx prettier --check \"{tests,src}/**/*.{js,jsx,ts,tsx,json,md}\" --ignore-path .prettierignore", "type-check": "tsc --noEmit --pretty --project tsconfig.json && vite" }, "eslintConfig": { @@ -113,18 +114,18 @@ "@testing-library/react": "^16.0.0", "@testing-library/user-event": "^14.5.2", "@types/jest": "^29.5.12", + "@types/lodash": "4.17.5", "@types/node": "^20.14.2", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "@types/uuid": "^9.0.8", - "@types/lodash": "4.17.5", "@vitejs/plugin-react-swc": "^3.7.0", "autoprefixer": "^10.4.19", "eslint": "^9.5.0", "postcss": "^8.4.38", "prettier": "^3.3.2", "prettier-plugin-organize-imports": "^3.2.4", - "prettier-plugin-tailwindcss": "^0.6.4", + "prettier-plugin-tailwindcss": "^0.6.5", "simple-git-hooks": "^2.11.1", "tailwindcss": "^3.4.4", "tailwindcss-dotted-background": "^1.1.0", @@ -132,4 +133,4 @@ "ua-parser-js": "^1.0.38", "vite": "^5.3.1" } -} +} \ No newline at end of file diff --git a/src/frontend/playwright.config.ts b/src/frontend/playwright.config.ts index 5af71db80..fa1df86e3 100644 --- a/src/frontend/playwright.config.ts +++ b/src/frontend/playwright.config.ts @@ -19,9 +19,9 @@ export default defineConfig({ /* Fail the build on CI if you accidentally left test.only in the source code. */ forbidOnly: !!process.env.CI, /* Retry on CI only */ - retries: process.env.CI ? 2 : 0, + retries: process.env.CI ? 2 : 3, /* Opt out of parallel tests on CI. */ - workers: 1, + workers: 2, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ timeout: 120 * 1000, // reporter: [ diff --git a/src/frontend/src/App.tsx b/src/frontend/src/App.tsx index 1c8274e63..1a7178248 100644 --- a/src/frontend/src/App.tsx +++ b/src/frontend/src/App.tsx @@ -103,13 +103,6 @@ export default function App() { if (isAuthenticated) { try { await setupAxiosDefaults(); - - const res = await getGlobalVariables(); - setGlobalVariables(res); - - checkHasStore(); - fetchApiData(); - resolve(); } catch (error) { console.error("Failed to fetch data:", error); diff --git a/src/frontend/src/CustomNodes/GenericNode/components/handleRenderComponent/index.tsx b/src/frontend/src/CustomNodes/GenericNode/components/handleRenderComponent/index.tsx index 4e53881d4..e415eb0c7 100644 --- a/src/frontend/src/CustomNodes/GenericNode/components/handleRenderComponent/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/components/handleRenderComponent/index.tsx @@ -52,7 +52,7 @@ export default function HandleRenderComponent({ side={left ? "left" : "right"} > Promise, + setNode: (id: string, callback: (oldNode: any) => any) => void, + setIsLoading: (value: boolean) => void, ) => { const setErrorData = useAlertStore((state) => state.setErrorData); diff --git a/src/frontend/src/CustomNodes/hooks/use-handle-new-value.tsx b/src/frontend/src/CustomNodes/hooks/use-handle-new-value.tsx index b9690e270..a32c4d2dc 100644 --- a/src/frontend/src/CustomNodes/hooks/use-handle-new-value.tsx +++ b/src/frontend/src/CustomNodes/hooks/use-handle-new-value.tsx @@ -5,15 +5,16 @@ import { } from "../../constants/constants"; import useAlertStore from "../../stores/alertStore"; import { ResponseErrorTypeAPI } from "../../types/api"; +import { NodeDataType } from "../../types/flow"; const useHandleOnNewValue = ( - data, - name, - takeSnapshot, - handleUpdateValues, - debouncedHandleUpdateValues, - setNode, - setIsLoading, + data: NodeDataType, + name: string, + takeSnapshot: () => void, + handleUpdateValues: (name: string, data: NodeDataType) => Promise, + debouncedHandleUpdateValues: any, + setNode: (id: string, callback: (oldNode: any) => any) => void, + setIsLoading: (value: boolean) => void, ) => { const setErrorData = useAlertStore((state) => state.setErrorData); diff --git a/src/frontend/src/CustomNodes/hooks/use-handle-node-class.tsx b/src/frontend/src/CustomNodes/hooks/use-handle-node-class.tsx index 933f836a4..e82c06e72 100644 --- a/src/frontend/src/CustomNodes/hooks/use-handle-node-class.tsx +++ b/src/frontend/src/CustomNodes/hooks/use-handle-node-class.tsx @@ -1,11 +1,12 @@ import { cloneDeep } from "lodash"; +import { NodeDataType } from "../../types/flow"; const useHandleNodeClass = ( - data, - name, - takeSnapshot, - setNode, - updateNodeInternals, + data: NodeDataType, + name: string, + takeSnapshot: () => void, + setNode: (id: string, callback: (oldNode: any) => any) => void, + updateNodeInternals: (id: string) => void, ) => { const handleNodeClass = (newNodeClass, code, type?: string) => { if (!data.node) return; diff --git a/src/frontend/src/CustomNodes/hooks/use-handle-refresh-buttons.tsx b/src/frontend/src/CustomNodes/hooks/use-handle-refresh-buttons.tsx index e2ecb3f46..65345fcea 100644 --- a/src/frontend/src/CustomNodes/hooks/use-handle-refresh-buttons.tsx +++ b/src/frontend/src/CustomNodes/hooks/use-handle-refresh-buttons.tsx @@ -7,7 +7,10 @@ import useAlertStore from "../../stores/alertStore"; import { ResponseErrorDetailAPI } from "../../types/api"; import { handleUpdateValues } from "../../utils/parameterUtils"; -const useHandleRefreshButtonPress = (setIsLoading, setNode) => { +const useHandleRefreshButtonPress = ( + setIsLoading: (value: boolean) => void, + setNode: (id: string, callback: (oldNode: any) => any) => void, +) => { const setErrorData = useAlertStore((state) => state.setErrorData); const handleRefreshButtonPress = async (name, data) => { diff --git a/src/frontend/src/CustomNodes/hooks/use-update-validation-status.tsx b/src/frontend/src/CustomNodes/hooks/use-update-validation-status.tsx index 2a7153dfb..e93691b5f 100644 --- a/src/frontend/src/CustomNodes/hooks/use-update-validation-status.tsx +++ b/src/frontend/src/CustomNodes/hooks/use-update-validation-status.tsx @@ -1,6 +1,11 @@ import { useEffect } from "react"; +import { FlowPoolType } from "../../types/zustand/flow"; -const useUpdateValidationStatus = (dataId, flowPool, setValidationStatus) => { +const useUpdateValidationStatus = ( + dataId: string, + flowPool: FlowPoolType, + setValidationStatus: (value: any) => void, +) => { useEffect(() => { const relevantData = flowPool[dataId] && flowPool[dataId]?.length > 0 diff --git a/src/frontend/src/CustomNodes/hooks/use-validation-status-string.tsx b/src/frontend/src/CustomNodes/hooks/use-validation-status-string.tsx index 31929eb99..3ad905dc8 100644 --- a/src/frontend/src/CustomNodes/hooks/use-validation-status-string.tsx +++ b/src/frontend/src/CustomNodes/hooks/use-validation-status-string.tsx @@ -4,7 +4,7 @@ import { isErrorLog } from "../../types/utils/typeCheckingUtils"; const useValidationStatusString = ( validationStatus: VertexBuildTypeAPI | null, - setValidationString, + setValidationString: (value: any) => void, ) => { useEffect(() => { if (validationStatus && validationStatus.data?.outputs) { diff --git a/src/frontend/src/alerts/notice/index.tsx b/src/frontend/src/alerts/notice/index.tsx index 7d2d4d987..49fb52759 100644 --- a/src/frontend/src/alerts/notice/index.tsx +++ b/src/frontend/src/alerts/notice/index.tsx @@ -47,7 +47,7 @@ export default function NoticeAlert({ />
-

+

{title}

diff --git a/src/frontend/src/components/cardComponent/hooks/use-data-effect.tsx b/src/frontend/src/components/cardComponent/hooks/use-data-effect.tsx new file mode 100644 index 000000000..21d29049a --- /dev/null +++ b/src/frontend/src/components/cardComponent/hooks/use-data-effect.tsx @@ -0,0 +1,19 @@ +import { useEffect } from "react"; +import { storeComponent } from "../../../types/store"; + +const useDataEffect = ( + data: storeComponent, + setLikedByUser: (value: any) => void, + setLikesCount: (value: any) => void, + setDownloadsCount: (value: any) => void, +) => { + useEffect(() => { + if (data) { + setLikedByUser(data?.liked_by_user ?? false); + setLikesCount(data?.liked_by_count ?? 0); + setDownloadsCount(data?.downloads_count ?? 0); + } + }, [data, data?.liked_by_count, data?.liked_by_user, data?.downloads_count]); +}; + +export default useDataEffect; diff --git a/src/frontend/src/components/cardComponent/hooks/use-handle-install.tsx b/src/frontend/src/components/cardComponent/hooks/use-handle-install.tsx new file mode 100644 index 000000000..4c407349d --- /dev/null +++ b/src/frontend/src/components/cardComponent/hooks/use-handle-install.tsx @@ -0,0 +1,55 @@ +import { useState } from "react"; +import { getComponent } from "../../../controllers/API"; +import useFlowsManagerStore from "../../../stores/flowsManagerStore"; +import { storeComponent } from "../../../types/store"; +import cloneFlowWithParent from "../../../utils/storeUtils"; + +const useInstallComponent = ( + data: storeComponent, + name: string, + isStore: boolean, + downloadsCount: number, + setDownloadsCount: (value: any) => void, + setLoading: (value: boolean) => void, + setSuccessData: (value: { title: string }) => void, + setErrorData: (value: { title: string; list: string[] }) => void, +) => { + const addFlow = useFlowsManagerStore((state) => state.addFlow); + + const handleInstall = () => { + const temp = downloadsCount; + setDownloadsCount((old) => Number(old) + 1); + setLoading(true); + + getComponent(data.id) + .then((res) => { + const newFlow = cloneFlowWithParent(res, res.id, data.is_component); + addFlow(true, newFlow) + .then((id) => { + setSuccessData({ + title: `${name} ${isStore ? "Downloaded" : "Installed"} Successfully.`, + }); + setLoading(false); + }) + .catch((error) => { + setLoading(false); + setErrorData({ + title: `Error ${isStore ? "downloading" : "installing"} the ${name}`, + list: [error.response.data.detail], + }); + }); + }) + .catch((err) => { + setLoading(false); + setErrorData({ + title: `Error ${isStore ? "downloading" : "installing"} the ${name}`, + list: [err.response.data.detail], + }); + setDownloadsCount(temp); + }); + }; + + return { handleInstall }; +}; + +export default useInstallComponent; diff --git a/src/frontend/src/components/cardComponent/hooks/use-handle-like.tsx b/src/frontend/src/components/cardComponent/hooks/use-handle-like.tsx new file mode 100644 index 000000000..bfda076be --- /dev/null +++ b/src/frontend/src/components/cardComponent/hooks/use-handle-like.tsx @@ -0,0 +1,51 @@ +import { postLikeComponent } from "../../../controllers/API"; +import { storeComponent } from "../../../types/store"; + +const useLikeComponent = ( + data: storeComponent, + name: string, + setLoadingLike: (value: boolean) => void, + likedByUser: boolean | null | undefined, + likesCount: number, + setLikedByUser: (value: any) => void, + setLikesCount: (value: any) => void, + setValidApiKey: (value: boolean) => void, + setErrorData: (value: { title: string; list: string[] }) => void, +) => { + const handleLike = () => { + setLoadingLike(true); + if (likedByUser !== undefined || likedByUser !== null) { + const temp = likedByUser; + const tempNum = likesCount; + setLikedByUser((prev) => !prev); + setLikesCount((prev) => (temp ? prev - 1 : prev + 1)); + + postLikeComponent(data.id) + .then((response) => { + setLoadingLike(false); + setLikesCount(response.data.likes_count); + setLikedByUser(response.data.liked_by_user); + }) + .catch((error) => { + setLoadingLike(false); + setLikesCount(tempNum); + setLikedByUser(temp); + if (error.response.status === 403) { + setValidApiKey(false); + } else { + console.error(error); + setErrorData({ + title: `Error liking ${name}.`, + list: [error.response.data.detail], + }); + } + }); + } + }; + + return { + handleLike, + }; +}; + +export default useLikeComponent; diff --git a/src/frontend/src/components/cardComponent/hooks/use-on-drag-start.tsx b/src/frontend/src/components/cardComponent/hooks/use-on-drag-start.tsx new file mode 100644 index 000000000..251c668e2 --- /dev/null +++ b/src/frontend/src/components/cardComponent/hooks/use-on-drag-start.tsx @@ -0,0 +1,34 @@ +import { useCallback } from "react"; +import { createRoot } from "react-dom/client"; +import useFlowsManagerStore from "../../../stores/flowsManagerStore"; +import { storeComponent } from "../../../types/store"; +import DragCardComponent from "../components/dragCardComponent"; + +const useDragStart = (data: storeComponent) => { + const getFlowById = useFlowsManagerStore((state) => state.getFlowById); + + const onDragStart = useCallback( + (event) => { + let image = ; // Replace with whatever you want here + + const ghost = document.createElement("div"); + ghost.style.transform = "translate(-10000px, -10000px)"; + ghost.style.position = "absolute"; + document.body.appendChild(ghost); + event.dataTransfer.setDragImage(ghost, 0, 0); + + const root = createRoot(ghost); + root.render(image); + + const flow = getFlowById(data.id); + if (flow) { + event.dataTransfer.setData("flow", JSON.stringify(data)); + } + }, + [data], + ); + + return { onDragStart }; +}; + +export default useDragStart; diff --git a/src/frontend/src/components/cardComponent/hooks/use-playground-effect.tsx b/src/frontend/src/components/cardComponent/hooks/use-playground-effect.tsx new file mode 100644 index 000000000..e9236e98b --- /dev/null +++ b/src/frontend/src/components/cardComponent/hooks/use-playground-effect.tsx @@ -0,0 +1,27 @@ +import { useEffect } from "react"; +import { FlowType } from "../../../types/flow"; + +const usePlaygroundEffect = ( + currentFlowId: string, + playground: boolean, + openPlayground: boolean, + currentFlow: FlowType | undefined, + setNodes: (value: any, value2: boolean) => void, + setEdges: (value: any, value2: boolean) => void, + cleanFlowPool: () => void, +) => { + useEffect(() => { + if (currentFlowId && playground) { + if (openPlayground) { + setNodes(currentFlow?.data?.nodes ?? [], true); + setEdges(currentFlow?.data?.edges ?? [], true); + } else { + setNodes([], true); + setEdges([], true); + } + cleanFlowPool(); + } + }, [openPlayground]); +}; + +export default usePlaygroundEffect; diff --git a/src/frontend/src/components/cardComponent/index.tsx b/src/frontend/src/components/cardComponent/index.tsx index ba00e6958..a77877a2f 100644 --- a/src/frontend/src/components/cardComponent/index.tsx +++ b/src/frontend/src/components/cardComponent/index.tsx @@ -28,6 +28,11 @@ import { Checkbox } from "../ui/checkbox"; import { FormControl, FormField } from "../ui/form"; import Loading from "../ui/loading"; import DragCardComponent from "./components/dragCardComponent"; +import useDataEffect from "./hooks/use-data-effect"; +import useInstallComponent from "./hooks/use-handle-install"; +import useLikeComponent from "./hooks/use-handle-like"; +import useDragStart from "./hooks/use-on-drag-start"; +import usePlaygroundEffect from "./hooks/use-playground-effect"; import { convertTestName } from "./utils/convert-test-name"; export default function CollectionCardComponent({ @@ -59,11 +64,9 @@ export default function CollectionCardComponent({ const isStore = false; const [loading, setLoading] = useState(false); const [loadingLike, setLoadingLike] = useState(false); - const [liked_by_user, setLiked_by_user] = useState( - data?.liked_by_user ?? false, - ); - const [likes_count, setLikes_count] = useState(data?.liked_by_count ?? 0); - const [downloads_count, setDownloads_count] = useState( + const [likedByUser, setLikedByUser] = useState(data?.liked_by_user ?? false); + const [likesCount, setLikesCount] = useState(data?.liked_by_count ?? 0); + const [downloadsCount, setDownloadsCount] = useState( data?.downloads_count ?? 0, ); const currentFlow = useFlowsManagerStore((state) => state.currentFlow); @@ -99,115 +102,45 @@ export default function CollectionCardComponent({ return inputs.length > 0 || outputs.length > 0; } - useEffect(() => { - if (currentFlowId && playground) { - if (openPlayground) { - setNodes(currentFlow?.data?.nodes ?? [], true); - setEdges(currentFlow?.data?.edges ?? [], true); - } else { - setNodes([], true); - setEdges([], true); - } - cleanFlowPool(); - } - }, [openPlayground]); + usePlaygroundEffect( + currentFlowId, + playground!, + openPlayground, + currentFlow, + setNodes, + setEdges, + cleanFlowPool, + ); - useEffect(() => { - if (data) { - setLiked_by_user(data?.liked_by_user ?? false); - setLikes_count(data?.liked_by_count ?? 0); - setDownloads_count(data?.downloads_count ?? 0); - } - }, [data, data.liked_by_count, data.liked_by_user, data.downloads_count]); + useDataEffect(data, setLikedByUser, setLikesCount, setDownloadsCount); - function handleInstall() { - const temp = downloads_count; - setDownloads_count((old) => Number(old) + 1); - setLoading(true); - getComponent(data.id) - .then((res) => { - const newFlow = cloneFLowWithParent(res, res.id, data.is_component); - addFlow(true, newFlow) - .then((id) => { - setSuccessData({ - title: `${name} ${ - isStore ? "Downloaded" : "Installed" - } Successfully.`, - }); - setLoading(false); - }) - .catch((error) => { - setLoading(false); - setErrorData({ - title: `Error ${ - isStore ? "downloading" : "installing" - } the ${name}`, - list: [error["response"]["data"]["detail"]], - }); - }); - }) - .catch((err) => { - setLoading(false); - setErrorData({ - title: `Error ${isStore ? "downloading" : "installing"} the ${name}`, - list: [err["response"]["data"]["detail"]], - }); - setDownloads_count(temp); - }); - } + const { handleInstall } = useInstallComponent( + data, + name, + isStore, + downloadsCount, + setDownloadsCount, + setLoading, + setSuccessData, + setErrorData, + ); - function handleLike() { - setLoadingLike(true); - if (liked_by_user !== undefined || liked_by_user !== null) { - const temp = liked_by_user; - const tempNum = likes_count; - setLiked_by_user((prev) => !prev); - if (!temp) { - setLikes_count((prev) => Number(prev) + 1); - } else { - setLikes_count((prev) => Number(prev) - 1); - } - postLikeComponent(data.id) - .then((response) => { - setLoadingLike(false); - setLikes_count(response.data.likes_count); - setLiked_by_user(response.data.liked_by_user); - }) - .catch((error) => { - setLoadingLike(false); - setLikes_count(tempNum); - setLiked_by_user(temp); - if (error.response.status === 403) { - setValidApiKey(false); - } else { - console.error(error); - setErrorData({ - title: `Error liking ${name}.`, - list: [error["response"]["data"]["detail"]], - }); - } - }); - } - } + const { handleLike } = useLikeComponent( + data, + name, + setLoadingLike, + likedByUser, + likesCount, + setLikedByUser, + setLikesCount, + setValidApiKey, + setErrorData, + ); const isSelectedCard = selectedFlowsComponentsCards?.includes(data?.id) ?? false; - function onDragStart(event: React.DragEvent) { - let image: JSX.Element = ; // <== whatever you want here - - var ghost = document.createElement("div"); - ghost.style.transform = "translate(-10000px, -10000px)"; - ghost.style.position = "absolute"; - document.body.appendChild(ghost); - event.dataTransfer.setDragImage(ghost, 0, 0); - const root = createRoot(ghost); - root.render(image); - const flow = getFlowById(data.id); - if (flow) { - event.dataTransfer.setData("flow", JSON.stringify(data)); - } - } + const { onDragStart } = useDragStart(data); return ( <> @@ -264,7 +197,7 @@ export default function CollectionCardComponent({ - {likes_count ?? 0} + {likesCount ?? 0} @@ -275,7 +208,7 @@ export default function CollectionCardComponent({ className="h-4 w-4" /> - {downloads_count ?? 0} + {downloadsCount ?? 0} @@ -296,6 +229,7 @@ export default function CollectionCardComponent({ render={({ field }) => ( )} -

- {/* {data.tags && - data.tags.length > 0 && - data.tags.map((tag, index) => ( - - {tag.name} - - ))} */} -
+
@@ -457,7 +378,7 @@ export default function CollectionCardComponent({ name="Heart" className={cn( "h-5 w-5", - liked_by_user + likedByUser ? "fill-destructive stroke-destructive" : "", !authorized ? "text-ring" : "", diff --git a/src/frontend/src/components/chatComponent/index.tsx b/src/frontend/src/components/chatComponent/index.tsx index 83c6c80c1..a88bd9573 100644 --- a/src/frontend/src/components/chatComponent/index.tsx +++ b/src/frontend/src/components/chatComponent/index.tsx @@ -67,6 +67,7 @@ export default function FlowToolbar(): JSX.Element { ? "button-disable text-muted-foreground" : "", )} + data-testid="shared-button-flow" > = ({ name, @@ -17,7 +17,7 @@ export const EditFlowSettings: React.FC = ({ setEndpointName, }: InputProps): JSX.Element => { const [isMaxLength, setIsMaxLength] = useState(false); - const [isEndpointNameValid, setIsEndpointNameValid] = useState(true); + const [validEndpointName, setValidEndpointName] = useState(true); const [isInvalidName, setIsInvalidName] = useState(false); const currentFlow = useFlowsManagerStore((state) => state.currentFlow); @@ -34,10 +34,6 @@ export const EditFlowSettings: React.FC = ({ invalid = true; break; } - if (value === currentFlow?.name) { - invalid = true; - break; - } invalid = false; } setIsInvalidName(invalid); @@ -51,12 +47,8 @@ export const EditFlowSettings: React.FC = ({ const handleEndpointNameChange = (event: ChangeEvent) => { // Validate the endpoint name // use this regex r'^[a-zA-Z0-9_-]+$' - const isValid = - (/^[a-zA-Z0-9_-]+$/.test(event.target.value) && - event.target.value.length <= maxLength) || - // empty is also valid - event.target.value.length === 0; - setIsEndpointNameValid(isValid); + const isValid = isEndpointNameValid(event.target.value, maxLength); + setValidEndpointName(isValid); setEndpointName!(event.target.value); }; @@ -115,21 +107,21 @@ export const EditFlowSettings: React.FC = ({ }} /> ) : ( - {description === "" ? "No description" : description} - +
)} {setEndpointName && (
)} diff --git a/src/frontend/src/components/headerComponent/index.tsx b/src/frontend/src/components/headerComponent/index.tsx index ab186d1db..52818f940 100644 --- a/src/frontend/src/components/headerComponent/index.tsx +++ b/src/frontend/src/components/headerComponent/index.tsx @@ -263,7 +263,7 @@ export default function Header(): JSX.Element { - window.open("https://pre-release.langflow.org/", "_blank") + window.open("https://docs.langflow.org/", "_blank") } > diff --git a/src/frontend/src/components/sidebarComponent/hooks/use-on-file-drop.tsx b/src/frontend/src/components/sidebarComponent/hooks/use-on-file-drop.tsx index c75bf4bec..4dd87fc50 100644 --- a/src/frontend/src/components/sidebarComponent/hooks/use-on-file-drop.tsx +++ b/src/frontend/src/components/sidebarComponent/hooks/use-on-file-drop.tsx @@ -9,7 +9,10 @@ import useFlowsManagerStore from "../../../stores/flowsManagerStore"; import { useFolderStore } from "../../../stores/foldersStore"; import { addVersionToDuplicates } from "../../../utils/reactflowUtils"; -const useFileDrop = (folderId, folderChangeCallback) => { +const useFileDrop = ( + folderId: string, + folderChangeCallback: (folderId: string) => void, +) => { const setFolderDragging = useFolderStore((state) => state.setFolderDragging); const setFolderIdDragging = useFolderStore( (state) => state.setFolderIdDragging, diff --git a/src/frontend/src/components/tableComponent/components/tableNodeCellRender/index.tsx b/src/frontend/src/components/tableComponent/components/tableNodeCellRender/index.tsx index b55788134..d0c3d4e53 100644 --- a/src/frontend/src/components/tableComponent/components/tableNodeCellRender/index.tsx +++ b/src/frontend/src/components/tableComponent/components/tableNodeCellRender/index.tsx @@ -153,7 +153,7 @@ export default function TableNodeCellRender({ disabled={disabled} editNode={true} value={ - templateValue?.length === 0 || !templateValue + Object.keys(templateValue)?.length === 0 || !templateValue ? [{ "": "" }] : convertObjToArray(templateValue, templateData.type) } diff --git a/src/frontend/src/components/textAreaComponent/index.tsx b/src/frontend/src/components/textAreaComponent/index.tsx index ce42437d7..18a7f5b40 100644 --- a/src/frontend/src/components/textAreaComponent/index.tsx +++ b/src/frontend/src/components/textAreaComponent/index.tsx @@ -2,6 +2,7 @@ import { useEffect } from "react"; import { EDIT_TEXT_MODAL_TITLE } from "../../constants/constants"; import { TypeModal } from "../../constants/enums"; import GenericModal from "../../modals/genericModal"; +import { Case } from "../../shared/components/caseComponent"; import { TextAreaComponentType } from "../../types/components"; import IconComponent from "../genericIconComponent"; import { Button } from "../ui/button"; @@ -24,29 +25,31 @@ export default function TextAreaComponent({ return (
- { - onChange(event.target.value); - }} - /> -
- + { - onChange(value); - }} disabled={disabled} - > - {!editNode && ( + className={editNode ? "input-edit-node w-full" : "w-full"} + placeholder={"Type something..."} + onChange={(event) => { + onChange(event.target.value); + }} + /> + + { + onChange(value); + }} + disabled={disabled} + > + {!editNode ? ( +
- )} - -
+
+ ) : ( + + )} +
); diff --git a/src/frontend/src/constants/constants.ts b/src/frontend/src/constants/constants.ts index f963d7234..8b5d4e177 100644 --- a/src/frontend/src/constants/constants.ts +++ b/src/frontend/src/constants/constants.ts @@ -863,3 +863,11 @@ export const TITLE_ERROR_UPDATING_COMPONENT = "Error while updating the Component"; export const EMPTY_INPUT_SEND_MESSAGE = "No input message provided."; + +export const TABS_ORDER = [ + "run curl", + "python api", + "js api", + "python code", + "chat widget html", +]; diff --git a/src/frontend/src/contexts/authContext.tsx b/src/frontend/src/contexts/authContext.tsx index bd5c2d02c..cfdbdfb4f 100644 --- a/src/frontend/src/contexts/authContext.tsx +++ b/src/frontend/src/contexts/authContext.tsx @@ -1,9 +1,15 @@ import { createContext, useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; import Cookies from "universal-cookie"; -import { getLoggedUser, requestLogout } from "../controllers/API"; +import { + getGlobalVariables, + getLoggedUser, + requestLogout, +} from "../controllers/API"; import useAlertStore from "../stores/alertStore"; import { useFolderStore } from "../stores/foldersStore"; +import { useGlobalVariablesStore } from "../stores/globalVariablesStore/globalVariables"; +import { useStoreStore } from "../stores/storeStore"; import { Users } from "../types/api"; import { AuthContextType } from "../types/contexts/auth"; @@ -45,6 +51,11 @@ export function AuthProvider({ children }): React.ReactElement { ); const getFoldersApi = useFolderStore((state) => state.getFoldersApi); + const setGlobalVariables = useGlobalVariablesStore( + (state) => state.setGlobalVariables, + ); + const checkHasStore = useStoreStore((state) => state.checkHasStore); + const fetchApiData = useStoreStore((state) => state.fetchApiData); useEffect(() => { const storedAccessToken = cookies.get("access_token_lf"); @@ -66,8 +77,11 @@ export function AuthProvider({ children }): React.ReactElement { setUserData(user); const isSuperUser = user!.is_superuser; setIsAdmin(isSuperUser); - getFoldersApi(true, true); + const res = await getGlobalVariables(); + setGlobalVariables(res); + checkHasStore(); + fetchApiData(); }) .catch((error) => { setLoading(false); diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index 17e89debe..3635f5f44 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -1112,7 +1112,7 @@ export async function getMessagesTable( return { rows: rowsOrganized, columns }; } -export async function deleteMessagesFn(ids: number[]) { +export async function deleteMessagesFn(ids: string[]) { try { return await api.delete(`${BASE_URL_API}monitor/messages`, { data: ids, @@ -1124,5 +1124,5 @@ export async function deleteMessagesFn(ids: number[]) { } export async function updateMessageApi(data: Message) { - return await api.post(`${BASE_URL_API}monitor/messages/${data.index}`, data); + return await api.post(`${BASE_URL_API}monitor/messages/${data.id}`, data); } diff --git a/src/frontend/src/icons/Firecrawl/FirecrawlLogo.jsx b/src/frontend/src/icons/Firecrawl/FirecrawlLogo.jsx new file mode 100644 index 000000000..f79173d13 --- /dev/null +++ b/src/frontend/src/icons/Firecrawl/FirecrawlLogo.jsx @@ -0,0 +1,61 @@ +const SvgFirecrawlLogo = (props) => ( + + + + + + + + + + + + + + + +); +export default SvgFirecrawlLogo; diff --git a/src/frontend/src/icons/Firecrawl/firecraw-logo.svg b/src/frontend/src/icons/Firecrawl/firecraw-logo.svg new file mode 100644 index 000000000..ea8d2c7f1 --- /dev/null +++ b/src/frontend/src/icons/Firecrawl/firecraw-logo.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/frontend/src/icons/Firecrawl/index.tsx b/src/frontend/src/icons/Firecrawl/index.tsx new file mode 100644 index 000000000..060d053bb --- /dev/null +++ b/src/frontend/src/icons/Firecrawl/index.tsx @@ -0,0 +1,9 @@ +import React, { forwardRef } from "react"; +import SvgFirecrawlLogo from "./FirecrawlLogo"; + +export const FirecrawlIcon = forwardRef< + SVGSVGElement, + React.PropsWithChildren<{}> +>((props, ref) => { + return ; +}); diff --git a/src/frontend/tests/end-to-end/logs.spec.ts b/src/frontend/src/logs.spec.ts similarity index 94% rename from src/frontend/tests/end-to-end/logs.spec.ts rename to src/frontend/src/logs.spec.ts index 8f5ce4a2d..f3f0a7c95 100644 --- a/src/frontend/tests/end-to-end/logs.spec.ts +++ b/src/frontend/src/logs.spec.ts @@ -33,6 +33,11 @@ test("should able to see and interact with logs", async ({ page }) => { await page .getByTestId("popover-anchor-input-openai_api_key") .fill(process.env.OPENAI_API_KEY ?? ""); + + await page.getByTestId("dropdown-model_name").click(); + await page.getByTestId("gpt-4o-0-option").click(); + + await page.waitForTimeout(2000); await page.getByTestId("button_run_chat output").first().click(); await page.waitForTimeout(2000); diff --git a/src/frontend/src/modals/IOModal/components/SessionView/hooks/index.tsx b/src/frontend/src/modals/IOModal/components/SessionView/hooks/index.tsx index e8e638def..17b44fd2b 100644 --- a/src/frontend/src/modals/IOModal/components/SessionView/hooks/index.tsx +++ b/src/frontend/src/modals/IOModal/components/SessionView/hooks/index.tsx @@ -10,7 +10,7 @@ const useRemoveSession = (setSuccessData, setErrorData) => { await deleteMessagesFn( messages .filter((msg) => msg.session_id === session_id) - .map((msg) => msg.index), + .map((msg) => msg.id), ); deleteSession(session_id); setSuccessData({ diff --git a/src/frontend/src/modals/IOModal/components/SessionView/index.tsx b/src/frontend/src/modals/IOModal/components/SessionView/index.tsx index 2ea6ef606..70174ee72 100644 --- a/src/frontend/src/modals/IOModal/components/SessionView/index.tsx +++ b/src/frontend/src/modals/IOModal/components/SessionView/index.tsx @@ -17,7 +17,7 @@ export default function SessionView({ rows }: { rows: Array }) { const setErrorData = useAlertStore((state) => state.setErrorData); const setSuccessData = useAlertStore((state) => state.setSuccessData); - const [selectedRows, setSelectedRows] = useState([]); + const [selectedRows, setSelectedRows] = useState([]); const { handleRemoveMessages } = useRemoveMessages( setSelectedRows, @@ -52,7 +52,8 @@ export default function SessionView({ rows }: { rows: Array }) { ]} overlayNoRowsTemplate="No data available" onSelectionChanged={(event: SelectionChangedEvent) => { - setSelectedRows(event.api.getSelectedRows().map((row) => row.index)); + console.log(event.api.getSelectedRows()); + setSelectedRows(event.api.getSelectedRows().map((row) => row.id)); }} rowSelection="multiple" suppressRowClickSelection={true} diff --git a/src/frontend/src/modals/IOModal/components/chatView/chatInput/components/textAreaWrapper/index.tsx b/src/frontend/src/modals/IOModal/components/chatView/chatInput/components/textAreaWrapper/index.tsx index 29f88453a..0a9ba4a7e 100644 --- a/src/frontend/src/modals/IOModal/components/chatView/chatInput/components/textAreaWrapper/index.tsx +++ b/src/frontend/src/modals/IOModal/components/chatView/chatInput/components/textAreaWrapper/index.tsx @@ -45,6 +45,7 @@ const TextAreaWrapper = ({ return (