构建无服务器 ChatGPT 支持的简历助手 - 基础(二)

2023-11-12

之前我们制作了一个简洁的小命令行工具,可以用来帮助我们构建更好的简历。现在我们将该应用程序部署到云中!

我将使用 AWS CDK,因为我喜欢它,而且它使此类事情变得相对简单。如果愿意,您当然可以将这些说明改编为 Terraform。首先让我们开始一个 CDK 项目,然后我们可以讨论我们需要为项目的这一部分提供什么。

启动一个新的CDK项目

创建一个新的项目目录和cdk init项目。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">mkdir </span>resume-assistant
<span style="color:var(--syntax-text-color)">cd </span>resume-assistant
cdk init app <span style="color:var(--syntax-error-color)">--language</span> python
</code></span></span>

设置虚拟环境并安装软件包。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>python3 <span style="color:var(--syntax-error-color)">-m</span> venv .venv
<span style="color:var(--syntax-text-color)">source</span> .venv/bin/activate   
pip <span style="color:var(--syntax-text-color)">install</span> <span style="color:var(--syntax-error-color)">-r</span> requirements.txt
</code></span></span>

现在我们已经设置了存储库,以下是我们要放入其中的内容。

  1. 包含 Lambda 代码的目录(我们将对其进行一些修改)
  2. 用于创建 S3 存储桶来存储我们的对话“状态”的 CDK 代码
  3. 用于创建 Lambda 函数来运行我们的代码的 CDK 代码
  4. CDK代码创建一个函数URL以便我们可以调用该函数

让我们开始吧!

Python 应用程序的新栖息地

在 CDK 存储库的根目录中创建一个名为的新文件夹,并从我们之前会话的目录中chat_lambda复制您的文件app.pyrequirements.txt文件。chat_app

我们本质上是分叉这些代码,并将以不同的方式修改它们中的每一个,以达到我们想要的目标。chat_lambdaCDK 将被告知 lambda 函数的代码所在的目录。假设您正在运行 docker(确保您正在运行 docker),CDK 将根据您指定的运行时创建一个容器,在requirements.txt 中安装依赖项,添加您的代码,然后将整个内容压缩并将其部署为拉姆达函数。它太酷了。让我们开始 Lambda-fying 我们的代码。

首先,由于最近的一些原因,我们需要减少

lambda_handler传统规定我们通过带有一些参数(特别是参数)的方法进入函数event。让我们重构lambda_handler并期望我们要发送的请求将位于bodyevent

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)"># chat_lambda/app.py
</span>
<span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">openai</span>
<span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">os</span>
<span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">json</span>
<span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">logging</span>

<span style="color:var(--syntax-text-color)">openai</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">api_key</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">os</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">environ</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">get</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">'OPENAI_API_KEY'</span><span style="color:var(--syntax-text-color)">)</span>

<span style="color:var(--syntax-text-color)">logger</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">logging</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">getLogger</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-text-color)">logger</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">setLevel</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">logging</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">INFO</span><span style="color:var(--syntax-text-color)">)</span>


<span style="color:var(--syntax-declaration-color)">def</span> <span style="color:var(--syntax-name-color)">lambda_handler</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">event</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">context</span><span style="color:var(--syntax-text-color)">):</span>
    <span style="color:var(--syntax-text-color)">logger</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">info</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">event</span><span style="color:var(--syntax-text-color)">)</span>

    <span style="color:var(--syntax-text-color)">payload</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">loads</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">event</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-string-color)">"body"</span><span style="color:var(--syntax-text-color)">])</span>
    <span style="color:var(--syntax-text-color)">resume</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">payload</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-string-color)">"resume"</span><span style="color:var(--syntax-text-color)">]</span>
    <span style="color:var(--syntax-text-color)">jd</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">payload</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-string-color)">"jd"</span><span style="color:var(--syntax-text-color)">]</span>

    <span style="color:var(--syntax-text-color)">messages</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">[</span>
        <span style="color:var(--syntax-text-color)">{</span><span style="color:var(--syntax-string-color)">"role"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"system"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"content"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"You are a resume review assistant. You will be provided information about a job candidate. that information might be in the form of a formatted resume, or just a sentence about themselves. You also may also receive a description of a job or position sought by the candidate. Your task as the assistant is to prompt the candidate for additional information they could add to their resume to make it better generally, and more well suited for the job they are seeking specifically. Don't shy away from asking and promoting transferrable and soft skills."</span><span style="color:var(--syntax-text-color)">},</span>
    <span style="color:var(--syntax-text-color)">]</span>
    <span style="color:var(--syntax-text-color)">messages</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">append</span><span style="color:var(--syntax-text-color)">({</span><span style="color:var(--syntax-string-color)">"role"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"user"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"content"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">f</span><span style="color:var(--syntax-string-color)">"Candidate information: </span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">resume</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">})</span>
    <span style="color:var(--syntax-text-color)">messages</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">append</span><span style="color:var(--syntax-text-color)">({</span><span style="color:var(--syntax-string-color)">"role"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"user"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"content"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">f</span><span style="color:var(--syntax-string-color)">"Description of the job they want: </span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">jd</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">})</span>

    <span style="color:var(--syntax-text-color)">completion</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">openai</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">ChatCompletion</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">create</span><span style="color:var(--syntax-text-color)">(</span>
        <span style="color:var(--syntax-text-color)">model</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-string-color)">"gpt-3.5-turbo"</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-text-color)">messages</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">messages</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">)</span>

    <span style="color:var(--syntax-text-color)">assistant_response</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">completion</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">choices</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">].</span><span style="color:var(--syntax-text-color)">message</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">content</span>
    <span style="color:var(--syntax-text-color)">logger</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">info</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">assistant_response</span><span style="color:var(--syntax-text-color)">)</span>

    <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-string-color)">"statusCode"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">200</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-string-color)">"headers"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">{</span>
            <span style="color:var(--syntax-string-color)">"Access-Control-Allow-Headers"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"*"</span>
        <span style="color:var(--syntax-text-color)">},</span>
        <span style="color:var(--syntax-string-color)">"body"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">dumps</span><span style="color:var(--syntax-text-color)">({</span>
            <span style="color:var(--syntax-string-color)">"message"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">assistant_response</span>
            <span style="color:var(--syntax-text-color)">})</span>
    <span style="color:var(--syntax-text-color)">}</span>
</code></span></span>

所以您会注意到我们还添加了一些日志记录。因为它处于 INFO 级别,所以如果我们在本地运行它,我们将无法在 stdout 中看到它,但它会登录 Lambda 并在 CloudWatch 中可用,以帮助我们在做错了什么时进行故障排除。我们通常这样做!

您还会注意到,该函数将在事件正文中查找简历和工作描述作为 和 的值resumejd当我们调用这个函数时,我们需要确保提供它们。

最后,我们以一种实际上不允许我们继续对话的方式返回助理的响应。那将在以后出现。

S3 状态桶

桶很简单。我们将确保对象是加密且非公开的,并设置索引。因为我们只是玩玩,所以我们还将 和 设置removal_policyauto_delete_objects使清理更容易的值。我们将在函数本身之前进行此操作,以便我们可以将其标识作为环境变量传递给函数。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)"># resume_assistant/resume_assistant_stack.py
</span>
<span style="color:var(--syntax-error-color)">from</span> <span style="color:var(--syntax-text-color)">aws_cdk</span> <span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">aws_s3</span> <span style="color:var(--syntax-declaration-color)">as</span> <span style="color:var(--syntax-text-color)">s3</span>
<span style="color:var(--syntax-error-color)">from</span> <span style="color:var(--syntax-text-color)">aws_cdk</span> <span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">RemovalPolicy</span>

<span style="color:var(--syntax-declaration-color)">class</span> <span style="color:var(--syntax-name-color)">ResumeAssistantStack</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">Stack</span><span style="color:var(--syntax-text-color)">):</span>
    <span style="color:var(--syntax-declaration-color)">def</span> <span style="color:var(--syntax-name-color)">__init__</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">self</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">scope</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">Construct</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">construct_id</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">str</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-error-color)">**</span><span style="color:var(--syntax-text-color)">kwargs</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">-></span> <span style="color:var(--syntax-text-color)">None</span><span style="color:var(--syntax-text-color)">:</span>
        <span style="color:var(--syntax-text-color)">super</span><span style="color:var(--syntax-text-color)">().</span><span style="color:var(--syntax-text-color)">__init__</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">scope</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">construct_id</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-error-color)">**</span><span style="color:var(--syntax-text-color)">kwargs</span><span style="color:var(--syntax-text-color)">)</span>

        <span style="color:var(--syntax-text-color)">chat_log_bucket</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">s3</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">Bucket</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">self</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"ChatLogBucket"</span><span style="color:var(--syntax-text-color)">,</span>
            <span style="color:var(--syntax-text-color)">versioned</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">True</span><span style="color:var(--syntax-text-color)">,</span>
            <span style="color:var(--syntax-text-color)">encryption</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">s3</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">BucketEncryption</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">S3_MANAGED</span><span style="color:var(--syntax-text-color)">,</span>
            <span style="color:var(--syntax-text-color)">enforce_ssl</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">True</span><span style="color:var(--syntax-text-color)">,</span>
            <span style="color:var(--syntax-text-color)">block_public_access</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">s3</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">BlockPublicAccess</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">BLOCK_ALL</span><span style="color:var(--syntax-text-color)">,</span>
            <span style="color:var(--syntax-text-color)">removal_policy</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">RemovalPolicy</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">DESTROY</span><span style="color:var(--syntax-text-color)">,</span>
            <span style="color:var(--syntax-text-color)">auto_delete_objects</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">True</span><span style="color:var(--syntax-text-color)">,</span>
            <span style="color:var(--syntax-text-color)">public_read_access</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">False</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-text-color)">)</span>
