Bugfixes and updates to Components (#1554)

- Fix issue causing Store API key to become invalid.
- Refactor the `parse_return_statement` method to handle nested returns,
addressing issue #1357.
- Update the `.env.example` file with the latest configuration options.
- Fix the `refresh_http_only` variable to ensure proper handling of
HTTP-only cookies.
- Fix uninteded submission
- Update Anthropic implementation
This commit is contained in:
Gabriel Luiz Freitas Almeida 2024-03-22 09:13:54 -03:00 • committed by GitHub
commit 18fe8ed2d0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 1824 additions and 1289 deletions

View file

@ -66,12 +66,12 @@ LANGFLOW_SUPERUSER_PASSWORD=
# STORE_URL # STORE_URL
# Example: LANGFLOW_STORE_URL=https://api.langflow.store # Example: LANGFLOW_STORE_URL=https://api.langflow.store
LANGFLOW_STORE_URL= # LANGFLOW_STORE_URL=
# DOWNLOAD_WEBHOOK_URL # DOWNLOAD_WEBHOOK_URL
# #
LANGFLOW_DOWNLOAD_WEBHOOK_URL= # LANGFLOW_DOWNLOAD_WEBHOOK_URL=
# LIKE_WEBHOOK_URL # LIKE_WEBHOOK_URL
# #
LANGFLOW_LIKE_WEBHOOK_URL= # LANGFLOW_LIKE_WEBHOOK_URL=

View file

@ -15,6 +15,7 @@ COPY ./ ./
# Install dependencies # Install dependencies
RUN poetry config virtualenvs.create false && poetry install --no-interaction --no-ansi RUN poetry config virtualenvs.create false && poetry install --no-interaction --no-ansi
RUN poetry add pymysql==1.0.2 RUN poetry add botocore
RUN poetry add pymysql
CMD ["sh", "./container-cmd-cdk.sh"] CMD ["sh", "./container-cmd-cdk.sh"]

View file

@ -1,3 +1,5 @@
export LANGFLOW_DATABASE_URL="mysql+pymysql://${username}:${password}@${host}:3306/${dbname}" export LANGFLOW_DATABASE_URL="mysql+pymysql://${username}:${password}@${host}:3306/${dbname}"
# echo $LANGFLOW_DATABASE_URL # echo $LANGFLOW_DATABASE_URL
uvicorn --factory src.backend.langflow.main:create_app --host 0.0.0.0 --port 7860 --reload --log-level debug uvicorn --factory src.backend.langflow.main:create_app --host 0.0.0.0 --port 7860 --reload --log-level debug
# python -m langflow run --host 0.0.0.0 --port 7860

1995
poetry.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "langflow" name = "langflow"
version = "0.6.10" version = "0.6.11"
description = "A Python package with a built-in web application" description = "A Python package with a built-in web application"
authors = ["Logspace <contact@logspace.ai>"] authors = ["Logspace <contact@logspace.ai>"]
maintainers = [ maintainers = [
@ -60,7 +60,6 @@ cohere = "^4.47.0"
python-multipart = "^0.0.7" python-multipart = "^0.0.7"
sqlmodel = "^0.0.14" sqlmodel = "^0.0.14"
faiss-cpu = "^1.7.4" faiss-cpu = "^1.7.4"
anthropic = "^0.15.0"
orjson = "3.9.15" orjson = "3.9.15"
multiprocess = "^0.70.14" multiprocess = "^0.70.14"
cachetools = "^5.3.1" cachetools = "^5.3.1"
@ -105,6 +104,8 @@ elasticsearch = "^8.12.0"
pytube = "^15.0.0" pytube = "^15.0.0"
llama-index = "0.9.48" llama-index = "0.9.48"
langchain-openai = "^0.0.6" langchain-openai = "^0.0.6"
urllib3 = "<2"
langchain-anthropic = "^0.1.4"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
pytest-asyncio = "^0.23.1" pytest-asyncio = "^0.23.1"

View file

@ -8,10 +8,9 @@ Langflow on AWS では、 [AWS Cloud Development Kit](https://aws.amazon.com/cdk
作成するアプリケーションのアーキテクチャです。 作成するアプリケーションのアーキテクチャです。
![langflow-archi](./img/langflow-archi.png) ![langflow-archi](./img/langflow-archi.png)
AWS CDK によって [Application Load Balancer](https://aws.amazon.com/elasticloadbalancing/application-load-balancer/?nc1=h_ls)、[AWS Fargate](https://aws.amazon.com/fargate/?nc2=type_a)、[Amazon Aurora](https://aws.amazon.com/rds/aurora/?nc2=type_a) を作成します。 AWS CDK によって Langflow のアプリケーションをデプロイします。アプリケーションは [Amazon CloudFront](https://aws.amazon.com/cloudfront/?nc1=h_ls) を介して配信されます。CloudFront は 2 つのオリジンを有しています。1 つ目は静的な Web サイトを配信するための [Amazon Simple Storage Service](https://aws.amazon.com/s3/?nc1=h_ls) (S3)、2 つ目は バックエンドと通信するための [Application Load Balancer](https://aws.amazon.com/elasticloadbalancing/application-load-balancer/?nc1=h_ls) (ALB) です。ALB の背後には FastAPI が動作する [AWS Fargate](https://aws.amazon.com/fargate/?nc2=type_a) 、データベースの [Amazon Aurora](https://aws.amazon.com/rds/aurora/?nc2=type_a) が作成されます。
Fargate は [Amazon Elastic Container Registry](https://aws.amazon.com/ecr/?nc1=h_ls) (ECR) に保存された Docker イメージを使用します。
Auroraのシークレットは [AWS Secrets Manager](https://aws.amazon.com/secrets-manager/?nc2=type_a) によって管理されます。 Auroraのシークレットは [AWS Secrets Manager](https://aws.amazon.com/secrets-manager/?nc2=type_a) によって管理されます。
Fargate のタスクはフロントエンドとバックエンドに分かれており、サービス検出によって通信します。
リソースをデプロイするだけであれば、上記の各サービスについて深い知識は必要ありません。
# 環境構築とデプロイ方法 # 環境構築とデプロイ方法
1. [AWS CloudShell](https://us-east-1.console.aws.amazon.com/cloudshell/home?region=us-east-1)を開きます。 1. [AWS CloudShell](https://us-east-1.console.aws.amazon.com/cloudshell/home?region=us-east-1)を開きます。
@ -28,7 +27,7 @@ Fargate のタスクはフロントエンドとバックエンドに分かれて
1. 以下のコマンドを実行します。 1. 以下のコマンドを実行します。
```shell ```shell
git clone -b aws-cdk https://github.com/logspace-ai/langflow.git git clone https://github.com/logspace-ai/langflow.git
cd langflow/scripts/aws cd langflow/scripts/aws
cp .env.example .env # 環境設定を変える場合はこのファイル(.env)を編集してください。 cp .env.example .env # 環境設定を変える場合はこのファイル(.env)を編集してください。
npm ci npm ci
@ -38,7 +37,7 @@ Fargate のタスクはフロントエンドとバックエンドに分かれて
1. 表示される URL にアクセスします。 1. 表示される URL にアクセスします。
```shell ```shell
Outputs: Outputs:
LangflowAppStack.NetworkURLXXXXXX = http://alb-XXXXXXXXXXX.elb.amazonaws.com LangflowAppStack.frontendURLXXXXXX = https://XXXXXXXXXXX.cloudfront.net
``` ```
1. サインイン画面でユーザー名とパスワードを入力します。`.env`ファイルでユーザー名とパスワードを設定していない場合、ユーザー名は`admin`、パスワードは`123456`で設定されます。 1. サインイン画面でユーザー名とパスワードを入力します。`.env`ファイルでユーザー名とパスワードを設定していない場合、ユーザー名は`admin`、パスワードは`123456`で設定されます。
![make-cloud9](./img/langflow-signin.png) ![make-cloud9](./img/langflow-signin.png)

View file

@ -9,11 +9,9 @@ This tutorial assumes you have an AWS account and basic knowledge of AWS.
The architecture of the application to be created: The architecture of the application to be created:
![langflow-archi](./img/langflow-archi.png) ![langflow-archi](./img/langflow-archi.png)
Langflow is deployed using AWS CDK. The application is distributed via [Amazon CloudFront](https://aws.amazon.com/cloudfront/?nc1=h_ls), which has two origins: the first is [Amazon Simple Storage Service](https://aws.amazon.com/s3/?nc1=h_ls) (S3) for serving a static website, and the second is an [Application Load Balancer](https://aws.amazon.com/elasticloadbalancing/application-load-balancer/?nc1=h_ls) (ALB) for communicating with the backend. [AWS Fargate](https://aws.amazon.com/fargate/?nc2=type_a), where FastAPI runs and [Amazon Aurora](https://aws.amazon.com/rds/aurora/?nc2=type_a), the database, are created behind the ALB.
[Application Load Balancer](https://aws.amazon.com/elasticloadbalancing/application-load-balancer/?nc1=h_ls), [AWS Fargate](https://aws.amazon.com/fargate/?nc2=type_a) and [Amazon Aurora](https://aws.amazon.com/rds/aurora/?nc2=type_a) are created by AWS CDK. Fargate uses a Docker image stored in [Amazon Elastic Container Registry](https://aws.amazon.com/ecr/?nc1=h_ls) (ECR).
The aurora's secrets are managed by [AWS Secrets Manager](https://aws.amazon.com/secrets-manager/?nc2=type_a). Aurora's secret is managed by [AWS Secrets Manager](https://aws.amazon.com/secrets-manager/?nc2=type_a).
The Fargate task is divided into a frontend and a backend, which communicate through service discovery.
If you just want to deploy resources, you do not need in-depth knowledge of each of the above services.
# How to set up your environment and deploy langflow # How to set up your environment and deploy langflow
@ -22,13 +20,14 @@ If you just want to deploy resources, you do not need in-depth knowledge of each
```shell ```shell
git clone https://github.com/aws-samples/cloud9-setup-for-prototyping git clone https://github.com/aws-samples/cloud9-setup-for-prototyping
cd cloud9-setup-for-prototyping cd cloud9-setup-for-prototyping
cat params.json | jq '.name |= "c9-for-langflow"'
./bin/bootstrap ./bin/bootstrap
``` ```
1. When you see `Done!` in Cloudshell, open `cloud9-for-prototyping` from [AWS Cloud9](https://us-east-1.console.aws.amazon.com/cloud9control/home?region=us-east-1#/). 1. When you see `Done!` in Cloudshell, open `c9-for-langflow` from [AWS Cloud9](https://us-east-1.console.aws.amazon.com/cloud9control/home?region=us-east-1#/).
![make-cloud9](./img/langflow-cloud9-en.png) ![make-cloud9](./img/langflow-cloud9-en.png)
1. Run the following command in the Cloud9 terminal. 1. Run the following command in the Cloud9 terminal.
```shell ```shell
git clone -b aws-cdk https://github.com/logspace-ai/langflow.git git clone https://github.com/logspace-ai/langflow.git
cd langflow/scripts/aws cd langflow/scripts/aws
cp .env.example .env # Edit this file if you need environment settings cp .env.example .env # Edit this file if you need environment settings
npm ci npm ci
@ -38,7 +37,7 @@ If you just want to deploy resources, you do not need in-depth knowledge of each
1. Access the URL displayed. 1. Access the URL displayed.
```shell ```shell
Outputs: Outputs:
LangflowAppStack.NetworkURLXXXXXX = http://alb-XXXXXXXXXXX.elb.amazonaws.com LangflowAppStack.frontendURLXXXXXX = https://XXXXXXXXXXX.cloudfront.net
``` ```
1. Enter your user name and password to sign in. If you have not set a user name and password in your `.env` file, the user name will be set to `admin` and the password to `123456`. 1. Enter your user name and password to sign in. If you have not set a user name and password in your `.env` file, the user name will be set to `admin` and the password to `123456`.
![signin-langflow](./img/langflow-signin.png) ![signin-langflow](./img/langflow-signin.png)
@ -49,5 +48,6 @@ If you just want to deploy resources, you do not need in-depth knowledge of each
```shell ```shell
bash delete-resources.sh bash delete-resources.sh
``` ```
1. Open [AWS CloudFormation](https://us-east-1.console.aws.amazon.com/cloudformation/home?region=us-east-1#/getting-started), select `aws-cloud9-cloud9-for-prototyping-XXXX` and delete it. 1. Open [AWS CloudFormation](https://us-east-1.console.aws.amazon.com/cloudformation/home?region=us-east-1#/getting-started), select `aws-cloud9-c9-for-langflow-XXXX` and delete it.
![delete-cfn](./img/langflow-cfn.png) ![delete-cfn](./img/langflow-cfn.png)
s

View file

@ -4,6 +4,7 @@ import * as cdk from 'aws-cdk-lib';
import { LangflowAppStack } from '../lib/cdk-stack'; import { LangflowAppStack } from '../lib/cdk-stack';
const app = new cdk.App(); const app = new cdk.App();
new LangflowAppStack(app, 'LangflowAppStack', { new LangflowAppStack(app, 'LangflowAppStack', {
/* If you don't specify 'env', this stack will be environment-agnostic. /* If you don't specify 'env', this stack will be environment-agnostic.
* Account/Region-dependent features and context lookups will not work, * Account/Region-dependent features and context lookups will not work,

View file

@ -17,6 +17,8 @@
] ]
}, },
"context": { "context": {
"ragEnabled": false,
"kendraIndexArn": null,
"@aws-cdk/aws-lambda:recognizeLayerVersion": true, "@aws-cdk/aws-lambda:recognizeLayerVersion": true,
"@aws-cdk/core:checkSecretUsage": true, "@aws-cdk/core:checkSecretUsage": true,
"@aws-cdk/core:target-partitions": [ "@aws-cdk/core:target-partitions": [

View file

@ -1,4 +1,4 @@
aws cloudformation delete-stack --stack-name LangflowAppStack # aws cloudformation delete-stack --stack-name LangflowAppStack
aws ecr delete-repository --repository-name langflow-backend-repository --force aws ecr delete-repository --repository-name langflow-backend-repository --force
aws ecr delete-repository --repository-name langflow-frontend-repository --force # aws ecr delete-repository --repository-name langflow-frontend-repository --force
# aws ecr describe-repositories --output json | jq -re ".repositories[].repositoryName" # aws ecr describe-repositories --output json | jq -re ".repositories[].repositoryName"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 291 KiB

After

Width:  |  Height:  |  Size: 224 KiB

Before After
Before After

View file

@ -2,21 +2,38 @@ import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs'; import { Construct } from 'constructs';
import * as ecs from 'aws-cdk-lib/aws-ecs' import * as ecs from 'aws-cdk-lib/aws-ecs'
import { Network, EcrRepository, FrontEndCluster, BackEndCluster, Rds, EcsIAM } from './construct'; import { Network, EcrRepository, Web, BackEndCluster, Rds, EcsIAM, Rag} from './construct';
// import * as sqs from 'aws-cdk-lib/aws-sqs'; // import * as sqs from 'aws-cdk-lib/aws-sqs';
const errorMessageForBooleanContext = (key: string) => {
return `There was an error setting $ {key}. Possible causes are as follows.
- Trying to set it with the -c option instead of changing cdk.json
- cdk.json is set to a value that is not a boolean (e.g. “true” double quotes are not required)
- no items in cdk.json (unset) `;
};
export class LangflowAppStack extends cdk.Stack { export class LangflowAppStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) { constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props); super(scope, id, props);
// Kendra Enable
const ragEnabled: boolean = this.node.tryGetContext('ragEnabled')!;
if (typeof ragEnabled !== 'boolean') {
throw new Error(errorMessageForBooleanContext('ragEnabled'));
}
if (ragEnabled) {
new Rag(this, 'Rag', {
});
}
// Arch // Arch
const arch = ecs.CpuArchitecture.X86_64 const arch = ecs.CpuArchitecture.X86_64
// VPC // VPC
const { vpc, cluster, alb, targetGroup, cloudmapNamespace, ecsFrontSG, ecsBackSG, dbSG, albSG, backendLogGroup, frontendLogGroup} = new Network(this, 'Network') const { vpc, cluster, ecsBackSG, dbSG, backendLogGroup, alb, albTG, albSG} = new Network(this, 'Network')
// ECR // ECR
const { ecrFrontEndRepository,ecrBackEndRepository} = new EcrRepository(this, 'Ecr', { const { ecrBackEndRepository } = new EcrRepository(this, 'Ecr', {
cloudmapNamespace:cloudmapNamespace,
arch:arch arch:arch
}) })
@ -25,7 +42,7 @@ export class LangflowAppStack extends cdk.Stack {
const { rdsCluster } = new Rds(this, 'Rds', { vpc, dbSG }) const { rdsCluster } = new Rds(this, 'Rds', { vpc, dbSG })
// IAM // IAM
const { frontendTaskRole, frontendTaskExecutionRole, backendTaskRole, backendTaskExecutionRole } = new EcsIAM(this, 'EcsIAM',{ const { backendTaskRole, backendTaskExecutionRole } = new EcsIAM(this, 'EcsIAM',{
rdsCluster:rdsCluster rdsCluster:rdsCluster
}) })
@ -36,29 +53,18 @@ export class LangflowAppStack extends cdk.Stack {
backendTaskRole:backendTaskRole, backendTaskRole:backendTaskRole,
backendTaskExecutionRole:backendTaskExecutionRole, backendTaskExecutionRole:backendTaskExecutionRole,
backendLogGroup:backendLogGroup, backendLogGroup:backendLogGroup,
cloudmapNamespace:cloudmapNamespace,
rdsCluster:rdsCluster, rdsCluster:rdsCluster,
alb:alb, arch:arch,
arch:arch albTG:albTG
}) })
backendService.node.addDependency(rdsCluster); backendService.node.addDependency(rdsCluster);
const frontendService = new FrontEndCluster(this, 'frontend',{ const frontendService = new Web(this, 'frontend',{
cluster:cluster, cluster:cluster,
ecsFrontSG:ecsFrontSG, alb:alb,
ecrFrontEndRepository:ecrFrontEndRepository, albSG:albSG
targetGroup: targetGroup,
backendServiceName: backendService.backendServiceName,
frontendTaskRole: frontendTaskRole,
frontendTaskExecutionRole: frontendTaskExecutionRole,
frontendLogGroup: frontendLogGroup,
cloudmapNamespace: cloudmapNamespace,
arch:arch
}) })
frontendService.node.addDependency(backendService); frontendService.node.addDependency(backendService);
// S3+CloudFront
// new Web(this,'Cloudfront-S3')
} }
} }

View file

@ -21,18 +21,17 @@ interface BackEndProps {
backendTaskRole: iam.Role; backendTaskRole: iam.Role;
backendTaskExecutionRole: iam.Role; backendTaskExecutionRole: iam.Role;
backendLogGroup: logs.LogGroup; backendLogGroup: logs.LogGroup;
cloudmapNamespace: servicediscovery.PrivateDnsNamespace;
rdsCluster:rds.DatabaseCluster rdsCluster:rds.DatabaseCluster
alb:elb.IApplicationLoadBalancer
arch:ecs.CpuArchitecture arch:ecs.CpuArchitecture
albTG: elb.ApplicationTargetGroup;
} }
export class BackEndCluster extends Construct { export class BackEndCluster extends Construct {
readonly backendServiceName: string
constructor(scope: Construct, id: string, props:BackEndProps) { constructor(scope: Construct, id: string, props:BackEndProps) {
super(scope, id) super(scope, id)
const containerPort = 7860 const backendServiceName = 'backend'
const backendServicePort = 7860
// Secrets ManagerからDB認証情報を取ってくる // Secrets ManagerからDB認証情報を取ってくる
const secretsDB = props.rdsCluster.secret!; const secretsDB = props.rdsCluster.secret!;
@ -59,20 +58,13 @@ export class BackEndCluster extends Construct {
logGroup: props.backendLogGroup, logGroup: props.backendLogGroup,
}), }),
environment:{ environment:{
// user:pass@endpoint:port/dbname
// "LANGFLOW_DATABASE_URL" : `mysql+pymysql://${username}:${password}@${host}:3306/${dbname}`,
// "LANGFLOW_DATABASE_URL" : "sqlite:///./langflow.db",
// "LANGFLOW_LANGCHAIN_CACHE" : "SQLiteCache",
// "LANGFLOW_AUTO_LOGIN" : "false",
// "LANGFLOW_SUPERUSER" : "admin",
// "LANGFLOW_SUPERUSER_PASSWORD" : "1234567"
"LANGFLOW_AUTO_LOGIN" : process.env.LANGFLOW_AUTO_LOGIN ?? 'false', "LANGFLOW_AUTO_LOGIN" : process.env.LANGFLOW_AUTO_LOGIN ?? 'false',
"LANGFLOW_SUPERUSER" : process.env.LANGFLOW_SUPERUSER ?? "admin", "LANGFLOW_SUPERUSER" : process.env.LANGFLOW_SUPERUSER ?? "admin",
"LANGFLOW_SUPERUSER_PASSWORD" : process.env.LANGFLOW_SUPERUSER_PASSWORD ?? "123456" "LANGFLOW_SUPERUSER_PASSWORD" : process.env.LANGFLOW_SUPERUSER_PASSWORD ?? "123456"
}, },
portMappings: [ portMappings: [
{ {
containerPort: containerPort, containerPort: backendServicePort,
protocol: ecs.Protocol.TCP, protocol: ecs.Protocol.TCP,
}, },
], ],
@ -84,22 +76,15 @@ export class BackEndCluster extends Construct {
"password": ecs.Secret.fromSecretsManager(secretsDB, 'password'), "password": ecs.Secret.fromSecretsManager(secretsDB, 'password'),
}, },
}); });
this.backendServiceName = 'backend'
const backendService = new ecs.FargateService(this, 'BackEndService', { const backendService = new ecs.FargateService(this, 'BackEndService', {
cluster: props.cluster, cluster: props.cluster,
serviceName: this.backendServiceName, serviceName: backendServiceName,
taskDefinition: backendTaskDefinition, taskDefinition: backendTaskDefinition,
enableExecuteCommand: true, enableExecuteCommand: true,
securityGroups: [props.ecsBackSG], securityGroups: [props.ecsBackSG],
cloudMapOptions: {
cloudMapNamespace: props.cloudmapNamespace,
containerPort: containerPort,
dnsRecordType: servicediscovery.DnsRecordType.A,
dnsTtl: Duration.seconds(10),
name: this.backendServiceName
},
vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },
}); });
props.albTG.addTarget(backendService);
} }
} }

View file

@ -9,12 +9,10 @@ import { Construct } from 'constructs'
interface ECRProps { interface ECRProps {
cloudmapNamespace: servicediscovery.PrivateDnsNamespace;
arch:ecs.CpuArchitecture; arch:ecs.CpuArchitecture;
} }
export class EcrRepository extends Construct { export class EcrRepository extends Construct {
readonly ecrFrontEndRepository: ecr.Repository
readonly ecrBackEndRepository: ecr.Repository readonly ecrBackEndRepository: ecr.Repository
constructor(scope: Construct, id: string, props: ECRProps) { constructor(scope: Construct, id: string, props: ECRProps) {
@ -22,7 +20,6 @@ export class EcrRepository extends Construct {
const imagePlatform = props.arch == ecs.CpuArchitecture.ARM64 ? Platform.LINUX_ARM64 : Platform.LINUX_AMD64 const imagePlatform = props.arch == ecs.CpuArchitecture.ARM64 ? Platform.LINUX_ARM64 : Platform.LINUX_AMD64
const backendPath = path.join(__dirname, "../../../../../", "langflow") const backendPath = path.join(__dirname, "../../../../../", "langflow")
const frontendPath = path.join(__dirname, "../../../../src/", "frontend")
const excludeDir = ['node_modules','.git', 'cdk.out'] const excludeDir = ['node_modules','.git', 'cdk.out']
const LifecycleRule = { const LifecycleRule = {
tagStatus: ecr.TagStatus.ANY, tagStatus: ecr.TagStatus.ANY,
@ -30,31 +27,16 @@ export class EcrRepository extends Construct {
maxImageCount: 30, maxImageCount: 30,
} }
// リポジトリ作成 // Backend ECR リポジトリ作成
this.ecrFrontEndRepository = new ecr.Repository(scope, 'LangflowFrontEndRepository', {
repositoryName: 'langflow-frontend-repository',
removalPolicy: RemovalPolicy.RETAIN,
imageScanOnPush: true,
})
this.ecrBackEndRepository = new ecr.Repository(scope, 'LangflowBackEndRepository', { this.ecrBackEndRepository = new ecr.Repository(scope, 'LangflowBackEndRepository', {
repositoryName: 'langflow-backend-repository', repositoryName: 'langflow-backend-repository',
removalPolicy: RemovalPolicy.RETAIN, removalPolicy: RemovalPolicy.RETAIN,
imageScanOnPush: true, imageScanOnPush: true,
}) })
// LifecycleRule作成 // LifecycleRule作成
this.ecrFrontEndRepository.addLifecycleRule(LifecycleRule)
this.ecrBackEndRepository.addLifecycleRule(LifecycleRule) this.ecrBackEndRepository.addLifecycleRule(LifecycleRule)
// Create Docker Image Asset // Create Docker Image Asset
const dockerFrontEndImageAsset = new DockerImageAsset(this, "DockerFrontEndImageAsset", {
directory: frontendPath,
file:"cdk.Dockerfile",
buildArgs:{
"BACKEND_URL":`http://backend.${props.cloudmapNamespace.namespaceName}:7860`
},
exclude: excludeDir,
platform: imagePlatform,
});
const dockerBackEndImageAsset = new DockerImageAsset(this, "DockerBackEndImageAsset", { const dockerBackEndImageAsset = new DockerImageAsset(this, "DockerBackEndImageAsset", {
directory: backendPath, directory: backendPath,
file:"cdk.Dockerfile", file:"cdk.Dockerfile",
@ -62,12 +44,6 @@ export class EcrRepository extends Construct {
platform: imagePlatform, platform: imagePlatform,
}); });
// Deploy Docker Image to ECR Repository
new ecrdeploy.ECRDeployment(this, "DeployFrontEndImage", {
src: new ecrdeploy.DockerImageName(dockerFrontEndImageAsset.imageUri),
dest: new ecrdeploy.DockerImageName(this.ecrFrontEndRepository.repositoryUri)
});
// Deploy Docker Image to ECR Repository // Deploy Docker Image to ECR Repository
new ecrdeploy.ECRDeployment(this, "DeployBackEndImage", { new ecrdeploy.ECRDeployment(this, "DeployBackEndImage", {
src: new ecrdeploy.DockerImageName(dockerBackEndImageAsset.imageUri), src: new ecrdeploy.DockerImageName(dockerBackEndImageAsset.imageUri),

View file

@ -1,117 +1,141 @@
import { Duration } from 'aws-cdk-lib' import { Stack, Duration, RemovalPolicy, CfnOutput } from 'aws-cdk-lib';
import { Construct } from 'constructs' import { Construct } from 'constructs';
import { import {
aws_ec2 as ec2, aws_ec2 as ec2,
aws_ecs as ecs, aws_ecs as ecs,
aws_ecr as ecr, aws_s3 as s3,
aws_servicediscovery as servicediscovery,
aws_iam as iam, aws_iam as iam,
aws_logs as logs, aws_logs as logs,
aws_elasticloadbalancingv2 as elb, aws_elasticloadbalancingv2 as elb,
aws_cloudfront as cloudfront,
aws_cloudfront_origins as origins,
aws_s3_deployment as s3_deployment
} from 'aws-cdk-lib'; } from 'aws-cdk-lib';
import { CpuArchitecture } from 'aws-cdk-lib/aws-ecs'; import { CloudFrontToS3 } from '@aws-solutions-constructs/aws-cloudfront-s3';
import { CfnDistribution, Distribution } from 'aws-cdk-lib/aws-cloudfront';
import { NodejsBuild } from 'deploy-time-build';
interface FrontEndProps { interface WebProps {
cluster:ecs.Cluster cluster:ecs.Cluster
ecsFrontSG:ec2.SecurityGroup alb:elb.IApplicationLoadBalancer;
ecrFrontEndRepository:ecr.Repository albSG:ec2.SecurityGroup;
targetGroup: elb.ApplicationTargetGroup;
backendServiceName: string;
frontendTaskRole: iam.Role;
frontendTaskExecutionRole: iam.Role;
frontendLogGroup: logs.LogGroup;
cloudmapNamespace: servicediscovery.PrivateDnsNamespace;
arch:ecs.CpuArchitecture;
} }
export class FrontEndCluster extends Construct { export class Web extends Construct {
constructor(scope: Construct, id: string, props:FrontEndProps) { readonly distribution;
constructor(scope: Construct, id: string, props:WebProps) {
super(scope, id) super(scope, id)
const containerPort = 3000 const commonBucketProps: s3.BucketProps = {
const frontendTaskDefinition = new ecs.FargateTaskDefinition( blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
encryption: s3.BucketEncryption.S3_MANAGED,
autoDeleteObjects: true,
removalPolicy: RemovalPolicy.DESTROY,
objectOwnership: s3.ObjectOwnership.OBJECT_WRITER,
enforceSSL: true,
};
// CDKにて 静的WebサイトをホストするためのAmazon S3バケットを作成
const websiteBucket = new s3.Bucket(this, 'LangflowWebsiteBucket', commonBucketProps);
const originAccessIdentity = new cloudfront.OriginAccessIdentity(
this, this,
'FrontendTaskDef', 'OriginAccessIdentity',
{ {
memoryLimitMiB: 3072, comment: 'langflow-distribution-originAccessIdentity',
cpu: 1024,
executionRole: props.frontendTaskExecutionRole,
runtimePlatform:{
operatingSystemFamily: ecs.OperatingSystemFamily.LINUX,
cpuArchitecture: props.arch,
},
taskRole: props.frontendTaskRole,
} }
); );
const frontendServiceName = 'frontend'
frontendTaskDefinition.addContainer('frontendContainer', { const webSiteBucketPolicyStatement = new iam.PolicyStatement({
image: ecs.ContainerImage.fromEcrRepository(props.ecrFrontEndRepository, "latest"), actions: ['s3:GetObject'],
containerName:'langflow-front-container', effect: iam.Effect.ALLOW,
environment: { principals: [
BACKEND_SERVICE_NAME: props.backendServiceName, new iam.CanonicalUserPrincipal(
BACKEND_URL: `http://${props.backendServiceName}.${props.cloudmapNamespace.namespaceName}:7860/`, originAccessIdentity.cloudFrontOriginAccessIdentityS3CanonicalUserId
VITE_PROXY_TARGET: `http://${props.backendServiceName}.${props.cloudmapNamespace.namespaceName}:7860/`, ),
}, ],
logging: ecs.LogDriver.awsLogs({ resources: [`${websiteBucket.bucketArn}/*`],
streamPrefix: 'my-stream', });
logGroup: props.frontendLogGroup,
}), websiteBucket.addToResourcePolicy(webSiteBucketPolicyStatement);
portMappings: [ websiteBucket.grantRead(originAccessIdentity);
const s3SpaOrigin = new origins.S3Origin(websiteBucket);
const ApiSpaOrigin = new origins.LoadBalancerV2Origin(props.alb,{
protocolPolicy: cloudfront.OriginProtocolPolicy.HTTP_ONLY
});
const albBehaviorOptions = {
origin: ApiSpaOrigin,
allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL,
viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.ALLOW_ALL,
cachePolicy: cloudfront.CachePolicy.CACHING_DISABLED,
originRequestPolicy: cloudfront.OriginRequestPolicy.ALL_VIEWER_EXCEPT_HOST_HEADER
}
const cloudFrontWebDistribution = new cloudfront.Distribution(this, 'distribution', {
comment: 'langflow-distribution',
defaultRootObject: 'index.html',
errorResponses: [
{ {
name:frontendServiceName, httpStatus: 403,
containerPort: containerPort, responseHttpStatus: 200,
protocol: ecs.Protocol.TCP, responsePagePath: '/index.html',
appProtocol:ecs.AppProtocol.http, },
{
httpStatus: 404,
responseHttpStatus: 200,
responsePagePath: '/index.html',
}, },
], ],
}); defaultBehavior: { origin: s3SpaOrigin },
const frontendService = new ecs.FargateService( additionalBehaviors: {
this, '/api/v1/*': albBehaviorOptions,
'FrontendService', '/health' : albBehaviorOptions,
{
serviceName: frontendServiceName,
cluster: props.cluster,
desiredCount: 1,
assignPublicIp: false,
taskDefinition: frontendTaskDefinition,
enableExecuteCommand: true,
securityGroups: [props.ecsFrontSG],
cloudMapOptions: {
cloudMapNamespace: props.cloudmapNamespace,
containerPort: containerPort,
dnsRecordType: servicediscovery.DnsRecordType.A,
dnsTtl: Duration.seconds(10),
name: frontendServiceName
}, },
healthCheckGracePeriod: Duration.seconds(1000), enableLogging: true, // ログ出力設定
} logBucket: new s3.Bucket(this, 'LogBucket',commonBucketProps),
); logFilePrefix: 'distribution-access-logs/',
logIncludesCookies: true,
});
this.distribution = cloudFrontWebDistribution;
props.targetGroup.addTarget(frontendService);
// // Create ALB and ECS Fargate Service new NodejsBuild(this, 'BuildFrontEnd', {
// const frontService = new ecs_patterns.ApplicationLoadBalancedFargateService( assets: [
// this, {
// "FrontEndService", path: '../../src/frontend',
// { exclude: [
// cluster: cluster, '.git',
// serviceName: 'langflow-frontend-service', '.github',
// cpu: 256, '.gitignore',
// memoryLimitMiB: 512, '.prettierignore',
// listenerPort: 80, 'build',
// assignPublicIp: true, // Public facing - ALB 'node_modules'
// taskSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, ],
// securityGroups:[ecsFrontSG], },
// taskImageOptions: { ],
// family: 'langflow-taskdef', nodejsVersion:20,
// containerName: 'langflow-front-container', destinationBucket: websiteBucket,
// image: ecs.ContainerImage.fromEcrRepository(ecrFrontEndRepository, "latest"), distribution: cloudFrontWebDistribution,
// containerPort: 3000, // L2なので、TargetGroupのportが3000で設定されるはず outputSourceDirectory: 'build',
// }, buildCommands: ['npm install', 'npm run build'],
// loadBalancer:alb, buildEnvironment: {
// openListener:false, // VITE_AXIOS_BASE_URL: `https://${this.distribution.domainName}`
// } },
// ); });
// distribution から backendへのinbound 許可
const alb_listen_port=80
props.albSG.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(alb_listen_port))
const alb_listen_port_443=443
props.albSG.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(alb_listen_port_443))
new CfnOutput(this, 'URL', {
value: `https://${this.distribution.domainName}`,
});
}
}
} }

View file

@ -10,8 +10,6 @@ interface IAMProps {
} }
export class EcsIAM extends Construct { export class EcsIAM extends Construct {
readonly frontendTaskRole: iam.Role;
readonly frontendTaskExecutionRole: iam.Role;
readonly backendTaskRole: iam.Role; readonly backendTaskRole: iam.Role;
readonly backendTaskExecutionRole: iam.Role; readonly backendTaskExecutionRole: iam.Role;
@ -58,12 +56,6 @@ export class EcsIAM extends Construct {
})], })],
}) })
// FrontEnd Task Role
this.frontendTaskRole = new iam.Role(this, 'FrontendTaskRole', {
assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'),
});
this.frontendTaskRole.addToPolicy(ECSExecPolicyStatement);
// BackEnd Task Role // BackEnd Task Role
this.backendTaskRole = new iam.Role(this, 'BackendTaskRole', { this.backendTaskRole = new iam.Role(this, 'BackendTaskRole', {
assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'),
@ -73,17 +65,6 @@ export class EcsIAM extends Construct {
// KendraとBedrockのアクセス権付与 // KendraとBedrockのアクセス権付与
this.backendTaskRole.attachInlinePolicy(RagAccessPolicy); this.backendTaskRole.attachInlinePolicy(RagAccessPolicy);
// FrontEnd Task ExecutionRole
this.frontendTaskExecutionRole = new iam.Role(this, 'frontendTaskExecutionRole', {
assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'),
managedPolicies: [
{
managedPolicyArn:
'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy',
},
],
});
// BackEnd Task ExecutionRole // BackEnd Task ExecutionRole
this.backendTaskExecutionRole = new iam.Role(this, 'backendTaskExecutionRole', { this.backendTaskExecutionRole = new iam.Role(this, 'backendTaskExecutionRole', {
assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'),

View file

@ -4,3 +4,4 @@ export * from './iam';
export * from './frontend'; export * from './frontend';
export * from './backend'; export * from './backend';
export * from './network'; export * from './network';
export * from './kendra';

View file

@ -0,0 +1,141 @@
import * as kendra from 'aws-cdk-lib/aws-kendra';
import * as iam from 'aws-cdk-lib/aws-iam';
import { Construct } from 'constructs';
import { Duration, Token, Arn } from 'aws-cdk-lib';
import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';
import { Runtime } from 'aws-cdk-lib/aws-lambda';
export interface RagProps {
}
/**
* RAG を実行するためのリソースを作成する
*/
export class Rag extends Construct {
constructor(scope: Construct, id: string, props: RagProps) {
super(scope, id);
const kendraIndexArnInCdkContext =
this.node.tryGetContext('kendraIndexArn');
let kendraIndexArn: string;
let kendraIndexId: string;
if (kendraIndexArnInCdkContext) {
// 既存の Kendra Index を利用する場合
kendraIndexArn = kendraIndexArnInCdkContext!;
kendraIndexId = Arn.extractResourceName(
kendraIndexArnInCdkContext,
'index'
);
} else {
// 新規に Kendra Index を作成する場合
const indexRole = new iam.Role(this, 'KendraIndexRole', {
assumedBy: new iam.ServicePrincipal('kendra.amazonaws.com'),
});
indexRole.addToPolicy(
new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
resources: ['*'],
actions: ['s3:GetObject'],
})
);
indexRole.addManagedPolicy(
iam.ManagedPolicy.fromAwsManagedPolicyName('CloudWatchLogsFullAccess')
);
const index = new kendra.CfnIndex(this, 'KendraIndex', {
name: 'langflow-index',
edition: 'DEVELOPER_EDITION',
roleArn: indexRole.roleArn,
});
kendraIndexArn = Token.asString(index.getAtt('Arn'));
kendraIndexId = index.ref;
// WebCrawler を作成
const webCrawlerRole = new iam.Role(this, 'KendraWebCrawlerRole', {
assumedBy: new iam.ServicePrincipal('kendra.amazonaws.com'),
});
webCrawlerRole.addToPolicy(
new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
resources: [kendraIndexArn],
actions: ['kendra:BatchPutDocument', 'kendra:BatchDeleteDocument'],
})
);
new kendra.CfnDataSource(this, 'WebCrawler', {
indexId: kendraIndexId,
name: 'WebCrawler',
type: 'WEBCRAWLER',
roleArn: webCrawlerRole.roleArn,
languageCode: 'ja',
dataSourceConfiguration: {
webCrawlerConfiguration: {
urls: {
seedUrlConfiguration: {
webCrawlerMode: 'HOST_ONLY',
// デモ用に AWS の GenAI 関連のページを取り込む
seedUrls: [
'https://aws.amazon.com/jp/what-is/generative-ai/',
'https://aws.amazon.com/jp/generative-ai/',
'https://aws.amazon.com/jp/generative-ai/use-cases/',
'https://aws.amazon.com/jp/bedrock/',
'https://aws.amazon.com/jp/bedrock/features/',
'https://aws.amazon.com/jp/bedrock/testimonials/',
],
},
},
crawlDepth: 1,
urlInclusionPatterns: ['https://aws.amazon.com/jp/.*'],
},
},
});
}
// RAG 関連の API を追加する
// Lambda
const queryFunction = new NodejsFunction(this, 'Query', {
runtime: Runtime.NODEJS_18_X,
entry: './lambda/queryKendra.ts',
timeout: Duration.minutes(15),
bundling: {
// 新しい Kendra の機能を使うため、AWS SDK を明示的にバンドルする
externalModules: [],
},
environment: {
INDEX_ID: kendraIndexId,
},
});
queryFunction.role?.addToPrincipalPolicy(
new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
resources: [kendraIndexArn],
actions: ['kendra:Query'],
})
);
const retrieveFunction = new NodejsFunction(this, 'Retrieve', {
runtime: Runtime.NODEJS_18_X,
entry: './lambda/retrieveKendra.ts',
timeout: Duration.minutes(15),
bundling: {
// 新しい Kendra の機能を使うため、AWS SDK を明示的にバンドルする
externalModules: [],
},
environment: {
INDEX_ID: kendraIndexId,
},
});
retrieveFunction.role?.addToPrincipalPolicy(
new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
resources: [kendraIndexArn],
actions: ['kendra:Retrieve'],
})
);
}
}

View file

@ -11,20 +11,16 @@ import {
export class Network extends Construct { export class Network extends Construct {
readonly vpc: ec2.Vpc; readonly vpc: ec2.Vpc;
readonly cluster: ecs.Cluster; readonly cluster: ecs.Cluster;
readonly alb: elb.IApplicationLoadBalancer;
readonly targetGroup: elb.ApplicationTargetGroup;
readonly cloudmapNamespace: servicediscovery.PrivateDnsNamespace;
readonly ecsFrontSG: ec2.SecurityGroup;
readonly ecsBackSG: ec2.SecurityGroup; readonly ecsBackSG: ec2.SecurityGroup;
readonly dbSG: ec2.SecurityGroup; readonly dbSG: ec2.SecurityGroup;
readonly albSG: ec2.SecurityGroup;
readonly backendLogGroup: logs.LogGroup; readonly backendLogGroup: logs.LogGroup;
readonly frontendLogGroup: logs.LogGroup; readonly alb: elb.IApplicationLoadBalancer;
readonly albTG: elb.ApplicationTargetGroup;
readonly albSG: ec2.SecurityGroup;
constructor(scope: Construct, id: string) { constructor(scope: Construct, id: string) {
super(scope, id) super(scope, id)
const alb_listen_port=80 const alb_listen_port=80
const front_service_port=3000
const back_service_port=7860 const back_service_port=7860
// VPC等リソースの作成 // VPC等リソースの作成
@ -51,22 +47,6 @@ export class Network extends Construct {
], ],
natGateways: 1, natGateways: 1,
}) })
// Cluster
this.cluster = new ecs.Cluster(this, 'EcsCluster', {
clusterName: 'langflow-cluster',
vpc: this.vpc,
enableFargateCapacityProviders: true,
});
// Private DNS
this.cloudmapNamespace = new servicediscovery.PrivateDnsNamespace(
this,
'Namespace',
{
name: 'ecs-deploy.com',
vpc: this.vpc,
}
);
// ALBに設定するセキュリティグループ // ALBに設定するセキュリティグループ
this.albSG = new ec2.SecurityGroup(scope, 'ALBSecurityGroup', { this.albSG = new ec2.SecurityGroup(scope, 'ALBSecurityGroup', {
@ -74,7 +54,6 @@ export class Network extends Construct {
description: 'for alb', description: 'for alb',
vpc: this.vpc, vpc: this.vpc,
}) })
this.albSG.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(alb_listen_port))
this.alb = new elb.ApplicationLoadBalancer(this,'langflow-alb',{ this.alb = new elb.ApplicationLoadBalancer(this,'langflow-alb',{
internetFacing: true, //インターネットからのアクセスを許可するかどうか指定 internetFacing: true, //インターネットからのアクセスを許可するかどうか指定
@ -85,8 +64,8 @@ export class Network extends Construct {
const listener = this.alb.addListener('Listener', { port: alb_listen_port }); const listener = this.alb.addListener('Listener', { port: alb_listen_port });
this.targetGroup = listener.addTargets('targetGroup', { this.albTG = listener.addTargets('targetGroup', {
port: front_service_port, port: back_service_port,
protocol: elb.ApplicationProtocol.HTTP, protocol: elb.ApplicationProtocol.HTTP,
healthCheck: { healthCheck: {
enabled: true, enabled: true,
@ -99,13 +78,12 @@ export class Network extends Construct {
}, },
}); });
// ECS FrontEndに設定するセキュリティグループ // Cluster
this.ecsFrontSG = new ec2.SecurityGroup(scope, 'ECSFrontEndSecurityGroup', { this.cluster = new ecs.Cluster(this, 'EcsCluster', {
securityGroupName: 'langflow-ecs-front-sg', clusterName: 'langflow-cluster',
description: 'for langflow-front-ecs',
vpc: this.vpc, vpc: this.vpc,
}) enableFargateCapacityProviders: true,
this.ecsFrontSG.addIngressRule(this.albSG, ec2.Port.allTcp()) });
// ECS BackEndに設定するセキュリティグループ // ECS BackEndに設定するセキュリティグループ
this.ecsBackSG = new ec2.SecurityGroup(scope, 'ECSBackEndSecurityGroup', { this.ecsBackSG = new ec2.SecurityGroup(scope, 'ECSBackEndSecurityGroup', {
@ -113,7 +91,7 @@ export class Network extends Construct {
description: 'for langflow-back-ecs', description: 'for langflow-back-ecs',
vpc: this.vpc, vpc: this.vpc,
}) })
this.ecsBackSG.addIngressRule(this.ecsFrontSG, ec2.Port.tcp(back_service_port)) this.ecsBackSG.addIngressRule(this.albSG,ec2.Port.tcp(back_service_port))
// RDSに設定するセキュリティグループ // RDSに設定するセキュリティグループ
this.dbSG = new ec2.SecurityGroup(scope, 'DBSecurityGroup', { this.dbSG = new ec2.SecurityGroup(scope, 'DBSecurityGroup', {
@ -122,7 +100,7 @@ export class Network extends Construct {
description: 'for langflow-db', description: 'for langflow-db',
vpc: this.vpc, vpc: this.vpc,
}) })
// AppRunnerSecurityGroupからのポート3306:mysql(5432:postgres)のインバウンドを許可 // langflow-ecs-back-sg からのポート3306:mysql(5432:postgres)のインバウンドを許可
this.dbSG.addIngressRule(this.ecsBackSG, ec2.Port.tcp(3306)) this.dbSG.addIngressRule(this.ecsBackSG, ec2.Port.tcp(3306))
// Create CloudWatch Log Group // Create CloudWatch Log Group
@ -131,13 +109,5 @@ export class Network extends Construct {
removalPolicy: RemovalPolicy.DESTROY, removalPolicy: RemovalPolicy.DESTROY,
}); });
this.frontendLogGroup = new logs.LogGroup(this, 'frontendLogGroup', {
logGroupName: 'langflow-frontend-logs',
removalPolicy: RemovalPolicy.DESTROY,
});
new CfnOutput(this, 'URL', {
value: `http://${this.alb.loadBalancerDnsName}`,
});
} }
} }

View file

@ -8,9 +8,11 @@
"name": "cdk", "name": "cdk",
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"aws-cdk-lib": "^2.86.0", "@aws-solutions-constructs/aws-cloudfront-s3": "^2.49.0",
"aws-cdk-lib": "^2.124.0",
"cdk-ecr-deployment": "^2.5.30", "cdk-ecr-deployment": "^2.5.30",
"constructs": "^10.0.0", "constructs": "^10.0.0",
"deploy-time-build": "^0.3.12",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"source-map-support": "^0.5.21" "source-map-support": "^0.5.21"
}, },
@ -20,7 +22,7 @@
"devDependencies": { "devDependencies": {
"@types/jest": "^29.5.1", "@types/jest": "^29.5.1",
"@types/node": "20.1.7", "@types/node": "20.1.7",
"aws-cdk": "2.86.0", "aws-cdk": "^2.86.0",
"jest": "^29.5.0", "jest": "^29.5.0",
"ts-jest": "^29.1.0", "ts-jest": "^29.1.0",
"ts-node": "^10.9.1", "ts-node": "^10.9.1",
@ -41,19 +43,324 @@
} }
}, },
"node_modules/@aws-cdk/asset-awscli-v1": { "node_modules/@aws-cdk/asset-awscli-v1": {
"version": "2.2.201", "version": "2.2.202",
"resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.201.tgz", "resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.202.tgz",
"integrity": "sha512-INZqcwDinNaIdb5CtW3ez5s943nX5stGBQS6VOP2JDlOFP81hM3fds/9NDknipqfUkZM43dx+HgVvkXYXXARCQ==" "integrity": "sha512-JqlF0D4+EVugnG5dAsNZMqhu3HW7ehOXm5SDMxMbXNDMdsF0pxtQKNHRl52z1U9igsHmaFpUgSGjbhAJ+0JONg=="
}, },
"node_modules/@aws-cdk/asset-kubectl-v20": { "node_modules/@aws-cdk/asset-kubectl-v20": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/@aws-cdk/asset-kubectl-v20/-/asset-kubectl-v20-2.1.2.tgz", "resolved": "https://registry.npmjs.org/@aws-cdk/asset-kubectl-v20/-/asset-kubectl-v20-2.1.2.tgz",
"integrity": "sha512-3M2tELJOxQv0apCIiuKQ4pAbncz9GuLwnKFqxifWfe77wuMxyTRPmxssYHs42ePqzap1LT6GDcPygGs+hHstLg==" "integrity": "sha512-3M2tELJOxQv0apCIiuKQ4pAbncz9GuLwnKFqxifWfe77wuMxyTRPmxssYHs42ePqzap1LT6GDcPygGs+hHstLg=="
}, },
"node_modules/@aws-cdk/asset-node-proxy-agent-v5": { "node_modules/@aws-cdk/asset-node-proxy-agent-v6": {
"version": "2.0.166", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@aws-cdk/asset-node-proxy-agent-v5/-/asset-node-proxy-agent-v5-2.0.166.tgz", "resolved": "https://registry.npmjs.org/@aws-cdk/asset-node-proxy-agent-v6/-/asset-node-proxy-agent-v6-2.0.1.tgz",
"integrity": "sha512-j0xnccpUQHXJKPgCwQcGGNu4lRiC1PptYfdxBIH1L4dRK91iBxtSQHESRQX+yB47oGLaF/WfNN/aF3WXwlhikg==" "integrity": "sha512-DDt4SLdLOwWCjGtltH4VCST7hpOI5DzieuhGZsBpZ+AgJdSI2GCjklCXm0GCTwJG/SolkL5dtQXyUKgg9luBDg=="
},
"node_modules/@aws-solutions-constructs/aws-cloudfront-s3": {
"version": "2.49.0",
"resolved": "https://registry.npmjs.org/@aws-solutions-constructs/aws-cloudfront-s3/-/aws-cloudfront-s3-2.49.0.tgz",
"integrity": "sha512-0VMtl+Ma+aLZo3Nuvq9bTl/Oz9vn5OaPEOELr9pe8kYuoHwGQUGuxXP/xJlQUWbXwR3JCQVcN5k4kdnD5eLXFw==",
"dependencies": {
"@aws-solutions-constructs/core": "2.49.0",
"@aws-solutions-constructs/resources": "2.49.0"
},
"peerDependencies": {
"@aws-solutions-constructs/core": "2.49.0",
"@aws-solutions-constructs/resources": "2.49.0",
"aws-cdk-lib": "^2.118.0",
"constructs": "^10.0.0"
}
},
"node_modules/@aws-solutions-constructs/core": {
"version": "2.49.0",
"resolved": "https://registry.npmjs.org/@aws-solutions-constructs/core/-/core-2.49.0.tgz",
"integrity": "sha512-SZ3CBYF6jVQj0DSNwhksqwz5ohW4w+DlgKiZhrO9gLiW4YcRrxFzwQ7I9FHFUDPZOxsN4NmsuQNj/3s02gycmQ==",
"bundleDependencies": [
"deepmerge",
"npmlog",
"deep-diff"
],
"dependencies": {
"deep-diff": "^1.0.2",
"deepmerge": "^4.0.0",
"npmlog": "^4.1.2"
},
"peerDependencies": {
"aws-cdk-lib": "^2.118.0",
"constructs": "^10.0.0"
}
},
"node_modules/@aws-solutions-constructs/core/node_modules/ansi-regex": {
"version": "2.1.1",
"inBundle": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/@aws-solutions-constructs/core/node_modules/aproba": {
"version": "1.2.0",
"inBundle": true,
"license": "ISC"
},
"node_modules/@aws-solutions-constructs/core/node_modules/are-we-there-yet": {
"version": "1.1.7",
"inBundle": true,
"license": "ISC",
"dependencies": {
"delegates": "^1.0.0",
"readable-stream": "^2.0.6"
}
},
"node_modules/@aws-solutions-constructs/core/node_modules/code-point-at": {
"version": "1.1.0",
"inBundle": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/@aws-solutions-constructs/core/node_modules/console-control-strings": {
"version": "1.1.0",
"inBundle": true,
"license": "ISC"
},
"node_modules/@aws-solutions-constructs/core/node_modules/core-util-is": {
"version": "1.0.3",
"inBundle": true,
"license": "MIT"
},
"node_modules/@aws-solutions-constructs/core/node_modules/deep-diff": {
"version": "1.0.2",
"inBundle": true,
"license": "MIT"
},
"node_modules/@aws-solutions-constructs/core/node_modules/deepmerge": {
"version": "4.3.1",
"inBundle": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/@aws-solutions-constructs/core/node_modules/delegates": {
"version": "1.0.0",
"inBundle": true,
"license": "MIT"
},
"node_modules/@aws-solutions-constructs/core/node_modules/emoji-regex": {
"version": "8.0.0",
"inBundle": true,
"license": "MIT"
},
"node_modules/@aws-solutions-constructs/core/node_modules/gauge": {
"version": "2.7.4",
"inBundle": true,
"license": "ISC",
"dependencies": {
"aproba": "^1.0.3",
"console-control-strings": "^1.0.0",
"has-unicode": "^2.0.0",
"object-assign": "^4.1.0",
"signal-exit": "^3.0.0",
"string-width": "^1.0.1",
"strip-ansi": "^3.0.1",
"wide-align": "^1.1.0"
}
},
"node_modules/@aws-solutions-constructs/core/node_modules/has-unicode": {
"version": "2.0.1",
"inBundle": true,
"license": "ISC"
},
"node_modules/@aws-solutions-constructs/core/node_modules/inherits": {
"version": "2.0.4",
"inBundle": true,
"license": "ISC"
},
"node_modules/@aws-solutions-constructs/core/node_modules/is-fullwidth-code-point": {
"version": "1.0.0",
"inBundle": true,
"license": "MIT",
"dependencies": {
"number-is-nan": "^1.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/@aws-solutions-constructs/core/node_modules/isarray": {
"version": "1.0.0",
"inBundle": true,
"license": "MIT"
},
"node_modules/@aws-solutions-constructs/core/node_modules/npmlog": {
"version": "4.1.2",
"inBundle": true,
"license": "ISC",
"dependencies": {
"are-we-there-yet": "~1.1.2",
"console-control-strings": "~1.1.0",
"gauge": "~2.7.3",
"set-blocking": "~2.0.0"
}
},
"node_modules/@aws-solutions-constructs/core/node_modules/number-is-nan": {
"version": "1.0.1",
"inBundle": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/@aws-solutions-constructs/core/node_modules/object-assign": {
"version": "4.1.1",
"inBundle": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/@aws-solutions-constructs/core/node_modules/process-nextick-args": {
"version": "2.0.1",
"inBundle": true,
"license": "MIT"
},
"node_modules/@aws-solutions-constructs/core/node_modules/readable-stream": {
"version": "2.3.8",
"inBundle": true,
"license": "MIT",
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"node_modules/@aws-solutions-constructs/core/node_modules/safe-buffer": {
"version": "5.1.2",
"inBundle": true,
"license": "MIT"
},
"node_modules/@aws-solutions-constructs/core/node_modules/set-blocking": {
"version": "2.0.0",
"inBundle": true,
"license": "ISC"
},
"node_modules/@aws-solutions-constructs/core/node_modules/signal-exit": {
"version": "3.0.7",
"inBundle": true,
"license": "ISC"
},
"node_modules/@aws-solutions-constructs/core/node_modules/string_decoder": {
"version": "1.1.1",
"inBundle": true,
"license": "MIT",
"dependencies": {
"safe-buffer": "~5.1.0"
}
},
"node_modules/@aws-solutions-constructs/core/node_modules/string-width": {
"version": "1.0.2",
"inBundle": true,
"license": "MIT",
"dependencies": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
"strip-ansi": "^3.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/@aws-solutions-constructs/core/node_modules/strip-ansi": {
"version": "3.0.1",
"inBundle": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^2.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/@aws-solutions-constructs/core/node_modules/util-deprecate": {
"version": "1.0.2",
"inBundle": true,
"license": "MIT"
},
"node_modules/@aws-solutions-constructs/core/node_modules/wide-align": {
"version": "1.1.5",
"inBundle": true,
"license": "ISC",
"dependencies": {
"string-width": "^1.0.2 || 2 || 3 || 4"
}
},
"node_modules/@aws-solutions-constructs/core/node_modules/wide-align/node_modules/ansi-regex": {
"version": "5.0.1",
"inBundle": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/@aws-solutions-constructs/core/node_modules/wide-align/node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"inBundle": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/@aws-solutions-constructs/core/node_modules/wide-align/node_modules/string-width": {
"version": "4.2.3",
"inBundle": true,
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@aws-solutions-constructs/core/node_modules/wide-align/node_modules/strip-ansi": {
"version": "6.0.1",
"inBundle": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@aws-solutions-constructs/resources": {
"version": "2.49.0",
"resolved": "https://registry.npmjs.org/@aws-solutions-constructs/resources/-/resources-2.49.0.tgz",
"integrity": "sha512-HHx9tTA36plfVxzzQ+qjHCJOo6ikHR+xEqtb1dDBQvgtWo3SnEbWAKBDqNPA6DGn7PoFhxE0zA0ntj7RfFjeLQ==",
"bundleDependencies": [
"@aws-sdk/client-kms",
"@aws-sdk/client-s3",
"aws-sdk-client-mock"
],
"dependencies": {
"@aws-sdk/client-kms": "^3.478.0",
"@aws-sdk/client-s3": "^3.478.0",
"@aws-solutions-constructs/core": "2.49.0",
"aws-sdk-client-mock": "^3.0.0"
},
"peerDependencies": {
"@aws-solutions-constructs/core": "2.49.0",
"aws-cdk-lib": "^2.118.0",
"constructs": "^10.0.0"
}
}, },
"node_modules/@babel/code-frame": { "node_modules/@babel/code-frame": {
"version": "7.22.13", "version": "7.22.13",
@ -1313,9 +1620,9 @@
} }
}, },
"node_modules/aws-cdk-lib": { "node_modules/aws-cdk-lib": {
"version": "2.86.0", "version": "2.124.0",
"resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.86.0.tgz", "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.124.0.tgz",
"integrity": "sha512-76yZ2MawAGXLD3ox4FjhUIPmAMXteGKkeo3tPMthemusDCCkD2X6DBssXBHjB7r9GnrOMMf8JH5BGq2lOZ539g==", "integrity": "sha512-K/Tey8TMw30GO6UD0qb19CPhBMZhleGshz520ZnbDUJwNfFtejwZOnpmRMOdUP9f4tHc5BrXl1VGsZtXtUaGhg==",
"bundleDependencies": [ "bundleDependencies": [
"@balena/dockerignore", "@balena/dockerignore",
"case", "case",
@ -1329,17 +1636,17 @@
"yaml" "yaml"
], ],
"dependencies": { "dependencies": {
"@aws-cdk/asset-awscli-v1": "^2.2.177", "@aws-cdk/asset-awscli-v1": "^2.2.202",
"@aws-cdk/asset-kubectl-v20": "^2.1.1", "@aws-cdk/asset-kubectl-v20": "^2.1.2",
"@aws-cdk/asset-node-proxy-agent-v5": "^2.0.148", "@aws-cdk/asset-node-proxy-agent-v6": "^2.0.1",
"@balena/dockerignore": "^1.0.2", "@balena/dockerignore": "^1.0.2",
"case": "1.6.3", "case": "1.6.3",
"fs-extra": "^11.1.1", "fs-extra": "^11.2.0",
"ignore": "^5.2.4", "ignore": "^5.3.0",
"jsonschema": "^1.4.1", "jsonschema": "^1.4.1",
"minimatch": "^3.1.2", "minimatch": "^3.1.2",
"punycode": "^2.3.0", "punycode": "^2.3.1",
"semver": "^7.5.1", "semver": "^7.5.4",
"table": "^6.8.1", "table": "^6.8.1",
"yaml": "1.10.2" "yaml": "1.10.2"
}, },
@ -1454,7 +1761,7 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/aws-cdk-lib/node_modules/fs-extra": { "node_modules/aws-cdk-lib/node_modules/fs-extra": {
"version": "11.1.1", "version": "11.2.0",
"inBundle": true, "inBundle": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -1472,7 +1779,7 @@
"license": "ISC" "license": "ISC"
}, },
"node_modules/aws-cdk-lib/node_modules/ignore": { "node_modules/aws-cdk-lib/node_modules/ignore": {
"version": "5.2.4", "version": "5.3.0",
"inBundle": true, "inBundle": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@ -1539,7 +1846,7 @@
} }
}, },
"node_modules/aws-cdk-lib/node_modules/punycode": { "node_modules/aws-cdk-lib/node_modules/punycode": {
"version": "2.3.0", "version": "2.3.1",
"inBundle": true, "inBundle": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@ -1555,7 +1862,7 @@
} }
}, },
"node_modules/aws-cdk-lib/node_modules/semver": { "node_modules/aws-cdk-lib/node_modules/semver": {
"version": "7.5.2", "version": "7.5.4",
"inBundle": true, "inBundle": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
@ -1624,7 +1931,7 @@
} }
}, },
"node_modules/aws-cdk-lib/node_modules/universalify": { "node_modules/aws-cdk-lib/node_modules/universalify": {
"version": "2.0.0", "version": "2.0.1",
"inBundle": true, "inBundle": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@ -2400,6 +2707,15 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/deploy-time-build": {
"version": "0.3.12",
"resolved": "https://registry.npmjs.org/deploy-time-build/-/deploy-time-build-0.3.12.tgz",
"integrity": "sha512-fVyuwB0Nh7mOLYswhHIHv3NOCeTWyNAjzM8cqSBnuhfvRKSdLZUFPnfwlPk1VgvYp9lfrxBZ+eicjWPBrAr53g==",
"peerDependencies": {
"aws-cdk-lib": "^2.38.0",
"constructs": "^10.0.5"
}
},
"node_modules/detect-newline": { "node_modules/detect-newline": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",

View file

@ -13,16 +13,18 @@
"devDependencies": { "devDependencies": {
"@types/jest": "^29.5.1", "@types/jest": "^29.5.1",
"@types/node": "20.1.7", "@types/node": "20.1.7",
"aws-cdk": "2.86.0", "aws-cdk": "^2.86.0",
"jest": "^29.5.0", "jest": "^29.5.0",
"ts-jest": "^29.1.0", "ts-jest": "^29.1.0",
"ts-node": "^10.9.1", "ts-node": "^10.9.1",
"typescript": "~5.1.3" "typescript": "~5.1.3"
}, },
"dependencies": { "dependencies": {
"aws-cdk-lib": "^2.86.0", "@aws-solutions-constructs/aws-cloudfront-s3": "^2.49.0",
"aws-cdk-lib": "^2.124.0",
"cdk-ecr-deployment": "^2.5.30", "cdk-ecr-deployment": "^2.5.30",
"constructs": "^10.0.0", "constructs": "^10.0.0",
"deploy-time-build": "^0.3.12",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"source-map-support": "^0.5.21" "source-map-support": "^0.5.21"
} }

View file

@ -1,6 +1,7 @@
from typing import Optional from typing import Optional
from langchain_community.embeddings.cohere import CohereEmbeddings from langchain_community.embeddings.cohere import CohereEmbeddings
from langflow import CustomComponent from langflow import CustomComponent
@ -21,7 +22,7 @@ class CohereEmbeddingsComponent(CustomComponent):
self, self,
request_timeout: Optional[float] = None, request_timeout: Optional[float] = None,
cohere_api_key: str = "", cohere_api_key: str = "",
max_retries: Optional[int] = None, max_retries: int = 3,
model: str = "embed-english-v2.0", model: str = "embed-english-v2.0",
truncate: Optional[str] = None, truncate: Optional[str] = None,
user_agent: str = "langchain", user_agent: str = "langchain",

View file

@ -1,8 +1,10 @@
from typing import Callable, Optional, Union
from langchain_anthropic import ChatAnthropic
from pydantic.v1.types import SecretStr from pydantic.v1.types import SecretStr
from langflow import CustomComponent from langflow import CustomComponent
from typing import Optional, Union, Callable
from langflow.field_typing import BaseLanguageModel from langflow.field_typing import BaseLanguageModel
from langchain_community.chat_models.anthropic import ChatAnthropic
class ChatAnthropicComponent(CustomComponent): class ChatAnthropicComponent(CustomComponent):
@ -17,31 +19,48 @@ class ChatAnthropicComponent(CustomComponent):
"field_type": "str", "field_type": "str",
"password": True, "password": True,
}, },
"anthropic_api_url": {
"display_name": "Anthropic API URL",
"field_type": "str",
},
"model_kwargs": { "model_kwargs": {
"display_name": "Model Kwargs", "display_name": "Model Kwargs",
"field_type": "dict", "field_type": "dict",
"advanced": True, "advanced": True,
}, },
"model_name": {
"display_name": "Model Name",
"field_type": "str",
"advanced": False,
"required": False,
"options": ["claude-3-opus-20240229", "claude-3-sonnet-20240229", "claude-3-haiku-20240307"],
},
"temperature": { "temperature": {
"display_name": "Temperature", "display_name": "Temperature",
"field_type": "float", "field_type": "float",
}, },
"max_tokens": {
"display_name": "Max Tokens",
"field_type": "int",
"advanced": False,
"required": False,
},
"top_k": {"display_name": "Top K", "field_type": "int", "advanced": True},
"top_p": {"display_name": "Top P", "field_type": "float", "advanced": True},
} }
def build( def build(
self, self,
anthropic_api_key: str, anthropic_api_key: str,
anthropic_api_url: Optional[str] = None,
model_kwargs: dict = {}, model_kwargs: dict = {},
model_name: str = "claude-3-opus-20240229",
temperature: Optional[float] = None, temperature: Optional[float] = None,
max_tokens: Optional[int] = 1024,
top_k: Optional[int] = None,
top_p: Optional[float] = None,
) -> Union[BaseLanguageModel, Callable]: ) -> Union[BaseLanguageModel, Callable]:
return ChatAnthropic( return ChatAnthropic(
anthropic_api_key=SecretStr(anthropic_api_key), anthropic_api_key=SecretStr(anthropic_api_key),
anthropic_api_url=anthropic_api_url,
model_kwargs=model_kwargs, model_kwargs=model_kwargs,
model_name=model_name,
temperature=temperature, temperature=temperature,
max_tokens=max_tokens, # type: ignore
top_k=top_k,
top_p=top_p,
) )

