diff --git a/source/infrastructure/lib/api/api-stack.ts b/source/infrastructure/lib/api/api-stack.ts index 7c26f14d7..42f8bdfb0 100644 --- a/source/infrastructure/lib/api/api-stack.ts +++ b/source/infrastructure/lib/api/api-stack.ts @@ -11,7 +11,7 @@ * and limitations under the License. * *********************************************************************************************************************/ -import { Aws, Size, StackProps } from "aws-cdk-lib"; +import { Aws, Duration, Size, StackProps } from "aws-cdk-lib"; import * as apigw from "aws-cdk-lib/aws-apigateway"; import * as s3 from "aws-cdk-lib/aws-s3"; import { Runtime, Code } from 'aws-cdk-lib/aws-lambda'; @@ -30,6 +30,8 @@ import { ChatStackOutputs } from "../chat/chat-stack"; import { UserConstructOutputs } from "../user/user-construct"; import { LambdaFunction } from "../shared/lambda-helper"; import { Constants } from "../shared/constants"; +import { PythonFunction } from "@aws-cdk/aws-lambda-python-alpha"; +import { BundlingFileAccess } from 'aws-cdk-lib/core'; interface ApiStackProps extends StackProps { config: SystemConfig; @@ -65,8 +67,6 @@ export class ApiConstruct extends Construct { const messageQueue = props.chatStackOutputs.messageQueue; const lambdaLayers = new LambdaLayers(this); - // const apiLambdaExecutorLayer = lambdaLayers.createExecutorLayer(); - const apiLambdaEmbeddingLayer = lambdaLayers.createEmbeddingLayer(); const apiLambdaOnlineSourceLayer = lambdaLayers.createOnlineSourceLayer(); const apiLambdaAuthorizerLayer = lambdaLayers.createAuthorizerLayer(); @@ -143,39 +143,6 @@ export class ApiConstruct extends Construct { // if (props.config.knowledgeBase.knowledgeBaseType.intelliAgentKb.enabled) { if (props.config.knowledgeBase.enabled && props.config.knowledgeBase.knowledgeBaseType.intelliAgentKb.enabled) { - const embeddingLambda = new LambdaFunction(this, "lambdaEmbedding", { - code: Code.fromAsset(join(__dirname, "../../../lambda/embedding")), - vpc: vpc, - securityGroups: securityGroups, - environment: { - ETL_MODEL_ENDPOINT: props.modelConstructOutputs.defaultKnowledgeBaseModelName, - REGION: Aws.REGION, - RES_BUCKET: resBucketName, - }, - layers: [apiLambdaEmbeddingLayer], - statements: [ - this.iamHelper.esStatement, - this.iamHelper.s3Statement, - this.iamHelper.endpointStatement, - ], - }); - - const aosLambda = new LambdaFunction(this, "AOSLambda", { - code: Code.fromAsset(join(__dirname, "../../../lambda/aos")), - vpc: vpc, - securityGroups: securityGroups, - environment: { - opensearch_cluster_domain: domainEndpoint, - embedding_endpoint: props.modelConstructOutputs.defaultEmbeddingModelName, - }, - layers: [apiLambdaEmbeddingLayer], - statements: [ - this.iamHelper.esStatement, - this.iamHelper.s3Statement, - this.iamHelper.endpointStatement, - ], - }); - const executionManagementLambda = new LambdaFunction(this, "ExecutionManagementLambda", { code: Code.fromAsset(join(__dirname, "../../../lambda/etl")), handler: "execution_management.lambda_handler", @@ -199,27 +166,6 @@ export class ApiConstruct extends Construct { statements: [this.iamHelper.s3Statement], }); - // Define the API Gateway Lambda Integration with proxy and no integration responses - const lambdaEmbeddingIntegration = new apigw.LambdaIntegration( - embeddingLambda.function, - { proxy: true }, - ); - - // Define the API Gateway Method - const apiResourceEmbedding = api.root.addResource("extract"); - apiResourceEmbedding.addMethod("POST", lambdaEmbeddingIntegration, this.genMethodOption(api, auth, null),); - - // Define the API Gateway Lambda Integration with proxy and no integration responses - const lambdaAosIntegration = new apigw.LambdaIntegration(aosLambda.function, { - proxy: true, - }); - - // All AOS wrapper should be within such lambda - const apiResourceAos = api.root.addResource("aos"); - apiResourceAos.addMethod("POST", lambdaAosIntegration, this.genMethodOption(api, auth, null),); - // Add Get method to query & search index in OpenSearch, such embedding lambda will be updated for online process - apiResourceAos.addMethod("GET", lambdaAosIntegration, this.genMethodOption(api, auth, null),); - const apiResourceStepFunction = api.root.addResource("knowledge-base"); const apiKBExecution = apiResourceStepFunction.addResource("executions"); if (props.knowledgeBaseStackOutputs.sfnOutput !== undefined) { @@ -405,21 +351,21 @@ export class ApiConstruct extends Construct { const promptManagementLambda = new LambdaFunction(this, "PromptManagementLambda", { runtime: Runtime.PYTHON_3_12, - code: Code.fromAsset(join(__dirname, "../../../lambda/prompt_management")), handler: "prompt_management.lambda_handler", + code: Code.fromAsset(join(__dirname, '../../../lambda/deployment_assets/lambda_assets/prompt_management.zip')), environment: { PROMPT_TABLE_NAME: props.chatStackOutputs.promptTableName, }, layers: [apiLambdaOnlineSourceLayer], - statements: [this.iamHelper.dynamodbStatement, - this.iamHelper.logStatement], + statements: [this.iamHelper.dynamodbStatement, this.iamHelper.logStatement], }); - - const intentionLambda = new LambdaFunction(this, "IntentionLambda", { + const intentionLambda = new PythonFunction(this, "IntentionLambda", { runtime: Runtime.PYTHON_3_12, - code: Code.fromAsset(join(__dirname, "../../../lambda/intention")), - handler: "intention.lambda_handler", + entry: join(__dirname, "../../../lambda/intention"), + index: "intention.py", + handler: "lambda_handler", + timeout: Duration.minutes(15), vpc: vpc, securityGroups: securityGroups, environment: { @@ -435,15 +381,14 @@ export class ApiConstruct extends Construct { BEDROCK_REGION: props.config.chat.bedrockRegion, }, layers: [apiLambdaOnlineSourceLayer], - statements: [this.iamHelper.dynamodbStatement, - this.iamHelper.logStatement, - this.iamHelper.secretStatement, - this.iamHelper.esStatement, - this.iamHelper.s3Statement, - this.iamHelper.bedrockStatement, - this.iamHelper.endpointStatement, - ], }); + intentionLambda.addToRolePolicy(this.iamHelper.dynamodbStatement); + intentionLambda.addToRolePolicy(this.iamHelper.logStatement); + intentionLambda.addToRolePolicy(this.iamHelper.secretStatement); + intentionLambda.addToRolePolicy(this.iamHelper.esStatement); + intentionLambda.addToRolePolicy(this.iamHelper.s3Statement); + intentionLambda.addToRolePolicy(this.iamHelper.bedrockStatement); + intentionLambda.addToRolePolicy(this.iamHelper.endpointStatement); const chatbotManagementLambda = new LambdaFunction(this, "ChatbotManagementLambda", { runtime: Runtime.PYTHON_3_12, @@ -619,10 +564,6 @@ export class ApiConstruct extends Construct { // // }) // } // ); - - - - // const apiResourceChatbot = apiResourceChatbotManagement.addResource("chatbot"); // const apiResourceChatbotDetail = apiResourceChatbot.addResource('{chatbotId}') // apiResourceChatbotDetail.addMethod("GET", lambdaChatbotIntegration, this.genMethodOption(api, auth, null)); @@ -657,7 +598,7 @@ export class ApiConstruct extends Construct { apiResourcePromptProxy.addMethod("GET", lambdaPromptIntegration, this.genMethodOption(api, auth, null)); // Define the API Gateway Lambda Integration to manage intention - const lambdaIntentionIntegration = new apigw.LambdaIntegration(intentionLambda.function, { + const lambdaIntentionIntegration = new apigw.LambdaIntegration(intentionLambda, { proxy: true, }); const apiResourceIntentionManagement = api.root.addResource("intention"); diff --git a/source/infrastructure/lib/chat/chat-stack.ts b/source/infrastructure/lib/chat/chat-stack.ts index 9d7387b8a..0eb2e6cfa 100644 --- a/source/infrastructure/lib/chat/chat-stack.ts +++ b/source/infrastructure/lib/chat/chat-stack.ts @@ -112,12 +112,12 @@ export class ChatStack extends NestedStack implements ChatStackOutputs { handler: "lambda_main.main.lambda_handler", code: Code.fromCustomCommand( "/tmp/online_lambda_function_codes", - ['bash', '-c',[ + ['bash', '-c', [ "mkdir -p /tmp/online_lambda_function_codes", - `cp -r ${join(__dirname, "../../../lambda/online/*")} /tmp/online_lambda_function_codes`, - `cp ${join(__dirname, "../../../lambda/job/dep/llm_bot_dep/sm_utils.py")} /tmp/online_lambda_function_codes/`, + `cp -r ${join(__dirname, "../../../lambda/online/*")} /tmp/online_lambda_function_codes`, + `cp ${join(__dirname, "../../../lambda/job/dep/llm_bot_dep/sm_utils.py")} /tmp/online_lambda_function_codes/`, ].join(' && ') - ] + ] ), memorySize: 4096, vpc: vpc, @@ -177,7 +177,7 @@ export class ChatStack extends NestedStack implements ChatStackOutputs { "cloudformation:List*", "cloudformation:ValidateTemplate", "cloudformation:Detect*" - ], + ], effect: iam.Effect.ALLOW, resources: ["*"], }), diff --git a/source/infrastructure/lib/model/model-construct.ts b/source/infrastructure/lib/model/model-construct.ts index 99bdcf6c1..74387ca55 100644 --- a/source/infrastructure/lib/model/model-construct.ts +++ b/source/infrastructure/lib/model/model-construct.ts @@ -112,7 +112,7 @@ export class ModelConstruct extends NestedStack implements ModelConstructOutputs if (props.config.chat.useOpenSourceLLM) { const modelTriggerLambda = new Function(this, "ModelTriggerLambda", { - runtime: Runtime.PYTHON_3_11, + runtime: Runtime.PYTHON_3_12, handler: "pipeline_monitor.post_model_deployment", code: Code.fromAsset(join(__dirname, "../../../lambda/pipeline_monitor")), timeout: Duration.minutes(10), @@ -123,7 +123,7 @@ export class ModelConstruct extends NestedStack implements ModelConstructOutputs }); modelTriggerLambda.addToRolePolicy(this.modelIamHelper.dynamodbStatement); const pipelineMonitorLambda = new Function(this, "PipelineMonitorLambda", { - runtime: Runtime.PYTHON_3_11, + runtime: Runtime.PYTHON_3_12, handler: "pipeline_monitor.lambda_handler", code: Code.fromAsset(join(__dirname, "../../../lambda/pipeline_monitor")), timeout: Duration.minutes(10), @@ -311,7 +311,7 @@ export class ModelConstruct extends NestedStack implements ModelConstructOutputs // Custom resource to update ETL endpoint autoscaling setting const crLambda = new Function(this, "ETLCustomResource", { - runtime: Runtime.PYTHON_3_11, + runtime: Runtime.PYTHON_3_12, code: Code.fromAsset(join(__dirname, "../../../lambda/etl")), handler: "etl_custom_resource.lambda_handler", environment: { diff --git a/source/infrastructure/lib/shared/lambda-layers.ts b/source/infrastructure/lib/shared/lambda-layers.ts index 470841d30..6568bf3b2 100644 --- a/source/infrastructure/lib/shared/lambda-layers.ts +++ b/source/infrastructure/lib/shared/lambda-layers.ts @@ -19,72 +19,51 @@ import * as pyLambda from "@aws-cdk/aws-lambda-python-alpha"; export class LambdaLayers { constructor(private scope: Construct) { } - createEmbeddingLayer() { - const LambdaEmbeddingLayer = new LayerVersion( - this.scope, - "APILambdaEmbeddingLayer", - { - code: Code.fromAsset( - path.join(__dirname, "../../../lambda/embedding"), - { - bundling: { - image: Runtime.PYTHON_3_12.bundlingImage, - command: [ - "bash", - "-c", - `pip install -r requirements.txt -t /asset-output/python`, - ], - }, - }, - ), - compatibleRuntimes: [Runtime.PYTHON_3_12], - description: `LLM Bot - API layer`, - }, - ); - return LambdaEmbeddingLayer; - } - createOnlineSourceLayer() { - const LambdaOnlineSourceLayer = new pyLambda.PythonLayerVersion( + const sharedLayer = new pyLambda.PythonLayerVersion( this.scope, - "APILambdaOnlineSourceLayer", + "AICSSharedLayer", { entry: path.join(__dirname, "../../../lambda/online"), compatibleRuntimes: [Runtime.PYTHON_3_12], description: `AI-Customer-Service - Online Source layer`, bundling: { "command": [ - "bash", "-c", "pip install -r requirements.txt -t /asset-output/python"], - "assetExcludes": ["*.pyc","*/__pycache__/*","*.xls","*.xlsx","*.csv","*.png","lambda_main/retail/size/*"], + "bash", "-c", "pip install -r requirements.txt -t /asset-output/python"], + "assetExcludes": [ + "*.pyc", "*/__pycache__/*", + "*.xls", "*.xlsx", "*.csv", + "*.png", + "lambda_main/retail/size/*"], } }, ); - return LambdaOnlineSourceLayer; + return sharedLayer; } createJobSourceLayer() { - const LambdaJobSourceLayer = new pyLambda.PythonLayerVersion( + const etlLayer = new pyLambda.PythonLayerVersion( this.scope, - "APILambdaJobSourceLayer", + "AICSETLLayer", { entry: path.join(__dirname, "../../../lambda/job/dep/llm_bot_dep"), compatibleRuntimes: [Runtime.PYTHON_3_12], description: `AI Customer Service agent - Job Source layer`, }, ); - return LambdaJobSourceLayer; + return etlLayer; } createAuthorizerLayer() { - const LambdaAuthorizerLayer = new pyLambda.PythonLayerVersion( + const authorizerLayer = new pyLambda.PythonLayerVersion( this.scope, - "APILambdaAuthorizerLayer", + "AICSAuthorizerLayer", { entry: path.join(__dirname, "../../../lambda/authorizer"), compatibleRuntimes: [Runtime.PYTHON_3_12], description: `LLM Bot - Authorizer layer`, }, ); - return LambdaAuthorizerLayer; + return authorizerLayer; } } diff --git a/source/lambda/aos/main.py b/source/lambda/aos/main.py deleted file mode 100644 index 3b8d3fd7c..000000000 --- a/source/lambda/aos/main.py +++ /dev/null @@ -1,94 +0,0 @@ -import json -import logging -import os - -from utils.aos_utils import OpenSearchClient - -logger = logging.getLogger() -# logging.basicConfig(format='%(asctime)s,%(module)s,%(processName)s,%(levelname)s,%(message)s', level=logging.INFO, stream=sys.stderr) -logger.setLevel(logging.INFO) - -# fetch all the environment variables -_opensearch_cluster_domain = os.environ.get("opensearch_cluster_domain") -_opensearch_region = os.environ.get("embedding_endpoint") - - -def lambda_handler(event, _context): - logger.info("event: {}".format(event)) - # parse arguments from event - index_name = json.loads(event["body"])["aos_index"] - operation = json.loads(event["body"])["operation"] - http_method = event["httpMethod"] - body = json.loads(event["body"])["body"] - aos_client = OpenSearchClient(_opensearch_cluster_domain) - # other metadata need to pass to aos_client - kwargs = json.loads(event["body"]) - - operations_mapping = { - "GET": { - "query_all": lambda: aos_client.query_all( - index_name, json.dumps(body), kwargs - ), - "query_full_text_match": lambda: aos_client.query_full_text_match( - index_name, json.dumps(body), kwargs - ), - "query_full_text_multi_match": lambda: aos_client.query_full_text_multi_match( - index_name, json.dumps(body), kwargs - ), - "query_term": lambda: aos_client.query_term( - index_name, json.dumps(body), kwargs - ), - "query_term_regex": lambda: aos_client.query_term_wildcard( - index_name, json.dumps(body), kwargs - ), - "query_knn": lambda: aos_client.query_knn( - index_name, json.dumps(body), kwargs - ), - "query_exact": lambda: aos_client.query_exact( - index_name, json.dumps(body), kwargs - ), - "query_index": lambda: aos_client.query_index( - index_name, json.dumps(body), kwargs - ), - }, - "POST": { - "create_index": lambda: aos_client.create_index( - index_name, json.dumps(body), kwargs - ), - "update_index": lambda: aos_client.update_index( - index_name, json.dumps(body), kwargs - ), - "index": lambda: aos_client.index(index_name, json.dumps(body), kwargs), - "bulk": lambda: aos_client.bulk(index_name, json.dumps(body), kwargs), - "delete_index": lambda: aos_client.delete_index( - index_name, json.dumps(body), kwargs - ), - "delete_document": lambda: aos_client.delete_document( - index_name, json.dumps(body), kwargs - ), - "embed_document": lambda: aos_client.embed_document( - index_name, json.dumps(body), kwargs - ), - "embed_query": lambda: aos_client.embed_query( - index_name, json.dumps(body), kwargs - ), - }, - } - - if ( - http_method in operations_mapping - and operation in operations_mapping[http_method] - ): - response = operations_mapping[http_method][operation]() - logger.info( - "http_method: {}, operation: {}, response: {}".format( - http_method, operation, response - ) - ) - return { - "statusCode": 200, - "headers": {"Content-Type": "application/json"}, - "body": json.dumps(response), - } - else: - raise Exception(f"Invalid {http_method} operation: {operation}") diff --git a/source/lambda/aos/utils/aos_utils.py b/source/lambda/aos/utils/aos_utils.py deleted file mode 100644 index c6bb525eb..000000000 --- a/source/lambda/aos/utils/aos_utils.py +++ /dev/null @@ -1,611 +0,0 @@ -import json -import logging -import os - -import boto3 -from langchain.docstore.document import Document -from langchain.vectorstores import OpenSearchVectorSearch -from opensearchpy import OpenSearch, RequestsHttpConnection -from requests_aws4auth import AWS4Auth - -from .sm_utils import create_sagemaker_embeddings_from_js_model - -logger = logging.getLogger() -logger.setLevel(logging.INFO) - -credentials = boto3.Session().get_credentials() -region = boto3.Session().region_name -awsauth = AWS4Auth( - credentials.access_key, - credentials.secret_key, - region, - "es", - session_token=credentials.token, -) - -# Get params from Lambda environment variables -aosEndpoint = os.environ.get("opensearch_cluster_domain") -embeddingModelEndpoint = os.environ.get("embedding_endpoint") - - -class OpenSearchClient: - def __init__(self, _opensearch_cluster_domain: str): - """ - Initialize OpenSearch client using OpenSearch Endpoint - """ - self.client = OpenSearch( - hosts=[ - { - "host": _opensearch_cluster_domain.replace("https://", ""), - "port": 443, - } - ], - http_auth=awsauth, - use_ssl=True, - verify_certs=True, - connection_class=RequestsHttpConnection, - region=region, - ) - - def create_index(self, index: str, body: str, _kwargs: dict): - """ - Create an index in OpenSearch. - - Args: - index (str): The name of the index to create. - body (dict): A dictionary containing the settings and mappings for the index. - """ - # avoid NotFoundError: NotFoundError(404, 'index_not_found_exception'... - if self.client.indices.exists(index=index): - return { - "statusCode": 404, - "headers": {"Content-Type": "application/json"}, - "body": json.dumps({"error": f"index {index} already exist"}), - } - # fixed settings and mappings - # "knn.algo_param.index_thread_qty": 8, - # "knn.memory.circuit_breaker.limit": "70%", - body = { - "settings": { - "index": { - "knn": True, - "knn.algo_param.ef_search": 512, - "refresh_interval": "60s", - "number_of_shards": 8, - # disabel replica - "number_of_replicas": 0, - } - }, - "mappings": { - "properties": { - "vector_field": { - "type": "knn_vector", - "dimension": 1024, - "method": { - "name": "hnsw", - "space_type": "l2", - "engine": "nmslib", - "parameters": {"ef_construction": 128, "m": 16}, - }, - } - } - }, - } - # Create the index with the specified settings and mappings - response = self.client.indices.create(index=index, body=body) - return response - - def update_index(self, index: str, body: str, _kwargs: dict): - """ - Update an index in OpenSearch. - - Args: - index (str): The name of the index to create. - body (dict): A dictionary containing the settings and mappings for the index. - - Sample body: - { - "aos_index": "chatbot-index", - "operation": "update_index", - "body": { - "query": "heading_hierarchy", - "type": "long" - } - } - """ - # check if the index exists before updating - if not self.client.indices.exists(index=index): - return { - "statusCode": 404, - "headers": {"Content-Type": "application/json"}, - "body": json.dumps({"error": f"index {index} does not exist"}), - } - body_dict = json.loads(body) - property = str(body_dict.get("property")) - type = str(body_dict.get("type")) - # Define the new mapping for the field - new_mapping = { - "properties": {property: {"properties": {"size": {"type": type}}}} - } - logger.info(f"index {index} new mapping: {new_mapping}") - # update the index with the specified settings and mappings - response = self.client.indices.put_mapping(index=index, body=new_mapping) - return response - - def query_index(self, index: str, body: str, _kwargs: dict): - """ - Get all mappings for specified index or indices. - :param index_name: Name of the index or '_all' for all indices. - :return: Mappings of the index or indices. - """ - # avoid NotFoundError: NotFoundError(404, 'index_not_found_exception'... - if not self.client.indices.exists(index=index): - return { - "statusCode": 404, - "headers": {"Content-Type": "application/json"}, - "body": json.dumps({"error": f"index {index} does not exist"}), - } - # set default index to '_all' if index is not specified - if index == "": - index = "_all" - return self.client.indices.get_mapping(index=index) - - def delete_index(self, index: str, _body: str, _kwargs: dict): - """ - Delete an index in OpenSearch. - - Args: - index (str): The name of the index to delete. - """ - # avoid NotFoundError: NotFoundError(404, 'index_not_found_exception'... - if not self.client.indices.exists(index=index): - return { - "statusCode": 404, - "headers": {"Content-Type": "application/json"}, - "body": json.dumps({"error": f"index {index} does not exist"}), - } - - # delete the index - response = self.client.indices.delete(index=index) - return response - - def delete_document(self, index: str, body: str, _kwargs: dict): - """ - Delete a document in a specific index. - - Args: - index (str): The name of the index to delete. - document_id (str): The id of the document to delete. - - Sample body: - { - "aos_index": "chatbot-index", - "operation": "delete_document", - "body": { - "document_id": "1" - } - } - """ - # avoid NotFoundError: NotFoundError(404, 'index_not_found_exception'... - if not self.client.indices.exists(index=index): - return { - "statusCode": 404, - "headers": {"Content-Type": "application/json"}, - "body": json.dumps({"error": f"index {index} does not exist"}), - } - body_dict = json.loads(body) - document_id = body_dict.get("body", {}).get("document_id", {}) - # delete the document - self.client.delete(index=index, id=document_id) - - def bulk(self, index: str, body: str, _kwargs: dict): - """ - Bulk index documents in a specific index. - - Args: - index (str): The name of the index to delete. - document (List[Document]): A list of documents to index. - - Sample body: - { - "aos_index": "chatbot-index", - "operation": "bulk", - "body": { - List[Document] - } - } - """ - # avoid NotFoundError: NotFoundError(404, 'index_not_found_exception'... - if not self.client.indices.exists(index=index): - return { - "statusCode": 404, - "headers": {"Content-Type": "application/json"}, - "body": json.dumps({"error": f"index {index} does not exist"}), - } - body_dict = json.loads(body) - document = body_dict.get("body", {}) - # bulk index the documents - self.client.bulk(index=index, body=document) - - def index(self, index: str, body: str, _kwargs: dict): - """ - Index a document in a specific index. - - Args: - index (str): The name of the index to delete. - document (List[Document]): A list of documents to index. - - Sample body: - { - "aos_index": "chatbot-index", - "operation": "index", - "body": { - List[Document] - } - } - """ - # avoid NotFoundError: NotFoundError(404, 'index_not_found_exception'... - if not self.client.indices.exists(index=index): - return { - "statusCode": 404, - "headers": {"Content-Type": "application/json"}, - "body": json.dumps({"error": f"index {index} does not exist"}), - } - body_dict = json.loads(body) - document = body_dict.get("body", {}) - # iterate through the documents and index them - for doc in document: - try: - response = self.client.index(index=index, body=doc) - logger.info(f"response: {response}") - except Exception as e: - logger.error(f"Error indexing document: {e}") - - def query_all(self, index: str, _body: str, _kwargs: dict): - # avoid NotFoundError: NotFoundError(404, 'index_not_found_exception'... - if not self.client.indices.exists(index=index): - return { - "statusCode": 404, - "headers": {"Content-Type": "application/json"}, - "body": json.dumps({"error": f"index {index} does not exist"}), - } - body = {"query": {"match_all": {}}} - response = self.client.search(index=index, body=body) - for hit in response["hits"]["hits"]: - hit["_source"]["vector_field"] = hit["_source"]["vector_field"][:10] - hit["_source"]["metadata"]["additional_vecs"] = {} - return response - - def query_full_text_match(self, index: str, body: str, _kwargs: dict): - """ - Basic query with fixed result size - - Args: - index (str): The name of the index to delete. - body (str): The query body. - - Sample body: - { - "aos_index": "chatbot-index", - "operation": "query", - "body": { - "field": field, - "value": value, - "size": size - } - } - """ - # avoid NotFoundError: NotFoundError(404, 'index_not_found_exception'... - if not self.client.indices.exists(index=index): - return { - "statusCode": 404, - "headers": {"Content-Type": "application/json"}, - "body": json.dumps({"error": f"index {index} does not exist"}), - } - body_dict = json.loads(body) - field = str(body_dict.get("field")) - value = str(body_dict.get("value")) - # optional size with default value 100 - size = str(body_dict.get("size", 100)) - logger.info(f"field: {field}, value: {value}, size: {size}") - body = { - "query": { - # use term-level queries only for fields mapped as keyword - "match": { - field: value - # "operator": "and", - # "minimum_should_match": 2 - } - }, - "size": size, - "sort": [{"_score": {"order": "desc"}}], - } - response = self.client.search(index=index, body=body) - return response - - def query_full_text_multi_match(self, index: str, body: str, _kwargs: dict): - """ - Basic query with fixed result size - - Args: - index (str): The name of the index to delete. - body (str): The query body. - - Sample body: - { - "aos_index": "chatbot-index", - "operation": "query", - "body": { - "field": field, - "value": value, - "size": size - } - } - """ - # avoid NotFoundError: NotFoundError(404, 'index_not_found_exception'... - if not self.client.indices.exists(index=index): - return { - "statusCode": 404, - "headers": {"Content-Type": "application/json"}, - "body": json.dumps({"error": f"index {index} does not exist"}), - } - body_dict = json.loads(body) - field = str(body_dict.get("field")) - value = str(body_dict.get("value")) - # optional size with default value 100 - size = str(body_dict.get("size", 100)) - logger.info(f"field: {field}, value: {value}, size: {size}") - body = { - "query": { - # use term-level queries only for fields mapped as keyword - "multi_match": { - "query": field, - # sample: "fields": ["title", "body"] - "fields": value, - "type": "best_fields", - # add (tie_breaker * _score) for all other matching fields - # "tie_breaker": 0.3 - } - }, - "size": size, - "sort": [{"_score": {"order": "desc"}}], - } - response = self.client.search(index=index, body=body) - return response - - def query_term(self, index: str, body: str, _kwargs: dict): - """ - Execute a term-level query, documents returned by a term-level query are not sorted by their relevance scores. - - Args: - index (str): The name of the index to delete. - body (str): The query body. - - Sample body: - { - "aos_index": "chatbot-index", - "operation": "query_term", - "body": { - "quey": query, - "filter": filter - "size": size - } - } - """ - # avoid NotFoundError: NotFoundError(404, 'index_not_found_exception'... - if not self.client.indices.exists(index=index): - return { - "statusCode": 404, - "headers": {"Content-Type": "application/json"}, - "body": json.dumps({"error": f"index {index} does not exist"}), - } - body_dict = json.loads(body) - field = str(body_dict.get("field")) - value = str(body_dict.get("value")) - # optional size with default value 100 - size = str(body_dict.get("size", 100)) - logger.info(f"field: {field}, value: {value}, size: {size}") - # With a filter context, OpenSearch returns matching documents without calculating a relevance score. - body = { - "query": { - # use term-level queries only for fields mapped as keyword - "term": {field: {"value": value, "case_insensitive": False}} - }, - "size": size, - "sort": [{"_score": {"order": "desc"}}], - } - response = self.client.search(index=index, body=body) - return response - - def query_term_regex(self, index: str, body: str, _kwargs: dict): - """ - Execute a term-level query, documents returned by a term-level query are not sorted by their relevance scores. - - Args: - index (str): The name of the index to delete. - body (str): The query body. - - Sample body: - { - "aos_index": "chatbot-index", - "operation": "query_term", - "body": { - "quey": query, - "filter": filter - "size": size - } - } - """ - # avoid NotFoundError: NotFoundError(404, 'index_not_found_exception'... - if not self.client.indices.exists(index=index): - return { - "statusCode": 404, - "headers": {"Content-Type": "application/json"}, - "body": json.dumps({"error": f"index {index} does not exist"}), - } - body_dict = json.loads(body) - field = str(body_dict.get("field")) - value = str(body_dict.get("value")) - # optional size with default value 100 - size = str(body_dict.get("size", 100)) - logger.info(f"field: {field}, value: {value}, size: {size}") - # With a filter context, OpenSearch returns matching documents without calculating a relevance score. - body = { - "query": { - # use term-level queries only for fields mapped as keyword - "regexp": {field: {"value": value, "case_insensitive": False}} - }, - "size": size, - "sort": [{"_score": {"order": "desc"}}], - } - response = self.client.search(index=index, body=body) - return response - - def query_knn(self, index: str, body: str, _kwargs: dict): - """ - Execute a search query using knn. - - Args: - index (str): The name of the index to delete. - body (str): The query body. - - Sample body: - { - "aos_index": "chatbot-index", - "operation": "query_knn", - "body": { - "query": query, - "field": field, - "size": size - } - } - """ - # avoid NotFoundError: NotFoundError(404, 'index_not_found_exception'... - if not self.client.indices.exists(index=index): - return { - "statusCode": 404, - "headers": {"Content-Type": "application/json"}, - "body": json.dumps({"error": f"index {index} does not exist"}), - } - body_dict = json.loads(body) - query = body_dict.get("query") - # optional size with default value 10 - size = str(body_dict.get("size", 10)) - logging.info(f"knn query: {query}, size limit: {size}") - body = { - "size": size, - "query": {"knn": {"vector_field": {"vector": query, "k": size}}}, - } - response = self.client.search(index=index, body=body) - return response - - def query_exact(self, index: str, body: str, _kwargs: dict): - """ - Execute a search query using exact match. - - Args: - index (str): The name of the index to delete. - body (str): The query body. - - Sample body: - { - "aos_index": "chatbot-index", - "operation": "query_exact", - "body": { - "query": query, - "field": field, - "size": size - } - } - """ - # avoid NotFoundError: NotFoundError(404, 'index_not_found_exception'... - if not self.client.indices.exists(index=index): - return { - "statusCode": 404, - "headers": {"Content-Type": "application/json"}, - "body": json.dumps({"error": f"index {index} does not exist"}), - } - body_dict = json.loads(body) - query = str(body_dict.get("query")) - field = str(body_dict.get("field")) - # optional size with default value 100 - size = str(body_dict.get("size", 100)) - body = {"query": {"match_phrase": {field: query}}} - response = self.client.search(index=index, body=body) - return response - - # @retry(stop=stop_after_attempt(3)) - def _embed_document(self, index: str, document: Document, _kwargs: dict): - embeddings = create_sagemaker_embeddings_from_js_model( - embeddingModelEndpoint, region - ) - docsearch = OpenSearchVectorSearch( - index_name=index, - embedding_function=embeddings, - opensearch_url="https://{}".format(aosEndpoint), - http_auth=awsauth, - use_ssl=True, - verify_certs=True, - connection_class=RequestsHttpConnection, - ) - logger.info("Adding documents %s to OpenSearch with index %s", document, index) - # List of ids from adding the texts into the vectorstore. - return docsearch.add_documents(documents=[document]) - # logger.info("Retry statistics: %s", _embed_document.retry.statistics) - - def embed_document(self, index: str, body: str, _kwargs: dict): - """ - Returns: - List of ids from adding the texts into the vectorstore. - - Sample body: - { - "index": "chatbot-index", - "operation": "embed_document", - "body": { - "documents": { - "page_content": "This is a test", - "metadata": { - "heading_hierarchy": "Title 1" - ... - } - } - } - } - """ - body_dict = json.loads(body) - # assemble the document according to the Document class below: - document = Document( - page_content=body_dict["documents"]["page_content"], - metadata=body_dict["documents"]["metadata"], - ) - # if the embedding function execute successfully, return success with the document id - res = self._embed_document(index, document, _kwargs) - # assemble the response - response = { - "statusCode": 200, - "headers": {"Content-Type": "application/json"}, - "body": {"document_id": res}, - } - return response - - def embed_query(self, index: str, body: str, _kwargs: dict): - # fetch query from body - body_dict = json.loads(body) - query = body_dict.get("query") - logger.info(f"query: {query}") - query_embedding = SagemakerEndpointVectorOrCross( - prompt=query, - endpoint_name=embeddingModelEndpoint, - region_name=region, - model_type="vector", - stop=None, - ) - return query_embedding - # # assemble the body to multiplex the query_knn function - # body = { - # "query": query_embedding, - # "size": 10 - # } - # response = self.query_knn(index, json.dumps(body), _kwargs) - # return response diff --git a/source/lambda/aos/utils/sm_utils.py b/source/lambda/aos/utils/sm_utils.py deleted file mode 100644 index 416d03541..000000000 --- a/source/lambda/aos/utils/sm_utils.py +++ /dev/null @@ -1,94 +0,0 @@ -""" -Helper functions for using Samgemaker Endpoint via LangChain -""" - -# Imports -import json -import logging -import time -from typing import List - -from langchain.embeddings import SagemakerEndpointEmbeddings -from langchain.embeddings.sagemaker_endpoint import EmbeddingsContentHandler - -# Logger setup -logger = logging.getLogger() -logger.setLevel(logging.INFO) - - -class SagemakerEndpointEmbeddingsJumpStart(SagemakerEndpointEmbeddings): - """Extend the SagemakerEndpointEmbeddings class from langchain to provide a custom embedding function, wrap the embedding & injection logic into a single class""" - - def embed_documents( - self, texts: List[str], chunk_size: int = 500 - ) -> List[List[float]]: - """Compute doc embeddings using a SageMaker Inference Endpoint.""" - results = [] - _chunk_size = len(texts) if chunk_size > len(texts) else chunk_size - st = time.time() - for i in range(0, len(texts), _chunk_size): - response = self._embedding_func(texts[i : i + _chunk_size]) - results.extend(response) - time_taken = time.time() - st - logger.debug( - f"got results for {len(texts)} in {time_taken}s, length of embeddings list is {len(results)}" - ) - - return results - - -class RelevanceM3ContentHandler(EmbeddingsContentHandler): - """Content handler for the Relevance M3 model.""" - - content_type = "application/json" - accepts = "application/json" - - def transform_input(self, prompt, model_kwargs={}) -> bytes: - # add bge_prompt to each element in prompt - model_kwargs = {} - model_kwargs["batch_size"] = 12 - model_kwargs["max_length"] = 512 - model_kwargs["return_type"] = "dense" - input_str = json.dumps({"inputs": prompt, **model_kwargs}) - - return input_str.encode("utf-8") - - def transform_output(self, output: bytes) -> str: - response_json = json.loads(output.read().decode("utf-8")) - embeddings = response_json["sentence_embeddings"] - - if len(embeddings) == 1: - return [embeddings[0]] - - return [embeddings] - - -# Function definitions - - -def create_embeddings_with_m3_model(embeddings_model: str, aws_region: str): - """Create embeddings with the M3 model.""" - # Implementation omitted for brevity - embeddings_result = None - - content_handler = RelevanceM3ContentHandler() - - embeddings_result = create_sagemaker_embeddings_from_js_model( - embeddings_model, aws_region, content_handler - ) - - return embeddings_result - - -def create_sagemaker_embeddings_from_js_model( - embeddings_model_endpoint_name: str, aws_region: str, content_handler -) -> SagemakerEndpointEmbeddingsJumpStart: - """Create SageMaker embeddings from a JumpStart model.""" - # Implementation omitted for brevity - embeddings = SagemakerEndpointEmbeddingsJumpStart( - endpoint_name=embeddings_model_endpoint_name, - region_name=aws_region, - content_handler=content_handler, - ) - - return embeddings diff --git a/source/lambda/embedding/main.py b/source/lambda/embedding/main.py deleted file mode 100644 index db2e6d80d..000000000 --- a/source/lambda/embedding/main.py +++ /dev/null @@ -1,155 +0,0 @@ -import itertools -import json -import logging -import os -from typing import Generator, List - -import boto3 -import chardet -from langchain.docstore.document import Document -from utils.auto import cb_process_object - -logger = logging.getLogger() -logger.setLevel(logging.INFO) - -etlModelEndpoint = os.environ.get("ETL_MODEL_ENDPOINT") -region = os.environ.get("REGION") -res_bucket = os.environ.get("RES_BUCKET") - -s3 = boto3.client("s3") -smr_client = boto3.client("sagemaker-runtime") - - -def decode_file_content(content: str, default_encoding: str = "utf-8"): - """Decode the file content and auto detect the content encoding. - - Args: - content: The content to detect the encoding. - default_encoding: The default encoding to try to decode the content. - timeout: The timeout in seconds for the encoding detection. - """ - - try: - decoded_content = content.decode(default_encoding) - except UnicodeDecodeError: - # Try to detect encoding - encoding = chardet.detect(content)["encoding"] - decoded_content = content.decode(encoding) - - return decoded_content - - -def iterate_s3_files(bucket: str, key: str, need_split: bool) -> Generator: - # extract the file type from the key, e.g. llm/pdf-sample-01.pdf - file_type = key.split(".")[-1] - response = s3.get_object(Bucket=bucket, Key=key) - file_content = response["Body"].read() - - # assemble bucket and key as args for the callback function - kwargs = { - "bucket": bucket, - "key": key, - "etl_model_endpoint": etlModelEndpoint, - "smr_client": smr_client, - "res_bucket": res_bucket, - "need_split": need_split, - } - if file_type == "txt": - yield "txt", decode_file_content(file_content), kwargs - elif file_type == "csv": - # Update row count here, the default row count is 1 - kwargs["csv_row_count"] = 1 - yield "csv", decode_file_content(file_content), kwargs - elif file_type in ["xlsx", "xls"]: - # Update row count here, the default row count is 1 - kwargs["xlsx_row_count"] = 1 - yield "xlsx", decode_file_content(file_content), kwargs - elif file_type == "html": - yield "html", decode_file_content(file_content), kwargs - elif file_type in ["pdf"]: - yield "pdf", file_content, kwargs - elif file_type in ["jpg", "png"]: - yield "image", file_content, kwargs - elif file_type in ["docx", "doc"]: - yield "doc", file_content, kwargs - elif file_type == "md": - yield "md", decode_file_content(file_content), kwargs - elif file_type == "json": - yield "json", decode_file_content(file_content), kwargs - elif file_type == "jsonl": - yield "jsonl", file_content, kwargs - else: - logger.info(f"Unknown file type: {file_type}") - - -def batch_generator(generator, batch_size: int): - iterator = iter(generator) - while True: - batch = list(itertools.islice(iterator, batch_size)) - if not batch: - break - yield batch - - -def document_to_dict(document: Document) -> dict: - """ - Convert a Document instance to a dictionary. - - :param document: The Document instance to convert. - :return: A dictionary representation of the Document. - """ - return { - "page_content": document.page_content, - "metadata": document.metadata, - # 'type': document.type, - } - - -def serialize_documents(documents: List[Document]) -> str: - """ - Serialize a list of Document instances to a JSON string. - - :param documents: The list of Document instances to serialize. - :return: A JSON string representing the list of documents. - """ - res_dicts = [document_to_dict(doc) for doc in documents] - return json.dumps(res_dicts) - - -def lambda_handler(event, context): - logger.info(f"Event: {event}") - # get the bucket name and key from the event - s3_bucket = json.loads(event["body"])["s3_bucket"] - s3_prefix = json.loads(event["body"])["s3_prefix"] - need_split = json.loads(event["body"])["need_split"] - - # Type List[List[Document] - resp_list = [] - for file_type, file_content, kwargs in iterate_s3_files( - s3_bucket, s3_prefix, need_split - ): - try: - response = cb_process_object(s3, file_type, file_content, **kwargs) - # for document in response: - # save_content_to_s3( - # s3, document, res_bucket, SplittingType.SEMANTIC.value - # ) - # logger.info(f"Response: {response} type: {type(response)}, serialize_documents: {serialize_documents(response)}") - resp_list.append(serialize_documents(response)) - except Exception as e: - logger.error( - f"Error processing file: {kwargs['key']} in bucket: {kwargs['bucket']}" - ) - logger.error(e) - raise e - # logger.info(f"responseList: {resp_list} type: {type(resp_list)}") - return { - "statusCode": 200, - "body": json.dumps( - { - "bucket": s3_bucket, - "prefix": s3_prefix, - "content": json.loads(resp_list[0]), - } - ), - } diff --git a/source/lambda/embedding/requirements.txt b/source/lambda/embedding/requirements.txt deleted file mode 100644 index ec1e365ae..000000000 --- a/source/lambda/embedding/requirements.txt +++ /dev/null @@ -1,13 +0,0 @@ -langchain==0.1.0 -requests-aws4auth==1.2.3 -# boto3==1.28.84 -# openai==0.28.1 -pyOpenSSL==23.3.0 -tenacity==8.2.3 -markdownify==0.11.6 -mammoth==1.6.0 -chardet==5.2.0 -python-docx==1.1.0 -# nltk==3.8.1 -pdfminer.six==20221105 -opensearch-py==2.2.0 \ No newline at end of file diff --git a/source/lambda/embedding/utils/auto.py b/source/lambda/embedding/utils/auto.py deleted file mode 100644 index 55e8bf091..000000000 --- a/source/lambda/embedding/utils/auto.py +++ /dev/null @@ -1,39 +0,0 @@ -# from .docx import process_doc -# from .markdown import process_md -# from .text import process_text -# from .csvx import process_csv -# from .htmlx import process_html -# from .image import process_image -# from .json import process_json -# from .jsonl import process_jsonl -import logging - -from .pdf import process_pdf - -logger = logging.getLogger() -logger.setLevel(logging.INFO) - - -def cb_process_object(s3, file_type: str, file_content, **kwargs): - logger.info(f"Processing file type: {file_type}") - res = None - # leave pdf only before we move to other type for sync invocation since there are still timeout issue in api gw - if file_type == "pdf": - res = process_pdf(s3, file_content, **kwargs) - # if file_type == "txt": - # res = process_text(file_content, **kwargs) - # elif file_type == "csv": - # res = process_csv(s3, file_content, **kwargs) - # elif file_type == "html": - # res = process_html(file_content, **kwargs) - # elif file_type == "doc": - # res = process_doc(s3, **kwargs) - # elif file_type == "md": - # res = process_md(file_content, **kwargs) - # elif file_type == "image": - # process_image(s3, file_content, **kwargs) - # elif file_type == "json": - # res = process_json(file_content, **kwargs) - # elif file_type == 'jsonl': - # res = process_jsonl(s3, file_content, **kwargs) - return res diff --git a/source/lambda/embedding/utils/cleaning.py b/source/lambda/embedding/utils/cleaning.py deleted file mode 100644 index 5de8b9115..000000000 --- a/source/lambda/embedding/utils/cleaning.py +++ /dev/null @@ -1,229 +0,0 @@ -# lite version of cleaning module refer to unstructure io -import re -from typing import Final, List - -UNICODE_BULLETS: Final[List[str]] = [ - "\u0095", - "\u2022", - "\u2023", - "\u2043", - "\u3164", - "\u204c", - "\u204d", - "\u2219", - "\u25cb", - "\u25cf", - "\u25d8", - "\u25e6", - "\u2619", - "\u2765", - "\u2767", - "\u29be", - "\u29bf", - "\u002d", - "", - "\*", - "\x95", - "·", -] - -BULLETS_PATTERN = "|".join(UNICODE_BULLETS) -UNICODE_BULLETS_RE = re.compile(f"(?:{BULLETS_PATTERN})(?!{BULLETS_PATTERN})") -# zero-width positive lookahead so bullet characters will not be removed when using .split() -UNICODE_BULLETS_RE_0W = re.compile(f"(?={BULLETS_PATTERN})(? str: - """Cleans non-ascii characters from unicode string. - - Example - ------- - \x88This text contains non-ascii characters!\x88 - -> This text contains non-ascii characters! - """ - en = text.encode("ascii", "ignore") - return en.decode() - - -def clean_bullets(text: str) -> str: - """Cleans unicode bullets from a section of text. - - Example - ------- - ● This is an excellent point! -> This is an excellent point! - """ - search = UNICODE_BULLETS_RE.match(text) - if search is None: - return text - - cleaned_text = UNICODE_BULLETS_RE.sub("", text, 1) - return cleaned_text.strip() - - -def clean_ordered_bullets(text) -> str: - """Cleans the start of bulleted text sections up to three “sub-section” - bullets accounting numeric and alphanumeric types. - - Example - ------- - 1.1 This is a very important point -> This is a very important point - a.b This is a very important point -> This is a very important point - """ - text_sp = text.split() - text_cl = " ".join(text_sp[1:]) - if any(["." not in text_sp[0], ".." in text_sp[0]]): - return text - - bullet = re.split(pattern=r"[\.]", string=text_sp[0]) - if not bullet[-1]: - del bullet[-1] - - if len(bullet[0]) > 2: - return text - - return text_cl - - -def clean_ligatures(text) -> str: - """Replaces ligatures with their most likely equivalent characters. - - Example - ------- - The benefits -> The benefits - High quality financial -> High quality financial - """ - ligatures_map = { - "æ": "ae", - "Æ": "AE", - "ff": "ff", - "fi": "fi", - "fl": "fl", - "ffi": "ffi", - "ffl": "ffl", - "ſt": "ft", - "ʪ": "ls", - "œ": "oe", - "Œ": "OE", - "ȹ": "qp", - "st": "st", - "ʦ": "ts", - } - cleaned_text: str = text - for k, v in ligatures_map.items(): - cleaned_text = cleaned_text.replace(k, v) - - return cleaned_text - - -def group_bullet_paragraph(paragraph: str) -> list: - """Groups paragraphs with bullets that have line breaks for visual/formatting purposes. - For example: - - '''○ The big red fox - is walking down the lane. - - ○ At the end of the lane - the fox met a friendly bear.''' - - Gets converted to - - '''○ The big red fox is walking down the lane. - ○ At the end of the land the fox met a bear.''' - """ - clean_paragraphs = [] - # pytesseract converts some bullet points to standalone "e" characters. - # Substitute "e" with bullets since they are later used in partition_text - # to determine list element type. - paragraph = (re.sub(E_BULLET_PATTERN, "·", paragraph)).strip() - - bullet_paras = re.split(UNICODE_BULLETS_RE_0W, paragraph) - for bullet in bullet_paras: - if bullet: - clean_paragraphs.append(re.sub(PARAGRAPH_PATTERN, " ", bullet)) - return clean_paragraphs - - -def group_broken_paragraphs( - text: str, - line_split: re.Pattern[str] = PARAGRAPH_PATTERN_RE, - paragraph_split: re.Pattern[str] = DOUBLE_PARAGRAPH_PATTERN_RE, -) -> str: - """Groups paragraphs that have line breaks for visual/formatting purposes. - For example: - - '''The big red fox - is walking down the lane. - - At the end of the lane - the fox met a bear.''' - - Gets converted to - - '''The big red fox is walking down the lane. - At the end of the land the fox met a bear.''' - """ - paragraphs = paragraph_split.split(text) - clean_paragraphs = [] - for paragraph in paragraphs: - if not paragraph.strip(): - continue - # NOTE(robinson) - This block is to account for lines like the following that shouldn't be - # grouped together, but aren't separated by a double line break. - # Apache License - # Version 2.0, January 2004 - # http://www.apache.org/licenses/ - para_split = line_split.split(paragraph) - all_lines_short = all(len(line.strip().split(" ")) < 5 for line in para_split) - # pytesseract converts some bullet points to standalone "e" characters - if UNICODE_BULLETS_RE.match(paragraph.strip()) or E_BULLET_PATTERN.match( - paragraph.strip() - ): - clean_paragraphs.extend(group_bullet_paragraph(paragraph)) - elif all_lines_short: - clean_paragraphs.extend([line for line in para_split if line.strip()]) - else: - clean_paragraphs.append(re.sub(PARAGRAPH_PATTERN, " ", paragraph)) - - return "\n\n".join(clean_paragraphs) - - -def remove_duplicate_sections(text: str) -> str: - # Split the text into paragraphs - paragraphs = text.split("\n\n") - - # Function to remove punctuation from a string - def remove_punctuation(s): - no_punc = re.sub(r"[^\w\s]", "", s) - # revmoe extra spaces between words - normal = re.sub(r"\s+", " ", no_punc) - return normal.lower() - - # Remove punctuation and convert paragraphs to lower case for comparison - cleaned_paragraphs = [remove_punctuation(p) for p in paragraphs] - - # Remove duplicate paragraphs (considering punctuation and case-insensitivity) - unique_paragraphs = [] - seen = set() - for original, cleaned in zip(paragraphs, cleaned_paragraphs): - if cleaned not in seen: - unique_paragraphs.append(original) - seen.add(cleaned) - - # Join the unique paragraphs back into a single text - cleaned_text = "\n\n".join(unique_paragraphs) - - return cleaned_text diff --git a/source/lambda/embedding/utils/constant.py b/source/lambda/embedding/utils/constant.py deleted file mode 100644 index 64aa40983..000000000 --- a/source/lambda/embedding/utils/constant.py +++ /dev/null @@ -1,12 +0,0 @@ -""" -Constant used in Glue job -""" - -from enum import Enum, unique - - -@unique -class SplittingType(Enum): - BEFORE = "before-splitting" - SEMANTIC = "semantic-splitting" - CHUNK = "chunk-size-splitting" diff --git a/source/lambda/embedding/utils/csvx.py b/source/lambda/embedding/utils/csvx.py deleted file mode 100644 index e7545ef54..000000000 --- a/source/lambda/embedding/utils/csvx.py +++ /dev/null @@ -1,179 +0,0 @@ -import csv -import uuid -from datetime import datetime -from io import TextIOWrapper -from typing import Dict, List, Optional, Sequence - -from langchain.docstore.document import Document -from langchain.document_loaders.csv_loader import CSVLoader -from langchain.document_loaders.helpers import detect_file_encodings - - -class CustomCSVLoader(CSVLoader): - """Load a `CSV` file into a list of Documents. - - Each document represents one row of the CSV file. The rows are converted into markdown format based on row_count. - - Output Example: - when row_count = 1, - page_document_1 contains: - |index|name| - |-|-| - |1|Demo1| - page_document_2 contains: - |index|name| - |-|-| - |2|Demo2| - - when row_count = 3, - page_document_1 contains: - |index|name| - |-|-| - |1|Demo1| - |2|Demo2| - |3|Demo3| - page_document_2 contains: - |index|name| - |-|-| - |4|Demo4| - |5|Demo5| - |6|Demo6| - """ - - def __init__( - self, - file_path: str, - aws_path: str, - source_column: Optional[str] = None, - metadata_columns: Sequence[str] = (), - csv_args: Optional[Dict] = None, - encoding: Optional[str] = None, - autodetect_encoding: bool = False, - row_count: int = 1, - ): - """ - - Args: - file_path: The path to the CSV file. - source_column: The name of the column in the CSV file to use as the source. Optional. Defaults to None. - metadata_columns: A sequence of column names to use as metadata. Optional. - csv_args: A dictionary of arguments to pass to the csv.DictReader. Optional. Defaults to None. - encoding: The encoding of the CSV file. Optional. Defaults to None. - autodetect_encoding: Whether to try to autodetect the file encoding. - row_count: How many row in a page document. - """ - self.row_number = row_count - self.aws_path = aws_path - super().__init__( - file_path, - source_column, - metadata_columns, - csv_args, - encoding, - autodetect_encoding, - ) - - def __read_file(self, csvfile: TextIOWrapper) -> List[Document]: - docs = [] - - csv_reader = csv.DictReader(csvfile, **self.csv_args) - counter = 0 - for i, row in enumerate(csv_reader): - try: - source = ( - row[self.source_column] - if self.source_column is not None - else self.file_path - ) - except KeyError: - raise ValueError( - f"Source column '{self.source_column}' not found in CSV file." - ) - counter += 1 - - if counter % self.row_number == 1: - # First row with header and separator - header = "|" - md_separator = "|" - row_content = "|" - for k, v in row.items(): - header += k + "|" - md_separator += "-|" - row_content += v + "|" - row_content += "\n" - elif counter % self.row_number == 0: - if 1 == self.row_number: - header = "|" - md_separator = "|" - row_content = "|" - for k, v in row.items(): - header += k + "|" - md_separator += "-|" - row_content += v + "|" - else: - for k, v in row.items(): - row_content += v + "|" - content = header + "\n" + md_separator + "\n" + row_content - print(f"markdown content: {content}") - - metadata = {"source": source, "row": i, "file_path": self.aws_path} - for col in self.metadata_columns: - try: - metadata[col] = row[col] - except KeyError: - raise ValueError( - f"Metadata column '{col}' not found in CSV file." - ) - doc = Document(page_content=content, metadata=metadata) - docs.append(doc) - counter = 0 - else: - for k, v in row.items(): - row_content += v + "|" - row_content += "\n" - - return docs - - def load(self) -> List[Document]: - """Load data into document objects.""" - - docs = [] - try: - with open(self.file_path, newline="", encoding=self.encoding) as csvfile: - docs = self.__read_file(csvfile) - except UnicodeDecodeError as e: - if self.autodetect_encoding: - detected_encodings = detect_file_encodings(self.file_path) - for encoding in detected_encodings: - try: - with open( - self.file_path, newline="", encoding=encoding.encoding - ) as csvfile: - docs = self.__read_file(csvfile) - break - except UnicodeDecodeError: - continue - else: - raise RuntimeError(f"Error loading {self.file_path}") from e - except Exception as e: - raise RuntimeError(f"Error loading {self.file_path}") from e - - return docs - - -def process_csv(s3, csv_content: str, **kwargs): - now = datetime.now() - timestamp_str = now.strftime("%Y%m%d%H%M%S") - random_uuid = str(uuid.uuid4())[:8] - bucket_name = kwargs["bucket"] - key = kwargs["key"] - row_count = kwargs["csv_row_count"] - local_path = f"/tmp/csv-{timestamp_str}-{random_uuid}.csv" - - s3.download_file(bucket_name, key, local_path) - loader = CustomCSVLoader( - file_path=local_path, aws_path=f"s3://{bucket_name}/{key}", row_count=row_count - ) - data = loader.load() - - return data diff --git a/source/lambda/embedding/utils/docx.py b/source/lambda/embedding/utils/docx.py deleted file mode 100644 index 76613724a..000000000 --- a/source/lambda/embedding/utils/docx.py +++ /dev/null @@ -1,97 +0,0 @@ -import logging -import uuid -from datetime import datetime -from typing import List, Optional - -import mammoth -from docx import Document as pyDocument -from langchain.docstore.document import Document -from langchain.document_loaders.base import BaseLoader -from splitter_utils import MarkdownHeaderTextSplitter - -from .htmlx import CustomHtmlLoader - -logger = logging.getLogger(__name__) - - -class CustomDocLoader(BaseLoader): - """Load docx file. - - Args: - file_content: File content in docx file. - - encoding: File encoding to use. If `None`, the file will be loaded - with the default system encoding. - - autodetect_encoding: Whether to try to autodetect the file encoding - if the specified encoding fails. - """ - - def __init__( - self, - file_path: str, - aws_path: str, - encoding: Optional[str] = None, - autodetect_encoding: bool = False, - ): - """Initialize with file path.""" - self.file_path = file_path - self.aws_path = aws_path - self.encoding = encoding - self.autodetect_encoding = autodetect_encoding - - def clean_document(self, doc: pyDocument): - """Clean document including removing header and footer for each page - - Args: - doc (Document): The document to clean - """ - # Remove headers and footers - for section in doc.sections: - if section.header is not None: - for paragraph in section.header.paragraphs: - paragraph.clear() - - if section.footer is not None: - for paragraph in section.footer.paragraphs: - paragraph.clear() - - def load(self) -> List[Document]: - """Load from file path.""" - metadata = {"file_path": self.aws_path, "file_type": "docx"} - - def _convert_image(image): - # Images are excluded - return {"src": ""} - - pyDoc = pyDocument(self.file_path) - self.clean_document(pyDoc) - pyDoc.save(self.file_path) - - with open(self.file_path, "rb") as docx_file: - result = mammoth.convert_to_html( - docx_file, convert_image=mammoth.images.img_element(_convert_image) - ) - html_content = result.value - loader = CustomHtmlLoader(aws_path=self.aws_path) - doc = loader.load(html_content) - doc.metadata = metadata - - return doc - - -def process_doc(s3, **kwargs): - now = datetime.now() - timestamp_str = now.strftime("%Y%m%d%H%M%S") - random_uuid = str(uuid.uuid4())[:8] - bucket_name = kwargs["bucket"] - key = kwargs["key"] - local_path = f"/tmp/doc-{timestamp_str}-{random_uuid}.docx" - - s3.download_file(bucket_name, key, local_path) - loader = CustomDocLoader(file_path=local_path, aws_path=f"s3://{bucket_name}/{key}") - doc = loader.load() - splitter = MarkdownHeaderTextSplitter(kwargs["res_bucket"]) - doc_list = splitter.split_text(doc) - - return doc_list diff --git a/source/lambda/embedding/utils/htmlx.py b/source/lambda/embedding/utils/htmlx.py deleted file mode 100644 index df5779fcc..000000000 --- a/source/lambda/embedding/utils/htmlx.py +++ /dev/null @@ -1,81 +0,0 @@ -import logging -import re - -import markdownify -from langchain.docstore.document import Document -from langchain.document_loaders.base import BaseLoader - -from .splitter_utils import MarkdownHeaderTextSplitter - -logger = logging.getLogger(__name__) - - -class CustomHtmlLoader(BaseLoader): - """Load `HTML` files using `Unstructured`. - - You can run the loader in one of two modes: "single" and "elements". - If you use "single" mode, the document will be returned as a single - langchain Document object. If you use "elements" mode, the unstructured - library will split the document into elements such as Title and NarrativeText. - You can pass in additional unstructured kwargs after mode to apply - different unstructured settings. - - """ - - def __init__(self, aws_path: str): - """Initialize with file path.""" - self.aws_path = aws_path - - def clean_html(self, html_str: str) -> str: - # Filter out DOCTYPE - html_str = " ".join(html_str.split()) - re_doctype = re.compile(r"", re.S) - s = re_doctype.sub("", html_str) - - # Filter out CDATA - re_cdata = re.compile("//]*//\]\]>", re.I) - s = re_cdata.sub("", s) - - # Filter out script - re_script = re.compile("<\s*script[^>]*>[^<]*<\s*/\s*script\s*>", re.I) - s = re_script.sub("", s) - - # Filter out style - re_style = re.compile("<\s*style[^>]*>[^<]*<\s*/\s*style\s*>", re.I) - s = re_style.sub("", s) - - # Filter out HTML comments - re_comment = re.compile("") - s = re_comment.sub("", s) - - # Remove extra blank lines - blank_line = re.compile("\n+") - s = blank_line.sub("\n", s) - - # Remove blank image - img_src = re.compile('') - s = img_src.sub("", s) - - return s.strip() - - # def load(self, file_content: str) -> List[Document]: - def load(self, file_content: str): - file_content = self.clean_html(file_content) - file_content = markdownify.markdownify(file_content, heading_style="ATX") - doc = Document( - page_content=file_content, - metadata={"file_type": "html", "file_path": self.aws_path}, - ) - - return doc - - -def process_html(html_str: str, **kwargs): - bucket_name = kwargs["bucket"] - key = kwargs["key"] - loader = CustomHtmlLoader(aws_path=f"s3://{bucket_name}/{key}") - doc = loader.load(html_str) - splitter = MarkdownHeaderTextSplitter(kwargs["res_bucket"]) - doc_list = splitter.split_text(doc) - - return doc_list diff --git a/source/lambda/embedding/utils/image.py b/source/lambda/embedding/utils/image.py deleted file mode 100644 index 514c567bf..000000000 --- a/source/lambda/embedding/utils/image.py +++ /dev/null @@ -1,3 +0,0 @@ -def process_image(image: bytes): - # TODO: Implement image processing with ASK API - pass diff --git a/source/lambda/embedding/utils/json.py b/source/lambda/embedding/utils/json.py deleted file mode 100644 index 440e32578..000000000 --- a/source/lambda/embedding/utils/json.py +++ /dev/null @@ -1,77 +0,0 @@ -import copy -import json -import logging -from typing import Optional - -from langchain.docstore.document import Document -from langchain.document_loaders.base import BaseLoader - -from .splitter_utils import MarkdownHeaderTextSplitter - -logger = logging.getLogger(__name__) - - -class CustomJsonLoader(BaseLoader): - """Load markdown file. - - Args: - file_content: File content in markdown file. - - encoding: File encoding to use. If `None`, the file will be loaded - with the default system encoding. - - autodetect_encoding: Whether to try to autodetect the file encoding - if the specified encoding fails. - """ - - def __init__( - self, - aws_path: str, - res_bucket: str, - encoding: Optional[str] = None, - autodetect_encoding: bool = False, - ): - """Initialize with file path.""" - self.aws_path = aws_path - self.encoding = encoding - self.autodetect_encoding = autodetect_encoding - self.splitter = MarkdownHeaderTextSplitter(res_bucket) - - def load(self, content: str): - """Load from file path.""" - metadata = { - "content_type": "paragraph", - "heading_hierarchy": {}, - "figure_list": [], - "chunk_id": "$$", - "file_path": "", - "keywords": [], - "summary": "", - "file_type": "json", - } - item = json.loads(content) - content = item["content"] - source_url = item["source"] if "source" in item else item.get("url", "N/A") - source_url = source_url if isinstance(source_url, str) else "N/A" - - item_metadata = copy.deepcopy(metadata) - item_metadata["file_path"] = source_url - - for key, values in item.items(): - if key not in ["content", "source", "url"]: - item_metadata[key] = values - - doc = Document(page_content=content, metadata=item_metadata) - - return doc - - -def process_json(file_content: str, **kwargs): - bucket = kwargs["bucket"] - key = kwargs["key"] - res_bucket = kwargs["res_bucket"] - loader = CustomJsonLoader(aws_path=f"s3://{bucket}/{key}", res_bucket=res_bucket) - doc = loader.load(file_content) - splitter = MarkdownHeaderTextSplitter(kwargs["res_bucket"]) - doc_list = splitter.split_text(doc) - return doc_list diff --git a/source/lambda/embedding/utils/jsonl.py b/source/lambda/embedding/utils/jsonl.py deleted file mode 100644 index 89dce939e..000000000 --- a/source/lambda/embedding/utils/jsonl.py +++ /dev/null @@ -1,81 +0,0 @@ -import json -import logging -from typing import Iterable, List - -from langchain.docstore.document import Document - -logging.basicConfig(level=logging.INFO) -logger = logging.getLogger(__name__) - - -def process_jsonl(s3, jsonl: bytes, **kwargs) -> List[Document]: - """ - Process the jsonl file include query and answer pairs or other k-v alike data, in format of: - {"question": "", "answer": ""} - {"question": "", "answer": ""} - ... - - We will extract the question and assemble the content in page_content of Document, extract the answer and assemble as extra field in metadata (jsonlAnswer) of Document. - - :param jsonl: jsonl file content - :param kwargs: other arguments - - :return: list of Document, e.g. - [ - Document(page_content="", metadata={"jsonlAnswer": ", other metadata in metadata_template"}), - Document(page_content="", metadata={"jsonlAnswer": ", other metadata in metadata_template"}), - ... - ] - """ - logger.info("Processing jsonl file...") - bucket = kwargs["bucket"] - key = kwargs["key"] - - try: - # load the jsonl file from bytes directly and split into lines - jsonl_list = jsonl.decode("utf-8").split("\n") - - doc_list = [] - for jsonl_line in jsonl_list: - try: - # instantiate the metadata template for each document - metadata_template = { - "content_type": "paragraph", - "heading_hierarchy": {}, - "figure_list": [], - "chunk_id": "$$", - "file_path": "", - "keywords": [], - "summary": "", - } - # load the jsonl line as a json object - json_obj = json.loads(jsonl_line) - # extract the question - page_content = json_obj["question"] - # assemble the metadata - metadata = metadata_template - metadata["jsonlAnswer"] = json_obj["answer"] - metadata["file_path"] = f"s3://{bucket}/{key}" - logger.info( - "question: {}, answer: {}".format( - json_obj["question"], json_obj["answer"] - ) - ) - # assemble the Document - doc = Document(page_content=page_content, metadata=metadata) - doc_list.append(doc) - except json.JSONDecodeError as e: - logger.error( - f"jsonl_line: {jsonl_line} is not a valid json object, error: {e}" - ) - continue - except KeyError as e: - logger.error(f"jsonl_line: {jsonl_line} does not contain key: {e}") - except UnicodeDecodeError as e: - logger.error(f"jsonl file is not utf-8 encoded, error: {e}") - raise e - - logger.info( - f"processed jsonl_list: {doc_list} and if it is iterable: {isinstance(doc_list, Iterable)}" - ) - return doc_list diff --git a/source/lambda/embedding/utils/markdown.py b/source/lambda/embedding/utils/markdown.py deleted file mode 100644 index a7c287356..000000000 --- a/source/lambda/embedding/utils/markdown.py +++ /dev/null @@ -1,51 +0,0 @@ -import logging -from typing import Optional - -from langchain.docstore.document import Document -from langchain.document_loaders.base import BaseLoader - -from .splitter_utils import MarkdownHeaderTextSplitter - -logger = logging.getLogger(__name__) - - -class CustomMarkdownLoader(BaseLoader): - """Load markdown file. - - Args: - file_content: File content in markdown file. - - encoding: File encoding to use. If `None`, the file will be loaded - with the default system encoding. - - autodetect_encoding: Whether to try to autodetect the file encoding - if the specified encoding fails. - """ - - def __init__( - self, - aws_path: str, - encoding: Optional[str] = None, - autodetect_encoding: bool = False, - ): - """Initialize with file path.""" - self.aws_path = aws_path - self.encoding = encoding - self.autodetect_encoding = autodetect_encoding - - def load(self, content: str) -> Document: - """Load from file path.""" - metadata = {"file_path": self.aws_path, "file_type": "md"} - - return Document(page_content=content, metadata=metadata) - - -def process_md(file_content: str, **kwargs): - bucket = kwargs["bucket"] - key = kwargs["key"] - loader = CustomMarkdownLoader(aws_path=f"s3://{bucket}/{key}") - doc = loader.load(file_content) - splitter = MarkdownHeaderTextSplitter(kwargs["res_bucket"]) - doc_list = splitter.split_text(doc) - - return doc_list diff --git a/source/lambda/embedding/utils/nougat_pdf.py b/source/lambda/embedding/utils/nougat_pdf.py deleted file mode 100644 index 7ca674405..000000000 --- a/source/lambda/embedding/utils/nougat_pdf.py +++ /dev/null @@ -1,170 +0,0 @@ -import logging -import subprocess -from pathlib import Path -from typing import Dict, Iterator, List, Optional - -from langchain.docstore.document import Document -from langchain.document_loaders.pdf import BasePDFLoader - -from .splitter_utils import MarkdownHeaderTextSplitter, extract_headings - -# from langchain.text_splitter import MarkdownHeaderTextSplitter - -logging.basicConfig(level=logging.INFO) -logger = logging.getLogger(__name__) - -metadata_template = { - "content_type": "paragraph", - "heading_hierarchy": {}, - "figure_list": [], - "chunk_id": "$$", - "file_path": "", - "keywords": [], - "summary": "", -} - - -class NougatPDFLoader(BasePDFLoader): - """A PDF loader class for converting PDF files to MMD. - - This class leverages the `nougat` library to perform the conversion from PDF to HTML. - It inherits from `BasePDFLoader` and extends its functionality to utilize the `nougat` library. - TODO, the load_and_split method need to be implemented and default is RecursiveCharacterTextSplitter - Attributes: - file_path (str): The path to the PDF file to be loaded. - headers (Optional[Dict]): Optional headers to be used when loading the PDF. - - Raises: - ImportError: If the `nougat` library is not installed. - RuntimeError: If the `nougat` command fails to execute successfully. - """ - - def __init__(self, file_path: str, *, headers: Optional[Dict] = None): - """Initialize with a file path.""" - try: - import nougat - except ImportError: - raise ImportError( - "Please install nougat to use NougatPDFLoader. " - "You can install it with `pip install nougat`." - ) - - super().__init__(file_path, headers=headers) - - def nougat(self, file_path: Path) -> str: - """Executes the `nougat` command to convert the specified PDF file to Markdown format. - - Args: - file_path (Path): The path to the PDF file to be converted. - - Returns: - str: The Markdown content resulting from the `nougat` conversion. - """ - # nougat ./paperSnapshot.pdf --full-precision --markdown -m 0.1.0-base -o tmp --recompute - cli_command = [ - "nougat", - str(file_path), - "full-precision", - "--markdown", - "-m", - "0.1.0-base", - "-o", - "tmp", - "--recompute", - ] - - try: - result = subprocess.run( - cli_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True - ) - result.check_returncode() - return result.stdout - - except subprocess.CalledProcessError as e: - logger.info( - f"Nougat command failed with return code {e.returncode}: {e.stderr}" - ) - raise RuntimeError("Nougat command failed.") from e - - def load(self) -> List[Document]: - """Loads and processes the specified PDF file, converting it to a list of Document objects. - - Returns: - List[Document]: A list containing a single Document object with the processed content. - """ - return list(self.lazy_load()) - - def lazy_load(self) -> Iterator[Document]: - """Lazy load and process the specified PDF file, yielding Document objects. - - This method reads the PDF file, processes it using the `nougat` command, - reads the resulting Markdown content, and yields a Document object with the content. - """ - # try: - file_path = self.file_path - # Call the method to run the Nougat OCR command - self.nougat(file_path) - - # Rest of your code for reading and processing the output - file_path = Path(file_path) - output_path = Path("tmp") / f"{file_path.stem}.mmd" - with output_path.open("r") as f: - content = f.read() - # consider math expressions are enclosed in \( and \) in Markdown - content = ( - content.replace(r"\(", "$") - .replace(r"\)", "$") - .replace(r"\[", "$$") - .replace(r"\]", "$$") - ) - logger.info("content: %s", content) - # extract headings hierarchically - headings = extract_headings(content) - - # assemble metadata from template - metadata = metadata_template - metadata["content_type"] = "paragraph" - metadata["heading_hierarchy"] = headings - metadata["chunk_id"] = "$$" - metadata["file_path"] = str(file_path) - # TODO, use PyMuPDF to detect image and figure list, but no link to the image for the extracted text - # metadata["figure_list"] = [] - - yield Document(page_content=content, metadata=metadata) - - # except Exception as e: - # logger.info(f"An error occurred while processing the PDF: {str(e)}") - - -def nougat_process_pdf(local_path, **kwargs): - """ - Process a given PDF file and extracts structured information from it. - - This function reads a PDF file, converts it to HTML using PDFMiner, then extracts - and structures the information into a list of dictionaries containing headings and content. - - Parameters: - s3 (boto3.client): The S3 client to use for downloading the PDF file. - pdf (bytes): The PDF file to process. - **kwargs: Arbitrary keyword arguments. The function expects 'bucket' and 'key' among the kwargs - to specify the S3 bucket and key where the PDF file is located. - - Returns: - list[Document]: A list of Document objects, each representing a semantically grouped section of the PDF file. Each Document object contains a metadata defined in metadata_template, and page_content string with the text content of that section. - """ - - bucket = kwargs["bucket"] - key = kwargs["key"] - - loader = NougatPDFLoader(local_path) - data = loader.load() - logger.info("raw data: %s", data) - # Update file_path metadata to full s3 path in list of Document objects - data[0].metadata["file_path"] = f"s3://{bucket}/{key}" - markdown_splitter = MarkdownHeaderTextSplitter(kwargs["res_bucket"]) - md_header_splits = markdown_splitter.split_text(data[0]) - for i, doc in enumerate(md_header_splits): - logger.info( - "PDF file processed successfully, with content of chunk %s: %s", i, doc - ) - return md_header_splits diff --git a/source/lambda/embedding/utils/pdf.py b/source/lambda/embedding/utils/pdf.py deleted file mode 100644 index 1e031b539..000000000 --- a/source/lambda/embedding/utils/pdf.py +++ /dev/null @@ -1,163 +0,0 @@ -import json -import logging -import os -import re - -from langchain.docstore.document import Document -from langchain.document_loaders import PDFMinerPDFasHTMLLoader - -from .cleaning import remove_duplicate_sections -from .splitter_utils import MarkdownHeaderTextSplitter - -logger = logging.getLogger() -logger.setLevel(logging.INFO) - -metadata_template = { - "content_type": "paragraph", - "heading_hierarchy": {}, - "figure_list": [], - "chunk_id": "$$", - "file_path": "", - "keywords": [], - "summary": "", -} - - -def detect_language(input): - """ - This function detects the language of the input text. It checks if the input is a list, - and if so, it joins the list into a single string. Then it uses a regular expression to - search for Chinese characters in the input. If it finds any, it returns 'ch' for Chinese. - If it doesn't find any Chinese characters, it assumes the language is English and returns 'en'. - """ - if isinstance(input, list): - input = " ".join(input) - if re.search("[\u4e00-\u9fff]", input): - return "ch" - else: - return "en" - - -def invoke_etl_model( - smr_client, - etl_model_endpoint, - bucket, - key, - res_bucket, - portal_bucket_name: str, - mode="ppstructure", - lang="ch", -): - response_model = smr_client.invoke_endpoint( - EndpointName=etl_model_endpoint, - Body=json.dumps( - { - "s3_bucket": bucket, - "object_key": key, - "destination_bucket": res_bucket, - "portal_bucket": portal_bucket_name, - "mode": mode, - "lang": lang, - } - ), - ContentType="application/json", - ) - - json_str = response_model["Body"].read().decode("utf8") - json_obj = json.loads(json_str) - markdown_prefix = json_obj["destination_prefix"] - - return markdown_prefix - - -def load_content_from_s3(s3, bucket, key): - """ - This function loads the content of a file from S3 and returns it as a string. - """ - logger.info(f"Loading content from s3://{bucket}/{key}") - obj = s3.get_object(Bucket=bucket, Key=key) - return obj["Body"].read().decode("utf-8") - - -def process_pdf(s3, pdf: bytes, **kwargs): - """ - Process a given PDF file and extracts structured information from it. - - This function reads a PDF file, converts it to HTML using PDFMiner, then extracts - and structures the information into a list of dictionaries containing headings and content. - - Parameters: - s3 (boto3.client): The S3 client to use for downloading the PDF file. - pdf (bytes): The PDF file to process. - **kwargs: Arbitrary keyword arguments. The function expects 'bucket' and 'key' among the kwargs - to specify the S3 bucket and key where the PDF file is located. - - Returns: - list[Document]: A list of Document objects, each representing a semantically grouped section of the PDF file. Each Document object contains a metadata defined in metadata_template, and page_content string with the text content of that section. - """ - bucket = kwargs["bucket"] - key = kwargs["key"] - etl_model_endpoint = kwargs.get("etl_model_endpoint", None) - smr_client = kwargs.get("smr_client", None) - res_bucket = kwargs.get("res_bucket", None) - portal_bucket_name = kwargs.get("portal_bucket_name", None) - need_split = kwargs.get("need_split", None) - logger.info("Input arguments: {}".format(kwargs)) - # extract the file into tmp folder - local_path = "/tmp/{}".format(os.path.basename(key)) - s3.download_file(Bucket=bucket, Key=key, Filename=local_path) - # TODO, will be deprecated and replaced by nougat class in loader_utils - loader = PDFMinerPDFasHTMLLoader(local_path) - # entire PDF is loaded as a single Document - file_content = loader.load()[0].page_content - - detected_lang = detect_language(file_content[:100000]) - logger.info(f"Detected language: {detected_lang}") - - if not etl_model_endpoint or not smr_client or not res_bucket: - logger.error( - "Cannot find ETL model endpoint, SMR client or result bucket, please check the arguments." - ) - else: - if detected_lang == "ch": - logger.info("Detected language is Chinese, using default PDF loader...") - markdown_prefix = invoke_etl_model( - smr_client, - etl_model_endpoint, - bucket, - key, - res_bucket, - portal_bucket_name, - mode="ppstructure", - lang="ch", - ) - logger.info(f"Markdown file path: s3://{res_bucket}/{markdown_prefix}") - content = load_content_from_s3(s3, res_bucket, markdown_prefix) - else: - logger.info("Detected language is English, using ETL model endpoint...") - markdown_prefix = invoke_etl_model( - smr_client, - etl_model_endpoint, - bucket, - key, - res_bucket, - portal_bucket_name, - mode="ppstructure", - lang="en", - ) - logger.info(f"Markdown file path: s3://{res_bucket}/{markdown_prefix}") - content = load_content_from_s3(s3, res_bucket, markdown_prefix) - - # remove duplicate sections - content = remove_duplicate_sections(content) - metadata = {"file_path": f"s3://{bucket}/{key}", "file_type": "pdf"} - # need_split is type of boolean, judge if we need to split the content - if not need_split: - return [Document(page_content=content, metadata=metadata)] - - markdown_splitter = MarkdownHeaderTextSplitter(res_bucket) - doc_list = markdown_splitter.split_text( - Document(page_content=content, metadata=metadata) - ) - - return doc_list diff --git a/source/lambda/embedding/utils/splitter_utils.py b/source/lambda/embedding/utils/splitter_utils.py deleted file mode 100644 index ead54df92..000000000 --- a/source/lambda/embedding/utils/splitter_utils.py +++ /dev/null @@ -1,362 +0,0 @@ -import logging -import re -import uuid -from typing import Any, List - -import boto3 -from langchain.docstore.document import Document -from langchain.text_splitter import ( - TextSplitter, -) - - -s3 = boto3.client("s3") -logger = logging.getLogger() -logger.setLevel(logging.INFO) - - -def _make_spacy_pipeline_for_splitting(pipeline: str) -> Any: # avoid importing spacy - try: - import spacy - except ImportError: - raise ImportError( - "Spacy is not installed, please install it with `pip install spacy`." - ) - if pipeline == "sentencizer": - from spacy.lang.en import English - - sentencizer = English() - sentencizer.add_pipe("sentencizer") - else: - sentencizer = spacy.load(pipeline, exclude=["ner", "tagger"]) - return sentencizer - - -class NLTKTextSplitter(TextSplitter): - """Splitting text using NLTK package.""" - - def __init__( - self, separator: str = "\n\n", language: str = "english", **kwargs: Any - ) -> None: - """Initialize the NLTK splitter.""" - super().__init__(**kwargs) - try: - from nltk.tokenize import sent_tokenize - - self._tokenizer = sent_tokenize - except ImportError: - raise ImportError( - "NLTK is not installed, please install it with `pip install nltk`." - ) - self._separator = separator - self._language = language - - def split_text(self, text: str) -> List[str]: - """Split incoming text and return chunks.""" - # First we naively split the large input into a bunch of smaller ones. - splits = self._tokenizer(text, language=self._language) - return self._merge_splits(splits, self._separator) - - -class SpacyTextSplitter(TextSplitter): - """Splitting text using Spacy package. - - - Per default, Spacy's `en_core_web_sm` model is used. For a faster, but - potentially less accurate splitting, you can use `pipeline='sentencizer'`. - """ - - def __init__( - self, separator: str = "\n\n", pipeline: str = "en_core_web_sm", **kwargs: Any - ) -> None: - """Initialize the spacy text splitter.""" - super().__init__(**kwargs) - self._tokenizer = _make_spacy_pipeline_for_splitting(pipeline) - self._separator = separator - - def split_text(self, text: str) -> List[str]: - """Split incoming text and return chunks.""" - splits = (s.text for s in self._tokenizer(text).sents) - return self._merge_splits(splits, self._separator) - - -def find_parent(headers: dict, level: int): - """Find the parent node of current node - Find the last node whose level is less than current node - - Args: - headers (dict): headers dict - level (int): level of the header, eg. # is level1, ## is level2 - - Returns: - _type_: parent node id or None - """ - for id, header in reversed(list(headers.items())): - if header["level"] < level: - return id - - return None - - -def find_previous_with_same_level(headers: dict, level: int): - """Find the previous node with same level - - Args: - headers (dict): headers dict - level (int): level of the header, eg. # is level1, ## is level2 - - Returns: - _type_: previous node id or None - """ - for id, header in reversed(list(headers.items())): - if header["level"] == level: - return id - - return None - - -def find_next_with_same_level(headers: dict, header_id: str): - level = headers[header_id]["level"] - header_found = False - - for id, header in headers.items(): - if header_id == id: - header_found = True - - # Find the next node with the same level - if header_found and header["level"] == level and header_id != id: - return id - - return None - - -def find_child(headers: dict, header_id: str): - children = [] - level = headers[header_id]["level"] - - for id, header in headers.items(): - if ( - header["level"] == level + 1 - and id not in children - and header["parent"] == header_id - ): - children.append(id) - - return children - - -def extract_headings(md_content: str): - """Extract heading hierarchy from Markdown content. - Args: - md_content (str): Markdown content. - Returns: - Json object contains the heading hierarchy - """ - header_index = 0 - headers = {} - lines = md_content.split("\n") - id_index_dict = {} - for line in lines: - match = re.match(r"(#+)(.*)", line) - if match: - header_index += 1 - # print(match.group) - level = len(match.group(1)) - title = match.group(2).strip() - id_prefix = str(uuid.uuid4())[:8] - _id = f"${header_index}-{id_prefix}" - parent = find_parent(headers, level) - previous = find_previous_with_same_level(headers, level) - headers[_id] = { - "title": title, - "level": level, - "parent": parent, - "previous": previous, - } - # Use list in case multiple heading have the same title - if title not in id_index_dict: - id_index_dict[title] = [_id] - else: - id_index_dict[title].append(_id) - - for header_obj in headers: - headers[header_obj]["child"] = find_child(headers, header_obj) - headers[header_obj]["next"] = find_next_with_same_level(headers, header_obj) - - return headers, id_index_dict - - -# Rewrite this class to use the new TextSplitter for mmd type -class MarkdownHeaderTextSplitter: - # Place holder for now without parameters - def __init__(self, res_bucket: str = None): - self.res_bucket = res_bucket - - def _is_markdown_header(self, line): - header_pattern = r"^#+\s+" - if re.match(header_pattern, line): - return True - else: - return False - - def _is_markdown_table_row(self, line): - return re.fullmatch(r"\|.*\|.*\|", line) is not None - - def _set_chunk_id( - self, - id_index_dict: dict, - current_heading: str, - metadata: dict, - same_heading_dict: dict, - ): - """Set chunk id when there are multiple headings are the same. - Eg. - # Heading 1 - ## Same heading - # Heading 2 - ## Same heading - - Args: - id_index_dict (dict): Id and index mapping - current_heading (str): Current heading - metadata (dict): Metadata - same_heading_dict (dict): Same heading mapping - """ - if 1 == len(id_index_dict[current_heading]): - metadata["chunk_id"] = id_index_dict[current_heading][0] - elif len(id_index_dict[current_heading]) > 1: - # If multiple headings are the same in the document, - # use index in same_heading_dict to get the chunk_id - if current_heading not in same_heading_dict: - same_heading_dict[current_heading] = 0 - metadata["chunk_id"] = id_index_dict[current_heading][0] - else: - # Move one step to get the next chunk_id - same_heading_dict[current_heading] += 1 - if ( - len(id_index_dict[current_heading]) - > same_heading_dict[current_heading] - ): - metadata["chunk_id"] = id_index_dict[current_heading][ - same_heading_dict[current_heading] - ] - else: - id_prefix = str(uuid.uuid4())[:8] - metadata["chunk_id"] = f"$0-{id_prefix}" - - def split_text(self, text: Document) -> List[Document]: - if self.res_bucket is not None: - # save_content_to_s3(s3, text, self.res_bucket, SplittingType.BEFORE.value) - pass - else: - logger.warning( - "No resource bucket is defined, skip saving content into S3 bucket" - ) - - lines = text.page_content.strip().split("\n") - chunks = [] - current_chunk_content = [] - same_heading_dict = {} - table_content = [] - inside_table = False - heading_hierarchy, id_index_dict = extract_headings(text.page_content.strip()) - if len(lines) > 0: - current_heading = lines[0] - - for line in lines: - # Replace escaped characters for table markers - line = line.strip() - line = line.replace(r"\begin{table}", "\\begin{table}").replace( - r"\end{table}", "\\end{table}" - ) - if line in ["\\begin{table}", "\\end{table}"]: - continue - - if self._is_markdown_header(line): # Assuming these denote headings - # Save the current chunk if it exists - if current_chunk_content: - metadata = text.metadata.copy() - metadata["content_type"] = "paragragh" - metadata["current_heading"] = current_heading - current_heading = current_heading.replace("#", "").strip() - try: - self._set_chunk_id( - id_index_dict, current_heading, metadata, same_heading_dict - ) - except KeyError: - logger.info( - f"No standard heading found, check your document with {current_chunk_content}" - ) - id_prefix = str(uuid.uuid4())[:8] - metadata["chunk_id"] = f"$0-{id_prefix}" - if metadata["chunk_id"] in heading_hierarchy: - metadata["heading_hierarchy"] = heading_hierarchy[ - metadata["chunk_id"] - ] - chunks.append( - Document( - page_content="\n".join(current_chunk_content), - metadata=metadata, - ) - ) - current_chunk_content = [] # Reset for the next chunk - current_heading = line - - if self._is_markdown_table_row(line): - inside_table = True - elif inside_table: - # The first line under a table - inside_table = False - # Save table content as a separate document - if table_content: - metadata = text.metadata.copy() - metadata["content_type"] = "table" - metadata["current_heading"] = current_heading - current_heading = current_heading.replace("#", "").strip() - try: - self._set_chunk_id( - id_index_dict, current_heading, metadata, same_heading_dict - ) - except KeyError: - logger.info(f"No standard heading found") - id_prefix = str(uuid.uuid4())[:8] - metadata["chunk_id"] = f"$0-{id_prefix}" - if metadata["chunk_id"] in heading_hierarchy: - metadata["heading_hierarchy"] = heading_hierarchy[ - metadata["chunk_id"] - ] - chunks.append( - Document( - page_content="\n".join(table_content), metadata=metadata - ) - ) - table_content = [] # Reset for the next table - - if inside_table: - table_content.append(line) - else: - current_chunk_content.append(line) - - # Save the last chunk if it exists - if current_chunk_content: - metadata = text.metadata.copy() - metadata["content_type"] = "paragragh" - metadata["current_heading"] = current_heading - current_heading = current_heading.replace("#", "").strip() - try: - self._set_chunk_id( - id_index_dict, current_heading, metadata, same_heading_dict - ) - except KeyError: - logger.info(f"No standard heading found") - id_prefix = str(uuid.uuid4())[:8] - metadata["chunk_id"] = f"$0-{id_prefix}" - if metadata["chunk_id"] in heading_hierarchy: - metadata["heading_hierarchy"] = heading_hierarchy[metadata["chunk_id"]] - chunks.append( - Document( - page_content="\n".join(current_chunk_content), metadata=metadata - ) - ) - - return chunks diff --git a/source/lambda/embedding/utils/storage_utils.py b/source/lambda/embedding/utils/storage_utils.py deleted file mode 100644 index 55b8cc4af..000000000 --- a/source/lambda/embedding/utils/storage_utils.py +++ /dev/null @@ -1,85 +0,0 @@ -""" -Helper functions for storage intermediate content or log -""" - -import datetime -import json -import logging - -from langchain.docstore.document import Document - -logger = logging.getLogger() -logger.setLevel(logging.INFO) - - -def convert_to_logger(document: Document) -> str: - # TODO: Convert the document to a logger file format, customize if possible - logger_content = "Page Content: \n" + document.page_content + "\n" - logger_content += "Metadata: " + json.dumps(document.metadata, ensure_ascii=False) - - return logger_content - - -def upload_chunk_to_s3( - s3, logger_content: str, bucket: str, prefix: str, splitting_type: str -): - """Upload the logger file to S3 with hierarchy below: - filename A - ├── semantic-splitting (split by headers) - │ ├── timestamp 1 - │ │ ├── logger file 1 - │ ├── timestamp 2 - │ │ ├── logger file 2 - ├── chunk-size-splitting (split by chunk size) - │ ├── timestamp 3 - │ │ ├── logger file 3 - │ ├── timestamp 4 - │ │ ├── logger file 4 - ├── before-splitting (whole markdown content before splitting) - │ ├── timestamp 5 - │ │ ├── logger file 5 - │ ├── timestamp 6 - │ │ ├── logger file 6 - filename B - ├── semantic-splitting - │ ├── timestamp 7 - │ │ ├── logger file 7 - │ ├── timestamp 8 - │ │ ├── logger file 8 - ├── chunk-size-splitting - │ ├── timestamp 9 - │ │ ├── logger file 9 - │ ├── timestamp 10 - │ │ ├── logger file 10 - ├── before-splitting - │ ├── timestamp 11 - │ │ ├── logger file 11 - │ ├── timestamp 12 - │ │ ├── logger file 12 - ... - """ - # round the timestamp to hours to avoid too many folders - timestamp = datetime.datetime.now().strftime("%Y-%m-%d-%H") - # make the logger file name unique - object_key = f"{prefix}/{splitting_type}/{timestamp}/{datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S-%f')}.log" - try: - res = s3.put_object(Bucket=bucket, Key=object_key, Body=logger_content) - logger.debug(f"Upload logger file to S3: {res}") - except Exception as e: - logger.error(f"Error uploading logger file to S3: {e}") - - -def save_content_to_s3(s3, document: Document, res_bucket: str, splitting_type: str): - """Save content to S3 bucket - - Args: - document (Document): The page document to be saved - res_bucket (str): Target S3 bucket - s3 (_type_): S3 client - """ - logger_file = convert_to_logger(document) - # Extract the filename from the file_path in the metadata - file_path = document.metadata.get("file_path", "") - filename = file_path.split("/")[-1].split(".")[0] - # RecursiveCharacterTextSplitter have been rewrite to split based on chunk size & overlap, use separate folder to store the logger file - upload_chunk_to_s3(s3, logger_file, res_bucket, filename, splitting_type) diff --git a/source/lambda/embedding/utils/text.py b/source/lambda/embedding/utils/text.py deleted file mode 100644 index 8af8d4d80..000000000 --- a/source/lambda/embedding/utils/text.py +++ /dev/null @@ -1,62 +0,0 @@ -import logging -import re -from typing import List, Optional - -from langchain.docstore.document import Document -from langchain.document_loaders.text import TextLoader - -from .splitter_utils import MarkdownHeaderTextSplitter - -logger = logging.getLogger(__name__) - - -class CustomTextLoader(TextLoader): - """Load text file. - - Args: - file_content: Text file content. - - encoding: File encoding to use. If `None`, the file will be loaded - with the default system encoding. - - autodetect_encoding: Whether to try to autodetect the file encoding - if the specified encoding fails. - """ - - def __init__( - self, - file_path: str, - encoding: Optional[str] = None, - autodetect_encoding: bool = False, - ): - """Initialize with file path.""" - self.file_path = file_path - self.encoding = encoding - self.autodetect_encoding = autodetect_encoding - - def load(self, text_content: str) -> List[Document]: - """Load from file path.""" - metadata = {"file_path": self.file_path, "file_type": "txt"} - - return Document(page_content=text_content, metadata=metadata) - - -def pre_process_text(text_content: str) -> str: - # Clean up text content - text_content = re.sub(r"\s+", " ", text_content) - text_content = re.sub(r"\n+", "\n", text_content) - - return text_content.strip() - - -def process_text(file_content: str, **kwargs): - clean_text = pre_process_text(file_content) - bucket = kwargs["bucket"] - key = kwargs["key"] - loader = CustomTextLoader(file_path=f"s3://{bucket}/{key}") - doc = loader.load(clean_text) - - splitter = MarkdownHeaderTextSplitter(kwargs["res_bucket"]) - doc_list = splitter.split_text(doc) - - return doc_list diff --git a/source/lambda/intention/requirements.txt b/source/lambda/intention/requirements.txt new file mode 100644 index 000000000..16ba7866f --- /dev/null +++ b/source/lambda/intention/requirements.txt @@ -0,0 +1 @@ +openpyxl==3.1.3 \ No newline at end of file diff --git a/source/lambda/job/retail_entry_workflow.png b/source/lambda/job/retail_entry_workflow.png deleted file mode 100644 index 05c81f81e..000000000 Binary files a/source/lambda/job/retail_entry_workflow.png and /dev/null differ diff --git a/source/lambda/online/common_logic/common_utils/langchain_utils.py b/source/lambda/online/common_logic/common_utils/langchain_utils.py index 87e8c44e8..b3f9f3160 100644 --- a/source/lambda/online/common_logic/common_utils/langchain_utils.py +++ b/source/lambda/online/common_logic/common_utils/langchain_utils.py @@ -9,10 +9,6 @@ RunnablePassthrough, ) from langchain.schema.runnable.base import RunnableLambda -from prettytable import PrettyTable - -# import threading -# import time from .logger_utils import logger from .python_utils import update_nest_dict @@ -211,32 +207,5 @@ def chain_logger( return new_chain -def format_trace_infos(trace_infos: list, use_pretty_table=True): - trace_infos = sorted(trace_infos, key=lambda x: x["create_time"]) - trace_info_strs = [] - - if use_pretty_table: - table = PrettyTable() - table.field_names = ["chain_name", "create_time", "action"] - table.add_rows( - [ - ( - trace_info["chain_name"], - trace_info["create_time"], - trace_info["action"], - ) - for trace_info in trace_infos - ] - ) - return str(table) - - for trace_info in trace_infos: - trace_info_strs.append( - f"time: {trace_info['create_time']}, action: {trace_info['action']}, chain: {trace_info['chain_name']}, " - ) - - return "\n".join(trace_info_strs) - - class NestUpdateState(TypedDict): keys: Annotated[dict, update_nest_dict] diff --git a/source/lambda/online/common_logic/langchain_integration/chains/hyde_chain.py b/source/lambda/online/common_logic/langchain_integration/chains/hyde_chain.py deleted file mode 100644 index 7302b6d53..000000000 --- a/source/lambda/online/common_logic/langchain_integration/chains/hyde_chain.py +++ /dev/null @@ -1,107 +0,0 @@ -# hyde - -from langchain.prompts import ( - ChatPromptTemplate, - HumanMessagePromptTemplate, -) -from langchain.schema.runnable import ( - RunnableLambda, - RunnablePassthrough, -) - -from common_logic.common_utils.constant import ( - LLMTaskType, - LLMModelType -) - -from ..chains import LLMChain -from ..chat_models import Model as LLM_Model -from .chat_chain import Internlm2Chat7BChatChain -from . import LLMChain - -HYDE_TYPE = LLMTaskType.HYDE_TYPE - -WEB_SEARCH_TEMPLATE = """Please write a passage to answer the question -Question: {query} -Passage:""" -# hyde_web_search_template = PromptTemplate(template=WEB_SEARCH_TEMPLATE, input_variables=["query"]) - - -class Claude2HydeChain(LLMChain): - model_id = LLMModelType.CLAUDE_2 - intent_type = HYDE_TYPE - - default_model_kwargs = { - "temperature": 0.5, - "max_tokens": 1000, - "stop_sequences": ["\n\nHuman:"], - } - - @classmethod - def create_chain(cls, model_kwargs=None, **kwargs): - # query_key = kwargs.pop("query_key", "query") - model_kwargs = model_kwargs or {} - model_kwargs = {**cls.default_model_kwargs, **model_kwargs} - - llm = LLM_Model.get_model( - model_id=cls.model_id, - model_kwargs=model_kwargs, - ) - prompt = ChatPromptTemplate.from_messages( - [HumanMessagePromptTemplate.from_template(WEB_SEARCH_TEMPLATE)] - ) - chain = RunnablePassthrough.assign( - hyde_doc=prompt | llm | RunnableLambda(lambda x: x.content) - ) - return chain - - -class Claude21HydeChain(Claude2HydeChain): - model_id = LLMModelType.CLAUDE_21 - - -class ClaudeInstanceHydeChain(Claude2HydeChain): - model_id = LLMModelType.CLAUDE_INSTANCE - - -class Claude3SonnetHydeChain(Claude2HydeChain): - model_id = LLMModelType.CLAUDE_3_SONNET - - -class Claude3HaikuHydeChain(Claude2HydeChain): - model_id = LLMModelType.CLAUDE_3_HAIKU - - -class Claude35SonnetHydeChain(Claude2HydeChain): - model_id = "anthropic.claude-3-5-sonnet-20240620-v1:0" - - -internlm2_meta_instruction = "You are a helpful AI Assistant." - - -class Internlm2Chat7BHydeChain(Internlm2Chat7BChatChain): - model_id = LLMModelType.INTERNLM2_CHAT_7B - intent_type = HYDE_TYPE - - default_model_kwargs = {"temperature": 0.1, "max_new_tokens": 200} - - @classmethod - def create_prompt(cls, x): - query = f"""Please write a brief passage to answer the question. \nQuestion: {prompt}""" - prompt = ( - cls.build_prompt( - query=query, - meta_instruction=internlm2_meta_instruction, - ) - + "Passage: " - ) - return prompt - - -class Internlm2Chat20BHydeChain(Internlm2Chat7BHydeChain): - model_id = LLMModelType.INTERNLM2_CHAT_20B - intent_type = HYDE_TYPE - - -class NovaProHydeChain(Claude2HydeChain): - model_id = LLMModelType.NOVA_PRO diff --git a/source/lambda/online/common_logic/langchain_integration/chains/intention_chain.py b/source/lambda/online/common_logic/langchain_integration/chains/intention_chain.py deleted file mode 100644 index b5483ef9a..000000000 --- a/source/lambda/online/common_logic/langchain_integration/chains/intention_chain.py +++ /dev/null @@ -1,226 +0,0 @@ -import json -import os -from functools import lru_cache -from random import Random - -from langchain.prompts import ( - ChatPromptTemplate, - HumanMessagePromptTemplate, -) -from langchain.schema.runnable import ( - RunnableLambda, - RunnablePassthrough, -) - -from common_logic.common_utils.constant import LLMTaskType, LLMModelType -from ..chat_models import Model -from .chat_chain import Internlm2Chat7BChatChain -from . import LLMChain - -abs_dir = os.path.dirname(__file__) - -intent_save_path = os.path.join( - os.path.dirname(os.path.dirname(abs_dir)), - "intent_utils", - "intent_examples", - "examples.json", -) - - -@lru_cache() -def load_intention_file(intent_save_path=intent_save_path, seed=42): - intent_few_shot_examples = json.load(open(intent_save_path)) - intent_indexs = { - intent_d["intent"]: intent_d["index"] - for intent_d in intent_few_shot_examples["intents"] - } - few_shot_examples = [] - intents = list(intent_few_shot_examples["examples"].keys()) - for intent in intents: - examples = intent_few_shot_examples["examples"][intent] - for query in examples: - few_shot_examples.append({"intent": intent, "query": query}) - # shuffle - Random(seed).shuffle(few_shot_examples) - return { - "few_shot_examples": few_shot_examples, - "intent_indexs": intent_indexs, - } - - -class Internlm2Chat7BIntentRecognitionChain(Internlm2Chat7BChatChain): - model_id = LLMModelType.INTERNLM2_CHAT_7B - intent_type = LLMTaskType.INTENT_RECOGNITION_TYPE - - default_model_kwargs = { - "temperature": 0.1, - "max_new_tokens": 100, - "stop_tokens": ["\n", "。", "."], - } - - @classmethod - def create_prompt(cls, x): - r = load_intention_file(intent_save_path) - few_shot_examples = r["few_shot_examples"] - # intent_indexs = r['intent_indexs'] - exmaple_template = "问题: {query}\n类别: {label}" - example_strs = [] - for example in few_shot_examples: - example_strs.append( - exmaple_template.format( - query=example["query"], label=example["intent"]) - ) - - example_str = "\n\n".join(example_strs) - - meta_instruction = f"你是一个问题分类助理,正在对用户的问题进行分类。为了辅助你进行问题分类,下面给出一些示例:\n{example_str}" - query_str = exmaple_template.format(query=x["query"], label="") - prompt_template = """请对下面的问题进行分类: - {query_str} - """ - prompt = cls.build_prompt( - prompt_template.format(query_str=query_str), - meta_instruction=meta_instruction, - ) - prompt = prompt + f"根据前面给到的示例, 问题{x['query']}属于类别:" - - return prompt - - @staticmethod - def postprocess(intent): - intent = intent.replace("。", "").replace(".", "").strip().strip("**") - r = load_intention_file(intent_save_path) - intent_indexs = r["intent_indexs"] - assert intent in intent_indexs, (intent, intent_indexs) - return intent - - @classmethod - def create_chain(cls, model_kwargs=None, **kwargs): - model_kwargs = model_kwargs or {} - model_kwargs = {**cls.default_model_kwargs, **model_kwargs} - chain = super().create_chain(model_kwargs=model_kwargs, **kwargs) - chain = chain | RunnableLambda(lambda x: cls.postprocess(x)) - return chain - - -class Internlm2Chat20BIntentRecognitionChain(Internlm2Chat7BIntentRecognitionChain): - model_id = LLMModelType.INTERNLM2_CHAT_20B - - -INTENT_RECOGINITION_PROMPT_TEMPLATE_CLUADE = """Please classify this query: {query}. The categories are: - -{categories} - -Some examples of how to classify queries: -{examples} - -Now classify the original query. Respond with just one letter corresponding to the correct category. -""" - - -INTENT_RECOGINITION_EXAMPLE_TEMPLATE = """{query}\n{label}""" - - -class Claude2IntentRecognitionChain(LLMChain): - model_id = LLMModelType.CLAUDE_2 - intent_type = LLMTaskType.INTENT_RECOGNITION_TYPE - - default_model_kwargs = { - "temperature": 0, - "max_tokens": 2000, - "stop_sequences": ["\n\n", "\n\nHuman:"], - } - - @classmethod - def create_few_shot_examples(cls): - ret = [] - for intent in cls.intents: - examples = cls.intent_few_shot_examples["examples"][intent] - for query in examples: - ret.append({"intent": intent, "query": query}) - return ret - - @classmethod - def create_few_shot_example_string( - cls, example_template=INTENT_RECOGINITION_EXAMPLE_TEMPLATE - ): - example_strs = [] - intent_indexs = cls.intent_indexs - for example in cls.few_shot_examples: - example_strs.append( - example_template.format( - label=intent_indexs[example["intent"] - ], query=example["query"] - ) - ) - return "\n\n".join(example_strs) - - @classmethod - def create_all_labels_string(cls): - intent_few_shot_examples = cls.intent_few_shot_examples - label_strs = [] - labels = intent_few_shot_examples["intents"] - for i, label in enumerate(labels): - label_strs.append(f"({label['index']}) {label['describe']}") - return "\n".join(label_strs) - - def postprocess(self, output: str): - out = output.strip() - assert out, output - return self.index_intents[out[0]] - - @classmethod - def create_chain(cls, model_kwargs=None, **kwargs): - r = load_intention_file(intent_save_path) - cls.few_shot_examples = r["few_shot_examples"] - cls.intent_indexs = r["intent_indexs"] - - cls.index_intents = {v: k for k, v in cls.intent_indexs.items()} - cls.intents = list(cls.intent_few_shot_examples["examples"].keys()) - cls.few_shot_examples = cls.create_few_shot_examples() - - cls.examples_str = cls.create_few_shot_example_string( - example_template=INTENT_RECOGINITION_EXAMPLE_TEMPLATE - ) - cls.categories_str = cls.create_all_labels_string() - - intent_recognition_prompt = ChatPromptTemplate.format_messages( - [ - HumanMessagePromptTemplate.from_template( - INTENT_RECOGINITION_PROMPT_TEMPLATE_CLUADE - ) - ] - ) - - model_kwargs = model_kwargs or {} - model_kwargs = {**cls.default_model_kwargs, **model_kwargs} - - llm = Model.get_model(cls.model_id, model_kwargs=model_kwargs) - - chain = ( - RunnablePassthrough.assign( - categories=lambda x: cls.categories_str, - examples=lambda x: cls.examples_str, - ) - | intent_recognition_prompt - | llm - | RunnableLambda(lambda x: cls.postprocess(x.content)) - ) - - return chain - - -class Claude21IntentRecognitionChain(Claude2IntentRecognitionChain): - model_id = LLMModelType.CLAUDE_21 - - -class ClaudeInstanceIntentRecognitionChain(Claude2IntentRecognitionChain): - model_id = LLMModelType.CLAUDE_INSTANCE - - -class Claude3SonnetIntentRecognitionChain(Claude2IntentRecognitionChain): - model_id = LLMModelType.CLAUDE_3_SONNET - - -class Claude3HaikuIntentRecognitionChain(Claude2IntentRecognitionChain): - model_id = LLMModelType.CLAUDE_3_HAIKU diff --git a/source/lambda/online/common_logic/langchain_integration/chains/marketing_chains/__init__.py b/source/lambda/online/common_logic/langchain_integration/chains/marketing_chains/__init__.py deleted file mode 100644 index a78a05a3a..000000000 --- a/source/lambda/online/common_logic/langchain_integration/chains/marketing_chains/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -from .mkt_conversation_summary import ( - Claude21MKTConversationSummaryChain, - ClaudeInstanceMKTConversationSummaryChain, - Claude2MKTConversationSummaryChain, - Claude3HaikuMKTConversationSummaryChain, - Claude3SonnetMKTConversationSummaryChain, - Internlm2Chat7BMKTConversationSummaryChain, - Internlm2Chat20BMKTConversationSummaryChain -) - -from .mkt_rag_chain import ( - Internlm2Chat7BKnowledgeQaChain, - Internlm2Chat20BKnowledgeQaChain -) - diff --git a/source/lambda/online/common_logic/langchain_integration/chains/marketing_chains/mkt_conversation_summary.py b/source/lambda/online/common_logic/langchain_integration/chains/marketing_chains/mkt_conversation_summary.py deleted file mode 100644 index 82690c2db..000000000 --- a/source/lambda/online/common_logic/langchain_integration/chains/marketing_chains/mkt_conversation_summary.py +++ /dev/null @@ -1,126 +0,0 @@ - -from langchain.schema.runnable import ( - RunnableLambda, - RunnablePassthrough, -) - -from ..chat_chain import Claude2ChatChain, Internlm2Chat7BChatChain - -from common_logic.common_utils.constant import ( - MessageType, - LLMTaskType, - LLMModelType -) - -AI_MESSAGE_TYPE = MessageType.AI_MESSAGE_TYPE -HUMAN_MESSAGE_TYPE = MessageType.HUMAN_MESSAGE_TYPE -QUERY_TRANSLATE_TYPE = LLMTaskType.QUERY_TRANSLATE_TYPE -SYSTEM_MESSAGE_TYPE = MessageType.SYSTEM_MESSAGE_TYPE -MKT_CONVERSATION_SUMMARY_TYPE = LLMTaskType.MKT_CONVERSATION_SUMMARY_TYPE - -CHIT_CHAT_SYSTEM_TEMPLATE = """You are a helpful AI Assistant""" - - -class Internlm2Chat7BMKTConversationSummaryChain(Internlm2Chat7BChatChain): - model_id = LLMModelType.INTERNLM2_CHAT_7B - intent_type = MKT_CONVERSATION_SUMMARY_TYPE - - @classmethod - def create_prompt(cls, x): - return x["prompt"] - - @classmethod - def _create_prompt(cls, x): - chat_history = x["chat_history"] - assert len(chat_history) % 2 == 0, chat_history - - history = [] - questions = [] - for i in range(0, len(chat_history), 2): - assert chat_history[i].type == HUMAN_MESSAGE_TYPE, chat_history - assert chat_history[i + 1].type == AI_MESSAGE_TYPE, chat_history - questions.append(chat_history[i].content) - history.append( - (chat_history[i].content, chat_history[i + 1].content)) - - questions_str = "" - for i, question in enumerate(questions): - questions_str += f"问题{i+1}: {question}\n" - # print(questions_str) - query_input = """请总结上述对话中的内容,为每一轮对话单独做一个不超过50个字的简短总结。\n""" - prompt = cls.build_prompt( - meta_instruction=CHIT_CHAT_SYSTEM_TEMPLATE, - history=history, - query=query_input, - ) - prompt_assist = f"好的,根据提供历史对话信息,共有{len(history)}段对话:\n{questions_str}\n对它们的总结如下(每一个总结要先复述一下问题):\n" - prefix = f"问题1: {questions[0]}\n总结:" - # thread_local.mkt_conversation_prefix = prefix - # print(thread_local,thread_local.mkt_conversation_prefix) - prompt = prompt + prompt_assist + prefix - # prompt = prompt - return {"prompt": prompt, "prefix": prefix} - - @staticmethod - def stream_postprocess_fn(x): - yield x["prefix"] - yield from x["llm_output"] - - @classmethod - def create_chain(cls, model_kwargs=None, **kwargs): - model_kwargs = model_kwargs or {} - stream = kwargs.get("stream", False) - llm_chain = super().create_chain(model_kwargs=model_kwargs, **kwargs) - chain = ( - RunnablePassthrough.assign( - prompt_dict=lambda x: cls._create_prompt(x)) - | RunnablePassthrough.assign( - prompt=lambda x: x["prompt_dict"]["prompt"], - prefix=lambda x: x["prompt_dict"]["prefix"], - ) - | RunnablePassthrough.assign(llm_output=llm_chain) - ) - if stream: - chain = chain | RunnableLambda( - lambda x: cls.stream_postprocess_fn(x)) - else: - chain = chain | RunnableLambda( - lambda x: x["prefix"] + x["llm_output"]) - return chain - - -class Internlm2Chat20BMKTConversationSummaryChain( - Internlm2Chat7BMKTConversationSummaryChain -): - model_id = LLMModelType.INTERNLM2_CHAT_20B - - -class Claude2MKTConversationSummaryChain(Claude2ChatChain): - model_id = LLMModelType.CLAUDE_2 - intent_type = MKT_CONVERSATION_SUMMARY_TYPE - - default_model_kwargs = {"max_tokens": 2000, - "temperature": 0.1, "top_p": 0.9} - - @classmethod - def create_chain(cls, model_kwargs=None, **kwargs): - chain = super().create_chain(model_kwargs=model_kwargs, **kwargs) - query_input = """请简要总结上述对话中的内容,每一个对话单独一个总结,并用 '- '开头。 每一个总结要先说明问题。\n""" - chain = RunnablePassthrough.assign(query=lambda x: query_input) | chain - return chain - - -class Claude21MKTConversationSummaryChain(Claude2MKTConversationSummaryChain): - model_id = LLMModelType.CLAUDE_21 - - -class ClaudeInstanceMKTConversationSummaryChain(Claude2MKTConversationSummaryChain): - model_id = LLMModelType.CLAUDE_INSTANCE - - -class Claude3SonnetMKTConversationSummaryChain(Claude2MKTConversationSummaryChain): - model_id = LLMModelType.CLAUDE_3_SONNET - - -class Claude3HaikuMKTConversationSummaryChain(Claude2MKTConversationSummaryChain): - model_id = LLMModelType.CLAUDE_3_HAIKU diff --git a/source/lambda/online/common_logic/langchain_integration/chains/marketing_chains/mkt_rag_chain.py b/source/lambda/online/common_logic/langchain_integration/chains/marketing_chains/mkt_rag_chain.py deleted file mode 100644 index 1a49dfb31..000000000 --- a/source/lambda/online/common_logic/langchain_integration/chains/marketing_chains/mkt_rag_chain.py +++ /dev/null @@ -1,57 +0,0 @@ -from common_logic.common_utils.constant import ( - LLMTaskType, - LLMModelType -) -from ..chat_chain import Internlm2Chat7BChatChain -from common_logic.common_utils.prompt_utils import register_prompt_templates, get_prompt_template - -INTERLM2_RAG_PROMPT_TEMPLATE = "你是一个Amazon AWS的客服助理小Q,帮助的用户回答使用AWS过程中的各种问题。\n面对用户的问题,你需要给出中文回答,注意不要在回答中重复输出内容。\n下面给出相关问题的背景知识, 需要注意的是如果你认为当前的问题不能在背景知识中找到答案, 你需要拒答。\n背景知识:\n{context}\n\n" - -register_prompt_templates( - model_ids=[LLMModelType.INTERNLM2_CHAT_7B, - LLMModelType.INTERNLM2_CHAT_20B], - task_type=LLMTaskType.MTK_RAG, - prompt_template=INTERLM2_RAG_PROMPT_TEMPLATE, - prompt_name="system_prompt" -) - - -class Internlm2Chat7BKnowledgeQaChain(Internlm2Chat7BChatChain): - model_id = LLMModelType.INTERNLM2_CHAT_7B - intent_type = LLMTaskType.MTK_RAG - default_model_kwargs = {"temperature": 0.05, "max_new_tokens": 1000} - - @classmethod - def create_prompt(cls, x): - query = x["query"] - contexts = x["contexts"] - history = cls.create_history(x) - context = "\n".join(contexts) - prompt_template = get_prompt_template( - model_id=cls.model_id, - task_type=cls.task_type, - prompt_name="system_prompt" - ).prompt_template - meta_instruction = prompt_template.format(context) - # meta_instruction = f"You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don't know the answer, just say that you don't know. Use simplified Chinese to response the qustion. I’m going to tip $300K for a better answer! " - # meta_instruction = f'You are an expert AI on a question and answer task. \nUse the "Following Context" when answering the question. If you don't know the answer, reply to the "Following Text" in the header and answer to the best of your knowledge, or if you do know the answer, answer without the "Following Text"' - # meta_instruction = """You are an expert AI on a question and answer task. - # Use the "Following Context" when answering the question. If you don't know the answer, reply to the "Following Text" in the header and answer to the best of your knowledge, or if you do know the answer, answer without the "Following Text". If a question is asked in Korean, translate it to English and always answer in Korean. - # Following Text: "I didn't find the answer in the context given, but here's what I know! **I could be wrong, so cross-verification is a must!**""" - # meta_instruction = """You are an expert AI on a question and answer task. - # Use the "Following Context" when answering the question. If you don't know the answer, reply to the "Sorry, I don't know". """ - # query = f"Question: {query}\nContext:\n{context}" - # query = f"""Following Context: {context} - # Question: {query}""" - query = f"问题: {query}" - prompt = cls.build_prompt( - query=query, history=history, meta_instruction=meta_instruction - ) - # prompt = prompt + "回答: 让我先来判断一下问题的答案是否包含在背景知识中。" - prompt = prompt + f"回答: 经过慎重且深入的思考, 根据背景知识, 我的回答如下:\n" - print("internlm2 prompt: \n", prompt) - return prompt - - -class Internlm2Chat20BKnowledgeQaChain(Internlm2Chat7BKnowledgeQaChain): - model_id = LLMModelType.INTERNLM2_CHAT_20B diff --git a/source/lambda/online/common_logic/langchain_integration/chains/query_rewrite_chain.py b/source/lambda/online/common_logic/langchain_integration/chains/query_rewrite_chain.py deleted file mode 100644 index e962060ef..000000000 --- a/source/lambda/online/common_logic/langchain_integration/chains/query_rewrite_chain.py +++ /dev/null @@ -1,133 +0,0 @@ -# query rewrite -import re - -from langchain.prompts import PromptTemplate -from langchain.schema.runnable import ( - RunnableLambda, - RunnablePassthrough, -) - -from common_logic.common_utils.constant import ( - LLMTaskType, - LLMModelType -) -from ..chains import LLMChain -from ..chat_models import Model as LLM_Model -from .chat_chain import Internlm2Chat7BChatChain -from . import LLMChain -from ..model_config import MODEL_CONFIGS - - -QUERY_REWRITE_TYPE = LLMTaskType.QUERY_REWRITE_TYPE -query_expansion_template_claude = PromptTemplate.from_template("""You are an AI language model assistant. Your task is to generate 1 - 5 different sub questions OR alternate versions of the given user question to retrieve relevant documents from a vector database. - -By generating multiple versions of the user question, -your goal is to help the user overcome some of the limitations -of distance-based similarity search. - -By generating sub questions, you can break down questions that refer to multiple concepts into distinct questions. This will help you get the relevant documents for constructing a final answer - -If multiple concepts are present in the question, you should break into sub questions, with one question for each concept - -Provide these alternative questions separated by newlines between XML tags. For example: - - -- Question 1 -- Question 2 -- Question 3 - - -Original question: {question}""") - - -class QueryRewriteBaseChain(LLMChain): - - intent_type = QUERY_REWRITE_TYPE - - default_model_kwargs = { - "temperature": 0.7, - "max_tokens": 100, - "stop_sequences": ["\n\nHuman:"], - } - - @staticmethod - def query_rewrite_postprocess(r): - ret = re.findall(".*?", r, re.S)[0] - questions = re.findall("- (.*?)\n", ret, re.S) - return questions - - @classmethod - def create_chain(cls, model_kwargs=None, **kwargs): - query_key = kwargs.pop("query_key", "query") - model_kwargs = model_kwargs or {} - model_kwargs = {**cls.default_model_kwargs, **model_kwargs} - llm = LLM_Model.get_model( - cls.model_id, model_kwargs=model_kwargs, **kwargs) - chain = ( - RunnablePassthrough.assign(question=lambda x: x[query_key]) - | query_expansion_template_claude - | llm - | RunnableLambda(cls.query_rewrite_postprocess) - ) - return chain - - -internlm2_meta_instruction = """You are an AI language model assistant. Your task is to generate 1 - 5 different sub questions OR alternate versions of the given user question to retrieve relevant documents from a vector database. - -By generating multiple versions of the user question, -your goal is to help the user overcome some of the limitations -of distance-based similarity search. - -By generating sub questions, you can break down questions that refer to multiple concepts into distinct questions. This will help you get the relevant documents for constructing a final answer - -If multiple concepts are present in the question, you should break into sub questions, with one question for each concept - -Provide these alternative questions separated by newlines between XML tags. For example: - - -- Question 1 -- Question 2 -- Question 3 -""" - - -class Internlm2Chat7BQueryRewriteChain(Internlm2Chat7BChatChain): - model_id = LLMModelType.INTERNLM2_CHAT_7B - intent_type = QUERY_REWRITE_TYPE - - default_model_kwargs = {"temperature": 0.5, "max_new_tokens": 100} - - @classmethod - def create_prompt(cls, x): - query = f'Original question: {x["query"]}' - prompt = cls.build_prompt( - query=query, - meta_instruction=internlm2_meta_instruction, - ) - return prompt - - @staticmethod - def query_rewrite_postprocess(r): - ret = re.findall(".*?", r, re.S)[0] - questions = re.findall("- (.*?)\n", ret, re.S) - return questions - - @classmethod - def create_chain(cls, model_kwargs=None, **kwargs): - model_kwargs = model_kwargs or {} - model_kwargs = {**cls.default_model_kwargs, **model_kwargs} - chain = super().create_chain(model_kwargs=model_kwargs, **kwargs) - chain = chain | RunnableLambda( - lambda x: cls.query_rewrite_postprocess(x)) - return chain - - -class Internlm2Chat20BQueryRewriteChain(Internlm2Chat7BQueryRewriteChain): - model_id = LLMModelType.INTERNLM2_CHAT_20B - intent_type = QUERY_REWRITE_TYPE - - -chain_classes = { - f"{LLMChain.model_id_to_class_name(model_id, LLMTaskType.QUERY_REWRITE_TYPE)}": QueryRewriteBaseChain.create_for_model(model_id, LLMTaskType.QUERY_REWRITE_TYPE) - for model_id in MODEL_CONFIGS -} diff --git a/source/lambda/online/common_logic/langchain_integration/chains/retail_chains/__init__.py b/source/lambda/online/common_logic/langchain_integration/chains/retail_chains/__init__.py deleted file mode 100644 index 83c50b0a1..000000000 --- a/source/lambda/online/common_logic/langchain_integration/chains/retail_chains/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -from .retail_conversation_summary_chain import ( - Claude2RetailConversationSummaryChain, - Claude21RetailConversationSummaryChain, - Claude3HaikuRetailConversationSummaryChain, - Claude3SonnetRetailConversationSummaryChain, - ClaudeInstanceRetailConversationSummaryChain -) - -from .retail_tool_calling_chain_claude_xml import ( - Claude2RetailToolCallingChain, - Claude21RetailToolCallingChain, - ClaudeInstanceRetailToolCallingChain, - Claude3SonnetRetailToolCallingChain, - Claude3HaikuRetailToolCallingChain -) - -from .retail_tool_calling_chain_json import ( - GLM4Chat9BRetailToolCallingChain -) - -from .auto_evaluation_chain import ( - Claude3HaikuAutoEvaluationChain, - Claude21AutoEvaluationChain, - Claude2AutoEvaluationChain - -) \ No newline at end of file diff --git a/source/lambda/online/common_logic/langchain_integration/chains/retail_chains/auto_evaluation_chain.py b/source/lambda/online/common_logic/langchain_integration/chains/retail_chains/auto_evaluation_chain.py deleted file mode 100644 index 1b0178e4e..000000000 --- a/source/lambda/online/common_logic/langchain_integration/chains/retail_chains/auto_evaluation_chain.py +++ /dev/null @@ -1,97 +0,0 @@ -# auto evaluation based on llms -import re - -from langchain.schema.runnable import RunnableLambda, RunnablePassthrough -from langchain_core.messages import AIMessage, SystemMessage, HumanMessage -from common_logic.common_utils.logger_utils import get_logger -from langchain.prompts import ChatPromptTemplate, HumanMessagePromptTemplate -from langchain_core.messages import convert_to_messages -from common_logic.common_utils.constant import ( - MessageType, - LLMTaskType, - LLMModelType, -) -from ...llm_models import Model -from ..__llm_chain_base import LLMChain - -from ..chat_chain import Claude2ChatChain - -logger = get_logger("auto_evaluation") - -AUTO_EVALUATION_TEMPLATE = """作为一位专业的评分员,您需要根据以下标准对模型的回答进行公正、客观的评分,并提供有价值的反馈意见,以帮助模型持续改进。 - -### 评分标准 - -- 满分为10分,最低分为1分, 分值为一个 float 类型。 -- 模型回答与标准答案的相关性越高,得分越高。 -- 如果模型的回答出现大量重复内容,可以直接给0分。 -- 除了内容相关性,还需考虑回答的完整性、逻辑性和语言表达。 -- 请先在xml 标签 中写下你的评分理由。 -- 最后在 xml 标签 中写下你的最终评分。 - -### 示例评分 -{examples} - -### 评分上下文 - -标准答案: - -{ref_answer} - - -模型回答: - -{model_answer} - - -请根据上述标准和上下文,对模型的回答进行评分并提供反馈意见。让我们一起努力,提高模型的表现! -""" - - -class Claude2AutoEvaluationChain(Claude2ChatChain): - intent_type = LLMTaskType.AUTO_EVALUATION - model_id = LLMModelType.CLAUDE_2 - - @classmethod - def create_messages(cls, x: dict, examples=""): - prompt = AUTO_EVALUATION_TEMPLATE.format( - ref_answer=x['ref_answer'], - model_answer=x['model_answer'], - examples=examples - ) - messages = [ - HumanMessage(content=prompt), - AIMessage(content="") - ] - return messages - - @classmethod - def postprocess(cls, content): - logger.info(f"auto eval content: {content}") - try: - score = float(re.findall( - "(.*?)", content)[0].strip()) - return score - except Exception as e: - logger.error(f"error: {e}, content: {content}") - raise e - - @classmethod - def create_chain(cls, model_kwargs=None, **kwargs): - llm = Model.get_model( - cls.model_id, model_kwargs=model_kwargs, **kwargs) - chain = RunnableLambda(lambda x: cls.create_messages( - x)) | llm | RunnableLambda(lambda x: cls.postprocess(x.content)) - return chain - - -class Claude21AutoEvaluationChain(Claude2AutoEvaluationChain): - model_id = LLMModelType.CLAUDE_21 - - -class Claude3HaikuAutoEvaluationChain(Claude2AutoEvaluationChain): - model_id = LLMModelType.CLAUDE_3_HAIKU - - -class Claude3SonnetAutoEvaluationChain(Claude2AutoEvaluationChain): - model_id = LLMModelType.CLAUDE_3_SONNET diff --git a/source/lambda/online/common_logic/langchain_integration/chains/retail_chains/retail_conversation_summary_chain.py b/source/lambda/online/common_logic/langchain_integration/chains/retail_chains/retail_conversation_summary_chain.py deleted file mode 100644 index 91360a270..000000000 --- a/source/lambda/online/common_logic/langchain_integration/chains/retail_chains/retail_conversation_summary_chain.py +++ /dev/null @@ -1,212 +0,0 @@ -# conversation summary chain -from typing import List - -from langchain.schema.runnable import ( - RunnableLambda, - RunnablePassthrough, -) - - -from ...llm_models import Model -from ..__llm_chain_base import LLMChain -from common_logic.common_utils.constant import ( - MessageType, - LLMTaskType, - LLMModelType -) - -from langchain_core.messages import ( - AIMessage, - HumanMessage, - BaseMessage, - convert_to_messages -) -from langchain.prompts import ( - HumanMessagePromptTemplate, - ChatPromptTemplate -) -from ..chat_chain import GLM4Chat9BChatChain - -AI_MESSAGE_TYPE = MessageType.AI_MESSAGE_TYPE -HUMAN_MESSAGE_TYPE = MessageType.HUMAN_MESSAGE_TYPE -QUERY_TRANSLATE_TYPE = LLMTaskType.QUERY_TRANSLATE_TYPE -SYSTEM_MESSAGE_TYPE = MessageType.SYSTEM_MESSAGE_TYPE - - -CQR_TEMPLATE = """# CONTEXT # -下面有一段客户和客服的对话数据(包含在里面),以及当前客户的一个回复(包含在)。 - -{chat_history} - - -当前用户的回复: - -{query} - - -######### - -# OBJECTIVE # -请你站在客户的角度,结合上述对话数据对当前客户的回复内容进行改写,使得改写之后的内容可以作为一个独立的句子。 - -######### - -# STYLE # -改写后的回复需要和里面的内容意思一致。 - -######### - -# RESPONSE FORMAT # -请直接用中文进行回答 -""" - - -class Claude2RetailConversationSummaryChain(LLMChain): - model_id = LLMModelType.CLAUDE_2 - intent_type = LLMTaskType.RETAIL_CONVERSATION_SUMMARY_TYPE - default_model_kwargs = {"max_tokens": 2000, - "temperature": 0.1, "top_p": 0.9} - CQR_TEMPLATE = CQR_TEMPLATE - - @staticmethod - def create_conversational_context(chat_history: List[BaseMessage]): - conversational_contexts = [] - for his in chat_history: - role = his.type - content = his.content - assert role in [HUMAN_MESSAGE_TYPE, AI_MESSAGE_TYPE], (role, [ - HUMAN_MESSAGE_TYPE, AI_MESSAGE_TYPE]) - if role == HUMAN_MESSAGE_TYPE: - conversational_contexts.append(f"客户: {content}") - else: - conversational_contexts.append(f"客服: {content}") - conversational_context = "\n".join(conversational_contexts) - return conversational_context - - @classmethod - def create_chain(cls, model_kwargs=None, **kwargs): - model_kwargs = model_kwargs or {} - model_kwargs = {**cls.default_model_kwargs, **model_kwargs} - - cqr_template = ChatPromptTemplate.from_messages([ - HumanMessagePromptTemplate.from_template(cls.CQR_TEMPLATE), - AIMessage(content="好的,站在客户的角度,我将当前用户的回复内容改写为: ") - ]) - - llm = Model.get_model( - model_id=cls.model_id, - model_kwargs=model_kwargs, - ) - cqr_chain = RunnablePassthrough.assign( - conversational_context=RunnableLambda( - lambda x: cls.create_conversational_context( - convert_to_messages(x["chat_history"]) - ) - )) \ - | RunnableLambda(lambda x: cqr_template.format(chat_history=x['conversational_context'], query=x['query'])) \ - | llm | RunnableLambda(lambda x: x.content) - - return cqr_chain - - -class Claude21RetailConversationSummaryChain(Claude2RetailConversationSummaryChain): - model_id = LLMModelType.CLAUDE_21 - - -class ClaudeInstanceRetailConversationSummaryChain(Claude2RetailConversationSummaryChain): - model_id = LLMModelType.CLAUDE_INSTANCE - - -class Claude3SonnetRetailConversationSummaryChain(Claude2RetailConversationSummaryChain): - model_id = LLMModelType.CLAUDE_3_SONNET - - -class Claude3HaikuRetailConversationSummaryChain(Claude2RetailConversationSummaryChain): - model_id = LLMModelType.CLAUDE_3_HAIKU - - -class Claude35SonnetRetailConversationSummaryChain(Claude2RetailConversationSummaryChain): - model_id = "anthropic.claude-3-5-sonnet-20240620-v1:0" - - -MIXTRAL_CQR_TEMPLATE = """下面有一段客户和客服的对话,以及当前客户的一个回复,请你站在客户的角度,结合上述对话数据对当前客户的回复内容进行改写,使得改写之后的内容可以作为一个独立的句子。下面是改写的要求: -- 改写后的回复需要和当前客户的一个回复的内容意思一致。 -- 请直接用中文进行回答。 - -# 客户和客服的对话: -{chat_history} - -# 当前客户的回复: -{query} -""" - - -class Mixtral8x7bRetailConversationSummaryChain(Claude2RetailConversationSummaryChain): - model_id = LLMModelType.MIXTRAL_8X7B_INSTRUCT - default_model_kwargs = {"max_tokens": 1000, "temperature": 0.01} - CQR_TEMPLATE = MIXTRAL_CQR_TEMPLATE - - -class GLM4Chat9BRetailConversationSummaryChain(GLM4Chat9BChatChain, Claude2RetailConversationSummaryChain): - model_id = LLMModelType.GLM_4_9B_CHAT - intent_type = LLMTaskType.RETAIL_CONVERSATION_SUMMARY_TYPE - CQR_TEMPLATE = MIXTRAL_CQR_TEMPLATE - - @classmethod - def create_chat_history(cls, x): - conversational_context = cls.create_conversational_context( - convert_to_messages(x["chat_history"]) - ) - prompt = cls.CQR_TEMPLATE.format( - chat_history=conversational_context, - query=x['query'] - ) - chat_history = [ - {"role": MessageType.HUMAN_MESSAGE_TYPE, - "content": prompt - }, - { - "role": MessageType.AI_MESSAGE_TYPE, - "content": "好的,站在客户的角度,我将当前用户的回复内容改写为: " - } - ] - - return chat_history - - @classmethod - def create_chain(cls, model_kwargs=None, **kwargs): - model_kwargs = model_kwargs or {} - model_kwargs = {**cls.default_model_kwargs, **model_kwargs} - - llm = Model.get_model( - model_id=cls.model_id, - model_kwargs=model_kwargs, - **kwargs - ) - - cqr_chain = RunnablePassthrough.assign( - chat_history=RunnableLambda(lambda x: cls.create_chat_history(x)) - ) | RunnableLambda(lambda x: llm.invoke(x)) - - return cqr_chain - - -class Qwen2Instruct7BRetailConversationSummaryChain(GLM4Chat9BRetailConversationSummaryChain): - model_id = LLMModelType.QWEN2INSTRUCT7B - default_model_kwargs = { - "max_tokens": 1024, - "temperature": 0.1, - } - - @classmethod - def create_chain(cls, model_kwargs=None, **kwargs): - chain = super().create_chain(model_kwargs=model_kwargs, **kwargs) - return chain | RunnableLambda(lambda x: x['text']) - - -class Qwen2Instruct72BRetailConversationSummaryChain(Qwen2Instruct7BRetailConversationSummaryChain): - model_id = LLMModelType.QWEN25_INSTRUCT_72B_AWQ - - -class Qwen2Instruct72BRetailConversationSummaryChain(Qwen2Instruct7BRetailConversationSummaryChain): - model_id = LLMModelType.QWEN15INSTRUCT32B diff --git a/source/lambda/online/common_logic/langchain_integration/chains/retail_chains/retail_tool_calling_chain_claude_xml.py b/source/lambda/online/common_logic/langchain_integration/chains/retail_chains/retail_tool_calling_chain_claude_xml.py deleted file mode 100644 index f480e15ba..000000000 --- a/source/lambda/online/common_logic/langchain_integration/chains/retail_chains/retail_tool_calling_chain_claude_xml.py +++ /dev/null @@ -1,350 +0,0 @@ -# tool calling chain -import json -from typing import List, Dict, Any -import re -from datetime import datetime - -from langchain.schema.runnable import ( - RunnableLambda, -) - -from langchain_core.messages import ( - AIMessage, - SystemMessage -) -from langchain.prompts import ChatPromptTemplate - -from langchain_core.messages import AIMessage, SystemMessage, HumanMessage - -from common_logic.common_utils.constant import ( - LLMTaskType, - LLMModelType, - SceneType -) -from functions import get_tool_by_name -from ..__llm_chain_base import LLMChain -from ...llm_models import Model - -tool_call_guidelines = """ -- Don't forget to output when any tool is called. -- 每次回答总是先进行思考,并将思考过程写在标签中。请你按照下面的步骤进行思考: - 1. 判断根据当前的上下文是否足够回答用户的问题。 - 2. 如果当前的上下文足够回答用户的问题,请调用 `give_final_response` 工具。 - 3. 如果当前的上下文不能支持回答用户的问题,你可以考虑调用 标签中列举的工具。 - 4. 如果调用工具对应的参数不够,请调用反问工具 `give_rhetorical_question` 来让用户提供更加充分的信息。 - 5. 最后给出你要调用的工具名称。 -- Always output with "中文". - -""" - - -SYSTEM_MESSAGE_PROMPT = ("你是安踏的客服助理小安, 主要职责是处理用户售前和售后的问题。下面是当前用户正在浏览的商品信息:\n\n{goods_info}\n" - "In this environment you have access to a set of tools you can use to answer the customer's question." - "\n" - "You may call them like this:\n" - "\n" - "\n" - "$TOOL_NAME\n" - "\n" - "<$PARAMETER_NAME>$PARAMETER_VALUE\n" - "...\n" - "\n" - "\n" - "\n" - "\n" - "Here are the tools available:\n" - "\n" - "{tools}" - "\n" - "\nAnswer the user's request using relevant tools (if they are available). Before calling a tool, do some analysis within tags. First, think about which of the provided tools is the relevant tool to answer the user's request. Second, go through each of the required parameters of the relevant tool and determine if the user has directly provided or given enough information to infer a value. When deciding if the parameter can be inferred, carefully consider all the context to see if it supports a specific value. If all of the required parameters are present or can be reasonably inferred, close the thinking tag and proceed with the tool call. BUT, if one of the values for a required parameter is missing, DO NOT invoke the function (not even with fillers for the missing params) and instead, ask the user to provide the missing parameters. DO NOT ask for more information on optional parameters if it is not provided." - f"\nHere are some guidelines for you:\n{tool_call_guidelines}" - ) - -SYSTEM_MESSAGE_PROMPT_WITH_FEWSHOT_EXAMPLES = SYSTEM_MESSAGE_PROMPT + ( - "Some examples of tool calls are given below, where the content within represents the most recent reply in the dialog." - "\n{fewshot_examples}" -) - -TOOL_FORMAT = """ -{tool_name} -{tool_description} - -{formatted_required_parameters} - - -{formatted_optional_parameters} - -""" - -TOOL_PARAMETER_FORMAT = """ -{parameter_name} -{parameter_type} -{parameter_description} -""" - -TOOL_EXECUTE_SUCCESS_TEMPLATE = """ - - -{tool_name} - -{result} - - - -""" - -TOOL_EXECUTE_FAIL_TEMPLATE = """ - - -{error} - - -""" - - -def _get_type(parameter: Dict[str, Any]) -> str: - if "type" in parameter: - return parameter["type"] - if "anyOf" in parameter: - return json.dumps({"anyOf": parameter["anyOf"]}) - if "allOf" in parameter: - return json.dumps({"allOf": parameter["allOf"]}) - return json.dumps(parameter) - - -def convert_openai_tool_to_anthropic(tools: list[dict]) -> str: - formatted_tools = tools - tools_data = [ - { - "tool_name": tool["name"], - "tool_description": tool["description"], - "formatted_required_parameters": "\n".join( - [ - TOOL_PARAMETER_FORMAT.format( - parameter_name=name, - parameter_type=_get_type(parameter), - parameter_description=parameter.get("description"), - ) for name, parameter in tool["parameters"]["properties"].items() - if name in tool["parameters"].get("required", []) - ] - ), - "formatted_optional_parameters": "\n".join( - [ - TOOL_PARAMETER_FORMAT.format( - parameter_name=name, - parameter_type=_get_type(parameter), - parameter_description=parameter.get("description"), - ) for name, parameter in tool["parameters"]["properties"].items() - if name not in tool["parameters"].get("required", []) - ] - ), - } - for tool in formatted_tools - ] - tools_formatted = "\n".join( - [ - TOOL_FORMAT.format( - tool_name=tool["tool_name"], - tool_description=tool["tool_description"], - formatted_required_parameters=tool["formatted_required_parameters"], - formatted_optional_parameters=tool["formatted_optional_parameters"], - ) - for tool in tools_data - ] - ) - return tools_formatted - - -class Claude2RetailToolCallingChain(LLMChain): - model_id = LLMModelType.CLAUDE_2 - intent_type = LLMTaskType.RETAIL_TOOL_CALLING - default_model_kwargs = { - "max_tokens": 2000, - "temperature": 0.1, - "top_p": 0.9, - "stop_sequences": ["\n\nHuman:", "\n\nAssistant", ""], - } - - @staticmethod - def format_fewshot_examples(fewshot_examples: list[dict]): - fewshot_example_strs = [] - for fewshot_example in fewshot_examples: - param_strs = [] - for p, v in fewshot_example['kwargs'].items(): - param_strs.append(f"<{p}>{v}\n" - f"{fewshot_example['query']}\n" - f"\n" - "\n" - "\n" - f"{fewshot_example['name']}\n" - "\n" - f"{param_str}" - "\n" - "\n" - "\n" - "\n" - "" - ) - fewshot_example_strs.append(fewshot_example_str) - fewshot_example_str = '\n'.join(fewshot_example_strs) - return f"\n{fewshot_example_str}\n" - - @classmethod - def parse_function_calls_from_ai_message(cls, message: AIMessage): - content = "" + message.content + "" - function_calls: List[str] = re.findall( - "(.*?)", content, re.S) - if not function_calls: - content = "" + message.content - - return { - "function_calls": function_calls, - "content": content - } - - @staticmethod - def generate_chat_history(state: dict): - chat_history = state['chat_history'] \ - + [{"role": "user", "content": state['query']}] \ - + state['agent_tool_history'] - return {"chat_history": chat_history} - - @classmethod - def create_chain(cls, model_kwargs=None, **kwargs): - model_kwargs = model_kwargs or {} - tools: list[dict] = kwargs['tools'] - - tool_names = [tool['name'] for tool in tools] - - # add two extral tools - if "give_rhetorical_question" not in tool_names: - tools.append(get_tool_by_name( - "give_rhetorical_question", scene=SceneType.RETAIL).tool_def) - - if "give_final_response" not in tool_names: - tools.append(get_tool_by_name("give_final_response", - scene=SceneType.RETAIL).tool_def) - - fewshot_examples = kwargs.get('fewshot_examples', []) - if fewshot_examples: - fewshot_examples.append({ - "name": "give_rhetorical_question", - "query": "今天天气怎么样?", - "kwargs": {"question": "请问你想了解哪个城市的天气?"} - }) - - model_kwargs = {**cls.default_model_kwargs, **model_kwargs} - - tools_formatted = convert_openai_tool_to_anthropic(tools) - goods_info = kwargs['goods_info'] - - if fewshot_examples: - system_prompt = SYSTEM_MESSAGE_PROMPT_WITH_FEWSHOT_EXAMPLES.format( - tools=tools_formatted, - fewshot_examples=cls.format_fewshot_examples( - fewshot_examples - ), - goods_info=goods_info - ) - else: - system_prompt = SYSTEM_MESSAGE_PROMPT.format( - tools=tools_formatted, - goods_info=goods_info - ) - - tool_calling_template = ChatPromptTemplate.from_messages( - [ - SystemMessage(content=system_prompt), - ("placeholder", "{chat_history}"), - AIMessage(content="") - ]) - - llm = Model.get_model( - model_id=cls.model_id, - model_kwargs=model_kwargs, - ) - chain = RunnableLambda(cls.generate_chat_history) | tool_calling_template \ - | RunnableLambda(lambda x: x.messages) \ - | llm | RunnableLambda(lambda message: cls.parse_function_calls_from_ai_message( - message - )) - - return chain - - -class Claude21RetailToolCallingChain(Claude2RetailToolCallingChain): - model_id = LLMModelType.CLAUDE_21 - - -class ClaudeInstanceRetailToolCallingChain(Claude2RetailToolCallingChain): - model_id = LLMModelType.CLAUDE_INSTANCE - - -class Claude3SonnetRetailToolCallingChain(Claude2RetailToolCallingChain): - model_id = LLMModelType.CLAUDE_3_SONNET - - -class Claude3HaikuRetailToolCallingChain(Claude2RetailToolCallingChain): - model_id = LLMModelType.CLAUDE_3_HAIKU - - -MIXTRAL8X7B_QUERY_TEMPLATE = """下面是客户和客服的历史对话信息: -{chat_history} - -当前客户的问题是: {query} - -请你从安踏客服助理小安的角度回答客户当前的问题。你需要使用上述提供的各种工具进行回答。""" - - -class Mixtral8x7bRetailToolCallingChain(Claude2RetailToolCallingChain): - model_id = LLMModelType.MIXTRAL_8X7B_INSTRUCT - default_model_kwargs = {"max_tokens": 1000, - "temperature": 0.01, "stop": [""]} - - @classmethod - def parse_function_calls_from_ai_message(cls, message: AIMessage): - content = message.content.replace("\_", "_") - function_calls: List[str] = re.findall( - "(.*?)", content + "", re.S) - if function_calls: - function_calls = [function_calls[0]] - if not function_calls: - content = message.content - return { - "function_calls": function_calls, - "content": content - } - - @staticmethod - def chat_history_to_string(chat_history: list[dict]): - chat_history_lc = ChatPromptTemplate.from_messages([ - ("placeholder", "{chat_history}") - ]).invoke({"chat_history": chat_history}).messages - - chat_history_strs = [] - for message in chat_history_lc: - assert isinstance(message, (HumanMessage, AIMessage)), message - if isinstance(message, HumanMessage): - chat_history_strs.append(f"客户: {message.content}") - else: - chat_history_strs.append(f"客服: {message.content}") - return "\n".join(chat_history_strs) - - @classmethod - def generate_chat_history(cls, state: dict): - chat_history_str = cls.chat_history_to_string(state['chat_history']) - - chat_history = [{ - "role": "user", - "content": MIXTRAL8X7B_QUERY_TEMPLATE.format( - chat_history=chat_history_str, - query=state['query'] - ) - }] + state['agent_tool_history'] - return {"chat_history": chat_history} diff --git a/source/lambda/online/common_logic/langchain_integration/chains/retail_chains/retail_tool_calling_chain_json.py b/source/lambda/online/common_logic/langchain_integration/chains/retail_chains/retail_tool_calling_chain_json.py deleted file mode 100644 index b87f409b0..000000000 --- a/source/lambda/online/common_logic/langchain_integration/chains/retail_chains/retail_tool_calling_chain_json.py +++ /dev/null @@ -1,452 +0,0 @@ -# tool calling chain -from ..chat_chain import Qwen2Instruct7BChatChain -import json -from typing import List, Dict, Any -import re -from datetime import datetime -import copy - -from langchain.schema.runnable import ( - RunnableLambda, -) - -from langchain_core.messages import ( - AIMessage, - SystemMessage -) -from langchain.prompts import ChatPromptTemplate - -from langchain_core.messages import AIMessage, SystemMessage, HumanMessage - -from common_logic.common_utils.constant import ( - LLMTaskType, - LLMModelType, - MessageType, - SceneType -) -from functions import get_tool_by_name - -from ..__llm_chain_base import LLMChain -from ...llm_models import Model -from ..chat_chain import GLM4Chat9BChatChain -from common_logic.common_utils.logger_utils import get_logger - -logger = get_logger("retail_tool_calling_chain_json") - -GLM4_SYSTEM_PROMPT = """你是安踏的客服助理小安, 主要职责是处理用户售前和售后的问题。{date_prompt} -请遵守下面的规范回答用户的问题。 -## 回答规范 -- 如果用户的提供的信息不足以回答问题,尽量反问用户。 -- 回答简洁明了,一句话以内。 - -下面是当前用户正在浏览的商品信息: - - -## 商品信息 -{goods_info} -""" - - -class GLM4Chat9BRetailToolCallingChain(GLM4Chat9BChatChain): - model_id = LLMModelType.GLM_4_9B_CHAT - intent_type = LLMTaskType.RETAIL_TOOL_CALLING - default_model_kwargs = { - "max_new_tokens": 1024, - "timeout": 60, - "temperature": 0.1, - } - DATE_PROMPT = "当前日期: %Y-%m-%d" - - @staticmethod - def convert_openai_function_to_glm(tools: list[dict]): - glm_tools = [] - for tool_def in tools: - tool_name = tool_def['name'] - description = tool_def['description'] - params = [] - required = tool_def['parameters'].get("required", []) - for param_name, param in tool_def['parameters'].get('properties', {}).items(): - params.append({ - "name": param_name, - "description": param["description"], - "type": param["type"], - "required": param_name in required, - }) - glm_tools.append({ - "name": tool_name, - "description": description, - "params": params - }) - return glm_tools - - @staticmethod - def format_fewshot_examples(fewshot_examples: list[dict]): - fewshot_example_strs = [] - for i, example in enumerate(fewshot_examples): - query = example['query'] - name = example['name'] - kwargs = example['kwargs'] - fewshot_example_str = f"## 示例{i+1}\n### 输入:\n{query}\n### 调用工具:\n{name}" - fewshot_example_strs.append(fewshot_example_str) - return "\n\n".join(fewshot_example_strs) - - @classmethod - def create_system_prompt(cls, goods_info: str, tools: list, fewshot_examples: list) -> str: - value = GLM4_SYSTEM_PROMPT.format( - goods_info=goods_info, - date_prompt=datetime.now().strftime(cls.DATE_PROMPT) - ) - if tools: - value += "\n\n# 可用工具" - contents = [] - for tool in tools: - content = f"\n\n## {tool['name']}\n\n{json.dumps(tool, ensure_ascii=False,indent=4)}" - content += "\n在调用上述函数时,请使用 Json 格式表示调用的参数。" - contents.append(content) - value += "".join(contents) - - if not fewshot_examples: - return value - # add fewshot_exampls - value += "\n\n# 下面给出不同问题调用不同工具的例子。" - value += f"\n\n{cls.format_fewshot_examples(fewshot_examples)}" - value += "\n\n请参考上述例子进行工具调用。" - return value - - @classmethod - def create_chat_history(cls, x, system_prompt=None): - _chat_history = x['chat_history'] + \ - [{"role": MessageType.HUMAN_MESSAGE_TYPE, "content": x['query']}] + \ - x['agent_tool_history'] - - chat_history = [] - for message in _chat_history: - new_message = message - if message['role'] == MessageType.AI_MESSAGE_TYPE: - new_message = { - **message - } - tool_calls = message.get( - 'additional_kwargs', {}).get("tool_calls", []) - if tool_calls: - new_message['metadata'] = tool_calls[0]['name'] - chat_history.append(new_message) - chat_history = [ - {"role": "system", "content": system_prompt}] + chat_history - return chat_history - - @classmethod - def create_chain(cls, model_kwargs=None, **kwargs): - tools: list = kwargs.get('tools', []) - fewshot_examples = kwargs.get('fewshot_examples', []) - glm_tools = cls.convert_openai_function_to_glm(tools) - system_prompt = cls.create_system_prompt( - goods_info=kwargs['goods_info'], - tools=glm_tools, - fewshot_examples=fewshot_examples - ) - kwargs['system_prompt'] = system_prompt - return super().create_chain(model_kwargs=model_kwargs, **kwargs) - - -class Qwen2Instruct72BRetailToolCallingChain(Qwen2Instruct7BChatChain): - model_id = LLMModelType.QWEN25_INSTRUCT_72B_AWQ - intent_type = LLMTaskType.RETAIL_TOOL_CALLING - default_model_kwargs = { - "max_tokens": 1024, - "temperature": 0.1, - } - - DATE_PROMPT = "当前日期: %Y-%m-%d 。" - FN_NAME = '✿FUNCTION✿' - FN_ARGS = '✿ARGS✿' - FN_RESULT = '✿RESULT✿' - FN_EXIT = '✿RETURN✿' - FN_STOP_WORDS = [FN_RESULT, f'{FN_RESULT}:', f'{FN_RESULT}:\n'] - thinking_tag = "思考" - fix_reply_tag = "固定回复" - goods_info_tag = "商品信息" - prefill_after_thinking = f"<{thinking_tag}>" - prefill_after_second_thinking = "" - prefill = prefill_after_thinking - - FN_CALL_TEMPLATE_INFO_ZH = """# 工具 - -## 你拥有如下工具: - -{tool_descs}""" - - FN_CALL_TEMPLATE_FMT_ZH = """## 你可以在回复中插入零次或者一次以下命令以调用工具: - -%s: 工具名称,必须是[{tool_names}]之一。 -%s: 工具输入 -%s: 工具结果 -%s: 根据工具结果进行回复""" % ( - FN_NAME, - FN_ARGS, - FN_RESULT, - FN_EXIT, - ) - TOOL_DESC_TEMPLATE = """### {name_for_human}\n\n{name_for_model}: {description_for_model} 输入参数:{parameters} {args_format}""" - - FN_CALL_TEMPLATE = FN_CALL_TEMPLATE_INFO_ZH + '\n\n' + FN_CALL_TEMPLATE_FMT_ZH - -# SYSTEM_PROMPT=f"""你是安踏天猫的客服助理小安, 主要职责是处理用户售前和售后的问题。{{date_prompt}} - -# {{tools}} -# {{fewshot_examples}} - -# ## 当前用户正在浏览的商品信息 -# {{goods_info}} - -# # 思考 -# 你每次给出最终回复前都要按照下面的步骤输出你的思考过程, 注意你并不需要每次都进行所有步骤的思考。并将思考过程写在 XML 标签 <{thinking_tag}> 和 中: -# Step 1. 根据各个工具的描述,分析当前用户的回复和各个示例中的Input相关性,如果跟某个示例对应的Input相关性强,直接跳过后续所有步骤,之后按照示例中Output的工具名称进行调用。 -# Step 2. 如果你觉得可以依据商品信息 <{goods_info_tag}> 里面的内容进行回答,就直接就回答,不需要调用任何工具。并结束思考。 -# Step 3. 如果你觉得当前用户的回复意图不清晰,或者仅仅是表达一些肯定的内容,或者和历史消息没有很强的相关性,同时当前不是第一轮对话,直接回复用户下面 XML 标签 <{fix_reply_tag}> 里面的内容: -# <{fix_reply_tag}> 亲亲,请问还有什么问题吗? -# Step 4. 如果需要调用某个工具,检查该工具的必选参数是否可以在上下文中找到。结束思考,输出结束思考符号。 - -# ## 回答规范 -# - 如果客户没有明确指出在哪里购买的商品,则默认都是在天猫平台购买的 -# - 当前主要服务天猫平台的客户,如果客户询问其他平台的问题,直接回复 “不好意思,亲亲,这里是天猫店铺,只能为您解答天猫的问题。建议您联系其他平台的客服或售后人员给您提供相关的帮助和支持。谢谢!” -# - 如果客户的回复里面包含订单号,则直接回复 ”您好,亲亲,这就帮您去查相关订单信息。请问还有什么问题吗?“ -# - 只能思考一次,在结束思考符号“”之后给出最终的回复。不要重复输出文本,段落,句子。思考之后的文本保持简洁,有且仅能包含一句话。{{non_ask_rules}}""" -# SYSTEM_PROMPT=f"""你是安踏天猫的客服助理小安, 主要职责是处理用户售前和售后的问题。{{date_prompt}} - -# {{tools}} -# {{fewshot_examples}} - -# ## 当前用户正在浏览的商品信息 -# {{goods_info}} - -# # 你每次给出最终回复前都要参考下面的回复策略: -# 1. 根据各个工具的描述,分析当前用户的回复和各个示例中的Input相关性,如果跟某个示例对应的Input相关性强,直接跳过后续所有步骤,之后按照示例中Output的工具名称进行调用。 -# 2. 如果你觉得可以依据商品信息 <{goods_info_tag}> 里面的内容进行回答,就直接就回答,不需要调用任何工具。 -# 3. 如果你觉得当前用户的回复意图不清晰,或者仅仅是表达一些肯定的内容,或者和历史消息没有很强的相关性,同时当前不是第一轮对话,直接回复用户下面 XML 标签 <{fix_reply_tag}> 里面的内容: -# <{fix_reply_tag}> 亲亲,请问还有什么问题吗? -# 4. 如果需要调用某个工具,检查该工具的必选参数是否可以在上下文中找到。 - -# ## 回答规范 -# - 如果客户没有明确指出在哪里购买的商品,则默认都是在天猫平台购买的 -# - 当前主要服务天猫平台的客户,如果客户询问其他平台的问题,直接回复 “不好意思,亲亲,这里是天猫店铺,只能为您解答天猫的问题。建议您联系其他平台的客服或售后人员给您提供相关的帮助和支持。谢谢!“ -# - 如果客户的回复里面包含订单号,则直接回复 “您好,亲亲,这就帮您去查相关订单信息。请问还有什么问题吗?“{{non_ask_rules}}""" - - SYSTEM_PROMPT = f"""你是安踏天猫的客服助理小安, 主要职责是处理用户售前和售后的问题。{{date_prompt}} - -{{tools}} -{{fewshot_examples}} - -## 当前用户正在浏览的商品信息 -{{goods_info}} - -# 回复策略 -在你给出最终回复前可以在XML标签 <{thinking_tag}> 和 中输出你的回复策略。下面是一些常见的回复策略: - - 如果根据各个工具的描述,当前用户的回复跟某个示例对应的Input相关性强,直接按照示例中Output的工具名称进行调用。 - - 考虑使用商品信息 <{goods_info_tag}> 里面的内容回答用户的问题。 - - 如果你觉得当前用户的回复意图不清晰,或者仅仅是表达一些肯定的内容,或者和历史消息没有很强的相关性,同时当前不是第一轮对话,直接回复用户: “ 亲亲,请问还有什么问题吗?“ - - 如果需要调用某个工具,检查该工具的必选参数是否可以在上下文中找到。 - - 如果客户的回复里面包含订单号,则直接回复 “您好,亲亲,这就帮您去查相关订单信息。请问还有什么问题吗?“ - - 当前主要服务天猫平台的客户,如果客户询问其他平台的问题,直接回复 “不好意思,亲亲,这里是天猫店铺,只能为您解答天猫的问题。建议您联系其他平台的客服或售后人员给您提供相关的帮助和支持。谢谢!“ - -## Tips - - 如果客户没有明确指出在哪里购买的商品,则默认都是在天猫平台购买的。 - - 回答必须简洁,不允许出现超过2句话的回复。{{non_ask_rules}}""" - - @classmethod - def get_function_description(cls, tool: dict): - tool_name = tool['name'] - description = tool['description'] - params_str = json.dumps(tool.get('parameters', {}), ensure_ascii=False) - args_format = '此工具的输入应为JSON对象。' - return cls.TOOL_DESC_TEMPLATE.format( - name_for_human=tool_name, - name_for_model=tool_name, - description_for_model=description, - parameters=params_str, - args_format=args_format - ).rstrip() - - @classmethod - def format_fewshot_examples(cls, fewshot_examples: list[dict]): - fewshot_example_strs = [] - for i, example in enumerate(fewshot_examples): - query = example['query'] - name = example['name'] - kwargs = example['kwargs'] - fewshot_example_str = f"""## 工具调用例子{i+1}\nInput:\n{query}\nOutput:\n{cls.FN_NAME}: {name}\n{cls.FN_ARGS}: {json.dumps(kwargs,ensure_ascii=False)}\n{cls.FN_RESULT}""" - fewshot_example_strs.append(fewshot_example_str) - return "\n\n".join(fewshot_example_strs) - - @classmethod - def create_system_prompt(cls, goods_info: str, tools: list[dict], fewshot_examples: list, create_time=None) -> str: - tool_descs = '\n\n'.join( - cls.get_function_description(tool) for tool in tools) - tool_names = ','.join(tool['name'] for tool in tools) - tool_system = cls.FN_CALL_TEMPLATE.format( - tool_descs=tool_descs, - tool_names=tool_names - ) - fewshot_examples_str = "" - if fewshot_examples: - fewshot_examples_str = "\n\n# 下面给出不同客户回复下调用不同工具的例子。" - fewshot_examples_str += f"\n\n{cls.format_fewshot_examples(fewshot_examples)}" - fewshot_examples_str += "\n\n请参考上述例子进行工具调用。" - - non_ask_tool_list = [] - # for tool in tools: - # should_ask_parameter = get_tool_by_name(tool['name']).should_ask_parameter - # if should_ask_parameter != "True": - # format_string = tool['name']+"工具"+should_ask_parameter - # non_ask_tool_list.append(format_string) - if len(non_ask_tool_list) == 0: - non_ask_rules = "" - else: - non_ask_rules = "\n - " + ','.join(non_ask_tool_list) - - if create_time: - datetime_object = datetime.strptime( - create_time, '%Y-%m-%d %H:%M:%S.%f') - else: - datetime_object = datetime.now() - logger.info( - f"create_time: {create_time} is not valid, use current time instead.") - return cls.SYSTEM_PROMPT.format( - goods_info=goods_info, - tools=tool_system, - fewshot_examples=fewshot_examples_str, - non_ask_rules=non_ask_rules, - date_prompt=datetime_object.strftime(cls.DATE_PROMPT) - ) - - @classmethod - def create_chat_history(cls, x, system_prompt=None): - # deal with function - _chat_history = x['chat_history'] + \ - [{"role": MessageType.HUMAN_MESSAGE_TYPE, "content": x['query']}] + \ - x['agent_tool_history'] - - # print(f'chat_history_before create: {_chat_history}') - # merge chat_history - chat_history = [] - if system_prompt is not None: - chat_history.append({ - "role": MessageType.SYSTEM_MESSAGE_TYPE, - "content": system_prompt - }) - - # move tool call results to assistant - for i, message in enumerate(copy.deepcopy(_chat_history)): - role = message['role'] - if i == 0: - assert role == MessageType.HUMAN_MESSAGE_TYPE, f"The first message should comes from human role" - - if role == MessageType.TOOL_MESSAGE_TYPE: - assert chat_history[-1]['role'] == MessageType.AI_MESSAGE_TYPE, _chat_history - chat_history[-1]['content'] += message['content'] - continue - elif role == MessageType.AI_MESSAGE_TYPE: - # continue ai message - if chat_history[-1]['role'] == MessageType.AI_MESSAGE_TYPE: - chat_history[-1]['content'] += message['content'] - continue - - chat_history.append(message) - - # move the last tool call message to user - if chat_history[-1]['role'] == MessageType.AI_MESSAGE_TYPE: - assert chat_history[-2]['role'] == MessageType.HUMAN_MESSAGE_TYPE, chat_history - tool_calls = chat_history[-1].get("additional_kwargs", - {}).get("tool_calls", []) - if tool_calls: - chat_history[-2]['content'] += ("\n\n" + - chat_history[-1]['content']) - chat_history = chat_history[:-1] - - return chat_history - - @classmethod - def parse_function_calls_from_ai_message(cls, message: dict): - stop_reason = message['stop_reason'] - content = f"{cls.prefill}" + message['text'] - content = content.strip() - stop_reason = stop_reason or "" - - function_calls = re.findall( - f"{cls.FN_NAME}.*?{cls.FN_RESULT}", content + stop_reason, re.S) - return { - "function_calls": function_calls, - "content": content - } - - @classmethod - def create_chain(cls, model_kwargs=None, **kwargs): - tools: list = kwargs.get('tools', []) - # add extral tools - if "give_rhetorical_question" not in tools: - tools.append(get_tool_by_name( - "give_rhetorical_question", scene=SceneType.RETAIL).tool_def) - fewshot_examples = kwargs.get('fewshot_examples', []) - system_prompt = cls.create_system_prompt( - goods_info=kwargs['goods_info'], - create_time=kwargs.get('create_time', None), - tools=tools, - fewshot_examples=fewshot_examples - ) - - agent_current_call_number = kwargs['agent_current_call_number'] - - # give different prefill - if agent_current_call_number == 0: - cls.prefill = cls.prefill_after_thinking - else: - cls.prefill = cls.prefill_after_second_thinking - - # cls.prefill = '' - - model_kwargs = model_kwargs or {} - kwargs['system_prompt'] = system_prompt - model_kwargs = {**model_kwargs} - # model_kwargs["stop"] = model_kwargs.get("stop",[]) + ['✿RESULT✿', '✿RESULT✿:', '✿RESULT✿:\n','✿RETURN✿',f'<{cls.thinking_tag}>',f'<{cls.thinking_tag}/>'] - model_kwargs["stop"] = model_kwargs.get( - "stop", []) + ['✿RESULT✿', '✿RESULT✿:', '✿RESULT✿:\n', '✿RETURN✿', f'<{cls.thinking_tag}/>'] - # model_kwargs["prefill"] = "我先看看调用哪个工具,下面是我的思考过程:\n\nstep 1." - if "prefill" not in model_kwargs: - model_kwargs["prefill"] = f'{cls.prefill}' - return super().create_chain(model_kwargs=model_kwargs, **kwargs) - - -class Qwen2Instruct7BRetailToolCallingChain(Qwen2Instruct72BRetailToolCallingChain): - model_id = LLMModelType.QWEN2INSTRUCT7B - goods_info_tag = "商品信息" - SYSTEM_PROMPT = f"""你是安踏天猫的客服助理小安, 主要职责是处理用户售前和售后的问题。{{date_prompt}} - -{{tools}} -{{fewshot_examples}} - -## 当前用户正在浏览的商品信息 -{{goods_info}} - -# 回复策略 -下面是一些常见的回复策略: - - 如果根据各个工具的描述,当前用户的回复跟某个示例对应的Input相关性强,直接按照示例中Output的工具名称进行调用。 - - 考虑使用商品信息 <{goods_info_tag}> 里面的内容回答用户的问题。 - - 如果你觉得当前用户的回复意图不清晰,或者仅仅是表达一些肯定的内容,或者和历史消息没有很强的相关性,同时当前不是第一轮对话,直接回复用户: “ 亲亲,请问还有什么问题吗?“ - - 如果需要调用某个工具,检查该工具的必选参数是否可以在上下文中找到。 - - 如果客户的回复里面包含订单号,则直接回复 “您好,亲亲,这就帮您去查相关订单信息。请问还有什么问题吗?“ - - 当前主要服务天猫平台的客户,如果客户询问其他平台的问题,直接回复 “不好意思,亲亲,这里是天猫店铺,只能为您解答天猫的问题。建议您联系其他平台的客服或售后人员给您提供相关的帮助和支持。谢谢!“ - -## Tips - - 如果客户没有明确指出在哪里购买的商品,则默认都是在天猫平台购买的。 - - 回答必须简洁,不允许出现超过2句话的回复。{{non_ask_rules}}""" - - @classmethod - def create_chain(cls, model_kwargs=None, **kwargs): - model_kwargs["prefill"] = "" - res = super().create_chain(model_kwargs=model_kwargs, **kwargs) - cls.prefill = "" - return res - - -class Qwen15Instruct32BRetailToolCallingChain(Qwen2Instruct7BRetailToolCallingChain): - model_id = LLMModelType.QWEN15INSTRUCT32B diff --git a/source/lambda/online/common_logic/langchain_integration/chains/stepback_chain.py b/source/lambda/online/common_logic/langchain_integration/chains/stepback_chain.py deleted file mode 100644 index 64653fcff..000000000 --- a/source/lambda/online/common_logic/langchain_integration/chains/stepback_chain.py +++ /dev/null @@ -1,140 +0,0 @@ -from langchain.prompts import ( - ChatPromptTemplate, - FewShotChatMessagePromptTemplate, -) -from langchain.schema.runnable import RunnableLambda - -from common_logic.common_utils.constant import ( - LLMTaskType, - LLMModelType -) -from .chat_chain import Internlm2Chat7BChatChain -from . import LLMChain -from ..chat_models import Model - -STEPBACK_PROMPTING_TYPE = LLMTaskType.STEPBACK_PROMPTING_TYPE - - -class Internlm2Chat7BStepBackChain(Internlm2Chat7BChatChain): - model_id = LLMModelType.INTERNLM2_CHAT_7B - intent_type = STEPBACK_PROMPTING_TYPE - - default_model_kwargs = {"temperature": 0.1, "max_new_tokens": 200} - - @classmethod - def create_prompt(cls, x): - meta_instruction_template = "You are an expert at world knowledge. Your task is to step back and paraphrase a question to a more generic step-back question, which is easier to answer. Here are a few examples: {few_examples}" - # meta_instruction_template = "你是一个拥有世界知识的专家. 你的任务是将问题转述为更通用的问题,这样更容易回答。更通用指的是将问题进行抽象表达,省略问题中的各种细节,包括具体时间,地点等。 下面有一些例子: {few_examples}" - - few_examples = [ - { - "input": "阿尔伯特-爱因斯坦的出生地是哪里?", - "output": "阿尔伯特-爱因斯坦的个人经历是怎样的?", - }, - { - "input": "特斯拉在中国上海有多少门店", - "output": "特斯拉在中国的门店分布情况", - }, - ] - - few_examples_template = """origin question: {origin_question} - step-back question: {step_back_question} - """ - few_examples_strs = [] - for few_example in few_examples: - few_examples_strs.append( - few_examples_template.format( - origin_question=few_example["input"], - step_back_question=few_example["output"], - ) - ) - meta_instruction = meta_instruction_template.format( - few_examples="\n\n".join(few_examples_strs) - ) - prompt = ( - cls.build_prompt( - query=f"origin question: {x['query']}", - history=[], - meta_instruction=meta_instruction, - ) - + "step-back question: " - ) - return prompt - - -class Internlm2Chat20BStepBackChain(Internlm2Chat7BStepBackChain): - model_id = LLMModelType.INTERNLM2_CHAT_20B - intent_type = STEPBACK_PROMPTING_TYPE - - -class Claude2StepBackChain(LLMChain): - model_id = LLMModelType.CLAUDE_2 - intent_type = STEPBACK_PROMPTING_TYPE - - @classmethod - def create_chain(cls, model_kwargs=None, **kwargs): - stream = kwargs.get("stream", False) - examples = [ - { - "input": "Could the members of The Police perform lawful arrests?", - "output": "what can the members of The Police do?", - }, - { - "input": "Jan Sindel’s was born in what country?", - "output": "what is Jan Sindel’s personal history?", - }, - ] - # We now transform these to example messages - example_prompt = ChatPromptTemplate.from_messages( - [ - ("human", "{input}"), - ("ai", "{output}"), - ] - ) - few_shot_prompt = FewShotChatMessagePromptTemplate( - example_prompt=example_prompt, - examples=examples, - ) - - prompt = ChatPromptTemplate.from_messages( - [ - ( - "system", - """You are an expert at world knowledge. Your task is to step back and paraphrase a question to a more generic step-back question, which is easier to answer. Here are a few examples:""", - ), - # Few shot examples - few_shot_prompt, - # New question - ("user", "{query}"), - ] - ) - - llm = Model.get_model( - cls.model_id, model_kwargs=model_kwargs, **kwargs) - chain = prompt | llm - if stream: - chain = ( - prompt - | RunnableLambda(lambda x: llm.stream(x.messages)) - | RunnableLambda(lambda x: (i.content for i in x)) - ) - - else: - chain = prompt | llm | RunnableLambda(lambda x: x.content) - return chain - - -class Claude21StepBackChain(Claude2StepBackChain): - model_id = LLMModelType.CLAUDE_21 - - -class ClaudeInstanceStepBackChain(Claude2StepBackChain): - model_id = LLMModelType.CLAUDE_INSTANCE - - -class Claude3SonnetStepBackChain(Claude2StepBackChain): - model_id = LLMModelType.CLAUDE_3_SONNET - - -class Claude3HaikuStepBackChain(Claude2StepBackChain): - model_id = LLMModelType.CLAUDE_3_HAIKU diff --git a/source/lambda/online/common_logic/langchain_integration/chains/tool_calling_chain_claude_xml.py b/source/lambda/online/common_logic/langchain_integration/chains/tool_calling_chain_claude_xml.py deleted file mode 100644 index e2bdb4e15..000000000 --- a/source/lambda/online/common_logic/langchain_integration/chains/tool_calling_chain_claude_xml.py +++ /dev/null @@ -1,328 +0,0 @@ -# tool calling chain -import json -from typing import List, Dict, Any -import re - -from langchain.schema.runnable import ( - RunnableLambda, - RunnablePassthrough -) -from common_logic.common_utils.prompt_utils import get_prompt_template -from common_logic.common_utils.logger_utils import print_llm_messages -from langchain_core.messages import ( - AIMessage, - SystemMessage -) -from langchain.prompts import ChatPromptTemplate - -from langchain_core.messages import AIMessage, SystemMessage - -from common_logic.common_utils.constant import ( - LLMTaskType, - LLMModelType, - MessageType -) -from common_logic.common_utils.time_utils import get_china_now - -from . import LLMChain -from ..chat_models import Model - -incorrect_tool_call_example = """Here is an example of an incorrectly formatted tool call, which you should avoid. - - - -tool_name - - -question -string -value - - - - - - -In this incorrect tool calling example, the parameter `name` should form a XLM tag. -""" - - -SYSTEM_MESSAGE_PROMPT = (f"In this environment you have access to a set of tools you can use to answer the user's question.\n" - "\n" - "You may call them like this:\n" - "\n" - "\n" - "$TOOL_NAME\n" - "\n" - "<$PARAMETER_NAME>$PARAMETER_VALUE\n" - "...\n" - "\n" - "\n" - "\n" - "\n" - "Here are the tools available:\n" - "\n" - "{tools}" - "\n" - "\nAnswer the user's request using relevant tools (if they are available). Before calling a tool, do some analysis within tags. First, think about which of the provided tools is the relevant tool to answer the user's request. Second, go through each of the required parameters of the relevant tool and determine if the user has directly provided or given enough information to infer a value. When deciding if the parameter can be inferred, carefully consider all the context to see if it supports a specific value. If all of the required parameters are present or can be reasonably inferred, close the thinking tag and proceed with the tool call. BUT, if one of the values for a required parameter is missing, DO NOT invoke the function (not even with fillers for the missing params) and instead, ask the user to provide the missing parameters. DO NOT ask for more information on optional parameters if it is not provided." - "\nHere are some guidelines for you:\n{tool_call_guidelines}." - f"\n{incorrect_tool_call_example}" - ) - -SYSTEM_MESSAGE_PROMPT_WITH_FEWSHOT_EXAMPLES = SYSTEM_MESSAGE_PROMPT + ( - "Some examples of tool calls are given below, where the content within represents the most recent reply in the dialog." - "\n{fewshot_examples}" -) - -TOOL_FORMAT = """ -{tool_name} -{tool_description} - -{formatted_required_parameters} - - -{formatted_optional_parameters} - -""" - -TOOL_PARAMETER_FORMAT = """ -{parameter_name} -{parameter_type} -{parameter_description} -""" - -TOOL_EXECUTE_SUCCESS_TEMPLATE = """ - - -{tool_name} - -{result} - - - -""" - -TOOL_EXECUTE_FAIL_TEMPLATE = """ - - -{error} - - -""" - -AGENT_SYSTEM_PROMPT = "你是一个亚马逊云科技的AI助理,你的名字是亚麻小Q。今天是{date_str},{weekday}. " - - -def _get_type(parameter: Dict[str, Any]) -> str: - if "type" in parameter: - return parameter["type"] - if "anyOf" in parameter: - return json.dumps({"anyOf": parameter["anyOf"]}) - if "allOf" in parameter: - return json.dumps({"allOf": parameter["allOf"]}) - return json.dumps(parameter) - - -def convert_openai_tool_to_anthropic(tools: list[dict]) -> str: - formatted_tools = tools - tools_data = [ - { - "tool_name": tool["name"], - "tool_description": tool["description"], - "formatted_required_parameters": "\n".join( - [ - TOOL_PARAMETER_FORMAT.format( - parameter_name=name, - parameter_type=_get_type(parameter), - parameter_description=parameter.get("description"), - ) for name, parameter in tool["parameters"]["properties"].items() - if name in tool["parameters"].get("required", []) - ] - ), - "formatted_optional_parameters": "\n".join( - [ - TOOL_PARAMETER_FORMAT.format( - parameter_name=name, - parameter_type=_get_type(parameter), - parameter_description=parameter.get("description"), - ) for name, parameter in tool["parameters"]["properties"].items() - if name not in tool["parameters"].get("required", []) - ] - ), - } - for tool in formatted_tools - ] - tools_formatted = "\n".join( - [ - TOOL_FORMAT.format( - tool_name=tool["tool_name"], - tool_description=tool["tool_description"], - formatted_required_parameters=tool["formatted_required_parameters"], - formatted_optional_parameters=tool["formatted_optional_parameters"], - ) - for tool in tools_data - ] - ) - return tools_formatted - - -class Claude2ToolCallingChain(LLMChain): - model_id = LLMModelType.CLAUDE_2 - intent_type = LLMTaskType.TOOL_CALLING_XML - default_model_kwargs = { - "max_tokens": 2000, - "temperature": 0.1, - "top_p": 0.9, - "stop_sequences": ["\n\nHuman:", "\n\nAssistant", ""], - } - - @staticmethod - def format_fewshot_examples(fewshot_examples: list[dict]): - fewshot_example_strs = [] - for fewshot_example in fewshot_examples: - param_strs = [] - for p, v in fewshot_example['kwargs'].items(): - param_strs.append(f"<{p}>{v}\n" - f"{fewshot_example['query']}\n" - f"\n" - "\n" - "\n" - f"{fewshot_example['name']}\n" - "\n" - f"{param_str}" - "\n" - "\n" - "\n" - "\n" - "" - ) - fewshot_example_strs.append(fewshot_example_str) - fewshot_example_str = '\n'.join(fewshot_example_strs) - return f"\n{fewshot_example_str}\n" - - @classmethod - def parse_function_calls_from_ai_message(cls, message: AIMessage): - content = "" + message.content + "" - function_calls: List[str] = re.findall( - "(.*?)", content, re.S) - if not function_calls: - content = "" + message.content - - return { - "function_calls": function_calls, - "content": content - } - - @classmethod - def create_chat_history(cls, x): - chat_history = x['chat_history'] + \ - [{"role": MessageType.HUMAN_MESSAGE_TYPE, "content": x['query']}] + \ - x['agent_tool_history'] - return chat_history - - @classmethod - def get_common_system_prompt(cls, system_prompt_template: str): - now = get_china_now() - date_str = now.strftime("%Y年%m月%d日") - weekdays = ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'] - weekday = weekdays[now.weekday()] - system_prompt = system_prompt_template.format( - date=date_str, weekday=weekday) - return system_prompt - - @classmethod - def create_chain(cls, model_kwargs=None, **kwargs): - model_kwargs = model_kwargs or {} - tools: list = kwargs['tools'] - fewshot_examples = kwargs.get('fewshot_examples', []) - if fewshot_examples: - fewshot_examples.append({ - "name": "give_rhetorical_question", - "query": "今天天气怎么样?", - "kwargs": {"question": "请问你想了解哪个城市的天气?"} - }) - user_system_prompt = get_prompt_template( - model_id=cls.model_id, - task_type=cls.intent_type, - prompt_name="user_prompt" - ).prompt_template - - user_system_prompt = kwargs.get( - "user_prompt", None) or user_system_prompt - - user_system_prompt = cls.get_common_system_prompt( - user_system_prompt - ) - guidelines_prompt = get_prompt_template( - model_id=cls.model_id, - task_type=cls.intent_type, - prompt_name="guidelines_prompt" - ).prompt_template - - guidelines_prompt = kwargs.get( - "guidelines_prompt", None) or guidelines_prompt - model_kwargs = {**cls.default_model_kwargs, **model_kwargs} - - tools_formatted = convert_openai_tool_to_anthropic(tools) - - if fewshot_examples: - system_prompt = SYSTEM_MESSAGE_PROMPT_WITH_FEWSHOT_EXAMPLES.format( - tools=tools_formatted, - fewshot_examples=cls.format_fewshot_examples(fewshot_examples), - tool_call_guidelines=guidelines_prompt - ) - else: - system_prompt = SYSTEM_MESSAGE_PROMPT.format( - tools=tools_formatted, - tool_call_guidelines=guidelines_prompt - ) - - system_prompt = user_system_prompt + system_prompt - tool_calling_template = ChatPromptTemplate.from_messages( - [ - SystemMessage(content=system_prompt), - ("placeholder", "{chat_history}"), - AIMessage(content="") - ]) - - llm = Model.get_model( - model_id=cls.model_id, - model_kwargs=model_kwargs, - ) - chain = RunnablePassthrough.assign(chat_history=lambda x: cls.create_chat_history(x)) | tool_calling_template \ - | RunnableLambda(lambda x: print_llm_messages(f"Agent messages: {x.messages}") or x.messages) \ - | llm | RunnableLambda(lambda message: cls.parse_function_calls_from_ai_message( - message - )) - return chain - - -class Claude21ToolCallingChain(Claude2ToolCallingChain): - model_id = LLMModelType.CLAUDE_21 - - -class ClaudeInstanceToolCallingChain(Claude2ToolCallingChain): - model_id = LLMModelType.CLAUDE_INSTANCE - - -class Claude3SonnetToolCallingChain(Claude2ToolCallingChain): - model_id = LLMModelType.CLAUDE_3_SONNET - - -class Claude3HaikuToolCallingChain(Claude2ToolCallingChain): - model_id = LLMModelType.CLAUDE_3_HAIKU - - -class Claude35SonnetToolCallingChain(Claude2ToolCallingChain): - model_id = "anthropic.claude-3-5-sonnet-20240620-v1:0" - - -class NovaProToolCallingChain(Claude2ToolCallingChain): - model_id = LLMModelType.NOVA_PRO - diff --git a/source/lambda/online/common_logic/langchain_integration/chains/translate_chain.py b/source/lambda/online/common_logic/langchain_integration/chains/translate_chain.py deleted file mode 100644 index 2be6a37d8..000000000 --- a/source/lambda/online/common_logic/langchain_integration/chains/translate_chain.py +++ /dev/null @@ -1,41 +0,0 @@ -# translate chain -from langchain.schema.runnable import RunnableLambda - -from common_logic.common_utils.constant import ( - LLMTaskType, - LLMModelType -) -from .chat_chain import Internlm2Chat7BChatChain - -QUERY_TRANSLATE_TYPE = LLMTaskType.QUERY_TRANSLATE_TYPE - - -class Internlm2Chat7BTranslateChain(Internlm2Chat7BChatChain): - intent_type = QUERY_TRANSLATE_TYPE - default_model_kwargs = {"temperature": 0.1, "max_new_tokens": 200} - - @classmethod - def create_prompt(cls, x): - query = x["query"] - target_lang = x["target_lang"] - history = cls.create_history(x) - meta_instruction = f"你是一个有经验的翻译助理, 正在将用户的问题翻译成{target_lang},不要试图去回答用户的问题,仅仅做翻译。" - query = f'将文本:\n "{query}" \n 翻译成{target_lang}。\n直接翻译文本,不要输出多余的文本。' - - prompt = cls.build_prompt( - query=query, history=history, meta_instruction=meta_instruction - ) - return prompt - - @classmethod - def create_chain(cls, model_kwargs=None, **kwargs): - model_kwargs = model_kwargs or {} - model_kwargs = {**cls.default_model_kwargs, **model_kwargs} - llm_chain = super().create_chain(model_kwargs=model_kwargs, **kwargs) - llm_chain = llm_chain | RunnableLambda( - lambda x: x.strip('"')) # postprocess - return llm_chain - - -class Internlm2Chat20BTranslateChain(Internlm2Chat7BTranslateChain): - model_id = LLMModelType.INTERNLM2_CHAT_20B diff --git a/source/lambda/online/common_logic/langchain_integration/chat_models/openai_models.py b/source/lambda/online/common_logic/langchain_integration/chat_models/openai_models.py deleted file mode 100644 index 7afe025be..000000000 --- a/source/lambda/online/common_logic/langchain_integration/chat_models/openai_models.py +++ /dev/null @@ -1,30 +0,0 @@ -from langchain_openai import ChatOpenAI -from common_logic.common_utils.constant import LLMModelType -from common_logic.common_utils.logger_utils import get_logger -from . import Model - -logger = get_logger("openai_model") - - -class ChatGPT35(Model): - model_id = LLMModelType.CHATGPT_35_TURBO_0125 - default_model_kwargs = {"max_tokens": 2000, - "temperature": 0.7, "top_p": 0.9} - - @classmethod - def create_model(cls, model_kwargs=None, **kwargs): - model_kwargs = model_kwargs or {} - model_kwargs = {**cls.default_model_kwargs, **model_kwargs} - llm = ChatOpenAI( - model=cls.model_id, - **model_kwargs, - ) - return llm - - -class ChatGPT4Turbo(ChatGPT35): - model_id = LLMModelType.CHATGPT_4_TURBO - - -class ChatGPT4o(ChatGPT35): - model_id = LLMModelType.CHATGPT_4O diff --git a/source/lambda/online/common_logic/langchain_integration/retrievers/retriever.py b/source/lambda/online/common_logic/langchain_integration/retrievers/retriever.py index f117b7413..c74b82838 100644 --- a/source/lambda/online/common_logic/langchain_integration/retrievers/retriever.py +++ b/source/lambda/online/common_logic/langchain_integration/retrievers/retriever.py @@ -4,9 +4,6 @@ from langchain.retrievers import ( ContextualCompressionRetriever, ) -from common_logic.langchain_integration.retrievers.utils.websearch_retrievers import ( - GoogleRetriever, -) from common_logic.langchain_integration.retrievers.utils.reranker import ( BGEReranker, MergeReranker, @@ -63,11 +60,6 @@ def get_bedrock_kb_retrievers(knowledge_base_id_list, top_k: int): return retriever_list -def get_websearch_retrievers(top_k: int): - retriever_list = [GoogleRetriever(top_k)] - return retriever_list - - def get_custom_qd_retrievers(config: dict, using_bm25=False): qd_retriever = QueryDocumentKNNRetriever(**config) @@ -115,7 +107,6 @@ def get_whole_chain(retriever_list, reranker_config): "qq": get_custom_qq_retrievers, "intention": get_custom_qq_retrievers, "qd": get_custom_qd_retrievers, - "websearch": get_websearch_retrievers, "bedrock_kb": get_bedrock_kb_retrievers, } diff --git a/source/lambda/online/common_logic/langchain_integration/retrievers/utils/websearch_retrievers.py b/source/lambda/online/common_logic/langchain_integration/retrievers/utils/websearch_retrievers.py deleted file mode 100644 index b58b27f2a..000000000 --- a/source/lambda/online/common_logic/langchain_integration/retrievers/utils/websearch_retrievers.py +++ /dev/null @@ -1,129 +0,0 @@ -from langchain.agents import Tool -from langchain.schema.retriever import BaseRetriever -from langchain.docstore.document import Document -from langchain.callbacks.manager import CallbackManagerForRetrieverRun -from langchain_community.utilities import GoogleSearchAPIWrapper -import asyncio -import aiohttp -import time -import re -from bs4 import BeautifulSoup -import os -from typing import Any, Dict, List -import logging -logger = logging.getLogger() -logger.setLevel(logging.INFO) - - -GOOGLE_API_KEY = os.environ.get('GOOGLE_API_KEY', None) -GOOGLE_CSE_ID = os.environ.get('GOOGLE_CSE_ID', None) - - -class GoogleSearchTool(): - tool: Tool - topk: int = 5 - - def __init__(self, top_k=5): - self.topk = top_k - search = GoogleSearchAPIWrapper() - - def top_results(query): - return search.results(query, self.topk) - self.tool = Tool( - name="Google Search Snippets", - description="Search Google for recent results.", - func=top_results, - ) - - def run(self, query): - return self.tool.run(query) - - -def remove_html_tags(text): - soup = BeautifulSoup(text, 'html.parser') - text = soup.get_text() - text = re.sub(r'\r{1,}', "\n\n", text) - text = re.sub(r'\t{1,}', "\t", text) - text = re.sub(r'\n{2,}', "\n\n", text) - return text - - -async def fetch(session, url, timeout): - try: - async with session.get(url) as response: - return await asyncio.wait_for(response.text(), timeout=timeout) - except asyncio.TimeoutError: - print(f"timeout:{url}") - return '' - except Exception as e: - print(f"ClientError:{url}", str(e)) - return '' - - -async def fetch_all(urls, timeout): - async with aiohttp.ClientSession() as session: - tasks = [] - for url in urls: - task = asyncio.create_task(fetch(session, url, timeout)) - tasks.append(task) - - results = await asyncio.gather(*tasks) - return results - - -def web_search(**args): - if not GOOGLE_API_KEY or not GOOGLE_CSE_ID: - logger.info('Missing google API key') - return [] - tool = GoogleSearchTool(args['top_k']) - result = tool.run(args['query']) - return [item for item in result if 'title' in item and 'link' in item and 'snippet' in item] - - -def add_webpage_content(snippet_results): - t1 = time.time() - urls = [item['doc_author'] for item in snippet_results] - loop = asyncio.get_event_loop() - fetch_results = loop.run_until_complete(fetch_all(urls, 5)) - t2 = time.time() - logger.info(f'deep web search time:{t2-t1:1f}s') - final_results = [] - for i, result in enumerate(fetch_results): - if not result: - continue - page_content = remove_html_tags(result) - final_results.append({**snippet_results[i], - 'doc': snippet_results[i]['doc']+'\n'+page_content[:10000] - }) - return final_results - - -class GoogleRetriever(BaseRetriever): - search: Any - result_num: Any - - def __init__(self, result_num): - super().__init__() - self.result_num = result_num - - def _get_relevant_documents( - self, question: Dict, *, run_manager: CallbackManagerForRetrieverRun - ) -> List[Document]: - query = question[self.query_key] - result_list = web_search(query=query, top_k=self.result_num) - doc_list = [] - for result in result_list: - doc_list.append( - Document( - page_content=result["doc"], - metadata={ - "source": result["link"], - "retrieval_content": result["title"] + '\n' + result["snippet"], - "retrieval_data": result["title"] - } - ) - ) - return doc_list - - def get_whole_doc(self, results) -> Dict: - return add_webpage_content(self._get_relevant_documents(results)) diff --git a/source/lambda/online/common_logic/langchain_integration/tools/common_tools/__init__.py b/source/lambda/online/common_logic/langchain_integration/tools/common_tools/__init__.py index bda64d5e8..dd6e5c944 100644 --- a/source/lambda/online/common_logic/langchain_integration/tools/common_tools/__init__.py +++ b/source/lambda/online/common_logic/langchain_integration/tools/common_tools/__init__.py @@ -115,96 +115,3 @@ def _load_rag_tool(tool_identifier: ToolIdentifier): tool_def=tool_def, return_direct=True ) - - -################### langchain tools ####################### - -@lazy_tool_load_decorator(SceneType.COMMON, "python_repl") -def _loadd_python_repl_tool(tool_identifier: ToolIdentifier): - from langchain_core.tools import Tool - from langchain_experimental.utilities import PythonREPL as _PythonREPL - from langchain_experimental.utilities.python import warn_once - import multiprocessing - - # modify LangChain's PythonREPL to adapt aws lambda, - # where it's execution environment not having /dev/shm - - class PythonREPL(_PythonREPL): - @classmethod - def worker( - cls, - command: str, - globals: Optional[Dict], - locals: Optional[Dict], - conn: Any, - ) -> None: - old_stdout = sys.stdout - sys.stdout = mystdout = StringIO() - try: - cleaned_command = cls.sanitize_input(command) - exec(cleaned_command, globals, locals) - sys.stdout = old_stdout - conn.send(mystdout.getvalue()) - except Exception as e: - sys.stdout = old_stdout - conn.send(repr(e)) - conn.close() - - def run(self, command: str, timeout: Optional[int] = None) -> str: - """Run command with own globals/locals and returns anything printed. - Timeout after the specified number of seconds.""" - - # Warn against dangers of PythonREPL - warn_once() - - # queue: multiprocessing.Queue = multiprocessing.Queue() - parent_conn, child_conn = multiprocessing.Pipe() - - # Only use multiprocessing if we are enforcing a timeout - if timeout is not None: - # create a Process - p = multiprocessing.Process( - target=self.worker, args=( - command, self.globals, self.locals, child_conn) - ) - - # start it - p.start() - - # wait for the process to finish or kill it after timeout seconds - p.join(timeout) - - if p.is_alive(): - p.terminate() - return "Execution timed out" - else: - self.worker(command, self.globals, self.locals, child_conn) - # get the result from the worker function - return parent_conn.recv() - - python_repl = PythonREPL() - - def _run(command: str, timeout=None) -> str: - res = python_repl.run(command=command, timeout=timeout) - if not res: - raise ValueError( - f"The current tool does not produce a result, modify your code and continue to call the `python_repl` tool, making sure to use the `print` function to output the final result.") - return res - - description = """\ -This tool handles scientific computing problems by executing python code. Typical scenarios include the follows: -1. Mathematical arithmetic/numerical comparisons. -2. Code execution scenarios, such as data analysis, visualization, etc. - -Input should be a valid python code. If you want to see the output of a value, you must print it out with `print(...)` statement. -""" - repl_tool = Tool( - name="python_repl", - description=description, - func=_run - ) - ToolManager.register_lc_tool( - scene=tool_identifier.scene, - name=tool_identifier.name, - tool=repl_tool - ) diff --git a/source/lambda/online/lambda_main/main_utils/online_entries/__init__.py b/source/lambda/online/lambda_main/main_utils/online_entries/__init__.py index bca58edd7..da6b224dd 100644 --- a/source/lambda/online/lambda_main/main_utils/online_entries/__init__.py +++ b/source/lambda/online/lambda_main/main_utils/online_entries/__init__.py @@ -1,19 +1,12 @@ from common_logic.common_utils.constant import EntryType -# from functions import get_tool_by_name,init_common_tools,init_retail_tools def get_common_entry(): from .common_entry import main_chain_entry # init_common_tools() return main_chain_entry -def get_retail_entry(): - from .retail_entry import main_chain_entry - # init_retail_tools() - return main_chain_entry - entry_map = { - EntryType.COMMON: get_common_entry, - EntryType.RETAIL: get_retail_entry + EntryType.COMMON: get_common_entry } def get_entry(entry_name): diff --git a/source/lambda/online/lambda_main/main_utils/online_entries/retail_entry.py b/source/lambda/online/lambda_main/main_utils/online_entries/retail_entry.py deleted file mode 100644 index 9bdb06705..000000000 --- a/source/lambda/online/lambda_main/main_utils/online_entries/retail_entry.py +++ /dev/null @@ -1,619 +0,0 @@ -import json -import re -import os -import random -from datetime import datetime -from textwrap import dedent -from typing import TypedDict, Any, Annotated -import validators -from langgraph.graph import StateGraph, END -from common_logic.common_utils.lambda_invoke_utils import invoke_lambda, node_monitor_wrapper -from common_logic.common_utils.python_utils import update_nest_dict, add_messages -from common_logic.common_utils.constant import ( - LLMTaskType, - ToolRuningMode, - SceneType -) - -from functions.lambda_retail_tools.product_information_search import goods_dict - -from lambda_main.main_utils.parse_config import RetailConfigParser -from common_logic.common_utils.lambda_invoke_utils import send_trace, is_running_local -from common_logic.common_utils.logger_utils import get_logger -from common_logic.common_utils.response_utils import process_response -from common_logic.common_utils.serialization_utils import JSONEncoder -from common_logic.common_utils.s3_utils import download_file_from_s3, check_local_folder -from lambda_main.main_utils.online_entries.agent_base import build_agent_graph, tool_execution -from functions import get_tool_by_name - -data_bucket_name = os.environ.get( - "RES_BUCKET", "aws-chatbot-knowledge-base-test") -order_info_path = "/tmp/functions/retail_tools/lambda_order_info/order_info.json" -check_local_folder(order_info_path) -download_file_from_s3( - data_bucket_name, "retail_json/order_info.json", order_info_path) -order_dict = json.load(open(order_info_path)) -logger = get_logger('retail_entry') - - -class ChatbotState(TypedDict): - ########### input/output states ########### - # inputs - # origin event body - event_body: dict - # origianl input question - query: str - # chat history between human and agent - chat_history: Annotated[list[dict], add_messages] - # complete chatbot config, consumed by all the nodes - chatbot_config: dict - goods_id: Any - # websocket connection id for the agent - ws_connection_id: str - # whether to enbale stream output via ws_connection_id - stream: bool - # message id related to original input question - message_id: str = None - # record running states of different nodes - trace_infos: Annotated[list[str], add_messages] - # whether to enbale trace info update via streaming ouput - enable_trace: bool - # outputs - # final answer generated by whole app graph - answer: Any - # information needed return to user, e.g. intention, context, figure and so on, anything you can get during execution - extra_response: Annotated[dict, update_nest_dict] - # addition kwargs which need to save into ddb - ddb_additional_kwargs: dict - # response of entire app - app_response: Any - - ########### query rewrite states ########### - # query rewrite results - query_rewrite: str = None - - ########### intention detection states ########### - # intention type of retrieved intention samples in search engine, e.g. OpenSearch - intent_type: str = None - # retrieved intention samples in search engine, e.g. OpenSearch - intent_fewshot_examples: list - # tools of retrieved intention samples in search engine, e.g. OpenSearch - intent_fewshot_tools: list - - ########### retriever states ########### - # contexts information retrieved in search engine, e.g. OpenSearch - qq_match_results: list = [] - contexts: str = None - figure: list = None - - ########### agent states ########### - # current output of agent - agent_current_output: dict - # record messages during agent tool choose and calling, including agent message, tool ouput and error messages - agent_tool_history: Annotated[list[dict], add_messages] - # the maximum number that agent node can be called - agent_repeated_call_limit: int - # the current call time of agent - agent_current_call_number: int - # whehter the current call time is less than maximum number of agent call - agent_repeated_call_validation: bool - # function calling - # whether the output of agent can be parsed as the valid tool calling - function_calling_parse_ok: bool - # whether the current parsed tool calling is run once - function_calling_is_run_once: bool - # current tool calls - function_calling_parsed_tool_calls: list - - # retail data - create_time: str - goods_info: None - human_goods_info: None - agent_llm_type: str - other_chain_kwargs: dict - - -# class ChatbotState(TypedDict): -# chatbot_config: dict # chatbot config -# query: str -# create_time: str -# ws_connection_id: str -# stream: bool -# query_rewrite: str = None # query rewrite ret -# intent_type: str = None # intent -# intent_fewshot_examples: list -# trace_infos: Annotated[list[str],add_messages] -# message_id: str = None -# chat_history: Annotated[list[dict],add_messages] -# agent_tool_history: Annotated[list[dict],add_messages] -# current_function_calls: list[str] -# current_tool_execute_res: dict -# debug_infos: Annotated[dict,update_nest_dict] -# answer: Any # final answer -# current_monitor_infos: str -# extra_response: Annotated[dict,update_nest_dict] -# contexts: str = None -# intent_fewshot_tools: list # -# current_agent_intent_type: str = None -# function_calling_parsed_tool_calls:list -# # current_agent_tools_def: list[dict] -# # current_agent_model_id: str -# agent_current_output: dict -# function_calling_parse_ok: bool -# query_rule_classification: str -# goods_info: None -# human_goods_info: None -# agent_llm_type: str -# query_rewrite_llm_type: str -# agent_repeated_call_limit: int # agent recursion limit -# agent_current_call_number: int -# enable_trace: bool -goods_info_tag = "商品信息" - -#################### -# nodes in lambdas # -#################### - - -@node_monitor_wrapper -def query_preprocess(state: ChatbotState): - output: str = invoke_lambda( - event_body={**state, "chat_history": []}, - lambda_name="Online_Query_Preprocess", - lambda_module_path="lambda_query_preprocess.query_preprocess", - handler_name="lambda_handler" - ) - state['extra_response']['query_rewrite'] = output - send_trace(f"\n\n **query_rewrite:** \n{output}") - return { - "query_rewrite": output, - "current_monitor_infos": f"query_rewrite: {output}" - } - - -@node_monitor_wrapper -def intention_detection(state: ChatbotState): - intent_fewshot_examples = invoke_lambda( - lambda_module_path='lambda_intention_detection.intention', - lambda_name="Online_Intention_Detection", - handler_name="lambda_handler", - event_body=state - ) - state['extra_response']['intent_fewshot_examples'] = intent_fewshot_examples - - # send trace - send_trace(f"\n\nintention retrieved:\n{json.dumps(intent_fewshot_examples,ensure_ascii=False,indent=2)}", - state["stream"], state["ws_connection_id"]) - intent_fewshot_tools: list[str] = list( - set([e['intent'] for e in intent_fewshot_examples])) - return { - "intent_fewshot_examples": intent_fewshot_examples, - "intent_fewshot_tools": intent_fewshot_tools, - "intent_type": "other" - } - - -@node_monitor_wrapper -def agent(state: ChatbotState): - goods_info = state.get('goods_info', None) or "" - agent_tool_history = state.get('agent_tool_history', "") - if agent_tool_history and hasattr(agent_tool_history[-1], 'additional_kwargs'): - search_result = agent_tool_history[-1]['additional_kwargs']['original'][0].get( - 'search_result', 1) - if search_result == 0: - context = agent_tool_history[-1]['additional_kwargs']['original'][0].get( - 'result', "") - system_prompt = ("你是安踏的客服助理,正在帮消费者解答问题,消费者提出的问题大多是属于商品的质量和物流规则。context列举了一些可能有关的具体场景及回复,你可以进行参考:\n" - "\n" - f"{context}\n" - "" - "你需要按照下面的guidelines对消费者的问题进行回答:\n" - "\n" - " - 回答内容为一句话,言简意赅。\n" - " - 如果问题与context内容不相关,就不要采用。\n" - " - 消费者的问题里面可能包含口语化的表达,比如鞋子开胶的意思是用胶黏合的鞋体裂开。这和胶丝遗留没有关系。\n" - ' - 如果问题涉及到订单号,请回复: "请稍等,正在帮您查询订单。"' - "" - ) - query = state['query'] - # print('llm config',state['chatbot_config']['rag_product_aftersales_config']['llm_config']) - output: str = invoke_lambda( - lambda_name='Online_LLM_Generate', - lambda_module_path="lambda_llm_generate.llm_generate", - handler_name='lambda_handler', - event_body={ - "llm_config": { - **state['chatbot_config']['rag_product_aftersales_config']['llm_config'], - "system_prompt": system_prompt, - "intent_type": LLMTaskType.CHAT - }, - "llm_input": {"query": query, "chat_history": state['chat_history']} - } - ) - agent_current_call_number = state['agent_current_call_number'] + 1 - agent_current_output = {} - agent_current_output['agent_output'] = {} - agent_current_output['agent_output']['function_calls'] = [] - agent_current_output['agent_output']['content'] = output - agent_current_output['current_agent_model_id'] = "qwen2-72B-instruct" - agent_current_output['current_agent_tools_def'] = [] - return { - "agent_current_output": agent_current_output, - "agent_current_call_number": agent_current_call_number - } - - # deal with once tool calling - if state['agent_repeated_call_validation'] and state['function_calling_parse_ok'] and state['agent_tool_history']: - tool_execute_res = state['agent_tool_history'][-1]['additional_kwargs']['raw_tool_call_results'][0] - tool_name = tool_execute_res['name'] - output = tool_execute_res['output'] - tool = get_tool_by_name(tool_name, scene=SceneType.RETAIL) - if tool.running_mode == ToolRuningMode.ONCE: - send_trace("once tool") - return { - "answer": str(output['result']), - "function_calling_is_run_once": True - } - - other_chain_kwargs = { - "goods_info": goods_info, - "create_time": state['create_time'], - "agent_current_call_number": state['agent_current_call_number'] - } - - response = app_agent.invoke({ - **state, - "other_chain_kwargs": other_chain_kwargs - }) - return response - - -@node_monitor_wrapper -def final_rag_retriever_lambda(state: ChatbotState): - # call retriever - retriever_params = state["chatbot_config"]["final_rag_retriever"]["retriever_config"] - retriever_params["query"] = state["query"] - output: str = invoke_lambda( - event_body=retriever_params, - lambda_name="Online_Functions", - lambda_module_path="functions.functions_utils.retriever.retriever", - handler_name="lambda_handler" - ) - contexts = [doc['page_content'] for doc in output['result']['docs']] - - context = "\n".join(contexts) - send_trace(f'**final_rag_retriever** {context}') - return {"contexts": contexts} - - -@node_monitor_wrapper -def final_rag_llm_lambda(state: ChatbotState): - context = "\n\n".join(state['contexts']) - system_prompt = ("你是安踏的客服助理,正在帮消费者解答售前或者售后的问题。 中列举了一些可能有关的具体场景及回复,你可以进行参考:\n" - "\n" - f"{context}\n" - "\n" - "你需要按照下面的guidelines对消费者的问题进行回答:\n" - "\n" - " - 回答内容为一句话,言简意赅。\n" - " - 如果问题与context内容不相关,就不要采用。\n" - "\n" - ) - output: str = invoke_lambda( - lambda_name='Online_LLM_Generate', - lambda_module_path="lambda_llm_generate.llm_generate", - handler_name='lambda_handler', - event_body={ - "llm_config": { - **state['chatbot_config']['final_rag_retriever']['llm_config'], - "system_prompt": system_prompt, - "intent_type": LLMTaskType.CHAT}, - "llm_input": {"query": state["query"], "chat_history": state['chat_history']} - } - ) - return {"answer": output} - -# def transfer_reply(state:ChatbotState): -# return {"answer": "您好,我是安踏官方客服,很高兴为您服务。请问您有什么需要帮助的吗?"} - - -# def give_rhetorical_question(state:ChatbotState): -# recent_tool_calling:list[dict] = state['function_calling_parsed_tool_calls'][0] -# return {"answer": recent_tool_calling['kwargs']['question']} - - -# def give_final_response(state:ChatbotState): -# recent_tool_calling:list[dict] = state['function_calling_parsed_tool_calls'][0] -# return {"answer": recent_tool_calling['kwargs']['response']} - -def rule_url_reply(state: ChatbotState): - state["extra_response"]["current_agent_intent_type"] = "rule reply" - if state['query'].endswith(('.jpg', '.png')): - answer = random.choice([ - "收到,亲。请问我们可以怎么为您效劳呢?", - "您好,请问有什么需要帮助的吗?" - ]) - return {"answer": answer} - # product information - r = re.findall(r"item.htm\?id=(.*)", state['query']) - if r: - goods_id = r[0] - else: - goods_id = 0 - if goods_id in goods_dict: - # call llm to make summary of goods info - human_goods_info = state['human_goods_info'] - output = f"您好,该商品的特点是:\n{human_goods_info}" - if human_goods_info: - system_prompt = (f"你是安踏的客服助理,当前用户对下面的商品感兴趣:\n" - f"<{goods_info_tag}>\n{human_goods_info}\n\n" - "请你结合商品的基础信息,特别是卖点信息返回一句推荐语。" - ) - output: str = invoke_lambda( - lambda_name='Online_LLM_Generate', - lambda_module_path="lambda_llm_generate.llm_generate", - handler_name='lambda_handler', - event_body={ - "llm_config": { - **state['chatbot_config']['rag_daily_reception_config']['llm_config'], - "system_prompt": system_prompt, - "intent_type": LLMTaskType.CHAT}, - "llm_input": {"query": state['query'], "chat_history": state['chat_history']} - } - ) - - return {"answer": output} - - return {"answer": "您好"} - - -def rule_number_reply(state: ChatbotState): - state["extra_response"]["current_agent_intent_type"] = "rule reply" - return {"answer": "收到订单信息"} - - -def final_results_preparation(state: ChatbotState): - state['ddb_additional_kwargs'] = { - "goods_id": state['goods_id'], - "current_agent_intent_type": state['extra_response'].get('current_agent_intent_type', "") - } - app_response = process_response(state['event_body'], state) - return {"app_response": app_response} - - -################ -# define edges # -################ - -def query_route(state: dict): - # check if rule reply - query = state['query'] - is_all_url = True - for token in query.split(): - if not validators.url(token): - is_all_url = False - if is_all_url: - return "url" - if query.isnumeric() and len(query) >= 8: - return "number" - else: - return "continue" - - -def intent_route(state: dict): - return state['intent_type'] - - -def agent_route(state: dict): - if state.get("function_calling_is_run_once", False): - return "no need tool calling" - - state["agent_repeated_call_validation"] = state['agent_current_call_number'] < state['agent_repeated_call_limit'] - - if state["agent_repeated_call_validation"]: - return "valid tool calling" - else: - # TODO give final strategy - raise 'final rag' - - -############################# -# define whole online graph # -############################# - -app_agent = None - - -def build_graph(chatbot_state_cls): - workflow = StateGraph(chatbot_state_cls) - # add all nodes - workflow.add_node("query_preprocess", query_preprocess) - workflow.add_node("intention_detection", intention_detection) - workflow.add_node("agent", agent) - workflow.add_node("tools_execution", tool_execution) - workflow.add_node("rule_url_reply", rule_url_reply) - workflow.add_node("rule_number_reply", rule_number_reply) - # workflow.add_node("rag_promotion_retriever",rag_promotion_retriever_lambda) - # workflow.add_node("rag_promotion_llm",rag_promotion_llm_lambda) - # workflow.add_node("final_rag_retriever",final_rag_retriever_lambda) - # workflow.add_node("final_rag_llm",final_rag_llm_lambda) - - workflow.add_node("final_results_preparation", final_results_preparation) - - # add all edges - workflow.set_entry_point("query_preprocess") - workflow.add_edge("intention_detection", "agent") - workflow.add_edge("tools_execution", "agent") - # workflow.add_edge("agent",'parse_tool_calling') - # workflow.add_edge("rag_daily_reception_retriever","rag_daily_reception_llm") - # workflow.add_edge('rag_goods_exchange_retriever',"rag_goods_exchange_llm") - # workflow.add_edge('rag_product_aftersales_retriever',"rag_product_aftersales_llm") - # workflow.add_edge('rag_customer_complain_retriever',"rag_customer_complain_llm") - # workflow.add_edge('rag_promotion_retriever',"rag_promotion_llm") - # workflow.add_edge('final_rag_retriever',"final_rag_llm") - - # end - # workflow.add_edge("transfer_reply",END) - # workflow.add_edge("give_rhetorical_question",END) - # workflow.add_edge("give_response_wo_tool",END) - # workflow.add_edge("rag_daily_reception_llm",END) - # workflow.add_edge("rag_goods_exchange_llm",END) - # workflow.add_edge("rag_product_aftersales_llm",END) - # workflow.add_edge("rag_customer_complain_llm",END) - workflow.add_edge('rule_url_reply', END) - workflow.add_edge('rule_number_reply', END) - # workflow.add_edge("rag_promotion_llm",END) - # workflow.add_edge("give_final_response",END) - # workflow.add_edge("final_rag_llm",END) - - # temporal add edges for ending logic - # add conditional edges - workflow.add_conditional_edges( - "query_preprocess", - query_route, - { - "url": "rule_url_reply", - "number": "rule_number_reply", - "continue": "intention_detection" - } - ) - - # the results of agent planning will be evaluated and decide next step: - # 1. valid tool calling: the agent chooses the valid tools, and the tools will be executed - # 2. no need tool calling: the agent thinks no tool needs to be called, the final results can be generated - workflow.add_conditional_edges( - "agent", - agent_route, - { - "valid tool calling": "tools_execution", - "no need tool calling": "final_results_preparation", - }, - ) - app = workflow.compile() - return app - - -app = None - - -def _prepare_chat_history(event_body): - if "history_config" in event_body["chatbot_config"]: - # experiment for chat history sep by goods_id - goods_id = str(event_body['chatbot_config']['goods_id']) - chat_history_by_goods_id = [] - for hist in event_body["chat_history"]: - if goods_id == hist['additional_kwargs']['goods_id']: - current_chat = {} - current_chat['role'] = hist['role'] - current_chat['content'] = hist['content'] - current_chat['addional_kwargs'] = {} - if 'goods_id' in hist['additional_kwargs']: - current_chat['addional_kwargs']['goods_id'] = str( - hist['additional_kwargs']['goods_id']) - chat_history_by_goods_id.append(current_chat) - return chat_history_by_goods_id - else: - return event_body["chat_history"] - - -def retail_entry(event_body): - """ - Entry point for the Lambda function. - :param event_body: The event body for lambda function. - return: answer(str) - """ - global app, app_agent - if app is None: - app = build_graph(ChatbotState) - - if app_agent is None: - app_agent = build_agent_graph(ChatbotState) - - # debuging - # TODO only write when run local - if is_running_local(): - with open('retail_entry_workflow.png', 'wb') as f: - f.write(app.get_graph().draw_mermaid_png()) - - with open('retail_entry_agent_workflow.png', 'wb') as f: - f.write(app_agent.get_graph().draw_mermaid_png()) - ################################################################################ - # prepare inputs and invoke graph - event_body['chatbot_config'] = RetailConfigParser.from_chatbot_config( - event_body['chatbot_config']) - chatbot_config = event_body['chatbot_config'] - query = event_body['query'] - stream = event_body['stream'] - create_time = chatbot_config.get('create_time', None) - message_id = event_body['custom_message_id'] - ws_connection_id = event_body['ws_connection_id'] - enable_trace = chatbot_config["enable_trace"] - goods_info_tag = "商品信息" - - goods_info = "" - human_goods_info = "" - goods_id = str(event_body['chatbot_config']['goods_id']) - if goods_id: - try: - _goods_info = json.loads(goods_dict.get( - goods_id, {}).get("goods_info", "")) - _goods_type = goods_dict.get(goods_id, {}).get("goods_type", "") - except Exception as e: - import traceback - error = traceback.format_exc() - logger.error( - f"error meesasge {error}, invalid goods_id: {goods_id}") - _goods_info = None - - if _goods_info: - logger.info(_goods_info) - if _goods_type: - goods_info = f"商品类型: \n\n{_goods_type}\n\n" - else: - goods_info = "" - goods_info += f"<{goods_info_tag}>\n" - - human_goods_info = "" - for k, v in _goods_info.items(): - goods_info += f"{k}:{v}\n" - human_goods_info += f"{k}:{v}\n" - - goods_info = goods_info.strip() - goods_info += f"\n" - - use_history = chatbot_config['use_history'] - chat_history = _prepare_chat_history(event_body) if use_history else [] - event_body['chat_history'] = chat_history - logger.info( - f'event_body:\n{json.dumps(event_body,ensure_ascii=False,indent=2,cls=JSONEncoder)}') - - logger.info(f"goods_info: {goods_info}") - logger.info(f"chat_hisotry: {chat_history}") - # invoke graph and get results - response = app.invoke({ - "stream": stream, - "chatbot_config": chatbot_config, - "query": query, - "create_time": create_time, - "enable_trace": enable_trace, - "trace_infos": [], - "message_id": message_id, - "chat_history": chat_history, - "agent_tool_history": [], - "ws_connection_id": ws_connection_id, - "debug_infos": {}, - "extra_response": {}, - "goods_info": goods_info, - "human_goods_info": human_goods_info, - "agent_llm_type": LLMTaskType.RETAIL_TOOL_CALLING, - "query_rewrite_llm_type": LLMTaskType.RETAIL_CONVERSATION_SUMMARY_TYPE, - "agent_repeated_call_limit": chatbot_config['agent_repeated_call_limit'], - "agent_current_call_number": 0, - "current_agent_intent_type": "", - "goods_info_tag": "商品信息", - "goods_id": goods_id - }) - return response['app_response'] - - -main_chain_entry = retail_entry diff --git a/source/lambda/online/requirements.txt b/source/lambda/online/requirements.txt index 7eef623b7..b0d9b89a2 100644 --- a/source/lambda/online/requirements.txt +++ b/source/lambda/online/requirements.txt @@ -1,18 +1,8 @@ # https://aws-gcr-solutions-assets.s3.us-east-1.amazonaws.com/dmaa/wheels/dmaa-0.4.0-py3-none-any.whl langchain-aws==0.2.6 -httpx==0.26.0 langgraph==0.2.43 -langchain_openai==0.2.6 langchain-community==0.3.5 -langchainhub==0.1.14 opensearch-py==2.2.0 requests_aws4auth==1.2.2 -python-dateutil==2.8.2 -prettytable==3.10.0 -beautifulsoup4==4.12.2 -validators==0.28.3 -openpyxl==3.1.3 -xlrd==2.0.1 pydantic==2.9.2 datamodel-code-generator==0.26.2 -langchain_experimental==0.3.3 \ No newline at end of file diff --git a/source/lambda/online/retail_entry_workflow.png b/source/lambda/online/retail_entry_workflow.png deleted file mode 100644 index c1d926f96..000000000 Binary files a/source/lambda/online/retail_entry_workflow.png and /dev/null differ diff --git a/source/lambda/prompt_management/prompt_management.py b/source/lambda/prompt_management/prompt_management.py index d9661ef88..675729e6c 100644 --- a/source/lambda/prompt_management/prompt_management.py +++ b/source/lambda/prompt_management/prompt_management.py @@ -1,10 +1,10 @@ import json import os import time +import logging import boto3 from botocore.paginate import TokenEncoder -from common_logic.common_utils.logger_utils import get_logger from common_logic.common_utils.prompt_utils import ( EXPORT_MODEL_IDS, EXPORT_SCENES, @@ -17,7 +17,8 @@ MODELS_RESOURCE = f"{ROOT_RESOURCE}/models" SCENES_RESOURCE = f"{ROOT_RESOURCE}/scenes" PROMPTS_RESOURCE = f"{ROOT_RESOURCE}/prompts" -logger = get_logger("main") +logger = logging.getLogger() +logger.setLevel(logging.INFO) dynamodb_client = boto3.client("dynamodb") encoder = TokenEncoder() diff --git a/source/panel/.env_sample b/source/panel/.env_sample deleted file mode 100644 index 51b730b4a..000000000 --- a/source/panel/.env_sample +++ /dev/null @@ -1,3 +0,0 @@ -PIPELINE_URL='' -S3_BUCKET_NAME='' -GLUE_JOB_NAME='' \ No newline at end of file diff --git a/source/panel/README.md b/source/panel/README.md deleted file mode 100644 index 9d00ff736..000000000 --- a/source/panel/README.md +++ /dev/null @@ -1 +0,0 @@ -python -m streamlit run app.py --server.runOnSave true --server.port 8088 --browser.gatherUsageStats false --server.fileWatcherType none diff --git a/source/panel/app.py b/source/panel/app.py deleted file mode 100644 index e0575c66e..000000000 --- a/source/panel/app.py +++ /dev/null @@ -1,236 +0,0 @@ -from dotenv import load_dotenv -import os -import streamlit as st -from langchain.text_splitter import CharacterTextSplitter -from langchain.embeddings.openai import OpenAIEmbeddings -from langchain.vectorstores import FAISS -from langchain.chains.question_answering import load_qa_chain -from langchain.llms import OpenAI -from langchain.callbacks import get_openai_callback -import boto3 -import requests -import json -import time - -import logging -logger = logging.getLogger(__name__) -logging.basicConfig(level=logging.INFO) - -# Load environment variables -load_dotenv() - -# Create an S3 client -s3 = boto3.client('s3') -glue = boto3.client('glue') -# load the job name from environment variable and convert it to string like 'PythonShellJobB6964098-YYlLj16uCsAn' -glue_job_name = str(os.getenv('GLUE_JOB_NAME')) - -def process_text(text): - # Split the text into chunks using langchain - text_splitter = CharacterTextSplitter( - separator="\n", - chunk_size=1000, - chunk_overlap=200, - length_function=len - ) - chunks = text_splitter.split_text(text) - - # Convert the chunks of text into embeddings to form a knowledge base, should aware of the Rate limit. - # Prompt like "reached for text-embedding-ada-002 in organization org-xx on tokens per min. Limit: 150000 / min. Current: 1 / min.≈ - embeddings = OpenAIEmbeddings() - knowledgeBase = FAISS.from_texts(chunks, embeddings) - - return knowledgeBase - -def get_job_runs(page_token=None): - if page_token: - response = glue.get_job_runs(JobName=glue_job_name, MaxResults=10, NextToken=page_token) - else: - logger.info("glue_job_name: %s", glue_job_name) - response = glue.get_job_runs(JobName=glue_job_name, MaxResults=10) - # function only return running aws glue jobs - job_runs = [job_run for job_run in response['JobRuns'] if job_run['JobRunState'] == 'RUNNING'] - return job_runs, response.get('NextToken'), response.get('PreviousToken') - -def pipeline_tab(): - st.title("LLM Bot ETL Pipeline") - # text box to allow user input the url address of the pipeline with default value - pipeline_url = st.text_input('Pipeline URL', value=os.getenv('PIPELINE_URL')) - aos_index = st.text_input('OpenSearch index name', value=os.getenv('AOS_INDEX')) - - col1, col2 = st.columns(2) - with col1: - # sub panel to upload pdf and trigger the pipeline - st.subheader('Online ETL Job') - # adjust the width of the file uploader and hint text - pdf = st.file_uploader('Upload your Document', type='pdf') - - if pdf is not None: - # upload the pdf onto s3 bucket created in CDK stack with fixed prefix 'documents' , and trigger the pipeline - s3.upload_fileobj(pdf, os.getenv('S3_BUCKET'), 'documents/' + pdf.name) - - # add hint text to tell user that the online ETL job will be triggered automatically after the pdf is uploaded - st.markdown('**Note:** The online ETL job will be triggered automatically after the pdf is uploaded.') - - with col2: - # sub panel to operate and monitor the offline ETL job running on AWS Glue - # input box to allow user input request body and specify endpoint url and button to trigger the request sending to the endpoint - st.subheader('Offline ETL Job') - - # dropdown to list all available s3 bucket and allow user to select one for further operation - s3_buckets = s3.list_buckets() - s3_bucket_names = [bucket['Name'] for bucket in s3_buckets['Buckets']] - s3_bucket_name = st.selectbox('Select S3 Bucket', s3_bucket_names) - - # dropdown to list all subfolders under the selected s3 bucket and allow user to select one for further operation - s3_objects = s3.list_objects(Bucket=s3_bucket_name) - s3_object_names = [obj['Key'] for obj in s3_objects['Contents']] - s3_object_name = st.selectbox('Select S3 Object', s3_object_names) - - # simple checkboxed to allow user select options to trigger the pipeline - col3, col4 = st.columns(2) - with col3: - documentEnhance = st.checkbox('Doc Enhance') - qaPairEnhance = st.checkbox('QA Pair Enhance') - with col4: - keyWordExtract = st.checkbox('Key Word Extract') - textSummarize = st.checkbox('Text Summarize') - - # request body to be sent to the endpoint - request_body = { - 's3Bucket': s3_bucket_name, - 's3Prefix': s3_object_name, - 'documentEnhance': documentEnhance, - 'qaEnhance': str(qaPairEnhance), - 'keyWordExtract': keyWordExtract, - 'textSummarize': textSummarize, - 'offline': 'true' - } - # send button to trigger the request sending to the endpoint with s3_bucket_name and s3_object_name as request body, in conform with - send_button = st.button('Start Offline Job') - if send_button: - response = requests.post(pipeline_url + '/etl', json=request_body, headers={'Content-Type': 'application/json'}) - st.text_area('Response:', value=response.text, height=200, max_chars=None) - - # progress bar to show the offline ETL job running status - st.subheader('AWS Glue Job Status') - - # Initialize session state for pagination - if 'next_token' not in st.session_state: - st.session_state['next_token'] = None - - # Layout for buttons - left_col, right_col = st.columns(2) - with left_col: - refresh_button = st.button('Refresh') - - with right_col: - placeholder, prev_button, next_button = st.columns([3, 1, 1]) - with prev_button: - if st.button('Prev'): - st.session_state['next_token'] = st.session_state.get('new_prev_token') - with next_button: - if st.button('Next'): - st.session_state['next_token'] = st.session_state.get('new_next_token') - - if refresh_button or 'next_token' in st.session_state: - response, st.session_state['new_next_token'], st.session_state['new_prev_token'] = get_job_runs(st.session_state['next_token']) - # Display the running glue jobs - job_runs_container = "" - total_job_runs = len(response) - for job_run in response: - job_runs_container += (f"Job Run ID: {job_run['Id']}") - job_runs_container += (f" Retries: {job_run.get('Attempt', 'N/A')}") - job_runs_container += (f" Start Time: {job_run['StartedOn']}") - job_runs_container += (f" Duration: {job_run.get('ExecutionTime', 'N/A')} seconds\n") - st.text_area('Running AWS Glue Jobs in total: ' + str(total_job_runs), value=job_runs_container, height=200, max_chars=None) - - # Sub panel to query and search the embedding in AOS - st.subheader('Query and Search AOS') - query = st.text_input('Input your query body here', value='{"aos_index": "chatbot-index", "query": {"operation": "match_all", "match_all": {}}}') - # send button to trigger the request sending to the endpoint with query as request body - request_body = { - 'aos_index': aos_index, - 'operation': 'match_all', - 'body': '' - } - send_button = st.button('Send') - if send_button: - response = requests.get(pipeline_url + '/embedding', json=request_body, headers={'Content-Type': 'application/json'}) - st.text_area('Response:', value=response.text, height=200, max_chars=None) - -def llm_bot_tab(): - # user input box to allow user input question - st.title("LLM Bot") - query = st.text_input('Ask a question to the PDF') - # cancel button to allow user to cancel the question - cancel_button = st.button('Cancel') - if cancel_button: - st.stop() - # send button to trigger the request sending to the endpoint with query as request body - send_button = st.button('Send') - if send_button: - # request body to be sent to the endpoint - request_body = { - "model": "knowledge_qa", - "messages": [ - { - "role": "user", - "content": query - } - ], - "temperature": 0.7 - } - response = requests.post(os.getenv('PIPELINE_URL') + '/llm', json=request_body, headers={'Content-Type': 'application/json'}) - try: - data_dict = json.loads(response.text) - content = data_dict["choices"][0]["message"]["content"] - st.text_area('Response:', value=content.encode('utf-8').decode('utf-8'), height=200, max_chars=None) - except json.JSONDecodeError as e: - st.error(f"Failed to parse response as JSON: {e}") - st.text(response.text) - # data_dict = response.text.json() - # content = data_dict["choices"][0]["message"]["content"] - # st.text_area('Response:', value=content.encode('utf-8').decode('unicode_escape'), height=200, max_chars=None) - -def main(): - # Create a tab bar - st.sidebar.title("LLM Bot") - tabs = ["ETL Pipeline", "LLM Bot"] - page = st.sidebar.radio("Select a tab", tabs) - if page == "ETL Pipeline": - pipeline_tab() - elif page == "LLM Bot": - llm_bot_tab() - - # using library and OpenAI for local testing, comment for now - - # if pdf is not None: - # pdf_reader = PdfReader(pdf) - # # Text variable will store the pdf text - # text = "" - # for page in pdf_reader.pages: - # text += page.extract_text() - - # # Create the knowledge base object - # knowledgeBase = process_text(text) - - # query = st.text_input('Ask a question to the PDF') - # cancel_button = st.button('Cancel') - - # if cancel_button: - # st.stop() - - # if query: - # docs = knowledgeBase.similarity_search(query) - # llm = OpenAI() - # chain = load_qa_chain(llm, chain_type='stuff') - - # with get_openai_callback() as cost: - # response = chain.run(input_documents=docs, question=query) - # print(cost) - - # st.write(response) - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/source/panel/auto_evaluation/TechBot QA Test-fifth-test.csv b/source/panel/auto_evaluation/TechBot QA Test-fifth-test.csv deleted file mode 100644 index 4cadad4ce..000000000 --- a/source/panel/auto_evaluation/TechBot QA Test-fifth-test.csv +++ /dev/null @@ -1,937 +0,0 @@ -ref_url,ref_answer,question,answer,source,retrieval_accuracy,m1_accuracy,comment,baichuan_answer,m2_accuracy,comment,baichuan_ft_answer,m3_accuracy,comment,claude_answer,TRUE,comment,ground truth, -https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/ebs-creating-snapshot.html#ebs-create-snapshot,https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/ebs-creating-snapshot.html#ebs-create-snapshot,"要在Amazon EC2控制台中创建一个EBS卷快照,需要采取哪些步骤?","要在Amazon EC2控制台中创建一个EBS卷快照,需要采取以下步骤: 1. 打开Amazon EC2控制台,网址为:https://console.aws.amazon.com/ec2/。 2. 在导航窗格中选择 ""Snapshots""(快照)选项。 3. 选择 ""Create snapshot""(创建快照)按钮。 4. 在 ""Resource type""(资源类型)中,选择 ""Volume""(卷)。 5. 在 ""Volume ID""(卷 ID)字段中,选择您需要从中创建快照的卷。 6. (可选)在 ""Encryption""(加密)字段中,选择 ""Yes""(是)以启用加密功能。 7. (可选)在 ""Description""(描述)字段中,输入一个简短的描述。 8. (可选)如果您需要为快照添加自定义标签,请在 ""Tags""(标签)部分选择 ""Add tag""(添加标签),并输入标签信息。 通过执行以上步骤,您就可以在Amazon EC2控制台中成功创建一个EBS卷的快照。","[""https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/ebs-creating-snapshot.html"",""https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/WindowsGuide/ebs-creating-snapshot.html""]",TRUE,FALSE,从EBS Volume创建快照时,没有启用加密的选项,回答:要在Amazon EC2控制台中创建一个EBS卷快照,你需要按照以下步骤操作: 1. 登录到Amazon EC2控制台:通过https://console.aws.amazon.com/ec2/地址打开Amazon EC2控制台。 2. 寻找“Snapshots”:在导航栏中找到并点击“Snapshots”选项。 3. 选择“Create snapshot”:在页面左侧,你会看到一些选项。找到“Create snapshot”选项并点击它。 4. 选择卷:在“Resource type”下拉菜单中选择“Volume”。 5. 选择卷ID:在“Volume ID”文本框中,选择你要创建快照的EBS卷。 6. (可选)添加描述:在“Description”文本框中,输入你对这个快照的描述。 7. (可选)选择加密:如果你的卷已加密,“Encryption”文本框将显示你的加密方法。如果你的卷未加密,这个文本框将为空。 8. (可选)复制标签:如果你希望将源卷的标签复制到这个快照,勾选“Copy tags from source volume”。 9. 点击“Create snapshot”:准备好上述信息后,点击“Create snapshot”按钮。系统会创建一个新的快照并在完成后发送通知给你。,FALSE,"如果你的卷未加密,这个文本框将为""未加密""",要在Amazon EC2控制台中创建一个EBS卷快照,可以按照以下步骤进行操作: 1. 登录Amazon EC2控制台并转到“Snapshots”页面。 2. 点击“Create snapshot”按钮。 3. 在弹出的“Create snapshot”对话框中,选择“Volume”作为资源类型。 4. 选择一个需要创建快照的卷,并在“Volume ID”字段中输入卷的ID。 5. 根据需要,可以选择是否排除根卷的快照。如果需要排除根卷的快照,请在“Exclude root volume”选项前选中复选框。 6. (可选)如果希望自动将标签从源卷复制到相应的快照,请在“Copy tags from source volume”选项前选中复选框。 7. 点击“Create snapshot”按钮,开始创建快照。 这样,就可以在Amazon EC2控制台中创建一个EBS卷快照了。,FALSE,"资源类型选择""Volume ID""时没有 排除根卷 的选项","为了在Amazon EC2控制台中创建EBS卷快照,可以采取以下步骤: 1. 登录AWS管理控制台,打开EC2页面。 2. 在左侧导航栏中,选择""Elastic Block Store"" -> ""Snapshots""。 3. 点击""Create Snapshot""按钮。 4. 在""Create Snapshot""页面中,选择要创建快照的EBS卷的""Volume ID""。 5. (可选)在""Description""中输入对此快照的描述。 6. (可选)添加任何所需的标签以组织快照。 7. 点击""Create Snapshot""按钮。 8. 等待快照创建完成。快照状态会从“pending”变为“completed”。 9. 创建完成后,可以在Snapshots页面看到新创建的快照。 总结下就是: 1. 打开EC2控制台,进入Snapshots页面 2. 点击""Create Snapshot""按钮 3. 选择要备份的EBS卷 4. 添加描述和标签 5. 点击""Create Snapshot""完成创建 6. 等待快照创建完成 7. 在Snapshots页面查看新创建的快照 通过这些步骤就可以在EC2控制台中轻松创建EBS卷的快照了。",TRUE,,"1. 通过以下网址打开 Amazon EC2 控制台:https://console.aws.amazon.com/ec2/。 -2. 在导航窗格中,选择 Snapshots(快照)、Create snapshot(创建快照)。 -3. 对于 Resource type (资源类型),选择 Volume (卷)。 -4. 对于 Volume ID(卷 ID),选择需要从其创建快照的卷。Encryption(加密)字段指示所选卷的加密状态。如果选定的卷已加密,则使用相同的 KMS 密钥自动加密快照。如果选定的卷未加密,则不会对快照进行加密。 -5.(可选)对于 Description (描述),输入对快照的简短描述。 -6.(可选)要为快照分配自定义标签,请在 Tags(标签)部分选择 Add tag(添加标签),然后输入标签键和值对。您最多可以添加 50 个标签。 -7.选择 Create snapshot (创建快照)。", -https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/disaster-recovery-resiliency.html,https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/disaster-recovery-resiliency.html,Amazon EC2 提供了哪些功能来支持不同区域之间的数据恢复?,"Amazon EC2提供了以下功能来支持不同区域之间的数据恢复: 1. 跨区域复制 AMI 2. 跨区域复制 EBS 快照 3. 使用 Amazon Data Lifecycle Manager 自动化 EBS 支持的 AMI 4. 使用 Amazon Data Lifecycle Manager 自动处理 EBS 快照 5. 使用 Amazon EC2 Auto Scaling 保持队列的运行状况和可用性 6. 使用 Elastic Load Balancing 在一个或多个可用区中的多个实例之间分配传入流量 这些功能可以确保在不同的区域之间自动复制数据和应用程序,并在发生故障时快速切换到其他区域。","[""https://docs.aws.amazon.com/drs/latest/userguide/failback-failover-region-region.html"",""https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/WindowsGuide/disaster-recovery-resiliency.html""]",TRUE,TRUE,,Amazon EC2 提供了以下几种功能来支持不同区域之间的数据恢复: 1. 跨区域复制AMI(Amazon Machine Images):这允许您在发生故障时快速恢复应用程序和数据库。 2. 跨区域复制EBS(Elastic Block Store)快照:这可以帮助您在发生硬件故障时恢复数据。 3. 使用Amazon Data Lifecycle Manager自动化EBS支持的AMI:这可以帮助您自动化数据备份和恢复过程。 4. 使用Amazon Data Lifecycle Manager自动处理EBS快照:这可以帮助您自动管理数据的备份和恢复。 5. 使用Amazon EC2 Auto Scaling保持队列的运行状况和可用性:这可以帮助您在发生故障时自动扩展资源。 6. 使用Elastic Load Balancing在一个或多个可用区中的多个实例之间分配传入流量:这可以帮助您在发生故障时保持应用程序的可用性。 此外,Amazon EC2还提供了AWS Elastic Disaster Recovery(AWS DRS)服务,允许您在执行故障切换和故障回退时将基于EC2的应用程序从一个AWS区域切换到另一个AWS区域。,TRUE,,Amazon EC2 提供了以下功能来支持不同区域之间的数据恢复: 1. 跨区域复制AMI(Amazon Machine Image) 2. 跨区域复制EBS快照 3. 使用Amazon Data Lifecycle Manager自动处理EBS快照 4. 使用Amazon EC2 Auto Scaling保持队列的运行状况和可用性 5. 使用Elastic Load Balancing在一个或多个可用区中的多个实例之间分配传入流量,TRUE,,"根据背景知识,Amazon EC2 提供了以下功能来支持不同区域之间的数据恢复: - 跨区域复制AMI - 可以将AMI从一个区域复制到另一个区域,以便在发生故障时快速启动实例。 - 跨区域复制EBS快照 - 可以将EBS快照从一个区域复制到另一个区域,以便在发生故障时快速恢复数据。 - 使用Amazon Data Lifecycle Manager自动化EBS支持的AMI - 可以自动将AMI复制到另一个区域,并管理AMI的生命周期。 - 使用Amazon Data Lifecycle Manager自动处理EBS快照 - 可以自动将EBS快照复制到另一个区域,并管理快照的生命周期。 - 使用Amazon EC2 Auto Scaling保持队列的运行状况和可用性 - 可以跨多个可用区和区域保持实例的数量和状态。 - 使用Elastic Load Balancing在一个或多个可用区中的多个实例之间分配传入流量 - 可以在不同的可用区或区域进行流量分发和故障转移。 - AWS Elastic Disaster Recovery (AWS DRS) - 可以在不同的AWS区域之间进行故障转移和故障恢复。",FALSE,EC2 ASG和ELB不可跨区域,"跨区域复制 AMI -跨区域复制 EBS 快照 -使用 Amazon Data Lifecycle Manager 自动化 EBS 支持的 AMI -使用 Amazon Data Lifecycle Manager 自动处理 EBS 快照 -使用 Amazon EC2 Auto Scaling 保持队列的运行状况和可用性 -使用 Elastic Load Balancing 在一个或多个可用区中的多个实例之间分配传入流量", -https://docs.aws.amazon.com/zh_cn/AmazonECS/latest/userguide/what-is-fargate.html#weclcome-operating-system,https://docs.aws.amazon.com/zh_cn/AmazonECS/latest/userguide/what-is-fargate.html#weclcome-operating-system,请问Amazon ECS Fargate支持哪些操作系统和CPU架构?,Amazon ECS Fargate支持以下操作系统:Amazon Linux 2、Windows Server 2019 Full、Windows Server 2019 Core、Windows Server 2022 Full、Windows Server 2022 Core。 当在Fargate上运行Windows容器时,需要使用X86_64 CPU架构。 当在Fargate上运行Linux容器时,可以使用X86_64 CPU架构或ARM64架构用于基于ARM的应用程序。,"[""https://docs.aws.amazon.com/zh_cn/AmazonECS/latest/userguide/what-is-fargate.html"",""https://docs.aws.amazon.com/zh_cn/AmazonECS/latest/userguide/AWS_Fargate-Regions.html""]",TRUE,TRUE,,Amazon ECS Fargate支持多种操作系统和CPU架构。对于Linux容器,支持的操作系统包括Amazon Linux 2、Windows Server 2019 Full、Windows Server 2019 Core、Windows Server 2022 Full和Windows Server 2022 Core。支持的CPU架构有ARM和X86_64。 对于Windows容器,仅支持Windows Server 2019 Full和Windows Server 2019 Core,且必须为X86_64 CPU架构。,FALSE,,Amazon ECS Fargate支持多种操作系统和CPU架构,包括: - Linux: Amazon Linux 2、Ubuntu、Debian - Windows: Windows Server 2019 Full、Windows Server 2019 Core、Windows Server 2022 Full、Windows Server 2022 Core 对于CPU架构,Fargate支持X86_64和ARM64。,FALSE,,"根据背景知识,Amazon ECS Fargate支持以下操作系统: - Amazon Linux 2 - Windows Server 2019 Full - Windows Server 2019 Core - Windows Server 2022 Full - Windows Server 2022 Core 支持以下两种CPU架构: - ARM - X86_64 当在Fargate上运行Windows容器时,必须使用X86_64 CPU架构。 当在Fargate上运行Linux容器时,可以使用X86_64 CPU架构,也可以使用ARM64架构用于基于ARM的应用程序。 所以综上,Amazon ECS Fargate支持Amazon Linux 2、Windows Server 2019和2022这些操作系统,支持X86_64和ARM64这两种CPU架构,但Windows容器只能使用X86_64架构。",TRUE,,"Amazon ECS Fargate支持以下操作系统: - - -- Amazon Linux 2 -- Windows Server 2019 Full -- Windows Server 2019 Core -- Windows Server 2022 Full -- Windows Server 2022 Core - - -支持以下两种CPU架构: - - -- ARM -- X86_64 - - -当在Fargate上运行Windows容器时,必须使用X86_64 CPU架构。 - - -当在Fargate上运行Linux容器时,可以使用X86_64 CPU架构,也可以使用ARM64架构用于基于ARM的应用程序。 - - -所以综上,Amazon ECS Fargate支持Amazon Linux 2、Windows Server 2019和2022这些操作系统,支持X86_64和ARM64这两种CPU架构,但Windows容器只能使用X86_64架构。", -https://docs.aws.amazon.com/zh_cn/athena/latest/ug/when-should-i-use-ate.html,https://docs.aws.amazon.com/zh_cn/athena/latest/ug/when-should-i-use-ate.html,Amazon Athena 可以帮助分析什么类型的数据?Athena 与哪些 AWS 服务集成?Athena 的主要优点是什么?,"Amazon Athena 可以帮助分析在 Amazon S3 中存储的非结构化、半结构化和结构化数据,如 CSV、JSON 或列式数据格式,如 Apache Parquet 和 Apache ORC。 Athena 与 Amazon QuickSight 集成,轻松实现数据可视化。您可以使用 Athena 生成报表,或借助商业智能工具或 SQL 客户端浏览数据。 Athena 与 AWS Glue Data Catalog 集成,后者为您在 Amazon S3 中的数据提供了持久元数据存储。这使您可以根据在您的整个 Amazon Web Services 账户中可用并与 AWS Glue 的 ETL 和数据发现功能集成在一起的中央元数据存储来创建表和在 Athena 中查询数据。 Amazon Athena 可以与 Amazon Redshift 集成。当您需要将来自许多不同源(例如库存系统、财务系统和零售销售系统)的数据汇集到通用格式并长时间存储时,Amazon Redshift 是理想选择。如果您需要根据历史数据构建复杂的业务报告,则建议选择 Amazon Redshift。 Athena 的主要优点是它是一个交互式的查询服务,让您可以直接使用标准 SQL 分析 Amazon S3 中的数据,无需进行数据格式转换或基础设施管理。它还与 AWS 的其他服务如 QuickSight 和 Glue 集成,方便数据可视化和大数据分析。","[""https://docs.aws.amazon.com/zh_cn/athena/latest/ug/when-should-i-use-ate.html"",""https://docs.aws.amazon.com/zh_cn/athena/latest/ug/what-is.html""]",TRUE,TRUE,,Amazon Athena 可以帮助分析在 Amazon S3 中存储的非结构化、半结构化和结构化数据。它与 Amazon QuickSight 集成,轻松实现数据可视化,并与 AWS Glue Data Catalog 集成,为您的数据提供持久元数据存储。 Athena 与以下 AWS 服务集成: 1. Amazon S3:Athena 可以直接在 Amazon S3 中对数据运行交互式查询。 2. Amazon QuickSight:Athena 可以与 Amazon QuickSight 集成,轻松实现数据可视化。 3. AWS Glue Data Catalog:Athena 与 AWS Glue Data Catalog 集成,后者为您在 Amazon S3 中的数据提供了持久元数据存储。 4. Amazon EMR:Athena 可以与亚马逊弹性地图(Amazon EMR)集成,后者是一个完全托管的 Hadoop 和 Spark 服务,可以轻松地在 Amazon EMR 上运行 Athena 查询。 5. Amazon Redshift:虽然 Athena 不能与 Amazon Redshift 集成,但它可以用于查询已存储在 Amazon Redshift 中的数据。,TRUE,,Amazon Athena 可以帮助分析非结构化、半结构化和结构化的数据,这些数据可以存储在 Amazon S3 中。Athena 可以与多种 AWS 服务集成,其中包括 Amazon QuickSight、AWS Glue 数据目录和 AWS Lambda 等。 Athena 的主要优点包括: 1. 提供了一种便捷的方式来在 Amazon S3 中运行交互式查询,无需管理任何基础设施或集群; 2. 支持标准 SQL 语法,可以轻松地进行数据分析; 3. 与 AWS 其他服务集成,方便进行数据分析和数据可视化; 4. 支持多种数据格式,包括 CSV、JSON、Parquet 和 ORC 等; 5. 提供高性能和高可用性,可以快速获取查询结果; 6. 提供自动扩展功能,可以在处理大规模数据时自动并行执行查询。,TRUE,,"根据背景知识,可以总结出: - Amazon Athena 可以帮助分析存储在Amazon S3中的非结构化、半结构化和结构化数据,例如CSV、JSON或列式数据格式如Apache Parquet和Apache ORC。 - Athena 与以下AWS服务集成: - AWS Glue Data Catalog - 提供元数据存储 - Amazon QuickSight - 数据可视化 - AWS Glue - ETL和数据发现 - Athena 的主要优点: - 可以直接在S3上运行交互式SQL查询,无需格式化数据或管理基础设施 - 自动扩展,可以快速查询大数据集和复杂查询 - 无服务器,只需为运行的查询付费 综上,Athena可以分析多种格式的S3数据,并与多种AWS服务集成,其主要优点是可以无服务器快速查询S3大数据。",TRUE,,"- Amazon Athena 可以帮助分析存储在Amazon S3中的非结构化、半结构化和结构化数据,例如CSV、JSON或列式数据格式如Apache Parquet和Apache ORC。 - - -- Athena 与以下AWS服务集成: - - AWS Glue Data Catalog - 提供元数据存储 - - Amazon QuickSight - 数据可视化 - - AWS Glue - ETL和数据发现 - - -- Athena 的主要优点: - - 可以直接在S3上运行交互式SQL查询,无需格式化数据或管理基础设施 - - 自动扩展,可以快速查询大数据集和复杂查询 - - 无服务器,只需为运行的查询付费 - - -综上,Athena可以分析多种格式的S3数据,并与多种AWS服务集成,其主要优点是可以无服务器快速查询S3大数据。", -https://docs.aws.amazon.com/zh_cn/quicksight/latest/user/supported-data-sources.html,https://docs.aws.amazon.com/zh_cn/quicksight/latest/user/supported-data-sources.html,亚马逊QuickSight支持哪些关系型数据源?我应该如何选择适合我的案例的数据源?,亚马逊QuickSight支持以下关系型数据源: 1. Amazon Athena 2. Amazon Aurora 3. 亚马逊 OpenSearch 服务 4. Amazon Redshift 5. Amazon Redshift Spectrum 6. Amazon S3 7. 亚马逊 S3 分析 8. Apache Spark 2.0 或更高版本 9. AWS IoT Analytics 10. Spark 1.6 或更高版本上的 Databricks 仅限 E2 平台,最高版本 3.0 11. Exasol 7.1.2 或更高版本 12. MariaDB 10.0 或更高版本 13. Microsoft SQL Server 2012 或更高版本 14. MySQL 5.1 或更高版本 15. 甲骨文 12c 或更高版本 16. PostgreSQL 9.3.1 或更高版本 17. Presto 0.167 或更高版本 18. Snowflake 19. 星爆 20. Trino 21. Teradata 14.0 或更高版本 22. Timestream 根据您的需求和数据源的特性,选择适合的源。您可能要选择支持您正在使用的数据存储和处理方式的数据源,例如Amazon Aurora、Amazon Redshift、Amazon S3、MariaDB等。您也可以根据数据的格式,例如CSV、JSON、ELF等,选择适当的格式。另外,您还可以考虑数据量的大小、数据访问速度和数据安全性等因素来做出最终选择。,"[""https://docs.aws.amazon.com/zh_cn/quicksight/latest/user/supported-data-sources.html"",""https://docs.aws.amazon.com/zh_cn/quicksight/latest/APIReference/API_DataSourceParameters.html""]",TRUE,TRUE,,亚马逊QuickSight支持多种关系型数据源,包括Amazon Athena、Amazon Aurora、Amazon OpenSearch Service、Amazon Redshift、Amazon Redshift Spectrum、Amazon S3、Amazon S3 Analytics、Apache Spark 2.0或更高版本、AWS IoT Analytics、Databricks(仅限E2平台,最高版本3.0)、Exasol 7.1.2或更高版本、MariaDB 10.0或更高版本、Microsoft SQL Server 2012或更高版本、MySQL 5.1或更高版本、Oracle 12c或更高版本、PostgreSQL 9.3.1或更高版本、Presto 0.167或更高版本、Snowflake、Starburst、Trino和Teradata 14.0或更高版本。 在选择适合您的案例的数据源时,您需要考虑以下几个因素: 1. 数据量和类型:不同的数据源处理不同类型和大小的数据的能力不同。例如,Amazon Redshift和Amazon Aurora非常适合处理大型数据集,而Amazon Athena和Amazon S3更适合处理较小的数据集。 2. 数据更新频率:某些数据源支持实时或接近实时数据更新,而其他数据源可能只支持定期更新。例如,Amazon Redshift和Amazon S3 Analytics支持定期数据加载,而Amazon Athena和Amazon OpenSearch Service支持实时数据分析。 3. 数据安全性:根据您的数据敏感性和合规性要求,您可能需要选择一个提供适当安全性和加密选项的数据源。例如,Amazon Redshift和Amazon S3 Analytics都支持服务器侧加密,而Amazon Athena和Amazon OpenSearch Service都支持数据源端加密。 4. 与QuickSight的兼容性:确保您选择的数据源与QuickSight兼容,并且可以轻松地将其添加为数据源。这可能需要查看QuickSight的文档或与亚马逊的支持团队联系以确认。 5. 成本:评估每个数据源的成本,包括数据存储、数据处理和数据传输成本。这可能会影响您的预算和决策。 总之,在选择适合您的案例的数据源时,您需要权衡这些因素并根据您的具体需求和约束进行选择。,TRUE,,亚马逊QuickSight支持多种关系型数据源,包括但不限于以下几种: - Amazon Athena - Amazon Aurora - 亚马逊 OpenSearch 服务 - Amazon Redshift - Amazon Redshift Spectrum - Amazon S3 - 亚马逊 S3 分析 - Apache Spark 2.0 或更高版本 - AWS IoT Analytics - Spark 1.6 或更高版本上的 Databricks(仅限 E2 平台),最高版本 3.0 - Exasol 7.1.2 或更高版本 - MariaDB 10.0 或更高版本 - Microsoft SQL Server 2012 或更高版本 - MySQL 5.1 或更高版本 - 甲骨文 12c 或更高版本 - PostgreSQL 9.3.1 或更高版本 - Presto 0.167 或更高版本 - Snowflake - 星爆 - Trino - Teradata 14.0 或更高版本 - Timestream 在选择适合你的案例的数据源时,你需要考虑以下几个因素: 1. 数据源的可用性:不同的数据源可能在不同的时间和地点可用性不同,因此你需要确保你选择的数据源在你的使用场景下是可靠的。 2. 数据源的性能:不同的数据源可能具有不同的性能特性,比如查询速度、吞吐量和可扩展性等。你需要根据你的应用场景来选择合适的数据源。 3. 数据源的安全性:数据源的安全级别和提供的保护措施也是需要考虑的因素。你需要确保你所选择的数据源能够满足你对数据安全和隐私的需求。 4. 数据源的成本:不同的数据源可能有不同的成本结构,比如使用费用、存储费用和查询费用等。你需要根据自己的预算来选择合适的数据源。 综上所述,你需要根据具体的业务需求和数据特点来选择合适的数据源。你可以先了解各个数据源的特点和适用范围,然后根据实际情况做出决策。,TRUE,,"根据背景知识,Amazon QuickSight 支持各种关系型数据源,包括: - Amazon Athena - Amazon Aurora - Amazon Redshift - Amazon Redshift Spectrum - Amazon S3 - Apache Spark - AWS IoT Analytics - Databricks - Exasol - MariaDB - Microsoft SQL Server - MySQL - Oracle - PostgreSQL - Presto - Snowflake - Teradata - Trino 选择合适的数据源要考虑以下几个方面: - 数据存储位置 - 如果数据存储在AWS上(如S3、Redshift等),通常选择AWS原生数据源会更方便。 - 数据格式 - 每种数据源对数据格式(如CSV、JSON等)的支持不太一样,选择对你的数据格式支持更友好的数据源。 - 数据规模 - 对大数据量的支持,可以选择Spark、Redshift等大数据源。 - 成本 - 不同的数据源有不同的费用模式,选择成本更低的数据源。 - 易用性 - 一些数据源的连接和使用更简单。 - 功能 - 部分数据源支持的功能更多,如复杂的SQL查询等。 综合考虑这些因素,选择对自己的业务场景最合适,既能满足技术需求,也符合成本预期的数据源。可以从简单的开始,评估使用后再考虑更换其他数据源。",TRUE,,"Amazon QuickSight 支持各种关系型数据源,包括: - - -- Amazon Athena -- Amazon Aurora -- Amazon Redshift -- Amazon Redshift Spectrum -- Amazon S3 -- Apache Spark -- AWS IoT Analytics -- Databricks -- Exasol -- MariaDB -- Microsoft SQL Server -- MySQL -- Oracle -- PostgreSQL -- Presto -- Snowflake -- Teradata -- Trino - - -选择合适的数据源要考虑以下几个方面: - - -- 数据存储位置 - 如果数据存储在AWS上(如S3、Redshift等),通常选择AWS原生数据源会更方便。 -- 数据格式 - 每种数据源对数据格式(如CSV、JSON等)的支持不太一样,选择对你的数据格式支持更友好的数据源。 -- 数据规模 - 对大数据量的支持,可以选择Spark、Redshift等大数据源。 -- 成本 - 不同的数据源有不同的费用模式,选择成本更低的数据源。 -- 易用性 - 一些数据源的连接和使用更简单。 -- 功能 - 部分数据源支持的功能更多,如复杂的SQL查询等。 - - -综合考虑这些因素,选择对自己的业务场景最合适,既能满足技术需求,也符合成本预期的数据源。可以从简单的开始,评估使用后再考虑更换其他数据源。", -https://docs.aws.amazon.com/zh_cn/redshift/latest/mgmt/serverless-capacity.html#serverless-rpu-capacity,https://docs.aws.amazon.com/zh_cn/redshift/latest/mgmt/serverless-capacity.html#serverless-rpu-capacity,请问 Amazon Redshift Serverless 的基本容量默认设置是多少 RPU?最低容量是多少?,Amazon Redshift Serverless 的基本容量默认设置是128个RPU,而最低容量是8个RPU。,"[""https://docs.aws.amazon.com/zh_cn/redshift/latest/mgmt/serverless-considerations.html"",""https://docs.aws.amazon.com/zh_cn/redshift/latest/mgmt/serverless-capacity.html""]",TRUE,TRUE,,根据提供的文章,Amazon Redshift Serverless的基本容量默认设置是128个RPU。最低容量为8个RPU。,TRUE,,Amazon Redshift Serverless 的默认基本容量是 128 个 RPU。最低容量是 8 个 RPU。,TRUE,,"根据背景知识,Amazon Redshift Serverless 的基本容量默认设置是128个RPU。 最低容量是8个RPU。",TRUE,,Amazon Redshift Serverless 的基本容量默认设置是128个RPU。 最低容量是8个RPU。, -https://docs.aws.amazon.com/zh_cn/AmazonECS/latest/userguide/using_data_volumes.html,https://docs.aws.amazon.com/zh_cn/AmazonECS/latest/userguide/using_data_volumes.html,Amazon ECS on Fargate支持哪些容器的数据卷选项?,Amazon ECS on Fargate支持以下容器的数据卷选项: 1. Amazon EFS卷:提供简单的可扩展和持久的文件存储供您的Amazon ECS任务使用。存储容量是弹性的,会随着文件添加和删除而自动增加和缩减。您的应用程序可以在需要时获得所需存储。 2. 绑定挂载:主机上的文件或目录,例如AWS Fargate挂载到容器中。绑定装载主机卷在Fargate上使用短暂存储。在不同的Fargate平台版本上,短暂存储容量会有所不同。您可以在Fargate Linux平台版本1.4.0或更高版本请求高达200 GiB短暂存储。有关更多信息,请参阅绑定挂载。 请注意,以上回答是基于给定的知识资源,如果有任何错误或遗漏,请联系AWS解决方案团队进行更正。,"[""https://docs.aws.amazon.com/zh_cn/AmazonECS/latest/developerguide/AWS_Fargate-Regions.html"",""https://docs.aws.amazon.com/zh_cn/AmazonECS/latest/userguide/using_data_volumes.html""]",TRUE,TRUE,,Amazon ECS on Fargate支持以下容器的数据卷选项: 1. Amazon EFS卷——提供简单的可扩展和持久的文件存储以供您的Amazon ECS任务使用。在使用Amazon EFS时,存储容量是弹性的,会随着您添加和删除文件而自动增加和缩减。 2. 绑定挂载——主机上的文件或目录,例如AWS Fargate挂载到容器中。绑定装载主机卷在Fargate上使用短暂存储。在不同的Fargate平台版本上,短暂存储容量会有所不同。 3. Fargate任务短暂存储——预置后,AWS Fargate上的Linux容器上托管的每个Amazon ECS任务都会收到绑定挂载的以下短暂存储。可在任务定义中使用volumes、mountPoints和volumesFrom参数在容器之间挂载和共享此存储。AWS Fargate上的Windows容器不支持此选项。,FALSE,Fargate任务短暂存储就是绑定挂载,Amazon ECS on Fargate支持以下容器的数据卷选项: - Amazon EFS 卷:提供简单的可扩展和持久的文件存储以供您的 Amazon ECS 任务使用。 - 绑定挂载:主机上的文件或目录,例如 AWS Fargate挂载到容器中。,TRUE,,"Amazon ECS on Fargate 支持以下容器的数据卷选项: - Amazon EFS 卷 - 提供简单的可扩展和持久的文件存储,用于 Fargate 任务。存储容量会自动扩展。 - 绑定挂载 - 将主机上的文件或目录挂载到 Fargate 容器中。这是一种短暂存储,量取决于 Fargate 平台版本。在 1.4.0 或更高版本中,默认为 20GB,最高可达 200GB。 - 对于 Linux 容器,1.4.0 或更高版本的平台会对临时存储进行加密。1.3.0 或更低版本有 10GB 的 Docker 层存储和 4GB 的卷挂载存储。 - 对于 Windows 容器,1.0.0 或更高版本的平台具有默认 20GB,最高 200GB 的临时存储。 所以简而言之,Fargate 支持 EFS 卷、绑定挂载以及基于平台版本的临时存储这些容器数据卷选项。",TRUE,,"Fargate 上的 Amazon ECS支持以下容器的数据卷选项。 -Amazon EFS 卷——提供简单的可扩展和持久的文件存储以供您的 Amazon ECS 任务使用。使用 Amazon EFS 时,存储容量是弹性的。它会随着您添加和删除文件而自动增加和缩减。您的应用程序可在需要时获得所需存储。有关更多信息,请参阅Amazon EFS 卷。 -绑定挂载——主机上的文件或目录,例如 AWS Fargate挂载到容器中。绑定装载主机卷在 Fargate 上使用短暂存储。在不同的 Fargate 平台版本上,短暂存储容量会有所不同。您可以在 Fargate Linux 平台版本 1.4.0 或更高版本请求高达 200 GiB 短暂存储。有关更多信息,请参阅绑定挂载。", -https://docs.aws.amazon.com/zh_cn/AmazonECS/latest/userguide/create-container-image.html#create-container-image-push-ecr,https://docs.aws.amazon.com/zh_cn/AmazonECS/latest/userguide/create-container-image.html#create-container-image-push-ecr,如何将镜像推送到 Amazon Elastic Container Registry?,要将镜像推送到Amazon Elastic Container Registry (Amazon ECR),您需要执行以下步骤: 1. 确保您具有适当的IAM权限。您需要具有ecr:CompleteLayerUpload、ecr:GetAuthorizationToken、ecr:UploadLayerPart、ecr:InitiateLayerUpload、ecr:BatchCheckLayerAvailability和ecr:PutImage等操作的权限。 2. 使用Docker CLI或首选的客户端,将您的镜像推送到Amazon ECR。您可以使用以下命令来推送镜像: ``` docker push : ``` 其中,是您要推送到Amazon ECR的存储库名称,是您为镜像指定的标签。 3. 如果您需要推送到特定存储库,请指定完整的Amazon资源名称(ARN)作为Resource部分。例如: ``` docker push : ``` 请确保替换为实际的ARN和标签。 请注意,您需要将容器映像推送到Amazon ECR,以便在Amazon ECS或Amazon EKS等Amazon容器服务中使用。,"[""https://docs.aws.amazon.com/zh_cn/AmazonECR/latest/userguide/images.html"",""https://docs.aws.amazon.com/zh_cn/AmazonECR/latest/userguide/image-push.html""]",TRUE,FALSE,,要将镜像推送到 Amazon Elastic Container Registry (Amazon ECR),您需要执行以下步骤: 1. 首先,确保您已安装 Docker 和 Docker CLI。然后,创建一个 Amazon ECR 账户。如果您还没有 AWS 账户,请先创建一个。 2. 登录到您的 AWS 账户并创建一个新的 Amazon ECR 仓库。您可以通过运行 `AWS_REGION=$(aws configure get region) docker run -d --name myecrrepo \ amazon/ecr-show-repos $AWS_REGION my-repository` 命令来完成此操作。这将创建一个名为 my-repository 的新仓库。 3. 准备要推送的镜像。确保您已经构建并完成镜像。如果尚未完成,请使用 `docker image build` 命令构建镜像。 4. 连接到 Amazon ECR。使用以下命令将您的 AWS 凭据提供给 Docker:`AWS_ACCESS_KEY_ID=$(aws configure get aws_access_key_id) \ AWS_SECRET_ACCESS_KEY=$(aws configure get aws_secret_access_key) \ AWS_SECURITY_TOKEN=$(aws configure get aws_session_token) \ AWS_REGION=$(aws configure get region) docker login -r my-repository $AWS_REGION \ ecr.amazonaws.com`。 5. 将镜像推送到 Amazon ECR。使用 `docker image push` 命令将镜像推送到 Amazon ECR。例如:`docker image push -a always \ localhost:5000/my-repository/my-image:latest localhost:5000/my-repository/my-image:v1`。这将在版本 v1 上推送最新的 my-image。 6. 如果您想将镜像推送到特定的存储库,可以更改 `docker image push` 命令中的仓库名称。例如:`docker image push -a always \ localhost:5000/my-repository2/my-image:latest localhost:5000/my-repository2/my-image:v1`。 遵循这些步骤,您应该能够将镜像成功推送到 Amazon ECR。,FALSE,,要将镜像推送到 Amazon Elastic Container Registry,您可以按照以下步骤操作: 1. 首先,确保您已经创建了一个 Amazon Elastic Container Registry 存储库并已启用镜像传输。 2. 使用 Docker CLI 或其他支持的客户端工具,将镜像导出为 tarball 文件。例如,使用以下命令将 Docker 镜像导出为 tarball 文件: ```bash docker save -o .tar : ``` 其中,`` 是输出的 tarball 文件名,`:` 是您要导出的镜像名称和标签。 3. 将 tarball 文件上传到 Amazon S3 或其他支持的对象存储服务。 4. 使用 Amazon ECR API 或其他支持的客户端工具,将 tarball 文件导入到 Amazon Elastic Container Registry 存储库中。例如,使用以下命令将 tarball 文件导入到 Amazon Elastic Container Registry 存储库中: ```bash aws ecr put-image --region --repository-name --image-tag --file ``` 其中,`` 是 Amazon Elastic Container Registry 所在的地域,`` 是您的存储库名称,`` 是您要使用的标签,`` 是您的 tarball 文件在 Amazon S3 中的路径。 5. 如果需要,您还可以使用其他 Amazon Elastic Container Registry 提供的功能,如镜像签名、查看镜像详细信息、提取镜像等。 希望这些信息对您有所帮助!,FALSE,,"要将镜像推送到 Amazon Elastic Container Registry (Amazon ECR),您需要执行以下步骤: 1. 使用 AWS CLI 获取授权登录 Amazon ECR 所需的授权令牌。 ```bash aws ecr get-login-password --region | docker login --username AWS --password-stdin .dkr.ecr..amazonaws.com ``` 2. 使用 docker tag 命令为镜像添加标签,格式为 .dkr.ecr..amazonaws.com/repository:tag。 ```bash docker tag myimage:latest .dkr.ecr..amazonaws.com/myrepository:latest ``` 3. 使用 docker push 命令将镜像推送到 Amazon ECR 存储库。 ```bash docker push .dkr.ecr..amazonaws.com/myrepository:latest ``` 这将授权登录到您的 Amazon ECR 注册表,为镜像添加正确的存储库和标签,然后将其推送到指定的存储库中。 另请注意,您需要具有适当的 IAM 权限才能推送镜像。通常情况下,您至少需要 ecr:GetAuthorizationToken 和 ecr:BatchCheckLayerAvailability、ecr:InitiateLayerUpload、ecr:UploadLayerPart、ecr:CompleteLayerUpload、ecr:PutImage 权限。",TRUE,,"要将镜像推送到 Amazon Elastic Container Registry (Amazon ECR),您需要执行以下步骤: - - - - -1. 使用 AWS CLI 获取授权登录 Amazon ECR 所需的授权令牌。 - - - - -```bash -aws ecr get-login-password --region | docker login --username AWS --password-stdin .dkr.ecr..amazonaws.com -``` - - -2. 如果在要推送的注册表中还没有您的镜像存储库,请创建它。 - - -3. 使用 docker tag 命令为镜像添加标签,格式为 .dkr.ecr..amazonaws.com/repository:tag。 - - - - -```bash -docker tag myimage:latest .dkr.ecr..amazonaws.com/myrepository:latest -``` - - - - -4. 使用 docker push 命令将镜像推送到 Amazon ECR 存储库。 - - - - -```bash -docker push .dkr.ecr..amazonaws.com/myrepository:latest -``` - - - - -这将授权登录到您的 Amazon ECR 注册表,为镜像添加正确的存储库和标签,然后将其推送到指定的存储库中。 - - - - -另请注意,您需要具有适当的 IAM 权限才能推送镜像。通常情况下,您至少需要 ecr:GetAuthorizationToken 和 ecr:BatchCheckLayerAvailability、ecr:InitiateLayerUpload、ecr:UploadLayerPart、ecr:CompleteLayerUpload、ecr:PutImage 权限。", -https://docs.aws.amazon.com/zh_cn/eks/latest/userguide/eks-deployment-options.html,https://docs.aws.amazon.com/zh_cn/eks/latest/userguide/eks-deployment-options.html,Amazon EKS提供了哪些主要的部署选项?请概述每种选项的关键特征。,Amazon EKS提供了以下主要的部署选项: 1. 云中的Amazon EKS:在AWS云中运行Kubernetes,无需安装、操作和维护自己的Kubernetes控制面板或节点。用户可以在AWS云中直接使用Amazon EKS来管理和部署Kubernetes集群。 2. Amazon EKS on Outposts:AWS Outposts在本地设施中启用本机AWS服务、基础设施和操作模型。通过Amazon EKS on Outposts,用户可以选择在本地运行集群或扩展集群,其中Kubernetes控制面板在AWS区域中运行,而节点在Outposts上运行。 3. Amazon EKS Anywhere:Amazon EKS Anywhere是在本地轻松创建和操作Kubernetes集群的选项。用户可以在本地使用Amazon EKS Anywhere来创建和管理Kubernetes集群,而不需要担心底层基础设施的维护和操作。 4. Amazon EKS Distro:Amazon EKS Distro是在云中部署的相同开源Kubernetes软件和依赖项的发行版。它遵循与Amazon EKS相同的Kubernetes版本发布周期,并作为开源项目提供。用户可以使用Amazon EKS Distro来部署和管理Kubernetes集群。 在选择部署选项时,用户需要考虑以下因素:硬件、部署位置、Kubernetes控制面板位置、Kubernetes数据面板位置以及支持。其中,硬件方面,用户可以选择AWS提供的硬件,也可以选择由自己提供的硬件。部署位置方面,用户可以选择在AWS云中直接部署,也可以在自己的数据中心中部署。Kubernetes控制面板位置、Kubernetes数据面板位置和支持的可用性取决于选择的选项。 以上是对Amazon EKS提供的部署选项的关键特征的概述。请注意,以上回答基于给定的知识资源,如有需要,请随时联系AWS解决方案团队以获取更详细和准确的信息。,"[""https://docs.aws.amazon.com/zh_cn/eks/latest/userguide/eks-deployment-options.html"",""https://docs.aws.amazon.com/zh_cn/eks/latest/userguide/common-use-cases.html""]",TRUE,FALSE,,Amazon EKS提供了以下几种主要的部署选项: 1. 云中的Amazon EKS:这是最常见的部署选项,它允许用户在AWS云中运行Kubernetes集群,而无需安装、操作和维护自己的Kubernetes控制面板或节点。这种选项的优势在于,用户可以充分利用AWS的服务和资源,如Elastic Load Balancing、AWS Cloud Map等,以实现高度可用的应用程序和弹性系统。 2. Amazon EKS on Outposts:这是一种特殊的部署选项,允许用户在本地设施中运行AWS服务、基础设施和操作模型。用户可以选择在Outposts上运行扩展集群或本地集群。这种选项的优势在于,它提供了在本地环境中运行Kubernetes集群的能力,同时仍然可以利用AWS的服务和资源。 3. Amazon EKS Anywhere:这是一种允许用户在本地基础设施上运行Kubernetes集群的部署选项。这种选项的优势在于,它实现了在本地环境中一致部署和管理应用程序的能力,同时仍然可以利用AWS的服务和资源。 4. Amazon EKS Distro:这是一种基于开源Kubernetes软件和依赖项的部署选项。用户可以在本地或云端部署和使用Amazon EKS Distro。这种选项的优势在于,它提供了一个与Amazon EKS兼容的开源解决方案,使得用户可以根据自己的需求和环境选择合适的部署方式。,TRUE,,Amazon EKS提供了多种主要的部署选项,包括: 1. 云中的Amazon EKS: 在AWS云中运行Kubernetes,无需自己安装、操作和维护Kubernetes控制面板或节点。 2. Amazon EKS on Outposts: 在本地设施中启用本地AWS服务、基础设施和操作模型,可以选择运行扩展集群或本地集群。 3. Amazon EKS Anywhere: 在本地轻松创建和操作Kubernetes集群,适用于本地数据中心。 4. Amazon EKS Distro: 基于开源Kubernetes软件和依赖项的发行版,可用于本地数据中心。 每种选项都有不同的关键特征,包括硬件、部署位置、Kubernetes控制面板位置以及支持和兼容性等方面的不同特点。,TRUE,,"Amazon EKS 提供了以下主要的部署选项: 1. 云中的Amazon EKS - 在AWS云中运行Kubernetes,无需安装和维护自己的Kubernetes控制面板和节点。 - Kubernetes控制面板托管在AWS云中,节点托管在AWS云计算资源上。 2. Amazon EKS on Outposts - 在本地AWS Outposts上运行Kubernetes集群。 - 支持扩展集群(控制面板在AWS云中,节点在Outpost上)和本地集群(完全在Outpost上运行)。 3. Amazon EKS Anywhere - 在本地数据中心运行Kubernetes集群。 - Kubernetes控制面板和节点都托管在本地环境中。 4. Amazon EKS Distro - Amazon EKS对应的开源Kubernetes发行版。 - 完全自行在本地环境中部署和维护Kubernetes集群。 主要差异在于Kubernetes控制面板和节点的托管位置,以及是否由AWS提供底层基础设施。需要根据应用程序的部署需求选择最合适的选项。",TRUE,,"可以使用以下任一选项部署 Amazon EKS: -1.云中的 Amazon EKS: 您可以在 AWS 云中运行 Kubernetes,而无需安装、操作和维护自己的 Kubernetes 控制面板或节点。本指南将介绍此选项。 -2.Amazon EKS on Outposts: AWS Outposts 在本地设施中启用本机 AWS 服务、基础设施和操作模型。借助 Amazon on Outposts,您可以选择运行扩展集群或本地集群。借助扩展集群,Kubernetes 控制面板在 AWS 区域 中运行,而节点在 Outposts 上运行。借助本地集群,整个 Kubernetes 集群在 Outpost 上本地运行,包括 Kubernetes 控制面板和节点。有关更多信息,请参阅AWS Outposts 上的 Amazon EKS。 -3.Amazon EKS Anywhere: Amazon EKS Anywhere 是 Amazon EKS 的部署选项,使您能够在本地轻松创建和操作 Kubernetes 集群。Amazon EKS 和 Amazon EKS Anywhere 都是基于 Amazon EKS Distro 构建的。要了解有关 Amazon EKS Anywhere 及其与 Amazon EKS 的区别的更多信息,请参阅 Amazon EKS Anywhere 文档中的概览和将 Amazon EKS Anywhere 与 Amazon EKS 比较。有关一些常见问题的答案,请参阅 Amazon EKS Anywhere 常见问题。 -4.Amazon EKS Distro:Amazon EKS Distro 是 Amazon EKS 在云中部署的相同开源 Kubernetes 软件和依赖项的发行版。Amazon EKS Distro 遵循与 Amazon EKS 相同的 Kubernetes 版本发布周期,并作为开源项目项目提供。要了解更多信息,请参阅 Amazon EKS Distro。您还可以在 GitHub 上查看和下载 Amazon EKS Distro 的源代码。", -https://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/UserGuide/USER_PIT.html,https://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/UserGuide/USER_PIT.html,如何将RDS数据库实例还原到指定时间点?,将RDS数据库实例还原到指定时间点的步骤如下: 1. 在AWS管理控制台中,导航到“创建RFC”页面。 2. 在“选择CT”部分,选择“ct-2uimt36z7j6vn”作为Change Type。 3. 在“创建RFC”页面上,选择“当前版本”为1.0。 4. 在“执行时间”中,指定360分钟。 5. 在“AWS审批”和“客户审批”选项中,确保勾选“是”。 6. 在“执行模式”中,选择“自动”。 7. 点击“创建RFC”开始创建RFC。 创建RFC后,您将收到一个成功的消息,并可以在“当前RFC”页面上查看执行的状态。您还可以使用“运行参数”部分来查看和更新RFC的配置。 请注意,此回答基于提供的知识资源,并假设您已经具有适当的权限和访问权限来执行上述步骤。如有任何疑问或需要进一步的帮助,请联系AWS解决方案团队。,"[""https://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/UserGuide/USER_PIT.html"",""https://docs.aws.amazon.com/managedservices/latest/ctref/management-advanced-rds-database-stack-restore-to-point-in-time.html""]",TRUE,FALSE,匹配到了两个文档,但是模型似乎选择了不太相关的文档知识去回答,"要将Amazon RDS数据库实例还原到指定时间点,您可以使用AWS Management Console、AWS CLI或RDS API。以下是使用CLI和API的步骤: **使用AWS CLI:** 1. 安装并运行AWS CLI。 2. 选择要还原的数据库实例所在的区域。 3. 使用`restore-db-instance-to-point-in-time`命令。 示例命令: ``` aws rds restore-db-instance-to-point-in-time \ --source-db-instance-identifier \ --target-db-instance-identifier \ --restore-time \ --allocated-storage \ --max-allocated-storage ``` 在这个命令中,将`<>`符号替换为实际值。例如: ``` aws rds restore-db-instance-to-point-in-time \ --source-db-instance-identifier source-db-instance \ --target-db-instance-identifier target-db-instance \ --restore-time 2017-10-14T23:45:00.000Z \ --allocated-storage 100 \ --max-allocated-storage 1000 ``` **使用RDS API:** 1. 注册并设置RDS API终结点。 2. 使用`RestoreDBInstanceToPointInTime`操作。 示例请求: ``` { ""DBInstanceIdentifier"": """", ""SourceDBInstanceIdentifier"": """", ""RestoreTime"": ""2017-10-14T23:45:00.000Z"", ""AllocatedStorage"": 100, ""MaxAllocatedStorage"": 1000 } ``` 示例响应: ``` { ""DBInstanceIdentifiers"": [ ""mydbinstance"" ], ""RestoreTime"": ""2017-10-14T23:45:00.000Z"", ""Marker"": ""2017-10-14T23:45:00.000Z"", ""ReplicationInstanceIdentifiers"": [] } ``` 在这个响应中,将`<>`符号替换为实际值。",FALSE,API部分参数错误:见https://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/APIReference/API_RestoreDBInstanceToPointInTime.html,要将RDS数据库实例还原到指定时间点,可以按照以下步骤进行操作: 1. 首先,登录AWS Management Console并通过以下链接打开Amazon RDS控制台:https://console.aws.amazon.com/rds/。 2. 在导航窗格中,选择Automated backups(自动备份)。 3. 然后,选择要还原的数据库实例。 4. 对于Actions(操作),选择Restore to point in time(还原到时间点)。 5. 在还原到时间点窗口中,选择最近可还原时间以还原到可能的最近时间,或者选择自定义来选择时间。 6. 如果选择Custom(自定义),请输入要将实例集群还原到的日期和时间。 7. 根据需要选择其他选项,例如数据库实例类、存储,以及是否要使用存储自动扩展。 8. 最后,选择还原到时间点,然后等待系统完成还原操作。 请注意,还原数据库实例时需要提供一些必要的参数和选项,包括源数据库实例标识符、目标数据库实例标识符、还原时间和所需的设置等。,TRUE,,"根据背景知识,要将RDS数据库实例还原到指定时间点,可以按以下步骤操作: 1. 在RDS控制台中,选择要还原的数据库实例,点击“Actions”然后选择“Restore to point in time”。 2. 在弹出窗口中,选择要还原到的时间点,或者选择“Custom”自定义时间点。 3. 为新数据库实例指定一个名称。 4. 根据需要设置其他参数,比如实例类、存储等。 5. 点击“Restore to point in time”启动还原过程。 或者通过AWS CLI使用restore-db-instance-to-point-in-time命令还原: ``` aws rds restore-db-instance-to-point-in-time \ --source-db-instance-identifier source-db \ --target-db-instance-identifier restored-db \ --restore-time 2021-03-15T12:00:00Z ``` 通过RDS API调用RestoreDBInstanceToPointInTime操作,指定SourceDBInstanceIdentifier、TargetDBInstanceIdentifier和RestoreTime参数。 总之,设置好源实例、目标实例、要还原的时间点,然后启动还原过程即可将RDS数据库实例恢复到指定时间点。",TRUE,,"要将RDS数据库实例还原到指定时间点,可以按以下步骤操作: - - -1. 在RDS控制台中,在导航窗格中,选择 Automated backups(自动备份), 选择要还原的数据库实例,点击“Actions”然后选择“Restore to point in time”。 - - -2. 在弹出窗口中,选择要还原到的时间点,或者选择“Custom”自定义时间点。 - - -3. 对于数据库实例标识符,请输入目标还原后的数据库实例的名称。名称必须唯一。 - - -4. 根据需要设置其他参数,比如实例类、存储等。 - - -5. 点击“Restore to point in time”启动还原过程。 - - -或者通过AWS CLI使用restore-db-instance-to-point-in-time命令还原: - - -``` -aws rds restore-db-instance-to-point-in-time \ - --source-db-instance-identifier source-db \ - --target-db-instance-identifier restored-db \ - --restore-time 2021-03-15T12:00:00Z -``` - - -通过RDS API调用RestoreDBInstanceToPointInTime操作,指定SourceDBInstanceIdentifier、TargetDBInstanceIdentifier和RestoreTime参数。 - - -总之,设置好源实例、目标实例、要还原的时间点,然后启动还原过程即可将RDS数据库实例恢复到指定时间点。", -https://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/AuroraUserGuide/Aurora.Overview.StorageReliability.html#aurora-storage-growth,https://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/AuroraUserGuide/Aurora.Overview.StorageReliability.html#aurora-storage-growth,Aurora 存储空间是如何根据数据量自动调整的?,Aurora 存储空间会根据数据量的增加自动调整大小。当数据库中的数据量增加时,Aurora 集群卷会自动增大,以确保足够的存储空间来存储数据。这种自动调整大小与高性能和高分布式存储子系统相结合,使得 Aurora 成为一个可靠和高可用的企业级数据库选择。,"[""https://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/AuroraUserGuide/Aurora.Overview.StorageReliability.html"",""https://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/AuroraUserGuide/aurora-storage-backup.html""]",TRUE,TRUE,,回答:Aurora 存储空间会根据数据库实例的数据量和选择的存储类型自动调整。Aurora 提供了多种存储类型供您选择,以满足不同的性能、吞吐量和成本需求。每种存储类型都有一个特定的性能级别和最小、最大硬盘空间要求。 当您创建或修改数据库实例时,可以选择相应的存储类型。一旦选择了存储类型,Aurora 将根据所选类型的最小和最大空间要求自动调整存储空间。此外,Aurora 还会根据数据量的增长和减少动态调整存储空间,以确保实例始终具有足够的空间来存储数据和应用程序。 这种自动调整功能使得您可以轻松地根据数据量的变化扩展或缩小存储空间,而无需预先分配过多的存储资源。然而,需要注意的是,这种自动调整功能可能会导致存储空间的实际使用量略高于指定的存储量。这是因为 Aws 会在满足最小和最大空间要求的同时,尽可能有效地利用存储空间。,FALSE,,Aurora 存储空间是根据数据量自动调整的。当数据量增加时,Aurora 会自动扩展存储空间以满足需求。这确保了数据库的性能和可靠性,同时也避免了因为存储空间不足而导致的问题。,TRUE,,"Aurora 存储空间的自动调整大小是其重要特性之一。主要有以下几点: - Aurora 使用单个可扩展的集群卷来存储所有数据。该卷会根据数据量自动增长。 - 集群卷可以增长到最大128 TiB(具体取决于数据库引擎版本)。您只需为使用的存储空间付费。 - 当删除数据时(如删除表),集群卷会自动缩小以释放不再使用的空间。这可以降低存储成本。 - 存储扩展行为依赖于 Aurora 版本。新版本支持更好的动态调整。 - 可以通过 CloudWatch 的 VolumeBytesUsed 指标来监控集群卷使用量。当接近限制时可以收到警报。 - 对于临时数据如临时表,存储在本地实例存储上,有单独的大小限制。 - Aurora 存储自动扩展可提供高性能、高可用性,非常适合重要的企业数据。自动调整大小是其中很重要的一点。",TRUE,,"Aurora 集群卷随着数据库中数据量的增加自动增大。Aurora 集群卷的最大大小为 128 TiB 或 64 TiB,具体取决于数据库引擎版本。有关特定版本最大大小的详细信息,请参阅 Amazon Aurora 大小限制。这种自动存储扩展与高性能和高分布式存储子系统相结合。当您的主要目标是可靠性和高可用性时,这些使 Aurora 成为您重要的企业数据的理想选择。 - - -要显示卷状态,请参阅 显示 Aurora MySQL 数据库集群的卷状态 或 显示 Aurora PostgreSQL 数据库集群的卷状态。有关平衡存储成本与其他优先级的方法,存储扩展 介绍了如何监控 CloudWatch 中的 Amazon Aurora 指标 AuroraVolumeBytesLeftTotal 和 VolumeBytesUsed。 -删除 Aurora 数据后,将释放为该数据分配的空间。删除数据的示例包括删除或截断表。这种自动减少存储使用量有助于您最大限度地减少存储费用。 - - -此处讨论的存储限制和动态调整大小行为适用于存储在集群卷中的持久性表和其他数据。对于 Aurora PostgreSQL,临时表数据存储在本地数据库实例中。对于 Aurora MySQL 版本 2,在原定设置情况下,临时表数据存储在写入器实例的集群卷中,读取器实例的临时表数据存储在本地存储中。有关更多信息,请参阅磁盘上的临时表的存储引擎。对于 Aurora MySQL 版本 3,临时表数据存储在本地数据库实例或集群卷中。有关更多信息,请参阅Aurora MySQL 版本 3 中的新临时表行为。驻留在本地存储中的临时表的最大大小受数据库实例的最大本地存储大小限制。本地存储大小取决于您使用的实例类。有关更多信息,请参阅 Aurora MySQL 的临时存储限制 和 Aurora PostgreSQL 的临时存储限制。 - - -某些存储功能(如集群卷的最大大小和删除数据时自动调整大小)取决于集群的 Aurora 版本。有关更多信息,请参阅存储扩展。您还可以了解如何避免存储问题,以及如何监控集群中分配的存储和可用空间。", -https://docs.aws.amazon.com/zh_cn/AmazonElastiCache/latest/red-ug/SelectEngine.html,https://docs.aws.amazon.com/zh_cn/AmazonElastiCache/latest/red-ug/SelectEngine.html,"Amazon ElastiCache Memcached 和 Amazon ElastiCache Redis的典型场景是什么?如果要使用ElastiCache Redis,应该选择哪些版本及其关键功能?",Amazon ElastiCache Memcached和ElastiCache Redis的典型场景如下: Memcached的典型场景: - 需要简单的模型 - 需要运行具有多个核心或线程的大型节点 - 需要具备缩放能力,随着系统需求的增加和减少来添加和移除节点 - 需要缓存对象 ElastiCache Redis的典型场景: - ElastiCache for Redis 版本7.0(加强版):想要使用Redis函数、分片发布/订阅或Redis ACL改进 - ElastiCache for Redis 版本6.2(加强版):想要使用r6gd节点类型在内存和SSD之间进行数据分层 - ElastiCache for Redis 版本6.0(加强版):想要使用基于角色的访问控制对用户进行身份验证 - ElastiCache for Redis 版本5.0.0(加强版):想要使用Redis流,它是一个日志数据结构,允许生成者实时附加新项,并允许使用者以阻塞或非阻塞方式使用消息 - ElastiCache for Redis 版本4.0.10(加强版):支持加密以及从您的Redis(已启用集群模式)集群动态添加或移除分区 如果您需要早期版本的功能,可以选择ElastiCache for Redis 3.2.10(加强版)或ElastiCache for Redis 3.2.6(加强版)。如果您需要更复杂的功能,可以选择ElastiCache for Redis 3.2.10(加强版)或ElastiCache for Redis 3.2.4(加强版)。 如果您的需求需要较为复杂的场景,建议选择ElastiCache for Redis 3.2.10(加强版)或ElastiCache for Redis 3.2.4(加强版)。 总之,选择ElastiCache Redis时,根据您的需求和场景选择适合的版本,并考虑其关键功能,以实现最佳性能和效益。,"[""https://docs.aws.amazon.com/zh_cn/AmazonElastiCache/latest/mem-ug/SelectEngine.html"",""https://docs.aws.amazon.com/zh_cn/AmazonElastiCache/latest/red-ug/WhatIs.html""]",TRUE,FALSE,,回答:Amazon ElastiCache Memcached 和 Amazon ElastiCache Redis 主要用于处理大量读操作而写操作较少的场景,因为它们提供了非常快速的读取性能。以下是一些典型的使用场景: 1. **内容缓存**:对于Web应用程序,可以将热门内容(如文章、产品列表等)存储在ElastiCache中,以便更快地向用户提供这些信息,而无需查询数据库。这可以提高网站的性能和响应时间。 2. **用户会话缓存**:ElastiCache可以作为用户会话缓存的备份,以防止重放攻击和提高应用程序的性能。 3. **数据库查询缓存**:对于数据库驱动应用程序,可以使用ElastiCache作为数据库查询结果的缓存。这样可以避免重复查询相同的数据,从而提高应用程序的性能。 要选择合适的ElastiCache Redis版本,您需要考虑以下几个关键因素: 1. **功能和性能**:不同的Redis版本具有不同的功能和性能特性。例如,某些版本支持高级数据结构(如Geospatial索引)和传输中加密。根据您的应用程序需求选择合适的版本。 2. **集群模式**:如果您需要一个分布式缓存环境,那么应该选择支持集群模式的Redis版本。这将允许您在多个节点上分布数据和提供额外的容错能力。 3. **加密和安全**:如果您需要加密数据以保护用户数据,那么应该选择支持加密的Redis版本。这可能包括传输中加密和静态加密。 总的来说,如果您需要一个高度可扩展且具有高级功能的分布式缓存环境,那么应该选择Redis版本4.0.10或更高版本。如果您只需要一个简单的单个节点缓存,那么可以选择任何版本的Redis。,TRUE,,Amazon ElastiCache Memcached 和 Amazon ElastiCache Redis 都可以用来作为高性能、可扩展且具有成本效益的缓存解决方案。它们的典型应用场景包括: - **Web 应用程序缓存**:ElastiCache Memcached 可用于缓存动态 Web 应用程序,例如 PHP 应用程序、Ruby on Rails 应用程序等。它可用于缓存数据库查询结果、缓存动态内容等。而 ElastiCache Redis 适用于缓存复杂的文档数据结构、缓存图像和视频等内容。 - **游戏应用和实时数据分析**:游戏应用通常需要进行大量的实时计算和数据处理,ElastiCache Redis 可以用来缓存游戏状态和玩家数据,并提供实时的数据分析和处理。 - **大数据处理和分析**:ElastiCache Redis 可以用于处理大规模数据集,例如用于缓存数据仓库查询结果,或者用作数据处理管道的一部分。 在选择 ElastiCache Redis 时,您可以根据需要选择不同的版本及其关键功能。以下是一些重要的版本和功能: - **ElastiCache Redis 版本 6.0(加强版)**:该版本引入了一些新的功能和增强特性,包括基于角色的访问控制、支持加密、动态添加或删除分区等。 - **ElastiCache Redis 版本 5.0.0(加强版)**:该版本引入了 Redis 流,允许生成者实时附加新项,并允许使用者以阻塞或非阻塞方式使用消息。它还提供了一些新的性能优化和改进的安全功能。 - **ElastiCache Redis 版本 4.0.10(加强版)**:该版本支持加密以及从你的 Redis 集群动态添加或移除分区。它还提供了一些性能改进和安全增强。 - **ElastiCache Redis 版本 3.2.10(加强版)**:该版本支持从你的 Redis 集群动态添加或移除分区的功能。它还提供了一些性能改进和安全性增强。 请注意,ElastiCache for Redis 3.2.10 不支持加密。如果您需要加密功能,请选择 ElastiCache for Redis 版本的 6.0 或以上版本。,FALSE,,"Amazon ElastiCache Memcached和Amazon ElastiCache Redis的典型场景如下: - 如果需要简单的模型,运行大型多核或多线程节点,以及可扩展性,则选择Memcached。 - 如果需要Redis函数、分片发布/订阅、Redis ACL等功能,则选择ElastiCache Redis。 如果要使用ElastiCache Redis,应该选择的版本和关键功能包括: - Redis 7.0(增强版):支持数据分层、ACL等功能。 - Redis 6.2(增强版):支持内存和SSD之间的数据分层。 - Redis 6.0(增强版):支持基于角色的访问控制。 - Redis 5.0.0(增强版):支持Redis流。 - Redis 4.0.10(增强版):支持加密以及在线重新分片。 - Redis 3.2.10(增强版):支持有限的在线重新分片。 - Redis 3.2.6(增强版):支持传输中加密和静态加密。 综上,根据具体需求,选择支持所需功能的最新Redis版本。比如需要ACL则选择6.0或更高版本,需要数据分层则选择6.2或更高版本。",TRUE,,"如果您存在以下情况,请选择 Memcached: -您需要使模型尽可能简单。 -您需要运行具有多个核心或线程的大型节点。 -您需要具备缩放能力,随着系统需求的增加和减少来添加和移除节点。 -您需要缓存对象。 -如果以下情况适用于您,请选择带 ElastiCache for Redis 版本的 Redis: -ElastiCache for Redis 版本 7.0(加强版) - 您想要使用 Redis 函数、分片发布/订阅 或 Redis ACL 改进。有关更多信息,请参阅 Redis 版本 7.0(加强版)。 -ElastiCache for Redis 版本 6.2(加强版) - 您希望能够使用 r6gd 节点类型在内存和 SSD 之间进行数据分层。有关更多信息,请参阅数据分层。 -ElastiCache for Redis 版本 6.0(加强版) - 您希望使用基于角色的访问控制对用户进行身份验证。 - 有关更多信息,请参阅 Redis 版本 6.0(加强版)。 -ElastiCache for Redis 版本 5.0.0(加强版) - 您需要使用 Redis 流,它是一个日志数据结构,允许生成者实时附加新项,并允许使用者以阻塞或非阻塞方式使用消息。 - 有关更多信息,请参阅 Redis 5.0.0 版(加强版)。 -ElastiCache for Redis 版本 4.0.10(加强版) - 支持加密以及从您的 Redis(已启用集群模式)集群动态添加或移除分区。 - 有关更多信息,请参阅 Redis 4.0.10 版(加强版)。 -以下版本已弃用、已达到使用寿命或即将达到使用寿命。 -ElastiCache for Redis 版本 3.2.10(加强版) - 支持从您的 Redis(已启用集群模式)集群动态添加或移除分区的功能。 -ElastiCache for Redis 版本 3.2.6(加强版) - 如果您需要早期 Redis 版本的功能外加以下功能,请选择 ElastiCache for Redis 3.2.6: -传输中加密。有关更多信息,请参阅 Amazon ElastiCache for Redis 传输中加密。 -静态加密。有关更多信息,请参阅 Amazon ElastiCache for Redis 静态加密。 -HIPAA 资格认证。有关更多信息,请参阅 Amazon ElastiCache for Redis 的 HIPAA 资格。 -ElastiCache for Redis(已启用集群模式)版本 3.2.4 - 如果需要 Redis 2.8.x 的功能外加以下功能,请选择 Redis 3.2.4 (集群模式): -您需要在 2 到 500 个节点组(仅限集群模式)之间对数据分区。 -您需要地理空间索引(集群模式或非集群模式)。 -您不需要支持多个数据库。 -ElastiCache for Redis(非集群模式)2.8.x 和 3.2.4(加强版) - 如果您存在以下情况,请选择 Redis 2.8.x 或 Redis 3.2.4 (非集群模式): -您需要复杂数据类型,如字符串、哈希、列表、集、排序集和位图。 -您需要对内存数据集进行排序或排名。 -您需要持久保留密钥库。 -您需要为读取操作密集型应用程序将主集群中的数据复制到一个或多个只读副本。 -您需要在主节点出现故障的情况下执行自动故障转移。 -您需要发布和订阅 (pub/sub) 功能 – 向客户端通知服务器上发生的事件。 -您需要备份和还原功能。 -您需要支持多个数据库。", -https://docs.aws.amazon.com/zh_cn/elasticloadbalancing/latest/classic/enable-disable-crosszone-lb.html#enable-cross-zone,https://docs.aws.amazon.com/zh_cn/elasticloadbalancing/latest/classic/enable-disable-crosszone-lb.html#enable-cross-zone,Elastic Load Balancing如何启用跨区域负载均衡?,您可以在创建经典负载均衡器时启用或禁用跨区域负载均衡。默认情况下,使用API或CLI创建负载均衡器时,跨区域负载均衡的默认值是禁用。使用AWS Management Console创建负载均衡器时,启用跨区域负载均衡的选项处于选中状态。您随时可以通过打开负载均衡器的详细信息页面并编辑属性来启用或禁用跨区域负载均衡。,"[""https://docs.aws.amazon.com/zh_cn/elasticloadbalancing/latest/network/target-group-cross-zone.html"",""https://docs.aws.amazon.com/zh_cn/elasticloadbalancing/latest/classic/enable-disable-crosszone-lb.html""]",TRUE,TRUE,,要在Elastic Load Balancing(ELB)中启用跨区域负载均衡,您需要执行以下步骤: 1. 登录到Amazon EC2控制台并找到负载均衡服务。 2. 在导航菜单上选择“负载均衡”,然后在下方列表中选择“负载均衡器”。 3. 点击您想要修改的负载均衡器的名称以进入详情视图。 4. 在详情视图中,找到“属性”选项卡,点击“编辑”。 5. 在弹出的编辑页面中,找到“可用区路由配置”部分,勾选“跨可用区负载均衡”复选框。 6. 完成以上步骤后,点击“保存更改”以保存您的设置。 这样,您就成功启用了跨区域负载均衡。,TRUE,,"要启用跨区域负载均衡,可以使用以下方法之一: 1. 使用控制台启用跨区域负载均衡:登录Amazon EC2控制台,选择Load Balancers(负载均衡器),然后选择所需的负载均衡器。在属性选项卡上,选择编辑,并在编辑负载均衡器属性页面的可用区路由配置部分中启用跨可用区负载均衡。最后,点击Save changes(保存更改)即可启用跨区域负载均衡。 2. 使用AWS CLI启用跨区域负载均衡:使用modify-load-balancer-attributes命令,将负载均衡器的CrossZoneLoadBalancing属性设置为true。例如: ``` aws elb modify-load-balancer-attributes --load-balancer-name my-loadbalancer --load-balancer-attributes ""{\""CrossZoneLoadBalancing\"":{\""Enabled\"":true}}"" ``` 这将使您的负载均衡器启用跨区域负载均衡。",TRUE,,"要启用Elastic Load Balancing的跨区域负载均衡,可以采取以下步骤: 1. 对于经典负载均衡器(ELB),可以在控制台中编辑负载均衡器的属性,启用""跨区域负载均衡""选项。或者使用AWS CLI,将CrossZoneLoadBalancing属性设置为true。 2. 对于应用负载均衡器(ALB),跨区域负载均衡是默认启用的,无需特殊配置。 3. 对于网络负载均衡器(NLB),需要在控制台中编辑负载均衡器的属性,启用""跨区域负载均衡""选项。或者使用AWS CLI,将load_balancing.cross_zone.enabled属性设置为true。 4. 对于NLB的目标组,可以在目标组级别覆盖负载均衡器的跨区域负载均衡设置。在控制台编辑目标组属性,或使用AWS CLI设置load_balancing.cross_zone.enabled属性。 5. 注意不能为类型为ALB的目标组单独配置跨区域负载均衡,它总是继承自负载均衡器的设置。 总之,对于经典ELB和NLB负载均衡器,需要显式地启用跨区域负载均衡。对于ALB默认启用,NLB的目标组可以覆盖负载均衡器的设置。",TRUE,,"要启用Elastic Load Balancing的跨区域负载均衡,可以采取以下步骤: - - -1. 对于经典负载均衡器(ELB),可以在控制台中编辑负载均衡器的属性,启用""跨区域负载均衡""选项。或者使用AWS CLI,将CrossZoneLoadBalancing属性设置为true。 - - -2. 对于应用负载均衡器(ALB),跨区域负载均衡是默认启用的,无需特殊配置。 - - -3. 对于网络负载均衡器(NLB),需要在控制台中编辑负载均衡器的属性,启用""跨区域负载均衡""选项。或者使用AWS CLI,将load_balancing.cross_zone.enabled属性设置为true。 - - -4. 对于NLB的目标组,可以在目标组级别覆盖负载均衡器的跨区域负载均衡设置。在控制台编辑目标组属性,或使用AWS CLI设置load_balancing.cross_zone.enabled属性。", -https://docs.aws.amazon.com/zh_cn/vpc/latest/userguide/default-security-group.html,https://docs.aws.amazon.com/zh_cn/vpc/latest/userguide/default-security-group.html,Amazon VPC默认安全组的默认入站和出站规则?,Amazon VPC默认安全组的默认入站和出站规则如下: 入站规则: - 源:全部 - 协议:全部 - 端口范围:全部 - 描述:允许来自分配给此安全组的所有资源的入站流量。 出站规则: - 目的地:0.0.0.0/0 - 协议:All - 端口范围:All - 描述:允许所有的出站IPv4流量。 请注意,默认安全组无法删除,如果尝试删除默认安全组,将显示错误代码“Client.CannotDelete”。,"[""https://docs.aws.amazon.com/zh_cn/config/latest/developerguide/vpc-default-security-group-closed.html"",""https://docs.aws.amazon.com/zh_cn/vpc/latest/userguide/default-security-group.html""]",TRUE,FALSE,,根据提供的文章,Amazon VPC的默认安全组的默认入站规则允许来自分配给该安全组的所有资源的入站流量,来源为此安全组的ID。而出站规则允许所有的出站IPv4流量和所有的出站IPv6流量,仅在VPC具有关联的IPv6 CIDR块时才添加此规则。,TRUE,,Amazon VPC默认安全组的默认入站规则允许来自所有分配给该安全组的所有资源的入站流量,而默认出站规则允许所有的出站IPv4和IPv6流量。具体规则如下所示: 入站规则: - 允许来自分配给此安全组的所有资源的入站流量。源为此安全组的 ID。 出站规则: - 允许所有的出站IPv4流量。 - 允许所有的出站IPv6流量。仅当VPC具有关联的IPv6 CIDR块时才添加此规则。,TRUE,,"根据背景知识,Amazon VPC默认安全组的默认入站和出站规则如下: 入站规则: - 源:sg-1234567890abcdef0(默认安全组的ID) - 协议:所有 - 端口范围:所有 - 描述:允许来自分配给此安全组的所有资源的入站流量。 出站规则: - 目的地:0.0.0.0/0 - 协议:所有 - 端口范围:所有 - 描述:允许所有的出站IPv4流量。 - 目的地::/0 - 协议:所有 - 端口范围:所有 - 描述:允许所有的出站IPv6流量。仅当VPC具有关联的IPv6 CIDR块时才添加此规则。 所以默认情况下,Amazon VPC默认安全组允许从同一安全组的资源进行全部入站访问,并允许全部出站访问。这符合开放的默认策略。",TRUE,,"Amazon VPC默认安全组的默认入站和出站规则如下: - - -入站规则: -- 源:sg-1234567890abcdef0(默认安全组的ID) -- 协议:所有 -- 端口范围:所有 -- 描述:允许来自分配给此安全组的所有资源的入站流量。 - - -出站规则: -- 目的地:0.0.0.0/0 -- 协议:所有 -- 端口范围:所有 -- 描述:允许所有的出站IPv4流量。 - - -- 目的地::/0 -- 协议:所有 -- 端口范围:所有 -- 描述:允许所有的出站IPv6流量。仅当VPC具有关联的IPv6 CIDR块时才添加此规则。 - - -所以默认情况下,Amazon VPC默认安全组允许从同一安全组的资源进行全部入站访问,并允许全部出站访问。这符合开放的默认策略。", -https://docs.aws.amazon.com/zh_cn/vpn/latest/s2svpn/vpn-limits.html#vpn-quotas-bandwidth,https://docs.aws.amazon.com/zh_cn/vpn/latest/s2svpn/vpn-limits.html#vpn-quotas-bandwidth,每个AWS Site-to-Site VPN 隧道的最大带宽是多少?,每个AWS Site-to-Site VPN隧道的最大带宽是1.25 Gbps。,"[""https://repost.aws/questions/QUjvfPv4HfRZOqVUp58oJGFw"",""https://docs.aws.amazon.com/zh_cn/vpn/latest/s2svpn/VPNTunnels.html""]",TRUE,TRUE,,每个AWS Site-to-Site VPN隧道的最大带宽取决于您的Internet服务提供商(ISP)的带宽限制。例如,如果您从ISP获得50 Mbps的互联网带宽,并且您设置了Site-to-Site VPN到AWS,您通常会获得1.25Gbps的带宽隧道。然而,这个带宽并不是每个VPN连接都可以使用的最大带宽。根据您的使用情况,很可能您的ISP将带宽限制在50 Mbps。如果您的应用程序需要更多带宽,您可能需要升级您的互联网电路。,TRUE,,每个AWS Site-to-Site VPN 隧道的最大带宽取决于多种因素,包括您的数据中心互联网带宽限制以及您使用的隧道类型和配置。通常情况下,每个Site-to-Site VPN 隧道的最大带宽取决于您的数据中心互联网带宽限制。如果您从ISP获得的互联网带宽较小,那么即使设置了Site-to-Site VPN连接,您仍然可能无法获得所需的带宽。此外,如果使用了基于BGP的Active-Active隧道,并且您的CGW设备支持ECMP路由,则可以在将VPN连接终止在Transit Gateway时有效地获得每个VPN的2.5 Gbps的总带宽。,TRUE,,"根据背景知识,每个AWS Site-to-Site VPN连接默认有两个隧道,每个隧道的最大带宽是1.25Gbps。 所以每个AWS Site-to-Site VPN连接的总带宽是2个隧道的带宽之和,即2 * 1.25Gbps = 2.5Gbps。",FALSE,,"每个AWS Site-to-Site VPN连接默认有两个隧道,每个隧道的最大带宽是1.25Gbps。", -https://docs.aws.amazon.com/zh_cn/secretsmanager/latest/userguide/rotate-secrets_turn-on-for-db.html,https://docs.aws.amazon.com/zh_cn/secretsmanager/latest/userguide/rotate-secrets_turn-on-for-db.html,AWS Secrets Manager如何为 Amazon RDS密钥设置自动轮换?,要为 Amazon RDS 密钥设置自动轮换,您可以按照以下步骤进行操作: 1. 打开 AWS Secrets Manager 控制台:https://console.aws.amazon.com/secretsmanager/ 2. 在密钥列表页上,选择您的密钥。 3. 在 Secret details (密钥详细信息) 页上的 Rotation configuration (轮换配置) 部分中,选择 Edit rotation (编辑轮换)。 4. 在 Edit rotation 对话框中,启用 Automatic rotation(自动轮换)。 5. 在 Rotation schedule(轮换计划)下,以 UTC 时区格式输入您的计划。Secrets Manager 会将您的计划存储为 rate() 或 cron() 表达式。轮换时段将自动从午夜开始,除非您指定 Start time(开始时间)。您可以每四小时轮换一次密钥。 6. (可选)对于 Window duration(时段持续时间),选择您希望 Secrets Manager 在其间轮换密钥的时段长度,例如 3h 表示三个小时的时段。该时段不得延伸到下一个轮换时段。如果未指定 Window duration(时段持续时间),则对于以小时为单位的轮换计划,时段将在一小时后自动关闭。对于以天为单位的轮换计划,时段将在一天结束时自动关闭。 7. (可选)请选择 Rotate immediately when the secret is stored(在存储密钥时立即轮换),以在保存更改时轮换密钥。如果您清除该复选框,则第一次轮换将按照您设置的计划开始。 8. 在 Rotation function(轮换函数)下,选择 Create function(创建函数)。此时将在新窗口中打开 Lambda 控制台。 在 Lambda 控制台的 Create function(创建函数)页面上,您可以选择以下操作之一: 1. 如果显示 Browse serverless app repository(浏览无服务器应用程序存储库),请选择此选项。 2. 如果没有显示 Browse serverless app repository(浏览无服务器应用程序存储库),则您的 AWS 区域 可能不支持 AWS Serverless Application Repository。选择从头开始编写。 在 Function name(函数名称)中输入您的函数名称,然后根据您的需求配置其他参数。配置完成后,选择 Deploy(部署)。 这样,您就可以为 Amazon RDS 密钥设置自动轮换。请注意,您需要具有创建 IAM 执行角色并向其附加权限策略的权限,并确保密钥与 Secrets Manager 和数据库或服务之间的网络访问。,"[""https://docs.aws.amazon.com/zh_cn/secretsmanager/latest/userguide/rotate-secrets_turn-on-for-other.html"",""https://docs.aws.amazon.com/zh_cn/secretsmanager/latest/userguide/rotate-secrets-cli.html""]",TRUE,TRUE,,AWS Secrets Manager可以为Amazon RDS密钥设置自动轮换,但需要在Lambda函数中进行一些配置。以下是详细的步骤: 1. 创建Lambda函数:首先,你需要创建一个Lambda函数,这个函数将负责轮换密钥。你可以从Secrets Manager提供的模板中复制代码,或者根据你的需求编写自定义代码。 2. 配置Lambda函数:在Lambda函数中,你需要编写代码来轮换密钥。这个代码应该包括创建秘密、设置秘密、测试秘密和完成秘密等四个步骤。 3. 创建执行角色:为了让Lambda函数能够访问Secrets Manager,你需要创建一个执行角色。这个执行角色应该包含对所有Secrets Manager操作的权限,以及访问KMS密钥的权限(如果密钥使用了KMS加密)。 4. 设置网络访问:为了确保Lambda函数能够访问Secrets Manager和Amazon RDS,你需要配置网络访问。这可能包括设置VPC终端节点,或者在VPC中配置Amazon RDS的VPC端点。 5. 配置密钥轮换:最后,你可以调用Secrets Manager的API来设置密钥轮换。你需要提供一个计划表达式来指定轮换的频率和持续时间。 这样,AWS Secrets Manager就可以为Amazon RDS密钥设置自动轮换了。,TRUE,,AWS Secrets Manager 为 Amazon RDS 密钥设置自动轮换的方法如下: 1. **创建超级用户密钥**:首先,您需要在 Secrets Manager 中创建一个超级用户密钥,用于存储数据库超级用户凭证。 2. **编写轮换函数代码**:编写一个 Lambda 轮换函数,用于轮换亚马逊 RDS 密钥。您可以使用 Secrets Manager 提供的轮换函数模板,或者根据您的需求编写自定义的轮换函数。 3. **创建 Lambda 函数和执行角色**:创建一个 Lambda 函数,并将其与一个执行角色关联起来。这个执行角色应该具有执行 Lambda 函数的必要权限。 4. **设置网络访问**:确保 Lambda 轮换函数可以通过网络访问 Secrets Manager 和数据库或服务。 5. **配置密钥以进行轮换**:调用 rotate-secret 函数,以开始自动轮换亚马逊 RDS 密钥。您可以根据需要设置轮换计划和轮换频率。 完成以上步骤后,您就可以使用 Secrets Manager 为 Amazon RDS 密钥设置自动轮换功能了。,TRUE,,"要为Amazon RDS密钥设置Secrets Manager自动轮换,可以按以下步骤操作: 1. 创建一个包含RDS数据库凭证(用户名和密码)的Secrets Manager密钥。 2. 选择单用户轮换策略或交替用户轮换策略。如果选择交替用户策略,需要另外创建一个包含RDS超级用户凭证的密钥。 3. 使用Secrets Manager提供的RDS轮换函数模板之一编写轮换函数代码。 4. 创建一个Lambda函数,上传轮换函数代码,并为其配置执行角色。执行角色需要secretsmanager和RDS的访问权限。 5. 配置网络访问,确保Lambda函数可以访问Secrets Manager端点和RDS数据库。 6. 在Secrets Manager控制台上为密钥配置轮换,指定轮换计划和轮换Lambda函数。 7. 测试轮换是否正常工作。Secrets Manager会根据计划定期调用轮换函数来轮换RDS凭证。 8. 监控CloudWatch日志,调试任何错误。可以在轮换函数代码中添加日志语句。 9. 考虑设置警报以通知轮换失败。 总体来说,需要正确配置执行角色、网络访问和轮换计划,并编写适当的轮换函数代码来轮换RDS凭证。使用单用户策略更简单,交替用户策略提供更高可用性。",TRUE,,"要为Amazon RDS密钥设置Secrets Manager自动轮换,可以按以下步骤操作: - - -1. 创建一个包含RDS数据库凭证(用户名和密码)的Secrets Manager密钥。 - - -2. 选择单用户轮换策略或交替用户轮换策略。如果选择交替用户策略,需要另外创建一个包含RDS超级用户凭证的密钥。 - - -3. 使用Secrets Manager提供的RDS轮换函数模板之一编写轮换函数代码。 - - -4. 创建一个Lambda函数,上传轮换函数代码,并为其配置执行角色。执行角色需要secretsmanager和RDS的访问权限。 - - -5. 配置网络访问,确保Lambda函数可以访问Secrets Manager端点和RDS数据库。 - - -6. 在Secrets Manager控制台上为密钥配置轮换,指定轮换计划和轮换Lambda函数。 - - -7. 测试轮换是否正常工作。Secrets Manager会根据计划定期调用轮换函数来轮换RDS凭证。 - - -8. 监控CloudWatch日志,调试任何错误。可以在轮换函数代码中添加日志语句。 - - -9. 考虑设置警报以通知轮换失败。", -https://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/reference_policies_examples_aws-enable-disable-regions.html,https://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/reference_policies_examples_aws-enable-disable-regions.html,如何设置AWS IAM策略禁用特定的 AWS 区域?,"要设置AWS IAM策略禁用特定的AWS区域,您可以按照以下步骤进行操作: 1. 使用AWS Management Console、AWS CLI或AWS SDKs,创建一个IAM策略。 2. 在策略中添加以下条件: ``` ""Condition"": { ""StringEquals"": { ""ec2:Region"": ""特定区域代码"" } } ``` 请将""特定区域代码""替换为您想要禁用的区域代码。 3. 将该策略分配给IAM用户、组或角色,以便他们可以使用该策略来访问AWS服务。 请注意,如果您在执行上述步骤时遇到任何问题或需要进一步的帮助,请联系AWS解决方案团队。","[""https://repost.aws/questions/QU5wjaO6vZR7Kx7SUULYYjrw"",""https://docs.aws.amazon.com/zh_cn/accounts/latest/reference/API_DisableRegion.html""]",TRUE,FALSE,策略不完整,没说明Effect是Allow还是Deny,要在 AWS IAM 中设置策略以禁用特定的 AWS 区域,您需要创建一个策略,其中包含允许或拒绝针对特定区域的操作的语句。然后,您可以将此策略分配给要限制对其服务的访问的用户或角色。 以下是设置策略以禁用特定 AWS 区域的步骤: 1. 在 IAM 控制台中,点击“策略”选项卡,然后点击“创建政策”按钮。 2. 在“创建政策”对话框中,输入政策的名称和描述,然后点击“下一步:条件”。 3. 在“条件”部分,添加一个或多个条件以限制对特定区域的访问。例如,您可以添加一个条件,要求操作只对在特定区域(如 us-west-2)中执行的 EC2 服务生效。 4. 点击“下一步:授权”。 5. 在“授权”部分,添加一个或多个允许或拒绝操作的语句。例如,您可以添加一个允许对所有 EC2 操作的语句,但拒绝对所有 S3 操作的语句。 6. 点击“下一步:预览”。 7. 在“预览”部分,检查策略的有效性和逻辑。如果有任何问题,可以更正并在需要时添加更多条件。 8. 点击“创建政策”以创建策略。 9. 现在,您可以将被限制对其服务的访问的用户或角色与新的策略关联。转到“用户”或“角色”选项卡,选择一个现有用户或角色,然后点击“权限”。 10. 在“权限”表格中,找到新创建的策略,然后点击“编辑”。 11. 在“编辑策略”对话框中,打开“权限”开关,然后从列表中选择要限制对其服务的访问的用户或角色。 现在,您已经设置了策略以禁用特定的 AWS 区域。用户的访问将受到策略的限制,只能对在特定区域中执行的特定服务生效。,FALSE,没有授权选项,"您可以使用 AWS IAM 策略来禁用特定的 AWS 区域。首先,您需要创建一个 IAM 策略,然后将其关联到您的 AWS 组织账户或用户。接下来,您可以定义一个条件语句来指定要禁用的 AWS 区域。最后,您可以将该策略分配给您想要限制访问的用户。 以下是一些详细的步骤: 1. 在 AWS 控制台上,转到 IAM 并选择您的 AWS 组织账户或用户。 2. 点击 **策略** 并选择 **创建政策**。 3. 为您的策略命名,然后选择 **创建**。 4. 在 **策略** 选项卡下,点击 **添加条目** 以添加一个允许条件。 5. 选择 **条件** 并选择一个 **StringEquals** 条件。 6. 将 **AttributeName** 设置为 `arn:aws:iam::aws:policy-document/aws-service-control-manager-policies:service-namespace/ec2*`, 并将 **Values** 设置为要禁用的区域(例如 us-west-2, eu-west-1)。 7. 点击 **保存**。 8. 返回到 **策略** 选项卡,然后点击 **分配** 将策略分配给您想要限制访问的用户。 请注意,这些步骤假定您已经具有足够的 AWS 权限来管理和编辑 IAM 策略。",FALSE,,"您可以通过在IAM策略中使用条件来限制用户只能访问特定的AWS区域。 这里是一个示例策略,它允许用户仅访问us-east-1区域: ```json { ""Version"": ""2012-10-17"", ""Statement"": [ { ""Sid"": ""AllowUSEast1Only"", ""Effect"": ""Allow"", ""Action"": ""ec2:*"", ""Resource"": ""*"", ""Condition"": { ""StringEquals"": {""ec2:Region"": ""us-east-1""} } } ] } ``` 该策略使用`ec2:Region`条件键来检查请求的区域。只有当区域为us-east-1时,该策略才会允许操作。 您可以通过替换服务和区域来调整此策略,以适应您的需要。例如,要仅允许S3的us-west-2,可以使用: ```json ""Condition"": { ""StringEquals"": {""s3:Region"": ""us-west-2""} } ``` 注意,某些服务(如IAM)没有区域,因此不能使用这种方法限制。在这种情况下,您需要使用其他策略语句显式拒绝访问其他区域。 还要注意,这不会阻止用户使用API或SDK访问其他区域。它只阻止通过控制台的访问。要完全阻止程序化访问其他区域,您需要拒绝相关的API调用。",FALSE,答非所问,"{ - ""Version"": ""2012-10-17"", - ""Statement"": [ - { - ""Action"": ""ec2:*"", - ""Resource"": ""*"", - ""Effect"": ""Deny"", - ""Condition"": { - ""StringEquals"": { - ""ec2:Region"": ""us-east-1"" - } - } - } - ] -}", -https://docs.aws.amazon.com/zh_cn/inspector/latest/user/scanning-ecr.html,https://docs.aws.amazon.com/zh_cn/inspector/latest/user/scanning-ecr.html,如何使用Inspector 扫描亚马逊 ECR 容器映像?,"要使用 Amazon Inspector 扫描亚马逊 ECR 容器映像,需要按照以下步骤进行操作: 1. 在 Amazon ECR 控制台中,打开您的存储库。 2. 在导航窗格中,选择""扫描""。 3. 在""扫描类型""列表中选择""增强扫描""。 4. 在""增强扫描""下拉菜单中选择""持续扫描所有存储库""。 5. 如果需要,可以选择""推送扫描""或者""自动重新扫描""以进一步缩小扫描范围。 6. 扫描结果会立即在 Amazon Inspector 控制台上显示。 7. 您还可以使用 Amazon Inspector 提供的 API 来查看、处理和导出扫描结果。 请注意,Amazon ECR 存储库默认支持 Amazon Inspector 提供的增强扫描功能。通过激活增强扫描、配置扫描时间和选择扫描范围,您可以在 Amazon Inspector 上对亚马逊 ECR 容器映像进行漏洞扫描。","[""https://docs.aws.amazon.com/zh_cn/inspector/latest/user/scanning-ecr.html"",""https://docs.aws.amazon.com/zh_cn/inspector/latest/user/ecr-integration.html""]",TRUE,TRUE,,要使用Amazon Inspector扫描Amazon ECR中的容器映像,请按照以下步骤操作: 1. 登录到Amazon Web Services (AWS) Management Console。 2. 找到并点击“Amazon Inspector”图标进入控制台。 3. 在导航菜单上,点击“扫描”。 4. 点击“立即开始”按钮。 5. 如果尚未将Amazon ECR设置为首选扫描服务,系统将提示您进行设置。 6. 等待扫描过程完成。扫描完成后,您可以在Amazon Inspector控制台查看扫描结果。 这样,您就可以使用Amazon Inspector扫描Amazon ECR中的容器映像,以查找软件漏洞并生成漏洞调查结果了。,FALSE,Inspector扫描ECR是在ECR console配置,您可以通过亚马逊 Inspector 控制台或 API 激活 Amazon Inspector 扫描,或者通过亚马逊 ECR 控制台或 API 将您的存储库配置为使用亚马逊 Inspector 的增强扫描,从而激活集成。 在 Amazon Inspector 控制台中,您可以配置 ECR 自动重新扫描持续时间,以便在满足条件时自动重新扫描存储库。您还可以配置增强扫描设置,例如持续扫描、推送扫描以及包含过滤器的扫描频率。 一旦激活,您可以在 Amazon ECR 控制台中查看 Amazon Inspector 对容器映像的调查结果。此外,您还可以通过创建包含筛选器来管理扫描频率并细化扫描范围。,TRUE,,"要使用 Amazon Inspector 扫描亚马逊 ECR 中的容器映像,您可以按照以下步骤操作: 1. 在Amazon ECR 控制台中,导航到您要扫描的存储库。 2. 在“扫描”选项卡上,选择“增强扫描”。这会将扫描类型更改为使用 Amazon Inspector 进行扫描。 3. 默认情况下,Amazon Inspector 将扫描存储库中的所有映像。您可以通过选择“仅推送扫描”或使用过滤器来限制扫描范围。 4. 推送您要扫描的任何新映像。Amazon Inspector 将自动扫描新推送的映像。 5. 查看扫描结果。您可以在Amazon ECR 控制台的“发现”选项卡上看到扫描结果。您也可以在Amazon Inspector 控制台中查看详细的扫描报告。 6. 要持续扫描映像,请确保选择“持续扫描”而不是“仅推送扫描”。Amazon Inspector 将定期重新扫描映像,查找新发现的漏洞。 7. 您可以在Amazon Inspector中配置自动重新扫描的间隔时间。默认为生命周期,但您可以将其设置为30天或180天。 8. 对于多账户环境,只有管理员账户可以启用或禁用增强扫描。但成员账户可以查看扫描结果。 9. 使用Amazon Inspector的扫描结果管理功能来跟踪、优先排序和修复发现的漏洞。",TRUE,,"要使用 Amazon Inspector 扫描亚马逊 ECR 中的容器映像,您可以按照以下步骤操作: - - -1. 在Amazon ECR 控制台中,导航到您要扫描的存储库。 - - -2. 在“扫描”选项卡上,选择“增强扫描”。这会将扫描类型更改为使用 Amazon Inspector 进行扫描。 - - -3. 默认情况下,Amazon Inspector 将扫描存储库中的所有映像。您可以通过选择“仅推送扫描”或使用过滤器来限制扫描范围。 - - -4. 推送您要扫描的任何新映像。Amazon Inspector 将自动扫描新推送的映像。 - - -5. 查看扫描结果。您可以在Amazon ECR 控制台的“发现”选项卡上看到扫描结果。您也可以在Amazon Inspector 控制台中查看详细的扫描报告。 - - -6. 要持续扫描映像,请确保选择“持续扫描”而不是“仅推送扫描”。Amazon Inspector 将定期重新扫描映像,查找新发现的漏洞。 - - -7. 您可以在Amazon Inspector中配置自动重新扫描的间隔时间。默认为生命周期,但您可以将其设置为30天或180天。 - - -8. 对于多账户环境,只有管理员账户可以启用或禁用增强扫描。但成员账户可以查看扫描结果。 - - -9. 使用Amazon Inspector的扫描结果管理功能来跟踪、优先排序和修复发现的漏洞。", -https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/userguide/object-lock-console.html,https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/userguide/object-lock-console.html,如何使用控制台配置 Amazon S3 对象锁定?,"要使用控制台配置 Amazon S3 对象锁定,请按照以下基本步骤进行操作: 1. 登录到 AWS 管理控制台,并打开 Amazon S3 控制台。 2. 在控制台上,选择您要配置对象锁定的存储桶。 3. 在存储桶的详细信息页面上,选择 ""对象锁定"" 选项卡。 4. 在 ""对象锁定"" 选项卡下,您可以选择启用对象锁定,并设置保留期限和依法保留。 5. 如果您想要配置默认保留期限,请选择 ""编辑"",然后在 ""保留"" 下选择 ""启用""。 6. 在 ""保留期限"" 框中,输入您希望对象保持锁定状态的时间段,以天为单位。 7. 如果您想要启用依法保留,请选择 ""启用""。 8. 在 ""依法保留"" 下,选择 ""启用"" 或 ""禁用""。 9. 选择 ""保存更改"" 以保存您的配置。 通过按照以上步骤,您可以在控制台上配置 Amazon S3 对象锁定。请注意,启用对象锁定后,您将无法禁用或暂停版本控制。","[""https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/userguide/object-lock-console.html"",""https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/userguide/object-lock.html""]",TRUE,FALSE,只能在创建S3桶时启用对象锁定,要在控制台中配置 Amazon S3 对象锁定,请遵循以下步骤: 1. 登录到 AWS Management Console,然后通过以下网址打开 Amazon S3 控制台:https://console.aws.amazon.com/s3/。 2. 在 Buckets(桶)列表中,选择您想要配置对象锁定的桶的名称。 3. 在 Objects(对象)列表中,选择要为其启用或禁用对象锁定的对象的名称。这将打开对象概述页面。 4. 在 Object Lock(对象锁定)下,选择编辑(Edit)。这将在右侧显示对象锁定的配置选项。 5. 如果要启用对象锁定,只需确保勾选了 Object lock enabled(对象锁定已启用)复选框。如果要从桶中移除对象锁定,请清除此复选框。 6. 如果需要为对象启用保留期限,可以在 Object lock retention(对象锁定保留)下拉菜单中选择适当的保留期限。如果要将依法保留应用于对象,请在 Object lock legal hold(对象锁定依法保留)下拉菜单中选择Enable(启用)。 7. 完成后,选择保存更改(Save)。现在,所选对象应根据所选的保留配置受到对象锁定的保护。 请注意,对象锁定只适用于受版本控制的桶。如果您希望在创建新桶时自动启用对象锁定,可以在创建桶的过程中选择对象锁定选项。,FALSE,只能在创建S3桶时启用对象锁定,要使用控制台配置 Amazon S3 对象锁定,可以按照以下步骤进行操作: 1. 登录到 AWS Management Console,然后通过以下网址打开 Amazon S3 控制台:https://console.aws.amazon.com/s3/。 2. 在 Buckets(桶)列表中,选择您想要的桶的名称。 3. 在 Objects(对象)列表中,选择要为其启用或禁用依法保留的对象的名称。 Object overview(对象概述)随即打开,其中显示对象的属性。 4. 在 Object Lock legal hold(对象锁定依法保留)下,选择 Edit(编辑)。 5. 在 Legal hold(依法保留)下,选择 Enable(启用)或 Disable(禁用)。 6. 选择保存更改。 这样就可以使用控制台配置 Amazon S3 对象锁定了。,FALSE,只能在创建S3桶时启用对象锁定,"您可以通过AWS管理控制台配置Amazon S3对象锁定,步骤如下: 1. 登录AWS管理控制台,打开Amazon S3控制台。 2. 创建一个新桶,或者选择一个已存在的桶。 3. 在""属性""选项卡下,找到""对象锁定""部分,选择""启用""。 4. 点击""保存""保存设置。 5. 对于新创建的桶,还需要启用版本控制。点击""属性""选项卡的""版本控制""部分,选择""启用""。 6. 在对象列表中,选择要应用对象锁定的对象,点击""操作""按钮。 7. 选择""编辑对象锁定""选项。 8. 在弹出窗口中,可以配置保留期限或者依法保留。保留期限需要设置到期日期;依法保留则一直有效直到手动删除。 9. 点击""保存更改""应用对象锁定设置。 这样就可以通过AWS管理控制台为S3桶和对象配置对象锁定。启用对象锁定的桶中上传的新对象,也可以按上述步骤编辑锁定设置。",FALSE,只能在创建S3桶时启用对象锁定,"创建新的 S3 存储桶时启用对象锁定: 1. 创建新桶,同时启用对象锁定。2.(可选)为放在桶中的对象配置默认保留期限。3. 将要锁定的对象放入桶。4. 将保留期限和/或依法保留应用于要保护的对象。 - - -在现有 S3 存储桶上启用对象锁定: 1.登录 AWS 管理控制台并通过以下网址打开 Amazon S3 控制台:https://console.aws.amazon.com/s3/。2.在左侧导航窗格中,选择存储桶。3.在存储桶列表中,选择要启用对象锁定的存储桶的名称。4.选择属性选项卡。5.在“属性”下,向下滚动到“对象锁定”部分,然后选择“编辑”。6.在对象锁定下,选择启用。7.您必须确认启用对象锁定将永久允许锁定此存储桶中的对象。8.选择保存更改。", -https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/userguide/WebsiteEndpoints.html,https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/userguide/WebsiteEndpoints.html,Amazon S3 静态网站端点支持 HTTPS吗?,是的,Amazon S3 静态网站端点不支持 HTTPS。,"[""https://repost.aws/questions/QUJvf1TajPQeKuLuKoDCSVNw"",""https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/userguide/WebsiteHosting.html""]",TRUE,TRUE,,Amazon S3 网站终端节点不支持 HTTPS。但是,可以使用 Amazon CloudFront 为 Amazon S3 上托管的静态网站提供服务。如需了解更多关于如何实现此功能的信息,请参阅“使用 CloudFront 为我的 Amazon S3 存储桶提供 HTTPS 请求”部分。,TRUE,,Amazon S3 静态网站终端节点本身不支持 HTTPS,但是可以通过使用 Amazon CloudFront 来为 Amazon S3 上托管的静态网站提供服务。如果您需要使用 HTTPS,可以考虑使用 CloudFront,它提供了自定义域名和 HTTPS 支持。,TRUE,,"不,Amazon S3 静态网站端点不直接支持 HTTPS。 Amazon S3 网站端点是用来托管静态网站的,但不支持 HTTPS。如果要为 S3 静态网站启用 HTTPS,有以下两种主要方法: 1. 使用Amazon CloudFront为S3静态网站提供服务。CloudFront支持使用HTTPS,并可以与S3集成以提供静态网站内容。 2. 使用Application Load Balancer将流量定向到S3网站端点。ALB支持HTTPS,可以终止SSL并通过HTTP将请求转发到S3网站端点。 另外,如果使用的是自定义域名,则需要从证书颁发机构获取SSL/TLS证书,并在CloudFront或ALB上安装证书来启用HTTPS。 总结一下: - S3静态网站端点不直接支持HTTPS - 要为S3静态网站启用HTTPS,可使用CloudFront或ALB终止SSL,并通过HTTP将请求转发到S3 - 需要获取SSL/TLS证书并在CloudFront或ALB上安装证书",TRUE,,Amazon S3 网站端点不支持 HTTPS 或接入点。如果要使用 HTTPS,则可以使用 Amazon CloudFront 为 Amazon S3 上托管的静态网站提供服务。, -https://docs.aws.amazon.com/zh_cn/efs/latest/ug/storage-classes.html,https://docs.aws.amazon.com/zh_cn/efs/latest/ug/storage-classes.html,Amazon EFS 提供哪些存储类?,Amazon EFS 提供了以下存储类: 1. EFS Standard 标准存储类 2. EFS Standard-IA 低频访问(标准IA)存储类 3. EFS One Zone 单区和 EFS One Zone-IA 低频访问(单区-IA)存储类 4. EFS 单区 IA 低频访问(单区-IA)存储类,"[""https://docs.aws.amazon.com/zh_cn/efs/latest/ug/storage-classes.html"",""https://repost.aws/questions/QU0AftMN0NRpe0vFPkYx__SQ""]",TRUE,TRUE,,Amazon EFS 提供了四种类型的存储类,分别是:EFS 标准、EFS 标准 - 低频访问 (标准 IA)、EFS 单区和 EFS 单区 - 低频访问 (EFS 单区-IA)。这些存储类旨在满足不同的使用场景和要求,例如频繁访问的数据、并非每天都访问的文件等。,TRUE,,Amazon EFS 提供多种存储类别,包括 EFS 标准、EFS 标准 - 低频访问 (IA)、EFS 单区和 EFS 单区 - 不频繁访问 (IA)。每种存储类别都有特定的设计用途和特点。,TRUE,,"根据背景知识,Amazon EFS 提供以下存储类: - EFS 标准:用于频繁访问的数据,提供区域级别的高可用性和持久性。 - EFS 标准-IA(低频访问):用于不经常访问但需要高可用性和持久性的数据,以更低的成本存储。 - EFS One Zone:用于频繁访问的数据,提供单可用区级别的可用性和持久性。 - EFS One Zone-IA(低频访问):用于不经常访问但需要单可用区级别的可用性和持久性的数据,以更低的成本存储。 每个存储类在可用性、持久性、最短存储持续时间等方面有所不同,需要根据访问频率和对可用性、持久性的要求来选择合适的存储类。",TRUE,,"Amazon EFS 提供以下存储类: - - -- EFS 标准:用于频繁访问的数据,提供区域级别的高可用性和持久性。 - - -- EFS 标准-IA(低频访问):用于不经常访问但需要高可用性和持久性的数据,以更低的成本存储。 - - -- EFS One Zone:用于频繁访问的数据,提供单可用区级别的可用性和持久性。 - - -- EFS One Zone-IA(低频访问):用于不经常访问但需要单可用区级别的可用性和持久性的数据,以更低的成本存储。 - - --EFS Archive: 一种成本优化的存储类别,适用于每年访问几次或更少的数据。 - - -每个存储类在可用性、持久性、最短存储持续时间等方面有所不同,需要根据访问频率和对可用性、持久性的要求来选择合适的存储类。", -https://docs.aws.amazon.com/zh_cn/eventbridge/latest/userguide/eb-service-event-list.html,https://docs.aws.amazon.com/zh_cn/eventbridge/latest/userguide/eb-service-event-list.html,AWS哪些服务可以向EventBridge发送事件?,以下AWS服务可以向EventBridge发送事件:Alexa for Business、Amazon API Gateway、AWS AppConfig、Amazon AppFlow、Application Auto Scaling、AWSProfiler、AWS Application Migration Service、Amazon Athena、AWS Backup、AWS Batch、Amazon Braket、AWS Certificate Manager、Amazon Chime、Amazon Cloud Directory、AWS CloudFormation、Amazon CloudFront、AWS CloudHSM、Amazon CloudSearch、AWS CloudShell、来自AWS CloudTrail的事件、Amazon CloudWatch、Amazon AppCloudWatch、亚马逊CloudWatch互联网监视器、亚马逊CloudWatch日志、Amazon SCloudWatch ynthetics、AWS CodeArtifact、AWS CodeBuild、AWS CodeCommit、AWS CodeDeploy、亚马逊CodeGuru概况器、AWS CodePipeline、AWSCodeStar、AWSCodeStar连接、Amazon Cognito Identity、Amazon Cognito用户池、Amazon Cognito Sync。,"[""https://docs.aws.amazon.com/zh_cn/eventbridge/latest/userguide/eb-service-event.html"",""https://docs.aws.amazon.com/zh_cn/eventbridge/latest/userguide/eb-service-event-list.html""]",TRUE,TRUE,,AWS许多服务都可以向EventBridge发送事件。以下是一些常见的例子: 1. Amazon S3 - 当对存储在Amazon S3中的对象进行操作(如创建、修改或删除对象)时,Amazon S3会生成事件并发送到EventBridge。 2. Amazon EC2 - 当Amazon EC2实例的状态发生变化(如启动、停止或替换)时,Amazon EC2会生成事件并发送到EventBridge。 3. Amazon Lambda - 当你在Amazon Lambda中触发函数时,Amazon Lambda会生成事件并发送到EventBridge。 4. Amazon Kinesis - 当在Amazon Kinesis数据流中发生特定事件(如数据到达或数据遗漏)时,Amazon Kinesis会生成事件并发送到EventBridge。 5. Amazon CloudWatch - 当在Amazon CloudWatch中设置报警时,Amazon CloudWatch会生成事件并发送到EventBridge。 6. Amazon API Gateway - 当对Amazon API Gateway的基干线程进行操作时(如创建、删除或更新基电线程),Amazon API Gateway会生成事件并发送到EventBridge。 7. Amazon SageMaker - 当在Amazon SageMaker中训练模型、部署模型或在Amazon SageMaker Notebook中运行代码时,Amazon SageMaker会生成事件并发送到EventBridge。 8. Amazon SQS - 当在Amazon SQS队列中发生特定事件(如消息到达或消息遗漏)时,Amazon SQS会生成事件并发送到EventBridge。 9. Amazon DynamoDB - 当对Amazon DynamoDB表进行操作(如创建、删除或更新表)时,Amazon DynamoDB会生成事件并发送到EventBridge。 这些只是其中的一部分,实际上几乎所有的AWS服务都可以向EventBridge发送事件。你可以查看[AWS服务事件参考指南](https://docs.aws.amazon.com/eventbridge/latest/reference/support-providing-events-to-eventbridge.html)以获取更全面的信息。,TRUE,,AWS有许多服务可以向EventBridge发送事件。以下是一些例子: - Amazon Elastic Compute Cloud (Amazon EC2) - Amazon EC2 Auto Scaling - Amazon EC2 Spot 实例 - Amazon Elastic Container Registry - Amazon Elastic Container Service - AWS Elastic Disaster Recovery - Amazon Elastic File System - Amazon Elastic Kubernetes Service - 弹性负载均衡 - 亚马逊弹性MapReduce - Amazon Elastic Transcoder - AWS Elemental MediaConnect - AWS Elemental MediaConvert - AWS Elemental MediaLive - AWS Elemental MediaPackage - AWS Elemental MediaStore - Amazon EMR - Amazon EMR on EKS - Amazon EMR Serverless - AWS Fault Injection Simulator - Forecast - Amazon GameLift - AWS Glue - AWS Glue DataBrew - AWS IoT GreengrassV1 - AWS IoT GreengrassV2 - AWS Ground Station - Amazon GuardDuty - AWS Health - AWS Identity and Access Management (IAM) - IAM Access Analyzer - Amazon Inspector Classic - Amazon Inspector - AWS IoT - AWS IoT Analytics - Amazon Interactive Video Service - Amazon Kinesis - Amazon Kinesis Data Firehose - AWS Key Management Service删除用户主密钥 - AWS Key Management ServiceCMK 轮换 - AWS Key Management Service导入的密钥材料过期 - AWS Lambda - Amazon Location Service - Amazon Machine Learning - Amazon Macie - Amazon Managed Blockchain - AWS Managed Services - AWS Management Console登录 - AWS计量Marketplace - AWS Migration Hub - AWS Migration Hub Refactor Spaces - AWS 监控 - AWS Network Manager - 亚马逊OpenSearch服务 - AWS OpsWorks - AWS OpsWorks CM - AWS Organizations - Amazon Polly - AWS Private Certificate Authority - AWS Proton - Amazon QLDB - Amazon RDS - Amazon Redshift - Amazon Redshift 数据 API - Amazon Redshift Serverless - AWS Resource Access Manager - AWS Resource Groups - AWS Resource Groups Tagging API - Amazon Route 53 - Amazon Route 53 Recovery 就绪性 - Amazon SageMaker - Savings Plans - AWS Secrets Manager - AWS Security Hub - AWS Security Token Service - AWS Server Migration Service - AWS Service Catalog - AWS Signer - Amazon Simple Email Service - Amazon Simple Storage Service (Amazon S3) - Amazon S3 on Outposts - Amazon Simple Queue Service - Amazon Simple Notification Service - Amazon Simple Workflow Service - AWS Step Functions - AWS Storage Gateway - AWS Support - AWS Systems Manager - Amazon Transcribe - AWS Transit Gateway - Amazon Translate - AWS Trusted Advisor - AWS WAF - AWS WAF 区域 - AWS Well-Architected Tool - Amazon WorkDocs - Amazon WorkSpaces,TRUE,,"根据背景知识,AWS的许多服务可以生成EventBridge接收的事件。主要有以下几点: 1. 生成事件的AWS服务会尽最大努力或保证将事件发送到EventBridge。 2. 尽最大努力发送是指服务会尝试发送所有事件,但在极少数情况下可能失败。保证交付意味着服务会至少成功发送一次事件。 3. EventBridge在正常条件下会接收所有有效事件。如果因服务中断而未能交付,EventBridge会在24小时内重试。 4. 生成事件的服务包括EC2、S3、CloudWatch、CodePipeline、Elastic Container Service等。具体的服务列表可参见背景知识中的表格。 5. CloudTrail记录的AWS API调用也可以作为事件源。需要启用日志记录并配置传送到EventBridge。 6. 一些事件既可由服务发送也可由CloudTrail发送,如EC2的启动/停止实例。 7. CloudTrail支持跨账户访问事件和基于事件设置自动化工作流程。 所以综上,AWS的众多核心服务可以将事件发送到EventBridge,启用CloudTrail日志可以获取更多事件,两者共同支持事件驱动的服务器less应用和自动化流程。",TRUE,,以下AWS服务可以向EventBridge发送事件:Alexa for Business、Amazon API Gateway、AWS AppConfig、Amazon AppFlow、Application Auto Scaling、AWSProfiler、AWS Application Migration Service、Amazon Athena、AWS Backup、AWS Batch、Amazon Braket、AWS Certificate Manager、Amazon Chime、Amazon Cloud Directory、AWS CloudFormation、Amazon CloudFront、AWS CloudHSM、Amazon CloudSearch、AWS CloudShell、来自AWS CloudTrail的事件、Amazon CloudWatch、Amazon AppCloudWatch、亚马逊CloudWatch互联网监视器、亚马逊CloudWatch日志、Amazon SCloudWatch ynthetics、AWS CodeArtifact、AWS CodeBuild、AWS CodeCommit、AWS CodeDeploy、亚马逊CodeGuru概况器、AWS CodePipeline、AWSCodeStar、AWSCodeStar连接、Amazon Cognito Identity、Amazon Cognito用户池、Amazon Cognito Sync。, -https://docs.aws.amazon.com/zh_cn/neptune/latest/userguide/migrating-using-dms.html,https://docs.aws.amazon.com/zh_cn/neptune/latest/userguide/migrating-using-dms.html,如何使用AWS DMS服务将数据从关系数据库或 NoSQL 数据库迁移到 Amazon Neptune?,要使用AWS Database Migration Service (AWS DMS)将数据从关系数据库或NoSQL数据库迁移到Amazon Neptune,您可以按照以下步骤进行操作: 1. 创建AWS DMS表映射对象:使用JSON对象指定从源数据库读取哪些表、按什么顺序读取以及如何命名它们的列。您还可以使用此表映射配置对象来筛选正在复制的行,并提供简单的值转换。 2. 创建Neptune GraphMappingConfig:对于RDF数据(使用SPARQL查询),使用W3的标准R2RML映射语言编写GraphMappingConfig。对于属性图数据(使用Gremlin查询),GraphMappingConfig是一个JSON对象,按照GraphMappingConfig Property-Graph/Gremlin数据的布局进行配置。 3. 在具有相同VPC的AWS DMS复制实例中创建:在与Neptune数据库集群相同的VPC中创建一个AWS DMS复制实例,以执行数据迁移。 4. 创建一个Amazon S3存储桶:创建一个Amazon S3存储桶作为迁移数据的中间存储。 5. 运行AWS DMS迁移任务:运行AWS DMS迁移任务,以便将数据从源数据库加载到Amazon Neptune中。 请注意,这些步骤仅概述了迁移过程的一部分。您可以参考AWS Database Migration Service的用户指南和API参考文档以获取更详细的信息和操作步骤。,"[""https://docs.aws.amazon.com/zh_cn/neptune/latest/userguide/migrating-using-dms.html"",""https://docs.aws.amazon.com/zh_cn/neptune/latest/userguide/dms-neptune.html""]",TRUE,TRUE,,要使用 AWS DMS 服务将数据从关系数据库或 NoSQL 数据库迁移到 Amazon Neptune,请遵循以下步骤: 1. 创建 AWS DMS 表映射对象:这个 JSON 对象指定了应从源数据库读取哪些表、按什么顺序读取以及如何命名它们的列。同时,它还可以筛选正在复制的行,并提供简单的值转换,例如转换为小写或舍入。 2. 创建 Neptune GraphMappingConfig:这个配置指定了如何将将从源数据库提取的数据加载到 Neptune 中。对于 RDF 数据(使用 SPARQL 查询),使用 W3 的标准 R2RML 映射语言编写;对于属性图数据(使用 Gremlin 查询),GraphMappingConfig是一个 JSON 对象。 3. 在与 Neptune 数据库集群相同的 VPC 中创建一个 AWS DMS 复制实例,以执行迁移。 4. 创建一个 Amazon S3 存储桶,用作暂存正在迁移的数据的中间存储。 5. 运行 AWS DMS 迁移任务:这包括四个步骤:设置源端连接、设置目标端连接、开始迁移并监控进度。 6. 在 AWS DMS 中将 Neptune 设置为迁移目标,以了解如何将数据导入 Neptune。,TRUE,,要使用 AWS DMS 服务将数据从关系数据库或 NoSQL 数据库迁移到 Amazon Neptune,您可以按照以下步骤进行操作: 1. 创建 AWS DMS 表映射对象:首先,您需要创建一个 AWS DMS 表映射对象,用于定义如何从源数据库中提取数据。这个对象指定了应该读取哪些表、按什么样的顺序读取以及如何命名这些表的列。此外,它还允许筛选要复制的行并进行简单的值转换。 2. 创建 Neptune GraphMappingConfig:接下来,您需要创建一个 Neptune GraphMappingConfig,用于指定如何将从源数据库提取的数据加载到 Neptune 中。根据您的数据类型选择 RDF 数据或使用 Gremlin 查询。对于 RDF 数据,使用 W3 的标准 R2RML 映射语言编写;对于属性图数据,使用 JSON 对象来描述数据布局。 3. 创建 AWS DMS 复制实例:在与您的 Neptune 数据库集群相同的 VPC 中创建一个 AWS DMS 复制实例,用于执行数据迁移。 4. 设置数据源:配置复制实例以连接到您的源数据库,并确保数据迁移期间源数据库可以正常运行。 5. 创建 S3 存储桶:创建一个 Amazon S3 存储桶,用于暂存正在迁移的数据的中间存储。 6. 开始迁移任务:启动 AWS DMS 迁移任务,以便将数据从源数据库迁移到 S3 存储桶,然后从 S3 存储桶迁移到 Neptune 数据库。 在整个迁移过程中,源数据库可以保持正常运行,从而最大程度减少对应用程序的影响。,TRUE,,"要使用AWS Database Migration Service (AWS DMS) 将数据从关系数据库或 NoSQL 数据库迁移到 Amazon Neptune,主要需要以下步骤: 1. 在与Neptune数据库集群相同的VPC中创建一个AWS DMS复制实例。 2. 创建一个Amazon S3桶作为迁移过程中的中间存储。 3. 创建AWS DMS表映射配置,指定要从源数据库迁移哪些表以及如何映射它们。 4. 对于RDF数据,创建R2RML映射文件将关系数据映射到图形。对于属性图数据,创建GraphMappingConfig JSON对象。 5. 在AWS DMS中,使用上述资源创建一个迁移任务,将源数据库指定为源端点,将Neptune指定为目标端点。 6. 运行迁移任务。AWS DMS会从源数据库中读取数据,应用表映射和图形映射配置,并将数据加载到Neptune中。 7. 迁移完成后,在Neptune中验证数据,然后就可以开始查询和分析图形数据了。 整个过程中源数据库可保持在线,最大限度地减少应用程序停机时间。AWS DMS和Neptune结合提供了一个高效的数据迁移解决方案。",TRUE,,使用的迁移数据流AWS DMS如下所示:1. 创建AWS DMS表映射对象。此 JSON 对象指定应从源数据库读取哪些表、按什么顺序读取以及如何命名它们的列。它还可以筛选正在复制的行,并提供简单的值转换,例如转换为小写或舍入。2. 创建 NeptuneGraphMappingConfig 以指定如何将从源数据库提取的数据加载到 Neptune 中。对于 RDF 数据(使用 SPARQL 查询),GraphMappingConfig 使用 W3 的标准 R2RML 映射语言编写。对于属性图数据(使用 Gremlin 查询),GraphMappingConfig是一个 JSON 对象,如中所述GraphMappingConfig Property-Graph/Gremlin 数据的布局。3. 在与您的 Neptune 数据库集群相同的 VPC 中创建一个AWS DMS复制实例,以执行迁移。4. 创建一个 Amazon S3 存储桶,用作暂存正在迁移的数据的中间存储。5. 运行AWS DMS迁移任务, -https://docs.aws.amazon.com/zh_cn/iotanalytics/latest/userguide/ingest-data.html,https://docs.aws.amazon.com/zh_cn/iotanalytics/latest/userguide/ingest-data.html,如何将数据发送到AWS IoT Analytics?,要将数据发送到AWS IoT Analytics,可以使用以下两种方法之一: 1. 使用AWS IoT消息代理: - 创建一个IAM角色,并授予该角色向AWS IoT Analytics频道发送消息数据的权限。 - 创建一个规则,将特定主题的消息路由到AWS IoT Analytics。 - 将规则与通道相关联,并将通道与数据存储相关联。 - 使用AWS IoT控制台发送消息到指定主题。 2. 使用AWS IoT AnalyticsBatchPutMessage API: - 使用AWS IoT Analytics BatchPutMessage API发送消息到指定的数据存储。 以上是两种将数据发送到AWS IoT Analytics的方法。具体选择哪种方法取决于您的需求和环境。,"[""https://docs.aws.amazon.com/zh_cn/iotanalytics/latest/userguide/ingest-data.html"",""https://repost.aws/questions/QUUHa-iQh_Sye2LWbnRKpkOg""]",TRUE,TRUE,,要将数据发送到AWS IoT Analytics,您需要使用一种方法将IoT消息代理或BatchPutMessage API。以下是这两种方法的简要说明: 1. **使用AWS IoT消息代理**:要使用AWS IoT消息代理,您需要使用规则引擎创建AWS IoT规则。该规则将具有特定主题的消息路由到AWS IoT Analytics。但首先,该规则要求您创建一个角色以授予所需的权限。然后,创建AWS IoT规则,然后将消息路由到AWS IoT Analytics。 2. **使用BatchPutMessage API**:使用BatchPutMessage API,您可以直接将消息发送到AWS IoT Analytics。这要求您使用AWS SDK(如Python、Java或Go SDK)或在命令行界面(CLI)上运行命令。首先,您需要创建一个包含要发送的消息的JSON文件。然后,使用BatchPutMessage API将消息发送到AWS IoT Analytics。,TRUE,,您可以使用AWS IoT消息代理或将数据发送到AWS IoT AnalyticsBatchPutMessage API来将数据发送到AWS IoT Analytics。这两种方法都可以将消息数据发送到您的AWS IoT Analytics频道。,TRUE,此回答的断句不太好,"有两种主要方法可以将数据发送到AWS IoT Analytics进行分析: 1. 使用AWS IoT消息代理(MQTT) - 在AWS IoT Core中创建一个规则,将特定主题的消息路由到AWS IoT Analytics通道。 - 需要先创建一个IAM角色,授予规则发送消息到AWS IoT Analytics的权限。 - 当与规则匹配的消息到达时,数据会自动流入AWS IoT Analytics管道和存储。 2. 使用BatchPutMessage API - 这不需要设置AWS IoT规则。 - 设备/应用程序需要使用AWS SDK或CLI调用BatchPutMessage API来发送数据。 - 每次调用都会将一批消息直接发送到指定的AWS IoT Analytics通道。 总结: - 使用AWS IoT消息代理的方法更适合持续的数据流。 - 使用BatchPutMessage的方法更适合批量发送历史数据。 - 两种方法都可以将数据导入AWS IoT Analytics进行处理和分析。",TRUE,,有两种主要方法可以将数据发送到AWS IoT Analytics进行分析: 1. 使用AWS IoT消息代理(MQTT) 2. 使用BatchPutMessage API, -https://docs.aws.amazon.com/zh_cn/iot/latest/fleethubuserguide/what-is-aws-iot-monitor-how-it-works.html,https://docs.aws.amazon.com/zh_cn/iot/latest/fleethubuserguide/what-is-aws-iot-monitor-how-it-works.html,Fleet Hub for AWS IoT Device Management的使用场景?,Fleet Hub for AWS IoT Device Management的使用场景是管理AWS IoT设备。它提供了一个Web应用程序,可以帮助用户、组和角色管理他们的设备。用户可以使用这个应用程序来检索AWS IoT设备数据、执行实例集级别的操作,以及监控和控制设备的状态。此外,Fleet Hub还提供了一系列的警报和警报操作,以便用户可以及时了解设备的状态和性能。通过Fleet Hub,用户可以更方便地管理和监控他们的AWS IoT设备,提高设备的可靠性和安全性。,"[""https://docs.aws.amazon.com/zh_cn/iot/latest/fleethubuserguide/security-iam-awsmanpol.html"",""https://docs.aws.amazon.com/zh_cn/iot/latest/fleethubuserguide/aws-iot-monitor-technician.html""]",TRUE,TRUE,,Fleet Hub for AWS IoT Device Management是一个用于管理和监控IoT设备的Web应用程序。它提供了诸如设备注册、设备状态查询、设备远程控制和设备数据可视化等功能。它可以与各种IoT设备兼容,如传感器、摄像头、机器人等。此外,它还提供了一个用户友好的界面,使得非技术人员也能轻松地管理和监控IoT设备。,TRUE,,Fleet Hub for AWS IoT Device Management主要用于管理和监控AWS IoT设备和设备数据。它提供了以下主要功能: 1. 设备管理:包括设备的注册、配置、升级和管理等。 2. 远程监视和控制:可以远程监视和控制设备的状态和行为。 3. 数据分析和可视化:提供了设备性能、故障和异常的分析和可视化工具。 4. 任务调度和自动化:可以自动调度任务和执行设备操作。 5. 安全性和合规性:支持设备和数据的安全性和合规性检查。 6. 集成和协作:与AWS IoT的其他服务以及第三方应用进行集成和协作。 因此,Fleet Hub for AWS IoT Device Management广泛适用于各种工业制造、物流运输、智慧城市等领域,用于设备监控与管理、任务调度与自动化等方面。,TRUE,,"Fleet Hub for AWS IoT Device Management的主要使用场景包括: 1. 大规模设备管理 Fleet Hub适用于需要管理大量IoT设备的场景。它提供了一个集中式的Web应用来监控和管理大量设备。 2. 远程设备管理 对于分布在不同地理位置的设备,Fleet Hub可以提供远程监控和管理。 technicians不需要物理接触设备就可以进行诊断和维护。 3. 设备监控 Fleet Hub可以实时监控设备状态和性能指标,比如CPU利用率、内存使用等。并可以设置警报来通知问题。 4. 设备维护 可以通过Fleet Hub下发固件更新、远程重启等维护任务到设备。可以灵活的使用任务模板来批量执行操作。 5. 安全管理 可以设置安全配置策略,并监控设备的安全合规情况。当有安全问题时,可以立即采取补救措施。 6. 日志分析 Fleet Hub可以收集和分析设备日志,帮助诊断问题及发现异常行为。 7. 基于角色的访问控制 可以通过IAM策略细粒度的控制Fleet Hub中的用户访问权限。 总之,Fleet Hub适合需要集中监控和管理大规模IoT设备的各种场景。它提高了运维效率并增强了设备安全。",TRUE,,1. 可视化设备连接问题 — 您可以查看机群中断开连接的设备数量、设备的上次连接状态以及设备断开连接的原因。2. 设置告警 — 您可以设置阈值以在特定数量的设备断开连接时触发告警。当设备因特定原因断开连接时,告警也会通知您。然后,您可以查看详细的设备数据以进行调查和排除故障。3. 运行任务 - 您可以在一台或多台设备上运行远程操作(如固件更新)。, -https://repost.aws/questions/QUnmvG3VBlTP-EzFCcPRRtrg,如果你使用Lake Formation来授予Athena用户或角色访问权限,那么是可以做到的。当您授予访问表的权限时,只需授予SELECT权限即可。,"如何限制Athena的访问权限,只允许用户进行SELECT查询?","要限制Athena的访问权限,只允许用户进行SELECT查询,可以使用以下方法: 1. 使用IAM ""athena:StartQueryExecution""权限:确保在IAM策略中授予用户该权限。这将允许用户在Athena中运行SELECT查询。 2. 设置查询数据使用控制:在Athena控制台中,为每个查询控制限制指定一个数据限制值。只允许用户查询的数据量不超过该限制值,超过限制值将导致查询被取消。 3. 使用CloudWatch告警和操作:创建每个工作组的数据使用控制,并设置多个数据使用阈值。当达到阈值时,CloudWatch会向指定的用户发送电子邮件告警,以通知他们查询超出了限制。 通过上述方法,可以限制Athena的访问权限,只允许用户进行SELECT查询。","[""https://docs.aws.amazon.com/zh_cn/athena/latest/ug/workgroups-setting-control-limits-cloudwatch.html"",""https://repost.aws/questions/QUnmvG3VBlTP-EzFCcPRRtrg""]",TRUE,TRUE,,"根据提供的信息,要实现这个目标,需要使用Amazon Lake Formation。当您授予用户访问表的权限时,只需授予SELECT权限即可。这将确保用户只能执行SELECT查询,而不能执行INSERT, UPDATE或DELETE等影响数据的操作。",TRUE,,可以使用Lake Formation来限制Athena的访问权限,只允许用户进行SELECT查询。当您授予访问表的权限时,只需授予SELECT权限即可。 Attenna允许您设置两种类型的成本控制:每个查询限制和每个工作组限制。对于每个工作组,您可以设置一个每个查询限制和多个每个工作组限制。,TRUE,,"根据背景知识,要限制Athena用户只能进行SELECT查询,可以采取以下方法: 1. 使用Lake Formation为Athena用户或角色授予访问表的权限时,只授予SELECT权限,不要授予INSERT权限。 2. 在Athena中,为工作组设置每查询数据使用控制,限制每个查询可以扫描的数据量。如果查询试图扫描超过限制的数据,查询会被取消。 3. 为工作组设置每小时或每日的数据使用阈值。当查询扫描的数据量达到阈值时,可以触发Amazon SNS通知,提醒管理员。虽然不会自动取消查询,但可以及时发现异常情况。 4. 配置CloudWatch警报,当Athena查询失败次数超过阈值时,向管理员发送通知。失败可能是由于数据量超限或权限不足导致的。 5. 在必要时,调用Lambda函数或禁用工作组,暂停Athena的查询能力。 6. 配置S3存储桶生命周期,在Athena查询失败时终止和删除部分查询结果。 综合利用Lake Formation、工作组控制、CloudWatch警报等手段,可以有效限制Athena只读访问,发现并制止异常情况,保护数据安全。",TRUE,标注部分跟回答不太相关,可以使用Lake Formation来限制Athena的访问权限,只允许用户进行SELECT查询。当您授予访问表的权限时,只需授予SELECT权限即可。, -https://repost.aws/questions/QUKGnKlubVR2S15RMOA_8mxw,"如果数据通过Amazon Kinesis Data Streams (KDS)流式传输,则请选择以下选项之一: - - -1. Kinesis Data Streams --> Lambda,使用[Redshift Data API](https://docs.aws.amazon.com/redshift/latest/mgmt/data-api.html) --> Redshift -2. Kinesis Data Streams --> Kinesis Firehose --> Redshift -3. Kinesis Data Streams --> Kinesis Firehose --> Amazon S3 (分区) <-- Redshift Spectrum (定期运行AWS Glue爬虫) - - -使用这些选项,数据一收到就可以进行查询。但是,有时您可能需要等待相当长一段时间才能查询数据。 - - -为了更具成本效益,可以采取以下方法: -首先,通过Kinesis Data Streams --> Kinesis Firehose --> S3 --> Lambda --> S3 (优化为Parquet或ORC)将数据写入Amazon S3。然后,定期(例如每小时)运行AWS Glue爬虫以刷新AWS Glue数据目录。使用AWS Glue数据目录通过Amazon Spectrum Spectrum从Redshift查询数据。","我的产品每分钟发送约20万个事件到网站以发布广告,将这些大量数据实时传输到Amazon Redshift的最佳方式是什么?",根据所提供的知识资源,最佳的将大量数据实时传输到Amazon Redshift的方式是使用Amazon Kinesis Data Streams (KDS)流式传输。以下是三种可能的解决方案: 1. Kinesis Data Streams --> Lambda,使用Redshift Data API --> Redshift 2. Kinesis Data Streams --> Kinesis Firehose --> Redshift 3. Kinesis Data Streams --> Kinesis Firehose --> Amazon S3 (分区) <-- Redshift Spectrum (定期运行AWS Glue爬虫) 通过这些方法,数据可以实时传输到Amazon Redshift,可以在数据到达时进行查询。然而,需要注意的是,查询可能需要等待一段时间才能完成。 为了实现成本效益,可以考虑以下方法: 1. 将数据写入Amazon S3,然后定期运行AWS Glue爬虫刷新数据目录。 2. 使用AWS Glue数据目录通过Amazon Spectrum Spectrum从Redshift查询数据。 此外,可以使用EventBridge来监控数据API,将实时数据流发送到AWS Lambda和Amazon SNS等目标。通过EventBridge,您可以收到类似于CloudWatch Events的事件。 无论选择哪种解决方案,都需要确保数据传输的可靠性,例如设置合适的状态字段(如FINISHED)来确保数据传输成功完成。 请注意,以上回答基于所提供的知识资源,如有其他因素或要求,请提供更多详细信息,以便提供更准确的回答。,"[""https://docs.aws.amazon.com/zh_cn/redshift/latest/mgmt/data-api-monitoring-events.html"",""https://repost.aws/questions/QUKGnKlubVR2S15RMOA_8mxw""]",TRUE,TRUE,,根据您的需求,将实时数据发送到Amazon Redshift的最佳方式是使用Amazon Kinesis Data Streams(KDS)。您可以选择以下两种方案之一: 1. 使用Kinesis Data Streams → Lambda,使用[Redshift Data API](https://docs.aws.amazon.com/redshift/latest/mgmt/data-api.html) → Redshift。这将使数据在收到后立即进行查询,但可能需要一些时间才能看到完整的数据集。 2. 使用Kinesis Data Streams → Kinesis Firehose → Redshift。这种方式可以提供更具成本效益的数据处理方式。首先,将数据写入Amazon S3(分为多个文件),然后将数据转换为优化的格式(如Parquet或ORC),最后使用AWS Glue爬虫定期地将数据加载到Redshift中进行查询。这种方法需要较长的数据处理时间,但可以节省成本。 对于您的特定情况,我们建议您尝试第二种方法,因为它具有更高的成本效益。您可以根据实际情况调整这两种方法,以达到最佳的数据处理效果和成本控制。,FALSE,,对于大规模数据传输到Amazon Redshift,最好的方法是使用Amazon Kinesis Data Streams (KDS) 进行流式传输,并选择以下三种方式之一: 1. Kinesis Data Streams → Lambda → Redshift Data API → Redshift 2. Kinesis Data Streams → Kinesis Firehose → Redshift 3. Kinesis Data Streams → Kinesis Firehose → Amazon S3(分区)→ Redshift Spectrum(定期运行AWS Glue爬虫) 通过这些选项,数据可以实时传输并进行查询。然而,有时需要等待一段时间才能查询数据。 为了更经济高效地处理数据,可以考虑以下几种方法: 1. 先将数据通过Kinesis Data Streams → Kinesis Firehose → S3 → Lambda → S3(优化为Parquet或ORC)写入Amazon S3。然后,定期(例如每小时)运行AWS Glue爬虫来刷新AWS Glue数据目录。最后,使用AWS Glue数据目录通过Amazon Spectrum Spectrum从Redshift查询数据。 2. 在EventBridge中监控数据API,从您的应用程序、软件即服务(SaaS)应用程序和AWS服务传输实时数据流。EventBridge将该数据路由到诸如AWS Lambda和Amazon SNS之类的目标。这些事件与CloudWatch Events中发生的事件相同,提供几乎实时的系统事件流,描述AWS资源的变化。事件将被发送到包含Amazon Redshift数据库的帐户。 无论是哪种方法,您可以使用Amazon Redshift执行语句或批量执行语句的API,将WithEvent选项设置为true,以发送数据API事件。事件的state字段包含以下值之一:中止-用户停止了查询运行;失败-查询运行失败;完成-查询已成功完成。这样,可以确保数据的送达。,TRUE,,"根据背景知识,您的产品每分钟生成大约20万个事件用于发布广告。考虑到数据量很大且需要实时处理,我建议使用以下方式将数据流入Amazon Redshift: 1. 使用Amazon Kinesis Data Streams收集和传输数据流。它可以处理每秒数百万个事件的吞吐量。 2. 将Kinesis Data Streams与Kinesis Firehose配合使用,自动将数据流加载到Amazon S3。这提供了持久性存储。 3. 在S3上对数据进行分区和转换为列式格式(如Parquet)。这可以优化Redshift的查询性能。 4. 使用AWS Glue Crawler定期爬取S3数据,并将元数据catalog更新到AWS Glue Data Catalog。 5. 在Redshift中创建外部表,指向AWS Glue Data Catalog中爬取的Parquet数据。 6. 使用Amazon Redshift Spectrum即时查询S3中的数据,无需先加载到Redshift。这可以节省加载时间和存储成本。 7. 也可以定期使用COPY命令或Redshift Data API将必要的数据加载到Redshift进行更快的查询。 综上,使用Kinesis、S3、Glue和Spectrum的服务器less架构,既可以实现实时数据处理,也可以优化成本。适当加载热点数据到Redshift,可以平衡查询性能。",TRUE,,"如果数据通过Amazon Kinesis Data Streams (KDS)流式传输,则请选择以下选项之一: - - -1. Kinesis Data Streams --> Lambda,使用[Redshift Data API](https://docs.aws.amazon.com/redshift/latest/mgmt/data-api.html) --> Redshift -2. Kinesis Data Streams --> Kinesis Firehose --> Redshift -3. Kinesis Data Streams --> Kinesis Firehose --> Amazon S3 (分区) <-- Redshift Spectrum (定期运行AWS Glue爬虫) - - -使用这些选项,数据一收到就可以进行查询。但是,有时您可能需要等待相当长一段时间才能查询数据。 - - -为了更具成本效益,可以采取以下方法: -首先,通过Kinesis Data Streams --> Kinesis Firehose --> S3 --> Lambda --> S3 (优化为Parquet或ORC)将数据写入Amazon S3。然后,定期(例如每小时)运行AWS Glue爬虫以刷新AWS Glue数据目录。使用AWS Glue数据目录通过Amazon Spectrum Spectrum从Redshift查询数据。", -https://repost.aws/questions/QUHn6xmQj5Q8660_UgYpjqDw,EMR Serverless Worker 专门为Job 而服务,即使Job 在同一无服务器应用程序下运行,也不会共享Worker。,EMR Serverless中,当多个Job同时运行在同一个应用程序上时,它们是否会共享Worker的可用容量,还是每个作业获得了整个工作容量?,"当多个Job同时运行在同一个EMR Serverless应用程序上时,它们不会共享Worker的可用容量,每个作业获得的是整个工作容量。","[""https://repost.aws/questions/QUHn6xmQj5Q8660_UgYpjqDw"",""https://docs.aws.amazon.com/emr/latest/EMR-Serverless-UserGuide/pre-init-capacity.html""]",TRUE,TRUE,,回答:EMR Serverless Worker专门服务于Job,即使在同一无服务器应用程序中运行多个Job,它们也不会共享Worker。,TRUE,,在EMR Serverless中,每个Job都是独立运行的,不会共享Worker的可用容量。每个Job都会获得自己所需的工作容量,并且可以在需要时请求额外的资源。这意味着每个Job都有自己的Worker来处理任务,而不与其他Job共享Worker。,TRUE,,"根据背景知识,即使多个 Job 在同一 EMR Serverless 应用程序中运行,它们也不会共享 Worker。每个 Job 会获得专属的 Worker 容量。 EMR Serverless 为每个 Job 分配专用的 Worker,即使这些 Job 在同一个应用程序下运行,它们也不会共享 Worker。每个 Job 启动时,会根据需求获取独立的 Worker 容量,不会共享其他 Job 的可用容量。",TRUE,,EMR Serverless Worker 专门为Job 而服务,即使Job 在同一无服务器应用程序下运行,也不会共享Worker。, -https://repost.aws/questions/QUA5-yEBZBQo-8KuGqFfclxw,在设置账户时,您可以选择禁用通过电子邮件邀请的选项。如果客户已启用此选项并正在运行帐户,则可以创建支持case以从后台禁用该选项。(此选项不通过API公开),如何禁用QuickSight账户中的电子邮件邀请新用户选项?,要禁用 QuickSight 账户中的电子邮件邀请新用户选项,您可以通过设置账户来禁用该选项。在设置账户时,您可以选择禁用通过电子邮件邀请新用户的功能。如果客户已启用此选项并正在运行帐户,则可以创建支持案例以从后台禁用该选项。该选项不通过 API 公开。,"[""https://repost.aws/questions/QUA5-yEBZBQo-8KuGqFfclxw"",""https://docs.aws.amazon.com/zh_cn/quicksight/latest/user/managing-users.html""]",TRUE,TRUE,,要在QuickSight账户中禁用电子邮件邀请新用户选项,您可以按照以下步骤操作: 1. 在应用程序栏上选择您的用户名,然后选择管理QuickSight。 2. 选择Manage Users。在此屏幕上,您可以管理在您的账户中已存在的用户。 3. 找到要禁用的电子邮件邀请选项,它通常位于屏幕左侧的菜单中。 4. 选择一个合适的选项,例如“关闭”或“禁用”,以便在发送邀请时不再使用电子邮件。 请注意,这个功能可能不会立即生效,因为它可能需要一段时间才能更新。另外,确保您已经保存所有配置更改,以免丢失任何重要数据。,FALSE,选择了quicksight文档的内容回答,但是答非所问,您可以在设置账户时选择禁用通过电子邮件邀请新用户的选项。如果客户已经启用了这个功能并且正在运行账户,您可以创建一个支持案例,要求从后台禁用这个选项。需要注意的是,这个选项不会通过API公开。,,,"根据背景知识,有以下方法可以禁用QuickSight账户中允许通过电子邮件邀请新用户的功能: 1. 在设置QuickSight账户时,可以选择禁用通过电子邮件邀请的选项。这可以防止账户中的用户通过电子邮件邀请新用户。 2. 如果客户已经启用了通过电子邮件邀请用户的功能,并希望禁用它,可以创建支持案例请求Amazon后台禁用该功能。该功能当前不可通过API公开访问。 3. 作为账户管理员,可以限制哪些用户有权限邀请新用户。可以通过设置用户的角色来实现。将用户角色设置为“Author”或“Reader”可以防止他们邀请新用户。 4. 可以定期检查并删除不需要的用户账户,以控制账户中的用户数量。 5. 在企业版中,网络管理员可以通过从访问QuickSight的网络组中删除用户账户来暂时停用账户。这可以防止用户访问QuickSight。 6. 最后,可以完全删除不需要的用户账户,并选择是否转移或删除该用户拥有的资源。",TRUE,回答融合了repost和quicksight文档的知识,在设置账户时,您可以选择禁用通过电子邮件邀请的选项。如果客户已启用此选项并正在运行帐户,则可以创建支持case以从后台禁用该选项。(此选项不通过API公开), -https://repost.aws/questions/QUD0__16OOQsyJhac22if6ig,"Glue内置了重试功能,可以通过MaxRetries参数来实现。该参数可通过程序定义或使用Glue Studio在“作业详情”选项卡中设置。 - - -MaxRetries是一个整数,代表在作业运行失败后重试的最大次数。如果此参数不足以满足您的需求,请考虑将Glue作业包装在[Step Function](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-error-handling.html )中,在此处可以实现更复杂的重试/控制机制。",如何实现Glue Job在通信失败时自动重新执行以确保数据完整性?,"Glue Job在通信失败时可以自动重新执行以确保数据完整性。您可以在Glue Studio中通过设置""MaxRetries""参数来指定重试的最大次数。该参数可以通过程序定义或使用Glue Studio在""作业详情""选项卡中设置。您可以根据需要调整该参数,确保满足您的需求。另外,您还可以将Glue作业包装在AWS Step Function中,以实现更复杂的重试/控制机制。","[""https://repost.aws/questions/QUD0__16OOQsyJhac22if6ig""]",TRUE,TRUE,,要在AWS Glue中的作业通信失败时自动重新执行以确保安全数据完整性,可以使用内置的重试功能通过设置MaxRetries参数来实现。如果需要更复杂的重试和控制机制,可以考虑将Glue作业包装在AWS Step Function中。,TRUE,,"您可以使用AWS Glue的重试功能来实现通信失败时自动重新执行作业以保持数据完整性。具体来说,您可以设置一个名为""MaxRetries""的参数来指定在作业运行失败后重试的最大次数。 另外,如果您需要更复杂的重试和错误处理机制,可以考虑将Glue作业包装在AWS Step Function中。这样可以实现更灵活的故障恢复和控制策略。",TRUE,,"您的问题中提到了Glue Job在与On-Prem通信失败时,希望能自动重试执行Job来保证数据完整性。这里我建议可以采用以下方法: 1. 在Glue Job中设置MaxRetries参数,指定作业失败后最大重试次数。可以在作业脚本中设置,也可以在Glue Studio的“作业详情”中设置。 2. 使用AWS Step Functions来编排Glue Job。在Step Functions状态机中,可以在通信失败时实现更复杂的重试逻辑,比如递增时间间隔、最大尝试次数等。 3. 将Glue Job失败事件通过CloudWatch Events规则发送到Step Functions状态机,触发重试流程。 4. 在Step Functions中可以添加通知,在重试多次仍失败时发送通知。 5. 也可以考虑在通信失败时,将数据写入S3,在重试成功后进行校验和补偿处理。 6. 通过上述方法,可以实现Glue Job的故障容错能力,在通信不可靠时也能最大程度保证数据处理的完整性。",TRUE,,"Glue Job在通信失败时可以自动重新执行以确保数据完整性。您可以在Glue Studio中通过设置""MaxRetries""参数来指定重试的最大次数。该参数可以通过程序定义或使用Glue Studio在""作业详情""选项卡中设置。您可以根据需要调整该参数,确保满足您的需求。另外,您还可以将Glue作业包装在AWS Step Function中,以实现更复杂的重试/控制机制。", -https://repost.aws/questions/QUvOaZvA5BT56skWO0iu2kZA,"目前 Amazon EMR 总是在一个单一的可用区启动所有节点(主节点、核心任务节点)。在 Instance fleet 选项中,您可以在启动集群时指定多个子网,但是 EMR 会自动选择一个子网(可用节点最好的可用区)。 - - -使用 EMR 多主节点功能,EMR 确实会启动 3 个主节点,但它们仅在相同的可用区。多个主节点功能可降低主节点终止导致集群终止的概率(单个主节点集群的单个故障点)。除此之外,它还实现了 HDFS 名称节点、Yarn 资源管理器、Hbase 主节点等的高可用功能。",如何将多个EMR主节点部署在不同的可用区?,目前 Amazon EMR 总是在一个单一的可用区启动所有节点(主节点、核心任务节点)。在 Instance fleet 选项中,您可以在启动集群时指定多个子网,但是 EMR 会自动选择一个子网(可用节点最好的可用区)。 使用 EMR 多主节点功能,EMR 确实会启动 3 个主节点,但它们仅在相同的可用区。多个主节点功能可降低主节点终止导致集群终止的概率(单个主节点集群的单个故障点)。除此之外,它还实现了 HDFS 名称节点、Yarn 资源管理器、Hbase 主节点等的高可用功能。 启动 Amazon EMR 集群时,可以选择在集群中设置一个或三个主节点。只有 Amazon EMR 版本 5.23.0 及更高版本支持启动具有三个主节点的集群。Amazon EMR 可以利用 EC2 置放群组确保将主节点放置在不同的基础硬件上,从而进一步提高集群可用性。有关更多信息,请参阅Amazon EMR 与 EC2 置放群组的集成: 具有多个主节点的 Amazon EMR 集群提供以下主要优势: * 主节点不再发生单点故障。如果其中一个主节点发生故障,集群将使用其他两个主节点,不会中断运行。同时,Amazon EMR 会自动使用预置了相同配置和引导操作的新主节点替换发生故障的主节点。 * 亚马逊 EMR 支持 HDFS 的 Hadoop 高可用性功能 NameNode 和 YARNResourceManager 并支持其他一些开源应用程序的高可用性。 有关具有多个主节点的 Amazon EMR 集群如何支持开源应用程序和其他 Amazon EMR 功能的详细信息,请参阅 支持的应用程序和功能。 请注意,集群只能驻留在一个可用区或子网中。,"[""https://docs.aws.amazon.com/zh_cn/emr/latest/ManagementGuide/emr-plan-ha.html"",""https://repost.aws/questions/QUvOaZvA5BT56skWO0iu2kZA""]",TRUE,TRUE,回答融合了repost和EMR文档的知识,根据文章的内容,当前Amazon EMR总是在一个单一的可用区启动所有节点(主节点、核心任务节点)。虽然可以通过在Instance fleet选项中指定多个子网来在不同可用区部署EC2实例,但EMR会自动选择一个子网(可用节点最好的可用区)。然而,通过使用EMR的多主节点功能,可以启动具有3个主节点的集群,这可以降低主节点终止导致集群终止的概率。此外,Amazon EMR支持HDFS的Hadoop高可用性功能NameNode和YARN ResourceManager以及其他一些开源应用程序的高可用性。,TRUE,,目前,Amazon EMR总是在一个单一的可用区启动所有节点(主节点、核心任务节点)。虽然您可以在启动集群时使用 Instance fleet 选项指定多个子网,但是EMR会自动选择一个子网(可用节点最好的可用区)。如果您希望将多个EMR主节点部署在不同的可用区,可以考虑使用Amazon EMR的多主节点功能。这样可以在同一个集群中启用多个主节点,从而提高集群的可用性。有关如何使用多主节点功能来部署多个EMR主节点在不同可用区的具体步骤和方法,您可以参考Amazon EMR官方文档中的相关内容。,FALSE,EMR集群多主节点只能部署在同一个可用去,"根据背景知识,Amazon EMR目前不支持将主节点部署在不同的可用区。EMR集群中的所有主节点都会部署在同一个可用区。 但是,可以使用EMR多主节点功能在同一个可用区启动3个主节点,这可以提高主节点的高可用性,避免单点故障。另外,还可以使用EC2置放群组将主节点部署在不同的基础硬件上,进一步提高可用性。 要实现跨可用区的EMR高可用,一种方法是在不同可用区分别创建EMR集群,并使用某种机制(比如Zookeeper)使它们协调工作,实现跨可用区的高可用。但这需要自定义开发,EMR本身还不直接支持跨可用区部署。 总结来说,EMR目前不支持跨可用区部署,可以通过多主节点和置放群组提高单可用区内的高可用性。要实现跨可用区高可用需要额外的开发和协调。",TRUE,,"目前 Amazon EMR 总是在一个单一的可用区启动所有节点(主节点、核心任务节点)。在 Instance fleet 选项中,您可以在启动集群时指定多个子网,但是 EMR 会自动选择一个子网(可用节点最好的可用区)。 - - -使用 EMR 多主节点功能,EMR 确实会启动 3 个主节点,但它们仅在相同的可用区。多个主节点功能可降低主节点终止导致集群终止的概率(单个主节点集群的单个故障点)。除此之外,它还实现了 HDFS 名称节点、Yarn 资源管理器、Hbase 主节点等的高可用功能。", -https://repost.aws/questions/QUeoNM8W4XTjOrlZUx_ym3Ow,"可以在“操作->监控和故障排除->获取系统日志”下检查系统日志,看是否有关于为什么无法启动的线索。如果发现可操作的内容,停止实例,卸载引导卷,将卷连接到正在运行的实例上,在操作系统上挂载并修复问题。然后将其重新挂载到原始实例上并启动。 -您还可以尝试连接到EC2串行控制台的实例并从那里进行故障排除。如果所有其他方法都失败,也可以使用升级前创建的快照创建新实例。",如何解决Linux实例在升级和重启后未通过实例检查、无法连接的问题?,要解决Linux实例在升级和重启后未通过实例检查、无法连接的问题,您可以按照以下步骤进行操作: 1. 检查实例状态检查失败的日志信息:在实例控制台输出中查找有关实例状态检查失败的详细信息。这将帮助您了解失败的根本原因。 2. 检查实例的SELinux设置:在实例控制台输出中,查找有关SELinux设置的信息。如果SELinux被设置为强制模式,您需要禁用它并重新启动实例。在实例启动后,确保正确配置SELinux以确保它不会阻止实例的正常运行。 3. 检查实例的系统日志:在实例控制台输出中查找有关系统日志的错误信息。这些错误可能是导致实例无法连接的原因之一。根据错误信息进行适当的故障排除。 4. 检查实例的网络配置:检查实例的网络配置是否正确,包括网络设置和防火墙规则。确保实例可以访问所需的网络资源。 5. 检查实例的存储设备:检查实例的存储设备,确保硬盘驱动器正常工作,并且可以访问存储在其中的数据。 6. 检查实例的物理设备:检查实例的物理设备,例如硬盘驱动器、内存和电源。确保它们正常工作,并且没有损坏或故障。 7. 检查实例的日志文件:检查实例的系统日志文件,查找有关实例无法连接的更多信息。这些日志文件可能提供了有关实例问题的详细信息。 通过按照上述步骤进行故障排除,您应该能够解决Linux实例在升级和重启后未通过实例检查、无法连接的问题。如果问题仍然存在,请联系AWS解决方案团队以获取进一步的帮助和支持。,"[""https://repost.aws/questions/QUJX_d59FyTgm5yKMAeK4FHQ"",""https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/instance-console.html""]",FALSE,TRUE,检索到了另一个repost问题,根据提供的信息,这个问题可能是由于SELinux策略引起的。在硬件降级后,尝试启动实例时,可能会出现SELinux策略的问题。为了解决这个问题,首先需要创建一个新的实例,然后安装原始卷。接下来,需要在grub/menu.lst文件中添加selinux=0,以一次性禁用SELinux。这样,实例应该能够正常启动。然后,需要进行适当的设置,以便在SELinux策略下正常运行。,FALSE,,您可以通过以下步骤来解决 Linux 实例在升级和重启后未通过实例检查、无法连接的问题: 1. 创建一个新实例,并安装原始卷。这可以帮助确保您的应用程序和数据在升级过程中得到保护。 2. 更改 grub/menu.lst 文件,并添加 `selinux=0` 以一次性禁用 SELinux。这将有助于解决由于 SELinux 限制导致的问题。 3. 重启实例以确保更改生效。现在,您的实例应该能够正常启动并且可以连接到 SSH。 4. 如果需要,根据您的具体需求进行适当的设置和配置。 这些方法应该能够帮助您在 Linux 实例升级和重启后解决无法连接的问题。,FALSE,,"根据背景知识,Linux实例在硬件降级后重启失败,状态检查失败,显示kernel panic。 可以尝试以下步骤解决: 1. 检查实例控制台输出,定位kernel panic的具体原因。常见原因包括SELinux策略加载失败等。 2. 如果是SELinux策略问题,可以在启动参数中临时禁用SELinux(selinux=0),使实例能够启动。 3. 启动后,检查并修复SELinux策略配置,也可以考虑重新部署实例。 4. 如果仍无法定位问题,可以试着从实例创建一个AMI,然后从该AMI启动一个新实例,将数据迁移过去。 5. 在新实例上进一步调试和修复问题。 6. 也可以Raise Ticket给AWS Support,提供实例ID和控制台日志,寻求进一步协助。 7. 确保重要数据有备份,在故障实例上操作时小心谨慎。 综上所述,主要是利用控制台输出来定位问题,通过重建实例、迁移数据的方式恢复服务,也可以 Raise Ticket 寻求帮助。",FALSE,,"可以在“操作->监控和故障排除->获取系统日志”下检查系统日志,看是否有关于为什么无法启动的线索。如果发现可操作的内容,停止实例,卸载引导卷,将卷连接到正在运行的实例上,在操作系统上挂载并修复问题。然后将其重新挂载到原始实例上并启动。 -您还可以尝试连接到EC2串行控制台的实例并从那里进行故障排除。如果所有其他方法都失败,也可以使用升级前创建的快照创建新实例。", -https://repost.aws/questions/QUnV4R9EoeSdW0GT3cKBUR7w,"这些服务之间存在许多微妙的区别,但基本的思路是,EC2 Instance Connect允许使用短期密钥进行方便和安全的本地SSH连接,而Session Manager则允许通过代理连接隧道进行SSH连接。 - - -会话管理器代理与服务建立反向连接,因此例如在主机上打开22端口是不必要的。EC2 Instance Connect要求主机安全组允许ssh入站流量。 - - -还有几点需要注意的:EC2 Instance Connect仅支持Linux EC2主机,而Session Manager支持Windows和Linux主机,包括EC2实例和On-prem设备。",Session Manager和EC2 Instance Connect有什么不同?Session Manager是如何工作的?,Session Manager和EC2 Instance Connect是用于建立安全Shell (SSH)连接的两种不同选项。 EC2 Instance Connect是一种简单且安全的方式,使用基于浏览器的客户端、Amazon EC2 Instance Connect CLI或您选择的SSH客户端连接到您的Linux实例。它通过一次性使用的SSH公钥推送到实例元数据中,并允许您在60秒内使用该连接。EC2 Instance Connect不需要打开入站端口或维护堡垒主机,因此是一种方便且安全的连接方式。 Session Manager则允许使用代理连接隧道来建立SSH连接。它通过服务与主机建立反向连接,因此在主机上打开22端口是非必要的。Session Manager需要主机安全组允许SSH入站流量。与EC2 Instance Connect不同,Session Manager支持Windows和Linux主机,包括EC2实例和On-prem设备。 总的来说,EC2 Instance Connect更简单,提供了一种方便的本地SSH连接方式,而Session Manager则通过代理连接隧道提供更灵活和更全面的SSH连接功能。,"[""https://docs.aws.amazon.com/zh_cn/systems-manager/latest/userguide/session-manager-working-with.html"",""https://repost.aws/questions/QUnV4R9EoeSdW0GT3cKBUR7w""]",TRUE,FALSE,,Session Manager和EC2 Instance Connect都是用于在AWS实例上执行远程操作的方法,但它们之间存在一些关键区别。 1. 使用方式:Session Manager是一种基于代理的服务,允许用户在不需要手动管理密钥的情况下使用SSH连接到实例。而EC2 Instance Connect则提供了基于浏览器的客户端、Amazon EC2 Instance Connect CLI或使用您选择的SSH客户端连接到Linux实例的简单方法。 2. 支持的操作:Session Manager除了提供SSH连接外,还可以使用安全拷贝协议(SCP)在本地机器和托管实例之间复制文件。而EC2 Instance Connect主要用于简单的SSH连接。 3. 安全性:Session Manager可以确保连接的安全性和隐私性,因为它不会打开入站端口或维护堡垒主机。而EC2 Instance Connect则需要主机安全组允许ssh入站流量。 4. 适用场景:Session Manager适用于需要更高级功能和更大灵活性的情况,如跨多个实例的管理和维护。而EC2 Instance Connect更适合需要在Linux EC2实例上进行简单连接的场景。 总之,Session Manager和EC2 Instance Connect都是为了实现远程连接,但它们的功能和适用场景有所不同。Session Manager作为一种基于代理的服务,提供了更多的功能和支持,而EC2 Instance Connect则更注重简便性和安全性。,TRUE,,Session Manager和EC2 Instance Connect是两种用于远程连接到AWS实例的不同方法。 Session Manager允许用户在不需要手动管理密钥的情况下从本地笔记本电脑通过SSH连接到AWS实例。它使用AWS CLI来创建一个安全Shell (SSH) 连接,并且允许用户使用安全拷贝协议(SCP)在本地机器和托管实例之间复制文件。Session Manager使用代理连接隧道进行SSH连接,这意味着它不需要打开入站端口或维护堡垒主机。 另一方面,EC2 Instance Connect提供了一种更简单和安全的方式来连接到AWS实例。它使用基于浏览器的客户端、Amazon EC2 Instance Connect CLI或用户选择的SSH客户端来连接到Linux实例。当使用EC2 Instance Connect连接实例时,Instance Connect API会将一次性使用的SSH公钥推送到实例元数据中,并在那里保留60秒。 总的来说,Session Manager提供了更多的功能和灵活性,而EC2 Instance Connect更适用于简单的连接需求。,TRUE,"https://docs.aws.amazon.com/zh_cn/systems-manager/latest/userguide/session-manager-working-with-sessions-start.html#sessions-start-ssh , https://docs.aws.amazon.com/zh_cn/systems-manager/latest/userguide/session-manager-getting-started-enable-ssh-connections.html","Session Manager和EC2 Instance Connect之间主要的区别有: 1. 连接方式不同: - Session Manager通过SSM服务建立反向连接隧道,不需要开放实例的端口。 - EC2 Instance Connect需要实例安全组开放ssh端口,通过短期有效的ssh密钥连接。 2. 支持的实例类型不同: - Session Manager支持Linux和Windows实例,以及On-premises设备。 - EC2 Instance Connect只支持Linux实例。 3. 连接持续时间不同: - Session Manager的连接不受IAM角色会话持续时间限制。 - EC2 Instance Connect的ssh密钥只有60秒的有效期。 Session Manager的工作原理: 1. 用户通过SSM控制台或CLI发起连接请求。 2. 请求发送到SSM服务。 3. SSM服务与目标实例建立反向SSH隧道。 4. 用户通过隧道连接到实例,实现端到端加密的SSH连接。 5. 连接不依赖实例的安全组,所有流量都通过SSM服务进行路由。 6. 连接自动记录日志并可用于审计。 7. 连接不占用实例的端口并且不受IAM会话时长限制。 所以Session Manager提供了更安全、可审计和易于管理的实例连接方式。",TRUE,http://sawers.com/blog/aws-session-manager-a-better-way-to-ssh/,"这些服务之间存在许多微妙的区别,但基本的思路是,EC2 Instance Connect允许使用短期密钥进行方便和安全的本地SSH连接,而Session Manager则允许通过代理连接隧道进行SSH连接。 - - -会话管理器代理与服务建立反向连接,因此例如在主机上打开22端口是不必要的。EC2 Instance Connect要求主机安全组允许ssh入站流量。 - - -还有几点需要注意的:EC2 Instance Connect仅支持Linux EC2主机,而Session Manager支持Windows和Linux主机,包括EC2实例和On-prem设备。", -https://repost.aws/questions/QUQDKKXZjnQZGwAAe6bQYB8g,请检查AWS Batch计算环境对应的Service role是否存在。AWS Batch使用Service role来代表您管理EC2和ECS资源。如果在删除计算环境之前删除了该role,则AWS Batch将无法删除计算资源并进入INVALID状态。如果发现该role已被删除,则可重新创建具有相同名称的Service role,并尝试再次删除计算环境。,"如何处理通过""aws batch delete-compute-environment""命令删除计算环境后,未获得其他提示信息且计算环境仍然存在的问题?","如果通过""aws batch delete-compute-environment""命令删除计算环境后,未获得其他任何提示信息且计算环境仍然存在,可以尝试检查AWS Batch计算环境对应的Service role是否存在。AWS Batch使用Service role来代表您管理EC2和ECS资源。如果删除了该role,那么AWS Batch将无法删除计算资源并进入INVALID状态。如果服务角色已被删除,可以重新创建具有相同名称的Service role,并尝试再次删除计算环境。","[""https://repost.aws/questions/QUQDKKXZjnQZGwAAe6bQYB8g"",""https://docs.aws.amazon.com/batch/latest/APIReference/API_DeleteComputeEnvironment.html""]",TRUE,TRUE,,在删除计算环境之前,必须将计算环境的状态设置为DISABLED,并通过UpdateComputeEnvironment操作将其与任何作业队列解除关联。如果使用AWS Fargate资源的计算环境,必须在删除计算环境之前终止所有活动作业。如果不执行这些操作,计算环境将进入无效状态。在这种情况下,请检查AWS Batch计算环境对应的Service role是否存在。如果该role已被删除,可重新创建具有相同名称的Service role,然后再次尝试删除计算环境。,TRUE,该回答融合了API Reference和repost的知识是,当通过 `aws batch delete-compute-environment` 命令删除计算环境时,如果未得到其他提示信息并且计算环境仍然存在,可能是因为在删除之前,计算环境的 Service role 被删除了。AWS Batch 使用 Service role 来代表用户管理 EC2 和 ECS 资源。如果在删除计算环境之前删除了该 role,则 AWS Batch 将无法删除计算资源并将其处于 INVALID 状态。因此,建议检查 Service role 是否还存在,如果已经被删除,则可以重新创建一个具有相同名称的 Service role,然后再次尝试删除计算环境。,TRUE,,"根据背景知识,在删除AWS Batch计算环境前,需要确保以下两点: 1. 使用UpdateComputeEnvironment API将计算环境状态设置为DISABLED。 2. 使用UpdateJobQueue API解除计算环境与任何作业队列的关联。 另外,如果计算环境使用的是AWS Fargate资源,必须先终止该计算环境上的所有活动作业,否则计算环境会进入无效状态。 如果发现计算环境删除后仍存在,很有可能是计算环境对应的Service Role已被删除。AWS Batch使用该Service Role来管理EC2和ECS资源。 建议的解决方案是: 1. 检查计算环境对应的Service Role是否存在。 2. 如果该Role已删除,重新创建一个同名的Service Role。 3. 然后尝试再次删除计算环境。 这样就可以成功删除处于无效状态的计算环境。",TRUE,该回答融合了API Reference和repost的知识是,请检查AWS Batch计算环境对应的Service role是否存在。AWS Batch使用Service role来代表您管理EC2和ECS资源。如果在删除计算环境之前删除了该role,则AWS Batch将无法删除计算资源并进入INVALID状态。如果发现该role已被删除,则可重新创建具有相同名称的Service role,并尝试再次删除计算环境。, -https://repost.aws/questions/QUSZOkcWUDTged7CRf1_YaBQ,"不可以,付费 Linux 与免费 Linux 是启动实例的 AMI 产品代码的一部分。对于 Windows,为了启动 BYOL 实例,需要客户携带自己的介质(例如通过VM Import 导入黄金映像 Gold image)。 - - -对于客户直接从 Red Hat 购买许可证的 RHEL 映像,可以从 Red Hat 获取基本 BYOL 映像(请参阅 [FAQ](https://aws.amazon.com/partners/redhat/faqs/))。",如何在不使用Red Hat共享的AMI的情况下将按需RHEL实例转换为BYOL,而不用重新部署每台RHEL服务器?,不可以使用从 Red Hat 共享的 AMI 来转换按需 RHEL 实例为 BYOL。付费 Linux 与免费 Linux 是启动实例的 AMI 产品代码的一部分。对于 Windows,需要客户携带自己的介质(例如通过 VM Import 导入黄金映像 Gold image)来导入 BYOL。对于客户直接从 Red Hat 购买许可证的 RHEL 映像,可以从 Red Hat 获取基本 BYOL 映像。,"[""https://repost.aws/questions/QUSZOkcWUDTged7CRf1_YaBQ""]",TRUE,TRUE,,根据提供的信息,在不使用从Red Hat共享的AMI的情况下将按需RHEL实例转换为BYOL实例是不可行的。这是因为转换过程需要使用付费Linux与免费Linux作为启动实例的AMI的产品代码。对于Windows实例,如果需要启动BYOL实例,则需要客户自带介质,如通过VM Import导入黄金映像Gold image。对于已从Red Hat购买的许可证的RHEL映像,可以使用基本BYOL映像,但该映像仍需从Red Hat获取。因此,在不重新部署每台RHEL服务器的情况下实现这一目标是不可能的。,TRUE,,很抱歉,根据提供的信息,在不使用Red Hat共享的AMI的情况下将按需RHEL实例转换为BYOL是不可能的。这是因为付费Linux与免费Linux是启动实例的AMI产品代码的一部分。对于Windows,为了启动BYOL实例,需要客户携带自己的介质(例如通过VM Import导入黄金映像Gold image)。因此,您需要使用Red Hat共享的AMI或者使用自己购买的许可证来满足您的需求。,TRUE,,"根据背景知识,不可以直接将按需RHEL实例转换为BYOL,而不更改AMI或者重新部署服务器。这是因为付费Linux和免费Linux是启动实例的AMI产品代码的一部分。 但是,如果客户直接从Red Hat购买了RHEL许可证,可以从Red Hat获取基本BYOL映像,然后使用该映像启动新的BYOL实例,并将数据从按需实例迁移到新的BYOL实例上,从而实现转换。具体步骤如下: 1. 从Red Hat获取基本BYOL RHEL映像 2. 使用BYOL映像启动新的RHEL实例 3. 将按需实例的数据(文件、配置等)迁移到新的BYOL实例上 4. 验证数据迁移正确后,终止按需实例 5. 将应用和流量切换到新的BYOL实例 这样就可以实现按需到BYOL的转换,而不需要重新部署每台RHEL服务器,也不需要更改AMI。关键是从Red Hat获取BYOL映像,并通过数据迁移的方式实现实例的切换。",TRUE,,"不可以,付费 Linux 与免费 Linux 是启动实例的 AMI 产品代码的一部分。对于 Windows,为了启动 BYOL 实例,需要客户携带自己的介质(例如通过VM Import 导入黄金映像 Gold image)。 - - -对于客户直接从 Red Hat 购买许可证的 RHEL 映像,可以从 Red Hat 获取基本 BYOL 映像(请参阅 [FAQ](https://aws.amazon.com/partners/redhat/faqs/))。", -https://repost.aws/questions/QU-DoY2Wz3RXiMlDZb1gSwAw,这个问题可以通过编辑 `wp_blogs` 和 `wp_site` 表来解决,将旧的IP地址改成一个新的静态IP地址。,"我的Lightsail WordPress多站点设置使用动态IP,服务器重启后IP地址改变导致网站无法访问,如何解决?","可以通过编辑`wp_blogs`和`wp_site`表来更改旧的IP地址,将新的静态IP地址添加到其中。","[""https://repost.aws/questions/QU-DoY2Wz3RXiMlDZb1gSwAw"",""https://docs.aws.amazon.com/lightsail/2016-11-28/api-reference/API_AllocateStaticIp.html""]",TRUE,TRUE,,要解决这个问题,您可以通过编辑 `wp_blogs` 和 `wp_site` 表,将旧的IP地址更改为一个新的静态IP地址。在Lightsail中,您可以分配一个静态IP地址来解决问题。,TRUE,,您可以通过编辑 `wp_blogs` 和 `wp_site` 表来解决这个问题。首先,找到旧的IP地址并将其更改为一个新的静态IP地址。这样,当您的服务器重启时,新的静态IP地址将被分配给您的网站,从而解决无法访问的问题。,TRUE,,"根据背景知识,您可以通过以下步骤解决该问题: 1. 申请一个静态IP地址。可以使用Lightsail的AllocateStaticIp API来完成。 2. 编辑WordPress的wp_blogs和wp_site表,将原来的动态IP地址替换为新申请的静态IP地址。 3. 重新启动Lightsail实例,使用新分配的静态IP地址访问网站。 4. 如果需要,可以将域名指向新的静态IP地址。 这样就可以解决服务器重启后IP地址改变导致网站不可访问的问题。关键是配置一个静态IP地址,并在WordPress数据库中使用该静态IP。",TRUE,该回答融合了API Reference和repost的知识,这个问题可以通过编辑 `wp_blogs` 和 `wp_site` 表来解决,将旧的IP地址改成一个新的静态IP地址。, -https://repost.aws/questions/QURAmQgLB1Rcu4MfvXyUQEVQ,"你好,目前没有(至少没有直接的方法)可以将RDS快照导出到本地。RDS快照存储在S3上,但这些S3存储桶由AWS而非客户管理。 - - -如果您想在本地存储数据库快照,您需要使用数据库引擎支持的原生备份工具。例如,对于MySQL数据库,您可以使用mysqldump。 - - -另一个要问客户的问题是,为什么他们想要将RDS快照导出到本地?客户可以考虑将RDS快照复制到一个完全不同的帐户(作为备份帐户)中,并设置非常严格的权限,甚至可以复制到另一个区域作为其数据的“离线”备份。http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_CopySnapshot.html - - -有一个可能适用的限制是: -您无法将快照复制到以下区域或从以下区域复制:AWS GovCloud(美国),中国(北京)。",我想把RDS快照导出到本地,怎么做?,您无法直接将RDS快照导出到本地。RDS快照存储在S3上,并且由AWS管理。如果您想在本地存储数据库快照,您需要使用数据库引擎支持的原生备份工具,例如MySQL的mysqldump。您可以在数据库中创建一个备份任务,将快照导出到本地。导出的文件将以压缩和一致的Apache Parquet格式存储在S3存储桶中。导出的数据可以被导入到Amazon Athena或Amazon Redshift Spectrum等工具中进行分析。请注意,导出的过程在后台运行,不会影响活动数据库实例的性能。,"[""https://repost.aws/questions/QURAmQgLB1Rcu4MfvXyUQEVQ"",""https://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/UserGuide/USER_ExportSnapshot.html""]",TRUE,FALSE,该回答融合了repost和user guide的知识,但是总结不太准确,使用mysqldump将RDS快照导出到外部MySQL数据库和将RDS快照导出到S3是两回事,见https://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/UserGuide/MySQL.Procedural.Exporting.NonRDSRepl.html 和 https://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/UserGuide/USER_ExportSnapshot.html#USER_ExportSnapshot.Exporting,要将RDS快照导出到本地,您可以按照以下步骤操作: 1. 在Amazon RDS管理控制台中,找到您要导出的RDS实例,然后单击“快照”选项卡。 2. 选择您要下载的快照,然后单击“立即恢复”按钮。 3. 在弹出的对话框中,选择要将数据库恢复到哪个AWS账户,然后选择一个可用的AWS账户。如果没有可用的AWS账户,您需要创建一个新的。 4. 选择一个存放在亚马逊简答存储服务(S3)中的备份文件位置。如果您还没有S3存储桶,系统会提示您创建一个。 5. 确认设置后,系统开始将数据库快照下载到您指定的S3存储桶中。下载完成后,您可以在S3管理控制台中找到下载的数据库文件。 6. 您可以将这些文件复制到本地计算机上进行分析和处理。,FALSE,,要将RDS快照导出到本地,您可以按照以下步骤操作: 1. 在Amazon RDS控制台中选择您的RDS实例。 2. 单击“备份”选项卡,然后选择“创建备份”。 3. 输入备份名称和描述信息,然后选择备份存储位置。 4. 等待备份完成。 5. 下载备份文件。 6. 将备份文件保存到本地计算机上。 请注意,根据您的RDS实例的备份策略,备份可能需要在一定时间后才能完成。,FALSE,,"您好,目前没有直接的方法可以将RDS快照导出到本地。RDS快照存储在AWS管理的S3存储桶中,不可以直接下载到本地。 如果您想在本地存储数据库快照,有以下几种方法: 1. 使用数据库引擎自带的备份工具,比如MySQL的mysqldump,创建逻辑备份导出到本地。 2. 创建一个EC2实例,将RDS快照还原到该实例,然后从EC2实例导出备份到本地。 3. 将RDS快照导出到您自己的S3桶中,然后从S3下载到本地。但要注意,从S3大容量下载数据会产生流量费用。 4. 不定期将RDS实例的数据备份到您自己的S3桶中,这样就可以随时从S3下载到本地。 另外,为什么您想要导出快照到本地?如果是为了冷备份,可以考虑将快照复制到另一个AWS账号或区域作为冷备份。 总之,直接下载RDS快照到本地是不支持的。如果真的需要本地快照,建议使用数据库引擎自带工具创建逻辑备份。同时,也要考虑业务需求,评估在云上保留备份是否可以满足需求。",FALSE,该回答融合了repost和user guide的知识,但是总结不太准确,"您好,目前没有直接的方法可以将RDS快照导出到本地。RDS快照存储在AWS管理的S3存储桶中,不可以直接下载到本地。 如果您想在本地存储数据库快照,有以下几种方法: 1. 使用数据库引擎自带的备份工具,比如MySQL的mysqldump,创建逻辑备份导出到本地。 2. 将RDS快照导出到您自己的S3桶中,然后从S3下载到本地。但要注意,从S3大容量下载数据会产生流量费用。 另外,为什么您想要导出快照到本地?如果是为了冷备份,可以考虑将快照复制到另一个AWS账号或区域作为冷备份。 总之,直接下载RDS快照到本地是不支持的。如果真的需要本地快照,建议使用数据库引擎自带工具创建逻辑备份。同时,也要考虑业务需求,评估在云上保留备份是否可以满足需求。", -https://repost.aws/questions/QU0-Vce1njRjmxnzMdpgXaew,"请参考[SAP Lens: 最佳实践14.2-选择和配置与性能要求一致的EBS类型](https://docs.aws.amazon.com/wellarchitected/latest/sap-lens/best-practice-14-2.html) - - -当您了解并验证系统的性能和可靠性要求或见证以下项目的性能瓶颈时,io2 Block Express 是 SAP HANA 工作负载的不错选择: - - -*您的 SAP HANA 数据或日志文件系统需要单个卷提供超过 16,000 IOPS 或 1,000 MB/秒的吞吐量 -*您需要毫秒级的延迟时间来处理SAP HANA日志卷。 -*您需要单个卷的存储耐用性超过99.9%。 io2为单个卷提供了99.999%的耐久性。 -*您需要将单个卷扩展到64TB。 - - -*注意:此答案由SAP on AWS专业团队提供,并在发布时准确。请查看评论,因为答案可能已更改/服务演变。*",使用 EBS io2块存储卷来处理SAP HANA工作负载的常见场景?,"使用 EBS io2 块存储卷来处理 SAP HANA 工作负载的常见场景包括: - 需要提供超过 16,000 IOPS 或 1,000 MB/秒的吞吐量。 - 需要毫秒级的延迟来处理 SAP HANA 日志卷。 - 需要单个卷的存储耐用性超过 99.9%。 - 需要将单个卷扩展到 64TB。 请注意,以上答案仅供参考,并且可能因AWS服务的更新而有所变化。建议参考官方文档和咨询AWS解决方案团队以获取最新的信息和指导。","[""https://repost.aws/questions/QU0-Vce1njRjmxnzMdpgXaew""]",TRUE,TRUE,,"根据提供的文章,以下是一些常见的场景,可以考虑使用Amazon EBS io2块存储卷来处理SAP HANA工作负载: 1. 当您的SAP HANA数据或日志文件系统需要单个卷提供超过16,000 IOPS或1,000 MB/秒的吞吐量时。 2. 当您需要毫秒级的延迟时间来处理SAP HANA日志卷时。 3. 当您需要单个卷的存储耐用性超过99.9%时。io2为单个卷提供了99.999%的耐久性。 4. 当您需要将单个卷扩展到64TB时。",TRUE,,"常见场景包括以下几种情况: 1. 当您的SAP HANA数据或日志文件系统需要单个卷提供超过16,000 IOPS或1,000 MB/秒的吞吐量时,可以考虑使用EBS io2块存储卷。 2. 如果您需要毫秒级的延迟时间来处理SAP HANA日志卷,那么EBS io2块存储卷也是一个不错的选择。 3. 当您需要单个卷的存储耐用性超过99.9%时,EBS io2块存储卷可以提供99.999%的耐久性。 4. 如果您需要将单个卷扩展到64TB以上,那么EBS io2块存储卷是一个可行的选择。",TRUE,,"根据背景知识,使用 Amazon EBS io2 块存储卷来处理 SAP HANA 工作负载的几个常见场景包括: - 当SAP HANA的数据或日志文件系统需要单个卷提供超过16,000 IOPS或1,000 MB/秒的吞吐量时。io2可以提供高达64,000 IOPS和1,000 MB/秒的吞吐量。 - 当需要毫秒级的延迟时间来处理SAP HANA日志卷时。io2提供了稳定和低延迟的性能。 - 当需要单个卷的存储耐用性超过99.9%时。io2为单个卷提供了99.999%的耐久性。 - 当需要将单个卷扩展到64TB时。io2支持高达64TB的卷大小。 - 当SAP HANA系统遇到I/O性能瓶颈时,切换到io2可以提升性能。 - 总体来说,对于有高IOPS、低延迟和高吞吐量要求的SAP HANA工作负载,EBS io2是非常合适的存储选择。",TRUE,,"请参考[SAP Lens: 最佳实践14.2-选择和配置与性能要求一致的EBS类型](https://docs.aws.amazon.com/wellarchitected/latest/sap-lens/best-practice-14-2.html) - - -当您了解并验证系统的性能和可靠性要求或见证以下项目的性能瓶颈时,io2 Block Express 是 SAP HANA 工作负载的不错选择: - - -*您的 SAP HANA 数据或日志文件系统需要单个卷提供超过 16,000 IOPS 或 1,000 MB/秒的吞吐量 -*您需要毫秒级的延迟时间来处理SAP HANA日志卷。 -*您需要单个卷的存储耐用性超过99.9%。 io2为单个卷提供了99.999%的耐久性。 -*您需要将单个卷扩展到64TB。 - - -*注意:此答案由SAP on AWS专业团队提供,并在发布时准确。请查看评论,因为答案可能已更改/服务演变。*", -https://repost.aws/questions/QUwczwWSybSQuqvwKiqOlW4w,"一些考虑因素: - - -在扩展 RDS 实例之前,请确保商业数据库引擎(如 SQL Server、Oracle)的许可证已放置正确,尤其是如果您采用自己的许可证 (BYOL)。重要提醒: 对于商业引擎,您受许可证的限制,通常是绑定到 CPU 套接字或核心。 - - -确定何时应用更改。您可以在指定实例维护窗口期间立即应用更改或稍后应用更改。 - - -存储和实例类型是分离的。当您扩展数据库实例时,存储大小保持不变,并不会受到更改的影响。您可以单独修改 DB 实例,以增加分配的存储空间,或通过更改存储类型(如更改普通用途 SSD 为预留 IOPS SSD)来提高性能。 - - -在多可用区实例中进行扩展操作时,由于备用数据库首先升级,因此几乎没有停机时间,然后会发生故障转移,切换到新的数据库。对于单一可用区实例,在扩展操作期间将不可用。 - - -请参阅:","我想将RDS实例从较旧的类型升级到最新的实例类型,这个升级过程中是否会存在一些问题?升级实例类型的最佳实践是什么?",在将RDS实例从较旧的类型升级到最新的实例类型时,可能会存在一些问题。这些问题可能包括: 1. 许可证问题:在升级之前,需要确保商业数据库引擎(如SQL Server、Oracle)的许可证已正确放置,特别是对于采用自己的许可证(BYOL)的客户。 2. 存储和实例类型分离:当扩展数据库实例时,存储大小保持不变,并不会受到更改的影响。因此,升级实例类型时,可以单独修改存储大小或通过更改存储类型来提高性能。 3. 可用区影响:在多可用区实例中扩展操作时,由于备用数据库首先升级,因此几乎没有停机时间,然后会发生故障转移,切换到新的数据库。在单一可用区实例中,在扩展操作期间会不可用。 4. 版本兼容性:在升级之前,需要确保目标CEV与当前CEV清单中的安装参数设置相匹配。例如,无法将使用原定设置Oracle主目录的数据库升级到使用非原定设置Oracle主目录的CEV。 5. 手动应用补丁:在特殊情况下,可以使用OPATCH将“一次性”补丁直接应用于底层Amazon EC2实例。但这种方法需要手动将补丁应用到每个实例,因此不如使用CEV自动化补丁同步高效。 尽管存在这些问题,但升级实例类型的最佳实践包括: 1. 在指定实例维护窗口期间立即应用更改,或者稍后应用更改。 2. 遵循CEV升级的一般信息,并使用CEV升级功能。 3. 在计划升级时,考虑升级的注意事项,如许可证问题、版本兼容性等。 4. 在升级过程中,可能需要恢复自定义引擎版本,例如将使用原定设置Oracle主目录的数据库升级到使用非原定设置Oracle主目录的CEV。 5. 在升级过程中,可能需要使用OPATCH将补丁直接应用于底层Amazon EC2实例。 总之,升级实例类型可能会面临一些挑战,但最佳实践包括使用CEV自动化补丁同步、在指定维护窗口期间或稍后应用更改、执行版本兼容性测试等。,"[""https://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/UserGuide/custom-upgrading.html"",""https://repost.aws/questions/QUwczwWSybSQuqvwKiqOlW4w""]",TRUE,TRUE,此回答融合了repost和user guide的RDS Custom for Oracle 升级的要求的知识,总结不够清晰,在将RDS实例从较旧类型升级到最新类型时,确实可能存在一些常见问题和挑战。以下是一些建议的最佳实践: 1. 在升级之前,确保您的数据库许可是正确的。对于商业数据库引擎(如SQL Server、Oracle),您的许可证通常是绑定到CPU核心或CPU套接字的,因此在升级时需要确保正确的许可证配置。 2. 确定何时进行升级。您可以选择在指定的管理窗口期间立即进行升级,或者在需要的时候稍后升级。 3. 考虑到存储和实例类型是分离的。升级实例类型不会影响存储大小,但可以影响实例的性能和资源使用。 4. 在进行横向扩展操作时,由于备用数据库首先升级,然后进行故障转移,因此在多可用区实例中可能几乎没有停机时间。而对于单一可用区实例,在扩展操作期间可能会暂时不可用。 5. 在升级过程中,确保遵循Amazon提供的最佳实践和指南,例如查看他们的博客文章或在官方文档中找到的相关内容。 总之,虽然升级RDS实例类型可能会带来一些挑战,但遵循这些最佳实践和建议可以帮助您更顺利地进行升级并减少可能出现的问题。,TRUE,,在升级RDS实例类型时,可能会出现一些问题和挑战。以下是一些可能遇到的问题和最佳实践的建议。 - **存储和实例类型不匹配**:在扩展实例类型时,存储的大小不会受到影响。因此,如果您的实例类型更旧,存储容量可能不足以支持最新类型的实例。为了解决这个问题,您可以考虑增加存储大小或调整实例类型的规格。 - **备份和恢复问题**:在升级实例类型时,您可能需要重新备份数据并恢复备份。确保备份策略和恢复过程适用于最新类型的实例。 - **性能问题**:较旧的实例类型可能无法提供最新类型的实例的性能水平。您需要评估您的应用程序是否需要最新的实例类型,并根据需要进行优化。 以下是升级实例类型的最佳实践: - **备份数据**:在升级前,务必备份您的数据库和数据。确保备份策略和恢复过程适用于新类型的实例。 - **测试备份和恢复**:在升级前进行备份和恢复测试,以确保备份可以成功恢复。 - **优化应用程序**:如果您的应用程序需要更高的性能,则需要进行优化。这可能涉及更改查询或调整资源分配。 - **确定维护窗口**:在选择升级实例类型的时间时,请确保您在维护窗口内完成升级操作。这将确保升级期间您的应用程序不受影响。 - **逐步升级**:如果您有多个实例类型,请考虑逐步升级。这将使您可以更好地管理和管理风险。 - **监控性能**:在升级后,监控性能以确保您获得所需的性能水平。如果需要,可以进行进一步的优化。 - **监控性能**:在升级后,持续监控性能以确保您获得所需的性能水平。如果需要,可以进行进一步的优化。 - **定期备份**:定期备份您的数据库和数据以确保备份可以成功恢复。 - **跟踪成本**:跟踪升级的成本并与您的预算进行比较。如果成本超出预算,请考虑调整应用程序或寻找其他解决方案。,TRUE,,"升级RDS实例类型时,需要注意以下几点: 1. 升级前确保数据库引擎的许可证放置正确,尤其是如果采用自己的许可证(BYOL)。商业数据库引擎的许可证通常绑定在CPU插槽或核心上。 2. 确定何时应用更改。可以在指定的实例维护窗口立即应用,也可以稍后应用。 3. 存储和实例类型是分离的。扩容实例时,存储大小不受影响。可以单独调整存储空间。 4. 对于多可用区实例,升级时备用数据库先升级,然后故障转移,几乎没有停机时间。对于单可用区实例,升级期间实例不可用。 5. 升级主实例后,只读副本会自动升级。 6. 测试升级的兼容性,尤其是跨大版本升级。 7. 备份数据之后再进行升级。 8. 在低峰时段进行升级。 9. 分阶段进行升级,先在非生产环境验证。 10. 监控升级状态,如果失败则回滚改动。 综上,升级实例类型要谨慎测试,选择合适的时间,同时监控升级过程,以减少对服务的影响。",FALSE,,"一些考虑因素: - - -在扩展 RDS 实例之前,请确保商业数据库引擎(如 SQL Server、Oracle)的许可证已放置正确,尤其是如果您采用自己的许可证 (BYOL)。重要提醒: 对于商业引擎,您受许可证的限制,通常是绑定到 CPU 套接字或核心。 - - -确定何时应用更改。您可以在指定实例维护窗口期间立即应用更改或稍后应用更改。 - - -存储和实例类型是分离的。当您扩展数据库实例时,存储大小保持不变,并不会受到更改的影响。您可以单独修改 DB 实例,以增加分配的存储空间,或通过更改存储类型(如更改普通用途 SSD 为预留 IOPS SSD)来提高性能。 - - -在多可用区实例中进行扩展操作时,由于备用数据库首先升级,因此几乎没有停机时间,然后会发生故障转移,切换到新的数据库。对于单一可用区实例,在扩展操作期间将不可用。 - - -请参阅:", -https://repost.aws/questions/QUbKAYHrekS8ykcZvQfgqaTw,如果您有一个正在运行的当前预配置的Aurora集群,您可以拍摄最新[快照并将其恢复](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless.restorefromsnapshot.html)到Aurora Serverless。恢复时,您会在Capacity Type选项中看到“预配置和Serverless”的选项,您可以选择“Serverless”。,"我想将数据库从Aurora迁移到Aurora Serverless,最佳实践是什么?看到有博客建议使用mysqldump,不推荐DMS,不知道这是否是最优的迁移方式?",根据提供的知识资源,使用mysqldump进行从Aurora迁移到Aurora Serverless的最佳实践是: 1. 创建Aurora Serverless数据库的快照,并恢复它到Aurora Serverless。 2. 如果您的数据库支持InnoDB或MyISAM表空间,可以使用mysqldump将数据转储到文件,然后将该数据导入到现有的Aurora MySQL数据库集群。 3. 将完整备份文件和增量备份文件从数据库复制到Amazon S3桶,然后从这些文件还原到Aurora MySQL数据库集群。 以上迁移方法提供了两种不同的方法,使用mysqldump和Amazon S3进行物理迁移和使用Percona XtraBackup和Amazon S3进行物理迁移。您可以根据您的具体情况选择最适合您的方法。 请注意,这些方法都是基于提供的背景知识,并没有直接引用文档或博客。因此,建议您在实施迁移之前,仔细阅读相关文档和咨询AWS解决方案团队以获取更准确和详细的指导。,"[""https://repost.aws/questions/QUbKAYHrekS8ykcZvQfgqaTw"",""https://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Migrating.ExtMySQL.html""]",TRUE,FALSE,不能直接给Aurora预置容量数据库创建Aurora Serverless快照,根据提供的文章,从Aurora迁移到Aurora Serverless的最佳实践是使用mysqldump工具进行数据迁移。这种方法包括首先使用mysqldump工具将现有Aurora数据库的数据导出,然后将这些数据导入到Aurora Serverless数据库中。这种方法的优点是可以在保留数据的同时对数据库进行迁移,而且可以根据需要灵活地调整资源分配。,FALSE,,根据我们的指引,如果您有一个正在运行的当前预配置的Aurora集群,可以拍摄最新快照并将其恢复(https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless.restorefromsnapshot.html)到Aurora Serverless。恢复时,您会在Capacity Type选项中看到“预配置和Serverless”的选项,您可以选择“Serverless”。 如果您的数据库支持InnoDB或MyISAM表空间,您还可以使用mysqldump或其他工具将数据迁移到Amazon Aurora MySQL数据库集群。这两种方法都是可行的,具体取决于您的需求和偏好。,TRUE,,"根据背景知识和文档的内容,从Aurora迁移到Aurora Serverless的最佳实践有以下两种方式: 1. 使用快照迁移:对Aurora集群创建最新快照,然后将该快照恢复到Aurora Serverless中。这是最简单快速的迁移方式。 2. 使用mysqldump迁移:使用mysqldump实用程序导出数据,然后导入到Aurora Serverless中。相比DMS,这种方式对于简单的环境更加可控和高效。 其中快照迁移是最推荐的方式。如果无法使用快照,那么可以使用mysqldump导出导入的方式进行逻辑迁移。不推荐使用DMS进行迁移,因为相比mysqldump,DMS的迁移过程更复杂,控制和调优也更困难。 综上所述,从Aurora到Aurora Serverless的迁移,首先考虑快照迁移,其次是使用mysqldump逻辑迁移,不推荐使用DMS迁移。这个建议适用于简单的迁移场景。如果遇到更复杂的情况,还需要考虑其他因素,选择最合适的迁移方案。",TRUE,,"从Aurora迁移到Aurora Serverless的最佳实践有以下两种方式: 1. 使用快照迁移:对Aurora集群创建最新快照,然后将该快照恢复到Aurora Serverless中。这是最简单快速的迁移方式。 2. 使用mysqldump迁移:使用mysqldump实用程序导出数据,然后导入到Aurora Serverless中。", -https://repost.aws/questions/QU-15FxvzsTJ-arH1y52SFww,"您需要使用主用户连接到您的集群,并使用 SQL 简单地创建一个新的数据库。例如: - - - - - - -``` -CREATE DATABASE mydatabase; - - -```",如何在现有的Aurora数据库集群中添加第二个数据库,而不是创建一个新的集群?,您可以使用主用户连接到您的Aurora数据库集群,并使用SQL语句创建一个新的数据库。例如,可以使用以下命令创建一个新的数据库: ``` CREATE DATABASE mydatabase; ``` 这样就可以在现有的Aurora数据库集群中添加第二个数据库。请注意,此操作会创建一个新的数据库实例,而不是创建一个新的Aurora集群。,"[""https://repost.aws/questions/QU-15FxvzsTJ-arH1y52SFww"",""https://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/AuroraUserGuide/aurora-replicas-adding.html""]",TRUE,TRUE,,您可以通过在现有的Aurora数据库集群中创建一个新的数据库来实现这一点。例如,您可以执行`CREATE DATABASE mydatabase;`语句来创建一个新的数据库。这样,您将在相同的Aurora数据库集群中添加一个新的数据库,而不是创建一个新的集群。,TRUE,,"您可以在现有的 Aurora 数据库集群中添加第二个数据库,而不必创建一个新的集群。您需要使用主用户连接到集群,然后使用 SQL 简单地创建一个新的数据库。例如: ```sql CREATE DATABASE mydatabase; ``` 这将创建一个名为 ""mydatabase"" 的新数据库,而无需创建一个新的 Aurora 集群。请注意,这将在相同的集群中创建另一个数据库实例,并且可能会影响集群的性能和容量规划。",TRUE,,"您可以在现有的Aurora集群中添加新的数据库,而不需要创建新的集群。步骤如下: 1. 使用主用户账户连接到现有的Aurora集群。 2. 使用SQL语句CREATE DATABASE在集群中创建新数据库。例如: ```sql CREATE DATABASE newdb; ``` 3. 新建立的数据库将和现有的数据库一起存在于同一个Aurora集群中。 4. 可以通过如下命令查看集群中的所有数据库: ```sql SHOW DATABASES; ``` 5. 同时可以使用SQL语句在新数据库中创建表等对象。 所以总结一下,关键是通过SQL语句CREATE DATABASE在现有Aurora集群内部新建数据库,不需要重新创建集群。这个方法适用于Aurora MySQL和Aurora PostgreSQL。",TRUE,,"您可以在现有的Aurora集群中添加新的数据库,而不需要创建新的集群。步骤如下: 1. 使用主用户账户连接到现有的Aurora集群。 2. 使用SQL语句CREATE DATABASE在集群中创建新数据库。例如: ```sql CREATE DATABASE newdb; ```", -https://repost.aws/questions/QU4DYhqh2yQGGmjE_x0ylBYg,"在多可用区切换时,RDS 可能会将旧的主数据库实例作为新的备用实例,也可能会添加一台新实例作为备用实例。 - - -具体来说: - - -故障切换过程通常在 60-120 秒内完成,备用实例被提升为新的主实例,使您能够在最短时间内恢复 DB 活动。 - - -同时,在后台,RDS 的内部健康监控系统会诊断故障的主实例,并根据检测到的错误采取纠正措施。纠正措施可能仅涉及重新启动有故障的实例,也可能涉及更换底层硬件,具体取决于检测到的故障类型。一旦旧的主节点恢复,它就会作为新的备用实例重新启动,以确保您的 DB 具有高可用性。 - - -故障节点的恢复时间可能取决于故障类型和具体使用的回复过程。此外,恢复时间很大程度上取决于崩溃时 DB 的负载,因为 RDS 将执行数据恢复并回滚任何未提交的事务,以消除节点间的任何数据不一致性,同时为您提供单一设备的体验。 - - -参考资料: - - -Amazon RDS 的内部情况 - 多可用区: - - - -RDS 的故障切换过程: -",RDS Multi-AZ故障转移的过程?,RDS Multi-AZ故障转移的过程如下: 1. 当一个主实例发生故障并切换到备用实例时,备用实例会被提升为新的主实例。 2. 在后台,RDS的内部健康监控系统会诊断故障的主实例,并根据检测到的错误采取纠正措施。 3. 纠正措施可能包括重新启动有故障的实例或者更换底层硬件。 4. 一旦旧的主节点恢复,它会被重新启动,并作为新的备用实例。 5. 这个过程可以在60到120秒内完成,以确保DB的活动恢复在最短时间内。 6. 恢复时间取决于故障类型和具体使用的恢复过程,并取决于崩溃时DB的负载。 7. 恢复时间可能包括执行数据恢复和回滚事务以消除数据一致性问题,并提供一个单一设备的体验。 8. 可以使用存储过程exec msdb.dbo.rds_failover_time来确定上次故障转移的时间。 请注意,这段回答是基于所提供的知识资源,如果有任何错误或不准确的地方,请联系AWS解决方案团队以获取准确和最新的信息。,"[""https://repost.aws/questions/QU4DYhqh2yQGGmjE_x0ylBYg"",""https://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/UserGuide/Appendix.SQLServer.CommonDBATasks.LastFailover.html""]",TRUE,TRUE,此回答融合了repost和UserGuide的知识,当RDS多AZ实例的主实例失败并切换到备用实例时,备用实例会被提升为新的主实例。这个过程通常在60-120秒内完成。在后台,RDS的内部健康监控系统会诊断故障的主实例,并采取相应的纠正措施。如果旧的主节点恢复,它就会作为新的备用实例重新启动,以确保数据库的高可用性。故障节点的恢复时间可能取决于故障类型和具体的恢复过程。,TRUE,,当RDS多可用区实例发生故障时,RDS会自动将主实例切换到备用实例上。这个过程被称为故障转移。故障转移通常会在几秒钟内完成,确保您的DB具有高可用性。 具体的故障转移过程如下: 1. 当主实例出现故障时,RDS会自动检测到这一点,并开始将流量切换到备用实例。 2. 在大约60-120秒的时间内,RDS会将备用实例提升为主实例,以确保您在最短的时间内恢复正常DB活动。 3. 在后台,RDS的内部健康监控系统会对故障的主实例进行诊断,并采取纠正措施。这些措施可能包括重新启动有故障的实例或更换底层硬件。 4. 一旦旧的主节点恢复,它将被用作新的备用实例,并重新启动。这样可以确保您的DB始终具有高可用性。 总的来说,RDS的多可用区故障转移是一个自动化的过程,旨在确保您的DB在高可用性下运行。,TRUE,,"根据背景知识,RDS Multi-AZ 故障转移的过程可以概括如下: 1. 主实例发生故障时,RDS 会自动触发故障转移,将备用实例升级为新的主实例,时间通常在60-120秒内完成。 2. 原主实例被标记为故障,RDS 会对其进行诊断并采取纠正措施,比如重新启动或更换硬件。 3. 一旦原主实例恢复正常,它会被重新设置为新的备用实例,确保数据库具有高可用性。 4. 在故障转移过程中,RDS 会在新主实例上执行数据恢复和事务回滚,以消除不同实例之间的数据不一致,对用户无感知。 5. 可以通过 RDS 存储过程查询上次故障转移的时间,如果未发生转移则返回 null。 6. 故障实例的恢复时间取决于故障类型和回复过程,也受数据库负载的影响。 7. 整个故障转移过程对用户透明,数据库可以在极短时间内恢复运行。 综上,RDS 会自动完成故障检测、转移以及实例恢复,以提供数据库的高可用性和数据一致性。",TRUE,,"在多可用区切换时,RDS 可能会将旧的主数据库实例作为新的备用实例,也可能会添加一台新实例作为备用实例。 - - -具体来说: - - -故障切换过程通常在 60-120 秒内完成,备用实例被提升为新的主实例,使您能够在最短时间内恢复 DB 活动。 - - -同时,在后台,RDS 的内部健康监控系统会诊断故障的主实例,并根据检测到的错误采取纠正措施。纠正措施可能仅涉及重新启动有故障的实例,也可能涉及更换底层硬件,具体取决于检测到的故障类型。一旦旧的主节点恢复,它就会作为新的备用实例重新启动,以确保您的 DB 具有高可用性。 - - -故障节点的恢复时间可能取决于故障类型和具体使用的回复过程。此外,恢复时间很大程度上取决于崩溃时 DB 的负载,因为 RDS 将执行数据恢复并回滚任何未提交的事务,以消除节点间的任何数据不一致性,同时为您提供单一设备的体验。 - - -参考资料: - - -Amazon RDS 的内部情况 - 多可用区: - - - -RDS 的故障切换过程: -", -https://repost.aws/questions/QU8gbjAMgPTfeojLBuX43bEA,"AWS IoT Core暂时不支持QoS2。 -``` -AAWS IoT and the AWS IoT Device SDKs support the MQTT Quality of Service (QoS) levels 0 and 1. The MQTT protocol defines a third level of QoS, level 2, but AWS IoT does not support it. Only the MQTT protocol supports the QoS feature. HTTPS supports QoS by passing a query string parameter ?qos=qos where the value can be 0 or 1. -```",IoT Core是否支持Qos2?,"你好,Ozy。 AWS IoT Core暂时不支持QoS2。 ``` AAWS IoT and the AWS IoT Device SDKs support the MQTT Quality of Service (QoS) levels 0 and 1. The MQTT protocol defines a third level of QoS, level 2, but AWS IoT does not support it. Only the MQTT protocol supports the QoS feature. HTTPS supports QoS by passing a query string parameter ?qos=qos where the value can be 0 or 1. ```","[""https://repost.aws/questions/QU8gbjAMgPTfeojLBuX43bEA""]",TRUE,TRUE,,,,,,,,,,,"AWS IoT Core暂时不支持QoS2。 -``` -AAWS IoT and the AWS IoT Device SDKs support the MQTT Quality of Service (QoS) levels 0 and 1. The MQTT protocol defines a third level of QoS, level 2, but AWS IoT does not support it. Only the MQTT protocol supports the QoS feature. HTTPS supports QoS by passing a query string parameter ?qos=qos where the value can be 0 or 1. -```", -https://repost.aws/questions/QUQGCzc1QgR9C2asXgSwHsnw,"最佳实践是不要使用“LATEST”标签,而是将构件URI设置为指向特定图像哈希值。这样,您的每个组件版本都是由一个不可变的图像版本完全定义的。 -这将确保当您发布带有更新工件的组件的新版本时,新图像将在那时被下载。",如何使GreenGrass组件在部署后使用ECR的最新版本的Docker镜像?,要使GreenGrass组件在部署后使用ECR的最新版本的Docker镜像,可以按照以下步骤进行操作: 1. 在部署前,确保GreenGrass组件已连接到ECR并能够成功验证其凭据。 2. 在组件的“生命周期”配置中,将“安装”阶段的一部分设置为使用“docker pull”命令来获取最新的Docker镜像。 在“安装”阶段,添加以下内容: ``` docker pull ``` 将替换为指向最新版本的Docker镜像的URI。 3. 保存并部署组件。 通过执行上述步骤,GreenGrass组件将在部署后自动下载并使用最新的ECR版本的Docker镜像。这将确保组件始终使用最新的Docker容器镜像,以获得最新的功能和性能改进。,"[""https://repost.aws/questions/QUQGCzc1QgR9C2asXgSwHsnw"",""https://docs.aws.amazon.com/zh_cn/greengrass/v2/developerguide/run-docker-container.html""]",TRUE,TRUE,,"当您使用亚马逊 ECR(Amazon Elastic Container Service for Kubernetes)或AWS 私有仓库时,Greengrass 组件会自动检测到仓库中的新镜像并自动部署它们。这是因为 Greengrass 使用 AWS 物流克隆功能检查仓库中的新镜像,并在检测到新镜像时自动部署它们。 然而,如果您使用的是 AWS 外部 ECR 仓库或其他类型的仓库,例如 Amazon S3 仓库,则可能需要手动触发部署过程。为此,您可以定期运行一个脚本或使用 AWS Lambda 函数来检测新镜像并从仓库拉取并部署它们。 以下是一个使用 AWS Lambda 函数的示例,该函数检测新镜像并部署它们: ```json { ""FunctionName"": ""DockerImageDetectionAndDeployment"", ""FunctionVersion"": ""1.0.0"", ""RoleArn"": ""arn:aws:iam:::role/greengrass-deployment-role"", ""Handler"": ""lambda_function.lambda_handler"", ""MemorySize"": 128, ""Timeout"": 3, ""Layers"": [ { ""External"": true, ""MediaType"": ""lambda-layer-function-1"", ""Arn"": ""arn:aws:lambda:us-west-2:account_id:function:lambda_function::1"" } ], ""Code"": { ""S3"": { ""Bucket"": ""my-bucket-name"", ""Version"": ""latest"", ""Key"": ""docker/dummy_image:latest"" } }, ""Description"": ""AWS Lambda function to detect new docker images in an external Amazon ECR repository and deploy them to Greengrass."", ""DeploymentConfig"": { ""OnEx"", ""EcREventToCloudWatchLogGroup"": false } } ``` 在这个例子中,Lambda 函数会定期检测 ECR 仓库中的新镜像,并使用 Greengrass 的部署 API 将这些新镜像部署到 Greengrass 设备上。 请注意,您需要在 Lambda 函数中包含适当的 IAM 角色和权限配置,以便它能够访问 ECR 仓库并执行部署操作。此外,您还需要创建一个 AWS Lambda 层,其中包含了运行 Lambda 函数所需的依赖项,例如 Docker SDK 和 Python 运行时。 一旦设置好这一切,Lambda 函数应该能够检测到 ECR 仓库中的新镜像,并将其部署到 Greengrass 设备上。这样,每当 ECR 仓库中有新的 Docker 镜像发布时,Greengrass 设备都会自动更新其部署的应用程序。",FALSE,,"要使GreenGrass组件在部署后使用ECR的最新版本的Docker镜像,您可以按照以下步骤操作: 1. 确保您已经安装了Docker和ECR CLI工具。如果您还没有安装它们,请参考[官方文档](https://docs.docker.com/en/latest/cli/install/)和[官方文档](https://docs.aws.io/en-us/amazonecr/latest/CLI/cli-init.html)来了解如何安装和使用它们。 2. 将您的Docker镜像推送到ECR仓库。例如,如果您的ECR仓库名为""my-repository"",并且您的Docker镜像标签为""latest"",则可以使用以下命令将其推送到ECR仓库: ``` docker tag my-image:latest amazonecr.aws.com/my-repository/my-image:latest docker push amazonecr.aws.io/my-repository/my-image:latest ``` 3. 更新您的GreenGrass组件的配置,以便在构建时使用最新的ECR镜像。例如,如果您的ECR仓库名为""my-repository"",则可以在您的GreenGrass组件配置文件中添加以下内容: ``` ComponentConfiguration: DefaultConfiguration: - ebs: - size: 8GiB - volumeName: my-volume-name - fileSystemType: ext4 - mountPoint: /var/lib/docker/volumes/my-volume-name - ecr: - imageName: amazonecr.aws.com/my-repository/my-image:latest - repositoryName: my-repository - region: us-west-2 - tag: latest - maximumRetryAttempts: 3 - waitTimeInSeconds: 30 ``` 其中,""imageName""是要使用的ECR镜像名称,""repositoryName""是ECR仓库名称,""region""是ECR所在区域,""tag""是要使用的镜像标签,""maximumRetryAttempts""是在尝试失败时重试的次数,""waitTimeInSeconds""是在等待ECR响应之前等待的时间。 4. 使用以下命令构建和推送您的GreenGrass组件: ``` make build make push ``` 这将构建并推送您的GreenGrass组件,并使用最新版本的ECR镜像。",FALSE,,"好的,有几种方法可以确保Greengrass组件在每次部署时使用ECR中的最新Docker镜像版本: 1. 不要使用""latest""标签,而是将组件中的镜像URI设置为指向特定的镜像digest值。这可以确保每个组件版本都完全由一个不变的镜像版本定义。当您发布带有更新工件的新组件版本时,新的镜像将在那时下载。 2. 在组件的安装生命周期脚本中,添加一个""docker pull""命令来显式拉取最新的镜像。例如: ``` docker pull account_id.dkr.ecr.region.amazonaws.com/myimage:latest ``` 这将在每次部署时获取最新版本。 3. 使用Lambda函数在部署组件之前触发一个步骤来更新ECR镜像。例如,您可以有一个Lambda在每次部署之前为镜像添加一个新的标签,然后组件工件可以引用该标签。 4. 使用版本别名(而不是latest标签)和Lambda函数来轮换ECR中的活动镜像。当您准备好新的镜像版本时,Lambda可以更新别名到新的镜像digest。组件工件引用别名,因此会获取最新的镜像。 5. 在组件配置中指定镜像URI,而不是硬编码在工件中。然后可以使用Lambda在部署前更新配置中的URI到最新的镜像。 总之,最佳实践是避免使用""latest""标签,并且确保组件明确引用不变的镜像版本,无论是digest、标签还是别名。如果需要,可以使用Lambda函数在部署过程中管理镜像版本。",FALSE,,"最佳实践是不要使用“LATEST”标签,而是将构件URI设置为指向特定图像哈希值。这样,您的每个组件版本都是由一个不可变的图像版本完全定义的。 -这将确保当您发布带有更新工件的组件的新版本时,新图像将在那时被下载。", -https://repost.aws/questions/QUrK0Z86-2TzOmINiLjVUcUg,截至今日,IoT SiteWise没有这样的选项。存储在IoT SiteWise中的数据将持久存在。,有没有办法在IoT SiteWise上设置数据保留策略,以便在“热”数据存储中避免包含旧数据,同时保持与IoT Analytics到S3的数据隔离?,目前没有在IoT SiteWise上设置数据保留策略的方法,以避免在“热”数据存储中包含旧数据,并与IoT Analytics到S3的数据隔离。存储在IoT SiteWise中的数据将持久存在,无法自动删除或保留一定时间。如果您需要实现这种要求,可能需要考虑将数据复制到冷层存储,或者考虑使用其他存储解决方案。有关更多信息,请参阅相关文档和资源。,"[""https://repost.aws/questions/QUrK0Z86-2TzOmINiLjVUcUg"",""https://docs.aws.amazon.com/zh_cn/iot-sitewise/latest/userguide/configure-storage.html""]",TRUE,TRUE,,根据提供的信息,目前尚无直接在IoT SiteWise上设置数据保留策略的方法。然而,可以配置存储设置以将数据复制到冷层,并设置保留期限以规定数据在热层中存储的时间。这样可以在保持与IoT Analytics到S3的数据隔离的同时,避免在IoT SiteWise中包含过多旧数据。,TRUE,,根据提供的文档,目前无法在IoT SiteWise上设置数据保留策略来实现您的需求。IoT SiteWise存储的数据将永久存在,并且没有选项来设置数据保留策略。然而,您可以通过配置存储设置将数据复制到冷层来解决这个问题。这样,您可以在热层中设置保留期限,并避免包含旧数据的同时,将数据隔离到冷层的AWS IoT Analytics中。有关更多信息,请参考《AWS IoT Analytics用户指南》中的“处理AWS IoT SiteWise数据”部分。,TRUE,,"根据背景知识,IoT SiteWise当前没有内置的数据保留策略来自动删除旧数据。但是,有一些方法可以实现类似的数据保留: 1. 使用存储设置中的保留期功能。这可以设置数据在热层存储中的保留天数。过期的数据会被自动删除。但是这只适用于热层存储,不影响冷层存储。 2. 定期使用BatchPutAssetPropertyValue API删除旧数据。可以编写脚本,定期查询旧数据并删除。这可以删除热层和冷层中的旧数据。需要自行处理数据查询和删除逻辑。 3. 使用AWS Lambda函数监控数据老化事件,并调用删除API。可以通过IoT SiteWise中的数据管理事件触发Lambda函数,在数据老化时自动删除。需要处理函数代码逻辑。 4. 将旧数据导出到S3等存储,并定期清理IoT SiteWise中的数据。可以导出后再删除IoT SiteWise中的数据。 5.考虑是否真的需要删除IoT SiteWise中的旧数据。可以只在IoT Analytics中设置数据保留策略,IoT SiteWise保留全部原始数据。 综上,如果确实需要在IoT SiteWise中删除旧数据,建议使用保留期或者Lambda函数的方式,相对比较自动化和可控。",TRUE,,可以配置存储设置以将数据复制到冷层,并设置保留期限以规定数据在热层中存储的时间。,原回答过时,现已支持数据保留策略https://docs.aws.amazon.com/zh_cn/iot-sitewise/latest/userguide/configure-storage.html -https://repost.aws/questions/QU2IbRXVaSQH2SkC5rkNQrXw,是的,支持向设备发送下行数据链路。目前尚未在控制台上实现,您可以使用CLI完成。具体参考可以通过此链接找到,。,AWS LoRaWAN Network Server是否支持向end node发送下行消息?,"是的,支持向设备发送下行数据链路。","[""https://docs.aws.amazon.com/zh_cn/iot/latest/developerguide/connect-iot-lorawan-downlink-queue.html"",""https://repost.aws/questions/QU2IbRXVaSQH2SkC5rkNQrXw""]",TRUE,TRUE,,是的,支持向设备发送下行数据链路。目前尚未在控制台上实现,您可以使用CLI完成。具体参考可以通过此链接找到,。,TRUE,,是的,AWS LoRaWAN Network Server支持向终节点(end node)发送下行消息。您可以使用AWS IoT Wireless API或CLI来执行此操作。具体参考可以通过这个链接找到,。,TRUE,,"是的,AWS LoRaWAN Network Server支持向end node发送下行消息。 主要有以下几点: 1. AWS IoT Wireless支持通过SendDataToWirelessDevice API或CLI向LoRaWAN设备发送下行消息。 2. 对于A类设备,需要设备先发送上行消息表示在线和可接收下行消息,Server才会从队列中发送下行消息。对B类和C类设备,可以随时发送下行消息。 3. 可以通过AWS IoT控制台或API管理下行消息队列,查看、添加和删除队列中的下行消息。 4. 控制台上需要设备先激活才能看到下行消息队列界面。API发送下行消息时,即使没有激活也可以发送,但消息可能会丢失。 5. 常见错误包括控制台看不到消息、API发送后消息丢失等情况。需要检查设备是否激活,目标配置是否正确等。 6. 整体来说,AWS LoRaWAN Network Server是支持向end node发送下行消息的,需要正确配置设备和下行消息目标。",TRUE,,是的,支持向设备发送下行数据链路。您可以使用 AWS Management Console 或API管理下行链路消息队列。具体参考可以通过此链接找到,,原回答过时,目前支持控制台操作 -https://repost.aws/questions/QUM7OtqnKuRoeOLTBK5RNohA,"AWS IoT Core支持每个MQTT客户端连接每秒最多发布100个消息。请参见此处的限制:。特别是“每连接每秒发布请求”。 - - -因此,每3秒钟发一条消息通常不是问题。但是,您需要明确“实时设备监测”的意义,消息需要从设备端通过互联网并到达IoT Core,还需要一些额外的时间来传播消息通过IoT Core、规则引擎等等,然后再实施相应的操作。",AWS IoT Core支持的MQTT消息的频率是多少?,AWS IoT Core支持的MQTT消息的频率是每连接每秒最多发布100个消息。,"[""https://docs.aws.amazon.com/zh_cn/iot/latest/developerguide/mqtt.html"",""https://repost.aws/questions/QUM7OtqnKuRoeOLTBK5RNohA""]",TRUE,TRUE,,抱歉,您的这个问题我没有找到明确的答案。但是,根据AWS IoT Core的文档,它是一个完全托管的服务,可以处理大量的消息传输。对于大多数应用,即使在高负载下,它也足以满足您的需求。如果您需要更高的吞吐量或更低的消息延迟,您可以考虑使用更高级别的 AWS 服务,如 Amazon SQS 或 Lambda。,FALSE,,根据文档提供的信息,AWS IoT Core支持的MQTT消息频率是没有明确规定的。它取决于您的应用程序的需求以及网络传输的性能。对于需要频繁发送和接收消息的应用程序,可能需要考虑网络传输的性能和带宽限制。,FALSE,,"根据AWS文档,AWS IoT Core支持每个MQTT客户端连接每秒最多发布100个消息。 具体来说,AWS IoT Core对MQTT消息频率有以下限制: - 每个客户端连接每秒最多可以发布100个消息(Publish requests per second per connection)。 - 每个客户端连接每秒最多可以接收100个消息(Receive requests per second per connection)。 - 每个账户在每个区域每秒最多可以发布500个消息(Publish requests per second per account per region)。 - 每个账户在每个区域每秒最多可以接收500个消息(Receive requests per second per account per region)。 这些限制适用于使用MQTT协议的所有消息,包括QoS 0、QoS 1和保留(retained)消息。 所以对于您的场景,设备每3秒发送一个MQTT消息,频率远低于每秒100条的限制,IoT Core可以很好地支持。 当然,在实际使用时,需要考虑从设备到IoT Core的网络质量和延迟等因素。为了实现最佳的实时监控效果,您还需要合理配置IoT Core规则引擎和后端服务。但从MQTT消息频率限制来看,IoT Core可以支持您的需求。",TRUE,,AWS IoT Core支持每个MQTT客户端连接每秒最多发布100个消息。, -https://repost.aws/questions/QUiRZ50gygRyaaT6_VOCwKug,"您可以通过单击右上角“操作”->“删除修订”来从控制台中删除部署:![删除部署](/media/postImages/original/IM5GtIKtvwRCOyvENakwizrQ) - - -您也可以使用API / CLI:",如何删除IoT Greengrass v2的部署,特别是那些与已删除的IoT设备关联的部署?,您可以通过单击右上角“操作”->“删除修订”来从控制台中删除与已删除的IoT设备关联的部署。您也可以使用API / CLI来删除部署。,"[""https://repost.aws/questions/QUiRZ50gygRyaaT6_VOCwKug"",""https://docs.aws.amazon.com/zh_cn/greengrass/v2/developerguide/cancel-deployments.html""]",TRUE,TRUE,,"要删除IoT Greengrass v2的部署,特别是在那些与已删除的IoT设备关联的部署,您可以使用AWS控制台、API或通过AWS CLI进行删除部署操作。首先,通过AWS控制台或在本地计算机上使用AWS CLI,运行命令 ""aws greengrassv2 list-deployments"" 以查找目标的最新部署版本的ID。然后,运行命令 ""aws greengrassv2 cancel-deployment"",将deploymentId替换为上一步中查找到的ID。这将使部署状态更改为CANCELED,从而删除部署。",FALSE,cancel-deployment是取消部署,不是删除部署,"要删除IoT Greengrass v2的部署,包括与已删除的IoT设备关联的部署,您可以使用AWS控制台或API/CLI。通过控制台,您可以右键点击部署并选择""删除修订""选项;也可以通过API/CLI使用`delete-deployment`命令。无论使用哪种方法,您需要提供部署的ID,以便将其从系统中删除。",TRUE,,"根据背景知识,主要问题是IoT Greengrass v2中大量旧部署的积累,以及无法删除与已删除IoT设备关联的部署。 有以下几种方法可以删除IoT Greengrass v2的部署: 1. 通过AWS控制台,点击右上角的“操作”->“删除修订”,可以删除单个部署。 2. 通过AWS CLI,可以批量查询和删除部署: - 列出所有部署:`aws greengrassv2 list-deployments` - 根据部署ID批量删除:`aws greengrassv2 delete-deployment --deployment-id ` 3. 对于与已删除IoT设备关联的部署,可以通过CLI查询部署与IoT设备的关联,找到已删除设备的部署,然后删除它们。 4. 考虑使用AWS IoT Fleet Hub等服务,在大规模场景下更好地管理设备和部署。 5. 定期清理无用的历史部署,避免过多积累。 6. 如果需要更复杂的部署管理,可以考虑构建自定义部署管理控制台或工具。",TRUE,,"有以下几种方法可以删除IoT Greengrass v2的部署: 1. 通过AWS控制台,点击右上角的“操作”->“删除修订”,可以删除单个部署。 2. 通过AWS CLI `aws greengrassv2 delete-deployment --deployment-id 删除", -https://repost.aws/questions/QU3C00WmyYRWmPSXAPAQHu_g,"今天不可能实现这个功能。请与您当地的AWS账户团队联系,以便我们将此作为功能请求添加。 - - -另外:在BGP会话中设置密码的要求是什么?BGP会话只能在已经通过身份验证和加密的VPN隧道内建立,因此为BGP添加密码不能提高安全级别。",在Site to Site VPN连接中,是否可以设置BGP秘钥?,在S2S VPN连接中,可以设置BGP秘钥。,"[""https://docs.aws.amazon.com/zh_cn/vpn/latest/s2svpn/HowToTestEndToEnd_Linux.html"",""https://repost.aws/questions/QU3C00WmyYRWmPSXAPAQHu_g""]",TRUE,FALSE,,回答:在S2S VPN连接中,目前不可能实现这个功能。请与您的当地AWS账户团队联系,以便我们将此作为功能请求添加。,TRUE,,抱歉,在Site to Site VPN连接中无法设置BGP秘钥。在S2S VPN文档和控制台中找不到相关信息。如果您需要此功能,请与当地的AWS账户团队联系,他们可以将其作为功能请求添加。,TRUE,,"根据背景知识的内容,在AWS Site-to-Site VPN连接中是不能设置BGP秘钥的。 主要原因有: 1. 在AWS文档和控制台中都没有找到关于在VPN连接中设置BGP秘钥的选项或字段。 2. BGP会话是在已经通过身份验证和加密的VPN隧道内建立的,所以为BGP再添加密码不会提高安全级别。 3. AWS账户团队表示目前不支持在VPN连接中设置BGP秘钥,如果需要可以作为功能请求提出。 4. 在测试VPN连接时,文档中也没有提到需要设置或验证BGP秘钥,只需要确保BGP状态正常建立就可以了。 5. Direct Connect连接中可以设置BGP秘钥,但VPN连接和Direct Connect在这方面处理是不同的。 所以综上所述,在AWS的Site-to-Site VPN连接中是不支持也不需要设置BGP秘钥的。如果真的需要该功能,可以联系AWS账户团队提出功能请求。",TRUE,,在S2S VPN连接中,不可以设置BGP秘钥。, -https://repost.aws/questions/QUyVYbeclnQyCDWSYltAShyA,是的,直到您删除网络负载均衡器,IP地址将保持不变。,创建没有弹性IP地址的Network Load Balancer(NLB)后,其IP地址会改变吗?,创建没有弹性IP地址的Network Load Balancer(NLB)后,其IP地址将保持不变。,"[""https://docs.aws.amazon.com/zh_cn/AmazonECS/latest/developerguide/create-network-load-balancer.html"",""https://repost.aws/questions/QUyVYbeclnQyCDWSYltAShyA""]",TRUE,TRUE,,回答:是的,除非您删除NLB,否则其IP地址将保持不变。,TRUE,,不会改变的。如果您创建了一个没有弹性IP地址的Network Load Balancer(NLB),其IP地址将保持不变,直到您删除该NLB。,TRUE,,"根据背景知识中的内容,如果创建了一个没有弹性IP地址的NLB,其IP地址是不会改变的,直到NLB被删除。 具体来说,背景知识中的内容提到: 如果创建了一个没有弹性IP地址的NLB,IP地址是否会保持不变?请让我知道 回答是: 是的,直到您删除网络负载均衡器,IP地址将保持不变。 所以可以确定,创建没有弹性IP地址的NLB后,其IP地址不会改变,会保持静态,直到NLB被删除。",TRUE,,创建没有弹性IP地址的Network Load Balancer(NLB)后,其IP地址将保持不变。, -https://repost.aws/questions/QU7x1tsf21T_CZB_jwLdL4aA,"ALB/ELB/NLB本身不支持限流。 -但您可以通过在ALB前添加AWS WAF来实现这个效果。具体参考如下: -https://docs.aws.amazon.com/waf/latest/developerguide/waf-rule-statement-type-rate-based.html",有什么方法可以实现在ALB/NLB进行流量限制,尤其是在来源IP层面,以满足每天几亿次的流量需求?,"您可以使用AWS WAF来实现在ALB/NLB上进行流量限制,特别是在来源IP层面。具体可以参考AWS WAF文档中的Rate-Based WAF规则: https://docs.aws.amazon.com/waf/latest/developerguide/waf-rule-statement-type-rate-based.html 感谢您的提问,希望能对您有所帮助。","[""https://repost.aws/questions/QU7x1tsf21T_CZB_jwLdL4aA""]",TRUE,TRUE,,您可以通过在ALB之前添加AWS WAF来实现这个效果。具体参考文档:https://docs.aws.amazon.com/waf/latest/developerguide/waf-rule-statement-type-rate-based.html,TRUE,,您好,您可以在ALB/NLB之前添加AWS WAF来实现流量限制。具体来说,您可以创建一个基于速率的基础规则语句类型,以限制来自特定IP地址的流量。这样可以满足您的要求,并确保只有符合条件的流量才能通过负载均衡器。请参考以下文档以获取详细信息:https://docs.aws.amazon.com/waf/latest/developerguide/waf-rule-statement-type-rate-based.html,TRUE,,"您好,您可以考虑以下几种方法在ALB/NLB实现基于来源IP的流量限制: 1. 使用AWS WAF进行限流 可以在ALB/NLB前面部署AWS WAF,并创建rate based规则,基于来源IP进行限流。AWS WAF支持限制每秒请求数或每5分钟请求数。您可以参考文档配置规则: https://docs.aws.amazon.com/waf/latest/developerguide/waf-rule-statement-type-rate-based.html 2. 使用第三方限流服务 也可以考虑使用第三方限流服务,比如Thundra、Cloudflare等,它们提供更灵活的限流策略。可以将这些服务部署在ALB/NLB前面,进行限流处理后再转发请求。 3. 应用层自行限流 如果不能在网络层限流,也可以在应用层自行实现限流逻辑,比如计数然后拒绝超过阈值的请求等。不过这种方式需要应用程序支持。 4. 利用Lambda@Edge实现限流 可以编写Lambda函数,在ALB/NLB的请求路径上进行限流处理,并可基于来源IP进行限制。 综合来说,使用AWS WAF或者第三方限流服务可能更为便捷高效。您可以根据实际需求和成本选择不同的限流方案。",TRUE,,"ALB/ELB/NLB本身不支持限流。 -但可以通过在ALB前添加AWS WAF来实现流量限制。具体参考如下: -https://docs.aws.amazon.com/waf/latest/developerguide/waf-rule-statement-type-rate-based.html", -https://repost.aws/questions/QUhvpfhsDsSZKRvoLOyWMRkQ,Amazon ELB 能够为我们的客户处理绝大多数场景,而无需“预热”(根据预期流量配置负载均衡器以具有适当的容量级别)。在某些特殊情况下,例如当预期流量会增加时,或者在无法以逐渐增加流量形式进行负载测试的情况下,我们建议您通过 AWS Support 联系我们以“预热”您的负载均衡器。然后,我们将根据您预期的流量配置负载均衡器以具有适当的容量级别。我们需要知道您的测试的开始和结束日期或预期的突增流量、预期的每秒请求速率以及您将测试的典型请求/响应的总大小。,AWS ALB如何启用预热功能?,根据给定的知识资源,AWS ALB没有直接提供预热功能。建议在无法以逐渐增加流量形式进行负载测试的情况下,通过AWS Support联系AWS以预热负载均衡器。预热的具体过程需要提供测试的开始和结束日期或预期的突增流量、预期的每秒请求速率以及预期的总请求大小等信息。,"[""https://repost.aws/questions/QUhvpfhsDsSZKRvoLOyWMRkQ""]",TRUE,TRUE,,AWS ALB的预热功能可以通过联系AWS支持团队并告诉他们预期的流量增加情况来实现。一旦他们了解到了测试的开始和结束日期、预期的突增流量、预期的每秒请求速率以及典型请求/响应的总大小,他们将根据这些信息进行负载均衡器的配置,使其具备适当的容量级别。这样,ALB就可以为突发的流量做好准备。,TRUE,,AWS ALB 提供了多种方式来处理突增流量。对于某些特殊情况,例如预期流量增加或者无法以逐渐增加流量的形式进行负载测试时,可以通过AWS Support联系我们的支持团队来启用ALB的预热功能。他们会根据您预期的流量情况来配置负载均衡器的容量级别,以确保您的应用能够处理突增的流量。 希望这能回答你的问题。如果您还有其他问题或疑虑,欢迎随时向我提问。,TRUE,,"对于AWS Application Load Balancer (ALB),可以通过以下步骤启用预热功能: 1. 通过AWS Support联系AWS支持团队,告知你计划进行负载测试的详情,包括测试的开始和结束时间,预期的流量峰值,每秒请求数等信息。 2. AWS支持团队会根据你提供的信息,提前配置ALB的容量,确保ALB有足够的资源来处理预期的流量峰值。 3. 在测试开始前,保证应用后端的实例数量是足够的,并已准备好处理大流量。 4. 测试开始时,将流量定向到ALB。ALB会自动进行扩容以处理流量增长。 5. 测试结束后,AWS支持团队会根据实际流量情况,适当优化ALB的容量配置。 6. 你也可以在ALB上启用自动扩缩容,让ALB根据实时流量自动调整容量。不过预热还是推荐的,可以避免自动扩缩容的不稳定期。 总之,如果预期有大流量的负载测试,提前通过AWS支持启用ALB预热是非常必要的,可以确保ALB有足够容量应对流量快速上涨。",TRUE,,Amazon ELB 能够为我们的客户处理绝大多数场景,而无需“预热”(根据预期流量配置负载均衡器以具有适当的容量级别)。在某些特殊情况下,例如当预期流量会增加时,或者在无法以逐渐增加流量形式进行负载测试的情况下,我们建议您通过 AWS Support 联系我们以“预热”您的负载均衡器。然后,我们将根据您预期的流量配置负载均衡器以具有适当的容量级别。我们需要知道您的测试的开始和结束日期或预期的突增流量、预期的每秒请求速率以及您将测试的典型请求/响应的总大小。, -https://repost.aws/questions/QUoupKCKu8ReWWDcFTa3jmww,一个VPC可以连接多达5个TGW。但是大多数客户实际上只需要一个,并可以使用TGW的路由表来隔离流量。,能否在同一区域内将一个VPC连接到两个不同的Transit Gateway(TGW)?,可以。,"[""https://repost.aws/questions/QUoupKCKu8ReWWDcFTa3jmww"",""https://docs.aws.amazon.com/local-zones/latest/ug/local-zones-connectivity-transit-gateway-lzs.html""]",TRUE,TRUE,,是的,您可以在同一区域内将一个VPC连接到两个不同的Transit Gateway(TGW)。根据提供的文章,AWS Transit Gateway可以用来连接同一区域内两个不同的Local Zone。,TRUE,该回答融合了respot和UserGuide的知识,在一个VPC内,您可以将它连接到多个TGW。然而,对于同一区域内的不同Local Zone之间的连接,最好使用单个TGW来连接它们。这样做的好处是可以通过TGW的路由表来隔离流量,而无需在每个Local Zone中都创建一个独立的TGW实例。,TRUE,该回答融合了respot和UserGuide的知识,"根据背景知识,在同一区域内,一个VPC可以连接多达5个TGW。所以,是可以将一个VPC连接到同一区域内的两个不同的TGW。 TGW允许一个VPC连接多个TGW,以实现VPC与多个其他网络的互联互通。不过,大多数客户实际上只需要连接一个TGW,通过TGW的路由表来隔离不同的流量。 所以结论是,在同一区域内,可以将一个VPC连接到多个TGW,比如两个TGW。这可以提供VPC访问多个其他网络的灵活性。但是否需要连接多个TGW,要根据实际业务需求来决定。",TRUE,,一个VPC可以连接多达5个TGW。但是大多数客户实际上只需要一个,并可以使用TGW的路由表来隔离流量。, -https://repost.aws/questions/QUUJamgzKrQISC7vnlmfDLjg,"好问题! - - - - -推荐的开箱即用方法是 Trusted Advisor自带对 S3 存储桶的安全检查:“检查 Amazon Simple Storage Service (Amazon S3) 中具有开放访问权限或允许访问任何经过身份验证的 AWS 用户的存储桶。存储桶权限授予列表如果存储桶中的对象被非预期用户频繁列出,访问可能会导致高于预期的费用。授予上传/删除访问权限的存储桶权限允许用户添加、修改或删除存储桶中的项目,从而造成潜在的安全漏洞” - - - - -Trusted Advisor: - - - - - -这通常通过上面列出的 S3 块公共访问控制来实现。但是,如果您的目标是对象资源上更细颗粒度的信息,则可以在目标对象上迭代使用GetObjectACL。要实现公开访问,还必须与 S3 Block Public Access 结合使用。 - - - - -另外,AWS 通常不建议使用 ACL。查看关于对象所有权更新的功能介绍:。",我想查找我的帐户中所有S3 bucket的公共对象,如何操作?,"您可以通过使用""aws s3""命令行、控制台或某些专门的 AWS 服务来查找您的帐户中所有 S3 bucket 的公共对象。以下是一些方法: 1. 使用""aws s3 ls""命令列出所有 S3 存储桶。 2. 使用 S3 控制台,选择""我的桶""选项卡,然后选择""属性""选项卡,检查""公共访问""部分。 3. 使用 AWS CLI 提供的文件列表命令来列出存储桶中的对象。使用 ""-A"" 参数以按对象创建时间排序,使用 ""-w"" 参数以仅列出前 10 个对象。 4. 使用 Amazon S3 提供的 ACL 功能来控制公开访问权限。 5. 使用 AWS Trusted Advisor 自带 S3 安全检查来查找存储桶中的公开访问权限。 请记住,在执行这些操作之前,您需要确保您有适当的权限。","[""https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBuckets.html"",""https://repost.aws/questions/QUUJamgzKrQISC7vnlmfDLjg""]",TRUE,TRUE,,根据提供的信息,您可以使用`aws s3`命令行工具或控制台来查找您的帐户中所有S3 bucket的公共对象。推荐的使用方法是Trustored Advisor的安全检查功能,它会检查S3存储桶中具有开放访问权限或允许访问任何经过身份验证的AWS用户的存储桶。如果您希望获取更细粒度的信息,可以在目标对象上迭代使用GetObjectACL,并与S3 Block Public Access一起使用以确保对象的安全性。,TRUE,,要查找您账户中所有S3 bucket的公共对象,可以通过以下方式操作: 1. 使用`aws s3`命令行工具或控制台来执行操作。 2. 使用AWS Trusted Advisor进行安全检查,以检查S3存储桶是否具有开放的访问权限或被授权给任何经过身份验证的AWS用户。 3. 如果需要更详细的对象级别信息,可以迭代使用`GetObjectACL`方法来获取每个对象的访问控制列表(ACL)。 4. 根据需要,可以使用S3块公共访问控制(Block Public Access)来限制公共访问。 5. 对于更具体的操作和示例,请参考AWS官方文档和相关教程。,TRUE,,"您可以通过以下几种方式查找您帐户中的S3 bucket公共对象: 1. 使用AWS Trusted Advisor进行检查。Trusted Advisor提供了一个内置的检查来检查S3 bucket的公开访问设置。它可以检查哪些bucket允许公开访问或允许任何经过身份验证的AWS用户访问。 2. 使用AWS Command Line Interface (CLI)。您可以使用aws s3api list-objects命令与--bucket参数来列出某个bucket中的所有对象。然后使用aws s3api get-object-acl命令检查每个对象的ACL。如果ACL设置为public-read,则该对象是公开的。 3. 使用AWS SDK。使用SDK中的相应API调用来列出bucket的对象,并检查每个对象的ACL设置。例如在Python SDK中: ```python import boto3 s3 = boto3.client('s3') for bucket in s3.list_buckets()['Buckets']: for obj in s3.list_objects(Bucket=bucket['Name'])['Contents']: acl = s3.get_object_acl(Bucket=bucket['Name'], Key=obj['Key']) if acl['Grants'][0]['Grantee']['Type'] == 'Group' and acl['Grants'][0]['Permission'] == 'READ': print(obj['Key'] + ' is public') ``` 4. 使用S3控制台。在S3控制台中可以看到每个bucket和对象的权限设置。检查需要注意的bucket和对象。 5. 使用S3 Block Public Access设置。您可以在账户级别和bucket级别设置Block Public Access,阻止公开访问S3资源。 6. 定期检查IAM policy设置,确保没有过于开放的策略导致S3资源可以公开访问。",TRUE,https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/userguide/acl-overview.html#permissions,"可以通过以下几种方式查找您帐户中的S3 bucket公共对象: 1. 推荐的开箱即用方法是 Trusted Advisor自带对 S3 存储桶的安全检查:“检查 Amazon Simple Storage Service (Amazon S3) 中具有开放访问权限或允许访问任何经过身份验证的 AWS 用户的存储桶。存储桶权限授予列表如果存储桶中的对象被非预期用户频繁列出,访问可能会导致高于预期的费用。授予上传/删除访问权限的存储桶权限允许用户添加、修改或删除存储桶中的项目,从而造成潜在的安全漏洞” -这通常通过上面列出的 S3 块公共访问控制来实现。Trusted Advisor参考链接: 。2. 如果您的目标是对象资源上更细颗粒度的信息,则可以在目标对象上迭代使用GetObjectACL。要实现公开访问,还必须与 S3 Block Public Access 结合使用。 - -注意:AWS 通常不建议使用 ACL。查看关于对象所有权更新的功能介绍:。", -https://repost.aws/questions/QUJtN-6-hXSZiQrLns7NvmAg,"创建密钥对后,浏览器会自动下载私钥。 - - -请检查您的浏览器是否阻止了自动下载。",如何下载EC2实例的SSH私钥,以便通过SSH连接到该实例?,"要下载 EC2 实例的 SSH 私钥, 您可以在浏览器中直接下载它。 当您创建好实例后, 浏览器会自动下载私钥文件。","[""https://repost.aws/questions/QUJtN-6-hXSZiQrLns7NvmAg"",""https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/ec2-instance-connect-set-up.html""]",TRUE,TRUE,,首先,您需要在AWS管理控制台中创建一个密钥对。在创建过程中,浏览器应该会自动下载私钥文件。如果浏览器阻止了自动下载,您可以手动下载它。要下载私钥文件,请在创建密钥对的页面中找到下载按钮,然后点击它。这将把私钥文件保存到您的计算机上。一旦您拥有了私钥文件,就可以使用SSH客户端(如ssh)连接到EC2实例。,TRUE,,您可以按照以下步骤下载 EC2 实例的 SSH 私钥: 1. 登录到 EC2 控制台并选择您想要连接到实例的区域。 2. 转到实例列表,选择您想要下载私钥的实例。 3. 点击“连接”按钮,然后选择“SSH”连接方式。 4. 在 SSH 连接窗口中,点击“加载授权”按钮,选择您想要使用的 SSH 私钥。 5. 如果您还没有创建私钥,请单击“创建密钥对”按钮,并按照提示创建一对 SSH 私钥和公钥。 6. 一旦您创建了私钥,点击“确定”按钮开始下载私钥。 7. 当浏览器自动下载完私钥后,您将能够在 SSH 连接窗口中使用私钥连接到 EC2 实例。,FALSE,,"根据背景知识,创建EC2实例时会自动下载私钥文件。如果没有自动下载,可以检查以下几点: 1. 检查浏览器是否阻止了自动下载。可以在浏览器设置中允许弹出的下载窗口。 2. 在EC2控制台的“密钥对”页面,找到创建的密钥对,在“操作”菜单中选择“下载私钥”,手动下载私钥文件。 3. 如果私钥文件已丢失,可以删除该密钥对,并重新创建一个新的密钥对,这次请务必保存好下载的私钥文件。 4. 确认实例使用的操作系统支持EC2 Instance Connect,如果不支持,需要先进行相关配置,才能使用私钥文件通过SSH连接实例。 5. 检查实例的网络和安全组设置,确认允许SSH连接的22端口开放。 6. 使用私钥文件、用户名和公有DNS连接实例时,请确保命令格式正确。 总之,核对自动下载的私钥文件,或者手动下载私钥文件,并检查实例和网络配置,使用正确的连接命令,就可以成功通过SSH连接EC2实例。",FALSE,下载不了,"要下载 EC2 实例的 SSH 私钥, 您可以在浏览器中直接下载它。 当您创建好实例后, 浏览器会自动下载私钥文件。", -https://repost.aws/questions/QUIdRjOEc2TaiZ7om8s9IMKg,没有直接的方法来实现这个,可以把对象移动到另一个位置,如果客户必须使预签名 URL 失效,由于预签名 URL 使用访问密钥中的权限,移除与访问密钥关联的用户的权限,则预签名 URL 将停止工作。,能否在向用户发送S3 presigned URL后使其无效?如何操作?,"不能直接操作预签名的S3 URL使其失效。预签名的S3 URL具有特定的有效期,在预签名的URL过期之前,即使停止使用该URL,该URL仍然有效。要使S3预签名的URL失效,需要移除与访问密钥关联的用户的权限,这将导致预签名的URL失效。","[""https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/userguide/using-presigned-url.html"",""https://repost.aws/questions/QUIdRjOEc2TaiZ7om8s9IMKg""]",TRUE,TRUE,,回答:目前没有直接的方法来实现这个。如果客户必须使预签名URL失效,可以将对象移动到另一个位置。由于预签名URL使用访问密钥中的权限,移除与访问密钥关联的用户的权限,则预签名URL将停止工作。,TRUE,,目前没有直接的方法来实现这个操作。但是可以通过以下几种方式来实现类似的效果: 1. 如果需要取消预签名 URL,可以将对象移动到另一个位置,这样可以使得预签名 URL 失效。因为预签名 URL 是基于访问密钥中的权限的,所以移除与访问密钥关联的用户权限,预签名 URL 就会停止工作。 2. 另一种方法是使用预签名 URL 授予对 Amazon S3 中对象的限时访问权限,而不是更新桶策略。这样可以在浏览器中输入预签名 URL,或者在程序中使用预签名 URL 下载对象。但是需要注意的是,预签名 URL 使用的凭证是生成该 URL 的 AWS 用户的凭证。 总之,虽然无法直接取消预签名 URL,但可以通过修改对象的位置或使用其他方法来达到类似的效果。,TRUE,总结得不太好,"根据背景知识,要使S3预签名URL失效,没有直接的方法。但可以通过以下两种方式实现类似的效果: 1. 将对象移动到另一个位置。由于预签名URL中指定了对象的键名,如果对象被移动到新的位置,原有的预签名URL就会失效。 2. 移除与用于生成预签名URL的访问密钥关联的用户权限。预签名URL使用的凭证来自创建它的用户。如果移除该用户的权限,则其生成的预签名URL也会失效。 所以,如果客户需要使预签名URL失效,可以将对象移动到新的位置,或者删除与用于生成预签名URL的访问密钥相关的用户权限。这两种方法都可以使原有的预签名URL无法继续访问对象。",TRUE,,"要使S3预签名URL失效,没有直接的方法。但可以通过以下两种方式实现类似的效果: 1. 将对象移动到另一个位置。由于预签名URL中指定了对象的键名,如果对象被移动到新的位置,原有的预签名URL就会失效。 2. 移除与用于生成预签名URL的访问密钥关联的用户权限。预签名URL使用的凭证来自创建它的用户。如果移除该用户的权限,则其生成的预签名URL也会失效。", -https://repost.aws/questions/QUdE1SunSsQLyjlnru7Ke17A,"你好,SMS MFA公共预览仅支持IAM用户,不能为root用户启用。此外,我们支持一次为用户(IAM和root)激活1个MFA。AWS MFA不支持您提到的方式。 -如果您在2017年9月之前创建了您的AWS帐户,并在您的亚马逊零售帐户上启用了MFA(与您的AWS root用户关联的电子邮件地址相同),则除了您为root用户启用的AWS MFA外,您还需要完成您的亚马逊MFA验证。",如何禁用root用户的SMS-MFA验证并完全切换到使用Google Authenticator MFA?,"您可以通过以下步骤禁用根用户的SMS-MFA验证并切换到使用Google Authenticator MFA: 1. 在IAM控制台上登录根用户账号。 2. 在导航栏的右上角选择您的账户名称。 3. 选择""Security credentials""。 4. 展开""Multi-factor authentication (MFA) (多重验证)""部分。 5. 选择""Assign MFA device""。 6. 在向导中,键入要分配的MFA设备名称,选择硬件TOTP令牌,然后选择""Next""。 7. 输入在MFA设备背面找到的序列号,在MFA设备上输入显示的六位数编码。 8. 输入MFA设备上显示的第二个六位数编码。 9. 选择""Add MFA""。 10. 使用Google Authenticator生成身份验证代码。 您将使用生成的代码来登录根用户账号。这样就可以禁用原有的SMS-MFA验证并启用Google Authenticator MFA。","[""https://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/enable-hw-mfa-for-root.html"",""https://repost.aws/questions/QUdE1SunSsQLyjlnru7Ke17A""]",TRUE,FALSE,答非所问,根据提供的文章,要禁用root用户的SMS-MFA验证并完全切换到使用Google Authenticator MFA,可以采取以下步骤: 1. 首先,登录到AWS Management Console,并选择Root user(根用户),输入您的AWS账户电子邮件地址,以账户拥有者身份登录IAM控制台。在下一页上,输入您的密码。 2. 在导航栏的右侧选择您的账户名称,然后选择Security credentials(安全凭证)。如有必要,选择Continue to Security Credentials(继续使用安全凭证)。 3. 展开Multi-factor authentication (MFA) (多重验证) 部分。 4. 选择Assign MFA device(分配 MFA 设备)。 5. 在向导中,键入Device name(设备名称),选择Hardware TOTP token(硬件 TOTP 令牌),然后选择Next(下一步)。 6. 在Serial Number (序列号) 框中,键入在MFA设备背面找到的序列号。 7. 在MFA code 1 (MFA 代码 1) 框中,输入MFA设备显示的六位数编码。您需要按设备正面的按钮来显示编码。 8. 在设备刷新期间等候30秒,然后在MFA code 2 (MFA 代码 2) 框中键入第二个六位数编码。您需要再次按设备正面的按钮来显示第二个编码。 9. 选择Add MFA(添加 MFA)。现在,MFA设备已与AWS账户相关联。 10. 如果您已经创建了一个IAM用户并且为其启用了SMS MFA,请在2019年2月1日之后,通过删除该用户的SMS MFA,将其切换到使用Google Authenticator MFA。 11. 如果您仍然看到SMS MFA,请联系AWS Support以停用您的MFA设置。,FALSE,答非所问,您好!要禁用root用户的SMS-MFA验证并完全切换到使用Google Authenticator MFA,可以按照以下步骤操作: 1. 登录到AWS Management Console,选择Root User(根用户)并输入您的AWS账户电子邮件地址,以账户拥有者身份登录IAM控制台。在下一页上,输入您的密码。 2. 在导航栏的右侧选择您的账户名称,然后选择Security Credentials(安全凭证)。如果有需要,可以选择Continue to Security Credentials(继续使用安全凭证)。 3. 展开Multi-factor authentication (MFA) (多重验证) 部分。 4. 点击Assign MFA device(分配MFA设备)。 5. 在向导中,选择Hardware TOTP token(硬件TOTP令牌),然后输入Device Name(设备名称)并选择Next(下一步)。 6. 在Serial Number(序列号)框中,键入在MFA设备背面找到的序列号。 7. 在MFA Code 1(MFA代码 1)框中,输入MFA设备显示的第一个六位编码。您需要在设备正面按下按钮来显示编码。 8. 在设备刷新期间等待30秒,然后在MFA Code 2(MFA代码 2)框中输入第二个六位编码。您需要再次按下设备正面的按钮来显示第二个编码。 9. 点击Add MFA(添加MFA)。这样,MFA设备已与AWS账户关联。 接下来,您需要下载Google Authenticator应用并将其安装到您的手机上。然后按照以下步骤启用Google Authenticator MFA: 1. 在AWS Management Console中选择Root User(根用户)。 2. 点击Security Credentials(安全凭证)。 3. 展开Multi-factor authentication (MFA) (多重验证) 部分。 4. 选择Enable MFA(启用MFA)。 5. 选择Use an external authentication app(使用外部身份验证应用程序)。 6. 选择Google Authenticator。 7. 点击Download Google Authenticator App(下载Google Authenticator应用程序)并按照指示操作。 8. 打开Google Authenticator应用并启用它。 现在,您已经成功禁用了SMS-MFA验证并完全切换到了使用Google Authenticator MFA。下次使用root用户凭证登录时,您将需要输入Google Authenticator应用生成的验证码。,FALSE,答非所问,"根据背景知识,您之前为root用户启用了SMS MFA,现在想完全切换到使用Google Authenticator。 要禁用root用户的SMS MFA并切换到Google Authenticator,可以采取以下步骤: 1. 联系AWS支持,请求他们为您的账户禁用SMS MFA。AWS不支持同时为root用户启用多个MFA设备。 2. 在IAM控制台为root用户分配Google Authenticator作为MFA设备。 3. 按照流程在Google Authenticator应用上配置MFA。 4. 测试登录,验证只提示输入Google Authenticator的验证码,不再需要SMS验证码。 5. 如果仍然提示输入SMS验证码,重复联系AWS支持,确认SMS MFA已完全禁用。 6. 可选步骤:在IAM控制台删除任何旧的SMS MFA设备。 7. 现在root用户的MFA应该完全切换到了Google Authenticator。 关键是联系AWS支持禁用旧的SMS MFA,因为AWS不允许同时为一个用户启用多个MFA设备。完成这一步后,就可以为root配置并启用新的Google Authenticator MFA了。",FALSE,基于 SMS 短信的 MFA – AWS 已终止对短信多重身份验证(MFA)的支持。,"要禁用root用户的SMS MFA并切换到Google Authenticator,可以采取以下步骤: 1. 联系AWS支持,请求他们为您的账户禁用SMS MFA。AWS不支持同时为root用户启用多个MFA设备。 2. 在IAM控制台为root用户分配Google Authenticator作为MFA设备。 3. 按照流程在Google Authenticator应用上配置MFA。 4. 测试登录,验证只提示输入Google Authenticator的验证码,不再需要SMS验证码。 5. 如果仍然提示输入SMS验证码,重复联系AWS支持,确认SMS MFA已完全禁用。 6. 可选步骤:在IAM控制台删除任何旧的SMS MFA设备。 7. 现在root用户的MFA应该完全切换到了Google Authenticator。", -https://repost.aws/questions/QU_aKeiIg6T96N5eAqFMSV5g,"这取决于不同的集成方式。比如,当使用Lambda集成时,负载将被发送到后端。当使用HTTP或VPC Link集成时,只有当选择集成方法为POST(也可能是PUT)时,负载才会发送到后端。 - - -因此,如果您创建一个包含GET方法的资源,并将其配置为使用POST方法与HTTP / VPC后端集成,负载将被发送到后端。",在API Gateway REST API中,能否将JSON数据作为GET方法的请求体发送?,这取决于不同的集成方式。比如,当使用Lambda集成时,负载将被发送到后端。当使用HTTP或VPC Link集成时,只有当选择集成方法为POST(也可能是PUT)时,负载才会发送到后端。 因此,如果您创建一个包含GET方法的资源,并将其配置为使用POST方法与HTTP / VPC后端集成,负载将被发送到后端。,"[""https://repost.aws/questions/QU_aKeiIg6T96N5eAqFMSV5g""]",TRUE,TRUE,,,,,,,,,,,"这取决于不同的集成方式。比如,当使用Lambda集成时,负载将被发送到后端。当使用HTTP或VPC Link集成时,只有当选择集成方法为POST(也可能是PUT)时,负载才会发送到后端。 - - -因此,如果您创建一个包含GET方法的资源,并将其配置为使用POST方法与HTTP / VPC后端集成,负载将被发送到后端。", -https://repost.aws/questions/QUd6IcnCLtQ6aN7Nd43TBUag,"使用Lambda可以实现最长达7天的presigned URL。使用Sig V4的任何预签名URL场景的最大有效到期日期为10天。要使预签名URL在整个7天内有效,您需要使用IAM用户的有效凭据来生成URL。在Lambda中执行此操作,您需要将Lambda访问长期IAM用户凭据,并使用它们生成带有v4版本的presigned URL。 - - -您可以使用加密的环境变量或Secrets Manager等方法来实现此操作。然后配置您的Lambda使用这些凭据,而不是在生成预签名URL时使用Lambda的执行角色凭据。",我想通过Lambda生成presigned URL以获取S3对象,请问到期时间最长可以设置为多少天?,您可以通过使用AWS SDK生成预签名URL,并且根据SDK的文档,最长可以设置为10天。,"[""https://repost.aws/questions/QUd6IcnCLtQ6aN7Nd43TBUag"",""https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/userguide/S3OutpostsPresignedUrlUploadObject.html""]",TRUE,FALSE,,根据您提供的信息,使用Lambda生成presigned URL的最长到期时间为7天。这是因为您需要在Lambda函数中生成带有v4版本的presigned URL,并根据需要设置到期时间。,TRUE,,到期时间最长可以设置为7天。,TRUE,,"根据背景知识,使用Lambda生成presigned URL访问S3对象时,到期时间最长可以设置为7天。 主要原因有: 1. 使用Sig V4签名的预签名URL的最大有效期限是10天。 2. 要使预签名URL在整个期限内有效,需要使用长期有效的IAM用户凭证来生成URL。在Lambda中,可以通过加密的环境变量或Secrets Manager来获取长期IAM用户凭证。 3. Lambda的执行角色凭证的有效期限不够长,无法支持超过7天的预签名URL。 4. 通过Lambda生成的预签名URL,到期时间最长可以设置为7天。 所以如果需要通过Lambda生成预签名URL访问S3对象,到期时间的最大设置是7天,无法设置为10天。要实现10天的有效期限,需要在Lambda函数外部生成预签名URL。",FALSE,,"使用Lambda可以实现最长达7天的presigned URL。要使预签名URL在整个7天内有效,您需要使用IAM用户的有效凭据来生成URL。在Lambda中执行此操作,您需要将Lambda访问长期IAM用户凭据,并使用它们生成带有v4版本的presigned URL。 - - -您可以使用加密的环境变量或Secrets Manager等方法来实现此操作。然后配置您的Lambda使用这些凭据,而不是在生成预签名URL时使用Lambda的执行角色凭据。",原问题回答有问题,「This can be accomplished using Lambda up to a maximum of 7 days. 10 days is beyond the maximum valid expiration period for any pre-signed url scenario using Sig V4. 」被翻译成「使用Lambda可以实现最长达7天的presigned URL。使用Sig V4的任何预签名URL场景的最大有效到期日期为10天。」 -https://repost.aws/questions/QUPSc8k5DCQ8249CR167RDkw,是的。可用区彼此足够接近以允许同步数据;但可用区内的设施更近。在所有其他条件相同的情况下,更短的距离等于更短的延迟。,将计算资源与Lambda函数部署在相同AZ是否会降低延迟?,是的,将计算资源与Lambda函数部署在相同可用区会降低延迟。因为可用区内的设施更近,距离更短,可以更快速地访问计算资源和数据,从而减少延迟。,"[""https://repost.aws/questions/QUPSc8k5DCQ8249CR167RDkw""]",TRUE,TRUE,,答案:是的。,TRUE,,是的,将计算资源与Lambda函数部署在相同的可用区(AZ)可以降低延迟。这是因为可用区彼此之间足够接近,可以确保同步数据的低延迟传输。此外,同一AZ内的计算资源和Lambda函数所在的设施也更近,从而进一步降低了延迟。,TRUE,,"根据背景知识,将计算资源(如EC2、ECS、Fargate)与Lambda函数部署在同一个可用区(AZ)内可以降低延迟。 原因是同一个AZ内的设施距离更近,距离更短可以减少网络传输时间,从而降低延迟。AWS的不同可用区设计为足够接近以允许同步数据传输,但同个AZ内的数据中心距离显然更近。 所以,如果其他条件相同的情况下,将计算资源与Lambda放在同一个AZ,相比跨AZ部署,可以减少两者之间的网络距离,降低延迟。这也是AWS那篇文章中的“可用区亲和性”优化的原理。 总结一下,将计算资源与Lambda函数部署在同一可用区内,可以降低两者之间的延迟。",TRUE,,"将计算资源(如EC2、ECS、Fargate)与Lambda函数部署在同一个可用区(AZ)内可以降低延迟。 原因是同一个AZ内的设施距离更近,距离更短可以减少网络传输时间,从而降低延迟。AWS的不同可用区设计为足够接近以允许同步数据传输,但同个AZ内的数据中心距离显然更近。 所以,如果其他条件相同的情况下,将计算资源与Lambda放在同一个AZ,相比跨AZ部署,可以减少两者之间的网络距离,降低延迟。", -https://repost.aws/questions/QUJkv4vqppQOip3MGhE2ZbLQ,"当您在Lambda函数的代码选项卡中时,请将页面滚动到底部以下。 - - -您会看到“代码属性”,后面是“运行时设置”。 - - -在“运行时设置”中,单击“编辑”按钮,然后应该可以将Python版本更改为3.9。",如何在AWS Lambda控制台中将Python 3.6更新至3.9?,"在AWS Lambda控制台中,您可以按照以下步骤将Python 3.6更新至3.9。 1. 打开AWS Lambda控制台,地址为https://console.aws.amazon.com/lambda/。 2. 从导航窗格中选择""my-date-time-app-myDateTimeFunction""函数。该函数名称在控制台中会显示一个标识符,类似于""my-date-time-app-myDateTimeFunction-123456ABCDEF""。 3. 选择""别名"",然后选择""直播""。 4. 在""原始函数版本(版本1)""和""更新的函数版本(版本2)""旁边,会显示每个版本所占的权重。权重表示在加载此AWS Lambda控制台页面时,每个版本所提供的流量。该页面不会随时间更新权重。如果每隔一分钟刷新一次页面,版本1的权重会降低10%,版本2的权重会增加10%,直到版本2的权重达到100%。 通过按照以上步骤操作,您可以在AWS Lambda控制台中将Python 3.6更新至3.9。","[""https://docs.aws.amazon.com/zh_cn/codedeploy/latest/userguide/tutorial-lambda-sam-deploy-update.html"",""https://repost.aws/questions/QUJkv4vqppQOip3MGhE2ZbLQ""]",TRUE,FALSE,,要在AWS Lambda控制台中将Python 3.6更新至3.9,请按照以下步骤操作: 1. 在Lambda函数的代码选项卡中,将页面滚动到底部。 2. 您会看到“代码属性”,后面是“运行时设置”。在“运行时设置”中,点击“编辑”按钮。 3. 应该可以将Python版本更改为3.9。在这里,您将使用更新后的Python版本进行部署和启动Lambda函数。 4. 在CodeDeploy或AWS Lambda控制台中监控部署进度。 5. 使用sam package和sam deploy命令更新并触发Lambda函数的部署。,TRUE,,"您可以通过以下步骤在AWS Lambda控制台中将Python 3.6更新至3.9: 1. 打开AWS Lambda控制台并选择您的函数。 2. 在代码选项卡中,点击""编辑""按钮。 3. 在运行时设置中,将Python版本更改为3.9。 4. 点击""保存""以应用更改。 5. 等待部署完成,您可以在AWS Lambda控制台的部署历史记录中查看进展情况。 请注意,您还需要确保您的代码和依赖项与Python 3.9兼容。",TRUE,,"根据背景知识,要在AWS Lambda控制台中将Python运行时从3.6更新到3.9,可以执行以下步骤: 1. 在Lambda函数的代码选项卡中,向下滚动到底部的“代码属性”部分。 2. 在“运行时设置”中,点击“编辑”按钮。 3. 在弹出的“编辑运行时设置”窗口中,将“运行时”下拉菜单改为Python 3.9。 4. 点击“保存”来应用更改。 这样就可以将该Lambda函数的Python运行时从3.6升级到3.9了。需要注意的是,代码需要与Python 3.9兼容,升级运行时后如果代码报错,可能需要相应做一些修改。",TRUE,,"要在AWS Lambda控制台中将Python运行时从3.6更新到3.9,可以执行以下步骤: 1. 在Lambda函数的代码选项卡中,向下滚动到底部的“运行时设置”部分。 2. 在“运行时设置”中,点击“编辑”按钮。 3. 在弹出的“编辑运行时设置”窗口中,将“运行时”下拉菜单改为Python 3.9。 4. 点击“保存”来应用更改。 这样就可以将该Lambda函数的Python运行时从3.6升级到3.9了。", -https://repost.aws/questions/QULEECrWJ-R52ONKr_SR-Smg,Lambda的有效负载有限制,同步调用为6MB,异步调用为256KB(请参阅https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html)。因此,在您的情况下,由于上下文会添加到传递给最终Lambda的有效负载中,因此最大尺寸将是(6MB-(来自API网关的有效负载大小))。,Lambda Authorizer 上下文响应是否有大小限制?如果存在,限制是多少?,Lambda的有效负载有限制,同步调用为6MB,异步调用为256KB(请参阅https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html)。因此,在您的情况下,由于上下文会添加到传递给最终Lambda的有效负载中,因此最大尺寸将是(6MB-(来自API网关的有效负载大小))。,"[""https://repost.aws/questions/QULEECrWJ-R52ONKr_SR-Smg""]",TRUE,TRUE,,,,,,,,,,,Lambda的有效负载有限制,同步调用为6MB,异步调用为256KB(请参阅https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html)。因此,在您的情况下,由于上下文会添加到传递给最终Lambda的有效负载中,因此最大尺寸将是(6MB-(来自API网关的有效负载大小))。, -https://repost.aws/questions/QUPfIJnXi3RfOWTH3P24P9YA,它可以[大小高达 10G](https://docs.aws.amazon.com/lambda/latest/dg/images-create.html#images-types)。,Lambda Docker镜像的最大支持多少?,它可以[大小高达 10G](https://docs.aws.amazon.com/lambda/latest/dg/images-create.html#images-types)。,"[""https://repost.aws/questions/QUPfIJnXi3RfOWTH3P24P9YA""]",TRUE,TRUE,,,,,,,,,,,它可以[大小高达 10G](https://docs.aws.amazon.com/lambda/latest/dg/images-create.html#images-types)。, -https://repost.aws/questions/QUbcls15KTRMuvBKfxhTz8mQ,"两个可能有帮助的想法: - - -1. 他们为什么要将数据从 EFS 复制到 S3? -如果他们希望在不经常访问的数据上省钱,那么[EFS Infrequent Access](https://aws.amazon.com/blogs/aws/new-infrequent-access- storage-class-for-amazon-elastic-file-system-efs/)可以很好地满足他们的要求。它将在可配置的时间段内未访问过的数据转换为价格比 EFS Standard低 85% 的存储。 -2. 他们的数据量大吗(几个GiB+),需要定期同步吗? -如果是这样,并且 EFS IA 不是合适的解决方案,而 [AWS DataSync](https://aws.amazon.com/datasync/) 可能是您的最佳选择。它针对性能进行了优化,因此它将是在两种服务之间移动数据的最快方式。它还可以配置为定期运行,每次都同步增量。",请告诉我将EFS中的数据复制到S3的最佳实践?是否建议使用DataSync或其他方法来加速传输?,将EFS中的数据复制到S3的最佳实践是使用EFS Infrequent Access存储类别。如果您希望在不经常访问的数据上省钱,EFS IA可以很好地满足您的要求。它将在可配置的时间段内未访问过的数据转换为价格比EFS Standard低85%的存储。 如果您的数据量大且需要定期同步,AWS DataSync可能是您最佳的解决方案。它针对性能进行了优化,可以成为在两种服务之间移动数据的最快方式。您还可以使用DataSync在两个EFS文件系统之间传输文件,以执行一次性数据迁移、分布式工作负载的定期数据提取和自动复制以实现数据保护与恢复。 如果您的数据量大且需要定期同步,并且EFS IA不是合适的解决方案,AWS DataSync可能是您的最佳选择。它针对性能进行了优化,可以成为在两种服务之间移动数据的最快方式。您还可以使用DataSync在两个EFS文件系统之间传输文件,以执行一次性数据迁移、分布式工作负载的定期数据提取和自动复制以实现数据保护与恢复。 请注意,上述回答基于您提供的知识资源,并提供了两种可能的解决方案。如果您需要更详细的信息,请参阅Amazon Elastic File System入门和AWS DataSync用户指南。,"[""https://docs.aws.amazon.com/zh_cn/efs/latest/ug/trnsfr-data-using-datasync.html"",""https://repost.aws/questions/QUbcls15KTRMuvBKfxhTz8mQ""]",TRUE,FALSE,第一句话表述有问题,根据提供的信息,将EFS中的数据复制到S3的最佳实践之一是使用AWS DataSync。这种方法可以优化性能并在网络文件系统(NFS)、服务器消息块(SMB)文件服务器、自管对象存储、Amazon S3存储桶、AWS Snowcone、Amazon EFS文件系统以及适用于Windows文件服务器文件系统的FsX之间复制数据。还可以通过使用DataSync在两个EFS文件系统之间传输文件,包括不同AWS区域或不同AWS账户拥有的文件系统。这样可以实现快速、可靠的数据复制,同时也可以根据需求进行定期同步。,TRUE,,将EFS中的数据复制到S3的最佳实践取决于多种因素,例如数据量、传输频率和成本考虑。以下是一些建议: 1. **了解EFS和S3的存储类型**:根据数据访问模式选择适当的存储类型非常重要。如果您的数据需要频繁读取,则EFS可能更适合;如果需要频繁写入或需要高可用性,则S3可能更合适。确保您了解每种存储类型的优缺点,以便做出正确的决定。 2. **使用EFS Infrequent Access**:如果您希望在不经常访问的数据上省钱,可以使用EFS Infrequent Access。这种存储类将在可配置的时间段内未访问过的数据转换为价格比EFS Standard低85%的存储。这对于那些只有少量数据需要频繁读取或写入的应用程序非常有用。 3. **使用DataSync**:如果您的数据量大且需要定期同步,则可以考虑使用AWS DataSync。DataSync针对性能进行了优化,因此在两种服务之间移动数据时是最快的方式。它可以配置为定期运行并每次同步增量,从而确保数据的准确性。 4. **使用多个文件网关**:如果您需要在EFS和S3之间传输大量数据,则可以考虑使用多个文件网关。这可以帮助分散流量并提高传输速度。确保您了解如何设置和管理多个文件网关。 总之,将EFS中的数据复制到S3的最佳实践取决于具体情况。在选择最佳方法时要考虑数据量、传输频率、成本和性能等因素。,FALSE,,"根据背景知识,将EFS中的数据复制到S3的最佳实践可以考虑以下几点: 1. 如果数据访问频率不高,可以考虑使用EFS Infrequent Access存储类,它可以将长时间未访问的数据以比EFS Standard低85%的价格存储。 2. 如果需要定期同步大量数据(几个GiB以上),AWS DataSync是最好的选择。它专门针对性能进行了优化,可以更快速地在EFS和S3之间传输数据。并且可以配置为定期运行,增量同步。 3. DataSync可以在EFS文件系统之间复制数据,实现跨区域、跨账户的数据迁移。 4. 可以考虑使用多个文件网关来加速EFS到S3的传输,但DataSync可能会更高效、方便。 5. 在成本、速度和可靠性方面,DataSync都是不错的选择。相比自建传输方案,它可以省去很多运维工作。 6. 如果需要一次性大规模数据迁移,可以考虑使用AWS Snowball等设备先离线传输,然后再使用DataSync增量同步。 综上所述,对于定期同步EFS中的数据到S3,使用AWS DataSync是非常好的选择,可以提供高速、可靠的数据传输和自动化同步。",TRUE,,"两个可能有帮助的想法: - - -1. 他们为什么要将数据从 EFS 复制到 S3? -如果他们希望在不经常访问的数据上省钱,那么[EFS Infrequent Access](https://aws.amazon.com/blogs/aws/new-infrequent-access- storage-class-for-amazon-elastic-file-system-efs/)可以很好地满足他们的要求。它将在可配置的时间段内未访问过的数据转换为价格比 EFS Standard低 85% 的存储。 -2. 他们的数据量大吗(几个GiB+),需要定期同步吗? -如果是这样,并且 EFS IA 不是合适的解决方案,而 [AWS DataSync](https://aws.amazon.com/datasync/) 可能是您的最佳选择。它针对性能进行了优化,因此它将是在两种服务之间移动数据的最快方式。它还可以配置为定期运行,每次都同步增量。", -https://repost.aws/questions/QUiT9aLCJZQzygJ2z80UChNw,"对的,它也有最小对象大小128KB的限制,您可以通该链接找到相关信息(https://aws.amazon.com/s3/pricing/)。 - - - - -来自上述链接页面的内容: - - -> S3标准-IA和S3单可用区-IA存储具有最小计费对象大小为128 KB。较小的对象可能会被存储,但会按照相应的存储类别费率计算128 KB的存储费。",S3 One Zone Infrequent Access存储类别下的最小对象的大小限制是多少?,S3 One Zone Infrequent Access存储类别下的最小对象的大小限制是128 KB。,"[""https://repost.aws/questions/QUiT9aLCJZQzygJ2z80UChNw"",""https://docs.aws.amazon.com/zh_cn/snowball/latest/developer-guide/limits.html""]",TRUE,TRUE,,根据提供的信息,S3 One Zone Infrequent Access存储类别下的最小对象的大小限制是128KB。,TRUE,,S3 One Zone Infrequent Access存储类别下的最小对象的大小限制是128KB。,TRUE,,"根据背景知识中的内容,S3 One Zone Infrequent Access (IA) 存储类别的最小计费对象大小是128KB。 即使实际存储了更小的对象,也会按128KB来计算存储费用。所以S3 One Zone IA的最小对象计费大小是128KB。",TRUE,,"S3 One Zone Infrequent Access (IA) 存储类别的最小计费对象大小是128KB。 即使实际存储了更小的对象,也会按128KB来计算存储费用。所以S3 One Zone IA的最小对象计费大小是128KB。", -https://repost.aws/questions/QUwHTYd0C9SmS3v4myPmUhNg,"在第一个完整副本之后它将是增量的。 - - - - -快照副本是否增量取决于最近完成的快照副本。跨地域或跨账号复制快照时,满足以下条件的副本为增量副本: - - - - -* 快照之前已复制到目标区域或账户。 -* 最近的快照副本仍然存在于目标区域或账户中。 -* 目标区域或账户中快照的所有副本未加密或使用相同的 CMK 加密。 - - - - -如果删除了最新的快照副本,则下一个副本是完整副本,而不是增量副本。如果在启动另一个副本时副本仍处于挂起状态,则第二个副本仅在第一个副本完成后开始。",我想将EBS快照复制到另一个区域,请问是否为增量复制?,是的,根据给定的知识资源,当将快照复制到另一个区域时,只有满足以下条件的副本是增量副本: 1. 快照之前已复制到目标区域或账户。 2. 最近的快照副本仍然存在于目标区域或账户中。 3. 目标区域或账户中快照的所有副本未加密或使用相同的 CMK 加密。 如果删除了最新的快照副本,则下一个副本是完整副本,而不是增量副本。如果在启动另一个副本时副本仍处于挂起状态,则第二个副本仅在第一个副本完成后开始。 因此,要复制的EBS快照的快照副本是否为增量复制取决于最近完成的快照副本。,"[""https://docs.aws.amazon.com/zh_cn/systems-manager-automation-runbooks/latest/userguide/automation-aws-copysnapshot.html"",""https://repost.aws/questions/QUwHTYd0C9SmS3v4myPmUhNg""]",TRUE,TRUE,,根据提供的信息,EBS快照的复制方式取决于最近完成的快照副本。如果满足以下条件,复制后的快照将会是增量副本: 1. 快照之前已复制到目标区域。 2. 最近的快照副本仍然存在于目标区域中。 3. 目标区域中快照的所有副本未加密或使用相同的CMK加密。 如果满足了这些条件,那么EBS快照的复制就是增量复制。,TRUE,,是的,如果您将EBS快照从一个区域复制到另一个区域,只要满足一些条件,它就是增量复制的。具体而言,快照副本是否为增量取决于最近完成的快照副本。如果您从源区域复制快照,并且最近完成的快照副本仍然存在,那么它就是增量副本。,TRUE,不够完整,"根据背景知识,在第一个完整副本之后,跨区域复制EBS快照是增量的。 具体来说: - 首次跨区域复制一个快照时,会创建一个完整的快照副本。 - 如果最近一次的快照副本仍存在目标区域,那么下一次的快照复制就是增量的,只复制源快照和目标快照差异部分的数据。 - 如果删除了目标区域的最新快照副本,那么下一次复制又会重新进行完整复制。 所以对于你的情况,从us-east-1区域复制快照到us-east-2区域,第一次是完整复制,之后如果保留了us-east-2的快照副本,后续的复制就是增量的。",TRUE,不够完整,当将快照复制到另一个区域时,只有满足以下条件的副本是增量副本: 1. 快照之前已复制到目标区域或账户。 2. 最近的快照副本仍然存在于目标区域或账户中。 3. 目标区域或账户中快照的所有副本未加密或使用相同的 CMK 加密。 如果删除了最新的快照副本,则下一个副本是完整副本,而不是增量副本。如果在启动另一个副本时副本仍处于挂起状态,则第二个副本仅在第一个副本完成后开始。, -https://repost.aws/questions/QU-62bkxzNS8-O5YvHXm3xFA,"当您将生命周期配置添加到存储桶中时,配置规则会同时适用于现有对象和以后添加的对象。例如,如果您今天添加一个生命周期配置规则,其中包含到期操作,使具有特定前缀的对象在创建后30天后过期,那么Amazon S3将排队删除创建超过30天的任何现有对象。 - - -当您在存储桶上启用版本控制时,存在于存储桶中的现有对象(如果有的话)不会发生变化:版本ID(为空)、内容和权限都保持不变。",S3 桶的生命周期规则和对象版本控制是适用于哪些对象?,S3 桶的生命周期规则和对象版本控制是适用于现有对象和以后添加的对象。,"[""https://repost.aws/questions/QU-62bkxzNS8-O5YvHXm3xFA"",""https://docs.aws.amazon.com/AmazonS3/latest/API/API_LifecycleRule.html""]",TRUE,TRUE,,根据提供的内容,S3桶的生命周期规则和对象版本控制适用于现有对象和以后添加的对象。,TRUE,,S3桶的生命周期规则和对象版本控制适用于现有对象和将来添加的对象。这意味着一旦设置了生命周期规则或启用了对象版本控制,它们将适用于存储桶中所有现有的对象以及后续添加的对象。,TRUE,,"根据背景知识,可以总结出: 1. 当在S3桶上启用生命周期规则时,规则会同时应用于现有对象和后续添加的新对象。 2. 当在桶上启用版本控制时,存在于桶中的现有对象不会发生变化,版本ID、内容和权限保持不变。 3. 生命周期规则和版本控制都是应用于现有对象和新对象的。启用规则后,不论对象是之前存在的还是之后添加的,规则都会应用在这些对象上。 4. 启用版本控制不会影响现有对象,只对新增对象产生影响。但生命周期规则会作用于所有对象。 所以,可以总结为: S3桶的生命周期规则适用于现有对象和新对象。对象版本控制仅适用于新添加的对象,不影响现有对象。",TRUE,,"当您将生命周期配置添加到存储桶中时,配置规则会同时适用于现有对象和以后添加的对象。例如,如果您今天添加一个生命周期配置规则,其中包含到期操作,使具有特定前缀的对象在创建后30天后过期,那么Amazon S3将排队删除创建超过30天的任何现有对象。 - - -当您在存储桶上启用版本控制时,存在于存储桶中的现有对象(如果有的话)不会发生变化:版本ID(为空)、内容和权限都保持不变。", -https://repost.aws/questions/QUjvS1awilSpmRGkGuJNcf3A,"使用生命周期是很常见的。 - - -您也可以使用CLI更改存储类别。 - - -生命周期的应用时间是每天一次,会检查对象的最后更新日期。",如何使用CLI将当前 s3 bucket对象移动到Glacier?,您可以使用CLI将当前 s3 bucket对象移动到Glacier。,"[""https://repost.aws/questions/QUjvS1awilSpmRGkGuJNcf3A"",""https://docs.aws.amazon.com/zh_cn/cli/v1/userguide/cli-services-glacier.html""]",TRUE,FALSE,,要将当前 S3 bucket 对象移动到 Glacier,可以使用 `aws s3 mv` 命令。以下是一个示例: ```bash aws s3 mv s3://my-bucket/path/to/object s3://my-glacier-vault/path/to/object ``` 这将把 s3://my-bucket/path/to/object 中的对象移动到 s3://my-glacier-vault/path/to/object。请注意,这个操作需要有足够的权限,并且 Glacier vault 已经存在。,FALSE,,要将当前 S3 bucket 中的对象移动到 Glacier,可以使用 AWS CLI 中的以下命令: ```bash aws s3 mv s3://bucket-name s3://my-glacier-vault ``` 这个命令会将 S3 bucket 中的所有对象移动到 Glacier 中的指定的 vault。其中,“bucket-name”是要移动的 S3 bucket 的名称,“my-glacier-vault”是要在 Glacier 中创建的 vault 的名称。 请注意,在执行此命令之前,确保您在 AWS 账户中启用了 S3 访问权限和 Glacier 访问权限,并且具有适当的 IAM 角色权限。,FALSE,,"您可以使用AWS CLI将S3对象移动到Glacier,主要步骤如下: 1. 创建一个S3生命周期规则,指定对象过期后将转换为Glacier存储类。例如: ```bash aws s3api put-bucket-lifecycle-configuration --bucket mybucket --lifecycle-configuration file://lifecycle.json ``` lifecycle.json内容: ```json { ""Rules"": [ { ""ID"": ""archive-to-glacier"", ""Filter"": {}, ""Status"": ""Enabled"", ""Transitions"": [ { ""Days"": 90, ""StorageClass"": ""GLACIER"" } ] } ] } ``` 这会在对象最后修改时间90天后自动转换为Glacier存储类。 2. 也可以使用aws s3api copy-object命令手动将对象复制到Glacier存储类,例如: ```bash aws s3api copy-object --bucket mybucket --key file.txt --storage-class GLACIER --copy-source mybucket/file.txt ``` 3. 如果需要直接使用Glacier API,可以使用aws glacier 命令,详见背景知识中的示例。 总之,S3生命周期规则可以自动过期对象到Glacier,也可以手动设置存储类或使用Glacier API。CLI提供了灵活的方式来管理对象的存储转换。",TRUE,,"您可以使用AWS CLI将S3对象移动到Glacier,主要步骤如下: 1. 创建一个S3生命周期规则,指定对象过期后将转换为Glacier存储类。例如: ```bash aws s3api put-bucket-lifecycle-configuration --bucket mybucket --lifecycle-configuration file://lifecycle.json ``` lifecycle.json内容: ```json { ""Rules"": [ { ""ID"": ""archive-to-glacier"", ""Filter"": {}, ""Status"": ""Enabled"", ""Transitions"": [ { ""Days"": 90, ""StorageClass"": ""GLACIER"" } ] } ] } ``` 这会在对象最后修改时间90天后自动转换为Glacier存储类。 2. 也可以使用aws s3api copy-object命令手动将对象复制到Glacier存储类,例如: ```bash aws s3api copy-object --bucket mybucket --key file.txt --storage-class GLACIER --copy-source mybucket/file.txt ``` 3. 如果需要直接使用Glacier API,可以使用aws glacier 命令,详见背景知识中的示例。 总之,S3生命周期规则可以自动过期对象到Glacier,也可以手动设置存储类或使用Glacier API。CLI提供了灵活的方式来管理对象的存储转换。", -https://repost.aws/questions/QUxPutzW7-QIavOlsy3g7s7Q,"S3分段上传的最后一部分可以小于5MB,但其他部分需要大于5MB。如果客户只进行单个部分的上传,那么可以将其设置为2MB(不过不推荐, 这种情况应该直接使用简单的PUT请求)。",S3的分段上传中每个部分的大小有限制吗?,在S3的分段上传中,每个部分的大小可以限制在5MB以下。根据给定的知识资源,每个部分的段大小必须以兆字节 (MiB)(1024 KiB)乘以 2 的幂来确定,例如,1 MiB、2 MiB、4 MiB等。但是,最后一部分的大小可以小于5MB,而其他部分的大小需要大于5MB。根据这些限制,您可以根据您的需求设置每个部分的大小。,"[""https://repost.aws/questions/QUxPutzW7-QIavOlsy3g7s7Q"",""https://docs.aws.amazon.com/zh_cn/amazonglacier/latest/dev/api-multipart-initiate-upload.html""]",TRUE,FALSE,此回答融合了repost和s3 glacier的知识,不正确。s3分段上传限制见https://docs.aws.amazon.com/AmazonS3/latest/userguide/qfacts.html,是的,S3的分段上传中,除了最后一部分之外,每个部分的大小都受到限制,不能超过5MB。,FALSE,,在S3的分段上传中,除了最后一部分可以小于5MB之外,其他部分都需要大于5MB。如果客户只进行单个部分的上传,那么可以将其设置为2MB(不过不推荐,建议直接使用简单的PUT请求)。,TRUE,,"根据背景知识和描述,S3的分段上传中有以下几点限制: 1. 每个部分的大小必须大于等于5MB,除了最后一个部分可以小于5MB。 2. 每个部分的大小必须是1MB的整数倍。 3. 第一个部分设置了大小后,后续所有部分的大小必须与第一个部分相同,最后一个部分除外。 4. 允许的最大部分大小是5GB。 5. 对于第一个部分,可以不设置大小,S3会默认每个部分是5MB。 6. 对于客户的需求,想设置每个部分为2MB,是不被S3支持的。因为2MB不满足每个部分至少5MB的限制。 7. 如果文件很小,可以直接使用PUT请求上传,不需要使用分段上传。 所以综上,S3的分段上传中,不能将每个部分限制在5MB以下,客户想把部分大小设置为2MB是不被支持的。需要注意每个部分大小的限制。",TRUE,,"S3分段上传的最后一部分可以小于5MB,但其他部分需要大于5MB。如果文件很小,可以直接使用PUT请求上传,不需要使用分段上传。", -https://repost.aws/questions/QU0VGYdZe8TRivmtGHoiDDHw,当端点大小缩到0时,您不需要支付任何计算成本的费用。但我认为您可以设计得更好。在SageMaker端点中,还有一些其他选项可供您使用(假设您正在使用实时端点):1. 尝试使用[SageMaker无服务器推理](https://docs.aws.amazon.com/sagemaker/latest/dg/serverless-endpoints.html)。它具有完全的无服务器性质,因此只有在端点提供推理时才需支付费用。我认为这更适合您的要求。2. 您也可以考虑使用Lambda,这将减少您的托管成本。但是,您需要更多地设置推理堆栈。3. 还有[SageMaker异步推理](https://docs.aws.amazon.com/sagemaker/latest/dg/async-inference.html)选项,但它主要适用于需要更长时间处理每个请求的推理。之所以提到它,是因为它也支持在没有流量时缩放到0。,当Amazon Sagemaker端点大小缩到0时,是否会产生相关费用?,"当Amazon Sagemaker端点大小缩到0时,不需要支付任何计算成本的费用。","[""https://repost.aws/questions/QU0VGYdZe8TRivmtGHoiDDHw""]",TRUE,TRUE,,根据您提供的内容,当Amazon SageMaker端点的大小缩到0时,您不需要支付任何计算成本的费用。然而,您可以考虑使用其他选项,如SageMaker无服务器推理、Lambda或SageMaker异步推理,以进一步优化成本和资源利用。,TRUE,,当Amazon SageMaker端点的大小缩到0时,不会产生任何费用。这意味着您只需要为实际使用的实例数量付费,而不会因闲置的实例而被收取额外的费用。,TRUE,,"根据背景知识中的内容,当Amazon SageMaker端点的大小缩放到0时,是不会产生任何计算相关的费用的。 背景知识中提到,为了在端点闲置时将成本降至0,可以使用自动扩展将实例数量缩减至0。并且明确指出,当端点大小缩放到0时,不需要支付任何计算成本的费用。 所以可以确定,当Amazon Sagemaker端点大小缩放到0时,不会产生任何与计算相关的费用。端点在闲置时可以通过自动扩展将实例数设置为0来实现零费用。",TRUE,,当端点大小缩到0时,您不需要支付任何计算成本的费用。但我认为您可以设计得更好。在SageMaker端点中,还有一些其他选项可供您使用(假设您正在使用实时端点):1. 尝试使用[SageMaker无服务器推理](https://docs.aws.amazon.com/sagemaker/latest/dg/serverless-endpoints.html)。它具有完全的无服务器性质,因此只有在端点提供推理时才需支付费用。我认为这更适合您的要求。2. 您也可以考虑使用Lambda,这将减少您的托管成本。但是,您需要更多地设置推理堆栈。3. 还有[SageMaker异步推理](https://docs.aws.amazon.com/sagemaker/latest/dg/async-inference.html)选项,但它主要适用于需要更长时间处理每个请求的推理。之所以提到它,是因为它也支持在没有流量时缩放到0。, -https://repost.aws/questions/QUT0vbImNKTO2ksfGRMDDEPw,"是的,这篇博文介绍了使用 Amazon Personalize 进行 A/B 测试的方法,提供了架构图,并列出了为此目的构建的工具。 -https://aws.amazon.com/blogs/machine-learning/using-a-b-testing-to-measure-the-efficacy-of-recommendations- generated-by-amazon-personalize/ -对于构建路径,零售行业中有用于A/B, interleaving, and multi-armed bandit 测试的demo - - -https://github.com/aws-samples/retail-demo-store/blob/master/workshop/3-Experimentation/3.2-AB-Experiment.ipynb -https://github.com/aws-samples/retail-demo-store/blob/master/workshop/3-Experimentation/3.3-Interleaving-Experiment.ipynb -https://github.com/aws-samples/retail-demo-store/blob/master/workshop/3-Experimentation/3.4-Multi-Armed-Bandit-Experiment.ipynb - - - - -Amazon CloudWatch Evidently 是 CloudWatch 的一项新功能,支持部署和衡量 A/B 测试。 它可以与 Amazon Personalize 结合使用,针对现有个性化解决方案和 Personalize 或两个 Personalize 模型变体进行 A/B 测试。",如何对Amazon Personalize进行A/B测试?,"要对Amazon Personalize进行A/B测试,需要按照以下步骤: 1. 定义可量化的业务目标和与目标一致的可量化假设。 2. 定义与业务目标相关的关键绩效指标(KPI)。 3. 根据假设验证实验组和对照组的用户数是否足够大。 4. 定义流量拆分策略,确保在实验运行时不更改流量分配。 5. 保持实验组和对照组的应用程序或网站的用户体验相同,但不允许应用 Amazon Personalize 的修改。 6. 控制外部因素,如节假日和营销活动。 7. 在评估结果之前,确保结果具有统计学意义。 8. 创建 Amazon Personalize 推荐器或使用 Amazon CloudWatch Evidenly 进行 A/B 测试。 9. 在 Amazon Personalize 中定义功能及其变体,在 CloudWatch Evidenly 中运行实验。 10. 在 CloudWatch Evidenly 查看实验结果。 以上步骤有助于设计、执行和评估Amazon Personalize的A/B测试。","[""https://docs.aws.amazon.com/zh_cn/personalize/latest/dg/ab-testing-evidently.html"",""https://docs.aws.amazon.com/zh_cn/personalize/latest/dg/ab-testing-recommendations.html""]",TRUE,TRUE,,要对Amazon Personalize进行A/B测试,可以按照以下步骤操作: 1. 规划实验:首先,确定实验的目标和业务目标。然后,定义实验变体,例如,要测试的推荐策略或算法。最后,确定实验的时间范围。 2. 拆分用户:将用户分成两个或多个组,包括一个对照组和一个或多个实验组。实验组将接收修改后的推荐,而对照组将接收未修改的推荐。 3. 运行实验:向实验组中的用户显示修改后的推荐,并向对照组中的用户显示未修改的推荐。记录他们与推荐的互动以跟踪结果。 4. 评估结果:分析实验结果以确定修改是否对实验组产生了统计学上的显著差异。这可以通过比较实验组和对照组的关键绩效指标(KPI)来完成。 在整个过程中,可以使用Amazon Personalize和Amazon CloudWatch Evidently进行A/B测试。Amazon CloudWatch Evidently可以帮助定义实验、跟踪KPI、将推荐请求流量路由到相关的Amazon Personalize资源,以及评估实验结果。,TRUE,,要对Amazon Personalize进行A/B测试,可以遵循以下步骤: 1. 规划实验:首先,需要明确实验的目标和业务假设。然后,确定实验的具体变量和实验的时间范围。 2. 拆分用户:将用户分成两组或多组,其中一组是实验组,另一组是对照组。 3. 运行实验:向实验组中的用户显示修改后的推荐,而对对照组中的用户显示未修改的推荐。记录用户与推荐的互动情况。 4. 评估结果:分析实验结果,确认实验组和对照组之间是否存在统计学意义的差异。这可以通过计算关键绩效指标(如点击率)来实现。 5. 做出决策:根据实验结果,决定是否实施改进措施或者调整推荐策略。 在整个过程中,可以使用Amazon Personalize提供的API和工具来进行实验设计、数据分析和结果评估。同时,也可以结合Amazon CloudWatch Evidently平台来管理实验和监控实验结果。,TRUE,,"根据背景知识,使用Amazon Personalize和Amazon CloudWatch Evidently进行A/B测试的主要步骤如下: 1. 在CloudWatch Evidently中创建一个项目,并定义要测试的功能及其变体。每个变体对应一个不同的Personalize推荐器或活动。 2. 更新应用程序代码,使用Evidently API评估每个用户会话的功能,并使用变体值调用相应的Personalize推荐器获取推荐。 3. 记录用户与推荐的互动结果,如点击、购买等。使用Evidently API报告指标,使用Personalize API报告事件。 4. 在Evidently中创建实验,指定功能、受众和要跟踪的指标。启动实验并让其运行一段时间。 5. 查看Evidently控制面板以评估实验组与对照组的指标差异,判断哪种推荐策略更好。 6. 根据结果,选择最佳的推荐策略应用于所有用户。 总体上,通过Evidently管理试验流量,在Personalize中创建不同的推荐器,然后比较实验结果来找到最优的推荐体验。",TRUE,,"使用Amazon Personalize和Amazon CloudWatch Evidently进行A/B测试的主要步骤如下: 1. 在CloudWatch Evidently中创建一个项目,并定义要测试的功能及其变体。每个变体对应一个不同的Personalize推荐器或活动。 2. 更新应用程序代码,使用Evidently API评估每个用户会话的功能,并使用变体值调用相应的Personalize推荐器获取推荐。 3. 记录用户与推荐的互动结果,如点击、购买等。使用Evidently API报告指标,使用Personalize API报告事件。 4. 在Evidently中创建实验,指定功能、受众和要跟踪的指标。启动实验并让其运行一段时间。 5. 查看Evidently控制面板以评估实验组与对照组的指标差异,判断哪种推荐策略更好。 6. 根据结果,选择最佳的推荐策略应用于所有用户。 总体上,通过Evidently管理试验流量,在Personalize中创建不同的推荐器,然后比较实验结果来找到最优的推荐体验。", -https://repost.aws/questions/QUOFMa1nZYQcGhTr-VwSAqpg,"Kendra是构建问答聊天机器人的良好起点。使用亚马逊网络服务(AWS)的Kendra,您可以构建一个使用自然语言理解和机器学习提供准确答案的问答聊天机器人,同时将您的数据保留在AWS账户中。如果您的数据已经在AWS中,您可以配置Kendra的源,例如使用S3进行索引 - - - -作为一种解决方案,通常需要通过Lex服务或传统的基于Web的解决方案(如API Gateway、Lambda和网站)配置“前端”,以处理用户交互。您还可以使用其他AWS服务,如Polly,将文本转换为语音。 -* -* - - -您可以将AWS Sagemaker JumpStart Foundation Models(在预览模式和选择的区域中)作为生成式AI模型,与Kendra/OpenSearch一起作为知识库,来组合LLM解决方案。我们提供文本摘要和问答的LLM模型。 - - -以下是一些起点链接: - - -* -* - - -希望这是您问答聊天机器人解决方案的良好起点。 - - -如果您认为这对您的解决方案设计有所帮助,请选择接受。",我想使用AWS服务来构建基于AWS中私有数据的聊天机器人,请推荐一些服务,建议使用Kendra作为构建基于AWS中私有数据的聊天机器人的解决方案。它能够使用自然语言理解和机器学习来提供准确答案,同时将数据保留在AWS账户中。您可以通过配置源,如使用S3进行索引,来使用Kendra。此外,您还可以使用其他AWS服务,如Polly,将文本转换为语音。您还可以使用AWS Sagemaker JumpStart Foundation Models作为生成式AI模型,与Kendra/OpenSearch一起作为知识库。希望这些信息对您有所帮助!,"[""https://docs.aws.amazon.com/zh_cn/chime/latest/ag/chat-bots.html"",""https://repost.aws/questions/QUOFMa1nZYQcGhTr-VwSAqpg""]",TRUE,TRUE,,根据所提供的文章,为了构建一个基于AWS中私有数据的聊天机器人,您可以考虑使用Kendra或者结合使用Kendra和LLM(生成式AI模型)解决方案。Kendra是一个良好的起点,可以帮助您构建一个使用自然语言理解和机器学习提供准确答案的问答聊天机器人,同时将您的数据保留在AWS账户中。而LLM解决方案可以通过Amazon Sagemaker JumpStart Foundation Models和Kendra/OpenSearch结合起来实现。此外,您还可以通过Lex服务或其他传统的基于Web的解决方案(如API Gateway、Lambda和网站)配置“前端”,以处理用户交互。同时,也可以使用Polly将文本转换为语音。,TRUE,,对于基于AWS中私有数据的聊天机器人,我建议您考虑使用Kendra。Kendra可以帮助您构建一个使用自然语言理解和机器学习提供准确答案的问答聊天机器人,同时将您的数据保留在AWS账户中。您可以通过配置Kendra的源,例如使用S3进行索引,来轻松地集成您的数据。此外,您还可以结合使用AWS Sagemaker JumpStart Foundation Models和Kendra/OpenSearch作为知识库,来构建更强大的LLM解决方案。,TRUE,,"根据背景知识,构建基于AWS中私有数据的聊天机器人,主要可以考虑使用以下AWS服务: - Kendra:一个知识库和搜索服务,可以用来构建问答型聊天机器人。可以将私有数据上传到S3,然后使用Kendra索引和搜索该数据,为用户查询提供答案。 - Lex:一个构建对话式交互和聊天机器人的服务。可以用来处理自然语言理解、意图识别、会话管理等。可以将Lex与Kendra集成,提供强大的问答功能。 - Polly:一个文本转语音服务,可以让聊天机器人以语音的形式和用户交互。 - Lambda:用于编写聊天机器人的逻辑和后端功能的服务器less计算服务。 - API Gateway:可以用来创建聊天机器人的web接口。 - Amazon Chime:可以与聊天机器人集成,让用户在Chime中使用聊天机器人。 - SageMaker:可以用来训练各种机器学习模型,如文本生成等,实现更智能的聊天机器人。 综合利用这些服务,可以快速构建功能强大、安全可靠的聊天机器人,并为用户提供便捷的交互体验。",TRUE,,"Kendra是构建问答聊天机器人的良好起点。使用亚马逊网络服务(AWS)的Kendra,您可以构建一个使用自然语言理解和机器学习提供准确答案的问答聊天机器人,同时将您的数据保留在AWS账户中。如果您的数据已经在AWS中,您可以配置Kendra的源,例如使用S3进行索引 - - - -作为一种解决方案,通常需要通过Lex服务或传统的基于Web的解决方案(如API Gateway、Lambda和网站)配置“前端”,以处理用户交互。您还可以使用其他AWS服务,如Polly,将文本转换为语音。 -* -* - - -您可以将AWS Sagemaker JumpStart Foundation Models(在预览模式和选择的区域中)作为生成式AI模型,与Kendra/OpenSearch一起作为知识库,来组合LLM解决方案。我们提供文本摘要和问答的LLM模型。 - - -以下是一些起点链接: - - -* -* ", -https://repost.aws/questions/QUy3Oiyj6sTbah-fX9mSSrkg,Amazon Forecast的训练过程是托管的。您无法将训练好的模型导出服务外。您可以通过在Amazon Forecast控制台中展开“训练参数”部分来查看使用的模型超参数。或者您可以调用API命令describe_predictor()来查看超参。如果您在“训练参数”部分中看不到设置的值,则说明它使用了默认值,关于默认值可以参考文档中的超参数部分。,如何在Amazon Forecast上导出已经训练好的模型,以便在其他地方部署?,您无法直接将训练好的模型导出到其他地方部署。您可以通过在Amazon Forecast控制台中查看训练参数或调用API命令来了解模型超参数。如果您想使用外部训练的模型,您需要先导入该模型。 导入外部训练的模型需要在AWS Management Console中选择Models(模型),然后选择Import model(导入模型)。在导入源中选择外部训练的模型,并提供模型路径、模型名称和其他相关信息。然后,选择Import model(导入模型)完成导入过程。 请注意,导入模型可能会根据您的具体设置和需求进行配置。在导入模型时,请确保提供正确的模型路径、名称和描述。,"[""https://docs.aws.amazon.com/zh_cn/deeplens/latest/dg/deeplens-import-external-trained.html"",""https://repost.aws/questions/QUy3Oiyj6sTbah-fX9mSSrkg""]",TRUE,FALSE,回答将repost和DeepLens服务的UserGuide结合在了一起,导致最终答案不太准确,首先,登录到AWS管理控制台并进入AWS DeepLens界面。然后在导航窗格中选择Models(模型),接着选择Import model(导入模型)。对于Import source(导入源),选择Externally trained model(外部训练的模型)。接下来,提供正确的模型构件路径、模型名称和其他相关信息。最后,选择Import model(导入模型)。,FALSE,,"抱歉,我之前的回答有误。在Amazon Forecast上,您无法直接导出已经训练好的模型。但是,您可以将训练好的模型导入到其他环境进行部署和使用。具体步骤如下: 1. 登录到Amazon Forecast控制台并展开“训练参数”部分。 2. 在“训练参数”部分中,您可以找到使用的模型超参数。 3. 如果您在“训练参数”部分中看不到设置的值,则说明它使用了默认值,可以参考文档《AWS Forecast 选择食谱》中的超参数部分。 要将外部训练的模型导入到Amazon Forecast中,请按照以下步骤操作: 1. 登录到Amazon Forecast控制台。 2. 在导航窗格中,选择Models (模型),然后选择Import model (导入模型)。 3. 对于Import source (导入源),选择Externally trained model (外部训练的模型)。 4. 对于Model settings (模型设置),提供以下信息。 - 在模型构件路径中,输入训练模型时创建的项目在Amazon Simple Storage Service (Amazon S3)位置的完整路径。路径以""s3://deeplens-""开头。例如,如果您遵循的是我们在本文档中自始至终使用的命名约定,则路径为""s3://deeplens-sagemaker-your_name/""。 - 对于Model name (模型名称),键入一个名称。模型名称最多只能包含100个字母数字字符和连字符。 - 可选。对于Description (描述),键入模型的描述。 5. 点击""Import model""按钮开始导入模型。",FALSE,,"对于在Amazon Forecast上训练的模型,无法直接将整个模型导出。但是可以通过以下方法获取模型信息: 1. 在Amazon Forecast控制台中,展开""训练参数""部分,可以查看模型使用的超参数信息。 2. 调用Amazon Forecast的DescribePredictor API,可以获取当前模型的详细信息,包括算法、超参数等。 3. 查看Amazon Forecast的算法文档,了解不同算法的默认超参数设置。例如ARIMA的默认参数设置见:https://docs.aws.amazon.com/forecast/latest/dg/aws-forecast-choosing-recipes.html 4. 如果需要部署外部训练的模型,可以考虑先在本地训练模型,然后通过Amazon Forecast的CreatePredictor API导入模型。需要提供模型的训练参数等信息。 5. 也可以考虑使用Amazon SageMaker训练模型,然后通过其部署接口进行部署。 总体来说,Amazon Forecast的目标是提供托管的训练和预测服务,不适合导出模型进行外部部署。如果有这个需求,可以考虑 SageMaker 等其他服务。",TRUE,,Amazon Forecast的训练过程是托管的。您无法将训练好的模型导出服务外。您可以通过在Amazon Forecast控制台中展开“训练参数”部分来查看使用的模型超参数。或者您可以调用API命令describe_predictor()来查看超参。如果您在“训练参数”部分中看不到设置的值,则说明它使用了默认值,关于默认值可以参考文档中的超参数部分。, -https://repost.aws/questions/QULE5r3b6eRCODKsA34EtMSw,有可能是因为您尝试进行跨帐户拷贝却没有启用资源策略resource based policy(项目策略project policy)。您需要为训练好的模型定义IAM资源策略,以允许跨帐户访问。这里有一篇博客,介绍了项目策略和跨账户拷贝的步骤。链接为:https://aws.amazon.com/blogs/machine-learning/announcing-the-launch-of-the-model-copy-feature-for-amazon-rekognition-custom-labels/。,如何解决在Amazon Rekognition复制旧模型时遇到的“Cross account access not allowed”错误?,要解决在Amazon Rekognition复制旧模型时遇到的“Cross account access not allowed”错误,您需要执行以下步骤: 1. 首先,您需要确保您具有访问Amazon Rekognition和IAM资源的权限。如果您没有权限,请联系您的管理员请求更新您的策略,以允许跨帐户访问。 2. 如果您已经具有访问权限,但仍然遇到错误,请确保您正在使用正确的AWS账号和正确的IAM角色。请确保您使用的账号和角色与您尝试复制的旧模型的所有者相匹配。 3. 如果您仍然遇到问题,请检查您的IAM策略。您需要为训练好的模型定义一个IAM资源策略,以允许跨帐户访问。您可以参考以下博客文章来了解如何创建适当的资源策略:https://aws.amazon.com/blogs/machine-learning/announcing-the-launch-of-the-model-copy-feature-for-amazon-rekognition-custom-labels/。 如果您需要进一步的帮助或遇到其他问题,请联系AWS解决方案团队。他们将能够提供更具体的指导和解决方案。,"[""https://docs.aws.amazon.com/zh_cn/rekognition/latest/dg/security_iam_troubleshoot.html"",""https://repost.aws/questions/QULE5r3b6eRCODKsA34EtMSw""]",TRUE,TRUE,,根据提供的文章,解决这个问题的关键在于为训练好的模型定义IAM资源策略,以允许跨账户访问。这是因为您尝试进行跨帐户拷贝而没有启用资源策略。您可以通过遵循文章中提供的步骤来完成此操作,例如联系您的管理员帮助更新您的策略以允许跨帐户访问。此外,还可以参考文章中提供的链接,了解更多关于项目策略和跨账户拷贝的信息。,TRUE,,您遇到“Cross account access not allowed”错误可能是因为您在尝试进行跨帐户拷贝时没有启用资源策略(project policy)。您需要为训练好的模型定义IAM资源策略,以允许跨帐户访问。您可以参考这篇博客,了解更多关于项目策略和跨账户拷贝的步骤。 [https://aws.amazon.com/blogs/machine-learning/announcing-the-launch-of-the-model-copy-feature-for-amazon-rekognition-custom-labels/](https://aws.amazon.com/blogs/machine-learning/announcing-the-launch-of-the-model-copy-feature-for-amazon-rekognition-custom-labels/),TRUE,,"根据背景信息,这个错误是因为您尝试进行跨账户复制模型,但没有启用资源策略(项目策略)来允许跨账户访问。 要解决这个问题,您需要以下步骤: 1. 为旧模型定义项目策略(resource-based policy),允许目标账户进行跨账户访问。项目策略可以允许特定账户或者所有账户访问。 2. 在目标账户中,确保拥有复制模型所需的IAM权限。 3. 使用目标账户尝试再次复制模型。现在应该可以成功复制,因为项目策略已经允许了跨账户访问。 4. 如果仍然失败,检查项目策略是否正确,以及目标账户的IAM权限是否足够。 5. 也可以参考AWS博客中的步骤,链接在背景信息中提供。它详细介绍了如何为自定义标签模型启用跨账户访问。 总之,启用项目策略以允许跨账户访问是解决这个错误的关键。请确保策略和IAM权限设置正确。",TRUE,没有给出链接,有可能是因为您尝试进行跨帐户拷贝却没有启用资源策略resource based policy(项目策略project policy)。您需要为训练好的模型定义IAM资源策略,以允许跨帐户访问。这里有一篇博客,介绍了项目策略和跨账户拷贝的步骤。链接为:https://aws.amazon.com/blogs/machine-learning/announcing-the-launch-of-the-model-copy-feature-for-amazon-rekognition-custom-labels/。, -https://repost.aws/questions/QUwLq6HNRZSOK7ODKKc_lC3Q,"亚马逊推出了第一个专门为机器学习构建CI/CD管道的服务,名为Amazon SageMaker Pipelines。 -https://aws.amazon.com/sagemaker/pipelines/ - - -有关更多信息,请参见“Amazon SageMaker Pipelines将DevOps功能引入您的机器学习项目” 。 -https://aws.amazon.com/blogs/aws/amazon-sagemaker-pipelines-brings-devops-to-machine-learning-projects/ - - -此外,我们还有一个客户案例,其中客户使用Airflow为模型开发创建了一个CI/CD服务。有关更多信息,请参阅“NerdWallet使用AWS上的机器学习服务助力推荐系统平台”和“使用Amazon SageMaker构建一个仅有三名工程师的机器学习平台”。 -https://aws.amazon.com/solutions/case-studies/nerdwallet-case-study/ -https://www.nerdwallet.com/blog/engineering/machine-learning-platform-amazon-sagemaker/",AWS客户在机器学习CI/CD方面有哪些成功案例和最佳实践?,AWS客户在机器学习CI/CD方面的成功案例包括: 1. Amazon SageMaker Pipelines:亚马逊推出了第一个专门为机器学习构建CI/CD管道的服务,名为Amazon SageMaker Pipelines。它提供了一种简化机器学习模型适配到持续集成/持续交付(CI/CD)管道的方法。 2. NerdWallet使用AWS上的机器学习服务助力推荐系统平台:NerdWallet使用AWS上的机器学习服务,如Amazon SageMaker和AWS Lambda,成功地实现了推荐系统的平台。 3. 使用Amazon SageMaker构建一个仅有三名工程师的机器学习平台:客户使用Amazon SageMaker构建了一个仅有三名工程师的机器学习平台,成功地实现了模型的开发和部署。 这些案例展示了AWS客户在机器学习CI/CD方面的成功实践,包括使用AWS提供的机器学习服务和工具,以及开发和部署机器学习模型的简化流程。,"[""https://repost.aws/questions/QUwLq6HNRZSOK7ODKKc_lC3Q""]",TRUE,TRUE,,AWS客户在机器学习CI/CD方面的成功案例和最佳实践包括使用Amazon SageMaker Pipelines服务来构建专门的机器学习CI/CD管道。此外,客户还可以参考其他成功案例,如NerdWallet使用Airflow为模型开发创建了一个CI/CD服务。这些案例和最佳实践可以帮助企业和开发者更好地利用AWS资源进行高效的机器学习项目。,TRUE,,AWS客户在机器学习CI/CD方面有一些成功案例和最佳实践,比如使用Amazon SageMaker Pipelines来构建CI/CD管道、使用Airflow为客户创建CI/CD服务等。这些成功案例表明了AWS客户在机器学习CI/CD领域的创新和实践经验。,TRUE,,"根据背景知识,AWS客户在机器学习CI/CD方面主要有以下几个成功案例和最佳实践: 1. 使用Amazon SageMaker Pipelines来构建机器学习的CI/CD管道。SageMaker Pipelines提供了端到端的机器学习工作流程管理,可以轻松地将训练代码连接到评估、部署等其他阶段。 2. NerdWallet使用Airflow在AWS上为机器学习模型开发构建了CI/CD管道。他们只用3名工程师就创建了整个机器学习平台。 3. 充分利用AWS的托管服务,如Amazon S3来存储模型文件和数据,Amazon SageMaker来训练和部署模型,Amazon ECS来运行模型服务等。这可以最大程度地减少运维工作。 4. 使用Git等版本控制工具来管理不同版本的模型和训练代码。将模型注册到Model Registry中进行版本管理。 5. 构建自动的模型测试和监控,在部署前评估模型性能。设定清晰的评估指标。 6. 进行自动化和可重现的训练实验,以便比较不同模型和超参数。 7. 根据业务需求和计算资源情况,选择合适的重新训练和模型部署频率。",TRUE,,"亚马逊推出了第一个专门为机器学习构建CI/CD管道的服务,名为Amazon SageMaker Pipelines。 -https://aws.amazon.com/sagemaker/pipelines/ - - -有关更多信息,请参见“Amazon SageMaker Pipelines将DevOps功能引入您的机器学习项目” 。 -https://aws.amazon.com/blogs/aws/amazon-sagemaker-pipelines-brings-devops-to-machine-learning-projects/ - - -此外,我们还有一个客户案例,其中客户使用Airflow为模型开发创建了一个CI/CD服务。有关更多信息,请参阅“NerdWallet使用AWS上的机器学习服务助力推荐系统平台”和“使用Amazon SageMaker构建一个仅有三名工程师的机器学习平台”。 -https://aws.amazon.com/solutions/case-studies/nerdwallet-case-study/ -https://www.nerdwallet.com/blog/engineering/machine-learning-platform-amazon-sagemaker/", -https://repost.aws/questions/QUq3-yyj5xRD2-MokBhsLkVQ,"完成考试后,您将在测试屏幕上收到通过或未通过的通知。 - - -我们的考试使用标度计分法。您将收到一封电子邮件确认您的考试完成。您的详细考试结果将在完成考试后的五个工作日内在您的AWS认证账户的“以往考试”下面可用。我们的模拟考试使用百分比计分法。完成考试后,您将收到一封电子邮件,其中包含您的详细考试结果。完成考试后的五个工作日内,您的AWS认证账户将记录您的考试结果在“以往考试”下面。",通过了AWS SAP认证,但尚未收到确认邮件或认证平台上的更新,应该采取什么步骤?,"根据给定的知识资源,我的回答是: 完成考试后,您将在测试屏幕上收到通过或未通过的通知。如果您没有收到任何邮件或看到任何更新,建议您检查以下几个方面: 1. 确保您输入的邮箱地址是正确的,并检查垃圾邮件文件夹,因为有时候邮件会被误判为垃圾邮件。 2. 检查您是否在考试当天完成了考试。如果考试未在规定时间内完成,您将收到未完成考试的提示。 3. 检查您的 AWS认证账户,确认是否收到了通过考试的通知,通常会在""以往考试""或""认证结果""页面显示。 如果以上几个方面都没有问题,您还可以联系 AWS 客服,询问您是否通过了考试,并请求他们提供进一步的确认信息。 总的来说,如果过了考试的确认时间还没有收到邮件或更新,建议您仔细检查确认邮件和账户信息,以及与 AWS 官方客服联系,以获取更多帮助。","[""https://repost.aws/questions/QUq3-yyj5xRD2-MokBhsLkVQ""]",TRUE,TRUE,,回答:完成了AWS SAP认证考试后,您将在测试屏幕上收到通过或通过的通知。然后,您将收到一封电子邮件确认您的考试已完成。您的详细考试结果将在完成考试后的五个工作日内在您的AWS认证账户的“以往考试”部分中显示。,TRUE,,您可以通过以下步骤来解决这个问题: 1. 首先,请确保您在参加考试时提供了正确的电子邮件地址和个人信息。这些信息将用于发送考试结果和认证状态更新的通知。 2. 等待一段时间。通常,您将在完成考试后的几个小时内接收电子邮件通知。如果超过了这个时间,您可以尝试重新登录到AWS认证平台,检查您的认证状态是否已更新。 3. 如果您仍然没有收到确认邮件或认证平台的更新,请联系AWS的支持团队。他们可以协助您解决问题并确保您的认证状态得到更新。,TRUE,,"根据背景知识,如果您通过了AWS SAP认证考试,但还没有收到确认邮件或在认证平台上看到更新,您可以采取以下步骤: 1. 等待5个工作日。邮件确认和认证平台上的详细考试结果通常会在考试结束后5个工作日内可见。 2. 检查垃圾邮件文件夹。确认邮件有时会被误标为垃圾邮件。 3. 联系AWS认证支持团队。如果5个工作日后您仍未收到确认,可以联系AWS支持团队寻求帮助。 4. 登录您的AWS认证账户,在“以往考试”部分检查考试结果。考试结果会在那里显示。 5. 如果考试结果在账户中显示为通过,但您仍未收到邮件,可以联系AWS支持团队。他们可以重新发送确认邮件。 主要是保持耐心等待结果更新,并在必要时联系AWS支持团队。确认邮件和认证平台结果有时会有轻微延迟,但如果在5个工作日后仍未更新,应跟进解决。",TRUE,,"完成考试后,您将在测试屏幕上收到通过或未通过的通知。 - - -我们的考试使用标度计分法。您将收到一封电子邮件确认您的考试完成。您的详细考试结果将在完成考试后的五个工作日内在您的AWS认证账户的“以往考试”下面可用。我们的模拟考试使用百分比计分法。完成考试后,您将收到一封电子邮件,其中包含您的详细考试结果。完成考试后的五个工作日内,您的AWS认证账户将记录您的考试结果在“以往考试”下面。", -https://repost.aws/questions/QUE_gygE16QqWU6lDAVitM_g,"你好, - - -由于Lambda Edge是通过Cloudfront托管的,因此您可以确保流量不会离开AWS,并使用lambda@edge和DynamoDB之间的骨干网络。您会发现这个链接很有用,因为它解释了这一点。同样适用于Dynamodb全局表,因为即使流量流向另一个地区,它仍将通过我们的骨干网络进行传输。",我想知道在使用Lambda @ Edge连接到DynamoDB时,流量是否会保留在AWS内部网络,尤其是在跨区域和同一区域使用global table时是否有区别?,使用Lambda @ Edge连接到DynamoDB时,流量是否会保留在AWS内部网络取决于使用情况。在跨区域时,连接离开AWS内部网络,但在同一区域使用global table时,连接将在AWS网络内保持。 因此,如果您正在考虑使用Lambda @ Edge连接到DynamoDB,特别是在同一区域使用global table时,流量将保持在AWS网络内,与跨区域连接相比,流量将更快且更安全。 请注意,以上回答是基于给定的知识资源。如有任何其他疑问,请随时联系AWS解决方案团队以获取更详细和准确的答案。,"[""https://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/bp-global-table-design.prescriptive-guidance.request-routing.html"",""https://repost.aws/questions/QUE_gygE16QqWU6lDAVitM_g""]",TRUE,FALSE,,在使用Lambda@Edge连接DynamoDB时,流量将会保留在AWS内部网络中。这是因为Lambda@Edge是在AWS边缘运行的,而DynamoDB是一个AWS服务。在同一个区域中使用global table时,流量将保持在AWS内部网络中,因为在同一地区内的服务之间通信不需要经过互联网。 然而,在跨区域使用global table时,虽然流量仍然会通过AWS骨干网络进行传输,但是会从AWS内部网络中离开一段时间,因为数据需要在不同的区域之间传输。但当数据返回原始Lambda@Edge函数时,流量会再次回到AWS内部网络。,FALSE,,当使用Lambda@Edge连接到DynamoDB时,流量将保持在AWS内部网络中,无论是在跨区域还是在同一区域使用global table时。Lambda@Edge是通过Cloudfront托管的,因此您可以确保流量不会离开AWS,并且使用lambda@edge和DynamoDB之间的骨干网络。无论您使用的表是global table还是本地表,流量都不会离开AWS内部网络。,TRUE,,"您的理解是正确的。 当Lambda@Edge连接到DynamoDB时,流量会保持在AWS内部网络内。这是因为Lambda@Edge是通过CloudFront托管的,所以请求会通过AWS骨干网络路由,不会离开AWS网络。 对于全局表,情况也是一样的。即使跨区域访问,请求也会通过AWS内部网络路由,不会暴露到公网上。具体来说: - 如果Lambda@Edge和DynamoDB表在同一区域,请求会在该区域内的AWS网络内完成。 - 如果Lambda@Edge和DynamoDB表在不同区域,请求会先路由到DynamoDB表所在的区域,然后再访问该表。中间的流量也不会离开AWS内部网络。 - 对于全局表中的数据复制,也是在AWS内部网络之间进行的。 所以无论是同区域还是跨区域,使用Lambda@Edge访问DynamoDB全局表,流量都会保持在AWS内部网络内,可以获得较低延迟和更高安全性。这是Lambda@Edge和DynamoDB全局表的一个重要优势。",TRUE,,由于Lambda Edge是通过Cloudfront托管的,因此您可以确保流量不会离开AWS,并使用lambda@edge和DynamoDB之间的骨干网络。您会发现这个链接很有用,因为它解释了这一点。同样适用于Dynamodb全局表,因为即使流量流向另一个地区,它仍将通过我们的骨干网络进行传输。, -https://repost.aws/questions/QUsdeGOsyXTeyvu-E9DFmopA,是的,请选择Amazon Aurora 13.6或更高版本(需要Babelfish 1.2.0或更高版本,在Aurora 13.6+中为默认版本)。有关详细信息,请参见[此讨论](https://dba.stackexchange.com/questions/311316/does-aurora-serverless-support-babelfish)。需要Serverless V2。,是否可以在Aurora Serverless中启用Babelfish功能,以支持SQL Server Dialect?,是的,可以在Aurora Serverless中启用Babelfish功能,以支持SQL Server方言。根据给定的知识资源,您需要选择Aurora 13.6或更高版本,并确保Babelfish 1.2.0或更高版本,并且Aurora 13.6+中为默认版本。此外,您还需要使用Serverless V2。有关更多详细信息,请参阅相关的文档和讨论。,"[""https://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/AuroraUserGuide/babelfish.html"",""https://repost.aws/questions/QUsdeGOsyXTeyvu-E9DFmopA""]",TRUE,TRUE,,是的,可以在Aurora Serverless中启用Babelfish功能,以支持SQL Server Dialect。需要Aurora 13.6或更高版本,并且需要Babelfish 1.2.0或更高版本,这是Aurora 13.6+中的默认版本。这将通过提供一个额外的端点来实现,使Aurora PostgreSQL数据库集群能够了解SQL Server线路级协议和常用的SQL Server语句。,TRUE,,是的,可以在Aurora Serverless中启用Babelfish功能,以支持SQL Server Dialect。这需要选择Amazon Aurora 13.6或更高版本,并确保安装了Babelfish 1.2.0或更高版本。这将为Aurora PostgreSQL数据库集群提供一个额外的端点,使它能够在SQL Server客户端连接时使用SQL Server Dialect。,TRUE,,"根据背景知识,可以总结以下关键信息: 1. Babelfish可以为Aurora PostgreSQL数据库提供一个额外的端点,使其能够理解SQL Server方言和语句。 2. Babelfish支持TDS版本7.1到7.4,客户端可以通过TDS协议原生连接到Aurora PostgreSQL。 3. Babelfish需要选择Aurora版本13.6或更高,并使用Serverless V2。 4. 讨论中确认Aurora Serverless确实支持Babelfish。 综上所述,可以在Aurora Serverless中启用Babelfish功能,以支持SQL Server Dialect。只需要选择合适的Aurora版本,并使用Serverless V2,就可以通过TDS端点使用SQL Server客户端原生连接到Aurora PostgreSQL,实现对SQL Server方言的支持。",TRUE,,"根据背景知识,可以总结以下关键信息: 1. Babelfish可以为Aurora PostgreSQL数据库提供一个额外的端点,使其能够理解SQL Server方言和语句。 2. Babelfish支持TDS版本7.1到7.4,客户端可以通过TDS协议原生连接到Aurora PostgreSQL。 3. Babelfish需要选择Aurora版本13.6或更高,并使用Serverless V2。 4. 讨论中确认Aurora Serverless确实支持Babelfish。 综上所述,可以在Aurora Serverless中启用Babelfish功能,以支持SQL Server Dialect。只需要选择合适的Aurora版本,并使用Serverless V2,就可以通过TDS端点使用SQL Server客户端原生连接到Aurora PostgreSQL,实现对SQL Server方言的支持。", -https://repost.aws/questions/QUuCFFG0cDRDuXVGjVTiCvCg,是的,在成本管理服务(Cost Explorer)中,CloudFront费用包括每个地区的数据传出费用(Data Transfer Out)。当您在CE中过滤该服务并使用Groupby选项时,您将能够看到所有在CloudFront下的收费项目。,Cost Explorer中的CloudFront包含哪些费用?,在Cost Explorer中,CloudFront的费用包括每个地区的数据传出费用(Data Transfer Out)。,"[""https://repost.aws/questions/QUuCFFG0cDRDuXVGjVTiCvCg""]",TRUE,TRUE,,Cost Explorer中的CloudFront费用包括每个地区的数据传出费用(Data Transfer Out)。,TRUE,,在Cost Explorer中,CloudFront的费用包括每个地区的数据传出费用 (Data Transfer Out)。当您在CE中过滤该服务并使用Groupby选项时,您将能够看到所有在CloudFront下的收费项目。,TRUE,,"根据背景知识,在Cost Explorer中查看CloudFront的收费情况时,其中包含: - CloudFront服务本身的费用 - 每个地区的数据传出(Data Transfer Out)费用 也就是说,Cost Explorer中的CloudFront收费既包含CloudFront服务的费用,也包含CloudFront的数据传出流量费用。这些费用可以通过在Cost Explorer中过滤CloudFront服务并使用Groupby选项进行查看。",TRUE,,CloudFront 的价格结构较为复杂,以下是一些主要的计费要点:1. 数据传输费用 2. 请求费用 3. 缓存相关费用, -https://repost.aws/questions/QUImID0dYDRR24o4PAEUPvyg,"是可行的,您可以在账户之间迁移弹性IP地址。您只需从源账户中启用EIP迁移,指定需要迁移的EIP以及目标账户ID,并在目标账户中接受迁移即可。 - - -具体可以参考 - - -有一点需要注意,迁移弹性IP地址需要源账户和目标账户在同一区域。",如何将EIP从一个AWS账户迁移到另一个AWS账户?,要将EIP从一个AWS账户迁移到另一个AWS账户,您需要执行以下步骤: 1. 打开AWS控制台并登录到源账户的Route 53控制台。 2. 在导航窗格中选择“Registered domains”(注册域)。 3. 选择要转移到另一个AWS账户的域名,并在“转出”下拉列表中,选择“转移到另一个AWS账户”。 4. 在“转移到另一个AWS账户”对话框中,输入目标AWS账户的ID。 5. 确认并提交请求。 6. 在目标AWS账户的Route 53控制台中,接受来自源账户的EIP转移请求。 7. 在“请求”页面上,选择您要接受EIP转移请求的域名旁边的单选按钮,并从源账户接收转账请求。 8. 在“行动”下拉列表中,选择“接受”。 请注意,这两个账户必须在同一AWS区域中。 以上是将EIP从一个AWS账户迁移到另一个AWS账户的一般步骤。具体操作可能会有所不同,具体取决于您的实际情况和需求。建议在进行任何操作之前,仔细阅读相关的AWS文档和指南,并确保您具有足够的权限来执行所需的操作。,"[""https://repost.aws/questions/QUImID0dYDRR24o4PAEUPvyg"",""https://docs.aws.amazon.com/zh_cn/Route53/latest/DeveloperGuide/domain-transfer-between-aws-accounts.html""]",TRUE,FALSE,是转移EIP,不是转移域名,回答:将弹性IP地址从一个AWS账户迁移到另一个AWS账户的过程包括以下几个步骤: 1. 从源账户中启用EIP迁移,指定需要迁移的EIP以及目标账户ID。 2. 在目标账户中接受迁移。 需要注意的是,迁移弹性IP地址需要源账户和目标账户在同一区域。在进行迁移操作之前,确保源账户和目标账户具有适当的权限和访问控制。,TRUE,,您可以将EIP从一个AWS账户迁移到另一个AWS账户。具体操作如下: 1. 从源账户中启用EIP迁移。 2. 指定需要迁移的EIP以及目标账户ID。 3. 在目标账户中接受迁移。 您可以通过AWS EC2控制台或AWS CLI来完成这个过程。具体流程可以参考官方文档 。,TRUE,,"根据背景知识,要将EIP从一个AWS账户迁移到另一个AWS账户,可以按以下步骤操作: 1. 在源AWS账户中,启用EIP迁移,指定要迁移的EIP和目标AWS账户ID。具体方法请参考文档:https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html#using-instance-addressing-eips-transfer-enable-ec2 2. 在目标AWS账户中,接受EIP迁移请求。 3. 等待迁移完成。 4. 注意两点: - 源账户和目标账户必须在同一区域 - 迁移EIP不会迁移与该EIP关联的资源(如EC2实例),需要在迁移后重新关联 5. 如果需要迁移 Route 53 域名的托管区域,可以在域名迁移完成后,再按照背景知识中的步骤2进行迁移。 总结来说,迁移EIP的关键是在源账户中启用迁移,在目标账户中接受迁移请求,同时确保两账户在同一区域。迁移完成后可根据需要迁移托管区域。",TRUE,回答似乎将route 53 domain transfer和 EIP跨账户迁移融合了,"您可以在账户之间迁移弹性IP地址。您只需从源账户中启用EIP迁移,指定需要迁移的EIP以及目标账户ID,并在目标账户中接受迁移即可。 - - -具体可以参考 - - -有一点需要注意,迁移弹性IP地址需要源账户和目标账户在同一区域。", -,参考教程 https://aws.amazon.com/getting-started/hands-on/create-connect-postgresql-db/?nc1=h_ls jdbc driver有pg官方的https://jdbc.postgresql.org/download.html,能不能通过JDBC连接到RDS for PostgreSQL? 请给出参考文档。,Groundtruth是个标注工具,需要人工用这个工具来标注。从工具角度上面讲,可以对任何语言支持,但是从人工来标注这个事情上面讲,不一定有各种语言的支持。如果客户有人工来标注,只是需要个工具来提供页面,流程管理,Groundtruth是可以的。如果需要Groundtruth来提供人工标注,不一定行。Groundtruth的plus版本,相当于是个众包服务,可以提供这种中文标注的支持。Plus是按project的方式走,单独签合同标签可以支持中文。另外,中国区现在没有开放 Ground truth 的功能。 Groudtruth的输出在s3,可以下载。 Groundtruth的输出就是一个S3当中的manifest JSON Lines文件,可以下载下来进行训练的输入。,"[""dgr-oncall""]",FALSE,FALSE,,,,,,,,,,,参考教程 https://aws.amazon.com/getting-started/hands-on/create-connect-postgresql-db/?nc1=h_ls jdbc driver有pg官方的https://jdbc.postgresql.org/download.html, -,RDS/Aurora没有原生的分库分表功能或工具,需要使用开源组件,如shardingsphere,这里有一篇blog介绍方案 另外客户的表有多大?,我想解决RDS MySQL中表过大的问题,请问AWS有没有分库分表中间件或服务?,在AWS上,可以使用Amazon RDS的自动分库功能,但是需要自己编写应用程序来处理分库后的数据。另外,也可以使用分表技术,例如使用Amazon DynamoDB的分区键和全局二级索引来处理大型数据表。,[],FALSE,FALSE,,,,,,,,,,,RDS/Aurora没有原生的分库分表功能或工具,需要使用开源组件,如shardingsphere,这里有一篇blog介绍方案 另外客户的表有多大?, -,可以将audit log发送至cloudwatch查看,具体操作详见链接,如何获取RDS MySQL数据库上的所有执行SQL?,要获取RDS MySQL数据库上所有正在执行的SQL,您可以执行以下步骤: 1. 使用MySQL客户端连接到您的RDS MySQL数据库实例。 2. 运行以下命令来获取当前数据库中的所有正在执行的SQL语句: ``` SHOW FULL PROCESSLIST; ``` 这将返回一个包含所有正在执行的SQL语句的列表。 请注意,这些命令是通用的,可用于任何RDS MySQL数据库实例,只要您具有适当的权限来执行这些命令。如果您无法执行这些命令,请联系AWS解决方案团队以获取更多帮助。,"[""https://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/UserGuide/USER_MySQL.Replication.html""]",FALSE,FALSE,,要获取在RDS MySQL数据库上所有执行的SQL,您需要配置并监控复制过程。这可以通过基于行的复制、基于语句的复制或混合复制来实现。然后,您可以使用复制日志来查看所有执行的SQL。具体步骤可能包括配置二进制日志格式、启用复制以及访问和解析复制日志。,FALSE,,要获取RDS MySQL数据库上所有执行的SQL,可以使用AWS CloudTrail服务来跟踪和记录所有的操作,包括对RDS MySQL数据库的所有SQL查询。具体步骤如下: 1. 启用CloudTrail:登录AWS控制台,转到CloudTrail服务页面,然后单击“启用CloudTrail”按钮。 2. 创建跟踪设置:在CloudTrail控制台上选择要追踪的资源(例如RDS MySQL数据库),并创建一个跟踪设置。 3. 启动跟踪:根据需要启用或禁用跟踪,并指定跟踪级别。 4. 查看日志:通过访问CloudTrail控制台的日志视图,可以查看RDS MySQL数据库上的所有SQL查询。 请注意,启用CloudTrail可能会产生一些费用,具体取决于您的使用情况。,FALSE,,"您可以通过以下几种方式获取 Amazon RDS for MySQL 数据库实例上执行的所有 SQL 语句: 1. 使用慢查询日志 RDS for MySQL 支持慢查询日志,可以记录执行时间超过指定阈值的所有查询。您可以通过参数组来配置慢查询日志,包括设置阈值、是否记录 SQL 语句等。 2. 使用通用查询日志 通用查询日志可以记录 MySQL 实例上执行的所有语句。您需要在参数组中启用该日志,并指定日志输出位置。 3. 使用二进制日志 MySQL 的二进制日志记录了所有对数据库进行修改的语句。对于 RDS for MySQL,默认情况下二进制日志是启用的。您可以通过读取二进制日志文件来获取所有执行过的 SQL。 4. 使用 MySQL Performance Schema Performance Schema 中的 events_statements_* 表可以记录执行过的 SQL 语句。您需要先启用该功能,然后可以查询这些表来获取 SQL 记录。 5. 使用第三方工具 一些第三方工具如 Percona Toolkit 中的 pt-query-digest 可以分析 MySQL 的日志并输出执行过的 SQL 语句。 综上,通过启用并查询各种 MySQL 日志,或使用第三方工具,都可以获取在 RDS for MySQL 上执行过的 SQL 语句。需要根据实际需求选择合适的方法。",TRUE,,"您可以通过以下几种方式获取 Amazon RDS for MySQL 数据库实例上执行的所有 SQL 语句: 1. 使用慢查询日志 RDS for MySQL 支持慢查询日志,可以记录执行时间超过指定阈值的所有查询。您可以通过参数组来配置慢查询日志,包括设置阈值、是否记录 SQL 语句等。 2. 使用通用查询日志 通用查询日志可以记录 MySQL 实例上执行的所有语句。您需要在参数组中启用该日志,并指定日志输出位置。 3. 使用二进制日志 MySQL 的二进制日志记录了所有对数据库进行修改的语句。对于 RDS for MySQL,默认情况下二进制日志是启用的。您可以通过读取二进制日志文件来获取所有执行过的 SQL。 4. 使用 MySQL Performance Schema Performance Schema 中的 events_statements_* 表可以记录执行过的 SQL 语句。您需要先启用该功能,然后可以查询这些表来获取 SQL 记录。 5. 使用第三方工具 一些第三方工具如 Percona Toolkit 中的 pt-query-digest 可以分析 MySQL 的日志并输出执行过的 SQL 语句。 综上,通过启用并查询各种 MySQL 日志,或使用第三方工具,都可以获取在 RDS for MySQL 上执行过的 SQL 语句。需要根据实际需求选择合适的方法。", -,"Amazon ElastiCache for Redis有rdb的持久保证,备份文件就是rdb文件,没有aof的支持。Amazon MemoryDB for Redis有更强的持久性保证,每条写入的数据都有持久性的保证,而且这个持久性是跨多个可用区的。可以认为MemoryDB是""增强版""的AOF。 -elasticache for redis只有2.8之前的版本支持aof,https://docs.aws.amazon.com/zh_cn/AmazonElastiCache/latest/red-ug/RedisAOF.html ,现在还在用老版本的客户估计不多,elasticache的高可用和持久性靠多可用+副本的方式实现。",亚马逊的ElastiCache for Redis是否支持AOF备份?,亚马逊的ElastiCache for Redis支持AOF备份。,"[""https://docs.aws.amazon.com/zh_cn/AmazonElastiCache/latest/red-ug/RedisAOF.html"",""https://docs.aws.amazon.com/zh_cn/AmazonElastiCache/latest/red-ug/BestPractices.AOF.html""]",TRUE,TRUE,,是的,亚马逊的ElastiCache for Redis支持AOF备份。但是,需要注意的是,AOF不能防范所有故障情况。例如,如果节点由于底层物理服务器中的硬件故障而出现故障,那么ElastiCache会在另一服务器上预置新节点,这种情况下AOF文件不再可用,无法用于恢复数据。因此,Redis会使用冷缓存重新启动。为了提高可靠性和更快的恢复,建议在不同可用区中为复制组创建一个或多个只读副本,并启用多可用区而不使用AOF。,TRUE,,是的,ElastiCache for Redis支持AOF备份。通过启用AOF功能,ElastiCache会为Redis节点创建一个仅附加文件,其中记录了所有的缓存数据变化。当节点重启或出现故障时,ElastiCache会通过重放这些记录来恢复数据。这对于保护数据免受节点重启和故障导致的丢失非常重要。此外,如果需要更高的可靠性,可以考虑使用Amazon ElastiCache复制组,该复制组可以在多个可用区域之间自动故障转移,并提供更高的可用性和快速恢复的能力。,TRUE,,"根据背景知识,ElastiCache for Redis 支持启用 AOF(仅附加文件)来实现数据持久性。但是 AOF 也存在一些限制: 1. cache.t1.micro 和 cache.t2.* 节点不支持 AOF。 2. 对于多可用区复制组,AOF 被禁用。 3. Redis 2.8.22及更高版本不再支持 AOF。 4. AOF 不能防范所有故障情况,在节点硬件故障时无法恢复数据。 所以简单来说,ElastiCache for Redis 确实支持通过 AOF 实现数据备份和恢复。但考虑到 AOF 的限制,为了更高可靠性和更快速的故障恢复,官方更推荐使用启用了多可用区的 Redis 复制组来实现高可用性,而不是依赖 AOF。 综上所述,ElastiCache for Redis 支持但不推荐使用 AOF 备份数据,启用多可用区的复制组是更可靠和高效的选择。",TRUE,该回答最好,"根据背景知识,ElastiCache for Redis 支持启用 AOF(仅附加文件)来实现数据持久性。但是 AOF 也存在一些限制: 1. cache.t1.micro 和 cache.t2.* 节点不支持 AOF。 2. 对于多可用区复制组,AOF 被禁用。 3. Redis 2.8.22及更高版本不再支持 AOF。 4. AOF 不能防范所有故障情况,在节点硬件故障时无法恢复数据。 所以简单来说,ElastiCache for Redis 确实支持通过 AOF 实现数据备份和恢复。但考虑到 AOF 的限制,为了更高可靠性和更快速的故障恢复,官方更推荐使用启用了多可用区的 Redis 复制组来实现高可用性,而不是依赖 AOF。 综上所述,ElastiCache for Redis 支持但不推荐使用 AOF 备份数据,启用多可用区的复制组是更可靠和高效的选择。", -,"不支持。 -PostgreSQL创建用户自定义C函数,需要在数据库服务器上先编译文件,然后再在数据库中执行create function来注册函数,RDS无法访问操作系统,也未提供入口进行上传操作。",AWS海外区域中的RDS for PostgreSQL是否支持执行C语言函数?,AWS海外区域中的RDS for PostgreSQL支持执行C语言函数。您可以在AWS文档中找到更多关于如何在RDS for PostgreSQL中执行C语言函数的详细信息。,[],FALSE,FALSE,,,,,,,,,,,"不支持。 -PostgreSQL创建用户自定义C函数,需要在数据库服务器上先编译文件,然后再在数据库中执行create function来注册函数,RDS无法访问操作系统,也未提供入口进行上传操作。", -,Lex目前确实不支持中文且未在中国区落地,可以看下我们合作伙伴的方案: , 其他partner见 ,中国区域目前没有Amazon Lex,可以介绍一些替代方案吗?,当然可以。以下是一些中国区域替代Amazon Lex的解决方案: 1. 百度智能助手:百度智能助手是中国最大的智能语音助手,支持语音识别、语音合成、语音交互等功能。 2. 阿里巴巴智能客服:阿里巴巴智能客服是中国最大的电商企业,提供了智能客服系统,支持语音识别、语音合成、语音交互等功能。 3. 腾讯智能客服:腾讯智能客服是中国最大的社交媒体企业,提供了智能客服系统,支持语音识别、语音合成、语音交互等功能。 4. 谷歌智能助手:谷歌智能助手是美国最大的智能语音助手,支持语音识别、语音合成、语音交互等功能。 5. 微软小冰:微软小冰是中国最大的聊天机器人平台,支持语音识别、语音合成、语音交互等功能。 以上是一些中国区域替代Amazon Lex的解决方案,可以根据具体需求选择适合的方案。,[],FALSE,TRUE,,,,,,,,,,,Lex目前确实不支持中文且未在中国区落地,可以看下我们合作伙伴的方案: , 其他partner见 , -,Transcribe可以做实时翻译,详见 因为translate和transcribe都支持实时api,可以把两者组合起来使用,实现客户的功能,Amazon Transcribe是否支持实时语音转文本,尤其是能否将韩语语音实时转成汉语文本?,根据给定的知识资源,Amazon Transcribe支持实时语音转文本,包括将韩语语音实时转成汉语文本。,"[""https://docs.aws.amazon.com/zh_cn/transcribe/latest/dg/supported-languages.html"",""https://docs.aws.amazon.com/zh_cn/transcribe/latest/dg/what-is.html""]",TRUE,FALSE,,是的,Amazon Transcribe支持实时语音转文本。您可以创建一个实时转录工作流,将音频流转换为文本。以下是一些关于如何使用Amazon Transcribe进行实时语音转文本的详细步骤: 1. 首先,确保您的音频源可以实时访问。这可能是一个网络摄像头、电话或实时流媒体。 2. 使用Amazon Transcribe创建一个新的实时转录任务。这需要在Amazon Transcribe控制台中创建一个新的项目,并配置流式处理设置。 3. 选择一个音频流并将它添加到实时转录任务中。这将启动音频流的实时转录。 4. 实时转录将在Amazon Transcribe上运行,并将转录文本发送到指定的S3存储桶。 5. 您可以使用Amazon Transcribe控制台或API来查看和管理实时转录任务。 对于韩语到汉语文本的实时转录,您需要确保Amazon Transcribe能够理解和识别韩语。这可能需要在创建实时转录任务时指定正确的语言模型和词汇表。如果您使用的是预构建的词汇表,请确保它包含足够的韩语词汇。此外,您还可以使用自定义语言模型来优化韩语的识别准确性。,FALSE,,是的,Amazon Transcribe可以支持实时语音转文本。对于实时转录,Amazon Transcribe可以将音频转换为可读的文本文件或流。这意味着您可以实时地将语音转换为文字,而无需等待整个音频文件的转录完成。 此外,对于韩语转汉语文本的实时转录,Amazon Transribe也提供支持。您可以使用Amazon Transcribe的实时转录功能,将韩语语音实时转换为汉语文本。,FALSE,,"根据Amazon Transcribe的语言支持列表,目前还不支持将韩语语音实时转录成汉语文本。 Amazon Transcribe支持以下实时语音转文本的语言: - 英语(美国、英国、澳大利亚等多种方言) - 德语 - 法语 - 日语 - 西班牙语(美国方言) - 葡萄牙语(巴西方言) 对于韩语,Amazon Transcribe 只支持批量转录(即转录预先录制的音频文件),还不支持实时流式语音转文本。 所以如果需要将韩语实时语音转成汉语文本,目前Amazon Transcribe还无法满足。你需要考虑使用其他的语音转文本服务,并结合机器翻译技术,先将韩语转录文本翻译成汉语。这需要自己对不同的语音和翻译服务进行集成。 总之,Amazon Transcribe目前尚不支持您提出的从韩语语音实时转录成汉语文本的需求。如果亟需此功能,你可以向Amazon Transcribe团队提交功能需求,希望他们未来能支持更多语言之间的实时语音转文本。",FALSE,,Amazon Transcribe支持实时语音转文本,但不支持将韩语语音实时转成汉语文本,需要配合Translate等服务实现。, -,"可以参考这个demo的实现方式通过IVS和aws transcribe生成直播流字幕:,还有看看这个github库是否有用: -",AWS是否提供适用于直播流视频内容的自动生成字幕的解决方案?,是的,AWS提供了适用于直播流视频内容的自动生成字幕的解决方案。您可以使用Amazon Transcribe服务来自动生成字幕,并将其集成到Amazon CloudFront中,以提供实时字幕。您可以使用AWS Elemental MediaLive服务将直播流视频内容转发到Amazon CloudFront,并将其与Amazon Transcribe集成,以自动生成字幕。此外,您还可以使用Amazon Polly服务将字幕转换为多种语言,并将其保存到Amazon S3中,以便在需要时进行播放。,[],FALSE,FALSE,,,,,,,,,,,"可以参考这个demo的实现方式通过IVS和aws transcribe生成直播流字幕:,还有看看这个github库是否有用: -", -,"支持提前生成好语音包,离线使用。Polly可以将相对固定的文字合成为MP3供离线使用。 -根据目前看Polly没有离线的动态生成功能。 -建议在离线时如果需要使用TTS可以降级为其他离线的TTS实现如OpenTTS。",Polly是否支持离线语音合成,而不依赖云服务,以适应网络不佳的导航场景?,是的,根据提供的知识资源,Polly支持离线语音合成,而不依赖云服务。这意味着在网络不佳的导航场景下,用户可以仍然使用Polly进行语音合成,以提高用户体验。,"[""https://docs.aws.amazon.com/zh_cn/polly/latest/dg/what-is.html""]",,,,是的,Amazon Polly 支持离线语音合成。通过缓存和重播 Amazon Polly 生成的语音,您可以在网络不佳的场景中使用离线语音合成,而无需支付额外费用。这使得在诸如导航等应用中能够提供高质量的语音输出,即使在网络连接不稳定的情况下也能正常工作。,FALSE,,Amazon Polly 不支持离线语音合成,它依赖于云服务进行语音合成。然而,Amazon Polly 的语音合成可以在网络不稳定的情况下进行缓存,以便在下一次请求时提供更快的响应速度。这意味着,即使在网络不佳的情况下,您的应用程序仍然可以获得高质量的语音合成结果。,TRUE,,"不,Amazon Polly 不支持离线语音合成。它是一个完全基于云的语音合成服务,需要连接到Amazon服务器来合成语音。 对于网络条件差的场景,您可以考虑使用Amazon Polly生成语音并缓存音频文件,然后在离线状态下播放这些预生成的音频文件。 具体来说,可以这样做: 1. 当有网络连接时,使用Amazon Polly API发送文本并获取生成的音频文件。 2. 将这些音频文件存储在设备上,例如下载到智能手机或汽车导航系统中的存储卡上。 3. 在网络不可用时,播放预生成的音频文件,为用户提供语音交互和导航提示。 4. 当网络条件允许时,可以清除旧的缓存并使用Amazon Polly生成新的音频文件。 这种方式可以充分利用Amazon Polly生成高质量的语音,同时适应网络条件差的场景。只要预先规划和缓存必要的音频片段,就可以为用户提供流畅的语音体验。",TRUE,,"Amazon Polly 不支持离线语音合成,但支持提前生成好语音包,离线使用。Polly可以将相对固定的文字合成为MP3供离线使用。 -根据目前看Polly没有离线的动态生成功能。 -建议在离线时如果需要使用TTS可以降级为其他离线的TTS实现如OpenTTS。", -,参考示例请见(),可以使用AWS SDK()或(),国内外的Amazon Transcribe是否都提供安卓接口供调用?,Groundtruth是个标注工具,需要人工用这个工具来标注。从工具角度上面讲,可以对任何语言支持,但是从人工来标注这个事情上面讲,不一定有各种语言的支持。如果客户有人工来标注,只是需要个工具来提供页面,流程管理,Groundtruth是可以的。如果需要Groundtruth来提供人工标注,不一定行。Groundtruth的plus版本,相当于是个众包服务,可以提供这种中文标注的支持。Plus是按project的方式走,单独签合同标签可以支持中文。另外,中国区现在没有开放 Ground truth 的功能。 Groudtruth的输出在s3,可以下载。 Groundtruth的输出就是一个S3当中的manifest JSON Lines文件,可以下载下来进行训练的输入。,"[""dgr-oncall""]",FALSE,FALSE,,,,,,,,,,,参考示例请见(),可以使用AWS SDK()或(), -,"有2个方法, -1. 通过VPC Flow log https://docs.aws.amazon.com/zh_cn/vpc/latest/userguide/flow-logs.html, 加上Athena进行过滤https://docs.aws.amazon.com/athena/latest/ug/vpc-flow-logs.html -2. 可以在EC2 的ENI上发布流量日志到CloudWatch Log https://docs.aws.amazon.com/zh_cn/vpc/latest/userguide/flow-logs-cwl.html ,利用CloudWatch Log Insight进行汇聚https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/AnalyzingLogData.html",如何查看AWS Lightsail单个实例的流量使用情况?,您可以使用AWS CloudWatch来监视AWS Lightsail实例的流量使用情况。以下是一些步骤: 1. 登录AWS控制台并导航到CloudWatch控制台。 2. 在CloudWatch控制台中,选择“Metrics”选项卡。 3. 在“Metrics”选项卡中,选择“EC2”作为服务名称,然后选择“Per-Instance Metrics”。 4. 在“Per-Instance Metrics”页面上,选择“NetworkIn”和“NetworkOut”指标。 5. 您可以选择要监视的特定实例,并设置时间范围。 6. 您还可以创建警报,以便在达到特定阈值时接收通知。 通过这些步骤,您可以查看AWS Lightsail实例的流量使用情况,并采取必要的措施来优化您的实例。,[],FALSE,FALSE,,,,,,,,,,,"有2个方法, -1. 通过VPC Flow log https://docs.aws.amazon.com/zh_cn/vpc/latest/userguide/flow-logs.html, 加上Athena进行过滤https://docs.aws.amazon.com/athena/latest/ug/vpc-flow-logs.html -2. 可以在EC2 的ENI上发布流量日志到CloudWatch Log https://docs.aws.amazon.com/zh_cn/vpc/latest/userguide/flow-logs-cwl.html ,利用CloudWatch Log Insight进行汇聚https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/AnalyzingLogData.html", -,访问慢和买ri没有关系,机器还是原来的机器。所以第一客户需要确认慢是机器慢还是网络慢,机器慢看cpu、内存和网络io是否过高、t系列的积分是否充足,第二排查是否网络慢比如使用站长之家类似的网站从全国多地ping服务器看延迟是否异常,考虑使用cdn加速网站,切换到RI预付款方案后,网站访问速度变慢,如何排查?,切换到RI预付款方案后,网站访问速度变慢可能是由于以下原因: 1. 网络带宽不足:如果您的网站流量增加,但网络带宽没有相应增加,会导致网站访问速度变慢。您可以联系您的网络服务提供商,增加带宽或升级套餐。 2. 服务器性能问题:如果您的服务器性能不足,也会导致网站访问速度变慢。您可以联系您的服务器提供商,升级服务器或更换服务器。 3. 网站代码问题:如果您的网站代码存在问题,也会导致网站访问速度变慢。您可以检查您的网站代码,修复问题。 4. 网站安全问题:如果您的网站存在安全漏洞,也会导致网站访问速度变慢。您可以检查您的网站安全,修复漏洞。 建议您逐一排查以上问题,找出导致网站访问速度变慢的原因,并采取相应的措施进行解决。,[],FALSE,TRUE,,,,,,,,,,,访问慢和买ri没有关系,机器还是原来的机器。所以第一客户需要确认慢是机器慢还是网络慢,机器慢看cpu、内存和网络io是否过高、t系列的积分是否充足,第二排查是否网络慢比如使用站长之家类似的网站从全国多地ping服务器看延迟是否异常,考虑使用cdn加速网站, -,"https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/ec2-instance-resize.html#migrate-instance-configuration -因为要停止-启动,公网ip会变,所以没有太好的办法,和客户说明一下需要绑定弹性IP",我想要升级EC2配置,如何让实例IP在升级前后保持不变?,要升级EC2配置并保持实例IP不变,您可以执行以下步骤: 1. 登录到AWS管理控制台,并转到EC2仪表板。 2. 选择要升级的EC2实例。 3. 单击“操作”按钮,然后选择“实例设置”>“更改安全组”。 4. 在“更改安全组”对话框中,保留当前安全组中的IP地址不变。 5. 单击“保存”。 这样,在升级实例的配置后,实例的IP地址将保持不变。请注意,这仅适用于EC2实例的配置,而不影响其他网络设置和IP地址。如果您需要更改其他网络设置,请参考相关文档或联系AWS解决方案团队以获取帮助。,"[""https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/WindowsGuide/serverupgrade.html"",""https://repost.aws/questions/QUeAvkTPqKTme5vHHpoXitcg""]",FALSE,FALSE,,为了在升级EC2配置的过程中保持实例IP地址不变,您可以采用以下步骤: 1. 首先,确保在升级过程中使用的实例类型具有相同的网段。这样,在升级完成后,您可以将原有的IP地址重新分配给新的实例。 2. 在执行升级操作时,请确保使用快照或其他备份工具备份所有重要数据。这样,在升级过程中出现的任何问题都可以通过恢复快照来解决。 3. 在执行升级操作时,尽量选择在业务低峰期进行。这样可以避免在升级过程中出现的问题影响到用户的正常使用。 4. 在升级过程中,密切关注系统的运行状况。如果出现任何异常,立即采取相应的措施进行处理。 5. 升级完成后,检查系统是否正常运行。如果一切正常,将原有的IP地址重新分配给新的实例。 总之,在升级EC2配置的过程中,保持实例IP地址不变需要在升级前做好充分的准备,并在升级过程中密切关注系统的运行状况。只要妥善应对可能出现的问题,就可以确保升级过程顺利进行。,FALSE,,要在升级EC2配置时保持实例IP地址不变,您可以采取以下步骤: 1. 首先,确保您使用的是支持IP地址保留的EC2实例类型。例如,Amazon EC2 Instance Store、EBS-backed instances等类型支持IP地址保留。 2. 如果您使用的是支持IP地址保留的实例类型,请确保在升级之前启用IP地址保留功能。您可以在EC2实例的“网络”选项卡中找到并启用此功能。 3. 接下来,您需要在升级过程中保留IP地址。为此,请在升级之前创建一个备份映像(AMI),其中包含所需的EC2配置和IP地址信息。 4. 在创建备份映像之后,使用该映像创建一个新的EC2实例。这将确保升级后的实例具有相同的IP地址。 5. 最后,您可以使用新的EC2实例来替换旧实例,并在升级完成后删除旧的实例。这样,您就可以保持实例IP地址不变了。,FALSE,,"您可以通过以下步骤来保持EC2实例在升级配置时的IP地址不变: 1. 停止要升级配置的EC2实例。 2. 注意实例当前绑定的私有IP地址和公有IP地址。 3. 启动一个新的具有所需配置的EC2实例。 4. 停止新启动的实例。 5. 回到旧实例,解绑它的私有IP地址和公有IP地址。 6. 为新实例分配旧实例的私有IP地址和公有IP地址。 7. 启动新实例,它将保留旧实例的IP地址。 8. 终止旧实例。 9. 验证新实例是否使用了旧实例的IP地址。 这样,新实例就可以保留旧实例的IP地址,实现无缝升级实例配置的目的。整个过程中对外服务的影响可以降到最低。需要注意的是在步骤5解绑IP后要尽快在新实例上绑定,避免IP被分配给其他实例。",FALSE,,绑定弹性IP, -,EC2 nitro有enclave提供TEE,该blog介绍的非常详细可参考实践https://aws.amazon.com/cn/blogs/china/build-a-secure-and-trusted-execution-environment-based-on-nitro-enclave/,AWS有支持Intel可信计算技术Software Guard Extensions (SGX) 功能的EC2实例吗?,根据给定的知识资源,AWS支持Intel可信计算技术Software Guard Extensions (SGX)功能的EC2实例。,"[""https://docs.aws.amazon.com/zh_cn/datapipeline/latest/DeveloperGuide/dp-ec2-supported-instance-types.html"",""https://docs.aws.amazon.com/zh_cn/directoryservice/latest/admin-guide/ms_ad_join_instance.html""]",FALSE,FALSE,,根据提供的文章,我们无法确定AWS是否支持带有Intel可信计算技术Software Guard Extensions (SGX) 的EC2实例。文章中仅列出了AWS Data Pipeline支持的Amazon EC2实例类型,但没有明确提及SGX支持。为了确认这一点,建议查阅AWS官方文档或相关产品说明。,TRUE,,AWS目前还不支持Intel可信计算技术Software Guard Extensions (SGX) 功能的EC2实例。,TRUE,,"是的,AWS确实支持SGX功能的EC2实例。 AWS提供了以下几种支持SGX的实例类型: - C5n实例 - 这是AWS的计算优化型SGX实例,提供了强大的计算性能。C5n实例包括c5n.large, c5n.xlarge, c5n.2xlarge, c5n.4xlarge, c5n.9xlarge, c5n.18xlarge等。 - M5n实例 - 这是AWS的内存优化型SGX实例,提供了大量的内存来支持SGX应用程序。M5n实例包括m5n.large, m5n.xlarge, m5n.2xlarge, m5n.4xlarge, m5n.8xlarge, m5n.12xlarge, m5n.16xlarge, m5n.24xlarge等。 - R5n实例 - 这是AWS的内存优化型SGX实例,比M5n提供更大的内存。R5n实例包括r5n.large, r5n.xlarge, r5n.2xlarge, r5n.4xlarge, r5n.8xlarge, r5n.12xlarge, r5n.16xlarge, r5n.24xlarge等。 - D3n实例 - 这是AWS的存储优化型SGX实例,提供了高性能本地NVMe SSD存储。D3n实例包括d3n.xlarge, d3n.2xlarge, d3n.4xlarge, d3n.8xlarge等。 所以在AWS上部署SGX应用程序时,可以根据需要选择合适的SGX实例类型。这为基于可信计算的应用提供了强大的支持。",FALSE,,AWS目前还不支持Intel可信计算技术Software Guard Extensions (SGX) 功能的EC2实例。不过EC2 nitro有enclave可提供TEE。, -,实例状态检查是向网络接口NIC发送ARP请求,验证操作系统是否在接受流量。失败原因可参考https://aws.amazon.com/cn/premiumsupport/knowledge-center/system-reachability-check/,EC2实例可达性检查失败,如何排查?,当EC2实例可达性检查失败时,可以尝试以下步骤进行排查: 1. 检查实例状态:首先,检查实例的运行状态是否正常。可以通过AWS控制台或使用describe-instances命令来查看实例的状态。如果实例状态为“停止”,尝试启动实例并再次进行可达性检查。 2. 检查网络配置:确保实例的网络配置正确。检查安全组、网络接口和路由表等网络组件是否正确设置。可以使用describe-security-groups和describe-network-interfaces等命令来查看和修改网络配置。 3. 检查实例类型:确保您选择的实例类型与您的需求和要求相匹配。可以通过describe-instance-type-offerings命令查找可用的实例类型,并确保您选择的实例类型在您请求的可用区和区域中可用。 4. 检查可用区:确认您的实例所在的可用区是否与您的需求和要求相符。可以使用describe-instances命令或查看实例的可用区网络窗格来确认。 5. 检查密钥对:如果您的EC2实例需要使用密钥对进行身份验证,确保您已经创建了与实例相关联的密钥对。可以使用describe-key-pairs命令获取可用的密钥对列表,并创建新的密钥对。 6. 检查启动模板和启动配置:检查您的启动模板或启动配置是否正确。确保它们包含正确的实例类型、网络配置和安全组等信息。 7. 检查自动缩放组:如果您的实例是作为自动缩放组的一部分进行管理的,检查自动缩放组的配置是否正确。确保自动缩放组中指定的实例类型和可用区与您的需求和要求相符。 如果以上步骤都没有解决问题,建议联系AWS解决方案团队以获取进一步的支持和帮助。,"[""https://docs.aws.amazon.com/zh_cn/autoscaling/ec2/userguide/ts-as-instancelaunchfailure.html"",""https://repost.aws/questions/QUzQqNFnwaQleHX5zVpSRcmQ""]",TRUE,FALSE,有用的信息不多,https://repost.aws/zh-Hans/knowledge-center/ec2-linux-status-check-failure,当您收到关于EC2实例可达性检查失败的错误消息时,可以通过以下步骤进行排查: 1. **检查网络安全组**:首先,检查您的VPC或子网的网络安全组是否允许其他VPC或子网的EC2实例与之通信。如果需要,您可以更新网络安全组规则以允许通信。 2. **检查NACLs(网络访问控制列表)**:如果您使用的是VPC,还需要检查VPC的NACLs是否允许其他VPC的EC2实例与之通信。如果需要,您可以更新NACLs规则以允许通信。 3. **检查安全组**:如果您的EC2实例与其他EC2实例在同一个子网中,但是仍然无法达到目标,那么可能需要检查安全组设置。确保目标EC2实例的安全组允许源EC2实例的IP地址范围与其通信。 4. **检查VPC路由表**:如果您的EC2实例与其他VPC中的EC2实例通信,那么需要检查VPC的路由表设置。确保正确的路由表被配置以便数据包能够正确路由到目标VPC。 5. **检查实例状态**:确保目标EC2实例正在运行并且没有被暂停或者处于未加载状态。 6. **检查网络安全组或NACLs的入站规则**:如果您的EC2实例正在尝试从一个没有入站规则的网络安全组或NACLs中访问资源,那么它将无法成功。确保网络安全组或NACLs有适当的入站规则。 7. **检查EC2实例的网络配置**:确保EC2实例的网络配置正确配置,例如正确的子网和路由表设置。 8. **检查VPC的默认路由**:如果您的VPC使用了隔离的子网,那么需要确保VPC的默认路由被正确配置以便EC2实例能够访问互联网。 经过以上步骤的排查,应该能找到导致EC2实例可达性检查失败的原因并采取相应的措施进行修复。,FALSE,只给出了VPC组件的排查,不够全,https://repost.aws/zh-Hans/knowledge-center/ec2-linux-status-check-failure,EC2 实例可达性检查失败的常见原因是网络连接问题或安全问题。以下是一些排查方法: 1. 检查网络连接:确保您的实例与云服务器网络连接正常。您可以尝试使用ping命令或其他网络工具测试实例的网络连接。 2. 检查安全组规则:确保您的实例的安全组规则允许传入流量。如果您看到任何阻止传入流量的规则,请将其删除。 3. 检查实例配置:确保您的实例的配置正确。例如,您可能需要确保实例的 IP 地址已分配,并且实例正在与正确的网络连接。 4. 检查日志文件:检查您的实例的日志文件,以查找有关网络连接或安全性问题的详细信息。这些日志文件通常位于 /var/log/ 目录下。 5. 检查网络流量:使用流量监控工具,如AWS CloudWatch或网络监测工具,以检查是否有异常网络流量。如果有任何问题,您可以使用这些工具来诊断和解决问题。,FALSE,只给出了网络故障的问题,不全,https://repost.aws/zh-Hans/knowledge-center/ec2-linux-status-check-failure,"根据背景知识,EC2实例在东京区域运行Ubuntu 18和Apache2 Web服务器,出现了""实例可达性检查失败""的问题,CPU和网络使用率正常。 要排查此问题,可以按以下步骤操作: 1. 检查实例的系统日志(例如/var/log/syslog),看是否有任何异常。 2. 检查网络连接情况,确认安全组规则已经开放了80端口。使用telnet或curl测试实例的80端口是否可达。 3. 检查Apache服务状态,使用命令service apache2 status查看服务是否运行正常。 4. 尝试重启Apache服务,使用命令service apache2 restart。 5. 尝试重启实例,可能会更换一个新的健康的主机。 6. 如果问题仍未解决,可以考虑更换实例类型,因为可能是主机硬件故障导致的问题。 7. 也可以提工单联系AWS支持,让他们帮助进一步排查实例网络连接或主机硬件方面的问题。 总之,需要从实例本身的日志、网络、服务等多个方面进行检查,以确定问题根源。重启实例或更换实例类型通常可以解决此类问题。",FALSE,,"EC2实例可达性检查失败的原因可能有以下几点: - -1. 底层主机硬件故障。可以尝试停止实例然后重新启动,让实例迁移到新的主机上。 - -2. 实例运行的操作系统故障。可以检查实例的系统日志,看是否有报错信息。 - -3. 实例网络连接故障。可以检查实例的网络设置,如安全组规则、ACL等是否正确。 - -4. 实例积分不足。对于T系列实例,可以检查其CPU积分是否耗尽。 - -5. 实例负载过高。可以从监控中查看实例的CPU、内存、网络等指标,判断是否超负荷运行。 - -6. 实例配置问题。检查实例的软件、服务是否正常启动。", -,"可以。打通内网有很多方案,比如vpn,sdwan,专线。这三个方案的成本由低到高,网络质量也是由低到高。以vpn为例,只需要在AWS开一台有公网的机器,安装openswan之类的软件,然后对接阿里云的VPN网关就行。这部分建议参考阿里云的文档。阿里云的VPN网关文档:https://help.aliyun.com/document_detail/64960.html -可以,建议使用专线打通。 -由于中国区不支持VPN,所以无法使用托管服务通过VPN打通。如果需要使用VPN,需要客户自行使用EC2搭建VPN网关(VPN网关的高可用会比较复杂)或使用第三方合作伙伴方案。 -专线相关请参考: -Amazon Direct Connect-亚马逊云科技 专用网络连接-亚马逊云科技中国区域 (amazonaws.cn)",如何打通AWS北京节点的网络和阿里云北京节点的内网?,您好,您需要打通的是公网和内网,我这边建议您使用专线连接,以下是具体的步骤: 1. 首先,您需要在AWS和阿里云的两端分别购买专线带宽,AWS和阿里云都有专线服务,您可以选择购买专线带宽。 2. 在AWS和阿里云上创建专线连接,AWS和阿里云都提供了专线连接的设置和管理工具,您可以选择使用它们来创建专线连接。 3. 在AWS和阿里云上设置路由,将两个节点的路由表添加一条路由规则,将公网流量路由到专线连接。 4. 测试连接,您可以使用ping命令测试两个节点的连通性,如果连通,则表示专线连接已经建立成功。 以上是打通公网和内网的基本步骤,如果您需要更详细的指导,请提供您的具体需求和环境信息,我将为您提供更详细的操作步骤。,[],FALSE,TRUE,,,,,,,,,,,"可以。打通内网有很多方案,比如vpn,sdwan,专线。这三个方案的成本由低到高,网络质量也是由低到高。以vpn为例,只需要在AWS开一台有公网的机器,安装openswan之类的软件,然后对接阿里云的VPN网关就行。这部分建议参考阿里云的文档。阿里云的VPN网关文档:https://help.aliyun.com/document_detail/64960.html -可以,建议使用专线打通。 -由于中国区不支持VPN,所以无法使用托管服务通过VPN打通。如果需要使用VPN,需要客户自行使用EC2搭建VPN网关(VPN网关的高可用会比较复杂)或使用第三方合作伙伴方案。 -专线相关请参考: -Amazon Direct Connect-亚马逊云科技 专用网络连接-亚马逊云科技中国区域 (amazonaws.cn)", -,DNS 全球复制最长需要48小时,最短15分钟,清除PC和内部DNS 服务器的DNS缓存,检测内部DNS上是否有域名和域名记录。可参照此链接方法排查:https://aws.amazon.com/cn/premiumsupport/knowledge-center/partial-dns-failures/ 1、Ping 一下域名,看看返回的IP是否是对应的公网IP; 2、是否停止及重启过实例,公网IP会变更; 3、为防止IP变更,看看业务需求,是否可关联使用EIP;,Route 53域名解析有时不成功,如何排查?,要排查Route 53域名解析失败的问题,可以按照以下步骤进行: 1. 检查域名是否在Route 53中注册:确保您正在尝试解析的域名已经在Route 53中注册并且没有任何问题。 2. 检查域名是否存在于DNS服务器:域名解析的DNS服务器必须在同一区域中。如果域名的DNS服务器不在同一区域,则可能需要请求相应的DNS服务器将域名解析为正确的IP地址。 3. 检查DNS服务器是否可达:确保域名解析的DNS服务器可达。如果域名解析的DNS服务器不可达或者无法访问,那么DNS查询将失败。 4. 检查DNS记录是否正确:检查域名解析的DNS记录是否正确。确保记录的TTL(生存时间)和值都正确,并且没有任何错误或冲突的记录。 5. 检查网络连接:检查您所在的计算机和网络是否与域名解析的DNS服务器建立了良好的网络连接。如果网络连接不稳定或不可用,可能会导致域名解析失败。 6. 检查防火墙和代理设置:如果您的计算机或网络中存在防火墙或代理设置,请确保它们不会阻止域名解析的请求。 7. 检查DNS服务器设置:如果您使用的是自定义的DNS服务器,请确保它们与Route 53中的DNS服务器设置匹配。 如果以上步骤都没有解决问题,您可以尝试使用其他DNS服务器进行域名解析,或者联系您的网络管理员或服务提供商寻求进一步的帮助。,"[""https://docs.aws.amazon.com/zh_cn/Route53/latest/DeveloperGuide/domain-whois-rdap.html"",""https://docs.aws.amazon.com/zh_cn/Route53/latest/DeveloperGuide/dns-test.html""]",TRUE,FALSE,,当遇到Route 53域名解析不成功的问题时,可以通过以下步骤进行排查: 1. 首先,检查域名的DNS配置是否正确。确保在Route 53控制台中,已经正确设置了DNS解析的托管区域,并将正确的DNS服务器地址添加到相应的记录中。 2. 其次,确认DNS服务器的可靠性。可以检查DNS服务器的性能和可用性,以确保它们没有过载或者出现故障。 3. 接下来,检查域名是否存在缓存问题。有时候,由于浏览器或者本地DNS服务器的缓存,可能会导致域名解析失败。可以尝试清除浏览器缓存和本地DNS缓存,然后再尝试解析。 4. 如果问题仍然存在,可以尝试使用其他的DNS服务提供商进行解析,以排除Route 53本身的问题。 5. 最后,如果需要,可以联系AWS技术支持,以获取更详细的技术支持和服务。,TRUE,,排查 Route 53 域名解析不成功的情况可以采取以下几种方法: 1. 使用 DNS 检查工具:可以使用 Route 53 控制台中的 DNS 检查工具或者第三方 DNS 检查工具,比如 `dig` 命令,来检查域名解析是否成功,并获取相关的 DNS 响应信息。 2. 检查域名记录设置:确保域名记录的设置正确无误,包括域名解析类型、IP 地址或别名记录等。可以通过 Route 53 控制台中的 DNS 检查工具或手动编辑 DNS 记录来实现。 3. 检查 DNS 解析设置:确保 DNS 解析设置正确,包括 DNS 服务器地址、解析超时时间等。可以在 Route 53 控制台的 DNS 设置中找到相关信息并进行修改。 4. 排除网络问题:检查网络连接是否正常,是否存在防火墙或代理服务器等问题导致域名解析失败。可以尝试使用其他 DNS 服务器进行域名解析,以排除网络问题的影响。 5. 排除域名解析限制:某些情况下,域名所有者可能会对域名解析进行限制,例如只允许特定 IP 地址或 DNS 服务器进行解析。可以通过联系域名所有者或者查看域名注册信息来确认是否有相关限制。 以上方法可以帮助排查 Route 53 域名解析不成功的问题,找到问题的根源并采取相应的措施解决。,TRUE,,"您好,如果使用 Route 53 域名解析时遇到解析不成功的情况,可以从以下几个方面进行排查: 1. 检查域名是否过期或者未续费。可以使用 whois 命令来检查域名的过期时间。 2. 检查域名是否已经正确指向 Route 53 托管区域。可以在 Route 53 控制台上查看域名的 NS 记录是否已经切换到 Route 53 分配的名称服务器。 3. 检查托管区域中的记录配置是否正确。可以使用 Route 53 的检查工具来模拟查询,验证记录返回的值是否正确。 4. 检查域名的 glue 记录是否配置正确。glue 记录是将子域名指向其权威名称服务器的记录,需要在注册商那里配置。 5. 检查网络是否被屏蔽。可以在不同网络环境下测试域名解析,以确定是否存在网络屏蔽问题。 6. 尝试清空本地 DNS 缓存,再次测试解析。清空缓存可以避免被过期的缓存记录影响解析结果。 7. 检查域名注册商的 WHOIS 信息,确保联系信息是正确的。错误的联系信息可能导致更新 DNS 记录时出错。 8. 联系 AWS 支持,报告无法解析的域名,由他们进一步排查问题原因。 在检查了各个环节后,通常可以找出域名解析不成功的具体原因,然后针对性地解决问题。",FALSE,,DNS 全球复制最长需要48小时,最短15分钟,清除PC和内部DNS 服务器的DNS缓存,检测内部DNS上是否有域名和域名记录。可参照此链接方法排查:https://aws.amazon.com/cn/premiumsupport/knowledge-center/partial-dns-failures/ 1、Ping 一下域名,看看返回的IP是否是对应的公网IP; 2、是否停止及重启过实例,公网IP会变更; 3、为防止IP变更,看看业务需求,是否可关联使用EIP;, -,国家区域级别的域名有当地要求, 请参考:https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/fr.html,Route 53注册abc.fr域名失败,应该怎么办?,Route 53注册abc.fr域名失败,您可以按照以下步骤进行处理: 1. 检查域名是否已经在Amazon Route 53注册。您可以在Route 53控制台中查看是否已经注册了该域名。 2. 检查域名是否已经过期。如果域名过期,您需要续订域名以继续使用它。 3. 检查域名是否已经锁定了。如果是,您需要解除域名锁定以进行转移。 4. 检查域名是否在黑名单中。如果域名在黑名单中,您需要将其从黑名单中移除。 5. 检查域名是否已经转移到其他注册商。如果域名已经转移到其他注册商,您需要联系该注册商以进行转移。 如果以上步骤都没有解决问题,您可以尝试联系Amazon Route 53的支持团队,以获取进一步的帮助和支持。 请注意,以上回答是基于一般情况的回答,如果您的情况与给定的知识资源不符,请根据您自己的知识或理解进行回答。,"[""https://docs.aws.amazon.com/zh_cn/Route53/latest/DeveloperGuide/fail.html"",""https://docs.aws.amazon.com/zh_cn/Route53/latest/DeveloperGuide/troubleshooting-domain-transfer-failed.html""]",FALSE,FALSE,,在尝试将abc.fr域名转移到Amazon Route 53时遇到失败,可能的原因有很多。根据提供的文章,首先需要确定问题出在哪里。以下是一些建议的解决方案: 1. 检查授权电子邮件:确保您已经收到了包含授权链接的电子邮件。如果没有,请在Route 53控制台中的状态页面查看是否显示您从当前注册商获取的授权代码无效。如果是这样,请联系当前注册商请求新的有效的授权代码。 2. 检查域名代码:确保在域名代码中正确列出了您要转移到Amazon Route 53的国际化域名。如果需要,使用域名代码来表示错误并重试。 3. 检查联系人类型:如果您的注册联系人的联系类型是Company(公司),而您正在尝试将.es域名转移到Route 53,请先将该类型更改为Person(人员),然后重新提交。 4. 如果以上步骤都无法解决问题,可能需要联系Amazon Route 53的支持团队以更进一步的帮助。,FALSE,,如果您在尝试注册 abc.fr 域名时遇到了问题,可以按照以下步骤进行处理: 1. 请确保您的域名注册信息完整并正确填写。 2. 如果您使用的是注册商的控制面板,请确保您已经选择了正确的域名注册类型。 3. 如果您使用的是第三方注册平台,请确保您已经选择了正确的域名注册类型。 4. 确保您选择的域名注册服务商与您的域名注册信息匹配。 5. 如果您无法解决问题,请联系域名注册商的客服寻求帮助。 6. 如果您使用的是 Route 53 注册服务,请检查您的注册信息是否正确填写,并确保您的域名注册服务商与您的域名注册信息匹配。 希望以上步骤能够帮助您解决注册 abc.fr 域名时遇到的问题。,FALSE,,"对于将域名转移到 Amazon Route 53 失败的情况,这里有几个常见的问题排查建议: 1. 检查是否点击了授权邮件中的链接。在转移域名过程中,ICANN 要求域名注册联系人向注册商提供转移授权。Amazon 会发送一封包含链接的邮件,您需要在指定时间内点击该链接授权转移,否则转移会失败。 2. 检查授权码是否有效。如果没有收到授权邮件,可以在 Route 53 控制台的状态页面检查授权码是否有效。如果显示无效,请联系当前注册商获取新的有效授权码后再次发起转移。 3. 检查域名格式。对于国际化域名,需要使用域名的 Punycode 格式,而不是原始字符。请检查转移请求中是否使用了正确的域名格式。 4. 检查注册联系人信息。对于一些顶级域名,注册联系人信息有特定要求,如 .es 域名要求联系人类型为个人。请确认注册信息符合要求。 5. 联系支持。如果按照上述建议仍无法解决问题,可以联系 Amazon 支持部门寻求帮助。提供尽可能多的错误详情会有助于快速定位问题。",FALSE,答非所问,和转移域名无关,"1. 国家和地区顶级域名(如.fr)有特定的注册要求,需要查看该国家或地区的具体域名注册政策。 - -2. 对于法国的.fr域名,可以参考AWS文档中的说明:https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/fr.html", -,"可以。https://docs.aws.amazon.com/zh_cn/Route53/latest/DeveloperGuide/domain-transfer.html -注意tld需要是route53支持的,像.cn这种不行; 另外还需要注意,转到海外区之后域名是不能用来备案的",腾讯云中国区域的域名如何转移到AWS海外区域的Route 53?,根据提供的知识资源,无法确定腾讯云中国区域的域名如何转移到AWS海外区域的Route 53。请联系AWS解决方案团队以获取进一步的帮助和指导。,"[""https://docs.aws.amazon.com/zh_cn/Route53/latest/DeveloperGuide/domain-transfer-between-aws-accounts.html"",""https://docs.aws.amazon.com/zh_cn/Route53/latest/DeveloperGuide/domain-transfer-to-route-53.html""]",TRUE,TRUE,,腾讯云中国区域的域名转移到AWS海外区域的Route 53的过程与上述步骤类似,但需要考虑一些额外的步骤和政策限制。以下是详细的步骤: 1. 登录到腾讯云的控制台,找到您想要转移的域名。 2. 点击管理,然后选择域名转移。 3. 在域名转移页面,您需要提供一个转移码。这个转移码可以通过腾讯云的控制台或者邮件获取。 4. 生成转移码后,前往AWS的全球区域性控制台,找到Registered Domains页面,点击Transfer domain to Route 53。 5. 在Transfer domain to Route 53页面,输入您的域名和转移码。 6. 点击Continue,系统会验证域名是否可以转移。这个过程可能需要一些时间,特别是对于一些特定的域名或者TLD。 7. 验证成功后,系统会发送一封邮件给您,要求您确认转移。点击邮件中的链接,确认转移。 8. 确认转移后,系统会发送另一封邮件给您,要求您支付转移费用。支付费用后,域名就会转移到AWS的Route 53了。 需要注意的是,腾讯云和中国地区的域名转移到全球其他地区可能会有一些政策限制,特别是在涉及到敏感信息或者政治相关的内容时。在进行转移前,建议先了解相关的政策和限制。,TRUE,,要把腾讯云中国区域的域名转移到 AWS 海外区域的 Route 53,您需要先完成一系列步骤,包括: 1. 创建 AWS 账户并在 AWS 控制台中登录。 2. 转到 AWS 控制台的导航菜单,然后选择“Services” > “Elastic Beanstalk” > “Application” > “Domain Name”。 3. 点击“Add Domain”,然后输入您要转移的域名。 4. 点击“Create Domain”以创建新的 AWS 域名。 5. 一旦创建了 AWS 域名,您可以在 AWS 控制台中选择“Services” > “Route53” > “Hosted zones”,然后点击“Import hosted zone”。 6. 从文件上传您的域名证书,然后点击“Review and submit”。 7. 确认您的域名转移请求后,您将在几小时内看到您的域名已经转移到 AWS 海外区域的 Route 53 中。,FALSE,,"要将腾讯云中国区域的域名转移到 AWS 海外区域的 Route 53,您可以参考以下步骤: 1. 在腾讯云中国解锁域名。进入腾讯云管理控制台,找到要转移的域名,将“域名锁定”设置为“关闭”状态。这可以允许域名进行转移。 2. 在腾讯云中国获取域名授权码。进入腾讯云管理控制台,找到要转移的域名,获取“域名授权码”。这个授权码需要在转移请求时提供给AWS。 3. 在AWS海外区域Route 53控制台请求域名转移。进入Route 53控制台,点击“注册域名”,选择“从其他注册商转入”,输入要转移的域名和步骤2获取的授权码,提交转移请求。 4. 授权域名转移。AWS会向域名的注册联系人邮箱发送确认邮件,您需要点击邮件中的链接来授权转移。 5. 等待转移完成。域名转移需要一定时间完成,通常在3-5天左右。您可以在Route 53控制台查看转移状态。 6. 更新域名服务器。转移完成后,需要将域名的名称服务器改为Route 53分配的服务器。在Route 53中可以找到名称服务器地址。 7. 测试解析。可以添加一个测试记录,确认域名可以正常解析到您的网站或应用。 注意在转移过程中需要保持耐心,如果有任何问题可以联系AWS支持或者腾讯云支持。",TRUE,,"要将腾讯云中国区域的域名转移到 AWS 海外区域的 Route 53,您可以参考以下步骤: 1. 在腾讯云中国解锁域名。进入腾讯云管理控制台,找到要转移的域名,将“域名锁定”设置为“关闭”状态。这可以允许域名进行转移。 2. 在腾讯云中国获取域名授权码。进入腾讯云管理控制台,找到要转移的域名,获取“域名授权码”。这个授权码需要在转移请求时提供给AWS。 3. 在AWS海外区域Route 53控制台请求域名转移。进入Route 53控制台,点击“注册域名”,选择“从其他注册商转入”,输入要转移的域名和步骤2获取的授权码,提交转移请求。 4. 授权域名转移。AWS会向域名的注册联系人邮箱发送确认邮件,您需要点击邮件中的链接来授权转移。 5. 等待转移完成。域名转移需要一定时间完成,通常在3-5天左右。您可以在Route 53控制台查看转移状态。 6. 更新域名服务器。转移完成后,需要将域名的名称服务器改为Route 53分配的服务器。在Route 53中可以找到名称服务器地址。 7. 测试解析。可以添加一个测试记录,确认域名可以正常解析到您的网站或应用。 注意在转移过程中需要保持耐心,如果有任何问题可以联系AWS支持或者腾讯云支持。", -,试试在东京、新加坡起个ec2做代理,回国走优化链路看看,未必保证会很快,但是比专线那些便宜。,有什么方法可以加速东南亚地区的开发人员对国内AWS EC2实例的SSH访问?,有两个方法可以加速东南亚地区的开发人员对国内AWS EC2实例的SSH访问: 1. 使用AWS Global Accelerator:AWS Global Accelerator是一项全球加速服务,可加速用户通过AWS Elastic Load Balancer访问AWS资源。它使用AWS全球网络来优化用户访问,从而提高访问速度。在实例所在的区域,使用Global Accelerator可以加速访问速度,因为实例被放置在距离用户最近的AWS边缘位置。 2. 使用AWS Direct Connect:AWS Direct Connect是一种服务,可让用户通过专用网络连接直接访问AWS。它提供了一条直接连接到AWS的私有网络连接,比通过公共网络访问AWS更快、更可靠。您可以使用AWS Direct Connect将东南亚地区的开发人员连接到AWS EC2实例,从而加速他们的访问速度。 无论您选择哪种方法,都可以显著提高东南亚地区的开发人员对国内AWS EC2实例的SSH访问速度。,[],FALSE,FALSE,,,,,,,,,,,试试在东京、新加坡起个ec2做代理,回国走优化链路看看,未必保证会很快,但是比专线那些便宜。, -https://docs.aws.amazon.com/zh_cn/glue/latest/dg/crawler-data-stores.html,https://docs.aws.amazon.com/zh_cn/glue/latest/dg/crawler-data-stores.html,AWS Glue Crawler可以爬取哪些类型的数据存储?,AWS Glue Crawler可以爬取以下类型的数据存储: 1. Amazon Simple Storage Service (Amazon S3) 2. Amazon DynamoDB 3. Delta Lake 4. Apache Iceberg 5. Apache Hudi 6. Amazon Redshift 7. Snowflake 8. Amazon Aurora 9. MariaDB 10. Microsoft SQL Server 11. MySQL 12. Oracle 13. PostgreSQL 请注意,AWS Glue目前不支持爬网程序爬取数据流的存储。,"[""https://docs.aws.amazon.com/zh_cn/glue/latest/dg/crawler-data-stores.html"",""https://repost.aws/questions/QUm8xWKDKaTTSQHb-DWnu3bA""]",TRUE,TRUE,,AWS Glue Crawler可以爬取多种类型的数据存储,包括本地客户端、JDBC、MongoDB客户端等。具体来说,它可以爬取以下几种数据存储: 1. Amazon Simple Storage Service (Amazon S3) 2. Amazon DynamoDB 3. Delta Lake 4. Apache Iceberg 5. Apache Hudi 6. Amazon Redshift 7. Snowflake 8. 在Amazon Relational Database Service(Amazon RDS)内部或Amazon RDS外部的一些数据库,如Amazon Aurora、MariaDB、Microsoft SQL Server、MySQL、Oracle和PostgreSQL。 需要注意的是,目前,AWS Glue不支持数据流的爬网程序。对于JDBC、MongoDB、MongoDB Atlas和Amazon DocumentDB(与MongoDB兼容)数据存储,用户必须指定爬网程序可用于连接到数据存储的AWS Glue连接。对于Amazon S3,用户可以选择指定网络类型的连接。,TRUE,,AWS Glue Crawler可以爬取多种不同类型的数据存储,包括以下几种: 1. **Amazon S3**:可以爬取S3中的文件和文件夹,包括路径中的子文件夹。 2. **Amazon DynamoDB**:可以爬取DynamoDB中的表和项目。 3. **Delta Lake**:可以爬取Delta Lake中的表和分区。 4. **Apache Iceberg**:可以爬取Iceberg中的表和分区。 5. **Apache Hudi**:可以爬取Hudi中的表和分区。 6. **JDBC**:可以爬取支持JDBC连接的数据库,例如Amazon Redshift、Snowflake等。 7. **MongoDB**:可以爬取MongoDB中的数据库和集合。 8. **Amazon DocumentDB (with MongoDB compatibility)**:可以爬取MongoDB数据库和集合。 9. **关系数据库**:可以爬取支持关系数据库的数据存储,例如MySQL、PostgreSQL等。 10. **Snowflake**:可以爬取Snowflake中的表、外部表、视图和实体化视图。 这些数据存储类型涵盖了广泛的数据存储选项,使得AWS Glue Crawler成为处理各种数据存储的灵活工具。,TRUE,,"AWS Glue Crawler可以爬取以下几种类型的数据存储: 1. Amazon S3 - 可以爬取S3路径上的文件,自动发现schema并创建表定义。 2. Amazon DynamoDB - 可以爬取DynamoDB表,发现schema并创建表定义。 3. MongoDB - 支持MongoDB 3.2及更高版本,可以爬取集合并发现schema。 4. 关系型数据库(使用JDBC连接)- 支持爬取常见关系型数据库如Amazon Aurora、MySQL、Postgres等中的表/视图。 5. Delta Lake - 可以爬取Delta Lake表并在Glue Data Catalog中创建表定义。 6. Apache Iceberg - 可以爬取Iceberg表并注册元数据到Data Catalog。 7. Apache Hudi - 可以爬取Hudi表并注册元数据。 8. Snowflake - 支持爬取Snowflake中的表/视图/外部表。 9. Amazon DocumentDB - 支持爬取与MongoDB兼容的DocumentDB。 需要注意的是,Glue Crawler需要使用IAM角色来访问这些数据存储。另外,对于某些存储类型,需要事先创建Glue连接来保存访问信息。 总结一下,Glue Crawler支持爬取广泛的数据源,可以自动发现schema信息,非常适合用于构建Glue数据目录。需要合理配置权限和连接信息来访问不同的数据源。",TRUE,,"AWS Glue Crawler可以爬取以下几种类型的数据存储: 1. Amazon S3 - 可以爬取S3路径上的文件,自动发现schema并创建表定义。 2. Amazon DynamoDB - 可以爬取DynamoDB表,发现schema并创建表定义。 3. MongoDB - 支持MongoDB 3.2及更高版本,可以爬取集合并发现schema。 4. 关系型数据库(使用JDBC连接)- 支持爬取常见关系型数据库如Amazon Aurora、MySQL、Postgres等中的表/视图。 5. Delta Lake - 可以爬取Delta Lake表并在Glue Data Catalog中创建表定义。 6. Apache Iceberg - 可以爬取Iceberg表并注册元数据到Data Catalog。 7. Apache Hudi - 可以爬取Hudi表并注册元数据。 8. Snowflake - 支持爬取Snowflake中的表/视图/外部表。 9. Amazon DocumentDB - 支持爬取与MongoDB兼容的DocumentDB。 需要注意的是,Glue Crawler需要使用IAM角色来访问这些数据存储。另外,对于某些存储类型,需要事先创建Glue连接来保存访问信息。 总结一下,Glue Crawler支持爬取广泛的数据源,可以自动发现schema信息,非常适合用于构建Glue数据目录。需要合理配置权限和连接信息来访问不同的数据源。", -https://docs.aws.amazon.com/zh_cn/elasticbeanstalk/latest/dg/using-features.CNAMESwap.html,https://docs.aws.amazon.com/zh_cn/elasticbeanstalk/latest/dg/using-features.CNAMESwap.html,AWS Elastic Beanstalk如何在控制台来配置蓝绿部署?,在AWS Elastic Beanstalk的配置控制台中,可以通过以下步骤来配置蓝绿部署: 1. 打开Elastic Beanstalk控制台,并选择您的AWS区域。 2. 在导航窗格中选择Environments(环境),然后从列表中选择您要配置的现有环境或创建一个新的环境。 3. 在环境概述页面上,选择Actions(操作),然后选择Swap environment URLs(交换环境URL)。 4. 选择当前环境作为目标环境。 5. 确认交换操作,等待Elastic Beanstalk完成交换操作。 6. 验证新环境是否能够响应旧环境的URL请求。 7. 在配置页面上查看和修改环境的各种配置选项。 8. 完成所有要更改的配置后,选择Apply changes(应用更改)将更改应用于环境。 请注意,这些步骤仅适用于在Elastic Beanstalk控制台中进行蓝绿部署的配置。如果您需要更详细的说明或碰到任何问题,请参考Elastic Beanstalk文档或联系AWS解决方案团队。,"[""https://docs.aws.amazon.com/zh_cn/elasticbeanstalk/latest/dg/using-features.CNAMESwap.html"",""https://docs.aws.amazon.com/zh_cn/elasticbeanstalk/latest/dg/environments-cfg-console.html""]",TRUE,FALSE,把KnowledgeSource两个链接中的知识混在一起了,要在Elastic Beanstalk控制台配置蓝绿部署,请按照以下步骤操作: 1. 打开Elastic Beanstalk控制台,然后在Regions(区域)列表中选择您的AWS区域。 2. 在导航窗格中,选择Environments(环境),然后从列表中选择环境的名称。 3. 在导航窗格中,选择Configuration(配置)。 4. 在配置概述页面中,可以看到一组配置类别。在每个配置类别中选择Edit(编辑)以转到相关的配置页面。 5. 在配置页面中,可以查看完整选项值并进行更改。完成修改后,可以选择继续或应用更改。,FALSE,答非所问,要在 AWS Elastic Beanstalk 的控制台中配置蓝绿部署,可以按照以下步骤进行操作: 1. 打开 Elastic Beanstalk 控制台,并在 Regions(区域)列表中选择所需的 AWS 区域。 2. 选择 Environments(环境),并从列表中选择要配置蓝绿部署的环境名称。 3. 在导航窗格中,选择 Configuration(配置)。 4. 在配置概述页面中,选择 Edit (编辑) 进入相关配置类别的编辑页面。 5. 在编辑页面中,可以根据需要进行相应的配置更改,包括环境行为、附加功能以及其他设置等。 6. 当需要时,可以取消编辑或取消待处理更改的摘要信息。 7. 如果需要应用更改,可以点击 Apply changes(应用更改)按钮,系统将提示确认某些配置决策的结果。,FALSE,答非所问,"根据背景知识,要在AWS Elastic Beanstalk控制台配置蓝绿部署,可以采取以下步骤: 1. 打开Elastic Beanstalk控制台,选择一个区域。 2. 克隆当前的生产环境,或启动一个新的环境运行所需的平台版本。 3. 在新环境中部署新的应用程序版本。 4. 在新环境中测试新的版本。 5. 在环境概述页面上,选择""Actions"",然后选择""Swap environment URLs""。 6. 对于""Environment name"",选择当前的生产环境。 7. 选择""Swap""。 这将交换两个环境的别名记录,将流量从旧版本重定向到新版本。 完成交换后,验证当访问旧环境URL时,是否会重定向到新环境。在DNS变更完全传播之前,不要终止旧环境。 这样就可以通过Elastic Beanstalk控制台实现蓝绿部署了。",TRUE,,"要在AWS Elastic Beanstalk控制台配置蓝绿部署,可以采取以下步骤: 1. 打开 Elastic Beanstalk 控制台,然后在 Regions(区域)列表中选择您的 AWS 区域。 -2. 克隆当前环境,或启动运行所需平台版本的新环境。3. 向新环境部署新应用程序版本。4. 在新环境上测试新版本。5. 在环境概述页面上,选择 Actions(操作),然后选择 Swap environment URLs(交换环境 URL)。6. 对于 Environment name(环境名称),请选择当前环境。7. 选择 Swap(交换)。 -Elastic Beanstalk 交换旧环境和新环境的别名记录,以将流量从旧版本重定向到新版本。", -https://docs.aws.amazon.com/zh_cn/AmazonECS/latest/developerguide/networkng-mode-options.html,https://docs.aws.amazon.com/zh_cn/AmazonECS/latest/developerguide/networkng-mode-options.html,ECS task有哪些联网模式?,ECS task有两种联网模式:host网络模式和Fargate网络模式。,"[""https://docs.aws.amazon.com/zh_cn/AmazonECS/latest/developerguide/networking-networkmode-host.html"",""https://docs.aws.amazon.com/zh_cn/config/latest/developerguide/ecs-task-definition-user-for-host-mode-check.html""]",TRUE,FALSE,,ECS task有两种网络模式:host网络模式和Fargate网络模式。,FALSE,,ECS task 有两种主要的联网模式:bridge网络模式和host网络模式。 bridge网络模式是将容器的网络与底层主机的网络隔离开,而host网络模式则是直接将容器的网络与底层主机的网络进行绑定。,TRUE,不完整,"ECS任务支持以下几种网络模式: - bridge 模式(默认) - 容器连接到默认的bridge网络,并分配一个内部IP地址。容器可以与同一任务中的其他容器通信,但与外部世界的通信需要进行端口映射。 - host 模式 - 容器直接使用宿主EC2实例的网络命名空间,没有隔离。容器可以绑定到任何宿主端口,但一个端口只能被一个容器使用。 - awsvpc 模式 - 容器连接到一个弹性网络接口(ENI),有自己的IP地址。提供了更好的隔离,弹性和可扩展性。 - none 模式 - 容器没有外部网络连接。 对于使用 host 网络模式的 ECS 任务,需要特别注意安全性。因为容器可以访问宿主机的所有端口和网络,有被利用的风险。建议设置 containerDefinition 的 privileged=false 和 user=非root用户,来限制容器的权限。 总之,如果使用 host 网络模式,一定要谨慎操作,设置容器的权限不要过大。awsvpc 模式能提供更好的安全隔离。",TRUE,,"ECS任务有以下几种网络模式: - -- awsvpc 模式:任务获得自己的弹性网络接口(ENI)和私有IP地址,提供与EC2实例相同的网络属性。这是推荐的模式。 - -- bridge 模式(Linux):任务使用Docker的默认bridge网络,在每个EC2实例内运行。这是Linux的默认模式。 - -- host 模式(Linux):任务绕过Docker网络,直接将容器端口映射到EC2实例的ENI。不支持动态端口映射。 - -- none 模式(Linux):任务没有外部网络连接。 - -- default 模式(Windows):任务使用Windows上的Docker默认网络,在每个EC2实例内运行。这是Windows的默认模式。", -https://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/Streams.Lambda.html,https://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/Streams.Lambda.html,我希望DynamoDB的表被改动时,能触发Lambda函数,应该如何实现?,"您可以创建一个DynamoDB的触发器, 当table发生变化时触发Lambda函数。在AWS控制台, 选择您的表, 然后在""管理触发器""下创建一个新触发器, 设Type为""Event Driven"", 然后配置触发器监听""Table""的Change事件。这样每次table发生变化时, 都会触发Lambda函数。","[""https://repost.aws/questions/QUcNO84Fg7QM2ayUQnI20wHA"",""https://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/Streams.Lambda.BestPracticesWithDynamoDB.html""]",TRUE,FALSE,Lambda设置DDB stream为触发器的步骤见 https://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/Streams.Lambda.Tutorial.html#Streams.Lambda.Tutorial.CreateTrigger,为了实现在DynamoDB表发生变化时触发Lambda函数,你需要设置两个东西:一个是事件源,另一个是事件监听器。首先,你需要在你的DynamoDB表中启用DynamoDB Streams。然后,你将设置一个Lambda函数作为事件监听器,当表的状态发生变化时会自动调用你的Lambda函数。 更多信息请查看[这里](https://docs.aws.amazon.com/amazondynamodb/latest/devguide/tutorial-enable-global-table-meta-update.html)。,TRUE,链接打不开,您可以使用Amazon S3的事件通知,将S3事件与Lambda函数关联起来。当DynamoDB表发生更改时,会触发一个事件,并将该事件发送到Amazon S3。然后,您可以设置S3事件通知规则,将S3事件发送给Lambda函数。 以下是一些步骤来实现这一目标: 1. 创建一个DynamoDB触发器,以便在表中发生更改时发送通知。 2. 创建一个S3桶,用于存储S3事件通知。 3. 创建一个S3事件通知规则,将S3事件发送到Lambda函数。 4. 在Lambda函数中编写代码,以处理来自S3事件的通知,并从DynamoDB表中获取数据。 5. 编写代码,以根据需要执行其他操作,如发送电子邮件等。 希望这些信息对您有所帮助!,FALSE,,"您可以通过以下步骤实现DynamoDB表改动时触发Lambda函数: 1. 在DynamoDB表上创建流。流可以捕获表上的插入、更新和删除事件。 2. 在Lambda中创建一个函数来处理流记录。函数需要实现处理流记录的逻辑。 3. 创建一个触发器,将DynamoDB流与Lambda函数相关联。这样当有新记录写入流时,Lambda函数就会被调用。 4. 在DynamoDB表上进行插入、更新或删除操作,以生成流记录。这将触发关联的Lambda函数。 5. 在Lambda函数中,从事件中提取流记录,并执行所需的业务逻辑,比如发送通知等。 6. 确保Lambda函数具有适当的IAM权限来读取流并访问其他AWS资源,比如SNS用于发送通知。 在Amplify中,您可以通过CLI添加触发器,它会自动处理大部分设置。总的来说,DynamoDB流是触发Lambda的一个强大方式,无需手动调用函数。",TRUE,,"您可以通过以下步骤实现DynamoDB表改动时触发Lambda函数: 1. 在DynamoDB表上创建流。流可以捕获表上的插入、更新和删除事件。 2. 在Lambda中创建一个函数来处理流记录。函数需要实现处理流记录的逻辑。 3. 创建一个触发器,将DynamoDB流与Lambda函数相关联。这样当有新记录写入流时,Lambda函数就会被调用。 4. 在DynamoDB表上进行插入、更新或删除操作,以生成流记录。这将触发关联的Lambda函数。 5. 在Lambda函数中,从事件中提取流记录,并执行所需的业务逻辑,比如发送通知等。 6. 确保Lambda函数具有适当的IAM权限来读取流并访问其他AWS资源,比如SNS用于发送通知。 在Amplify中,您可以通过CLI添加触发器,它会自动处理大部分设置。总的来说,DynamoDB流是触发Lambda的一个强大方式,无需手动调用函数。", -https://docs.aws.amazon.com/zh_cn/iot/latest/developerguide/configure-logging.html#configure-logging-console,https://docs.aws.amazon.com/zh_cn/iot/latest/developerguide/configure-logging.html#configure-logging-console,我想给所有 AWS IoT 配置日志记录,在控制台应该如何操作?,要在AWS IoT控制台中为所有AWS IoT配置日志记录,请按照以下步骤操作: 1. 登录到AWS IoT控制台。 2. 导航到“事件规则”页面。 3. 单击“创建规则”按钮。 4. 在规则配置页面上,选择“添加规则”。 5. 在“事件源”部分,选择“所有AWS IoT”。 6. 在“目标”部分,选择“发送到日志组”。 7. 在“日志组”字段中,输入日志组名称。 8. 选择“保存”。 通过执行以上步骤,您将能够在AWS IoT控制台中为所有AWS IoT配置日志记录。请注意,您还可以使用AWS CLI或API来执行相同的操作。,"[""https://docs.aws.amazon.com/zh_cn/iot/latest/developerguide/configure-logging.html"",""https://docs.aws.amazon.com/zh_cn/iot/latest/developerguide/connect-iot-lorawan-configure-resource-logging.html""]",TRUE,FALSE,,您可以在 AWS 控制台中查看和配置 AWS IoT 配置日志记录。以下是操作步骤: 1. 登录到您的 AWS 账户。 2. 在服务列表中,点击“管理控制和监控”。 3. 在左侧导航栏中,点击“日志”。 4. 在右侧面板中,点击“添加一个新的 log group”。 5. 在“新建日志组”对话框中,输入日志组的名称,然后点击“确定”。 6. 新创建的日志组将出现右侧面板中,现在,您可以开始配置日志记录的详细程度了。 7. 要在日志组中启用或禁用日志记录,请点击“详细信息”按钮。这将打开一个新窗口,显示日志记录的详细配置选项。 8. 在这里,您可以切换“包含详情”开关来启用或禁用日志记录。您还可以配置每个日志记录的详细程度。 9. 完成配置后,点击“关闭”按钮关闭详细信息窗口。 通过这种方式,您可以在 AWS 控制台中查看和配置 AWS IoT 配置日志记录。,FALSE,,要在控制台中启用所有 AWS IoT 配置日志记录,可以按照以下步骤操作: 1. 打开 AWS 管理控制台,并在导航栏中找到并选择“服务”。 2. 在左侧导航栏中,找到并点击“CloudWatch”图标。 3. 在 CloudWatch 仪表板中,找到并点击“数据源”选项卡。 4. 在数据源页面中,找到并单击“AWS IoT Wireless”数据源。 5. 单击“启用所有资源”按钮,以启用所有 AWS IoT 配置日志记录。 请注意,启用所有资源将导致所有资源的日志级别都被设置为 ERROR。如果您希望根据资源类型或事件类型来调整日志级别,请使用 AWS IoT Wireless API 或使用 AWS CLI 来进行更细粒度的控制。,FALSE,,"您可以按照以下步骤在AWS IoT控制台中为所有AWS IoT配置日志记录: 1. 登录AWS IoT控制台。 2. 在左侧导航窗格中,选择“设置”。 3. 在“设置”页面的“日志”部分,选择“管理日志”。 4. 在“日志”页面上,选择“选择角色”以指定您创建的用于日志记录的角色,或选择“创建角色”以创建一个新角色。 5. 选择日志级别,它描述了要在CloudWatch日志中显示的日志条目的详细级别。 6. 单击“更新”以保存更改。 这样就可以为AWS IoT中的所有资源启用日志记录了。启用日志记录后,您可以在CloudWatch控制台中查看日志条目,以监控AWS IoT活动。 请注意,如果要为特定的AWS IoT资源(如特定的thing组)配置日志记录,您需要使用AWS CLI或API,不能在控制台中进行配置。",TRUE,,"您可以按照以下步骤在AWS IoT控制台中为所有AWS IoT配置日志记录: 1. 登录AWS IoT控制台。 2. 在左侧导航窗格中,选择“设置”。 3. 在“设置”页面的“日志”部分,选择“管理日志”。 4. 在“日志”页面上,选择“选择角色”以指定您创建的用于日志记录的角色,或选择“创建角色”以创建一个新角色。 5. 选择日志级别,它描述了要在CloudWatch日志中显示的日志条目的详细级别。 6. 单击“更新”以保存更改。 这样就可以为AWS IoT中的所有资源启用日志记录了。启用日志记录后,您可以在CloudWatch控制台中查看日志条目,以监控AWS IoT活动。 请注意,如果要为特定的AWS IoT资源(如特定的thing组)配置日志记录,您需要使用AWS CLI或API,不能在控制台中进行配置。", -https://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/RemovingObjects.html,https://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/RemovingObjects.html,我想从 CloudFront 分配中立即删除某个缓存的文件,有哪些方法?,"您有两个方法可以立即删除 CloudFront 分配中某个缓存的文件: 1. 使文件失效:您可以通过将文件失效来立即删除它。失效文件后,它将不再包含在 CloudFront 分配中,并且无法再被查看器访问。有关更多信息,请参阅 AWS 文档中的 ""使文件失效""。 2. 使用文件版本控制:如果您希望保留文件的所有版本,您可以使用文件版本控制功能。通过使用版本控制,您可以创建和管理不同版本的文件,并指定在 CloudFront 分配中使用的不同名称。这样,您可以更改返回给查看器的文件,而不会影响其他版本。有关更多信息,请参阅 AWS 文档中的 ""使用版本控制的文件名更新现有文件""。 请注意,在删除文件之前,您必须先禁用 CloudFront 分配,并且需要有权限更新分发。","[""https://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/HowToDeleteDistribution.html"",""https://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/RemovingObjects.html""]",TRUE,TRUE,,要从 CloudFront 分配中立即删除某个缓存的文件,您可以选择以下几种方法之一: 1. 使文件失效:通过使文件失效,您可以在 CloudFront 中立即停止返回文件的缓存副本。这可以立即影响查看者的访问。 2. 使用文件版本控制:通过使用文件版本控制,您可以为不同的文件版本指定不同的名称,以便在 CloudFront 分配中进行更改。这将影响到返回给查看者的文件的响应。 3. 删除分配:如果您不再需要该分配,可以使用 CloudFront 控制台或 API 将其删除。请注意,在完成删除过程之前,可能需要几分钟的时间才能将所有更改传播到边缘站点。,TRUE,,要从 CloudFront 分配中立即删除某个缓存的文件,您可以选择以下几种方法之一: - 使文件失效:通过使文件失效,可以删除文件并从 CloudFront 中删除它。这种方法适用于文件即将到期的情况。 - 使用文件版本控制:通过使用文件版本控制,可以为每个文件创建多个版本,并在 CloudFront 中使用不同的文件名。这样,您可以更改返回给查看器的文件。 - 禁用和删除分配:如果分配包含您不再需要的文件,您可以先禁用该分配,然后再将其删除。这种方法适用于您不想再使用该分配的情况。,TRUE,,"根据背景知识,有两种方法可以立即从CloudFront分配中删除缓存的文件: 1. 使文件失效。您可以使用CloudFront 控制台、CLI或API来使特定文件的缓存失效。这将使CloudFront立即停止为该文件提供服务,而不管其缓存时间有多长。 2. 使用文件版本控制。如果您使用版本控制,可以通过更新文件名来更改CloudFront返回给用户的文件。例如,从file.jpg改为file_v2.jpg。CloudFront会识别这是新的文件版本并立即获取更新后的文件。 所以如果您需要快速删除CloudFront中的缓存文件,使其失效或使用版本控制都是有效的方法。只需注意使文件失效会需要您在源服务器上继续托管该文件,而版本控制会需要您上传新的文件版本。",TRUE,,有两种方法可以立即从CloudFront分配中删除缓存的文件: 1. 使文件失效。 2. 使用文件版本控制。当您使用版本控制时,不同版本的文件具有可在 CloudFront 分配中使用的不同名称,以便更改返回给查看器的文件。, -https://docs.aws.amazon.com/zh_cn/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html#cognito-user-identity-pools-working-with-aws-lambda-triggers-using-lambda,https://docs.aws.amazon.com/zh_cn/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html#cognito-user-identity-pools-working-with-aws-lambda-triggers-using-lambda,我想在Cognito控制台为用户池添加 Lambda 触发器,应该如何操作?,"要在Cognito控制台为用户池添加Lambda触发器,您可以按照以下步骤操作: 1. 登录到AWS管理控制台并打开Cognito服务。 2. 在Cognito控制台中,选择""用户池""选项卡,然后选择您想要添加Lambda触发器的用户池。 3. 在用户池的""管理""选项卡中,找到""触发器""部分,并单击""添加触发器""按钮。 4. 在触发器类型列表中选择""Lambda函数""。 5. 根据您的需求,选择适当的触发器配置选项,例如触发器的名称、Lambda函数的ARN等。 6. 配置Lambda函数的相关信息,例如函数名称、函数代码等。 7. 在""配置触发器""页面上,选择要触发Lambda函数的事件类型,例如""用户注册""、""用户登录""等。 8. 点击""保存""按钮以保存触发器配置。 完成以上步骤后,您的用户池将添加Lambda触发器,当满足触发器配置中定义的事件条件时,Lambda函数将自动被触发并执行相应的操作。 请注意,您需要确保Lambda函数已经配置并运行正常,并且具有适当的权限来访问和操作用户池数据。","[""https://docs.aws.amazon.com/zh_cn/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html"",""https://docs.aws.amazon.com/zh_cn/cognito/latest/developerguide/cognito-user-pools-import-using-lambda.html""]",TRUE,TRUE,,要在 Amazon Cognito 控制台为用户池添加 Lambda 触发器,请按照以下步骤操作: 1. 登录到 Amazon Cognito 控制台并转到您的用户池。 2. 在左侧导航栏中,点击“规则”选项卡。 3. 在“规则”屏幕上,向下滚动到“触发器”部分。 4. 点击“添加触发器”按钮。 5. 在“选择服务”下拉菜单中,选择“Lambda”。 6. 从可用触发器列表中选择所需的触发器。 7. 为触发器输入一个名称和一些其他必要的信息,如描述和 Lambda 函数 ARN。 8. 点击“保存”按钮。 现在,您已经成功为用户池添加了 Lambda 触发器。接下来,您需要确保 Lambda 函数已正确配置并可用。一旦 Lambda 函数开始运行,它将开始在用户触发相应事件时自动执行。,FALSE,,要在 Cognito 控制台中添加 Lambda 触发器,请按照以下步骤操作: 1. 打开 Cognito 控制台并转到您的用户池。 2. 单击“应用程序集成”选项卡,然后选择“Lambda 触发器”。 3. 点击“添加 Lambda 触发器”按钮。 4. 在“Lambda 触发器”页面上,填写触发器的名称和其他所需细节,如触发源、事件类型等。 5. 点击“保存”按钮以创建 Lambda 触发器。 6. 现在,您可以在“应用程序集成”选项卡下看到已创建的 Lambda 触发器,并根据需要对其进行配置和管理。,FALSE,,"您可以按照以下步骤在Cognito控制台为用户池添加Lambda触发器: 1. 登录Cognito控制台,选择要为其添加触发器的用户池。 2. 点击“用户池属性”选项卡。 3. 在“Lambda触发器”部分,点击“添加Lambda触发器”。 4. 选择触发器的类别,比如“注册前”或“身份验证后”等。这将决定触发器在什么情况下被调用。 5. 点击“分配Lambda函数”,选择与该用户池位于同一AWS区域的Lambda函数。 6. 点击“保存更改”。 这样Cognito就会在所选的事件发生时调用配置的Lambda函数。您还需要确保Lambda函数具有正确的执行角色和权限,以访问Cognito并进行所需的处理。 在控制台上添加触发器后,Cognito会自动向Lambda函数添加资源策略,允许被调用。如果是以编程方式添加触发器,您可能需要手动添加策略以授予Cognito调用权限。 总体来说,在控制台上操作简单直观。选择触发器类别,选择Lambda函数,保存更改,Cognito和Lambda之间的交互就配置完成了。",TRUE,,"您可以按照以下步骤在Cognito控制台为用户池添加Lambda触发器: 1. 登录Cognito控制台,选择要为其添加触发器的用户池。 2. 点击“用户池属性”选项卡。 3. 在“Lambda触发器”部分,点击“添加Lambda触发器”。 4. 选择触发器的类别,比如“注册前”或“身份验证后”等。这将决定触发器在什么情况下被调用。 5. 点击“分配Lambda函数”,选择与该用户池位于同一AWS区域的Lambda函数。 6. 点击“保存更改”。 这样Cognito就会在所选的事件发生时调用配置的Lambda函数。您还需要确保Lambda函数具有正确的执行角色和权限,以访问Cognito并进行所需的处理。 在控制台上添加触发器后,Cognito会自动向Lambda函数添加资源策略,允许被调用。如果是以编程方式添加触发器,您可能需要手动添加策略以授予Cognito调用权限。 总体来说,在控制台上操作简单直观。选择触发器类别,选择Lambda函数,保存更改,Cognito和Lambda之间的交互就配置完成了。", -https://docs.aws.amazon.com/zh_cn/lambda/latest/dg/with-kinesis.html#services-kinesis-eventsourcemapping,https://docs.aws.amazon.com/zh_cn/lambda/latest/dg/with-kinesis.html#services-kinesis-eventsourcemapping,如何将Kinesis Data Streams配置为AWS Lambda的事件源?,要将Kinesis Data Streams配置为AWS Lambda的事件源,您可以按照以下步骤进行操作: 1. 在AWS控制台中,导航到Kinesis服务。 2. 创建一个新的数据流或使用现有的数据流。 3. 在数据流的管理页面中,选择“事件源”选项卡。 4. 单击“创建应用程序”并输入应用程序的名称和描述。 5. 在“事件源”部分,选择“Lambda”作为事件源类型。 6. 选择您希望Lambda函数监听的Kinesis数据流。 7. 在“事件规则”部分,定义事件规则以定义Lambda函数何时被触发。您可以指定事件源(如数据记录)以及触发条件(如数据记录的大小或时间戳)。 8. 在“Lambda函数”部分,选择您希望使用的Lambda函数。您可以使用现有的Lambda函数或定义自己的Lambda函数。 9. 配置Lambda函数的执行角色,以便它可以访问所需的AWS资源。 10. 单击“创建应用程序”以完成配置。 这样,您就成功将Kinesis Data Streams配置为AWS Lambda的事件源。当Kinesis数据流中的事件满足定义的事件规则时,Lambda函数将被触发并执行相应的操作。,"[""https://docs.aws.amazon.com/pinpoint/latest/apireference/apps-application-id-eventstream.html"",""https://docs.aws.amazon.com/zh_cn/streams/latest/dev/tutorial-stock-data-lambda.html""]",TRUE,FALSE,,要将Kinesis Data Streams配置为AWS Lambda的事件源,请按照以下步骤操作: 1. 在Amazon Kinesis Console中,选择您的Amazon Kinesis数据流。 2. 点击“行为”选项卡,然后点击“允许”以启用事件源。 3. 在“事件源ARNCondition”字段中,输入Lambda函数的ARNCondition。 4. 单击“确定”以保存更改并创建事件源。 完成上述步骤后,您的Lambda函数现在可以将其事件发送到指定的Kinesis数据流。 注意:在创建事件源之前,您需要确保Lambda函数已正确授权来访问Kinesis数据流。这可以通过创建一个IAM角色并完成必要的权限分配来实现。,FALSE,,要将Kinesis Data Streams配置为AWS Lambda的事件源,您需要按照以下步骤进行操作: 1. 在Amazon Kinesis Console中创建或选择要使用的Kinesis Data Stream。 2. 创建一个Lambda函数并选择“Custom function”作为事件源类型。 3. 点击“Create function”按钮,然后选择“Create custom function”。 4. 输入Lambda函数的名称和描述信息,并选择“Authorization type”选项卡。 5. 在“Authorization type”选项卡中,选择“AWS Lambda Function”,然后输入您的Lambda函数的ARN。 6. 点击“Save”以保存Lambda函数的配置信息。 7. 现在,您可以继续配置Lambda函数的代码和触发器,以便将其与Kinesis Data Stream关联。 完成这些步骤后,当您在Kinesis Data Stream中生成数据时,该数据将自动发送到您的Lambda函数进行处理。,FALSE,,"根据背景知识,要将Kinesis Data Streams配置为AWS Lambda的事件源,可以按以下步骤操作: 1. 创建一个Kinesis数据流。 2. 创建一个IAM角色,赋予Lambda访问Kinesis数据流的权限。 3. 创建一个Lambda函数,选择Kinesis作为触发器,并指定刚才创建的IAM角色。 4. 在Lambda函数代码中,读取和处理Kinesis数据流中的事件数据。 5. 在数据生产者应用中,将数据记录写入Kinesis数据流。 6. Lambda会自动轮询Kinesis数据流,如果检测到新数据,就会调用Lambda函数来处理。 7. 在Lambda函数中读取并处理传递给事件的记录数据。 8. 数据经Lambda函数处理后,可以写入其他地方(S3等)进行存储。 这样就可以实现Kinesis Data Streams作为AWS Lambda的事件源,触发Lambda函数处理流式数据。",TRUE,,"根据背景知识,要将Kinesis Data Streams配置为AWS Lambda的事件源,可以按以下步骤操作: 1. 创建一个Kinesis数据流。 2. 创建一个IAM角色,赋予Lambda访问Kinesis数据流的权限。 3. 创建一个Lambda函数,选择Kinesis作为触发器,并指定刚才创建的IAM角色。 4. 在Lambda函数代码中,读取和处理Kinesis数据流中的事件数据。 5. 在数据生产者应用中,将数据记录写入Kinesis数据流。 6. Lambda会自动轮询Kinesis数据流,如果检测到新数据,就会调用Lambda函数来处理。 7. 在Lambda函数中读取并处理传递给事件的记录数据。 8. 数据经Lambda函数处理后,可以写入其他地方(S3等)进行存储。 这样就可以实现Kinesis Data Streams作为AWS Lambda的事件源,触发Lambda函数处理流式数据。", -https://docs.aws.amazon.com/zh_cn/aws-backup/latest/devguide/s3-backups.html,https://docs.aws.amazon.com/zh_cn/aws-backup/latest/devguide/s3-backups.html,AWS Backup 支持对 Amazon S3 存储桶进行连续备份吗?,"是的, AWS Backup支持对 Amazon S3 存储桶进行连续备份。","[""https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/userguide/backup-for-s3.html"",""https://docs.aws.amazon.com/zh_cn/aws-backup/latest/devguide/s3-backups.html""]",TRUE,TRUE,,是的,AWS Backup 支持对 Amazon S3 存储桶进行连续备份。连续备份允许您在任何时间恢复到特定的时间点,这对于数据恢复和灾难恢复非常重要。然而,请注意,连续备份的副本不具有 point-in-time 还原功能,而是提供完整备份的副本。,FALSE,,是的,AWS Backup 支持对 Amazon S3 存储桶进行连续备份。连续备份是一种实时跟踪 S3 存储桶数据更改的备份方式,允许您在保留期内随时恢复数据到任何时间点。您可以按照 1 小时、12 小时、1 天、1 周或 1 个月等频率安排定期备份。,FALSE,把连续备份和定期备份混在一起了,"是的,AWS Backup支持对Amazon S3存储桶进行连续备份。 连续备份允许您恢复到最近35天内的任何时间点。只能在一个备份计划中配置S3存储桶的连续备份。 完成现有数据的第一次完整备份后,系统会实时跟踪您的S3存储桶数据的更改。跟踪的更改允许您在连续备份的保留期内使用PITR(point-in-time恢复)。要执行还原作业,请选择要恢复到的时间点。 每次连续备份的保留期最长为35天。要使用AWS Backup进行连续备份,您必须先在S3存储桶上启用版本控制。 总之,AWS Backup支持对Amazon S3存储桶进行连续备份,这可以提供时点级别的恢复能力。但需要先启用版本控制,并且每个连续备份的保留期限制为35天。",TRUE,,AWS Backup支持对Amazon S3存储桶进行连续备份。 连续备份允许您恢复到最近35天内的任何时间点。只能在一个备份计划中配置S3存储桶的连续备份。, -https://docs.aws.amazon.com/zh_cn/kendra/latest/dg/getting-started-mysql.html,https://docs.aws.amazon.com/zh_cn/kendra/latest/dg/getting-started-mysql.html 或者 https://docs.aws.amazon.com/zh_cn/kendra/latest/dg/data-source-rds-mysql.html,如何在控制台配置Amazon Kendra使用RDS MySQL作为数据源?,要在控制台配置Amazon Kendra使用RDS MySQL作为数据源,您可以按照以下步骤操作: 1. 登录AWS Management Console并通过以下网址打开Amazon RDS控制台:https://console.aws.amazon.com/rds/ 2. 在导航窗格中,选择子网组,然后选择创建数据库子网组。 3. 命名群组并选择您的虚拟私有云 (VPC)。 4. 添加您的 VPC 的私有子网。您的私有子网是未连接到 NAT 的子网。选择创建。 5. 在导航窗格中,选择数据库,然后选择创建数据库。 6. 使用以下参数创建数据库。将所有其他参数保留为默认值。 - 引擎选项 — My SQL - 模板 — 免费套餐 - 凭证设置-输入并确认密码 - 在 “连接” 下,选择 “其他连接配置”。 - 子网组-选择您在步骤 4 中创建的子网组。 - VPC 安全组-选择包含您在 VPC 中创建的入站和出站规则的组。例如,DataSourceSecurityGroup。 - 在 “其他配置” 下,将初始数据库名称设置为 content。 7. 选择 Create database(创建数据库)。 8. 从数据库列表中选择您的新数据库。记下数据库端点。 9. 创建数据库后,必须创建一个用于存放文档的表。创建表不在这些说明的范围之内。创建表格时,请注意以下几点: - 数据库名称— content - 表名— documents - 列— ID Title、Body、和LastUpdate。如果需要,可以添加其他列。 现在您已经创建了 MySQL 数据库,可以为该数据库创建数据源。 要创建 MySQL 数据源,请按照以下步骤: 1. 登录AWS Management Console并通过 https://console.aws.amazon.com/kendra/home 打开Amazon Kendra控制台。 2. 在导航窗格中,选择索引,然后选择您的索引。 3. 选择添加数据源,然后选择 Amazon RDS。 4. 键入数据源的名称和描述,然后选择 “下一步”。 5. 选择 MySQL。 6. 在 “连接访问权限” 下,输入以下信息: - 端点 — 您之前创建的数据库的终端节点。 - 端口 — 数据库的端口号。对于 MySQL,默认值为 3306。 - 身份验证类型-选择 “新建”。 - 新的密钥容器名称-数据库凭证Secrets Manager容器的名称。 - 用户名 — 对数据库具有管理访问权限的用户的名称。 - 密码 — 用户的密码,然后选择保存身份验证。 - 数据库名称-content. - 表名-documents. - IAM 角色-选择创建新角色,然后键入该角色的名称。 7. 在列配置中输入以下内容: - 文档 ID 列名称 — ID - 文档标题列名称 — Title - 文档数据列名称 — Body 8. 在列变化检测中,输入以下内容: - 更改检测列 — LastUpdate 9. 在配置 VPC 和安全组中提供以下内容: - 在虚拟私有云 (VPC) 中,选择您的 VPC。 - 在子网中,选择您在 VPC 中创建的私有子网。 - 在 VPC 安全组中,选择包含您在 VPC for MySQL 数据库中创建的入站和出站规则的安全组。例如,DataSourceSecurityGroup。 10. 在 “设置同步运行时间表” 中,选择 “按需运行”,然后选择 “下一步”。 11. 在数据源字段映射中,选择下一步。 12. 检查您的数据源的配置,确保其正确无误。当你对一切都正确感到满意时,选择 Create。 Amazon RDS(Amazon Relational Database Service)是一项网络服务,可以更轻松地在AWS云中设置、操作和扩展关系数据库。如果您是Amazon RDS用户,则可以使用索Amazon Kendra引您的Amazon RDS (MySQL)数据源。Amazon Kendra数据源连接器支持 Amazon RDS MySQL 5.6、5.7 和 8.0。 要在控制台配置Amazon Kendra使用RDS MySQL作为数据源,请按照上述步骤进行操作。,"[""https://docs.aws.amazon.com/zh_cn/kendra/latest/dg/data-source-rds-mysql.html"",""https://docs.aws.amazon.com/zh_cn/kendra/latest/dg/getting-started-mysql.html""]",TRUE,TRUE,两个参考链接都对,要在控制台中配置Amazon Kendra使用RDS MySQL作为数据源,请按照以下步骤操作: 1. 登录到Amazon Kendra控制台。 2. 在左侧导航栏中,点击“索引”。 3. 在右上角,点击“添加数据源”。 4. 在弹出的菜单中,选择“Amazon RDS (MySQL)”。 5. 在下一个屏幕上,点击“添加数据源”。 6. 在“命名”和“描述”字段中输入数据源的名称和描述。 7. 选择适当的语言,然后点击“下一步”。 8. 在“定义访问权限和安全性”部分,输入数据库的主机名、端口、实例和身份验证信息。如果需要,可以设置虚拟私有云(VPC)和环境变量。 9. 选择适当的IAM角色,然后点击“下一步”。 10. 在“配置同步设置”部分,选择一个同步选项,然后设置同步频率,点击“下一步”。 11. 在“设置字段映射”部分,选择要映射到Amazon Kendra索引的字段,然后点击“下一步”。 12. 在“查看和创建”部分,检查您的设置,然后点击“添加数据源”。 一旦数据源创建成功,它将在“数据源”页面下方显示。,TRUE,,"要在控制台配置Amazon Kendra使用RDS MySQL作为数据源,您可以按照以下步骤进行操作: 1. 登录 AWS Management Console并打开 Amazon Kendra 控制台。 2. 在左侧导航窗格中,选择索引,然后从索引列表中选择要使用的索引。 3. 在入门页面上,选择添加数据源。 4. 在添加数据源页面上,选择Amazon RDS (MySQL)连接器,然后选择添加数据源。 5. 在指定数据源详细信息页面上,输入以下信息: - 在名称和描述中,在数据源名称中输入数据源的名称。可以包含连字符,但不能包含空格。 - (可选)描述-为您的数据源输入可选描述。 - 在语言中,表示默认语言 — 一种用于筛选文档以获取索引的语言。除非另行指定,否则语言默认为英语。在文档元数据中指定的语言会覆盖所选语言。 - 在 ""标签"" 中,“添加新标签 — 标签”,用于搜索和筛选您的资源或跟踪您的AWS成本。 - 点击 ""下一步""。 6. 在 ""定义访问权限和安全性"" 页面上,输入以下信息: - 在来源中,输入以下信息: - 主机-输入数据库主机名。 - 端口-输入数据库端口。 - 实例-输入数据库实例。 - 启用 SSL 证书位置-选择输入 SSL 证书文件的Amazon S3路径。 - 在 ""身份验证"" 中,输入以下信息: - AWSSecrets Managers@@ ecret —选择现有密钥或创建新Secrets Manager密钥来存储您的Amazon RDS (MySQL)身份验证凭证。如果您选择创建新密钥,则会打开一个AWSSecrets Manager秘密窗口。 - 在 ""AWSSecrets Managers@@ ecret"" 中,输入以下信息: - 密钥名称-您的密钥的名称。前缀 ""AmazonKendra-Amazon RDS (MySQL)-"" 会自动添加到您的密钥名称中。 - 对于数据库用户名和密码-输入您从数据库中复制的身份验证凭据值。 - 点击 ""保存""。 7. 在 ""配置同步设置"" 页面上,输入以下信息: - 在 ""同步"" 范围内,从以下选项中进行选择: - SQL 查询-输入 SQL 查询语句,例如 SELECT 和 JOIN 操作。SQL 查询必须小于 32KB。 Amazon Kendra将抓取与您的查询相匹配的所有数据库内容。 - 主键列-提供数据库表的主键。这会标识数据库中的表。 - 标题列-提供数据库表中文档标题列的名称。 - 正文列-提供数据库表中文档正文列的名称。 - 在 ""其他配置 — 可选"" 中,从以下选项中选择以同步特定内容而不是同步所有文件: - 变更检测列-输入Amazon Kendra将用于检测内容变化的列的名称。 当其中任何一列发生变化时,将重新索引内容。 - “用户 ID” 列-输入包含允许访问内容的用户 ID 的列的名称。 - “组” 列-输入包含允许访问内容的群组的列的名称。 - 来源 URL 列-输入包含要编制索引的源 URL 的列的名称。 - 时间戳列-输入包含时间戳的列的名称。 Amazon Kendra使用时间戳信息来检测内容的变化并仅同步已更改的内容。 - 时区列-输入列的名称,该列包含要搜索的内容的时区。 - 时间戳格式-输入列的名称,该列包含用于检测内容更改和重新同步内容的时间戳格式。 - 点击 ""下一步""。 8. 在 ""设置字段映射"" 页面上,输入以下信息: - 从生成的默认数据源字段(文档 ID、文档标题和来源 URL)中进行选择,以映射到Amazon Kendra索引字段。 - 添加字段-添加自定义数据源字段以创建要映射到的索引字段名称和字段数据类型。 - 点击 ""下一步""。 9. 在 ""查看并创建"" 页面上,检查您输入的信息是否正确,然后选择添加数据源。您也可以选择从此页面编辑您的信息。成功添加数据源后,您的数据源将显示在 ""数据源"" 页面上。",TRUE,,"根据背景知识,要在Amazon Kendra控制台中使用RDS MySQL作为数据源,可以按以下步骤操作: 1. 登录AWS管理控制台,打开Amazon Kendra控制台。 2. 在左侧导航窗格中,选择""索引"",然后从索引列表中选择要使用的索引。 3. 在入门页面上,选择""添加数据源""。 4. 在添加数据源页面上,选择""RDS MySQL""连接器,然后选择""添加数据源""。 5. 在""指定数据源详细信息""页面上,输入数据源名称和描述等信息。 6. 在""定义访问权限和安全性""页面上,输入RDS MySQL的主机、端口、实例等信息,以及身份验证信息。可以选择创建新的Secrets Manager密钥来存储身份验证凭据。 7. 在""配置同步设置""页面上,配置要同步的列,同步模式等信息。 8. 在""设置字段映射""页面上,映射RDS MySQL的数据源字段到Amazon Kendra索引字段。 9. 查看并确认配置信息,然后选择""添加数据源""完成添加。 10. 数据源添加成功后,它将显示在""数据源""页面上。 这样就可以在Amazon Kendra控制台中使用RDS MySQL作为数据源了。",TRUE,,"要在Amazon Kendra控制台中使用RDS MySQL作为数据源,可以按以下步骤操作: 1. 登录AWS管理控制台,打开Amazon Kendra控制台。 2. 在左侧导航窗格中,选择""索引"",然后从索引列表中选择要使用的索引。 3. 在入门页面上,选择""添加数据源""。 4. 在添加数据源页面上,选择""RDS MySQL""连接器,然后选择""添加数据源""。 5. 在""指定数据源详细信息""页面上,输入数据源名称和描述等信息。 6. 在""定义访问权限和安全性""页面上,输入RDS MySQL的主机、端口、实例等信息,以及身份验证信息。可以选择创建新的Secrets Manager密钥来存储身份验证凭据。 7. 在""配置同步设置""页面上,配置要同步的列,同步模式等信息。 8. 在""设置字段映射""页面上,映射RDS MySQL的数据源字段到Amazon Kendra索引字段。 9. 查看并确认配置信息,然后选择""添加数据源""完成添加。 10. 数据源添加成功后,它将显示在""数据源""页面上。 这样就可以在Amazon Kendra控制台中使用RDS MySQL作为数据源了。", -https://docs.aws.amazon.com/zh_cn/redshift/latest/APIReference/API_DescribeClusters.html#API_DescribeClusters_Examples,https://docs.aws.amazon.com/zh_cn/redshift/latest/APIReference/API_DescribeClusters.html#API_DescribeClusters_Examples,给我一个Amazon Redshift的DescribeClusters API的使用示例,以下是一个Amazon Redshift的DescribeClusters API的使用示例: ``` POST / HTTP/1.1 Host: redshift.us-east-2.amazonaws.com Content-Type: application/x-www-form-urlencoded Action=DescribeClusters&ClusterIdentifier=your_cluster_identifier ``` 其中,`ClusterIdentifier`是您要描述的Amazon Redshift集群的标识符。您还可以添加其他参数,如`MaxRecords`和`Marker`,根据需要提供。 请注意,您需要正确配置AWS凭证和访问密钥才能成功调用此API。,"[""https://docs.aws.amazon.com/redshift/latest/APIReference/API_DescribeClusterTracks.html"",""https://docs.aws.amazon.com/redshift/latest/APIReference/API_DescribeClusterSubnetGroups.html""]",FALSE,TRUE,,"以下是一个使用Amazon Redshift的DescribeClustersAPI的示例请求。这个请求将返回指定集群的所有信息,包括名称、状态、创建时间等。 ``` https://redshift.us-west-2.amazonaws.com/ ?Action=DescribeClusters &SignatureMethod=HmacSHA256&SignatureVersion=4 &Version=2012-12-01 &X-Amz-Algorithm=AWS4-HMAC-SHA256 &X-Amz-Credential=AKIAIOSFODNN7EXAMPLE/20190817/us-west-2/redshift/aws4_request &X-Amz-Date=20190825T160000Z &X-Amz-SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date &X-Amz-Signature=0aa1234bb5cc678ddddd901ee2ff3aa45678b90c12d345e6ff789012345a6b7b &ClusterIdentifier=myclusteridentifier ``` ``` myclusteridentifier 2019-08-25T16:00:00.000Z node.type-1 1 available 363f3c7e-2832-11ea-8397-219d1980588b ``` 在这个示例中,您需要将`ClusterIdentifier`参数替换为您要描述的集群的标识符。此外,由于Amazon RedshiftAPI使用SSL结束点(在上面的URL中的'https'前缀),因此您需要在您的代码中使用适当的SSL库来发起HTTPS请求。",TRUE,,"以下是一个使用Amazon Redshift的DescribeClusters API的使用示例: ```bash $ aws redshift describe-clusters \ --region us-west-2 \ --query ""Clusters[].{ClusterName:Name,ClusterStatus:Status}"" ``` 这个命令会返回一个名为“name”和“status”的数组,其中包含了指定区域的Amazon Redshift集群列表。每个元素都是一个包含集群名称(“name”)和状态(“status”)的字典对象。",FALSE,,"这里是一个使用DescribeClusters API的示例: ```python import boto3 client = boto3.client('redshift') response = client.describe_clusters() print(response['Clusters']) ``` 这个示例使用boto3 Python SDK连接到Amazon Redshift,调用DescribeClusters API,并打印返回的集群信息。 主要步骤是: 1. 导入boto3模块,并创建一个redshift客户端。 2. 调用describe_clusters()方法,这将发送DescribeClusters API请求。 3. 从返回的响应中打印出'Clusters'键对应的值,这包含了集群信息列表。 每个集群都包含了诸如集群标识符、节点类型、状态、安全和网络组等详细信息。 你也可以传入特定的集群标识符来获取单个集群的信息,或者添加其他可选参数来过滤结果,例如集群状态或标签。 这个API非常有用的一点是可以用来监控你的Redshift集群的状态和运行情况。",TRUE,Redshift.Client.describe_clusters() boto3文档:https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/redshift/client/describe_clusters.html,"https://redshift.us-east-2.amazonaws.com/ ?Action=DescribeClusters &SignatureMethod=HmacSHA256&SignatureVersion=4&Version=2012-12-01&X-Amz-Algorithm=AWS4-HMAC-SHA256 &X-Amz-Credential=AKIAIOSFODNN7EXAMPLE/20190817/us-east-2/redshift/aws4_request &X-Amz-Date=20190825T160000Z &X-Amz-SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date &X-Amz-Signature=0aa1234bb5cc678ddddd901ee2ff3aa45678b90c12d345e6ff789012345a6b7b - - -或者 - - - ```python import boto3 client = boto3.client('redshift') response = client.describe_clusters() print(response['Clusters']) ``` - - -或者 - - - ```aws redshift describe-clusters ```",这个GroundTruth不太好给,因为API和参数组合有很多 -https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/APIReference/API_CopyImage.html,https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/APIReference/API_CopyImage.html,将AMI从一个区域复制到另一个区域的API是什么?,将AMI从一个区域复制到另一个区域的API是CopyImage.,"[""https://docs.aws.amazon.com/dlm/latest/APIReference/API_CrossRegionCopyAction.html"",""https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CopyImage.html""]",TRUE,TRUE,,要将AMI从一个区域复制到另一个区域,您需要使用以下请求参数: - SourceRegion:指定源区域的名称。 - DestinationOutpostArn:指定目标Outpost的ARN(如果将从AWS区域复制到Outpost)。 - DestinationRegion:指定目标区域的终结点。 这些参数应与“action=copyimage”一起使用,并通过API完成请求。,FALSE,,将AMI从一个区域复制到另一个区域的API是`CopyImage`。这个API允许你指定源区域和目标区域,以及一些其他参数,然后从源区域复制一个AMI到目标区域。你可以选择将加密的备份快照或非加密的备份快照复制过去,并且可以指定是否使用特定KMS密钥进行加密。,TRUE,,"CopyImage API可用于将AMI从一个AWS区域复制到另一个区域。 主要参数包括: - SourceRegion - 源AMI所在的区域 - SourceImageId - 要复制的源AMI ID - Name - 目标AMI的名称 - Description - 目标AMI的描述 - DestinationRegion - 目标AMI所在的区域,通过终端节点指定 例如: ``` https://ec2.amazonaws.com/?Action=CopyImage &SourceRegion=us-west-2 &SourceImageId=ami-1a2b3c4d &Name=My-AMI-Copy &Description=Copy of AMI ami-1a2b3c4d &DestinationRegion=us-east-1 ``` 调用CopyImage后,响应中会返回新复制的目标AMI的ID。",FALSE,没有这个参数,CopyImage API可用于将AMI从一个AWS区域复制到另一个区域。 , -https://docs.aws.amazon.com/zh_cn/AmazonECS/latest/APIReference/API_RunTask.html,https://docs.aws.amazon.com/zh_cn/AmazonECS/latest/APIReference/API_RunTask.html,我想启动一个新的ECS task,应该使用什么API?,您可以使用StartTask API来启动一个新的ECS任务。,"[""https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_StartTask.html"",""https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_RunTask.html""]",TRUE,TRUE,,您应该使用[StartTask](https://docs.aws.org/AmazonECR/latest/APIReference/Api_StartTask.html) API。这个API可以帮助您在一个给定的亚马逊ECS集群中启动一个或多个任务。,TRUE,,要启动一个新的ECS task,可以使用AWS ECS的`RunTask` API。这个API可以帮助您在指定的Amazon ECS集群上运行一个任务定义。您需要指定一些参数,包括要运行的容器实例、要使用的任务定义以及一些其他设置。,TRUE,,"您可以使用Amazon ECS的RunTask或StartTask API来启动新的task。 RunTask API允许您启动使用指定的task definition的新task。ECS会为您放置task,或者您可以使用placement constraints和strategies来自定义task的放置。 StartTask API允许您在指定的container instance上启动task。 两者的主要区别是: - RunTask - ECS帮您放置task - StartTask - 您指定放置task的container instance 使用RunTask的请求语法: ``` { ""cluster"": ""string"", ""count"": number, ""group"": ""string"", ""launchType"": ""EC2""|""FARGATE""|""EXTERNAL"", ""networkConfiguration"": { ""awsvpcConfiguration"": { ""subnets"": [""string""], ""securityGroups"": [""string""], ""assignPublicIp"": ""ENABLED""|""DISABLED"" } }, ""overrides"": { ""containerOverrides"": [ { ""name"": ""string"", ""command"": [""string""], ""environment"": [ { ""name"": ""string"", ""value"": ""string"" } ], ... } ], ""cpu"": ""string"", ""memory"": ""string"", ... }, ""placementConstraints"": [ { ""type"": ""distinctInstance""|""memberOf"", ""expression"": ""string"" } ], ""placementStrategy"": [ { ""type"": ""random""|""spread""|""binpack"", ""field"": ""string"" } ], ""taskDefinition"": ""string"" } ``` 使用StartTask的请求语法: ``` { ""cluster"": ""string"", ""containerInstances"": [""string""], ""enableECSManagedTags"": true|false, ""group"": ""string"", ""networkConfiguration"": { ""awsvpcConfiguration"": { ""subnets"": [""string""], ""securityGroups"": [""string""], ""assignPublicIp"": ""ENABLED""|""DISABLED"" } }, ""overrides"": { ""containerOverrides"": [ { ""name"": ""string"", ""command"": [""string""], ""environment"": [ { ""name"": ""string"", ""value"": ""string"" } ] } ], ""cpu"": ""string"", ""memory"": ""string"" }, ""propagateTags"": ""TASK_DEFINITION""|""SERVICE""|""NONE"", ""referenceId"": ""string"", ""startedBy"": ""string"", ""tags"": [ { ""key"": ""string"", ""value"": ""string"" } ], ""taskDefinition"": ""string"" } ``` 所以如果您想启动并自行放置task,请使用StartTask API。如果您想让ECS帮您放置task,请使用RunTask API。",TRUE,,可以使用Amazon ECS的RunTask或StartTask API来启动新的task。 , -https://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/APIReference/API_UpdateTimeToLive.html,https://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/APIReference/API_UpdateTimeToLive.html,如何通过API为DynamoDB某个表启用生存时间(TTL)?,"您可以通过以下方式通过API为DynamoDB某个表启用生存时间(TTL): ``` { ""TableName"": ""string"", ""TimeToLiveSpecification"": { ""AttributeName"": ""string"", ""Enabled"": boolean } } ``` 您需要提供表名(TableName)和要配置的TTL属性的名称(AttributeName),以及是否启用TTL(Enabled)为true或false。 请注意,此请求中的参数名称和类型仅供参考,实际使用时应根据您的需求进行调整。 希望这对您有所帮助!","[""https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeTimeToLive.html"",""https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTimeToLive.html""]",TRUE,TRUE,,"要为DynamoDB的某个表启用生存时间(TTL),可以使用UpdateTimeToLive操作。这个操作的请求语法如下: ``` { ""[TableName](#DDB-UpdateTimeToLive-request-TableName)"": ""`string`"", ""[TimeToLiveSpecification](#DDB-UpdateTimeToLive-request-TimeToLiveSpecification)"": { ""[AttributeName](./API_TimeToLiveSpecification.html#DDB-Type-TimeToLiveSpecification-AttributeName)"": ""`string`"", ""[Enabled](./API_TimeToLiveSpecification.html#DDB-Type-TimeToLiveSpecification-Enabled)"": `boolean` } } ``` 其中,TableName是要设置的表的名称,TimeToLiveSpecification包含了用于启用或禁用生存时间的设置。 在请求参数中,需要提供TableName和TimeToLiveSpecification。如果成功执行此操作,DynamoDB将在最多一小时内完成更改处理。在这段时间内,对于同一表的任何其他UpdateTimeToLive调用将导致ValidationException。 注意,生存时间功能会将当前时间(以自1970年1月1日UTC的秒数格式存储)与项的生存时间属性中的时间进行比较。如果存储在属性中的时间值小于当前时间,则将该项标记为过期并随后删除。 在完成此操作后,可以通过查询DescribeTimeToLive操作来检查生存是否已成功启用。",TRUE,,要使用API为DynamoDB某个表启用生存时间(TTL),可以通过以下步骤完成: 1. 调用UpdateTimeToLive方法。这个方法允许您启用或禁用指定表的生存时间功能。 2. 在请求中传递所需的参数。这些参数包括要更新的表名和要启用的生存时间设置。 3. 等待大约一小时的处理时间。在这段时间内,您不能对同一张表进行再次更新TTL的调用。 4. 如果更新成功,您将获得当前生存时间规格的信息作为响应的一部分。 通过执行以上步骤,您可以成功地为DynamoDB中的某个表启用生存时间功能。,TRUE,,"您可以通过调用UpdateTimeToLive API为DynamoDB表启用TTL。 主要步骤是: 1. 指定要启用TTL的表名,如""TableName"": ""mytable""。 2. 在TimeToLiveSpecification参数中指定启用TTL的详细信息: - AttributeName - 要作为TTL属性的属性名称,如""AttributeName"": ""ttl""。 - Enabled - 将其设置为true以启用TTL,""Enabled"": true。 3. 将上述JSON格式的请求体传递给UpdateTimeToLive API。 4. 如果成功,API将返回当前的TimeToLiveSpecification。 例如请求体: ```json { ""TableName"": ""mytable"", ""TimeToLiveSpecification"": { ""AttributeName"": ""ttl"", ""Enabled"": true } } ``` 这将在名为""mytable""的表上启用TTL,使用""ttl""属性作为TTL属性。 调用成功后,您可以通过DescribeTimeToLive API来确认TTL已被启用。",TRUE,,"要通过 API 为 DynamoDB 表启用生存时间(TTL),可以使用 UpdateTimeToLive API。 - -主要步骤是: - -1. 构造一个TimeToLiveSpecification对象,指定Enabled为true,并指定要用于TTL的属性名,例如""AttributeName"": ""ttl""。 - -2. 调用UpdateTimeToLive API,传入表名和TimeToLiveSpecification对象。 - -例如,使用Python的boto3库: - -```python -import boto3 - -dynamodb = boto3.client('dynamodb') - -response = dynamodb.update_time_to_live( - TableName='YourTableName', - TimeToLiveSpecification={ - 'Enabled': True, - 'AttributeName': 'ttl' - } -) -```", -https://docs.aws.amazon.com/zh_cn/iot/latest/apireference/API_DeleteThing.html,https://docs.aws.amazon.com/zh_cn/iot/latest/apireference/API_DeleteThing.html,AWS IoT删除thing的API是什么?,AWS IoT删除thing的API是DeleteThingShadow。,"[""https://repost.aws/questions/QUmW5H8JKUQDy5QGTOOdIS1g"",""https://docs.aws.amazon.com/iot/latest/apireference/API_iotdata_DeleteThingShadow.html""]",FALSE,FALSE,,要删除thing,可以使用AWS IoT Events发布的API。请求语法是: ``` DELETE /things/thingName/shadow?name=shadowName HTTP/1.1 ``` 其中,`thingName`是事物的名称,`shadowName`是要删除的阴影的名称。在响应中,如果操作成功,服务将返回HTTP 200。,FALSE,,"AWS IoT发布了一个新的API,名为""batch-delete-detector"",用于批量删除探测器。这个API可以删除具有指定名称的阴影。您可以使用这个API来删除IoT事件检测器中的一个实例。",FALSE,,"您好,删除AWS IoT中thing shadow的API是DeleteThingShadow。 使用DeleteThingShadow API可以删除指定thing的shadow。主要步骤如下: 1. 构造DELETE请求,请求路径为/things/${thingName}/shadow?name=${shadowName} 2. thingName - 要删除shadow的thing名称 3. shadowName - 要删除的shadow名称 4. 发送DELETE请求。如果成功,API返回HTTP 200状态码 5. 返回的响应体包含删除的shadow信息 一个示例请求如下: ``` DELETE /things/MyDevice/shadow?name=desired HTTP/1.1 Host: mysite.iot.us-east-1.amazonaws.com ``` 如果成功,响应如下: ``` HTTP/1.1 200 OK { ""state"": { ""reported"": { ""temperature"": ""20C"" } }, ""metadata"": { ""reported"": { ""temperature"": { ""timestamp"": 1560956452 } } }, ""version"": 10, ""timestamp"": 1560956452 } ``` 总之,使用DeleteThingShadow API即可删除AWS IoT中thing的指定shadow。",FALSE,,AWS IoT Core中删除thing类型的API是DeleteThing, -https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/APIReference/API_CreateSecurityGroup.html#API_CreateSecurityGroup_RequestParameters,https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/APIReference/API_CreateSecurityGroup.html#API_CreateSecurityGroup_RequestParameters,创建VPC安全组的API是什么?包含哪些参数?,创建VPC安全组的API是`CreateVpcSecurityGroup`。包含以下参数: - `VpcSecurityGroupId`:一个唯一标识符,用于标识VPC安全组。 - `SecurityGroupIdentifier`:一个唯一的标识符,用于标识安全组。 - `Description`:可选,一个可选的描述,用于描述安全组。 - `VpcSecurityGroupDescription`:可选,用于描述VPC安全组的描述。 - `VpcSecurityGroupEfaId`:可选,用于指定VPC安全组的EFA ID。 - `VpcSecurityGroupOwnerId`:可选,用于指定VPC安全组的拥有者ID。 - `VpcSecurityGroupPurpose`:可选,用于指定VPC安全组的用途。 - `VpcSecurityGroupVersionId`:可选,用于指定VPC安全组版本ID。 - `VpcSecurityGroupTags`:可选,用于指定VPC安全组的标签。 - `VpcSecurityGroupStatus`:可选,用于指定VPC安全组的当前状态。 请注意,以上参数是可选的,具体取决于您的需求和使用情况。,"[""https://docs.aws.amazon.com/redshift/latest/APIReference/API_VpcSecurityGroupMembership.html"",""https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_dax_SecurityGroupMembership.html""]",FALSE,FALSE,,创建VPC安全组的API是DescribeVpcSecurityGroups,它用于描述VPC安全组的成员。该API包含以下必需和可选参数: 1. Status:VPC安全组的状态。 2. VpcSecurityGroupId:VPC安全组的标识符。 注意:在使用此API时,请参阅相应的AWS SDK文档以获取语言特定的信息,例如AWS SDK for C++、AWS SDK for Go、AWS SDK for Java V2或AWS SDK for Ruby V3。,FALSE,,创建VPC安全组的API是CreateVpcSecurityGroup。该API包含以下参数: - **Status**(字符串类型):表示VPC安全组的状态。最大长度为2147483647,不是必需的。 - **VpcSecurityGroupId**(字符串类型):VPC安全组的唯一标识符。最大长度为2147483647,不是必需的。,FALSE,,"根据背景知识,创建VPC安全组的API应该是DescribeVpcSecurityGroupMemberships。 该API包含以下参数: - Status(字符串类型,非必需):安全组的状态。 - VpcSecurityGroupId(字符串类型,非必需):安全组的标识符。 另外,从描述中可以看出,该API用于描述VPC安全组的成员,而不是创建安全组。创建安全组的API应该是CreateVpcSecurityGroup。",FALSE,," -创建VPC安全组的API是CreateSecurityGroup。 - -它包含以下参数: - -- GroupName:安全组的名称。 - -- GroupDescription: 安全组的描述。 - -- VpcId: 安全组所属的VPC的ID。 - -- TagSpecifications: 为安全组指定标签的选项。", -https://docs.aws.amazon.com/zh_cn/waf/latest/APIReference/API_GetWebACL.html,https://docs.aws.amazon.com/zh_cn/waf/latest/APIReference/API_GetWebACL.html或https://docs.aws.amazon.com/zh_cn/waf/latest/APIReference/API_ListWebACLs.html,如何通过API查看AWS WAF的Web 访问控制列表 (Web ACL)?,"要通过API查看AWS WAF的Web 访问控制列表 (Web ACL),需要发送一个GET请求,请求参数为`WebACLId`。 请求数据: { ""WebACLId"": ""string"" } 根据文档,请提供`WebACLId`的值。","[""https://docs.aws.amazon.com/waf/latest/APIReference/API_waf_GetWebACL.html"",""https://docs.aws.amazon.com/securityhub/1.0/APIReference/API_AwsWafWebAclDetails.html""]",TRUE,FALSE,,"要使用API查看AWS WAF的Web 访问控制列表 (Web ACL),您需要执行以下步骤: 1. 首先,确保已安装适当的AWS SDK。例如,如果您使用的是Python,则需要安装Boto3库。 2. 然后,编写一个函数来执行GET请求以获取指定的Web ACL。这个函数的请求参数应该包括WebACLId,即要获取的Web ACL的唯一标识符。 3. 在成功获取到Web ACL后,您可以检查其各种属性和规则,如DefaultAction、Name、Rules等。 以下是一个使用Python Boto3库获取Web ACL的示例代码: ```python import boto3 def get_web_acl(web_acl_id): # 创建一个WAF客户端 waf = boto3.client('waf') # 发送GET请求以获取指定Web ACL的信息 response = waf.get_web_acl( WebACLId=web_acl_id ) # 输出Web ACL的相关信息 print(""Web ACL ID: "", response['WebACLId']) print(""Default Action: "", response['WebACL']['DefaultAction']) print(""Name: "", response['WebACL']['Name']) for rule in response['WebACL']['Rules']: print(""Rule ID: "", rule['RuleId']) print(""Action: "", rule['Action']) print(""Priority: "", rule['Priority']) web_acl_id = 'YOUR_WEB_ACL_ID' # 替换为您的Web ACL ID get_web_acl(web_acl_id) ``` 请注意,您需要在代码中替换'YOUR_WEB_ACL_ID'为实际的Web ACL ID。运行此代码将输出指定Web ACL的相关信息,如ID、默认操作、名称以及所有规则的ID、操作和优先级。",TRUE,,要查看AWS WAF的Web 访问控制列表(Web ACL),可以使用AWS提供的API。首先,需要确保已经创建了一个Web ACL并获得了其ID。然后,可以通过以下步骤进行查看: 1. 发送一个GET请求到AWS WAF的API端点,包含所需的Web ACL ID作为参数。 2. 在响应中,将返回包含Web ACL详细信息的数据结构。其中包括Web ACL的基本信息(如名称、描述等)以及规则的信息。 以下是一个示例代码片段,展示了如何使用Python的Boto3库来发送GET请求以获取Web ACL的细节: ```python import boto3 def get_web_acl(web_acl_id): # 创建连接和会话 session = boto3.Session() waf = session.client('waf') # 发送GET请求以获取指定的Web ACL response = waf.get_web_acl( WebACLId=web_acl_id ) return response['WebACL'] ``` 请注意,上述示例代码使用了Boto3库中的AWS WAF客户端来发送GET请求。您可以根据自己的需求选择使用其他编程语言的AWS SDK。,TRUE,,"您可以使用GetWebACL API来查看AWS WAF的Web访问控制列表(Web ACL)的详细信息。 主要步骤是: 1. 准备WebACLId - 这是要获取的Web ACL的唯一标识符。您可以通过ListWebACLs API获取WebACLId。 2. 调用GetWebACL API,传入WebACLId作为参数。 3. GetWebACL返回一个WebACL对象,包含了该Web ACL的详细信息,比如默认操作、规则、规则优先级等。 4. 从返回的WebACL对象中您可以获取该Web ACL的各种配置信息。 例如,使用Python SDK: ```python import boto3 waf = boto3.client('waf') web_acl_id = 'abcd1234-abcd-1234-abcd-1234abcd1234' response = waf.get_web_acl(WebACLId=web_acl_id) print(response['WebACL']) ``` 这将打印出指定Web ACL的完整信息。 所以在AWS WAF中,使用GetWebACL API可以方便地查看Web ACL的配置详情。",TRUE,,可以使用GetWebACL 或者 ListWebACLs API来查看AWS WAF的Web访问控制列表(Web ACL)的信息。 , -https://docs.aws.amazon.com/zh_cn/lambda/latest/dg/API_CreateAlias.html,https://docs.aws.amazon.com/zh_cn/lambda/latest/dg/API_CreateAlias.html,我想为 Lambda 函数版本创建别名,应该使用什么API?,为 Lambda 函数版本创建别名,应该使用CreateAlias API。,"[""https://docs.aws.amazon.com/zh_cn/lambda/latest/dg/API_CreateAlias.html"",""https://docs.aws.amazon.com/zh_cn/lambda/latest/dg/API_AliasConfiguration.html""]",TRUE,TRUE,,要为 Lambda 函数版本创建别名,您应该使用 POST /2015-03-31/functions/`FunctionName`/aliases HTTP/1.1 请求。在这个请求中,您需要包含别名描述、要调用的函数版本、别名的名称以及可选的路由配置。,TRUE,,"要为 Lambda 函数版本创建别名,可以使用 AWS Lambda 管理器 API。你可以通过 POST 请求到 ""/2015-03-31/functions//aliases"" 来创建别名。",TRUE,,"您可以使用CreateAlias API来为Lambda函数版本创建别名。 CreateAlias API允许您为Lambda函数版本创建一个别名。通过别名,您可以为客户端提供一个函数标识符,并且可以更新该标识符以调用不同的版本。您还可以使用RoutingConfig参数将别名映射到两个版本之间,以拆分调用请求。 CreateAlias API的语法如下: ``` POST /2015-03-31/functions/FunctionName/aliases { ""Name"": ""string"", ""FunctionVersion"": ""string"", ""Description"": ""string"", ""RoutingConfig"": { ""AdditionalVersionWeights"": { ""string"": number } } } ``` 其中: - FunctionName: Lambda函数的名称。 - Name: 别名的名称。 - FunctionVersion: 别名指向的函数版本。 - Description: 别名的描述。 - RoutingConfig: 别名的路由配置。 调用CreateAlias时需要指定函数名称、别名名称和函数版本。其他参数都是可选的。 例如,以下请求为my-function的$LATEST版本创建名为PROD的别名: ``` POST /2015-03-31/functions/my-function/aliases { ""Name"": ""PROD"", ""FunctionVersion"": ""$LATEST"" } ``` 这样就可以通过别名PROD来调用my-function的最新版本了。 所以如果要为Lambda函数版本创建别名,请使用CreateAlias API。",TRUE,,可以使用CreateAlias API来为Lambda函数版本创建别名。, -https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/API/API_CopyObject.html,https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/API/API_CopyObject.html,S3 CopyObject API最大可以复制多大的对象?,5 GB,"[""https://docs.aws.amazon.com/AmazonS3/latest/API/SOAPCopyObject.html"",""https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html""]",TRUE,TRUE,,S3 CopyObject API可以复制任意大小的对象。但是,如果您尝试复制超过5GB的文件,将会导致CopyObject请求失败,并返回HTTP Status 400错误。这是因为Amazon S3限制单个CopyObject请求中要复制的对象大小不能超过5GB。为了解决这个问题,您需要将大文件分割成多个小文件,然后对每个小文件执行单独的CopyObject请求。,TRUE,,"The maximum size for a single copy operation is limited by the amount of data transfer allowed between two regions within the same geographic region. The limit varies depending on the AWS account, but typically ranges between 5 GB and 10 GB per copy operation. If you require larger transfers, consider using a different method such as multi-part upload or a different service like AWS Transfer Accelerator.",FALSE,,"根据S3 CopyObject API的文档,复制对象时有以下几点需要注意: 1. S3允许单个对象最大为5TB。使用CopyObject API可以在一个原子操作中复制最大5GB的对象。 2. 如果需要复制大于5GB的对象,必须使用分段上传的Upload Part - Copy API。 3. 对于所有复制请求,必须进行身份验证。另外,你必须对源对象有读权限,对目标存储桶有写权限。 4. 如果源对象的存储类是GLACIER或DEEP_ARCHIVE,或者源对象的存储类是INTELLIGENT_TIERING并且访问层是Archive Access或Deep Archive Access,你必须先恢复一个该对象的副本,然后才能将其用作复制操作的源对象。 5. CopyObject操作会根据指定的目标对象的存储类和区域进行收费。如果源存储类针对数据检索收费,该请求也可能导致数据检索费用。 所以简单来说,使用CopyObject API单次请求最大可以复制5GB的对象。如果需要复制超过5GB的大对象,必须使用分段上传的Upload Part - Copy API来实现。 另外在实际使用时,为了获得更好的性能,通常建议对较大对象使用分段上传,即使小于5GB。具体的分割大小可以根据对象大小、网络条件等因素确定。",TRUE,应该是 UploadPartCopy API,"根据S3 CopyObject API的文档,复制对象时有以下几点需要注意: 1. S3允许单个对象最大为5TB。使用CopyObject API可以在一个原子操作中复制最大5GB的对象。 2. 如果需要复制大于5GB的对象,必须使用分段上传的Upload Part - Copy API。 3. 对于所有复制请求,必须进行身份验证。另外,你必须对源对象有读权限,对目标存储桶有写权限。 4. 如果源对象的存储类是GLACIER或DEEP_ARCHIVE,或者源对象的存储类是INTELLIGENT_TIERING并且访问层是Archive Access或Deep Archive Access,你必须先恢复一个该对象的副本,然后才能将其用作复制操作的源对象。 5. CopyObject操作会根据指定的目标对象的存储类和区域进行收费。如果源存储类针对数据检索收费,该请求也可能导致数据检索费用。", -https://docs.aws.amazon.com/zh_cn/bedrock/latest/APIReference/API_runtime_InvokeModel.html,https://docs.aws.amazon.com/zh_cn/bedrock/latest/APIReference/API_runtime_InvokeModel.html 或者 https://docs.aws.amazon.com/zh_cn/bedrock/latest/APIReference/API_runtime_InvokeModelWithResponseStream.html,我想调用Amazon Bedrock中的基础模型,应该使用什么API?,"要调用Amazon Bedrock中的基础模型,您需要使用名为""InvokeModelWithResponseStream""的API。","[""https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_InvokeModelWithResponseStream.html"",""https://docs.aws.amazon.com/bedrock/latest/APIReference/welcome.html""]",TRUE,TRUE,,要调用Amazon Bedrock中的基础模型,您应该使用`POST /model/{modelId}/invoke-with-response-stream}` API。这个API允许您使用提供的输入运行基础模型的推断,并返回一个响应流。更多详细信息,请参阅Run inference部分。,TRUE,,要调用Amazon Bedrock中的基础模型,可以使用以下API: ``` POST /model/`modelId`/invoke-with-response-stream HTTP/1.1 ``` 其中,`modelId`是用于标识要调用的特定模型的ID。此API将返回一个响应流,其中包含每个批次的响应数据。 请注意,您需要在请求中指定所需的MIME类型,例如application/json或image/jpeg等。您还可以在请求中传递要传递给模型的数据。,TRUE,,"根据背景知识,要调用Amazon Bedrock中的基础模型运行推理,可以使用InvokeModelWithResponseStream API。 这个API允许你以流的形式发送输入并获取响应。要使用它,需要按如下格式发送请求: ``` POST /model/modelId/invoke-with-response-stream HTTP/1.1 X-Amzn-Bedrock-Accept: accept Content-Type: contentType body ``` 其中: - modelId: 基础模型的ID - accept: 响应的期望MIME类型,默认为application/json - contentType: 请求体的MIME类型,默认为application/json - body: 推理输入 响应将以流的形式返回,包含推理结果。 所以调用基础模型的基本步骤是: 1. 构造请求,指定模型ID、输入内容类型、期望的响应内容类型 2. 设置请求体为推理输入 3. 发送请求 4. 接收并处理响应流 使用AWS SDK也可以调用此API。总之,InvokeModelWithResponseStream API允许流式调用Bedrock基础模型。",TRUE,,"要调用Amazon Bedrock中的基础模型运行推理,可以使用InvokeModelWithResponseStream API 或者 InvokeModel API", \ No newline at end of file diff --git a/source/panel/auto_evaluation/llm_model.py b/source/panel/auto_evaluation/llm_model.py deleted file mode 100644 index 505b581a6..000000000 --- a/source/panel/auto_evaluation/llm_model.py +++ /dev/null @@ -1,97 +0,0 @@ -import boto3 -import json -import requests - - -class Claude2: - modelId = 'anthropic.claude-v2' - accept = 'application/json' - contentType = 'application/json' - client = None - region_name = 'us-east-1' - credentials_profile_name = 'default' - - default_generate_kwargs = { - "max_tokens_to_sample": 2000, - "temperature": 0.7, - "top_p": 0.9, - } - - @classmethod - def create_client(cls): - sess = boto3.Session( - profile_name=cls.credentials_profile_name, - region_name=cls.region_name - ) - bedrock = sess.client( - service_name='bedrock-runtime', - - ) - return bedrock - - @classmethod - def generate(cls,prompt,use_default_prompt_template=True,**generate_kwargs): - if cls.client is None: - cls.client = cls.create_client() - - generate_kwargs = dict(cls.default_generate_kwargs.copy(),**generate_kwargs) - if use_default_prompt_template: - prompt=f"\n\nHuman:{prompt}\n\nAssistant:" - - body = json.dumps(dict(generate_kwargs,prompt=prompt)) - - response = cls.client.invoke_model(body=body, modelId=cls.modelId, accept=cls.accept, contentType=cls.contentType) - - response_body = json.loads(response.get('body').read()) - # text - return response_body.get('completion') - - @classmethod - def batch_generate(cls,prompts,use_default_prompt_template=True,**generate_kwargs): - assert isinstance(prompts,list) - ret = [] - for prompt in prompts: - r = cls.generate( - prompt, - use_default_prompt_template = use_default_prompt_template, - **generate_kwargs - ) - ret.append(r) - return ret - - - -class ClaudeInstance(Claude2): - modelId = 'anthropic.claude-instant-v1' - - -class Claude21(Claude2): - modelId = 'anthropic.claude-v2:1' - -class CSDCDGRModel: - @staticmethod - def generate( - prompt, - dgr_url = None, - **generate_kwargs - ): - - json_data = { - "model": "knowledge_qa", - "messages": [ - { - "role": "user", - "content": prompt - } - ], - **generate_kwargs - } - - r = requests.post( - dgr_url, - json=json_data - ) - - if r.status_code != 200: - raise RuntimeError(r.json()) - return r.json() \ No newline at end of file diff --git a/source/panel/auto_evaluation/rag_metrics_with_claude2/__init__.py b/source/panel/auto_evaluation/rag_metrics_with_claude2/__init__.py deleted file mode 100644 index 12d9cde75..000000000 --- a/source/panel/auto_evaluation/rag_metrics_with_claude2/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from .context_precision import context_precision -from .context_recall import context_recall -from .faithfulness import faithfulness -from .answer_relevancy import answer_relevancy -from .answer_correctness import answer_correctness,answer_similarity -from .context_relevancy import context_relevancy - - diff --git a/source/panel/auto_evaluation/rag_metrics_with_claude2/answer_correctness.py b/source/panel/auto_evaluation/rag_metrics_with_claude2/answer_correctness.py deleted file mode 100644 index 6583368ed..000000000 --- a/source/panel/auto_evaluation/rag_metrics_with_claude2/answer_correctness.py +++ /dev/null @@ -1,22 +0,0 @@ -from datasets import Dataset -import re - -from langchain.embeddings import BedrockEmbeddings -from ragas.metrics import AnswerCorrectness -from ragas.metrics._answer_similarity import AnswerSimilarity -from .faithfulness import faithfulness - - -answer_correctness = AnswerCorrectness( - faithfulness = faithfulness, - answer_similarity = AnswerSimilarity(threshold=0) -) -answer_correctness.answer_similarity.embeddings = BedrockEmbeddings( - model_id = "cohere.embed-multilingual-v3" -) - -answer_similarity = AnswerSimilarity(threshold=0) -answer_similarity.embeddings = BedrockEmbeddings( - model_id = "cohere.embed-multilingual-v3" -) - diff --git a/source/panel/auto_evaluation/rag_metrics_with_claude2/answer_relevancy.py b/source/panel/auto_evaluation/rag_metrics_with_claude2/answer_relevancy.py deleted file mode 100644 index cd82fde48..000000000 --- a/source/panel/auto_evaluation/rag_metrics_with_claude2/answer_relevancy.py +++ /dev/null @@ -1,70 +0,0 @@ -import typing as t -from datasets import Dataset -from llm_model import Claude21 -import re - -from langchain.embeddings import BedrockEmbeddings -from ragas.metrics import AnswerRelevancy - - -CLAUDE_QUESTION_GEN="""\n\nHuman: -Generate question wrapped with tag for the given answer wrapped with tag. -The following context wrapped with tag is an example. - - -The PSLV-C56 mission is scheduled to be launched on Sunday, 30 July 2023 at 06:30 IST / 01:00 UTC. It will be launched from the Satish Dhawan Space Centre, Sriharikota, Andhra Pradesh, India - - - -When is the scheduled launch date and time for the PSLV-C56 mission, and where will it be launched from? - - - - -{answer} - - -\n\nAssistant: - -""" - - - -class ClaudeAnswerRelevancy(AnswerRelevancy): - embeddings = BedrockEmbeddings(model_id = "cohere.embed-multilingual-v3") - - def _score_batch( - self, - dataset: Dataset, - callbacks = None, - callback_group_name: str = "batch", - ) -> list[float]: - questions, answers = dataset["question"], dataset["answer"] - - results = [] - for ans in answers: - human_prompt = CLAUDE_QUESTION_GEN.format(answer=ans) - _questions = [] - for _ in range(self.strictness): - r = Claude21.generate( - prompt=human_prompt, - use_default_prompt_template=False - ) - r = '' + r - rets = re.findall('(.*?)',r,re.S) - rets = [ret.strip() for ret in rets] - if not rets and len(rets) > 1: - raise RuntimeError(f'invalid claude generation,prompt:\n{human_prompt}, \noutput: {r}') - _questions.append(rets[0]) - - results.append(_questions) - - scores = [] - for question, gen_questions in zip(questions, results): - cosine_sim = self.calculate_similarity(question, gen_questions) - scores.append(cosine_sim.mean()) - - return scores - - -answer_relevancy = ClaudeAnswerRelevancy() diff --git a/source/panel/auto_evaluation/rag_metrics_with_claude2/context_precision.py b/source/panel/auto_evaluation/rag_metrics_with_claude2/context_precision.py deleted file mode 100644 index a19fe58cb..000000000 --- a/source/panel/auto_evaluation/rag_metrics_with_claude2/context_precision.py +++ /dev/null @@ -1,86 +0,0 @@ -from ragas.metrics import ContextPrecision -import typing as t -from langchain.callbacks.manager import CallbackManager, trace_as_chain_group -from datasets import Dataset -from llm_model import Claude21 -import re -from utils.llm_utils.llm_models import Model -from langchain.prompts import ChatPromptTemplate -# from llm_model import Claude21 - -claude_model = Model.get_model( - model_id = "anthropic.claude-3-sonnet-20240229-v1:0", - model_kwargs={ - "max_tokens": 10000, - "temperature": 0.1 - } -) - - - -CLAUDE_CONTEXT_PRECISION = """Given a question wrapped with tag, and a context wrapped with tag, verify if the information in the given context is useful in answering the question. Return a Yes/No answer wrapped with tag. - -{question} - - - -{context} - - -Return a Yes/No answer wrapped with tag. -""" - -precision_prompt_template = ChatPromptTemplate.format_messages([ - ('user',CLAUDE_CONTEXT_PRECISION) -]) -class ClaudeContextprecision(ContextPrecision): - - def _score_batch( - self, - dataset: Dataset, - callbacks: t.Optional[CallbackManager] = None, - callback_group_name: str = "batch", - ) -> list: - prompts = [] - questions, contexts = dataset["question"], dataset["contexts"] - - for qstn, ctx in zip(questions, contexts): - human_prompts = [ - CLAUDE_CONTEXT_PRECISION.format( - question=qstn, - context=c - ) - for c in ctx - ] - prompts.append(human_prompts) - - responses: list[list[str]] = [] - for human_prompts in prompts: - response = [] - for prompt in human_prompts: - r = Claude21.generate( - prompt=prompt, - use_default_prompt_template=False - ) - r = '' + r - rets = re.findall('(.*?)',r,re.S) - rets = [ret.strip() for ret in rets] - if not rets and len(rets) > 1: - raise RuntimeError(f'invalid claude generation,prompt:\n{prompt}, \noutput: {r}') - response.append(r) - responses.append(response) - - scores = [] - - for response in responses: - response = [1 if "yes" in resp.lower() else 0 for resp in response] - # response = [int(any("yes" in r.lower() for r in resp)) for resp in response] - denominator = sum(response) + 1e-10 - numerator = sum(response) - - scores.append(numerator / denominator) - - return scores - - -context_precision = ClaudeContextprecision() \ No newline at end of file diff --git a/source/panel/auto_evaluation/rag_metrics_with_claude2/context_recall.py b/source/panel/auto_evaluation/rag_metrics_with_claude2/context_recall.py deleted file mode 100644 index 0a0c61416..000000000 --- a/source/panel/auto_evaluation/rag_metrics_with_claude2/context_recall.py +++ /dev/null @@ -1,420 +0,0 @@ -from ragas.metrics import ContextRecall -import typing as t -from langchain.callbacks.manager import CallbackManager, trace_as_chain_group -from datasets import Dataset -import re - -import xml.etree.ElementTree as ET -# from langchain.chat_models.bedrock import BedrockChat - -from utils.llm_utils.llm_models import Model -from langchain.prompts import ChatPromptTemplate -# from llm_model import Claude21 - -claude_model = Model.get_model( - model_id = "anthropic.claude-3-sonnet-20240229-v1:0", - model_kwargs={ - "max_tokens": 10000, - "temperature": 0.1 - } -) - - - -# CLAUDE_CONTEXT_RECALL_RA ="""Given a question wrapped with tag, a context wrapped with tag, and an answer wrapped with tag, analyze each sentence in the answer and classify if the sentence can be attributed to the given context or not. Output json with reason wrapped with tag. -# The following context wrapped with tag are two examples. - -# -# -# What can you tell me about albert Albert Einstein? -# - -# -# Albert Einstein (14 March 1879 – 18 April 1955) was a German-born theoretical physicist,widely held to be one of the greatest and most influential scientists of all time. Best known for developing the theory of relativity, he also made important contributions to quantum mechanics, and was thus a central figure in the revolutionary reshaping of the scientific understanding of nature that modern physics accomplished in the first decades of the twentieth century. His mass–energy equivalence formula E = mc2, which arises from relativity theory, has been called "the world's most famous equation". He received the 1921 Nobel Prize in Physics "for his services to theoretical physics, and especially for his discovery of the law of the photoelectric effect", a pivotal step in the development of quantum theory. His work is also known for its influence on the philosophy of science. In a 1999 poll of 130 leading physicists worldwide by the British journal Physics World, Einstein was ranked the greatest physicist of all time. His intellectual achievements and originality have made Einstein synonymous with genius. -# - -# -# Albert Einstein born in 14 March 1879 was German-born theoretical physicist, widely held to be one of the greatest and most influential scientists of all time. He received the 1921 Nobel Prize in Physics "for his services to theoretical physics. He published 4 papers in 1905. Einstein moved to Switzerland in 1895 -# - -# Here is my classification: -# -# [ -# {{ "statement_1":"Albert Einstein, born on 14 March 1879, was a German-born theoretical physicist, widely held to be one of the greatest and most influential scientists of all time.", -# "reason": "The date of birth of Einstein is mentioned clearly in the context.", -# "Attributed": "Yes" -# }}, -# {{ -# "statement_2":"He received the 1921 Nobel Prize in Physics 'for his services to theoretical physics.", -# "reason": "The exact sentence is present in the given context.", -# "Attributed": "Yes" -# }}, -# {{ -# "statement_3": "He published 4 papers in 1905.", -# "reason": "There is no mention about papers he wrote in the given context.", -# "Attributed": "No" -# }}, -# {{ -# "statement_4":"Einstein moved to Switzerland in 1895.", -# "reason": "There is no supporting evidence for this in the given context.", -# "Attributed": "No" -# }} -# ] -# -# - - -# -# -# who won 2020 icc world cup? -# - -# Who won the 2022 ICC Men's T20 World Cup? -# The 2022 ICC Men's T20 World Cup, held from October 16 to November 13, 2022, in Australia, was the eighth edition of the tournament. Originally scheduled for 2020, it was postponed due to the COVID-19 pandemic. England emerged victorious, defeating Pakistan by five wickets in the final to clinch their second ICC Men's T20 World Cup title. -# - - -# -# England -# - -# Here is my classification: -# -# [ -# {{ -# "statement_1":"England won the 2022 ICC Men's T20 World Cup.", -# "reason": "From context it is clear that England defeated Pakistan to win the World Cup.", -# "Attributed": "Yes" -# }} -# ] -# -# - -# -# {question} -# - -# -# {context} -# - -# -# {answer} -# -# """ - -# CLAUDA_CONTEXT_RECALL_RA= """Given a context, and an answer, analyze each sentence in the answer and classify if the sentence can be attributed to the given context or not. Output JSON with reason. -# Here are some examples of ideal JSON formatting: - - -# question: What can you tell me about albert Albert Einstein? -# context: Albert Einstein (14 March 1879 – 18 April 1955) was a German-born theoretical physicist,widely held to be one of the greatest and most influential scientists of all time. Best known for developing the theory of relativity, he also made important contributions to quantum mechanics, and was thus a central figure in the revolutionary reshaping of the scientific understanding of nature that modern physics accomplished in the first decades of the twentieth century. His mass–energy equivalence formula E = mc2, which arises from relativity theory, has been called "the world's most famous equation". He received the 1921 Nobel Prize in Physics "for his services to theoretical physics, and especially for his discovery of the law of the photoelectric effect", a pivotal step in the development of quantum theory. His work is also known for its influence on the philosophy of science. In a 1999 poll of 130 leading physicists worldwide by the British journal Physics World, Einstein was ranked the greatest physicist of all time. His intellectual achievements and originality have made Einstein synonymous with genius. -# answer: Albert Einstein born in 14 March 1879 was German-born theoretical physicist, widely held to be one of the greatest and most influential scientists of all time. He received the 1921 Nobel Prize in Physics "for his services to theoretical physics. He published 4 papers in 1905. Einstein moved to Switzerland in 1895 -# classification: -# [ -# {{ "statement_1":"Albert Einstein, born on 14 March 1879, was a German-born theoretical physicist, widely held to be one of the greatest and most influential scientists of all time.", -# "reason": "The date of birth of Einstein is mentioned clearly in the context.", -# "Attributed": "Yes" -# }}, -# {{ -# "statement_2":"He received the 1921 Nobel Prize in Physics 'for his services to theoretical physics.", -# "reason": "The exact sentence is present in the given context.", -# "Attributed": "Yes" -# }}, -# {{ -# "statement_3": "He published 4 papers in 1905.", -# "reason": "There is no mention about papers he wrote in the given context.", -# "Attributed": "No" -# }}, -# {{ -# "statement_4":"Einstein moved to Switzerland in 1895.", -# "reason": "There is no supporting evidence for this in the given context.", -# "Attributed": "No" -# }} -# ] - -# question: who won 2020 icc world cup? -# context: Who won the 2022 ICC Men's T20 World Cup? -# The 2022 ICC Men's T20 World Cup, held from October 16 to November 13, 2022, in Australia, was the eighth edition of the tournament. Originally scheduled for 2020, it was postponed due to the COVID-19 pandemic. England emerged victorious, defeating Pakistan by five wickets in the final to clinch their second ICC Men's T20 World Cup title. -# answer: England -# classification: -# [ -# {{ -# "statement_1":"England won the 2022 ICC Men's T20 World Cup.", -# "reason": "From context it is clear that England defeated Pakistan to win the World Cup.", -# "Attributed": "Yes" -# }} -# ] - - -# Now, given a context, and answer, please analyze each sentence in the answer and classify if the sentence can be attributed to the given context or not, following the formatting of the examples above. - -# question:{question} -# context:{context} -# answer:{answer} -# """ - - -CLAUDA_CONTEXT_RECALL_RA= """Given a question wrappered with ,a context wrappered with tag, and an answer wrappered with tag, analyze each sentence in the answer and classify if the sentence can be attributed to the given context or not. Output XML with reason. -Here are some examples of ideal XML formatting: - - -What can you tell me about albert Albert Einstein? - - - -Albert Einstein (14 March 1879 – 18 April 1955) was a German-born theoretical physicist,widely held to be one of the greatest and most influential scientists of all time. Best known for developing the theory of relativity, he also made important contributions to quantum mechanics, and was thus a central figure in the revolutionary reshaping of the scientific understanding of nature that modern physics accomplished in the first decades of the twentieth century. His mass–energy equivalence formula E = mc2, which arises from relativity theory, has been called "the world's most famous equation". He received the 1921 Nobel Prize in Physics "for his services to theoretical physics, and especially for his discovery of the law of the photoelectric effect", a pivotal step in the development of quantum theory. His work is also known for its influence on the philosophy of science. In a 1999 poll of 130 leading physicists worldwide by the British journal Physics World, Einstein was ranked the greatest physicist of all time. His intellectual achievements and originality have made Einstein synonymous with genius. - - - -Albert Einstein born in 14 March 1879 was German-born theoretical physicist, widely held to be one of the greatest and most influential scientists of all time. He received the 1921 Nobel Prize in Physics "for his services to theoretical physics. He published 4 papers in 1905. Einstein moved to Switzerland in 1895 - - - - - - Albert Einstein, born on 14 March 1879, was a German-born theoretical physicist, widely held to be one of the greatest and most influential scientists of all time. - - - The date of birth of Einstein is mentioned clearly in the context. - - - Yes - - - - - - He received the 1921 Nobel Prize in Physics 'for his services to theoretical physics. - - - The exact sentence is present in the given context. - - - Yes - - - - - - He published 4 papers in 1905. - - - There is no mention about papers he wrote in the given context. - - - No - - - - - - Einstein moved to Switzerland in 1895. - - - There is no supporting evidence for this in the given context. - - - No - - - - - - -who won 2020 icc world cup? - - - -Who won the 2022 ICC Men's T20 World Cup? -The 2022 ICC Men's T20 World Cup, held from October 16 to November 13, 2022, in Australia, was the eighth edition of the tournament. Originally scheduled for 2020, it was postponed due to the COVID-19 pandemic. England emerged victorious, defeating Pakistan by five wickets in the final to clinch their second ICC Men's T20 World Cup title. - - - -England - - - - - - England won the 2022 ICC Men's T20 World Cup. - - - From context it is clear that England defeated Pakistan to win the World Cup. - - - Yes - - - - - - -Now, given a new context, and answer, please analyze each sentence in the answer and classify if the sentence can be attributed to the given context or not, following the formatting of the examples above. - - -{question} - - - -{context} - - - -{answer} - -""" - - - - -# to_assistant_mouth = """classification:""" - -recall_prompt_template = ChatPromptTemplate.from_messages( - [ - ('user', CLAUDA_CONTEXT_RECALL_RA), - # ('assistant', to_assistant_mouth) - ] - -) - - -class ClaudeContextRacall(ContextRecall): - def _score_batch_helper( - self, - dataset: Dataset, - callbacks = None, - callback_group_name: str = "batch", - ) -> list: - prompts = [] - question, ground_truths, contexts = ( - dataset["question"], - dataset["ground_truths"], - dataset["contexts"], - ) - data = [] - for qstn, gt, ctx in zip(question, ground_truths, contexts): - - gt = "\n".join(gt) if isinstance(gt, list) else gt - ctx = "\n".join(ctx) if isinstance(ctx, list) else ctx - data.append({ - "question":qstn, - "context": ctx, - "answer": gt - }) - - # prompt = CLAUDE_CONTEXT_RECALL_RA.format( - # question=qstn, context=ctx, answer=gt - # ) - # prompts.append(prompt) - - responses: list[str] = [] - for datum in data: - prompt = str(recall_prompt_template.invoke(datum)) - r = (recall_prompt_template | claude_model).invoke(datum).content - - # pattern = "\[\s*\{.*?\}(\s*,\s*\{.*?\})*\s*\]" - # match = re.search(pattern, r.replace("\n", "")) - - # if not match: - # raise RuntimeError(f'invalid claude generation,prompt:\n{prompt} \noutput: {r}') - - # r = eval(r[0]) - # denom = len(r) - # numerator = sum( - # item.get("Attributed").lower() == "yes" for item in response - # ) - # scores.append(numerator / denom) - - responses.append((prompt, r)) - - # r = Claude3Sonne.generate( - # prompt=prompt, - # use_default_prompt_template=False, - # temperature=0.0 - # ) - - # parser result - # r1 = '\n[' + r - # rets = re.findall('(.*?)',r1,re.S) - # rets = [ret.strip() for ret in rets] - # if not rets and len(rets) > 1: - # # rets = re.findall('(.*?)',r,re.S) - # # if not rets and len(rets) > 1: - # raise RuntimeError(f'invalid claude generation,prompt:\n{prompt}, \noutput: {r}') - # responses.append((prompt,rets[0])) - - scores = [] - for prompt,res in responses: - try: - # r = re.findall('.*?',res,re.S) - # assert len(r) == 1 - # classification_str = r[0] - # from lxml import etree - # parser = etree.XMLParser(recover=True) - # root = etree.fromstring(classification_str, parser=parser) - # # root = ET.fromstring(classification_str) - # classifies = root.findall('./classify') - - response = [] - statements = [i.strip() for i in re.findall("(.*?)",res,re.S)] - reasons = [i.strip() for i in re.findall("(.*?)",res,re.S)] - attributeds = [i.strip() for i in re.findall("(.*?)",res,re.S)] - - for statement,reason,attributed in zip(statements,reasons,attributeds): - response.append( - { - "statement": statement, - "reason": reason, - "Attributed": attributed - } - ) - - - # for classifie in classifies: - # statement = classifie.findall('statement')[0].text.strip() - # reason = classifie.findall('reason')[0].text.strip() - # attributed = classifie.findall('Attributed')[0].text.strip() - # response.append( - # { - # "statement": statement, - # "reason": reason, - # "Attributed": attributed - # } - # ) - - denom = len(response) - numerator = sum( - item.get("Attributed").lower() == "yes" for item in response - ) - scores.append(numerator / denom) - except: - raise RuntimeError(f'invalid claude generation,prompt:\n{prompt}, \noutput: {res}') - - # scores = [] - # for prompt,res in responses: - # try: - # response = eval(res) - # denom = len(response) - # numerator = sum( - # item.get("Attributed").lower() == "yes" for item in response - # ) - # scores.append(numerator / denom) - # except: - # raise RuntimeError(f'invalid claude generation,prompt:\n{prompt}, \noutput: {res}') - - return scores - - def _score_batch( - self, - dataset: Dataset, - callbacks = None, - callback_group_name: str = "batch" - ) -> list: - return self._score_batch_helper( - dataset=dataset, - callbacks=callbacks, - callback_group_name=callback_group_name - ) - -context_recall = ClaudeContextRacall() \ No newline at end of file diff --git a/source/panel/auto_evaluation/rag_metrics_with_claude2/context_relevancy.py b/source/panel/auto_evaluation/rag_metrics_with_claude2/context_relevancy.py deleted file mode 100644 index d49bbcbbf..000000000 --- a/source/panel/auto_evaluation/rag_metrics_with_claude2/context_relevancy.py +++ /dev/null @@ -1,77 +0,0 @@ -import typing as t -from datasets import Dataset -from llm_model import Claude21 -import re -import numpy as np - -from ragas.metrics import ContextRelevancy as _ContextRelevancy -from ragas.metrics._context_relevancy import sent_tokenize - - -CLAUDE_CONTEXT_RELEVANCE = """\n\nHuman: -Please extract relevant sentences wrapped with tag from the provided context wrapped with tag, that is absolutely required answer the following question wrapped with tag. If no relevant sentences are found, or if you believe the question cannot be answered from the given context, return the phrase "Insufficient Information". While extracting candidate sentences you're not allowed to make any changes to sentences from given context. - - -{question} - - - -{context} - - -\n\nAssistant: - -""" - - -class ContextRelevancy(_ContextRelevancy): - def _score_batch( - self, - dataset: Dataset, - callbacks = None, - callback_group_name= "batch", - ) -> list[float]: - questions, contexts = dataset["question"], dataset["contexts"] - responses: list[str] = [] - - for q,c in zip(questions, contexts): - human_prompt = CLAUDE_CONTEXT_RELEVANCE.format( - question=q, context="\n".join(c) - ) - r = Claude21.generate( - prompt=human_prompt, - use_default_prompt_template=False - ) - r = '' + r - rets = re.findall('(.*?)',r,re.S) - rets = [ret.strip() for ret in rets] - - if not rets and len(rets) > 1: - raise RuntimeError(f'invalid claude generation,prompt:\n{human_prompt}, \noutput: {r}') - - responses.append([rets[0]]) - - - print(responses) - scores = [] - for context, n_response in zip(contexts, responses): - context = "\n".join(context) - overlap_scores = [] - context_sents = sent_tokenize(context) - for output in n_response: - indices = ( - sent_tokenize(output.strip()) - if output.lower() != "insufficient information." - else [] - ) - if len(context_sents) == 0: - score = 0 - else: - score = min(len(indices) / len(context_sents), 1) - overlap_scores.append(score) - scores.append(np.mean(overlap_scores)) - - return scores - - -context_relevancy = ContextRelevancy() \ No newline at end of file diff --git a/source/panel/auto_evaluation/rag_metrics_with_claude2/faithfulness.py b/source/panel/auto_evaluation/rag_metrics_with_claude2/faithfulness.py deleted file mode 100644 index c6ffc6004..000000000 --- a/source/panel/auto_evaluation/rag_metrics_with_claude2/faithfulness.py +++ /dev/null @@ -1,181 +0,0 @@ -from ragas.metrics import Faithfulness -import typing as t -from langchain.callbacks.manager import CallbackManager, trace_as_chain_group -from datasets import Dataset -from llm_model import Claude21 -import re -from tqdm import tqdm - - -# find statments from answer -CLAUDE_LONG_FORM_ANSWER_PROMPT = """\n\nHuman: -Given a question wrapped with tag and answer wrapped with tag, create one or more statements wrapped with tag from each sentence in the given answer. -The following context wrapped with tag are three examples. - - - -Who was Albert Einstein and what is he best known for? - - - -He was a German-born theoretical physicist, widely acknowledged to be one of the greatest and most influential physicists of all time. He was best known for developing the theory of relativity, he also made important contributions to the development of the theory of quantum mechanics. - - - -\nAlbert Einstein was born in Germany.\nAlbert Einstein was best known for his theory of relativity. - - - - - -Cadmium Chloride is slightly soluble in this chemical, it is also called what? - - - -alcohol - - - -\nCadmium Chloride is slightly soluble in alcohol. - - - - - -Were Shahul and Jithin of the same nationality? - - -They were from different countries. - - - -\nShahul and Jithin were from different countries. - - - - - -{question} - - - -{answer} - - -\n\nAssistant: -\n""" - - -CLAUDE_NLI_STATEMENTS_MESSAGE = """\n\nHuman: -Consider the given context wrapped with and following statements wrapped with , then determine whether they are supported by the information present in the context.Provide a brief explanation for each statement before arriving at the verdict (Yes/No). Provide a final verdict for each statement in order at the end in the given format. Do not deviate from the specified format. -The following context wrapped with tag is an example. - - -John is a student at XYZ University. He is pursuing a degree in Computer Science. He is enrolled in several courses this semester, including Data Structures, Algorithms, and Database Management. John is a diligent student and spends a significant amount of time studying and completing assignments. He often stays late in the library to work on his projects. - - - -1. John is majoring in Biology.\n2. John is taking a course on Artificial Intelligence.\n3. John is a dedicated student.\n4. John has a part-time job.\n5. John is interested in computer programming.\n - - - -1. John is majoring in Biology. -Explanation: John's major is explicitly mentioned as Computer Science. There is no information suggesting he is majoring in Biology. Verdict: No. -2. John is taking a course on Artificial Intelligence. -Explanation: The context mentions the courses John is currently enrolled in, and Artificial Intelligence is not mentioned. Therefore, it cannot be deduced that John is taking a course on AI. Verdict: No. -3. John is a dedicated student. -Explanation: The prompt states that he spends a significant amount of time studying and completing assignments. Additionally, it mentions that he often stays late in the library to work on his projects, which implies dedication. Verdict: Yes. -4. John has a part-time job. -Explanation: There is no information given in the context about John having a part-time job. Therefore, it cannot be deduced that John has a part-time job. Verdict: No. -5. John is interested in computer programming. -Explanation: The context states that John is pursuing a degree in Computer Science, which implies an interest in computer programming. Verdict: Yes. -Final verdict for each statement in order: No. No. Yes. No. Yes. - - - -{context} - - - -{statements} - - -\n\nAssistant: -\n -""" # noqa: E501 - - -class ClaudeFaithfulness(Faithfulness): - def _score_batch( - self, - ds: Dataset, - callbacks: t.Optional[CallbackManager] = None, - callback_group_name: str = "batch", - ) -> list[float]: - """ - returns the NLI score for each (q, c, a) pair - """ - question, answer, contexts = ds["question"], ds["answer"], ds["contexts"] - prompts = [] - list_statements: list[list[str]] = [] - - for q, a in tqdm(zip(question, answer),total=len(question)): - human_prompt = CLAUDE_LONG_FORM_ANSWER_PROMPT.format(question=q, answer=a) - prompts.append(human_prompt) - r = Claude21.generate( - prompt=human_prompt, - use_default_prompt_template=False, - ) - r = '\n' + r - rets = re.findall('(.*?)',r,re.S) - rets = [ret.strip() for ret in rets] - if not rets and len(rets) > 1: - raise RuntimeError(f'invalid claude generation,prompt:\n{human_prompt}, \noutput: {r}') - statements = rets[0].split("\n") - list_statements.append(statements) - - - outputs = [] - for context, statements in zip(contexts, list_statements): - statements_str: str = "\n".join( - [f"{i+1}.{st}" for i, st in enumerate(statements)] - ) - contexts_str: str = "\n".join(context) - human_prompt = CLAUDE_NLI_STATEMENTS_MESSAGE.format( - context=contexts_str, statements=statements_str - ) - r = Claude21.generate( - prompt=human_prompt, - use_default_prompt_template=False, - ) - r = '\n' + r - rets = re.findall('(.*?)',r,re.S) - rets = [ret.strip() for ret in rets] - if not rets and len(rets) > 1: - raise RuntimeError(f'invalid claude generation,prompt:\n{human_prompt}, \noutput: {r}') - outputs.append(rets[0]) - - scores = [] - final_answer = "Final verdict for each statement in order:" - final_answer = final_answer.lower() - for i, output in enumerate(outputs): - output = output.lower().strip() - if final_answer in output: - output = output[output.find(final_answer) + len(final_answer) :] - score = sum( - 0 if "yes" in answer else 1 - for answer in output.strip().split(".") - if answer != "" - ) - score = score / len(list_statements[i]) - else: - score = max(0, output.count("verdict: no")) / len( - list_statements[i] - ) - - scores.append(1 - score) - - return scores - - -faithfulness = ClaudeFaithfulness() diff --git a/source/panel/auto_evaluation/run_ragas_evaluation.py b/source/panel/auto_evaluation/run_ragas_evaluation.py deleted file mode 100644 index 849340222..000000000 --- a/source/panel/auto_evaluation/run_ragas_evaluation.py +++ /dev/null @@ -1,370 +0,0 @@ -""" -Note that the ragas version is 0.0.21 in current test -""" -import json -import sys -sys.path.append('../../lambda/executor') -import pandas as pd -from concurrent.futures import ThreadPoolExecutor -from concurrent.futures import as_completed -import traceback -from tqdm import tqdm -import pickle -import time -import requests -import os - -from dotenv import load_dotenv -load_dotenv() - -from ragas import evaluate -from datasets import Dataset -from ragas.metrics import ( - answer_relevancy, - context_precision, - context_recall, - faithfulness -) -from ragas.metrics._answer_correctness import answer_correctness,AnswerCorrectness -from ragas.metrics._answer_similarity import answer_similarity,AnswerSimilarity - -from rag_metrics_with_claude2 import context_recall as claude2_context_recall -from rag_metrics_with_claude2 import context_precision as claude2_context_precision -from rag_metrics_with_claude2 import faithfulness as claude2_faithfulness -from rag_metrics_with_claude2 import answer_relevancy as claude2_answer_relevancy -from rag_metrics_with_claude2 import answer_correctness as claude2_answer_correctness -from rag_metrics_with_claude2 import context_relevancy as claude2_context_relevancy -from rag_metrics_with_claude2 import answer_similarity as claude2_answer_similarity - - -try: - from websocket import create_connection -except ModuleNotFoundError: - os.system(f'{sys.executable} -m pip install websocket-client') - from websocket import create_connection -# RAGAS_EVAL_METRICS = [context_recall,answer_correctness,faithfulness] -# RAGAS_EVAL_METRICS = [claude2_context_recall] - - -def load_eval_data(eval_data_path): - data = pd.read_csv(eval_data_path).to_dict(orient='records') - ret = [] - for d in data: - ret.append({ - "question":d['question'], - "ground_truths": [d['ground truth']] - }) - return ret - - -def csdc_rag_call( - datum, - rag_api_url, - retry_times=3, - rag_parameters=None): - prompt = datum['question'] - json_data = { - "model": "knowledge_qa", - "messages": [ - { - "role": "user", - "content": prompt - } - ], - **rag_parameters - } - retry_time = 1 - while retry_time <= retry_times: - r = requests.post( - rag_api_url, - json=json_data - ) - if r.status_code == 200: - ret = r.json() - answer = ret['choices'][0]['message']['content'] - - contexts = [c['content'] for c in ret['contexts']] - - return { - "question": prompt, - "contexts": contexts, - "answer": answer, - "ground_truths": datum['ground_truths'] - } - print(f'retry time: {retry_time}/{retry_times}, meet error: {r.json()},prompt: {prompt}') - retry_time += 1 - time.sleep(10) - - raise RuntimeError(r.json()) - -def websocket_call( - datum, - ws_url=os.getenv('RAG_WS_URL'), - rag_parameters=None - ): - prompt = datum['question'] - ws = create_connection(ws_url) - body = { - "action": "sendMessage", - "model": "knowledge_qa", - "messages": [{"role": "user","content": prompt}], - # "temperature": 0.7, - "type" : "market_chain", - "enable_q_q_match": True, - "enable_debug": False, - # "llm_model_id":'anthropic.claude-v2:1', - } - body.update(**rag_parameters) - ws.send(json.dumps(body)) - start_time = time.time() - answer = "" - contexts = None - while True: - ret = json.loads(ws.recv()) - try: - message_type = ret['choices'][0]['message_type'] - except: - print(ret) - print(f'total time: {time.time()-start_time}' ) - raise - if message_type == "START": - continue - elif message_type == "CHUNK": - answer += ret['choices'][0]['message']['content'] - elif message_type == "END": - break - elif message_type == "ERROR": - raise RuntimeError(ret['choices'][0]['message']['content']) - elif message_type == "CONTEXT": - # contexts = ret - contexts = [i['doc'] for i in ret['choices'][0]['contexts']] - print('sources: ',ret['choices'][0]['knowledge_sources']) - ws.close() - return {"answer": answer, "contexts": contexts} - -def csdc_rag_call_stream(datum, - rag_api_url, - retry_times=3, - rag_parameters=None): - _ret = websocket_call(datum,rag_api_url,rag_parameters=rag_parameters) - ret = { - "question": datum['question'], - "ground_truths": datum['ground_truths'] - } - ret.update(_ret) - return ret - - -def get_rag_result(data, - rag_api_url=None, - num_worker=1, - stream=True, - rag_parameters=None, - ): - """_summary_ - - Args: - data (_type_): _description_ - rag_api_url (_type_, optional): _description_. Defaults to None. - num_worker (int, optional): _description_. Defaults to 1. - """ - rag_parameters = rag_parameters or {} - futures = [] - ret = [] - if stream: - func = csdc_rag_call_stream - else: - func = csdc_rag_call - with ThreadPoolExecutor(num_worker) as pool: - for datum in data: - # question = datum['question'] - - future = pool.submit(func,datum,rag_api_url,rag_parameters=rag_parameters) - future.datum = datum - futures.append(future) - # futures = [pool.submit(Claude2.generate,prompt) for prompt in prompts] - for future in tqdm(as_completed(futures),total=len(futures)): - try: - output_datum = future.result() - except: - print(traceback.format_exc(),flush=True) - output_datum = None - if output_datum is None: - datum = future.datum - datum['answer'] = None - ret.append(datum) - continue - ret.append(output_datum) - return ret - -def run_eval( - eval_data_path, - rag_api_url, - rag_num_worker=1, - llm_output_cache_path=None, - ret_save_profix = '', - # ragas_parameters: dict = None, - ragas_eval_metrics = None, - stream=True, - rag_parameters=None - ): - - # ragas_eval_llm_model_id = ragas_parameters['llm_model_id'] - # if ragas_eval_llm_model_id == "openai": - # assert os.getenv('OPENAI_API_KEY'), 'ragas evaluation needs openai api key' - - # ragas_parameters = ragas_parameters or {} - # load eval_data - if llm_output_cache_path is not None and \ - os.path.exists(llm_output_cache_path): - print(f'load cache llm output data: {llm_output_cache_path}') - with open(llm_output_cache_path,'rb') as f: - data_to_eval = pickle.load(f) - else: - print('loading data......') - data = load_eval_data(eval_data_path) - # get rag result - print(f'run rag, {len(data)} example......') - data_to_eval = get_rag_result( - data, - rag_api_url=rag_api_url, - num_worker=rag_num_worker, - stream=stream, - rag_parameters=rag_parameters - ) - print(data_to_eval[0]) - if llm_output_cache_path is not None: - print(f'save llm output to {llm_output_cache_path}') - with open(llm_output_cache_path,'wb') as f: - pickle.dump(data_to_eval,f) - - # call ragas - print(f'run ragas eval, data num: {len(data_to_eval)}') - # filter None answer - data_to_eval = [d for d in data_to_eval if \ - (d['answer'] is not None \ - and d['ground_truths'] and d['ground_truths'][0] is not None\ - and d['contexts'] \ - and isinstance(d['ground_truths'][0],str) - )] - print(f'run ragas eval, data num after filtered empty answer: {len(data_to_eval)}') - dataset = Dataset.from_pandas(pd.DataFrame(data_to_eval)) - results = evaluate( - dataset, - metrics=ragas_eval_metrics - ) - save_path = f'{ret_save_profix}_ragas_eval_res.csv' - print('saving ragas eval result to : ', save_path) - results.to_pandas().to_csv(save_path,index=False) - print('results: ',results) - return results - - -if __name__ == "__main__": - # RAGAS_EVAL_METRICS = [ - # AnswerCorrectness( - # answer_similarity=AnswerSimilarity(threshold=0), - # batch_size=15 - # ) - # ] - RAGAS_EVAL_METRICS = [ - claude2_context_recall - ] - - rag_api_url = os.getenv('RAG_API_URL') - - # eval_data_path = "TechBot QA Test-fifth-test.csv" - eval_data_path = "TechBot QA Test-fifth-test-sample-50.csv" - # eval_id = 'claude2-csds-retrive' - by = 'claude2-answer_correctness' #'claude2' - eval_id = f'claude2-csdc-retrive-by-{by}' - # llm_output_cache_path = f'{eval_id}-llm-output-cache-120.pkl' - # llm_output_cache_path = f'{eval_id}-llm-output-cache.pkl' - # llm_output_cache_path = "techbot_question_dgr_res_1_16_120_with_gt.pkl" - # llm_output_cache_path = "techbot_question_dgr_res_6_120_with_gt.pkl" - # llm_output_cache_path = "techbot_question_dgr_res_1_16_120_with_gt.pkl" - # llm_output_cache_path = "techbot_question_dgr_res_1_3_120_with_gt_context_1.pkl" - # llm_output_cache_path = "techbot_question_dgr_res_2_1_120_with_gt_context_1_with_whole_doc_baichuan2_13b_4bits.max_new_2000_token.pkl" - # llm_output_cache_path = "techbot_question_dgr_res_2_1_120_with_gt_context_1_with_whole_doc_baichuan2_13b_4bits.max_new_2000_token.pkl.internlm2-7b-hf-4bits.tranc.to.2048.pkl" - # llm_output_cache_path = "techbot_question_dgr_res_2_1_120_with_gt_context_1_with_whole_doc_baichuan2_13b_4bits.max_new_2000_token.pkl.internlm2-7b-hf-4bits.pkl" - # llm_output_cache_path = "techbot_question_dgr_res_2_1_120_with_gt_context_1_with_whole_doc_baichuan2_13b_4bits.max_new_2000_token.pkl.internlm2-20b-hf-4bits.trunc.2048.pkl" - # llm_output_cache_path = "techbot_question_dgr_res_2_1_120_with_gt_context_1_with_whole_doc_baichuan2_13b_4bits.max_new_2000_token.pkl.OrionStar-Yi-34B-Chat-Llama-AWQ.pkl" - # llm_output_cache_path = "techbot_question_dgr_res_2_1_120_with_gt_context_1_with_whole_doc_baichuan2_13b_4bits.max_new_2000_token.pkl.qianwen.72b.gptq.pkl" - # llm_output_cache_path = "techbot_question_dgr_res_2_1_120_with_gt_context_1_with_whole_doc_baichuan2_13b_4bits.max_new_2000_token.pkl.Yi-34B-Chat-hf-4bits.pkl" - # llm_output_cache_path = "techbot_question_dgr_res_2_1_120_with_gt_context_1_with_whole_doc_baichuan2_13b_4bits.max_new_2000_token.pkl.internlm2-20b-hf-4bits.g4dn.pkl" - # llm_output_cache_path = "techbot_question_dgr_res_1_23_120_with_gt_context_2_with_whole_doc.pkl" - llm_output_cache_path = "techbot_question_dgr_res_1_3_120_with_gt_context_1.pkl" - ret_save_profix = f'{eval_id}-{llm_output_cache_path}-eval' - # ragas_parameters = { - # "region_name":'us-west-2', - # "credentials_profile_name": "atl", - # # "llm_model_id": "anthropic.claude-v2:1", # "openai", #"anthropic.claude-v2:1", #"anthropic.claude-v2:1" - # "llm_model_generate_paramerters": { - # "max_tokens_to_sample": 2000 - # }, - # # "generator_llm_config":{ - # # "context_num":2 - # # } - # } - - # rag_parameters = { - # # 'llm_model_id': "anthropic.claude-v2:1", - # # 'llm_model_id': "anthropic.claude-v2:1", - # # "temperature": 0.7, - # # "enable_q_q_match": True, - # "get_contexts": True, - # "retriever_config":{ - # "using_whole_doc": True, - # "chunk_num": 4, - # "retriever_top_k": 20 - # }, - # "generator_llm_config":{ - # # "model_id": "anthropic.claude-instant-v1", - # "model_id": "anthropic.claude-v2:1", - # "model_kwargs":{ - # "max_tokens_to_sample": 2000, - # "temperature": 0.7, - # "top_p": 0.9 - # }, - # # "model_id": "anthropic.claude-v2:1", - # "context_num": 1 - # } - # } - rag_parameters = { - # 'llm_model_id': "anthropic.claude-v2:1", - # 'llm_model_id': "anthropic.claude-v2:1", - # "temperature": 0.7, - # "enable_q_q_match": True, - "get_contexts": True, - "retriever_config":{ - "using_whole_doc": True, - "chunk_num": 1, - "retriever_top_k": 20 - }, - "generator_llm_config":{ - # "model_id": "anthropic.claude-instant-v1", - "model_kwargs":{ - "max_new_tokens": 2000, - "temperature": 0.1, - "top_p": 0.9 - }, - "model_id":"anthropic.claude-v2:1", - # "model_id": "Baichuan2-13B-Chat-4bits", - # "endpoint_name": "baichuan2-13b-chat-4bits-2024-02-01-03-58-29-048", - "context_num": 1 - } - } - r = run_eval( - eval_data_path, - rag_api_url, - rag_num_worker=1, - llm_output_cache_path=llm_output_cache_path, - ret_save_profix=ret_save_profix, - # ragas_parameters=ragas_parameters, - ragas_eval_metrics = RAGAS_EVAL_METRICS, - stream=True, - rag_parameters=rag_parameters - ) - print(r) - - diff --git a/source/panel/evaluator/.env_sample b/source/panel/evaluator/.env_sample deleted file mode 100644 index 0b241f0e5..000000000 --- a/source/panel/evaluator/.env_sample +++ /dev/null @@ -1,7 +0,0 @@ -PIPELINE_URL='Check from CDK output' -S3_BUCKET_NAME='Check from CDK output' -GLUE_JOB_NAME='Check from CDK output' - -OPENAI_API_KEY= -OPENAI_API_BASE='https://api.openai.com/v1' -AOS_INDEX='chatbox-index' diff --git a/source/panel/evaluator/README.md b/source/panel/evaluator/README.md deleted file mode 100644 index 5721c0287..000000000 --- a/source/panel/evaluator/README.md +++ /dev/null @@ -1,70 +0,0 @@ -Execute the following commands to setup local Amazon Open Search running on docker. -''' -docker run -d -p 9200:9200 -p 9600:9600 -e "discovery.type=single-node" opensearchproject/opensearch:latest -''' - -Create the specified index -''' -curl -XPUT "https://localhost:9200/\_cluster/settings" -k -u 'admin:admin' -H 'Content-Type: application/json' -d' -{ -"persistent": { -"cluster.blocks.create_index": false -} -}' - -curl -XPUT "https://localhost:9200/llm-bot-index" -k -u 'admin:admin' -H 'Content-Type: application/json' -d' -{ -"settings": { -"index": { -"knn": true, -"knn.algo_param.ef_search": 512, -"refresh_interval": "60s", -"number_of_shards": 8, -"number_of_replicas": 0 -} -}, -"mappings": { -"properties": { -"vector_field": { -"type": "knn_vector", -"dimension": 1536, -"method": { -"name": "hnsw", -"space_type": "l2", -"engine": "nmslib", -"parameters": { -"ef_construction": 128, -"m": 16 -} -} -} -} -} -}' -''' - -Check if index actually indexed. -''' -curl -XGET "https://localhost:9200/\_search" -k -u 'admin:admin' -H 'Content-Type: application/json' -d' -{ -"query": { -"match_all": {} -} -}' -''' - -Remove the Read-Only Block in case the throttling error like [TOO_MANY_REQUESTS/12/disk usage exceeded flood-stage watermark, index has read-only-allow-delete block]'. -''' -curl -X PUT "http://localhost:9200/llm-bot-index/\_settings" -k -u 'admin:admin' -H "Content-Type: application/json" -d' -{ -"index.blocks.read_only_allow_delete": false -} -' - -du -ah -d 1 | sort -hr | head -n 10 //List disk usage sorted by size and remove the unwanted files to free up space. -''' - -Delete the index and start over if needed if all index messed up. -''' -curl -X DELETE "https://localhost:9200/llm-bot-index" -ku 'admin:admin' -''' diff --git a/source/panel/evaluator/__pycache__/prompts.cpython-38.pyc b/source/panel/evaluator/__pycache__/prompts.cpython-38.pyc deleted file mode 100644 index c462c49cb..000000000 Binary files a/source/panel/evaluator/__pycache__/prompts.cpython-38.pyc and /dev/null differ diff --git a/source/panel/evaluator/benchmark.ipynb b/source/panel/evaluator/benchmark.ipynb deleted file mode 100644 index 2ebcfff69..000000000 --- a/source/panel/evaluator/benchmark.ipynb +++ /dev/null @@ -1,117 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!pip install -U langchain" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - } - ], - "source": [ - "!export LANGCHAIN_TRACING_V2=true\n", - "!export LANGCHAIN_ENDPOINT=\"https://api.smith.langchain.com\"\n", - "!export LANGCHAIN_API_KEY=\"ls__991755ac40ff4af1b05a7ec2e89d978a\"\n", - "!export LANGCHAIN_PROJECT=\"CSDC-LLM-Bot\"\n", - "\n", - "!echo $LANGCHAIN_TRACING_V2" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "from langchain.chat_models import ChatOpenAI\n", - "# os.environ['OPENAI_API_KEY'] = \"sk-xxx\"\n", - "\n", - "os.environ['OPENAI_API_KEY'] = \"sk-xxx\"\n", - "\n", - "llm = ChatOpenAI(openai_api_key=\"sk-xxx\")\n", - "llm.invoke(\"Hello, world!\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from langsmith import Client\n", - "\n", - "example_inputs = [\n", - " (\"What is the largest mammal?\", \"The blue whale\"),\n", - " (\"What do mammals and birds have in common?\", \"They are both warm-blooded\"),\n", - " (\"What are reptiles known for?\", \"Having scales\"),\n", - " (\"What's the main characteristic of amphibians?\", \"They live both in water and on land\"),\n", - "]\n", - "\n", - "client = Client()\n", - "dataset_name = \"Elementary Animal Questions\"\n", - "\n", - "# Storing inputs in a dataset lets us\n", - "# run chains and LLMs over a shared set of examples.\n", - "dataset = client.create_dataset(\n", - " dataset_name=dataset_name, description=\"Questions and answers about animal phylogenetics.\",\n", - ")\n", - "for input_prompt, output_answer in example_inputs:\n", - " client.create_example(\n", - " inputs={\"question\": input_prompt},\n", - " outputs={\"answer\": output_answer},\n", - " dataset_id=dataset.id,\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "base", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.16" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/source/panel/evaluator/benchmark.py b/source/panel/evaluator/benchmark.py deleted file mode 100644 index 28f15fe04..000000000 --- a/source/panel/evaluator/benchmark.py +++ /dev/null @@ -1,1065 +0,0 @@ -import csv -import itertools -import json -import logging -import os -import time -from itertools import product -from typing import Any, Dict, Generator, Iterable, List, Optional, Tuple - -import boto3 -import matplotlib.pyplot as plt -import pandas as pd -import requests -import seaborn -from dotenv import load_dotenv -from langchain.chat_models import ChatOpenAI -from langchain.docstore.document import Document -from langchain.document_loaders import ( - UnstructuredFileLoader, - UnstructuredMarkdownLoader, -) -from langchain.embeddings import BedrockEmbeddings, OpenAIEmbeddings -from langchain.evaluation import EvaluatorType, load_evaluator -from langchain.llms.bedrock import Bedrock -from langchain.text_splitter import RecursiveCharacterTextSplitter -from langchain.vectorstores import FAISS, OpenSearchVectorSearch -from llm_bot_dep.loaders.markdown import CustomMarkdownLoader, process_md -from llm_bot_dep.loaders.nougat_pdf import NougatPDFLoader -from llm_bot_dep.sm_utils import ( - SagemakerEndpointVectorOrCross, - create_sagemaker_embeddings_from_js_model, -) -from llm_bot_dep.splitter_utils import MarkdownHeaderTextSplitter -from opensearchpy import RequestsHttpConnection -from ragas.llms import LangchainLLM -from ragas.testset import TestsetGenerator -from requests_aws4auth import AWS4Auth -from tenacity import retry, stop_after_attempt, wait_exponential - -# from langchain_core.language_models import BaseLanguageModel - - -load_dotenv(dotenv_path=".env") - -logging.basicConfig(level=logging.INFO) -logger = logging.getLogger(__name__) - -# set logger level to debug -logger.setLevel(logging.INFO) - -AOS_API_SUFFIX = "aos" -LLM_API_SUFFIX = "llm" -embeddingModelEndpoint = os.getenv("EMBEDDING_MODEL_ENDPOINT") -aosEndpoint = os.getenv("AOS_ENDPOINT") -region = os.getenv("REGION") -apiEndpoint = os.getenv("APIEndpointAddress") -openaiApiKey = os.getenv("OPENAI_API_KEY") -openaiApiBase = os.getenv("OPENAI_API_BASE") - -credentials = boto3.Session().get_credentials() -awsauth = AWS4Auth( - credentials.access_key, - credentials.secret_key, - region, - "es", - session_token=credentials.token, -) - -default_aos_index_name = "llm-bot-index" - -s3 = boto3.client("s3") -glue = boto3.client("glue") - -metadata_template = { - "content_type": "paragraph", - "current_heading": 0, - "heading_hierarchy": {}, - "figure_list": [], - "chunk_id": "$$", - "file_path": "", - "keywords": [], - "summary": "", -} - -# prerequisite for testdata generation using ragas, or using OpenAIEmbeddings but need to set the OPENAI_API_KEY/OPENAI_API_BASE in env -bedrock_client = boto3.client("bedrock-runtime", region_name="us-east-1") -bedrock_llm = Bedrock( - model_id="anthropic.claude-v2:1", - client=bedrock_client, - model_kwargs={"temperature": 0}, -) -_bedrock_embedding = BedrockEmbeddings( - model_id="amazon.titan-embed-text-v1", - region_name="us-east-1", - # model_id="cohere.embed-multilingual-v3", region_name="us-east-1" - # model_id = "amazon.titan-text-express-v1", region_name="us-east-1" -) - -_openai_embedding = OpenAIEmbeddings() - - -def csdc_markdown_loader(file_path: str) -> List[Document]: - # read content from file_path - with open(file_path, "r") as f: - file_content = f.read() - # placeholder for bucket and key - bucket = "default" - key = "default" - - loader = CustomMarkdownLoader(aws_path=f"s3://{bucket}/{key}") - docs = loader.load(file_content) - logger.debug("csdc markdown load data: {}".format(docs)) - return docs - - -def nougat_loader(file_path: str) -> List[Document]: - loader = NougatPDFLoader(file_path) - docs = loader.load() - logger.debug("nougat load data: {}".format(docs)) - - -def llamaIndex_pdf_loader(file_path: str) -> List[Document]: - try: - import pypdf - except ImportError: - raise ImportError("pypdf is required to read PDF files: `pip install pypdf`") - with open(file_path, "rb") as fp: - # Create a PDF object - pdf = pypdf.PdfReader(fp) - - # Get the number of pages in the PDF document - num_pages = len(pdf.pages) - - # Iterate over every page - docs = [] - for page in range(num_pages): - # Extract the text from the page - page_text = pdf.pages[page].extract_text() - page_label = pdf.page_labels[page] - - metadata = {"page_label": page_label, "file_name": file_path} - logger.debug("page_text: {}, page_label: {}".format(page_text, page_label)) - docs.append(Document(page_content=page_text, metadata=metadata)) - - -def langchain_md_loader(file_path: str) -> List[Document]: - loader = UnstructuredMarkdownLoader(file_path, mode="elements") - docs = loader.load() - logger.debug("langchain md load data: {}".format(docs)) - return docs - - -def langchain_unstructured_loader(file_path: str) -> List[Document]: - """ - Loads a document from a file path. - - Args: - file_path (str): The path to the file. - - Returns: - list[Document]: A list of Document objects. - """ - loader = UnstructuredFileLoader(file_path, mode="elements") - docs = loader.load() - logger.info("unstructured load data: {} type: {}".format(docs, type(docs))) - return docs - - -def parse_log_to_document_list(log_content: str) -> List[Document]: - # Split the log content into page content and metadata parts - parts = log_content.split("Metadata: ") - page_content = parts[0].replace("Page Content: \n", "").strip() - metadata = json.loads(parts[1].strip()) if len(parts) > 1 else {} - - # Create a Document object - doc = Document(page_content=page_content, metadata=metadata) - return [doc] - - -def csdc_unstructured_loader(file_path: str) -> List[Document]: - """ - Loads a document from a file path. - - Args: - file_path (str): The path to the file. - - Returns: - list[Document]: A list of Document objects. - """ - """ - Such function include several steps to interact with solution deployed on AWS. - 1. upload the file to s3 bucket, we use the DocumentBucket from cdk output, the whole s3 path is s3:///demo/pdf-sample-01.pdf, pdf-sample-01 is the file name - 2. trigger the offline etl job with api, we use the apiEndpoint from cdk output, the payload is { - "s3Bucket": "", - "s3Prefix": "demo", - "aosIndex": "demo", - "qaEnhance": "false", - "offline": "true" - } - 3. check the glue job status and wait for the job to finish with success status - 4. fetch loaded files from s3 bucket, we use the ChunkBucket from cdk output, the whole s3 path is s3:///pdf-sample-01/before-splitting/<%Y-%m-%d-%H>/.log, pdf-sample-01 is the file name - """ - # first get DocumentBucket and ChunkBucket from env variables - document_bucket = os.getenv("DocumentBucket") - chunk_bucket = os.getenv("ChunkBucket") - - # step 1, upload the file to s3 bucket with fixed s3 prefix demo/ - # extract file name also in consideration of file name with blank space - file_name = str(os.path.basename(file_path)) - # make the s3 prefix unique - s3_prefix = "demo/" + file_name - # upload the file to s3 bucket - s3.upload_file(file_path, document_bucket, s3_prefix) - - # step 2, trigger the offline etl job with api - # construct the payload - payload = json.dumps( - { - "s3Bucket": document_bucket, - "s3Prefix": s3_prefix, - "aosIndex": "demo", - "qaEnhance": "false", - "offline": "true", - } - ) - headers = {"Content-Type": "application/json"} - logger.debug( - "payload: {}, apiEndpoint: {}, headers: {}, type: {}".format( - payload, apiEndpoint, headers, type(payload) - ) - ) - try: - response = requests.request( - "POST", apiEndpoint + "etl", headers=headers, data=payload - ) - logger.debug("response: {}".format(json.loads(response.text))) - except Exception as e: - logger.error("error: {}".format(e)) - raise e - - # step 3, check the glue job status and wait for the job to finish with success status - # load the job name from environment variable and convert it to string like 'PythonShellJobB6964098-YYlLj16uCsAn' - glue_job_name = str(os.getenv("GLUE_JOB_NAME")) - # sleep 10 seconds to wait for the glue job to start - time.sleep(10) - # check the glue job status and wait for the job to finish with success status - response = glue.get_job_runs(JobName=glue_job_name, MaxResults=10) - # function only return running aws glue jobs - job_runs = [ - job_run - for job_run in response["JobRuns"] - if job_run["JobRunState"] == "RUNNING" - ] - while len(job_runs) > 0: - time.sleep(10) - logger.debug("waiting for glue job to finish...") - response = glue.get_job_runs(JobName=glue_job_name, MaxResults=10) - job_runs = [ - job_run - for job_run in response["JobRuns"] - if job_run["JobRunState"] == "RUNNING" - ] - - # step 4, fetch loaded files from s3 bucket - # scan the ChunkBucket s3:///pdf-sample-01/before-splitting/ - # construct the s3 prefix, note to strip the file type - s3_prefix = file_name.split(".")[0] + "/before-splitting/" - logger.debug("s3_prefix: {}, chunk_bucket: {}".format(s3_prefix, chunk_bucket)) - # find the latest timestamp folder then fetch the latest log file under that folder - response = s3.list_objects_v2(Bucket=chunk_bucket, Prefix=s3_prefix) - logger.debug("list_objects_v2 response: {}".format(response)) - # get the latest timestamp folder - latest_timestamp = max( - [content["Key"].split("/")[-2] for content in response["Contents"]] - ) - # construct the s3 prefix with latest timestamp folder - s3_prefix = s3_prefix + latest_timestamp + "/" - # find the latest log file - response = s3.list_objects_v2(Bucket=chunk_bucket, Prefix=s3_prefix) - logger.debug("list_objects_v2 response: {}".format(response)) - latest_log_file = max( - [content["Key"].split("/")[-1] for content in response["Contents"]] - ) - # construct the s3 prefix with latest log file - s3_prefix = s3_prefix + latest_log_file - # download the log file to local - s3.download_file(chunk_bucket, s3_prefix, file_name + ".log") - - # read content from file_path - with open(file_name + ".log", "r") as f: - file_content = f.read() - logger.debug("file_content: {}".format(file_content)) - - # transform to Document object - doc = parse_log_to_document_list(file_content) - logger.debug("csdc unstructured load data: {} and type: {}".format(doc, type(doc))) - # return to raw extracted file contents to match with the function as any loader class. TODO: return the result of splitter (SplittingType.SEMANTIC) to integrate into current benchmark - return doc - - -def langchain_recursive_splitter(docs: List[Document]) -> List[Document]: - """ - Splits a document into chunks recursively. - - Args: - docs (list[Document]): A list of Document objects. - - Returns: - list[Document]: A list of Document objects. - """ - text_splitter = RecursiveCharacterTextSplitter( - chunk_size=500, - chunk_overlap=30, - length_function=len, - add_start_index=True, - ) - docs = text_splitter.split_documents(docs) - logger.debug("langchain recursive splitter: {}".format(docs)) - return docs - - -def csdc_markdown_header_splitter(docs: List[Document]) -> List[Document]: - """ - Splits a document into chunks recursively. - - Args: - docs (list[Document]): A list of Document objects. - - Returns: - list[Document]: A list of Document objects. - """ - doc_list = [] - for doc in docs: - # Split the document into chunks based on the headers - markdown_splitter = MarkdownHeaderTextSplitter("default") - docs = markdown_splitter.split_text(doc) - logger.debug("csdc markdown header splitter: {}".format(docs)) - doc_list.extend(docs) - return doc_list - - -def documents_to_strings(documents: List[Document]) -> List[str]: - serialized_documents = [] - for doc in documents: - # Serialize the document into a JSON string - serialized_doc = json.dumps( - { - "page_content": doc.page_content, - "metadata": doc.metadata, - "type": doc.type, - } - ) - serialized_documents.append(serialized_doc) - return serialized_documents - - -def openai_embedding(index: str, docs: List[Document]) -> List[List[float]]: - embeddings = OpenAIEmbeddings() - docs = documents_to_strings(docs) - embeddings.embed_documents(docs) - logger.debug("openai embeddings: {}".format(embeddings)) - return embeddings - - -def csdc_embedding(index: str, docs: List[Document]) -> List[List[str]]: - # embedding - batches = batch_generator(docs, batch_size=5) - for batch in batches: - for doc in batch: - embedding_res = _csdc_embedding(default_aos_index_name, doc) - - -def _csdc_embedding(index: str, doc: Document): - """ - Embeds the given documents using the CSDC embedding model. - - Args: - index (str): The name of the index to which the documents will be added. - document (Document): The document to embed. - - Returns: - document_id (str): The ID of the document in the index. - e.g. - "document_id": [ - "05d0f6bb-b5c6-40e0-8064-c79448bd2332" - ] - """ - page_content = doc.page_content - metadata = doc.metadata - payload = json.dumps( - { - "aos_index": index, - "operation": "embed_document", - "body": {"documents": {"page_content": page_content, "metadata": metadata}}, - } - ) - headers = {"Content-Type": "application/json"} - logger.debug( - "payload: {}, apiEndpoint: {}, headers: {}, type: {}".format( - payload, apiEndpoint, headers, type(payload) - ) - ) - try: - response = requests.request( - "POST", apiEndpoint + "aos", headers=headers, data=payload - ) - logger.debug("csdc embedding: {}".format(json.loads(response.text))) - return json.loads(response.text) - except Exception as e: - logger.error("error: {}".format(e)) - raise e - - -@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10)) -def bedrock_embedding(index: str, docs: List[Document]) -> List[List[str]]: - """ - Embeds the given documents using the Bedrock embedding model. - - Args: - index (str): The name of the index to which the documents will be added. - document (Document): The document to embed. - - Returns: - list: List of ids from adding the texts into the vectorstore. - """ - opensearch_vector_search = OpenSearchVectorSearch( - opensearch_url="https://localhost:9200", - index_name=index, - # embedding_function=_bedrock_embedding, - embedding_function=_openai_embedding, - http_auth=("admin", "admin"), - use_ssl=False, - verify_certs=False, - ssl_assert_hostname=False, - ssl_show_warn=False, - bulk_size=1024, - ) - res_list = [] - batches = batch_generator(docs, batch_size=5) - for batch in batches: - for doc in batch: - res = opensearch_vector_search.add_embeddings( - # text_embeddings = [(doc.page_content, _bedrock_embedding.embed_documents([doc.page_content])[0])], - text_embeddings=[ - ( - doc.page_content, - _openai_embedding.embed_documents([doc.page_content])[0], - ) - ], - metadatas=None, - ids=None, - bulk_size=1024, - ) - res_list.append(res) - logger.debug("bedrock embedding: {}".format(res_list)) - return res_list - - -def _query_embedding( - index: str = default_aos_index_name, query: str = "Hello World" -) -> List[float]: - """ - Embeds the given query using the CSDC embedding model. - - Args: - index (str): The name of the index to which the documents will be added, not used for now. - query (str): The query to embed. - - Returns: - list: A list of floats with length of vector dimensions (1024). - """ - headersList = { - "Accept": "*/*", - "Content-Type": "application/json", - } - payload = json.dumps( - {"aos_index": index, "operation": "embed_query", "body": {"query": query}} - ) - - try: - response = requests.request( - "POST", apiEndpoint + AOS_API_SUFFIX, data=payload, headers=headersList - ) - logger.debug("response: {}".format(json.loads(response.text))) - except Exception as e: - logger.error("error: {}".format(e)) - raise e - return response - - -def aos_retriever(index: str, query: str, size: int = 10): - # such aos running inside vpc created by solution template, we use request library to call the api backed by api gw & lambda - query_res = _query_embedding(index, query) - vector_field = json.loads(query_res.text) - headersList = { - "Accept": "*/*", - "Content-Type": "application/json", - } - logger.debug( - "vector_field: {} and type: {}".format(vector_field, type(vector_field)) - ) - payload = json.dumps( - { - "aos_index": index, - "operation": "query_knn", - "body": { - "query": vector_field, - "size": size, - }, - } - ) - - try: - response = requests.request( - "GET", apiEndpoint + AOS_API_SUFFIX, data=payload, headers=headersList - ) - # parse the response and get the query result - response = json.loads(response.text) - logger.debug("aos retriever response: {}".format(response)) - # parse the response to get the score with following schema - """ - { - "took": 2, - "timed_out": false, - "_shards": { - "total": 5, - "successful": 5, - "skipped": 0, - "failed": 0 - }, - "hits": { - "total": { - "value": 111, - "relation": "eq" - }, - "max_score": 0.45040068, - "hits": [ - { - "_index": "jsonl", - "_id": "df050ddf-98c2-4396-83e2-ce467164b440", - "_score": 0.45040068, - ... - """ - score_list = [float(score["_score"]) for score in response["hits"]["hits"]] - # assemble the response with type as [(Document, score), (Document, score), ...], (hit['_source']['text']) is the document page_content - response = [ - (Document(page_content=hit["_source"]["text"]), score) - for hit, score in zip(response["hits"]["hits"], score_list) - ] - - except Exception as e: - logger.error("error: {}".format(e)) - raise e - return response - - -def local_aos_retriever( - index: str, query: str, size: int = 10 -) -> List[Tuple[Document, float]]: - """ - retrieve the similar documents with query from local aos - - Args: - index (str): The name of the index to which the documents will be added. - query (str): The query to embed. - size (int): The number of documents to retrieve. - - Returns: - list: A list of tuples with document and score, e.g. [(Document, float), (Document, float), ...] - """ - # assure local aos is running, e.g. simplely using 'docker run -d -p 9200:9200 -p 9600:9600 -e "discovery.type=single-node" opensearchproject/opensearch:latest' - opensearch_vector_search = OpenSearchVectorSearch( - opensearch_url="https://localhost:9200", - index_name=index, - # embedding_function=_bedrock_embedding, - embedding_function=_openai_embedding, - http_auth=("admin", "admin"), - use_ssl=False, - verify_certs=False, - ssl_assert_hostname=False, - ssl_show_warn=False, - bulk_size=1024, - ) - response = opensearch_vector_search.similarity_search_with_score(query, k=size) - logger.debug("local aos retriever response: {}".format(response)) - # parse the response to get the score with type List[Tuple[Document, float]] - score_list = [float(score[1]) for score in response] - return response - - -# utils to run embeddings with metrics of dimension and time -def run_embeddings(embeddings_list, docs: List[str]): - results = [] - for embed_func in embeddings_list: - start = time.perf_counter() - embedding_result = embed_func.embed_documents(docs) - end = time.perf_counter() - time_elapsed = end - start - results.append( - { - "Model": embed_func.__class__.__name__, - "Dimensions": len(embedding_result[0]), - "time": round(time_elapsed, 4), - } - ) - return results - - -def faiss_retriver(texts: List[str], query: str): - retriever = FAISS.from_texts(texts, OpenAIEmbeddings()).as_retriever() - docs = retriever.get_relevant_documents(query) - logger.debug("retriever docs: {}".format(docs)) - db = FAISS.from_texts(texts, OpenAIEmbeddings()) - docs_with_score = db.similarity_search_with_score(query, 3) - logger.debug("docs_with_score: {}".format(docs_with_score)) - return docs_with_score - - -@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10)) -def langchain_evaluator(prediction: str, reference: str, type: str): - """ - evaluate the retrieved documents with query and return summary result depend on the type of evaluator - - Args: - prediction (str): The query to evaluate. - reference (str): The reference to evaluate. - type (str): The type of evaluator to use. - - Returns: - dict: A dictionary of evaluation results, e.g. {'score': 0.1682955026626587} - """ - # explicitly set the llm model for bedrock - bedrock_llm = Bedrock( - model_id="anthropic.claude-v2:1", - client=bedrock_client, - model_kwargs={"temperature": 0}, - ) - evaluator = load_evaluator(type, llm=bedrock_llm) - response = evaluator.evaluate_strings(prediction=prediction, reference=reference) - logger.debug("evaluator response: {}".format(response)) - return response - - -def llama_index_evalutor(query: str, docs_with_score: List[Tuple[str, float]]): - pass - - -def testdata_generate( - doc: Document, llm: str = "bedrock", embedding: str = "bedrock", test_size: int = 3 -): - """ - generate test data for evaluation - """ - if llm == "bedrock": - generator_llm = LangchainLLM(llm=bedrock_llm) - critic_llm = LangchainLLM(llm=bedrock_llm) - elif llm == "openai": - generator_llm = LangchainLLM( - llm=ChatOpenAI( - model="gpt-3.5-turbo", - openai_api_key=openaiApiKey, - openai_api_base=openaiApiBase, - ) - ) - critic_llm = LangchainLLM( - llm=ChatOpenAI( - model="gpt-4-1106-preview", - openai_api_key=openaiApiKey, - openai_api_base=openaiApiBase, - ) - ) - # critic_llm = LangchainLLM(llm=ChatOpenAI(model="gpt-4")) - else: - raise ValueError(f"Unsupported llm: {llm}") - - # check embedding model - if embedding == "bedrock": - embeddings_model = bedrock_embedding - elif embedding == "openai": - embeddings_model = OpenAIEmbeddings() - - # Change resulting question type distribution - testset_distribution = { - "simple": 0.25, - "reasoning": 0.5, - "multi_context": 0.0, - "conditional": 0.25, - } - - # percentage of conversational question - chat_qa = 0.2 - - test_generator = TestsetGenerator( - generator_llm=generator_llm, - critic_llm=critic_llm, - embeddings_model=embeddings_model, - testset_distribution=testset_distribution, - chat_qa=chat_qa, - ) - - logger.info( - "doc input to testdata_generate: {} with type: {}".format(doc, type(doc)) - ) - testset = test_generator.generate(doc, test_size=test_size) - test_df = testset.to_pandas() - logger.info("testdata head: {}".format(test_df.head())) - - # Saving to a csv and txt file for debugging purpose - test_df.to_csv("test_data.csv", index=False) - test_df.to_csv("test_data.txt", sep="\t", index=False) - - # extract the question and answer from testset - question = test_df["question"].tolist() - question_type = test_df["question_type"].tolist() - - return question, question_type - - -class WorkflowExecutor: - """ - A class to execute a workflow with various components such as loaders, splitters, - embedders, retrievers, and evaluators. - - Attributes: - components (dict): A dictionary to store lists of different workflow components. - """ - - def __init__(self): - """Initializes the WorkflowExecutor with empty lists of components.""" - self.components = { - "loaders": [], - "splitters": [], - "embedders": [], - "retrievers": [], - "evaluators": [], - } - - self.index = default_aos_index_name - self.size = 10 - - def update_component(self, component_type, component, action): - """ - Adds or removes a component to/from the respective component list. - - Args: - component_type (str): The type of component (e.g., 'loaders', 'splitters'). - component (object): The component to add or remove. - action (str): 'add' to add the component, 'remove' to remove it. - - Raises: - ValueError: If the component type is invalid. - """ - if component_type in self.components: - if action == "add": - self.components[component_type].append(component) - elif action == "remove" and component in self.components[component_type]: - self.components[component_type].remove(component) - else: - raise ValueError(f"Invalid component type: {component_type}") - - def execute_workflow(self, doc_path: str, query, skip: bool = False): - """ - Executes the workflow with all combinations of components and returns the results. - - Args: - doc_path (str): The path to the document to be loaded. - query (str): The query for retrieval and evaluation. - - Returns: - list: A list of results from executing each workflow combination. - - Embedding evaluation: embedding into AOS using solution and langchain with different index , then using same question to query the retrieved references, calculate the similarities score between query and retrieved score, compare the score for both methods. - - E2E LLM evaluation: construct dataset with ground truth and using exiting langchain or llama index library to evaluate the faithfulness, relevance and accuracy metrics, OpenAI or Claude will be used as judger to determine the final score. - """ - summary = { - "rounds_of_experiments": 0, - "number_of_evaluation_questions": len(query), - "chunk_size": None, # Update this if you have chunk size information - "overlap_size": None, # Update this if you have overlap size information - "load_method": [], - "split_method": [], - "retrieval_method": [], - "embedding_algorithm_model": [], - "number_of_chunks_retrieved": 0, - "average_relevance_score": 0, - "average_similarity_score": 0, - "average_time_of_retrieval": 0, - } - - total_relevance_score = 0 - total_similarity_score = 0 - total_retrieval_time = 0 - - # results_matrix = [] - for loader, splitter, embedder, retriever, evaluator in product( - self.components["loaders"], - self.components["splitters"], - self.components["embedders"], - self.components["retrievers"], - self.components["evaluators"], - ): - start_time = time.perf_counter() - - if not skip: - # Execute splitter and embedder if flag is not set to skip - loader_res = loader(doc_path) - splitter_res = splitter(loader_res) - embedder(self.index, splitter_res) - summary["split_method"].append(splitter.__name__) - summary["embedding_algorithm_model"].append(embedder.__name__) - else: - # Skip loader, splitter, embedder steps - logger.info("Skipping loader, splitter, embedder steps") - summary["split_method"].append("Skipped") - summary["embedding_algorithm_model"].append("Skipped") - - retriever_res = retriever(self.index, query, self.size) - retrieval_time = time.perf_counter() - start_time - - total_retrieval_time += retrieval_time - summary["rounds_of_experiments"] += 1 - summary["load_method"].append(loader.__name__) - summary["split_method"].append(splitter.__name__) - summary["retrieval_method"].append(retriever.__name__) - summary["embedding_algorithm_model"].append(embedder.__name__) - summary["number_of_chunks_retrieved"] += len(retriever_res) - - # openai required for now, bedrock is not working even setup the llm model explicitly - for reference in retriever_res: - logger.debug( - "reference: {} with type {}".format(reference, type(reference)) - ) - score = evaluator( - prediction=query, - reference=reference[0].page_content, - type=EvaluatorType.EMBEDDING_DISTANCE, - )["score"] - total_similarity_score += score - # TODO, unified score parse method - total_relevance_score += float(reference[1]) - # total_relevance_score += float(score['_score']) for score in reference['hits']['hits'] for csdc - - # results_matrix.append(evaluator(prediction=query, reference=reference.page_content, type=EvaluatorType.EMBEDDING_DISTANCE)['score']) - summary["average_relevance_score"] = ( - total_relevance_score / summary["number_of_chunks_retrieved"] - ) - summary["average_similarity_score"] = ( - total_similarity_score / summary["number_of_chunks_retrieved"] - ) - summary["average_time_of_retrieval"] = ( - total_retrieval_time / summary["rounds_of_experiments"] - ) - - return summary - - def summary_viz(self, summary: List[Dict[str, Any]]): - """ - Visualizes the summary data to gain insights on the best combination for relevance and retrieval score. - - Args: - summary (list): Rounds of experiments with metrics of relevance and retrieval score. - - Returns: - Display the bar charts of average relevance and retrieval score separately with x axis as rounds of experiments and y axis as average score and similarity score. - """ - # Convert the data to a DataFrame - df = pd.DataFrame(summary) - - # Plotting - plt.figure(figsize=(12, 6)) - - # Plotting average_relevance_score and average_similarity_score as separate bar charts - plt.subplot(1, 2, 1) - seaborn.barplot( - x="rounds_of_experiments", - y="average_relevance_score", - data=df, - color="blue", - ) - plt.title("Average Relevance Score per Round") - plt.xlabel("Rounds of Experiments") - plt.ylabel("Average Relevance Score") - - plt.subplot(1, 2, 2) - seaborn.barplot( - x="rounds_of_experiments", - y="average_similarity_score", - data=df, - color="red", - ) - plt.title("Average Similarity Score per Round") - plt.xlabel("Rounds of Experiments") - plt.ylabel("Average Similarity Score") - - plt.tight_layout() - plt.show() - - # save image to local folder - plt.savefig("summary.png") - - def summary_comparison( - summary_original: List[Dict[str, Any]], summary: List[Dict[str, Any]] - ): - """ - Visualizes both summary data on the same bar chart to compare the results, separate the bar chart per metric include average_relevance_score, average_similarity_score - - Args: - summary_original (list): Rounds of experibenchmark.pyments with metrics of relevance and retrieval score. - summary (list): Rounds of experiments with metrics of relevance and retrieval score. - - Returns: - Display the separate bar charts of average relevance and retrieval score separately with x-axis as rounds of experiments and y-axis as average score and similarity score. - """ - # Convert the data to a DataFrame - df_original = pd.DataFrame(summary_original) - df_original["Type"] = "LangChain" - - df = pd.DataFrame(summary) - df["Type"] = "CSDC" - - # Combine the two dataframes - df_combined = pd.concat([df_original, df], ignore_index=True) - - # Plotting - plt.figure(figsize=(14, 6)) - - # Plotting average_relevance_score for both summary and summary_original in the same bar chart - plt.subplot(1, 2, 1) - seaborn.barplot( - x="rounds_of_experiments", - y="average_relevance_score", - hue="Type", - data=df_combined, - ) - plt.title("Average Relevance Score per Round") - plt.xlabel("Rounds of Experiments") - plt.ylabel("Average Relevance Score") - - # Plotting average_similarity_score for both summary and summary_original in the same bar chart - plt.subplot(1, 2, 2) - seaborn.barplot( - x="rounds_of_experiments", - y="average_similarity_score", - hue="Type", - data=df_combined, - ) - plt.title("Average Similarity Score per Round") - plt.xlabel("Rounds of Experiments") - plt.ylabel("Average Similarity Score") - - plt.tight_layout() - - # Save image to local folder before plt.show() - plt.savefig("summary_comparison.png") - - # Show the plot - plt.show() - - -# Preparing loader, splitter, and embeddings retriever list, iterate them to create comparison matrix -loader_list = [langchain_unstructured_loader, nougat_loader, csdc_markdown_loader] -splitter_list = [langchain_recursive_splitter, csdc_markdown_header_splitter] -embeddings_list = [openai_embedding, csdc_embedding] -retriever_list = [faiss_retriver, aos_retriever, local_aos_retriever] -evalutor_list = [langchain_evaluator] - - -def batch_generator(generator, batch_size: int): - iterator = iter(generator) - while True: - batch = list(itertools.islice(iterator, batch_size)) - if not batch: - break - yield batch - - -# Debugging purpose -if __name__ == "__main__": - """ - evaluate the retrieved documents with query and return summary result including metrics below: - 1. # round of experiments - 2. # of evaluation questions - 3. chunk size and overlap size - 4. split method - 5. retrieval method - 6. embedding algorithm & model - 7. # of chunks retrieved - 8. average relevance score of retrival - 9. average similarity score of retrival - 10. average time of retrival - """ - loader_res = langchain_unstructured_loader("pdf-sample-01.pdf") - # loader_res = csdc_unstructured_loader("pdf-sample-01.pdf") - question_list, question_type_list = testdata_generate( - loader_res, llm="openai", embedding="openai", test_size=10 - ) - - # initialization of workflow executor - # legacy = WorkflowExecutor() - # legacy.update_component('loaders', langchain_unstructured_loader, 'add') - # legacy.update_component('splitters', langchain_recursive_splitter, 'add') - # legacy.update_component('embedders', bedrock_embedding, 'add') - # legacy.update_component('retrievers', local_aos_retriever, 'add') - # legacy.update_component('evaluators', langchain_evaluator, 'add') - - # response = legacy.execute_workflow("pdf-sample-01.pdf", "请介绍什么是kindle以及它的主要功能?") - - # workaround for inconsistent network issue, if you have already generated the test data as sample schema below - """ - question,ground_truth_context,ground_truth,question_type,episode_done - How can you navigate to the next page on the screen?,['- 要翻到下一页,请用手指在屏幕上从右往左滑动。\n- 要翻到上一页,请用手指在屏幕上从左往右滑动。\n- 您还可以使用屏幕一侧的控件来翻页。'],"['To navigate to the next page on the screen, you can swipe your finger from right to left on the screen.']",simple,True - What are the steps for restarting an unresponsive or non-turning on Kindle device?,['- 如果您的 Kindle 无法开机或使用过程中停止响应而需要重启,请按住电源开关 7 秒,直 至【电源】对话框出现,然后选择【重新启动】。\n- 如果【电源】对话框不出现,请按住电 源开关 40 秒或直至 LED 灯停止闪烁。'],"['The steps for restarting an unresponsive or non-turning on Kindle device are as follows:\n1. Press and hold the power button for 7 seconds until the ""Power"" dialog box appears.\n2. Select ""Restart"" from the dialog box.\n3. If the ""Power"" dialog box does not appear, press and hold the power button for 40 seconds or until the LED light stops flashing.']",conditional,True - """ - # question_list = [] - # with open('test_data.csv', 'r') as f: - # reader = csv.reader(f) - # for row in reader: - # question_list.append(row[0]) - - # # iterate the question list to execute the workflow - # response_list = [] - # for question in question_list: - # response = legacy.execute_workflow("pdf-sample-01.pdf", question, skip=True) - # logger.info("test of legacy workflow: {}".format(response)) - # response_list.append(response) - - # logger.info("response_list: {}".format(response_list)) - - # # visualize the summary - # legacy.summary_viz(response_list) - - # initialization of workflow executor - # csdc = WorkflowExecutor() - # csdc.update_component('loaders', csdc_unstructured_loader, 'add') - # csdc.update_component('splitters', csdc_markdown_header_splitter, 'add') - # csdc.update_component('embedders', csdc_embedding, 'add') - # csdc.update_component('retrievers', aos_retriever, 'add') - # csdc.update_component('evaluators', langchain_evaluator, 'add') - - # loader_res = langchain_unstructured_loader("pdf-sample-01.pdf") - # # question_list, question_type_list = testdata_generate(loader_res, llm="openai", embedding="openai", test_size=10) - - # # workaround for inconsistent network issue, if you have already generated the test data as sample schema below - # """ - # question,ground_truth_context,ground_truth,question_type,episode_done - # How can you navigate to the next page on the screen?,['- 要翻到下一页,请用手指在屏幕上从右往左滑动。\n- 要翻到上一页,请用手指在屏幕上从左往右滑动。\n- 您还可以使用屏幕一侧的控件来翻页。'],"['To navigate to the next page on the screen, you can swipe your finger from right to left on the screen.']",simple,True - # What are the steps for restarting an unresponsive or non-turning on Kindle device?,['- 如果您的 Kindle 无法开机或使用过程中停止响应而需要重启,请按住电源开关 7 秒,直 至【电源】对话框出现,然后选择【重新启动】。\n- 如果【电源】对话框不出现,请按住电 源开关 40 秒或直至 LED 灯停止闪烁。'],"['The steps for restarting an unresponsive or non-turning on Kindle device are as follows:\n1. Press and hold the power button for 7 seconds until the ""Power"" dialog box appears.\n2. Select ""Restart"" from the dialog box.\n3. If the ""Power"" dialog box does not appear, press and hold the power button for 40 seconds or until the LED light stops flashing.']",conditional,True - # """ - # question_list = [] - # with open('test_data.csv', 'r') as f: - # reader = csv.reader(f) - # for row in reader: - # question_list.append(row[0]) - # # iterate the question list to execute the workflow - # response_list = [] - # for question in question_list: - # response = csdc.execute_workflow("pdf-sample-01.pdf", question, skip=True) - # logger.debug("test of csdc workflow: {}".format(response)) - # response_list.append(response) - - # logger.info("response_list: {}".format(response_list)) - - # # visualize the summary - # csdc.summary_viz(response_list) diff --git a/source/panel/evaluator/prompts.py b/source/panel/evaluator/prompts.py deleted file mode 100644 index ad72f257d..000000000 --- a/source/panel/evaluator/prompts.py +++ /dev/null @@ -1,146 +0,0 @@ -from langchain.prompts import PromptTemplate - -template = """You are a teacher grading a quiz. -You are given a question, the student's answer, and the true answer, and are asked to score the student answer as either Correct or Incorrect. - -Example Format: -QUESTION: question here -STUDENT ANSWER: student's answer here -TRUE ANSWER: true answer here -GRADE: Correct or Incorrect here - -Grade the student answers based ONLY on their factual accuracy. Ignore differences in punctuation and phrasing between the student answer and true answer. It is OK if the student answer contains more information than the true answer, as long as it does not contain any conflicting statements. If the student answers that there is no specific information provided in the context, then the answer is Incorrect. Begin! - -QUESTION: {query} -STUDENT ANSWER: {result} -TRUE ANSWER: {answer} -GRADE: - -Your response should be as follows: - -GRADE: (Correct or Incorrect) -(line break) -JUSTIFICATION: (Without mentioning the student/teacher framing of this prompt, explain why the STUDENT ANSWER is Correct or Incorrect. Use one or two sentences maximum. Keep the answer as concise as possible.) -""" - -GRADE_ANSWER_PROMPT = PromptTemplate(input_variables=["query", "result", "answer"], template=template) - -template = """You are a teacher grading a quiz. -You are given a question, the student's answer, and the true answer, and are asked to score the student answer as either Correct or Incorrect. - -Example Format: -QUESTION: question here -STUDENT ANSWER: student's answer here -TRUE ANSWER: true answer here -GRADE: Correct or Incorrect here - -Grade the student answers based ONLY on their factual accuracy. Ignore differences in punctuation and phrasing between the student answer and true answer. It is OK if the student answer contains more information than the true answer, as long as it does not contain any conflicting statements. If the student answers that there is no specific information provided in the context, then the answer is Incorrect. Begin! - -QUESTION: {query} -STUDENT ANSWER: {result} -TRUE ANSWER: {answer} -GRADE:""" - -GRADE_ANSWER_PROMPT_FAST = PromptTemplate(input_variables=["query", "result", "answer"], template=template) - -template = """You are a teacher grading a quiz. -You are given a question, the student's answer, and the true answer, and are asked to score the student answer as either Correct or Incorrect. -You are also asked to identify potential sources of bias in the question and in the true answer. - -Example Format: -QUESTION: question here -STUDENT ANSWER: student's answer here -TRUE ANSWER: true answer here -GRADE: Correct or Incorrect here - -Grade the student answers based ONLY on their factual accuracy. Ignore differences in punctuation and phrasing between the student answer and true answer. It is OK if the student answer contains more information than the true answer, as long as it does not contain any conflicting statements. If the student answers that there is no specific information provided in the context, then the answer is Incorrect. Begin! - -QUESTION: {query} -STUDENT ANSWER: {result} -TRUE ANSWER: {answer} -GRADE: - -Your response should be as follows: - -GRADE: (Correct or Incorrect) -(line break) -JUSTIFICATION: (Without mentioning the student/teacher framing of this prompt, explain why the STUDENT ANSWER is Correct or Incorrect, identify potential sources of bias in the QUESTION, and identify potential sources of bias in the TRUE ANSWER. Use one or two sentences maximum. Keep the answer as concise as possible.) -""" - -GRADE_ANSWER_PROMPT_BIAS_CHECK = PromptTemplate(input_variables=["query", "result", "answer"], template=template) - -template = """You are assessing a submitted student answer to a question relative to the true answer based on the provided criteria: - - *** - QUESTION: {query} - *** - STUDENT ANSWER: {result} - *** - TRUE ANSWER: {answer} - *** - Criteria: - relevance: Is the submission referring to a real quote from the text?" - conciseness: Is the answer concise and to the point?" - correct: Is the answer correct?" - *** - Does the submission meet the criterion? First, write out in a step by step manner your reasoning about the criterion to be sure that your conclusion is correct. Avoid simply stating the correct answers at the outset. Then print "Correct" or "Incorrect" (without quotes or punctuation) on its own line corresponding to the correct answer. - Reasoning: -""" - -GRADE_ANSWER_PROMPT_OPENAI = PromptTemplate(input_variables=["query", "result", "answer"], template=template) - -template = """ - You are a grader trying to determine if a set of retrieved documents will help a student answer a question. \n - - Here is the question: \n - {query} - - Here are the documents retrieved to answer question: \n - {result} - - Here is the correct answer to the question: \n - {answer} - - Criteria: - relevance: Do all of the documents contain information that will help the student arrive that the correct answer to the question?" - - Your response should be as follows: - - GRADE: (Correct or Incorrect, depending if all of the documents retrieved meet the criterion) - (line break) - JUSTIFICATION: (Write out in a step by step manner your reasoning about the criterion to be sure that your conclusion is correct. Use three sentences maximum. Keep the answer as concise as possible.) - """ - -GRADE_DOCS_PROMPT = PromptTemplate(input_variables=['result', 'answer', 'query'], template=template) - -template = """You are an AI travel assistant for a company called Osito that answers questions using the provided context. - -Your job is to help the customer decide on which cities might be good for an event they are planning, and then optionally to help them pick a shortlist of hotels within those cities to request proposals from. - -If you need more information at any point, you can ask the customer follow up questions about where their attendees are coming from ("origin cities"), what vibe they are looking for, their budget, what hotel class they want (2-star through 5-star), etc. - -Question: -{question} - -Here is some context that might be helpful: -{context} - -Answer:""" - -QA_CHAIN_PROMPT_TRAVEL = PromptTemplate(input_variables=["context", "question"],template=template,) - -template = """You are an assistant providing summary answers about the Lex Fridman podcast. - -If the user asks a question about a specific episode, just answeer using information in the below context. - -Be concise and truthful. Think step by step. - -Question: -{question} - -Here is some context that might be helpful: -{context} - -Answer:""" - -QA_CHAIN_PROMPT_LEX = PromptTemplate(input_variables=["context", "question"],template=template,) \ No newline at end of file diff --git a/source/panel/evaluator/requirements.txt b/source/panel/evaluator/requirements.txt deleted file mode 100644 index 250bc49c4..000000000 --- a/source/panel/evaluator/requirements.txt +++ /dev/null @@ -1,19 +0,0 @@ -python-dotenv -PyPDF2 -streamlit==1.37.0 -langchain==0.1.11 -openai==1.1.0 -tiktoken==0.5.1 -boto3==1.28.84 -nougat-ocr==0.1.17 -tenacity==8.2.2 -altair==4.2.2 -scikit-learn==1.5.0 -kor==0.9.2 -transformers==4.36.0 -lark==1.1.5 -ragas==0.0.21 -simsimd==3.6.0 -pandas==1.5.3 -matplotlib==3.7.1 -seaborn==0.12.2 \ No newline at end of file diff --git a/source/panel/evaluator/ui.py b/source/panel/evaluator/ui.py deleted file mode 100644 index f06de7ff1..000000000 --- a/source/panel/evaluator/ui.py +++ /dev/null @@ -1,429 +0,0 @@ -import json -import os -import time -from typing import List - -import altair as alt -import pandas as pd -import streamlit as st -from benchmark import WorkflowExecutor -from dotenv import load_dotenv -from langchain.chains.question_answering import load_qa_chain -from langchain.chat_models import ChatOpenAI -from langchain.docstore.document import Document -from langchain.embeddings import HuggingFaceEmbeddings -from langchain.embeddings.openai import OpenAIEmbeddings -from langchain.evaluation.qa import QAEvalChain -from langchain.llms import Anthropic -from langchain.retrievers.self_query.base import SelfQueryRetriever -from langchain.vectorstores import OpenSearchVectorSearch -from prompts import ( - GRADE_ANSWER_PROMPT, - GRADE_ANSWER_PROMPT_BIAS_CHECK, - GRADE_ANSWER_PROMPT_FAST, - GRADE_ANSWER_PROMPT_OPENAI, - GRADE_DOCS_PROMPT, - QA_CHAIN_PROMPT_LEX, - QA_CHAIN_PROMPT_TRAVEL, -) - -load_dotenv(dotenv_path=".env") - -import logging - -logging.basicConfig(level=logging.INFO) -logger = logging.getLogger(__name__) - -oai_api_key = os.getenv("OPENAI_API_KEY") - - -# Keep dataframe in memory to accumulate experimental results -if "existing_df" not in st.session_state: - summary = pd.DataFrame( - columns=[ - "model", - "retriever", - "embedding", - "num_neighbors", - "Latency", - "Retrieval score", - "Answer score", - ] - ) - st.session_state.existing_df = summary -else: - summary = st.session_state.existing_df - - -@st.cache_resource -def make_llm(model_version: str): - """ - Make LLM from model version - @param model_version: model_version - @return: LLN - """ - if (model_version == "gpt-3.5-turbo") or (model_version == "gpt-4"): - chosen_model = ChatOpenAI(model_name=model_version, temperature=0) - elif model_version == "anthropic": - chosen_model = Anthropic(temperature=0) - else: - st.warning("`Model version not recognized. Using gpt-3.5-turbo`", icon="⚠️") - chosen_model = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0) - return chosen_model - - -@st.cache_resource -def make_retriever(retriever_type, embedding_type): - """ - Make document retriever - @param retriever_type: retriever type - @param embedding_type: embedding type - @param num_neighbors: number of neighbors for retrieval - - """ - # TODO: - pass - - -def make_chain(llm): - """ - Make retrieval chain - @param retriever: retriever - @param retriever_type: retriever type - @return: QA chain - """ - - qa_chain = load_qa_chain(llm, chain_type="stuff", prompt=QA_CHAIN_PROMPT_LEX) - - return qa_chain - - -def grade_model_answer( - predicted_dataset: List, predictions: List, grade_answer_prompt: str -) -> List: - """ - Grades the distilled answer based on ground truth and model predictions. - @param predicted_dataset: A list of dictionaries containing ground truth questions and answers. - @param predictions: A list of dictionaries containing model predictions for the questions. - @param grade_answer_prompt: The prompt level for the grading. Either "Fast" or "Full". - @return: A list of scores for the distilled answers. - """ - # Grade the distilled answer - st.info("`Grading model answer ...`") - # Set the grading prompt based on the grade_answer_prompt parameter - if grade_answer_prompt == "Fast": - prompt = GRADE_ANSWER_PROMPT_FAST - elif grade_answer_prompt == "Descriptive w/ bias check": - prompt = GRADE_ANSWER_PROMPT_BIAS_CHECK - elif grade_answer_prompt == "OpenAI grading prompt": - prompt = GRADE_ANSWER_PROMPT_OPENAI - else: - prompt = GRADE_ANSWER_PROMPT - - # Create an evaluation chain - eval_chain = QAEvalChain.from_llm( - llm=ChatOpenAI(model_name="gpt-4", temperature=0), prompt=prompt - ) - - # Evaluate the predictions and ground truth using the evaluation chain - graded_outputs = eval_chain.evaluate( - predicted_dataset, predictions, question_key="question", prediction_key="result" - ) - - return graded_outputs - - -def grade_model_retrieval(gt_dataset: List, predictions: List, grade_docs_prompt: str): - """ - Grades the relevance of retrieved documents based on ground truth and model predictions. - @param gt_dataset: list of dictionaries containing ground truth questions and answers. - @param predictions: list of dictionaries containing model predictions for the questions - @param grade_docs_prompt: prompt level for the grading. Either "Fast" or "Full" - @return: list of scores for the retrieved documents. - """ - # Grade the docs retrieval - st.info("`Grading relevance of retrieved docs ...`") - - # Set the grading prompt based on the grade_docs_prompt parameter - prompt = GRADE_DOCS_PROMPT - - # Create an evaluation chain - eval_chain = QAEvalChain.from_llm( - llm=ChatOpenAI(model_name="gpt-4", temperature=0), prompt=prompt - ) - - # Evaluate the predictions and ground truth using the evaluation chain - graded_outputs = eval_chain.evaluate( - gt_dataset, predictions, question_key="question", prediction_key="result" - ) - return graded_outputs - - -def run_evaluation( - chain, retriever, eval_set, grade_prompt, retriever_type, num_neighbors -): - """ - - Runs evaluation on a model's performance on a given evaluation dataset. - @param chain: Model chain used for answering questions - @param retriever: Document retriever used for retrieving relevant documents - @param eval_set: List of dictionaries containing questions and corresponding ground truth answers - @param grade_prompt: String prompt used for grading model's performance - @param retriever_type: String specifying the type of retriever used - @param num_neighbors: Number of neighbors to retrieve using the retriever - @return: A tuple of four items: - - answers_grade: A dictionary containing scores for the model's answers. - - retrieval_grade: A dictionary containing scores for the model's document retrieval. - - latencies_list: A list of latencies in seconds for each question answered. - - predictions_list: A list of dictionaries containing the model's predicted answers and relevant documents for each question. - """ - st.info("`Running evaluation ...`") - predictions_list = [] - retrieved_docs = [] - gt_dataset = [] - latencies_list = [] - - for data in eval_set: - - # Get answer and log latency - start_time = time.time() - - # Get docs - if retriever_type == "Faiss retriever": - docs = retriever.similarity_search( - query=data["question"], k=num_neighbors, filter=metadata_filter - ) - elif retriever_type == "CSDC retriever": - docs = retriever.similarity_search( - query=data["question"], k=num_neighbors, filter=metadata_filter - ) - else: - docs = retriever.similarity_search(query=data["question"], k=num_neighbors) - logger.info("--DOCS--") - if not docs: - docs = [ - Document( - page_content="I was unable to recover any information about the question!" - ) - ] - logger.info(docs) - - # Get answer - answer = chain.run(input_documents=docs, question=data["question"]) - predictions_list.append( - {"question": data["question"], "answer": data["answer"], "result": answer} - ) - gt_dataset.append(data) - end_time = time.time() - elapsed_time = end_time - start_time - latencies_list.append(elapsed_time) - - # Get doc text - retrieved_doc_text = "" - for i, doc in enumerate(docs): - retrieved_doc_text += "Doc %s: " % str(i + 1) + doc.page_content + " " - retrieved = { - "question": data["question"], - "answer": data["answer"], - "result": retrieved_doc_text, - } - retrieved_docs.append(retrieved) - - # Grade docs and answer - answers_grade = grade_model_answer(gt_dataset, predictions_list, grade_prompt) - retrieval_grade = grade_model_retrieval(gt_dataset, retrieved_docs, grade_prompt) - return answers_grade, retrieval_grade, latencies_list, predictions_list - - -# Auth -st.sidebar.image("https://d0.awsstatic.com/logos/powered-by-aws.png", width=200) - -with st.sidebar.form("user_input"): - - loader_type = st.radio( - "`Choose loader`", - ( - "unstructured loader", - "Nougat loader", - "CSDC loader", - ), - index=0, - ) - - splitter_type = st.radio( - "`Choose splitter`", - ( - "recursive splitter", - "CSDC markdown header splitter", - ), - index=0, - ) - - embedding_type = st.radio( - "`Choose embedding`", - ( - "HuggingFace", - "OpenAI", - "CSDC", - ), - index=1, - ) - - retriever_type = st.radio( - "`Choose retriever`", - ( - "Faiss retriever", - "CSDC retriever", - ), - index=0, - ) - - evaluator_type = st.radio( - "`Choose evaluator`", - ( - "LangChain evaluator", - "CSDC evaluator", - ), - index=0, - ) - - num_neighbors = st.select_slider( - "`Choose # chunks to retrieve`", options=[3, 4, 5, 6, 7, 8] - ) - - model = st.radio( - "`Choose model`", - ( - "gpt-3.5-turbo", - "gpt-4", - "anthropic", - "csdc", - ), - index=0, - ) - - grade_prompt = st.radio( - "`Grading style prompt`", - ("Fast", "Descriptive", "Descriptive w/ bias check", "OpenAI grading prompt"), - index=3, - ) - - submitted = st.form_submit_button("Submit evaluation") - -# App -st.header("`AOS auto-evaluator`") -st.info( - "`Evaluation tool for question-answering using an existing vectorDB (Amazon Open Search) and an eval set. " - " Such tool will generate & grade an answer to each eval set question with the user-specific retrieval setting, such as metadata filtering or self-querying retrieval." - " Experiments with different configurations are logged. For an example eval set, see eval_sets/lex-pod-eval.json.`" -) - -with st.form(key="file_inputs"): - - uploaded_eval_set = st.file_uploader( - "`Please upload eval set (.json):` ", type=["json"], accept_multiple_files=False - ) - - submitted = st.form_submit_button("Submit files") - -# Build an index from the supplied docs -if uploaded_eval_set: - - if embeddings == "OpenAI": - embedding = OpenAIEmbeddings() - elif embeddings == "HuggingFace": - embedding = HuggingFaceEmbeddings() - - # Eval set - eval_set = json.loads(uploaded_eval_set.read()) - - # Make LLM - llm = make_llm(model) - - # Make retriever - retriever = make_retriever(retriever_type, embeddings) - - # Make chain - qa_chain = make_chain(llm) - - # Grade model - graded_answers, graded_retrieval, latency, predictions = run_evaluation( - qa_chain, retriever, eval_set, grade_prompt, retriever_type, num_neighbors - ) - - # Assemble outputs - d = pd.DataFrame(predictions) - d["answer score"] = [g["text"] for g in graded_answers] - d["docs score"] = [g["text"] for g in graded_retrieval] - d["latency"] = latency - - # Summary statistics - mean_latency = d["latency"].mean() - correct_answer_count = len( - [text for text in d["answer score"] if "Incorrect" not in text] - ) - correct_docs_count = len( - [text for text in d["docs score"] if "Incorrect" not in text] - ) - percentage_answer = (correct_answer_count / len(graded_answers)) * 100 - percentage_docs = (correct_docs_count / len(graded_retrieval)) * 100 - - st.subheader("`Run Results`") - st.info( - "`I will grade the chain based on: 1/ the relevance of the retrieved documents relative to the question and 2/ " - "the summarized answer relative to the ground truth answer. You can see (and change) to prompts used for " - "grading in text_utils`" - ) - st.dataframe(data=d, use_container_width=True) - - # Accumulate results - st.subheader("`Aggregate Results`") - st.info( - "`Retrieval and answer scores are percentage of retrieved documents deemed relevant by the LLM grader (" - "relative to the question) and percentage of summarized answers deemed relevant (relative to ground truth " - "answer), respectively. The size of point corresponds to the latency (in seconds) of retrieval + answer " - "summarization (larger circle = slower).`" - ) - new_row = pd.DataFrame( - { - "model": [model], - "retriever": [retriever_type], - "embedding": [embeddings], - "num_neighbors": [num_neighbors], - "Latency": [mean_latency], - "Retrieval score": [percentage_docs], - "Answer score": [percentage_answer], - } - ) - summary = pd.concat([summary, new_row], ignore_index=True) - st.dataframe(data=summary, use_container_width=True) - st.session_state.existing_df = summary - - # Dataframe for visualization - show = summary.reset_index().copy() - show.columns = [ - "expt number", - "model", - "retriever", - "embedding", - "num_neighbors", - "Latency", - "Retrieval score", - "Answer score", - ] - show["expt number"] = show["expt number"].apply(lambda x: "Expt #: " + str(x + 1)) - c = ( - alt.Chart(show) - .mark_circle() - .encode( - x="Retrieval score", - y="Answer score", - size=alt.Size("Latency"), - color="expt number", - tooltip=["expt number", "Retrieval score", "Latency", "Answer score"], - ) - ) - st.altair_chart(c, use_container_width=True, theme="streamlit") - -else: - st.warning("Please specify a AOS index and add an eval set.", icon="⚠️") diff --git a/source/panel/requirements.txt b/source/panel/requirements.txt deleted file mode 100644 index 8d9338145..000000000 --- a/source/panel/requirements.txt +++ /dev/null @@ -1,9 +0,0 @@ -python-dotenv -PyPDF2 -streamlit==1.37.0 -langchain==0.1.0 -openai==1.1.0 -tiktoken==0.5.1 -boto3==1.28.84 -nougat-ocr==0.1.17 -tenacity==8.2.2 diff --git a/source/panel/sd/.env_sd_sample b/source/panel/sd/.env_sd_sample deleted file mode 100644 index 009e62f26..000000000 --- a/source/panel/sd/.env_sd_sample +++ /dev/null @@ -1,4 +0,0 @@ -COMMON_API_URL=https://xxxx.execute-api.ap-northeast-1.amazonaws.com/prod/ -API_KEY=xxxx -BEDROCK_REGION=us-east-1 -API_USERNAME=aws \ No newline at end of file diff --git a/source/panel/sd/.streamlit/config.toml b/source/panel/sd/.streamlit/config.toml deleted file mode 100644 index e3ade574e..000000000 --- a/source/panel/sd/.streamlit/config.toml +++ /dev/null @@ -1,3 +0,0 @@ -[theme] -base="light" -primaryColor="#FA972E" diff --git a/source/panel/sd/image_generation.py b/source/panel/sd/image_generation.py deleted file mode 100644 index 379d51841..000000000 --- a/source/panel/sd/image_generation.py +++ /dev/null @@ -1,675 +0,0 @@ -import json -import logging -import os -import re -import time -from datetime import datetime -from typing import List - -import boto3 -import requests -import streamlit as st -from dotenv import load_dotenv -from langchain.chains import ConversationChain -from langchain.llms.bedrock import Bedrock -from langchain.memory import ConversationBufferMemory -from langchain.prompts import PromptTemplate -from tenacity import stop_after_attempt, retry - -logging.basicConfig(level=logging.INFO) -# logging to stdout -logger = logging.getLogger(__name__) -logger.setLevel(logging.INFO) - -# load .env file with specific name -load_dotenv(dotenv_path='.env_sd') - -# Your ApiGatewayUrl in Extension for Stable Diffusion -# Example: https://xxxx.execute-api.us-west-2.amazonaws.com/prod/ -COMMAND_API_URL = os.getenv("COMMON_API_URL") -# Your ApiGatewayUrlToken in Extension for Stable Diffusion -API_KEY = os.getenv("API_KEY") -# Your username in Extension for Stable Diffusion -# Some resources are limited to specific users -API_USERNAME = os.getenv("API_USERNAME") -# The service support varies in different regions -BEDROCK_REGION = os.getenv("BEDROCK_REGION") - -# API URL -GENERATE_API_URL = COMMAND_API_URL + "inference/v2" -STATUS_API_URL = COMMAND_API_URL + "inference/get-inference-job" -PARAM_API_URL = COMMAND_API_URL + "inference/get-inference-job-param-output" -IMAGE_API_URL = COMMAND_API_URL + "inference/get-inference-job-image-output" - -default_models = ["sd_xl_base_1.0.safetensors"] - -def get_bedrock_llm(): - # specify the profile_name to call the bedrock api if needed - bedrock_client = boto3.client('bedrock-runtime', region_name=BEDROCK_REGION) - - modelId = "anthropic.claude-v2" - cl_llm = Bedrock( - model_id=modelId, - client=bedrock_client, - model_kwargs={"max_tokens_to_sample": 1000}, - ) - return cl_llm - -def create_or_get_conversation(type: str) -> ConversationChain: - # the type can be "conversation" or "summary" - cl_llm = get_bedrock_llm() - - # judge the type and create chain accordingly to store in session state - if type == "conversation": - # return if the Chain is already created - if 'conversation' in st.session_state: - logger.info("conversation session already created") - return st.session_state.conversation - memory = ConversationBufferMemory() - st.session_state.conversation = ConversationChain( - llm=cl_llm, verbose=True, memory=memory - ) - logger.info("conversation session created") - return st.session_state.conversation - elif type == "summary": - # return if the Chain is already created - if 'summary' in st.session_state: - logger.info("summary session already created") - return st.session_state.summary - memory = ConversationBufferMemory() - st.session_state.summary = ConversationChain( - llm=cl_llm, verbose=True, memory=memory - ) - logger.info("summary session created") - return st.session_state.summary - -# todo will update api -def deploy_sagemaker_endpoint(instance_type: str = "ml.g4dn.4xlarge", initial_instance_count: int = 1, - endpoint_name: str = "default-endpoint-for-llm-bot"): - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'x-api-key': API_KEY - } - inputBody = { - "instance_type": instance_type, - "initial_instance_count": initial_instance_count, - "endpoint_name": endpoint_name - } - # https://.execute-api..amazonaws.com/{basePath}/inference/deploy-sagemaker-endpoint - res = requests.post(COMMAND_API_URL + 'inference/deploy-sagemaker-endpoint', headers=headers, json=inputBody) - logger.info("deploy_sagemaker_endpoint: {}".format(res.json())) - -def upload_model(): - pass - -sd_prompt = PromptTemplate.from_template( - """ - Human: - - Transform the input prompt {input} into a detailed prompt for an image generation model, describing the scene with vivid and specific attributes that enhance the original concept, only adjective and noun are allowed, verb and adverb are not allowed, each words speperated by comma. - - Generate a negative prompt that specifies what should be avoided in the image, including any elements that contradict the desired style or tone. - - all the output should be in english. - - Other notes please refer to the following example: - - The output should be a plain text in Python List format shown follows, no extra content added beside Positive Prompt, Negative Prompt. - [ - Positive Prompt: , - Negative Prompt: , - Prompt End String: - ] - - For example: - If the input prompt is: "a cute dog in cartoon style", the output should be as follows: - [ - Positive Prompt: "visually appealing, high-quality image of a cute dog in a vibrant, cartoon style, adorable appearance, expressive eyes, friendly demeanor, artwork.", - Negative Prompt: "realism, dark or dull colors, scary or aggressive dog depictions, overly simplistic, stick figure drawings, blurry or distorted images, inappropriate or NSFW content.", - Prompt End String: - ] - - If the input prompt is: "a girl in photo-realistic style", the output should be as follows: - [ - Positive Prompt: "detailed, photo-realistic, life-like, high-definition, sharp, accurate color tones, realistic textures, natural lighting, subtle expressions, vivid, authentic appearance, real photograph.", - Negative Prompt: "cartoonish, abstract, stylized, overly simplistic, exaggerated, distorted features, bright unrealistic colors, artificial elements, fantasy elements, non-photo-realistic.", - Prompt End String: - ] - - If the input prompt is: "Can you draw a photograph of astronaut floating in space", the output should be as follows: - [ - Positive Prompt: "breathtaking selfie photograph of astronaut floating in space, earth in the background. masterpiece, best quality, highly detailed", - Negative Prompt: "lowres, anime, cartoon, graphic, text, painting, crayon, graphite, abstract glitch, blurry, cropped, worst quality, low quality, watermark", - Prompt End String: - ] - - If the input prompt is: "帮我画一个飞行的宇航员", the output should be as follows: - [ - Positive Prompt: "breathtaking selfie photograph of astronaut floating in space, earth in the background. masterpiece, best quality, highly detailed", - Negative Prompt: "lowres, anime, cartoon, graphic, text, painting, crayon, graphite, abstract glitch, blurry", - Prompt End String: - ] - - If the input prompt is: "Please generate a night street of Tokyo", the output should be as follows: - [ - Positive Prompt: "breathtaking night street of Tokyo, neon lights. masterpiece, best quality, highly detailed", - Negative Prompt: "lowres, anime, cartoon, graphic, text, painting, crayon, graphite, abstract glitch, blurry", - Prompt End String: - ] - - If the input prompt is: "你可以画一个东京的夜景图吗?", the output should be as follows: - [ - Positive Prompt: "breathtaking night street of Tokyo, neon lights. masterpiece, best quality, highly detailed", - Negative Prompt: "lowres, anime, cartoon, graphic, text, painting, crayon, graphite, abstract glitch, blurry", - Prompt End String: - ] - - If the input prompt is: "Generate an empty classroom in anime style", the output should be as follows: - [ - Positive Prompt: "anime artwork an empty classroom. anime style, key visual, vibrant, studio anime, highly detailed", - Negative Prompt: "photo, deformed, black and white, realism, disfigured, low contrast", - Prompt End String: - ] - - If the input prompt is: "i want a photo of 1 realistic girl", the output should be as follows: - [ - Positive Prompt: "masterpiece, best quality,realistic,1girl", - Negative Prompt: "nsfw,(worst quality:2), (low quality:2), (normal quality:2), lowres, ((monochrome)), ((grayscale)), watermark, (bad-hands-5:1.5)", - Prompt End String: - ] - - If the input prompt is: "我想要一张女生的写实照片", the output should be as follows: - [ - Positive Prompt: "best quality,highly detailed, masterpiece, 8k wallpaper, realistic,1girl", - Negative Prompt: "nsfw,(worst quality:2), (low quality:2), (normal quality:2), lowres, ((monochrome)), ((grayscale)), watermark, (bad-hands-5:1.5)", - Prompt End String: - ] - - If the input prompt is: "我想要一张漫画风格的小狗", the output should be as follows: - [ - Positive Prompt: "masterpiece, best quality, cartoon style, dog", - Negative Prompt: "realistic, dark or dull colors, (worst quality:2), (low quality:2), (normal quality:2), lowres, ((monochrome)), ((grayscale)), watermark", - Prompt End String: - ] - - If the input prompt is: "请帮忙画一张朋克风格的猫", the output should be as follows: - [ - Positive Prompt: "masterpiece, best quality, cybernetic cat wears futuristic armor", - Negative Prompt: "dark environment, (worst quality:2), (low quality:2), (normal quality:2), lowres, ((monochrome)), ((grayscale)), watermark", - Prompt End String: - ] - - If the input prompt is: "please draw a Steampunk cat", the output should be as follows: - [ - Positive Prompt: "masterpiece, best quality, cybernetic cat wears futuristic armor", - Negative Prompt: "dark environment, (worst quality:2), (low quality:2), (normal quality:2), lowres, ((monochrome)), ((grayscale)), watermark", - Prompt End String: - ] - - "Do not include style modifiers that do not appear in the question in positive prompt, such as cute, cartoon \n" - - Current conversation: - - {history} - - - Here is the human's next reply: - - {input} - - - Assistant: - """) - -summary_prompt = PromptTemplate.from_template( - """ - Human: - - According the input prompt {input} to generate summary for the image generated by the model. - Current conversation: - - {history} - - - Here is the human's next reply: - - {input} - - - Assistant: - """) - - -def get_llm_processed_prompts(initial_prompt): - conversation = create_or_get_conversation("conversation") - conversation.prompt = sd_prompt - - response = conversation.predict(input=initial_prompt) - logger.info("the first invoke: {}".format(response)) - - # logger.info("the second invoke: {}".format(conversation.predict(input="change to realist style"))) - - # TODO, below parse is not stable and can be changed accord to PE, will update later - # Define regular expressions - positive_pattern = r"Positive Prompt: (.*?),\s+Negative Prompt:" - negative_pattern = r"Negative Prompt: (.*?),\s+Prompt End String:" - - # Extract data using regex - positive_prompt = re.search(positive_pattern, response, re.DOTALL).group(1).strip() - negative_prompt = re.search(negative_pattern, response, re.DOTALL).group(1).strip() - - # remove the " and ' in the prompt - positive_prompt = positive_prompt.replace('"', '').replace("'", "") - negative_prompt = negative_prompt.replace('"', '').replace("'", "") - - logger.info("positive_pattern: {}".format(positive_prompt)) - logger.info("negative_pattern: {}".format(negative_prompt)) - - return positive_prompt, negative_prompt - - -def get_llm_summary(initial_prompt): - summary = create_or_get_conversation("summary") - summary.prompt = summary_prompt - - response = summary.predict(input=initial_prompt) - logger.info("summary response: {}".format(response)) - return response - - -def generate_image(positive_prompts: str, negative_prompts: str, current_col, progress_bar): - job = create_inference_job(default_models) - st.session_state.progress += 5 - progress_bar.progress(st.session_state.progress) - - inference = job["inference"] - - upload_inference_job_api_params(inference["api_params_s3_upload_url"], positive_prompts, negative_prompts) - st.session_state.progress += 5 - progress_bar.progress(st.session_state.progress) - - run_resp = run_inference_job(inference["id"]) - logger.info("run_resp: {}".format(run_resp)) - # if endpoint is not deleted through api, api may return an endpoint not available message - if 'errorMessage' in run_resp: - current_col.error(run_resp['errorMessage']) - return - - st.session_state.progress += 5 - progress_bar.progress(st.session_state.progress) - - while True: - status_response = get_inference_job(inference["id"]) - # if status is not created, increase the progress bar - if status_response['status'] != 'created': - if st.session_state.progress < 80: - st.session_state.progress += 10 - progress_bar.progress(st.session_state.progress) - logger.info("job status: {}".format(status_response['status'])) - if status_response['status'] == 'succeed': - progress_bar.progress(100) - image_url = get_inference_image_output(inference["id"])[0] - current_col.image(image_url, use_column_width=True) - break - elif status_response['status'] == 'failed': - current_col.error("Image generation failed.") - break - else: - time.sleep(1) - - api_params = get_inference_param_output(inference["id"]) - params = requests.get(api_params[0]).json() - info = json.loads(params['info']) - - # debug info - if debug: - if info["prompt"] != "": - current_col.write("prompt:") - current_col.info(info["prompt"]) - - if info["negative_prompt"] != "": - current_col.write("negative_prompt:") - current_col.info(info["negative_prompt"]) - - if info["sd_model_name"] != "": - current_col.write("sd_model_name:") - current_col.info(info["sd_model_name"]) - - for warning in st.session_state.warnings: - current_col.warning(warning) - - return inference["id"] - - -def get_inference_job(inference_id: str): - headers = { - "Content-Type": "application/json", - "Accept": "application/json", - 'x-api-key': API_KEY - } - - job = requests.get(STATUS_API_URL, headers=headers, params={"jobID": inference_id}) - - return job.json() - - -def get_inference_param_output(inference_id: str): - headers = { - "Content-Type": "application/json", - "Accept": "application/json", - 'x-api-key': API_KEY - } - - job = requests.get(PARAM_API_URL, headers=headers, params={"jobID": inference_id}) - - return job.json() - - -def get_inference_image_output(inference_id: str): - headers = { - "Content-Type": "application/json", - "Accept": "application/json", - 'x-api-key': API_KEY - } - - job = requests.get(IMAGE_API_URL, headers=headers, params={"jobID": inference_id}) - - return job.json() - - -def create_inference_job(models: List[str]): - - headers = { - "Content-Type": "application/json", - "Accept": "application/json", - 'x-api-key': API_KEY - } - - # todo use default api params - body = { - "user_id": API_USERNAME, - "task_type": "txt2img", - "models": { - "Stable-diffusion": models, - "embeddings": [] - }, - "filters": { - "createAt": datetime.now().timestamp(), - "creator": "sd-webui" - } - } - - job = requests.post(GENERATE_API_URL, headers=headers, json=body) - return job.json() - - -def run_inference_job(inference_id: str): - headers = { - "Content-Type": "application/json", - "Accept": "application/json", - 'x-api-key': API_KEY - } - - job = requests.put(COMMAND_API_URL + 'inference/v2/' + inference_id + '/run', headers=headers) - - return job.json() - - -def upload_inference_job_api_params(s3_url, positive: str, negative: str): - # todo use default api params - api_params = { - "prompt": positive, - "negative_prompt": negative, - "styles": [], - "seed": -1, - "subseed": -1, - "subseed_strength": 0.0, - "seed_resize_from_h": -1, - "seed_resize_from_w": -1, - "sampler_name": "DPM++ 2M Karras", - "batch_size": 1, - "n_iter": 1, - "steps": 20, - "cfg_scale": 7.0, - "width": 1024, - "height": 1024, - "restore_faces": None, - "tiling": None, - "do_not_save_samples": False, - "do_not_save_grid": False, - "eta": None, - "denoising_strength": None, - "s_min_uncond": 0.0, - "s_churn": 0.0, - "s_tmax": "Infinity", - "s_tmin": 0.0, - "s_noise": 1.0, - "override_settings": {}, - "override_settings_restore_afterwards": True, - "refiner_checkpoint": None, - "refiner_switch_at": None, - "disable_extra_networks": False, - "comments": {}, - "enable_hr": False, - "firstphase_width": 0, - "firstphase_height": 0, - "hr_scale": 2.0, - "hr_upscaler": "Latent", - "hr_second_pass_steps": 0, - "hr_resize_x": 0, - "hr_resize_y": 0, - "hr_checkpoint_name": None, - "hr_sampler_name": None, - "hr_prompt": "", - "hr_negative_prompt": "", - "sampler_index": "DPM++ 2M Karras", - "script_name": None, - "script_args": [], - "send_images": True, - "save_images": False, - "alwayson_scripts": { - "refiner": { - "args": [False, "", 0.8] - }, - "seed": { - "args": [-1, False, -1, 0, 0, 0] - }, - "controlnet": { - "args": [ - { - "enabled": False, - "module": "none", - "model": "None", - "weight": 1, - "image": None, - "resize_mode": "Crop and Resize", - "low_vram": False, - "processor_res": -1, - "threshold_a": -1, - "threshold_b": -1, - "guidance_start": 0, - "guidance_end": 1, - "pixel_perfect": False, - "control_mode": "Balanced", - "is_ui": True, - "input_mode": "simple", - "batch_images": "", - "output_dir": "", - "loopback": False - }, - { - "enabled": False, - "module": "none", - "model": "None", - "weight": 1, - "image": None, - "resize_mode": "Crop and Resize", - "low_vram": False, - "processor_res": -1, - "threshold_a": -1, - "threshold_b": -1, - "guidance_start": 0, - "guidance_end": 1, - "pixel_perfect": False, - "control_mode": "Balanced", - "is_ui": True, - "input_mode": "simple", - "batch_images": "", - "output_dir": "", - "loopback": False - }, - { - "enabled": False, - "module": "none", - "model": "None", - "weight": 1, - "image": None, - "resize_mode": "Crop and Resize", - "low_vram": False, - "processor_res": -1, - "threshold_a": -1, - "threshold_b": -1, - "guidance_start": 0, - "guidance_end": 1, - "pixel_perfect": False, - "control_mode": "Balanced", - "is_ui": True, - "input_mode": "simple", - "batch_images": "", - "output_dir": "", - "loopback": False - } - ] - }, - "segment anything": { - "args": [ - False, - False, - 0, - None, - [], - 0, - False, - [], - [], - False, - 0, - 1, - False, - False, - 0, - None, - [], - -2, - False, - [], - False, - 0, - None, - None - ] - }, - "extra options": { - "args": [] - } - } - } - - json_string = json.dumps(api_params) - response = requests.put(s3_url, data=json_string) - response.raise_for_status() - return response - - -def generate_llm_image(initial_prompt: str, col): - st.spinner() - st.session_state.progress = 5 - # Keep one progress bar instance for each column - progress_bar = col.progress(st.session_state.progress) - - try: - generate_llm_image_col(initial_prompt, col, progress_bar) - st.session_state.succeed_count += 1 - progress_bar.empty() - progress_bar.hidden = True - except Exception as e: - # Exceed the retry limit - col.error("Image generation failed, please try again.") - raise e - - -@retry(stop=stop_after_attempt(1)) -def generate_llm_image_col(initial_prompt: str, col, progress_bar): - positive_prompt, negative_prompt = get_llm_processed_prompts(initial_prompt) - st.session_state.progress += 15 - progress_bar.progress(st.session_state.progress) - - # if prompt is empty, use default - if positive_prompt == "" or negative_prompt == "": - positive_prompt = initial_prompt - # add original prompt to ensure the original subject in the final positive prompt - else: - positive_prompt = initial_prompt + "," + positive_prompt - - # if len(model_index_list) > 0: - # # TODO, support model list should align with prompt template, we assume the model list is fixed at 2 - # models = [support_model_list[int(index)] for index in model_index_list.strip("[]").split(",")] - - # select the model in model list according to the order while keep the List type to compatible with genegrate_image, e.g. models: ['LahCuteCartoonSDXL_alpha.safetensors', 'majicmixRealistic_v7.safetensors'] - # models = [models[order]] - - # This is a synchronous call, will block the UI - generate_image(positive_prompt, negative_prompt, col, progress_bar) - - -# Generator function -def image_generator(prompt, cols): - for idx, col in enumerate(cols): - yield generate_llm_image, (prompt, col) - - -# main entry point for serve -# python -m streamlit run image_generation.py --server.port 8088 - -# main entry point for debugging -# DEBUG=true python -m streamlit run image_generation.py --server.port 8088 -if __name__ == "__main__": - try: - st.set_page_config(page_title="Da Vinci", layout="wide") - st.title("Da Vinci") - - # Sidebar logo - st.sidebar.image("https://d0.awsstatic.com/logos/powered-by-aws.png", width=200) - - debug = os.getenv("DEBUG", "false").lower() == "true" - - # User input - prompt = st.text_input("What image do you want to create today?", "A cute dog") - button = st.button('Generate Image') - - if button: - st.session_state.warnings = [] - st.session_state.succeed_count = 0 - # 2*2 layout image grids - col1, col2 = st.columns(2) - col3, col4 = st.columns(2) - cols = [col1, col2, col3, col4] - # Create a generator for image generation tasks - generator = image_generator(prompt, cols) - - # Execute each image generation task - for func, args in generator: - try: - func(*args) - except Exception as e: - logger.exception(e) - # Each task can retry 5 times - # When one task fails, the next will not be executed - break - - # output box to summarize the image grid if succeed at least one image - if st.session_state.succeed_count > 0: - summary = st.subheader("In Summary...") - response = get_llm_summary(prompt) - summary.subheader("Summary") - st.success(response) - - except Exception as e: - logger.exception(e) - raise e diff --git a/source/panel/sd/requirements.txt b/source/panel/sd/requirements.txt deleted file mode 100644 index 8d9338145..000000000 --- a/source/panel/sd/requirements.txt +++ /dev/null @@ -1,9 +0,0 @@ -python-dotenv -PyPDF2 -streamlit==1.37.0 -langchain==0.1.0 -openai==1.1.0 -tiktoken==0.5.1 -boto3==1.28.84 -nougat-ocr==0.1.17 -tenacity==8.2.2 diff --git a/source/portal/src/pages/chatbot/ChatBot.tsx b/source/portal/src/pages/chatbot/ChatBot.tsx index 5fdf8a2eb..12b6e102c 100644 --- a/source/portal/src/pages/chatbot/ChatBot.tsx +++ b/source/portal/src/pages/chatbot/ChatBot.tsx @@ -102,7 +102,7 @@ const ChatBot: React.FC = (props: ChatBotProps) => { const [useChatHistory, setUseChatHistory] = useState(localStorage.getItem(USE_CHAT_HISTORY) == null || localStorage.getItem(USE_CHAT_HISTORY) == "true" ? true : false); const [enableTrace, setEnableTrace] = useState(localStorage.getItem(ENABLE_TRACE) == null || localStorage.getItem(ENABLE_TRACE) == "true" ? true : false); const [showTrace, setShowTrace] = useState(enableTrace); - const [onlyRAGTool, setOnlyRAGTool] = useState(localStorage.getItem(ONLY_RAG_TOOL) == null || localStorage.getItem(ONLY_RAG_TOOL) == "false" ? false : true); + const [onlyRAGTool, setOnlyRAGTool] = useState(localStorage.getItem(ONLY_RAG_TOOL) == null || localStorage.getItem(ONLY_RAG_TOOL) == "true" ? true : false); const [isComposing, setIsComposing] = useState(false); // const [useWebSearch, setUseWebSearch] = useState(false); // const [googleAPIKey, setGoogleAPIKey] = useState(''); diff --git a/source/script/build.sh b/source/script/build.sh index ced685e76..70f0835fb 100644 --- a/source/script/build.sh +++ b/source/script/build.sh @@ -56,9 +56,19 @@ build_deployment_module() { dmaa bootstrap } +build_lambda_asset() { + echo "Building Lambda Asset" + cd script + bash build-s3-dist.sh + cd - > /dev/null +} + modules_prepared="" cd .. +build_lambda_asset +modules_prepared="${modules_prepared}Lambda Deployment, " + if $ui_enabled; then build_frontend modules_prepared="${modules_prepared}Frontend, "