</code></span></span>

__init__注意:将来对 CDK 代码的所有添加(减去模块导入)都将在类中的该函数内ResumeAssistantStack以与上述相同的缩进级别完成chat_log_bucket。因此,这意味着如果您复制并粘贴代码块,您将必须自己进行一些缩进。

拉姆达函数

这个应用程序的明星!我们需要重构函数代码主体(我们之前“分叉”的代码)中的一些东西,但首先,让我们在 CDK 中创建函数基础结构。要让 CDK 实际构建和打包 lambda,您需要使用 alpha 模块。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code># requirements.txt

aws-cdk.aws-lambda-python-alpha
</code></span></span>

安装它

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>pip <span style="color:var(--syntax-text-color)">install</span> <span style="color:var(--syntax-error-color)">-r</span> requirements.txt
</code></span></span>

现在您将能够在 CDK 代码中使用这两个模块。
我们还可以为您的 lambda 添加读取和写入最后一个存储桶的权限。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)"># resume_assistant/resume_assistant_stack.py
</span>
<span style="color:var(--syntax-error-color)">from</span> <span style="color:var(--syntax-text-color)">aws_cdk</span> <span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">aws_lambda_python_alpha</span> <span style="color:var(--syntax-declaration-color)">as</span> <span style="color:var(--syntax-text-color)">p_lambda</span>
<span style="color:var(--syntax-error-color)">from</span> <span style="color:var(--syntax-text-color)">aws_cdk</span> <span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">aws_lambda</span> <span style="color:var(--syntax-declaration-color)">as</span> <span style="color:var(--syntax-text-color)">_lambda</span>
<span style="color:var(--syntax-error-color)">from</span> <span style="color:var(--syntax-text-color)">aws_cdk</span> <span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">Duration</span>
<span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">os</span>

<span style="color:var(--syntax-text-color)">chat_lambda</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">p_lambda</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">PythonFunction</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">self</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"ChatFunction"</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">runtime</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">_lambda</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">Runtime</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">PYTHON_3_10</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">timeout</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">Duration</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">seconds</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">60</span><span style="color:var(--syntax-text-color)">),</span>
    <span style="color:var(--syntax-text-color)">memory_size</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-literal-color)">256</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">entry</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-string-color)">"chat_lambda"</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">index</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-string-color)">"app.py"</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">handler</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-string-color)">"lambda_handler"</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">environment</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-string-color)">"CHAT_LOG_BUCKET"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">chat_log_bucket</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">bucket_name</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-string-color)">"OPENAI_API_KEY"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">os</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">environ</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">get</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"OPENAI_API_KEY"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"empty"</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-text-color)">},</span>
<span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">chat_log_bucket</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">grant_read_write</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">chat_lambda</span><span style="color:var(--syntax-text-color)">)</span>
</code></span></span>

上面的代码中有很多地方需要注意。首先,lambda 没有为其配置太多内存。这可能没问题。它实际上不会做太多计算,只是向 OpenAI 发送请求,然后传递响应。OPENAI_API_KEY其次,我们从本地环境变量进行设置,因为我将在本地构建和部署它,因此它可以访问我的环境变量。如果您打算从管道或其他东西构建和部署它,您必须确保您的管道也从管道秘密加载该值。

这是您第二次提醒请记住在 OpenAI 计费选项卡中为自己设置非常低的使用限制。您可能永远不会花费超过一美元左右,但如果您公开这一点,那么您就不会想要一个意外的账单。

函数地址

因为在很多情况下 OpenAI API 需要花费时间来响应我们(例如,当我们告诉它使用我们给它的所有上下文来解析完全格式化的简历时),我们不能使用API 网关在 29 秒后超时。我们将改用 Lambda 函数 URL。我们暂时将 CORS 保持打开状态,并确保输出该函数 URL。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)"># resume_assistant/resume_assistant_stack.py
</span>
<span style="color:var(--syntax-error-color)">from</span> <span style="color:var(--syntax-text-color)">aws_cdk</span> <span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">aws_lambda</span> <span style="color:var(--syntax-declaration-color)">as</span> <span style="color:var(--syntax-text-color)">_lambda</span>
<span style="color:var(--syntax-error-color)">from</span> <span style="color:var(--syntax-text-color)">aws_cdk</span> <span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">CfnOutput</span>

<span style="color:var(--syntax-text-color)">function_url</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">chat_lambda</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">add_function_url</span><span style="color:var(--syntax-text-color)">(</span>
    <span style="color:var(--syntax-text-color)">auth_type</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">_lambda</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">FunctionUrlAuthType</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">NONE</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">cors</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">_lambda</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">FunctionUrlCorsOptions</span><span style="color:var(--syntax-text-color)">(</span>
        <span style="color:var(--syntax-text-color)">allowed_origins</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-string-color)">"*"</span><span style="color:var(--syntax-text-color)">],</span>
        <span style="color:var(--syntax-text-color)">allowed_headers</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-string-color)">"*"</span><span style="color:var(--syntax-text-color)">],</span>
    <span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">)</span>

<span style="color:var(--syntax-text-color)">CfnOutput</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">self</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"ChatFunctionURL"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">value</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">function_url</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">url</span><span style="color:var(--syntax-text-color)">)</span>
</code></span></span>

现在,您的 S3 存储桶、函数和函数 URL 应该部署到 AWS,并且您应该有函数 URL 的地址。

让我们开始测试

我们现在要测试我们的函数和函数 URL。让我们回到将其复制到 CDK 项目之前的 python 项目并对其进行修改,以便它调用我们的 Lambda URL 而不是 OpenAI API。

我们将从简单开始,将这些resume和jd值设置为我们拥有的文件,通过Lambda URL将它们发送到Lambda,看看我们是否得到一致的响应。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)"># chat_app/app.py
</span>
<span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">requests</span>

<span style="color:var(--syntax-comment-color)"># Add your function URL from your CDK output here
</span><span style="color:var(--syntax-text-color)">function_url</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">"https://th1si5n0tmyactua1lam8daur1.lambda-url.us-east-1.on.aws/"</span>

<span style="color:var(--syntax-declaration-color)">with</span> <span style="color:var(--syntax-text-color)">open</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"resume.txt"</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-declaration-color)">as</span> <span style="color:var(--syntax-text-color)">f</span><span style="color:var(--syntax-text-color)">:</span>
    <span style="color:var(--syntax-text-color)">resume</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">f</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">readlines</span><span style="color:var(--syntax-text-color)">()</span>

<span style="color:var(--syntax-declaration-color)">with</span> <span style="color:var(--syntax-text-color)">open</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"jd.txt"</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-declaration-color)">as</span> <span style="color:var(--syntax-text-color)">f</span><span style="color:var(--syntax-text-color)">:</span>
    <span style="color:var(--syntax-text-color)">jd</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">f</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">readlines</span><span style="color:var(--syntax-text-color)">()</span>

<span style="color:var(--syntax-text-color)">response</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">requests</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">get</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">function_url</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-comment-color)"># this will be added to the event body
</span>    <span style="color:var(--syntax-string-color)">"resume"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">resume</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-string-color)">"jd"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">jd</span>
<span style="color:var(--syntax-text-color)">})</span>

<span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">response</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-text-color)">()[</span><span style="color:var(--syntax-string-color)">"message"</span><span style="color:var(--syntax-text-color)">])</span>
</code></span></span>

我的回应:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>⚡  python app.py
Can you please provide me with more details on your responsibilities as a team member at Old Navy? Also, what were some of your duties as a crew member at McDonald's? This would help me understand your previous roles and identify the transferable skills you have that align with the requirements mentioned in the job description.
</code></span></span>

好的!因此,我们现在将初始请求发送到我们的 Lambda,它添加我们的系统消息并将初始完成请求发送到 OpenAI,解析响应并将其发送回给我们!

但我们需要继续对话

是的,我们需要进行一些重构才能进行对话。我们需要一种存储该对话的方法(S3 存储桶),以及一种识别我们现在正在进行的对话的方法。

这是为此的计划。我们将重构 Lambda 以查找除 jd 和简历之外的一些内容。我们将在请求正文中添加一些附加信息: auuid和 a user_response

当我们启动对话时,密钥uuid将保留一个空字符串""作为其值,这将告诉 Lambda 这是一个对话并生成一个新的 uuid 来跟踪对话。然后,此 uuid 将在响应中返回给用户,以便用户可以在下一个请求中将其传回 Lambda,从而允许它继续对话。

<uuid>.txt这还允许我们通过放置(和获取)我们创建的 S3 存储桶中指定的对象来存储(和检索)对话的状态。

user_response键最初也会保存一个空字符串作为其值(因为第一条消息将只包含简历和 jd),但随着对话的继续,它将保存用户的回复。

我们首先修改 Lambda 代码的要求,以便它可以使用 AWS 的 boto3 python 库。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code># chat_lambda/requirements.txt

boto3>=1.26
</code></span></span>

现在我们可以使用 boto 来处理 Lambda 中的 S3 存储桶。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)"># chat_lambda/app.py
</span>
<span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">openai</span>
<span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">os</span>
<span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">json</span>
<span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">logging</span>
<span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">boto3</span>
<span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">uuid</span>