View file

@ -0,0 +1,17 @@
from langchain_core.vectorstores import VectorStoreRetriever
from langflow import CustomComponent
from langflow.field_typing import VectorStore
class VectoStoreRetrieverComponent(CustomComponent):
display_name = "VectorStore Retriever"
description = "A vector store retriever"
def build_config(self):
return {
"vectorstore": {"display_name": "Vector Store", "type": VectorStore},
}
def build(self, vectorstore: VectorStore) -> VectorStoreRetriever:
return vectorstore.as_retriever()

View file

@ -0,0 +1,32 @@
from langchain.tools.retriever import create_retriever_tool
from langflow import CustomComponent
from langflow.field_typing import BaseRetriever, Tool
class RetrieverToolComponent(CustomComponent):
display_name = "RetrieverTool"
description = "Tool for interacting with retriever"
def build_config(self):
return {
"retriever": {
"display_name": "Retriever",
"info": "Retriever to interact with",
"type": BaseRetriever,
},
"name": {"display_name": "Name", "info": "Name of the tool"},
"description": {"display_name": "Description", "info": "Description of the tool"},
}
def build(
self,
retriever: BaseRetriever,
name: str,
description: str,
) -> Tool:
return create_retriever_tool(
retriever=retriever,
name=name,
description=description,
)