<span style="color:var(--syntax-text-color)">openai</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">api_key</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">os</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">environ</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">get</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"OPENAI_API_KEY"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">CHAT_LOG_BUCKET</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">os</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">environ</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">get</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"CHAT_LOG_BUCKET"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">s3</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">boto3</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">client</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">'s3'</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">region_name</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">os</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">environ</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">get</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">'AWS_REGION'</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"us-east-1"</span><span style="color:var(--syntax-text-color)">))</span>


<span style="color:var(--syntax-text-color)">logger</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">logging</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">getLogger</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-text-color)">logger</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">setLevel</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">logging</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">INFO</span><span style="color:var(--syntax-text-color)">)</span>

<span style="color:var(--syntax-declaration-color)">def</span> <span style="color:var(--syntax-name-color)">load_file_from_s3</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">bucket</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">key</span><span style="color:var(--syntax-text-color)">):</span>
    <span style="color:var(--syntax-text-color)">response</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">s3</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">get_object</span><span style="color:var(--syntax-text-color)">(</span>
        <span style="color:var(--syntax-text-color)">Bucket</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">bucket</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-text-color)">Key</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">key</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">response</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-string-color)">'Body'</span><span style="color:var(--syntax-text-color)">].</span><span style="color:var(--syntax-text-color)">read</span><span style="color:var(--syntax-text-color)">().</span><span style="color:var(--syntax-text-color)">decode</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">'utf-8'</span><span style="color:var(--syntax-text-color)">)</span>

<span style="color:var(--syntax-declaration-color)">def</span> <span style="color:var(--syntax-name-color)">save_file_to_s3</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">bucket</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">key</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">data</span><span style="color:var(--syntax-text-color)">):</span>
    <span style="color:var(--syntax-text-color)">response</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">s3</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">put_object</span><span style="color:var(--syntax-text-color)">(</span>
        <span style="color:var(--syntax-text-color)">Bucket</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">bucket</span><span style="color:var(--syntax-text-color)">,</span> 
        <span style="color:var(--syntax-text-color)">Key</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">key</span><span style="color:var(--syntax-text-color)">,</span> 
        <span style="color:var(--syntax-text-color)">Body</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">data</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">response</span>

<span style="color:var(--syntax-declaration-color)">def</span> <span style="color:var(--syntax-name-color)">lambda_handler</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">event</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">context</span><span style="color:var(--syntax-text-color)">):</span>
    <span style="color:var(--syntax-text-color)">logger</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">info</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">event</span><span style="color:var(--syntax-text-color)">)</span>

    <span style="color:var(--syntax-text-color)">payload</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">loads</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">event</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-string-color)">"body"</span><span style="color:var(--syntax-text-color)">])</span>
    <span style="color:var(--syntax-text-color)">chat_uuid</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">payload</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-string-color)">"uuid"</span><span style="color:var(--syntax-text-color)">]</span>
    <span style="color:var(--syntax-text-color)">resume</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">payload</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-string-color)">"resume"</span><span style="color:var(--syntax-text-color)">]</span>
    <span style="color:var(--syntax-text-color)">jd</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">payload</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-string-color)">"jd"</span><span style="color:var(--syntax-text-color)">]</span>
    <span style="color:var(--syntax-text-color)">user_response</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">payload</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-string-color)">"user_response"</span><span style="color:var(--syntax-text-color)">]</span>

    <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">chat_uuid</span> <span style="color:var(--syntax-error-color)">==</span> <span style="color:var(--syntax-string-color)">""</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-comment-color)"># this is a new chat
</span>        <span style="color:var(--syntax-text-color)">chat_uuid</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">str</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">uuid</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">uuid4</span><span style="color:var(--syntax-text-color)">())</span>
        <span style="color:var(--syntax-text-color)">logger</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">info</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">f</span><span style="color:var(--syntax-string-color)">"Creating new uuid: </span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">chat_uuid</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">)</span>
        <span style="color:var(--syntax-text-color)">messages</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">[</span>
            <span style="color:var(--syntax-text-color)">{</span><span style="color:var(--syntax-string-color)">"role"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"system"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"content"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"You are a resume review assistant. You will be provided information about a job candidate. that information might be in the form of a formatted resume, or just a sentence about themselves. You also may also receive a description of a job or position sought by the candidate. Your task as the assistant is to prompt the candidate for additional information they could add to their resume to make it better generally, and more well suited for the job they are seeking specifically. Don't shy away from asking and promoting transferrable and soft skills."</span><span style="color:var(--syntax-text-color)">},</span>
        <span style="color:var(--syntax-text-color)">]</span>
        <span style="color:var(--syntax-text-color)">messages</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">append</span><span style="color:var(--syntax-text-color)">({</span><span style="color:var(--syntax-string-color)">"role"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"user"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"content"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">f</span><span style="color:var(--syntax-string-color)">"Candidate information: </span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">resume</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">})</span>
        <span style="color:var(--syntax-text-color)">messages</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">append</span><span style="color:var(--syntax-text-color)">({</span><span style="color:var(--syntax-string-color)">"role"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"user"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"content"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">f</span><span style="color:var(--syntax-string-color)">"Description of the job they want: </span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">jd</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">})</span>
        <span style="color:var(--syntax-text-color)">logger</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">info</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">save_file_to_s3</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">CHAT_LOG_BUCKET</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">f</span><span style="color:var(--syntax-string-color)">"chat_history/</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">chat_uuid</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-string-color)">.txt"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">dumps</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">messages</span><span style="color:var(--syntax-text-color)">)))</span>

    <span style="color:var(--syntax-declaration-color)">else</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-comment-color)"># this is an existing chat
</span>        <span style="color:var(--syntax-text-color)">logger</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">info</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">f</span><span style="color:var(--syntax-string-color)">"Loading uuid: </span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">chat_uuid</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">)</span>
        <span style="color:var(--syntax-text-color)">messages</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">loads</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">load_file_from_s3</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">CHAT_LOG_BUCKET</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">f</span><span style="color:var(--syntax-string-color)">"chat_history/</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">chat_uuid</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-string-color)">.txt"</span><span style="color:var(--syntax-text-color)">))</span>
        <span style="color:var(--syntax-text-color)">messages</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">append</span><span style="color:var(--syntax-text-color)">({</span><span style="color:var(--syntax-string-color)">"role"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"user"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"content"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">user_response</span><span style="color:var(--syntax-text-color)">})</span>


    <span style="color:var(--syntax-text-color)">completion</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">openai</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">ChatCompletion</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">create</span><span style="color:var(--syntax-text-color)">(</span>
        <span style="color:var(--syntax-text-color)">model</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-string-color)">"gpt-3.5-turbo"</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-text-color)">messages</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">messages</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">)</span>

    <span style="color:var(--syntax-text-color)">assistant_response</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">completion</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">choices</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">].</span><span style="color:var(--syntax-text-color)">message</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">content</span>
    <span style="color:var(--syntax-text-color)">messages</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">append</span><span style="color:var(--syntax-text-color)">({</span><span style="color:var(--syntax-string-color)">"role"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"assistant"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"content"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">assistant_response</span><span style="color:var(--syntax-text-color)">})</span>
    <span style="color:var(--syntax-text-color)">logger</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">info</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">save_file_to_s3</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">CHAT_LOG_BUCKET</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">f</span><span style="color:var(--syntax-string-color)">"chat_history/</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">chat_uuid</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-string-color)">.txt"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">dumps</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">messages</span><span style="color:var(--syntax-text-color)">)))</span>

    <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-string-color)">"statusCode"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">200</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-string-color)">"headers"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">{</span>
            <span style="color:var(--syntax-string-color)">"Access-Control-Allow-Headers"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"*"</span>
        <span style="color:var(--syntax-text-color)">},</span>
        <span style="color:var(--syntax-string-color)">"body"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">dumps</span><span style="color:var(--syntax-text-color)">({</span>
            <span style="color:var(--syntax-string-color)">"message"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">assistant_response</span><span style="color:var(--syntax-text-color)">,</span>
            <span style="color:var(--syntax-string-color)">"uuid"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">chat_uuid</span><span style="color:var(--syntax-text-color)">,</span>
            <span style="color:var(--syntax-text-color)">})</span>
    <span style="color:var(--syntax-text-color)">}</span>
</code></span></span>

您应该主要注意 S3 方法中添加的保存和加载以及它们如何利用uuid值以及函数如何流动,具体取决于它是没有 uuid 的新对话还是带有预先存在的 uuid 的后续对话uuid。

现在让我们修改我们的 Python 应用程序,该应用程序调用 Lambda 以传入所需的信息,并将请求循环到我们的 Lambda 直到退出。请注意,我在初次提交后清除了resume和值。jd我们不需要到处乱扔这些额外的数据。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)"># chat_app/app.py
</span>
<span style="color:var(--syntax-comment-color)"># Add your function URL from your CDK output here
</span><span style="color:var(--syntax-text-color)">function_url</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">"https://th1si5n0tmyactua1lam8daur1.lambda-url.us-east-1.on.aws/"</span>

<span style="color:var(--syntax-declaration-color)">with</span> <span style="color:var(--syntax-text-color)">open</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"resume.txt"</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-declaration-color)">as</span> <span style="color:var(--syntax-text-color)">f</span><span style="color:var(--syntax-text-color)">:</span>
    <span style="color:var(--syntax-text-color)">resume</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">f</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">readlines</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-declaration-color)">with</span> <span style="color:var(--syntax-text-color)">open</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"jd.txt"</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-declaration-color)">as</span> <span style="color:var(--syntax-text-color)">f</span><span style="color:var(--syntax-text-color)">:</span>
    <span style="color:var(--syntax-text-color)">jd</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">f</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">readlines</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-text-color)">user_response</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">""</span>
<span style="color:var(--syntax-text-color)">chat_uuid</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">""</span>
<span style="color:var(--syntax-declaration-color)">while</span> <span style="color:var(--syntax-text-color)">user_response</span> <span style="color:var(--syntax-error-color)">not</span> <span style="color:var(--syntax-error-color)">in</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-string-color)">"quit"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"Quit"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"stop"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"Stop"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"exit"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"Exit"</span><span style="color:var(--syntax-text-color)">]:</span>
    <span style="color:var(--syntax-text-color)">response</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">requests</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">get</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">function_url</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-string-color)">"resume"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">resume</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-string-color)">"jd"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">jd</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-string-color)">"uuid"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">chat_uuid</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-string-color)">"user_response"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">user_response</span>
    <span style="color:var(--syntax-text-color)">})</span>
    <span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">response</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-text-color)">()[</span><span style="color:var(--syntax-string-color)">"message"</span><span style="color:var(--syntax-text-color)">])</span>
    <span style="color:var(--syntax-text-color)">chat_uuid</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">response</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-text-color)">()[</span><span style="color:var(--syntax-string-color)">"uuid"</span><span style="color:var(--syntax-text-color)">]</span>
    <span style="color:var(--syntax-text-color)">user_response</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">input</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-literal-color)">\n</span><span style="color:var(--syntax-string-color)">Response:</span><span style="color:var(--syntax-literal-color)">\n</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-text-color)">resume</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">""</span>
    <span style="color:var(--syntax-text-color)">jd</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">""</span>
</code></span></span>

当我们运行这个时,我们将看到我们可以继续我们的对话。用户不会接触到 Lambda 中可能发生的任何有趣的内容,例如系统消息。耶!

现在我们已经在云中运行了该应用程序的后端,我们的最后一篇文章将设置某种公共静态站点,我们可以让用户使用它,而不是强迫他们使用命令行!

我们现在已将后端部署到 AWS,并且可以通过计算机上的 CLI 与其进行交互。但这确实不是您可以向朋友展示或作为投资组合项目分享的东西。现在我们将构建一个(非常)简单的前端,我们可以部署它来与简历助手 Lambda 函数进行交互。让我们开始工作吧。

一个简单的网页

让我们从 CDK 项目的根目录开始,创建一个static_site保存网站文件的目录。现在我们可以把一个基本的index.html 文件放在那里。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">mkdir </span>static_site
<span style="color:var(--syntax-text-color)">touch </span>static_site/index.html

</code></span></span>
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)"><!-- static_site/index.html --></span>

<span style="color:var(--syntax-comment-color)"><!DOCTYPE html></span>
<span style="color:var(--syntax-error-color)"><html></span>
  <span style="color:var(--syntax-error-color)"><head></span>
    <span style="color:var(--syntax-error-color)"><title></span>It's alive!<span style="color:var(--syntax-error-color)"></title></span>
  <span style="color:var(--syntax-error-color)"></head></span>
  <span style="color:var(--syntax-error-color)"><body></span>
    <span style="color:var(--syntax-error-color)"><h1></span>Hello from S3<span style="color:var(--syntax-error-color)"></h1></span>
  <span style="color:var(--syntax-error-color)"></body></span>
<span style="color:var(--syntax-error-color)"></html></span>
</code></span></span>

前端的 S3 桶

现在我们的站点有了一个简单的索引,我们将需要一个 S3 存储桶来存储它,以及一种将代码从我们的 repo 部署到该存储桶的方法(与我们需要 Lambda 和打包的方法非常相似)并部署它。)

桶很简单。我们将确保对象是加密且非公开的,并设置索引。我们还将设置removal_policyauto_delete_objects为使清理更容易的值。请注意,我们还为 设置了一个值website_index_document

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)"># resume_assistant/resume_assistant_stack.py
</span>
<span style="color:var(--syntax-error-color)">from</span> <span style="color:var(--syntax-text-color)">aws_cdk</span> <span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">aws_s3</span> <span style="color:var(--syntax-declaration-color)">as</span> <span style="color:var(--syntax-text-color)">s3</span>
<span style="color:var(--syntax-error-color)">from</span> <span style="color:var(--syntax-text-color)">aws_cdk</span> <span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">RemovalPolicy</span>

<span style="color:var(--syntax-error-color)">from</span> <span style="color:var(--syntax-text-color)">constructs</span> <span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">Construct</span>

<span style="color:var(--syntax-declaration-color)">class</span> <span style="color:var(--syntax-name-color)">ResumeAssistantStack</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">Stack</span><span style="color:var(--syntax-text-color)">):</span>
    <span style="color:var(--syntax-declaration-color)">def</span> <span style="color:var(--syntax-name-color)">__init__</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">self</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">scope</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">Construct</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">construct_id</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">str</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-error-color)">**</span><span style="color:var(--syntax-text-color)">kwargs</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">-></span> <span style="color:var(--syntax-text-color)">None</span><span style="color:var(--syntax-text-color)">:</span>
        <span style="color:var(--syntax-text-color)">super</span><span style="color:var(--syntax-text-color)">().</span><span style="color:var(--syntax-text-color)">__init__</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">scope</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">construct_id</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-error-color)">**</span><span style="color:var(--syntax-text-color)">kwargs</span><span style="color:var(--syntax-text-color)">)</span>

        <span style="color:var(--syntax-text-color)">site_bucket</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">s3</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">Bucket</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">self</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"SiteBucket"</span><span style="color:var(--syntax-text-color)">,</span>
            <span style="color:var(--syntax-text-color)">versioned</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">True</span><span style="color:var(--syntax-text-color)">,</span>
            <span style="color:var(--syntax-text-color)">encryption</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">s3</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">BucketEncryption</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">S3_MANAGED</span><span style="color:var(--syntax-text-color)">,</span>
            <span style="color:var(--syntax-text-color)">enforce_ssl</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">True</span><span style="color:var(--syntax-text-color)">,</span>
            <span style="color:var(--syntax-text-color)">block_public_access</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">s3</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">BlockPublicAccess</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">BLOCK_ALL</span><span style="color:var(--syntax-text-color)">,</span>
            <span style="color:var(--syntax-text-color)">removal_policy</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">RemovalPolicy</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">DESTROY</span><span style="color:var(--syntax-text-color)">,</span>
            <span style="color:var(--syntax-text-color)">auto_delete_objects</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">True</span><span style="color:var(--syntax-text-color)">,</span>
            <span style="color:var(--syntax-text-color)">public_read_access</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">False</span><span style="color:var(--syntax-text-color)">,</span>
            <span style="color:var(--syntax-text-color)">website_index_document</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-string-color)">"index.html"</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-text-color)">)</span>
</code></span></span>

__init__注意:将来对 CDK 代码的所有添加(减去模块导入)都将在类中的该函数内ResumeAssistantStack以与上述相同的缩进级别完成site_bucket。因此,这意味着如果您复制并粘贴代码块,您将必须自己进行一些缩进。

桶部署

这就是我们自动将代码从目录移动static_site到存储桶的方式。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)"># resume_assistant/resume_assistant_stack.py
</span>
<span style="color:var(--syntax-error-color)">from</span> <span style="color:var(--syntax-text-color)">aws_cdk</span> <span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">aws_s3_deployment</span> <span style="color:var(--syntax-declaration-color)">as</span> <span style="color:var(--syntax-text-color)">s3deploy</span>

<span style="color:var(--syntax-text-color)">s3deploy</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">BucketDeployment</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">self</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"DeployWebsite"</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">sources</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-text-color)">s3deploy</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">Source</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">asset</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"./static_site"</span><span style="color:var(--syntax-text-color)">)],</span>  
    <span style="color:var(--syntax-text-color)">destination_bucket</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">site_bucket</span><span style="color:var(--syntax-text-color)">,</span>
<span style="color:var(--syntax-text-color)">)</span>
</code></span></span>

OAI 和 CloudFront 分发

仅有存储桶和部署是不够的。我们需要s在 和 的最后http做一个可以实际访问我们存储桶中的对象的 OAI(毕竟我们确实阻止了对它的访问)。我们还将设置 0 秒的 ttl,以便在我们积极开发时 CloudFront 不会缓存(如果我们向全世界发布,我们可以稍后更改它)。

我们也可能有一个输出,以便我们可以看到我们页面的 CloudFront URL。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)"># resume_assistant/resume_assistant_stack.py
</span>
<span style="color:var(--syntax-error-color)">from</span> <span style="color:var(--syntax-text-color)">aws_cdk</span> <span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">aws_cloudfront</span> <span style="color:var(--syntax-declaration-color)">as</span> <span style="color:var(--syntax-text-color)">cloudfront</span>
<span style="color:var(--syntax-error-color)">from</span> <span style="color:var(--syntax-text-color)">aws_cdk</span> <span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">Duration</span>
<span style="color:var(--syntax-error-color)">from</span> <span style="color:var(--syntax-text-color)">aws_cdk</span> <span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">CfnOutput</span>


<span style="color:var(--syntax-text-color)">oai</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">cloudfront</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">OriginAccessIdentity</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">self</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"OAI"</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">comment</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-string-color)">"OAI for Resume Assistant"</span>
<span style="color:var(--syntax-text-color)">)</span>