View file

@ -1,22 +1,18 @@
from typing import List, Optional from typing import List, Optional
from langchain_community.vectorstores import MongoDBAtlasVectorSearch from langchain_community.vectorstores.mongodb_atlas import MongoDBAtlasVectorSearch
from langflow import CustomComponent from langflow import CustomComponent
from langflow.field_typing import ( from langflow.field_typing import Document, Embeddings, NestedDict
Document,
Embeddings,
NestedDict,
)
class MongoDBAtlasComponent(CustomComponent): class MongoDBAtlasComponent(CustomComponent):
display_name = "MongoDB Atlas" display_name = "MongoDB Atlas"
description = "Construct a `MongoDB Atlas Vector Search` vector store from raw documents." description = "a `MongoDB Atlas Vector Search` vector store from raw documents."
def build_config(self): def build_config(self):
return { return {
"documents": {"display_name": "Documents"}, "documents": {"display_name": "Documents", "is_list": True},
"embedding": {"display_name": "Embedding"}, "embedding": {"display_name": "Embedding"},
"collection_name": {"display_name": "Collection Name"}, "collection_name": {"display_name": "Collection Name"},
"db_name": {"display_name": "Database Name"}, "db_name": {"display_name": "Database Name"},
@ -27,8 +23,8 @@ class MongoDBAtlasComponent(CustomComponent):
def build( def build(
self, self,
documents: List[Document],
embedding: Embeddings, embedding: Embeddings,
documents: Optional[List[Document]] = None,
collection_name: str = "", collection_name: str = "",
db_name: str = "", db_name: str = "",
index_name: str = "", index_name: str = "",
@ -36,12 +32,17 @@ class MongoDBAtlasComponent(CustomComponent):
search_kwargs: Optional[NestedDict] = None, search_kwargs: Optional[NestedDict] = None,
) -> MongoDBAtlasVectorSearch: ) -> MongoDBAtlasVectorSearch:
search_kwargs = search_kwargs or {} search_kwargs = search_kwargs or {}
return MongoDBAtlasVectorSearch( vector_store = MongoDBAtlasVectorSearch.from_connection_string(
documents=documents, connection_string=mongodb_atlas_cluster_uri,
namespace=f"{db_name}.{collection_name}",
embedding=embedding, embedding=embedding,
collection_name=collection_name,
db_name=db_name,
index_name=index_name, index_name=index_name,
mongodb_atlas_cluster_uri=mongodb_atlas_cluster_uri,
search_kwargs=search_kwargs,
) )
if documents is not None:
if len(documents) == 0:
raise ValueError("If documents are provided, there must be at least one document.")
vector_store.add_documents(documents)
return vector_store

View file

@ -6,6 +6,8 @@ from typing import Any, Dict, List, Type, Union
from cachetools import TTLCache, cachedmethod, keys from cachetools import TTLCache, cachedmethod, keys
from fastapi import HTTPException from fastapi import HTTPException
from langflow.interface.custom.schema import CallableCodeDetails, ClassCodeDetails from langflow.interface.custom.schema import CallableCodeDetails, ClassCodeDetails
@ -234,10 +236,28 @@ class CodeParser:
def parse_return_statement(self, node: ast.FunctionDef) -> bool: def parse_return_statement(self, node: ast.FunctionDef) -> bool:
""" """
Parses the return statement of a function or method node. Parses the return statement of a function or method node, including nested returns.
""" """
return any(isinstance(n, ast.Return) for n in node.body) def has_return(node):
if isinstance(node, ast.Return):
return True
elif isinstance(node, ast.If):
return any(has_return(child) for child in node.body) or any(has_return(child) for child in node.orelse)
elif isinstance(node, ast.Try):
return (
any(has_return(child) for child in node.body)
or any(has_return(child) for child in node.handlers)
or any(has_return(child) for child in node.finalbody)
)
elif isinstance(node, (ast.For, ast.While)):
return any(has_return(child) for child in node.body) or any(has_return(child) for child in node.orelse)
elif isinstance(node, ast.With):
return any(has_return(child) for child in node.body)
else:
return False
return any(has_return(child) for child in node.body)
def parse_assign(self, stmt): def parse_assign(self, stmt):
""" """

View file

@ -32,6 +32,8 @@ def check_tools_in_params(params: Dict):
def instantiate_from_template(class_object, params: Dict): def instantiate_from_template(class_object, params: Dict):
from_template_params = {"template": params.pop("prompt", params.pop("template", ""))} from_template_params = {"template": params.pop("prompt", params.pop("template", ""))}
from_template_params.update(params)
if not from_template_params.get("template"): if not from_template_params.get("template"):
raise ValueError("Prompt template is required") raise ValueError("Prompt template is required")
return class_object.from_template(**from_template_params) return class_object.from_template(**from_template_params)

View file

@ -7,13 +7,13 @@ from langchain.schema import AgentAction, Document
from langchain_community.vectorstores import VectorStore from langchain_community.vectorstores import VectorStore
from langchain_core.messages import AIMessage from langchain_core.messages import AIMessage
from langchain_core.runnables.base import Runnable from langchain_core.runnables.base import Runnable
from loguru import logger
from pydantic import BaseModel
from langflow.graph.graph.base import Graph from langflow.graph.graph.base import Graph
from langflow.interface.custom.custom_component import CustomComponent
from langflow.interface.run import build_sorted_vertices, get_memory_key, update_memory_keys from langflow.interface.run import build_sorted_vertices, get_memory_key, update_memory_keys
from langflow.services.deps import get_session_service from langflow.services.deps import get_session_service
from langflow.services.session.service import SessionService from langflow.services.session.service import SessionService
from loguru import logger
from pydantic import BaseModel
def fix_memory_inputs(langchain_object): def fix_memory_inputs(langchain_object):
@ -172,8 +172,6 @@ async def process_inputs_dict(built_object: Union[Chain, VectorStore, Runnable],
result = result.content result = result.content
else: else:
result = result result = result
elif hasattr(built_object, "run") and isinstance(built_object, CustomComponent):
result = built_object.run(inputs)
else: else:
result = None result = None

View file

@ -9,8 +9,8 @@ from jose import JWTError, jwt
from sqlmodel import Session from sqlmodel import Session
from starlette.websockets import WebSocket from starlette.websockets import WebSocket
from langflow.services.database.models.api_key.model import ApiKey
from langflow.services.database.models.api_key.crud import check_key from langflow.services.database.models.api_key.crud import check_key
from langflow.services.database.models.api_key.model import ApiKey
from langflow.services.database.models.user.crud import get_user_by_id, get_user_by_username, update_user_last_login_at from langflow.services.database.models.user.crud import get_user_by_id, get_user_by_username, update_user_last_login_at
from langflow.services.database.models.user.model import User from langflow.services.database.models.user.model import User
from langflow.services.deps import get_session, get_settings_service from langflow.services.deps import get_session, get_settings_service
@ -333,7 +333,7 @@ def encrypt_api_key(api_key: str, settings_service=Depends(get_settings_service)
fernet = get_fernet(settings_service) fernet = get_fernet(settings_service)
# Two-way encryption # Two-way encryption
encrypted_key = fernet.encrypt(api_key.encode()) encrypted_key = fernet.encrypt(api_key.encode())
return encrypted_key return encrypted_key.decode()
def decrypt_api_key(encrypted_api_key: str, settings_service=Depends(get_settings_service)): def decrypt_api_key(encrypted_api_key: str, settings_service=Depends(get_settings_service)):

View file

@ -29,7 +29,7 @@ export default function ChatInput({
<div className="relative"> <div className="relative">
<Textarea <Textarea
onKeyDown={(event) => { onKeyDown={(event) => {
if (event.key === "Enter" && !lockChat && !event.shiftKey) { if (event.key === "Enter" && !event.nativeEvent.isComposing && !lockChat && !event.shiftKey) {
sendMessage(); sendMessage();
} }
}} }}