<span style="color:var(--syntax-text-color)">distribution</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">cloudfront</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">CloudFrontWebDistribution</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">self</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"Distribution"</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">origin_configs</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">[</span>
        <span style="color:var(--syntax-text-color)">cloudfront</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">SourceConfiguration</span><span style="color:var(--syntax-text-color)">(</span>
            <span style="color:var(--syntax-text-color)">s3_origin_source</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">cloudfront</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">S3OriginConfig</span><span style="color:var(--syntax-text-color)">(</span>
                <span style="color:var(--syntax-text-color)">s3_bucket_source</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">site_bucket</span><span style="color:var(--syntax-text-color)">,</span>
                <span style="color:var(--syntax-text-color)">origin_access_identity</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">oai</span><span style="color:var(--syntax-text-color)">,</span>
            <span style="color:var(--syntax-text-color)">),</span>
            <span style="color:var(--syntax-text-color)">behaviors</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">[</span>
                <span style="color:var(--syntax-text-color)">cloudfront</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">Behavior</span><span style="color:var(--syntax-text-color)">(</span>
                    <span style="color:var(--syntax-text-color)">is_default_behavior</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">True</span><span style="color:var(--syntax-text-color)">,</span>
                    <span style="color:var(--syntax-text-color)">default_ttl</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">Duration</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">seconds</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">),</span>
                    <span style="color:var(--syntax-text-color)">min_ttl</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">Duration</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">seconds</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">),</span>
                    <span style="color:var(--syntax-text-color)">max_ttl</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">Duration</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">seconds</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">),</span>
                <span style="color:var(--syntax-text-color)">)</span>
            <span style="color:var(--syntax-text-color)">]</span>
        <span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-text-color)">]</span>
<span style="color:var(--syntax-text-color)">)</span>

<span style="color:var(--syntax-text-color)">CfnOutput</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">self</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"WebsiteURL"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">value</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">distribution</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">distribution_domain_name</span><span style="color:var(--syntax-text-color)">)</span>
</code></span></span>

注意:CloudFront 发行版需要一段时间来配置和传播。如果您等待 10 多分钟左右 CDK 完成部署,请不要感到惊讶。您可以通过控制台中的 CloudFront 来预览 CloudFront URL。

呜呜!!

Route53 和 ACM 证书(非常可选)

现在您在 URL 上有一个网站<bunchacrap>.cloudfront.net,如果您问我,这对于一个概念验证网站来说已经足够好了。但是,如果您想从您可能拥有的域名访问它,则很容易添加一些 CDK 以使该站点可以从subdomain.yourdomain.com

我发现在 IAC 之外拥有通配符证书在此类项目中使用非常方便。通配符证书是一种对任意数量的子域有效*.yourdomain.com且可用于任意数量的子域的证书。它使此类项目更容易与人们共享并添加到投资组合中。我认为它应该在您的 IAC 之外,因为您不想错误地拆除管理证书的项目并破坏依赖于它的所有其他项目!

我们可以在 AWS Certificate Manager 中进行设置,方法是在管理该域的任何地方请求证书,*.yourdomain.com然后将CNAME name和添加CNAME value为 CNAME 记录。验证该证书后,您可以导出其 ARN 以及您要使用的域和子域。如果您希望地址是下面的 dexampleresume.yourdomain.com

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">export </span><span style="color:var(--syntax-text-color)">CERTIFICATE_ARN</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-string-color)">'arn:aws:acm:us-east-1:123456789100:certificate/some-uuid'</span>
<span style="color:var(--syntax-text-color)">export </span><span style="color:var(--syntax-text-color)">DOMAIN_NAME</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-string-color)">'yourdomain.com'</span>
<span style="color:var(--syntax-text-color)">export </span><span style="color:var(--syntax-text-color)">SUB_DOMAIN</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-string-color)">'resume'</span>
</code></span></span>

然后,您可以在 CDK 中使用它,就像使用 OpenAI API 密钥一样。我们将导入证书对象,然后在我们的 CloudFront 发行版中使用它

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)"># resume_assistant/resume_assistant_stack.py
</span>
<span style="color:var(--syntax-error-color)">from</span> <span style="color:var(--syntax-text-color)">aws_cdk</span> <span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">aws_certificatemanager</span> <span style="color:var(--syntax-declaration-color)">as</span> <span style="color:var(--syntax-text-color)">acm</span>
<span style="color:var(--syntax-error-color)">from</span> <span style="color:var(--syntax-text-color)">aws_cdk</span> <span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">aws_cloudfront</span> <span style="color:var(--syntax-declaration-color)">as</span> <span style="color:var(--syntax-text-color)">cloudfront</span>
<span style="color:var(--syntax-error-color)">from</span> <span style="color:var(--syntax-text-color)">aws_cdk</span> <span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">Duration</span>
<span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">os</span>

<span style="color:var(--syntax-text-color)">cert</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">acm</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">Certificate</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">from_certificate_arn</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">self</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"cert"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">os</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">environ</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">get</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"CERTIFICATE_ARN"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"empty"</span><span style="color:var(--syntax-text-color)">))</span>

<span style="color:var(--syntax-text-color)">domain</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">os</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">environ</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">get</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"DOMAIN_NAME"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"empty"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">sub_domain</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">os</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">environ</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">get</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"SUB_DOMAIN"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"empty"</span><span style="color:var(--syntax-text-color)">)</span>

<span style="color:var(--syntax-text-color)">distribution</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">cloudfront</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">CloudFrontWebDistribution</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">self</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"Distribution"</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">origin_configs</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">[</span>
        <span style="color:var(--syntax-text-color)">cloudfront</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">SourceConfiguration</span><span style="color:var(--syntax-text-color)">(</span>
            <span style="color:var(--syntax-text-color)">s3_origin_source</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">cloudfront</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">S3OriginConfig</span><span style="color:var(--syntax-text-color)">(</span>
                <span style="color:var(--syntax-text-color)">s3_bucket_source</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">site_bucket</span><span style="color:var(--syntax-text-color)">,</span>
                <span style="color:var(--syntax-text-color)">origin_access_identity</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">oai</span><span style="color:var(--syntax-text-color)">,</span>
            <span style="color:var(--syntax-text-color)">),</span>
            <span style="color:var(--syntax-text-color)">behaviors</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">[</span>
                <span style="color:var(--syntax-text-color)">cloudfront</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">Behavior</span><span style="color:var(--syntax-text-color)">(</span>
                    <span style="color:var(--syntax-text-color)">is_default_behavior</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">True</span><span style="color:var(--syntax-text-color)">,</span>
                    <span style="color:var(--syntax-text-color)">default_ttl</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">Duration</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">seconds</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">),</span>
                    <span style="color:var(--syntax-text-color)">min_ttl</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">Duration</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">seconds</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">),</span>
                    <span style="color:var(--syntax-text-color)">max_ttl</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">Duration</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">seconds</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">),</span>
                <span style="color:var(--syntax-text-color)">)</span>
            <span style="color:var(--syntax-text-color)">]</span>
        <span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-text-color)">],</span>
    <span style="color:var(--syntax-text-color)">viewer_certificate</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">cloudfront</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">ViewerCertificate</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">from_acm_certificate</span><span style="color:var(--syntax-text-color)">(</span>
        <span style="color:var(--syntax-text-color)">certificate</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">cert</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-text-color)">aliases</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-string-color)">f</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">sub_domain</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-string-color)">.</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">domain</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">],</span>
        <span style="color:var(--syntax-text-color)">security_policy</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">cloudfront</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">SecurityPolicyProtocol</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">TLS_V1_2_2021</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-text-color)">ssl_method</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">cloudfront</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">SSLMethod</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">SNI</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">)</span>
</code></span></span>

最后,您需要将 A 记录添加到托管区域,以将到达的流量发送resume.yourdomain.com到 CloudFront URL。如果您使用的 DNS 提供商不是 Route53,您可以手动执行此操作(或者如果您的提供商是 Route53,我想也可以手动执行此操作。),但如果可以的话,让我们使用 CDK 进行管理。

您将需要获取并导入另外一个环境变量,即yourdomain.com托管区域的 ID。

导出:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">export </span><span style="color:var(--syntax-text-color)">HOSTED_ZONE_ID</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-string-color)">'NUM83R5AND13TT3R5'</span>
</code></span></span>

然后我们可以添加那个A记录。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)"># resume_assistant/resume_assistant_stack.py
</span>
<span style="color:var(--syntax-error-color)">from</span> <span style="color:var(--syntax-text-color)">aws_cdk</span> <span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">aws_route53</span> <span style="color:var(--syntax-declaration-color)">as</span> <span style="color:var(--syntax-text-color)">route53</span><span style="color:var(--syntax-text-color)">,</span>
<span style="color:var(--syntax-error-color)">from</span> <span style="color:var(--syntax-text-color)">aws_cdk</span> <span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">aws_route53_targets</span> <span style="color:var(--syntax-declaration-color)">as</span> <span style="color:var(--syntax-text-color)">route53_targets</span><span style="color:var(--syntax-text-color)">,</span>
<span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-text-color)">os</span>

<span style="color:var(--syntax-text-color)">domain</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">os</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">environ</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">get</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"DOMAIN_NAME"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"empty"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">sub_domain</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">os</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">environ</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">get</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"SUB_DOMAIN"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"empty"</span><span style="color:var(--syntax-text-color)">)</span>

<span style="color:var(--syntax-text-color)">dns_zone</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">route53</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">HostedZone</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">from_hosted_zone_attributes</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">self</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"HostedZone"</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">hosted_zone_id</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">os</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">environ</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">get</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"HOSTED_ZONE_ID"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"empty"</span><span style="color:var(--syntax-text-color)">),</span>
    <span style="color:var(--syntax-text-color)">zone_name</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">domain</span><span style="color:var(--syntax-text-color)">,</span>
<span style="color:var(--syntax-text-color)">)</span>

<span style="color:var(--syntax-text-color)">route53</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">ARecord</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">self</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"SiteAliasRecord"</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">zone</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">dns_zone</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">record_name</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">sub_domain</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">target</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">route53</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">RecordTarget</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">from_alias</span><span style="color:var(--syntax-text-color)">(</span>
        <span style="color:var(--syntax-text-color)">route53_targets</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">CloudFrontTarget</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">distribution</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-text-color)">),</span>
<span style="color:var(--syntax-text-color)">)</span>
</code></span></span>

那里!现在您的网站有了一个友好的 URL。但它还不是一个网站,是吗?让我们开始构建它。

构建前端

注意:如果你是前端大师并且喜欢编写 React 或其他一些可以静态服务的高速前端框架,你可以停止关注并这样做(记住修改 te S3 部署以指向适当的目录)。

然而,我对那些东西很糟糕。因此,对于剩下的人,我们将编写一些简陋的 HTML/JavaScript/CSS,这是我与 ChatGPT 对话的产物。它不是很好,但可以完成工作。你被警告了!

让我们编写一些 HTML!

因此,我们首先需要的是两个文本框,允许用户添加他们的简历和职位描述,以及一个按钮,用于将数据提交到我们的 Lambda 以满足我们的初始请求。我们还需要一个地方用于助理的回复,以及一个用于输入文本以供将来回复的地方。

<body>让我们从我们的元素开始index.html创建一个 div 来放置我们的元素。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)"><!-- static_site/index.html --></span>
<span style="color:var(--syntax-error-color)"><html></span>
  <span style="color:var(--syntax-error-color)"><body></span>
    <span style="color:var(--syntax-error-color)"><div></span>
      <span style="color:var(--syntax-error-color)"><textarea</span> <span style="color:var(--syntax-name-color)">id=</span><span style="color:var(--syntax-string-color)">"resume-input"</span> <span style="color:var(--syntax-name-color)">placeholder=</span><span style="color:var(--syntax-string-color)">"Add resume here"</span><span style="color:var(--syntax-error-color)">></textarea></span>
      <span style="color:var(--syntax-error-color)"><br></span>
      <span style="color:var(--syntax-error-color)"><textarea</span> <span style="color:var(--syntax-name-color)">id=</span><span style="color:var(--syntax-string-color)">"jd-input"</span> <span style="color:var(--syntax-name-color)">placeholder=</span><span style="color:var(--syntax-string-color)">"Add job description here"</span><span style="color:var(--syntax-error-color)">></textarea></span>
      <span style="color:var(--syntax-error-color)"><br></span>
      <span style="color:var(--syntax-error-color)"><button></span>Submit Documents<span style="color:var(--syntax-error-color)"></button></span>
      <span style="color:var(--syntax-error-color)"><br></span>
      <span style="color:var(--syntax-error-color)"><div</span> <span style="color:var(--syntax-name-color)">id=</span><span style="color:var(--syntax-string-color)">"api-response"</span><span style="color:var(--syntax-error-color)">></div></span>
      <span style="color:var(--syntax-error-color)"><br></span>
      <span style="color:var(--syntax-error-color)"><textarea</span> <span style="color:var(--syntax-name-color)">id=</span><span style="color:var(--syntax-string-color)">"additional-input"</span> <span style="color:var(--syntax-name-color)">placeholder=</span><span style="color:var(--syntax-string-color)">"Response"</span><span style="color:var(--syntax-error-color)">></textarea></span>
      <span style="color:var(--syntax-error-color)"><br></span>
      <span style="color:var(--syntax-error-color)"><button></span>Reply<span style="color:var(--syntax-error-color)"></button></span>
    <span style="color:var(--syntax-error-color)"></div></span>
  <span style="color:var(--syntax-error-color)"></body></span>
<span style="color:var(--syntax-error-color)"></html></span>
</code></span></span>

一个不错的基础,但我们的按钮还没有做任何事情。让我们通过添加一些 onclick 属性并加载我们将要创建的 javascript 文件来解决这个问题。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)"><!-- static_site/index.html --></span>
<span style="color:var(--syntax-error-color)"><html></span>
    <span style="color:var(--syntax-error-color)"><body></span>
        <span style="color:var(--syntax-error-color)"><div></span>
            <span style="color:var(--syntax-error-color)"><textarea</span> <span style="color:var(--syntax-name-color)">id=</span><span style="color:var(--syntax-string-color)">"resume-input"</span> <span style="color:var(--syntax-name-color)">placeholder=</span><span style="color:var(--syntax-string-color)">"Add resume here"</span><span style="color:var(--syntax-error-color)">></textarea></span>
      <span style="color:var(--syntax-error-color)"><br></span>
      <span style="color:var(--syntax-error-color)"><textarea</span> <span style="color:var(--syntax-name-color)">id=</span><span style="color:var(--syntax-string-color)">"jd-input"</span> <span style="color:var(--syntax-name-color)">placeholder=</span><span style="color:var(--syntax-string-color)">"Add job description here"</span><span style="color:var(--syntax-error-color)">></textarea></span>
      <span style="color:var(--syntax-error-color)"><br></span>
      <span style="color:var(--syntax-error-color)"><button</span> <span style="color:var(--syntax-name-color)">onclick=</span><span style="color:var(--syntax-string-color)">"handleSubmit()"</span><span style="color:var(--syntax-error-color)">></span>Submit Documents<span style="color:var(--syntax-error-color)"></button></span>
      <span style="color:var(--syntax-error-color)"><br></span>
      <span style="color:var(--syntax-error-color)"><div</span> <span style="color:var(--syntax-name-color)">id=</span><span style="color:var(--syntax-string-color)">"api-response"</span><span style="color:var(--syntax-error-color)">></div></span>
      <span style="color:var(--syntax-error-color)"><br></span>
      <span style="color:var(--syntax-error-color)"><textarea</span> <span style="color:var(--syntax-name-color)">id=</span><span style="color:var(--syntax-string-color)">"additional-input"</span> <span style="color:var(--syntax-name-color)">placeholder=</span><span style="color:var(--syntax-string-color)">"Response"</span><span style="color:var(--syntax-error-color)">></textarea></span>
      <span style="color:var(--syntax-error-color)"><br></span>
      <span style="color:var(--syntax-error-color)"><button</span> <span style="color:var(--syntax-name-color)">onclick=</span><span style="color:var(--syntax-string-color)">"handleReply()"</span><span style="color:var(--syntax-error-color)">></span>Reply<span style="color:var(--syntax-error-color)"></button></span>
    <span style="color:var(--syntax-error-color)"></div></span>
    <span style="color:var(--syntax-error-color)"><script </span><span style="color:var(--syntax-name-color)">src=</span><span style="color:var(--syntax-string-color)">"script.js"</span><span style="color:var(--syntax-error-color)">></script></span>
  <span style="color:var(--syntax-error-color)"></body></span>
<span style="color:var(--syntax-error-color)"></html></span>
</code></span></span>

一些初始 JavaScript

让我们将该script.js文件添加到我们的static_site目录中并查看我们的 Lambda 函数所期望的内容。

首次提交:

  1. 简历中的简历:
  2. jd的职位描述:
  3. uuid 处的空 uuid:
  4. user_response 的空回复:

后续提交

  1. 简历中的空白简历:
  2. jd 的空职位描述:
  3. uuid 处的 uuid:
  4. user_response 的回复:

这就是为什么我们将创建handleSubmithandleReply函数,以便我们可以向 Lambda 形成适当的请求。让我们首先处理初始提交。

我们首先设置 chatUuid 和 apiURL 的值,然后创建初始请求将发送到的函数。在那里,我们将文本框中的值加载到变量中,然后为 Lambda 的第一个请求创建初始负载。

因为对 Lambda 的调用是相同的,所以我们将创建第二个函数来将该负载传递给实际调用 API 并将响应发布到 div 的函数api-response

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// static_site/script.js</span>

<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">chatUuid</span> <span style="color:var(--syntax-comment-color)">// this is initialized but left empty</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">apiURL</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">The lambda url from your cdk stack</span><span style="color:var(--syntax-string-color)">'</span>


<span style="color:var(--syntax-declaration-color)">function</span> <span style="color:var(--syntax-name-color)">handleSubmit</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-declaration-color)">var</span> <span style="color:var(--syntax-name-color)">resumeInput</span>  <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">document</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">getElementById</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">resume-input</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">).</span><span style="color:var(--syntax-name-color)">value</span><span style="color:var(--syntax-text-color)">;</span>
    <span style="color:var(--syntax-declaration-color)">var</span> <span style="color:var(--syntax-name-color)">jdInput</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">document</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">getElementById</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">jd-input</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">).</span><span style="color:var(--syntax-name-color)">value</span><span style="color:var(--syntax-text-color)">;</span>

    <span style="color:var(--syntax-declaration-color)">var</span> <span style="color:var(--syntax-name-color)">initalPayload</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">resume</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">resumeInput</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">jd</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">jdInput</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">uuid</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">''</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">user_response</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">''</span>
    <span style="color:var(--syntax-text-color)">};</span>
    <span style="color:var(--syntax-name-color)">callAPI</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">initalPayload</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">};</span>

<span style="color:var(--syntax-declaration-color)">function</span> <span style="color:var(--syntax-name-color)">callAPI</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">requestPayload</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-name-color)">fetch</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">apiURL</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-name-color)">method</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">POST</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-name-color)">headers</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">{</span>
            <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">Content-Type</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">application/json</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">,</span>
            <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">Access-Control-Allow-Origin</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">*</span><span style="color:var(--syntax-string-color)">'</span>
        <span style="color:var(--syntax-text-color)">},</span>
        <span style="color:var(--syntax-name-color)">body</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">JSON</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">stringify</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">requestPayload</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-text-color)">})</span>
    <span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">function</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">response</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-name-color)">response</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">json</span><span style="color:var(--syntax-text-color)">();</span>
    <span style="color:var(--syntax-text-color)">})</span>
    <span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">function</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-name-color)">chatUuid</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">uuid</span><span style="color:var(--syntax-text-color)">;</span>
        <span style="color:var(--syntax-text-color)">document</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">getElementById</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">api-response</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">).</span><span style="color:var(--syntax-name-color)">textContent</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">message</span><span style="color:var(--syntax-text-color)">;</span>
    <span style="color:var(--syntax-text-color)">})</span>
    <span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-declaration-color)">catch</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">function</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">error</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-name-color)">loadingElement</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">style</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">display</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">none</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">;</span>
        <span style="color:var(--syntax-name-color)">console</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">log</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">Error:</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">error</span><span style="color:var(--syntax-text-color)">);</span>
    <span style="color:var(--syntax-text-color)">});</span>
<span style="color:var(--syntax-text-color)">};</span>
</code></span></span>

请记住,如果发生浏览器缓存,您将不得不刷新甚至在私人窗口中打开。console.log("fixed misspelled url")添加某种消息以确保您获得您认为的版本也很有帮助。继续并通过添加一些稀疏信息进行测试,看看会发生什么。

显然,我们需要做一些工作来处理我们的造型。但我们首先要让回复部分正常工作。

我们将添加一个handleReply函数并以 Lambda 期望的方式格式化请求。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// static_site/script.js</span>

<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">chatUuid</span> <span style="color:var(--syntax-comment-color)">// this is initialized but left empty</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">apiURL</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">The lambda url from your cdk stack</span><span style="color:var(--syntax-string-color)">'</span>


<span style="color:var(--syntax-declaration-color)">function</span> <span style="color:var(--syntax-name-color)">handleReply</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-declaration-color)">var</span> <span style="color:var(--syntax-name-color)">additionalInputValue</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">document</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">getElementById</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">additional-input</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">).</span><span style="color:var(--syntax-name-color)">value</span><span style="color:var(--syntax-text-color)">;</span>

    <span style="color:var(--syntax-declaration-color)">var</span> <span style="color:var(--syntax-name-color)">replyPayload</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">resume</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">''</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">jd</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">''</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">uuid</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">chatUuid</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">user_response</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">additionalInputValue</span>
    <span style="color:var(--syntax-text-color)">};</span>
    <span style="color:var(--syntax-name-color)">callAPI</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">replyPayload</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">};</span>

<span style="color:var(--syntax-declaration-color)">function</span> <span style="color:var(--syntax-name-color)">callAPI</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">requestPayload</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">document</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">getElementById</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">api-response</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">).</span><span style="color:var(--syntax-name-color)">textContent</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">''</span><span style="color:var(--syntax-text-color)">;</span>
    <span style="color:var(--syntax-text-color)">document</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">getElementById</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">additional-input</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">).</span><span style="color:var(--syntax-name-color)">value</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">''</span><span style="color:var(--syntax-text-color)">;</span>

    <span style="color:var(--syntax-name-color)">fetch</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">apiURL</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-name-color)">method</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">POST</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-name-color)">headers</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">{</span>
            <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">Content-Type</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">application/json</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">,</span>
            <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">Access-Control-Allow-Origin</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">*</span><span style="color:var(--syntax-string-color)">'</span>
        <span style="color:var(--syntax-text-color)">},</span>
        <span style="color:var(--syntax-name-color)">body</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">JSON</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">stringify</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">requestPayload</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-text-color)">})</span>
    <span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">function</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">response</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-name-color)">response</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">json</span><span style="color:var(--syntax-text-color)">();</span>
    <span style="color:var(--syntax-text-color)">})</span>
    <span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">then</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">function</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-name-color)">chatUuid</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">uuid</span><span style="color:var(--syntax-text-color)">;</span>
        <span style="color:var(--syntax-text-color)">document</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">getElementById</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">api-response</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">).</span><span style="color:var(--syntax-name-color)">textContent</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">data</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">message</span><span style="color:var(--syntax-text-color)">;</span>
    <span style="color:var(--syntax-text-color)">})</span>
    <span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-declaration-color)">catch</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">function</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">error</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-name-color)">loadingElement</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">style</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">display</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">none</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">;</span>
        <span style="color:var(--syntax-name-color)">console</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">log</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">Error:</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">error</span><span style="color:var(--syntax-text-color)">);</span>
    <span style="color:var(--syntax-text-color)">});</span>
<span style="color:var(--syntax-text-color)">};</span>
</code></span></span>

请注意,除了handleReply()我们添加的功能之外,我们还添加了几行来callAPI()清除助手的最后回复以及我们刚刚提交的回复。那应该清理一下。

我们还可以做很多事情,比如在第一次提交时删除初始输入项,这样用户就不会不小心重新开始对话。我们还可以添加一些奇特的加载旋转器,这样用户就不会认为他们的请求不会回来。我将把它留给你自己改进和实施。

但我们应该让它更漂亮一点...首先让我们稍微修改一下index.html以导入样式表并向两个 div 添加一些类名。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)"><!-- static_site/index.html --></span>

<span style="color:var(--syntax-comment-color)"><!DOCTYPE html></span>
<span style="color:var(--syntax-error-color)"><html></span>
  <span style="color:var(--syntax-error-color)"><head></span>
    <span style="color:var(--syntax-error-color)"><title></span>It's alive!<span style="color:var(--syntax-error-color)"></title></span>
    <span style="color:var(--syntax-error-color)"><link</span> <span style="color:var(--syntax-name-color)">rel=</span><span style="color:var(--syntax-string-color)">"stylesheet"</span> <span style="color:var(--syntax-name-color)">type=</span><span style="color:var(--syntax-string-color)">"text/css"</span> <span style="color:var(--syntax-name-color)">href=</span><span style="color:var(--syntax-string-color)">"style.css"</span><span style="color:var(--syntax-error-color)">></span>
  <span style="color:var(--syntax-error-color)"></head></span>
  <span style="color:var(--syntax-error-color)"><body></span>
    <span style="color:var(--syntax-error-color)"><div</span> <span style="color:var(--syntax-name-color)">class=</span><span style="color:var(--syntax-string-color)">"container"</span><span style="color:var(--syntax-error-color)">></span>
      <span style="color:var(--syntax-error-color)"><textarea</span> <span style="color:var(--syntax-name-color)">id=</span><span style="color:var(--syntax-string-color)">"resume-input"</span> <span style="color:var(--syntax-name-color)">placeholder=</span><span style="color:var(--syntax-string-color)">"Add resume here"</span><span style="color:var(--syntax-error-color)">></textarea></span>
      <span style="color:var(--syntax-error-color)"><br></span>
      <span style="color:var(--syntax-error-color)"><textarea</span> <span style="color:var(--syntax-name-color)">id=</span><span style="color:var(--syntax-string-color)">"jd-input"</span> <span style="color:var(--syntax-name-color)">placeholder=</span><span style="color:var(--syntax-string-color)">"Add job description here"</span><span style="color:var(--syntax-error-color)">></textarea></span>
      <span style="color:var(--syntax-error-color)"><br></span>
      <span style="color:var(--syntax-error-color)"><button</span> <span style="color:var(--syntax-name-color)">onclick=</span><span style="color:var(--syntax-string-color)">"handleSubmit()"</span><span style="color:var(--syntax-error-color)">></span>Submit Documents<span style="color:var(--syntax-error-color)"></button></span>
      <span style="color:var(--syntax-error-color)"><br></span>
      <span style="color:var(--syntax-error-color)"><div</span> <span style="color:var(--syntax-name-color)">id=</span><span style="color:var(--syntax-string-color)">"api-response"</span> <span style="color:var(--syntax-name-color)">class=</span><span style="color:var(--syntax-string-color)">"api-response"</span><span style="color:var(--syntax-error-color)">></div></span>
      <span style="color:var(--syntax-error-color)"><br></span>
      <span style="color:var(--syntax-error-color)"><textarea</span> <span style="color:var(--syntax-name-color)">id=</span><span style="color:var(--syntax-string-color)">"additional-input"</span> <span style="color:var(--syntax-name-color)">placeholder=</span><span style="color:var(--syntax-string-color)">"Response"</span><span style="color:var(--syntax-error-color)">></textarea></span>
      <span style="color:var(--syntax-error-color)"><br></span>
      <span style="color:var(--syntax-error-color)"><button</span> <span style="color:var(--syntax-name-color)">onclick=</span><span style="color:var(--syntax-string-color)">"handleReply()"</span><span style="color:var(--syntax-error-color)">></span>Reply<span style="color:var(--syntax-error-color)"></button></span>
    <span style="color:var(--syntax-error-color)"></div></span>
    <span style="color:var(--syntax-error-color)"><script </span><span style="color:var(--syntax-name-color)">src=</span><span style="color:var(--syntax-string-color)">"script.js"</span><span style="color:var(--syntax-error-color)">></script></span>
  <span style="color:var(--syntax-error-color)"></body></span>
<span style="color:var(--syntax-error-color)"></html></span>
</code></span></span>

让我们开始努力吧style.css。我们将使页面的主要区域为窗口宽度的 75%,并将所有框设置为该宽度。我们还将让按钮变得更好一点。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">/* static_site.style.css */</span>

<span style="color:var(--syntax-name-color)">.container</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">max-width</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">75%</span><span style="color:var(--syntax-text-color)">;</span>
    <span style="color:var(--syntax-text-color)">margin</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">0</span> <span style="color:var(--syntax-text-color)">auto</span><span style="color:var(--syntax-text-color)">;</span>
    <span style="color:var(--syntax-text-color)">padding</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">20px</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>

<span style="color:var(--syntax-error-color)">textarea</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">width</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">100%</span><span style="color:var(--syntax-text-color)">;</span>
    <span style="color:var(--syntax-text-color)">height</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">100px</span><span style="color:var(--syntax-text-color)">;</span>
    <span style="color:var(--syntax-text-color)">resize</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">both</span><span style="color:var(--syntax-text-color)">;</span>
    <span style="color:var(--syntax-text-color)">margin-bottom</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">10px</span><span style="color:var(--syntax-text-color)">;</span>
    <span style="color:var(--syntax-text-color)">padding</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">5px</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>

<span style="color:var(--syntax-error-color)">button</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">padding</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">10px</span> <span style="color:var(--syntax-literal-color)">20px</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>

<span style="color:var(--syntax-name-color)">.api-response</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">margin-top</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">20px</span><span style="color:var(--syntax-text-color)">;</span>
    <span style="color:var(--syntax-text-color)">border</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">1px</span> <span style="color:var(--syntax-text-color)">solid</span> <span style="color:var(--syntax-literal-color)">#ccc</span><span style="color:var(--syntax-text-color)">;</span>
    <span style="color:var(--syntax-text-color)">padding</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">10px</span><span style="color:var(--syntax-text-color)">;</span>
    <span style="color:var(--syntax-text-color)">white-space</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">pre-wrap</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>

简单(但并非如此。就像我说的,ChatGPT 帮助引导了大部分前端,我刚刚将其编辑成一个最小且简单的包供您使用)。

现在您已经自行部署了,请尝试一下。打破它并查看您的 Lambda 代码中需要修改哪些内容。您可以通过以下一些方法来改进它:

  1. 当 OpenAI API 关闭时会发生什么?当您达到账单限额时怎么办?(你最好设置一个!)添加一些合理的例外情况。
  2. 如果用户不输入任何信息会发生什么?添加一些验证。
  3. 你能让网站变得更加用户友好吗?添加加载或“思考”动画。一旦用户提交了初始输入,就将其折叠起来。
  4. 我们正在保存可能违反 GDPR 和其他法律的各种对话。在存储桶上设置生命周期规则,以便在对话结束后立即删除对话或允许用户清除对话。
  5. 做点别的事并让我知道你做了什么!我很想听听!
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

构建无服务器 ChatGPT 支持的简历助手 - 基础(二) 的相关文章

随机推荐

  • Python面向过程编程主要知识

    摘自尚学堂的python 人工智能课程 用于复习 python是一种解释型的 面向对象的语言 python的特点 1 可读性强 易修改 2 简介 关注业务本身 生产效率高 3 面向对象 4 免费和开源 5 可移植性和跨平台 python被编
  • spring框架学习之路(一)-入门基础(1)-IOC(控制反转)&DI(依赖注入)

    前言 我就是一小白程序猴 不懂什么高新技术 只是在学习过程中把自己遇到问题或者学到的新知识记录下来 第一给自己复习用 第二小白更懂小白的苦 自己是新手所以应该更了解在刚开始学习时哪些学起来有困难 也就避开了所谓的专家盲点 给后面入坑的人一点
  • 【深度学习】使用kaggle提供的免费GPU在线训练模型

    背景 自己电脑没有GPU 只能找找网上的平台来跑模型 但是又买不起服务器 只能使用免费的平台这样子 免费的在线平台 各大计算平台免费GPU资源总结 本文要介绍的就是第三个 虽然是国外的 但是不用翻墙就可以访问 每周免费30小时使用时长 显卡
  • JAVA操作共享文件夹文件、下载、读取(windows、Linux通用)

    一 导入包 maven中央仓库https mvnrepository com artifact org samba jcifs jcifs 1 3 3
  • 在C#中??和?分别是什么意思?

    在C 中 和 分别是什么意思 1 可空类型修饰符 引用类型可以使用空引用表示一个不存在的值 而值类型通常不能表示为空 例如 string str null 是正确的 int i null 编译器就会报错 为了使值类型也可为空 就可以使用可空
  • 背完这套Java面试八股文,自动解锁面试牛逼症被动技能

    前言 国内的互联网面试 恐怕是现存的 最接近科举考试的制度 很多人对八股文都嗤之以鼻 认为无法衡量出一个程序员的真是水平 还有一部分人则是深恶痛绝 因为实在太难背了 但是国内大环境如此 互联网IT行业的求职者太多了 如果考察的是清一溜的算法
  • Weex 项目总结

    在项目中 我觉得暂时有两个地方需要总结一下 一个是weex内部的数据请求 一个是原生方法得调用 数据请求 在PC端调试的话会有跨域问题 在手机端没有跨域问题 原生方法需要原生开发者根据 Weex文档 写一个module 再暴露出一个方法给前
  • 解决springboot 项目配置文件指定端口号没生效

    方法1 指定启动端口号8022 覆盖配置文件 SpringBootApplication public class FadadaApplication public static void main String args SpringAp
  • Unity使用mesh绘制模型

    基本概念 首先要知道模型是如何产生的 比如说我们在一个3 3的空间创建这样9个点 vector3 这9个点构成了我们模型的范围 三点成三角 三角呈面 然后由面绘制出体 用这种方法可以绘制我们想要的图形 理论转为实践 第一步 绘制点 先将刚才
  • Vue 路由守卫详细介绍与演示

    Vue 路由守卫是一种在 Vue js 应用程序中控制路由导航的机制 它允许你在路由变化前 后或在特定路由上执行代码 以便实现诸如权限控制 数据加载 页面切换动画等功能 在下面的介绍中 我将首先提供官方定义和通俗解释 然后详细介绍全局前置路
  • python练习题(十九):有一分数序列:2/1,3/2,5/3,8/5,13/8,21/13...求出这个数列的前n项之和

    题目 有一分数序列 2 1 3 2 5 3 8 5 13 8 21 13 求出这个数列的前n项之和 n int input 请输入求和项数 n sum 0 记录前n项和 a 1 分母 b 2 分子 for i in range n n su
  • MinStack 和MaxStack

    leetcode链接 包含min函数的stack 分析 利用一个LinkedList 链表存储数据 类似于链stack 还有数组stack 采用ArrayList存储 关于如何查找最小元素的情况 思路一 双stack stack 保存正常的
  • git stash的用法

    首先 git stash的含义是将修改的代码先暂存起来 让本地仓库回到最后一次提交时的状态 便于代码的更新管理 主要避免修改文件与最新代码的冲突 最近项目中遇到一些文件修改了 暂时不想提交 就想到了使用stash命令 首先 可以将自己想提交
  • 学习笔记整理:网络应用技术-运输层(1)

    以下内容为个人的学习笔记整理 如有错误 请指出 谢谢 一 课前预习 1 数据交换有哪几种方式 电路交换 报文交换 分组交换 2 运输层实现的通信是什么之间的通信 两个网络应用程序之间的通信 3 运输层所说的端口有什么作用 什么是套接字 端口
  • 详解基于tensorflow实现对cifar100的识别,准确率达到65%附完整代码(涉及vggnet,resnet,,loss图像处理,图像增强,BN)

    文章目录 一 介绍cifar 数据集 二 resnet网络简介 a 网络结构图 b 使用resnet进行炼丹 c 第一次炼丹 d 第二次炼丹 完整代码 jupyter notebook 三 vggnet网络简介 a vggnet结构图 b
  • vue-cli+express前后端分离项目跨域问题解决

    1 express后端项目中使用命令npm i cors S安装cors 并在app js文件中引入cors 写下如下几行代码 var cors require cors 跨域 app use cors origin http localh
  • Java集合-HashMap1.8也会发生死循环

    在网上搜资料时候然后发现网上都说1 7版本的HashMap会发生死链也就是死循环 但是在HashMap中也会产生死循环 接下来直接看代码吧 代码 类名字我忘记改了这是我以前看park时候弄的但是这不重要 当你运行 public class
  • [第16课]统计:诸方差公式

    Start 观看可汗视频 本节课 可汗老师对原始方差公式进行推导 得出如下更简洁的公式 2 i
  • MapReduce基础知识(个人总结)

    声明 1 本文为我的个人复习总结 并非那种从零基础开始普及知识 内容详细全面 言辞官方的文章 2 由于是个人总结 所以用最精简的话语来写文章 3 若有错误不当之处 请指出 Writable类型 Java类型 Hadoop Writable类
  • 构建无服务器 ChatGPT 支持的简历助手 - 基础(二)

    之前我们制作了一个简洁的小命令行工具 可以用来帮助我们构建更好的简历 现在我们将该应用程序部署到云中 我将使用 AWS CDK 因为我喜欢它 而且它使此类事情变得相对简单 如果愿意 您当然可以将这些说明改编为 Terraform 首先让我们