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

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

我将使用 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.txtaws-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.txtboto3>=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. 做点别的事并让我知道你做了什么!我很想听听!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/53096.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

巴比特 | 元宇宙每日必读:2026年,互联网上90%的内容或由AI创建,科技大公司如何阻止虚假信息?...

摘要&#xff1a;据澎湃新闻报道&#xff0c;主流的AI生成工具如ChatGPT、DALL-E、Midjourney降低了创建虚假图像、视频和文本的难度和成本&#xff0c;使网络上的AI生成内容泛滥且难以分辨。欧盟执法机构“欧洲刑警组织&#xff08;Europol&#xff09;”的一份报告预测&#…

MasterGo入选36氪「下一个百亿规模AIGC产品」,持续探索AI+界面设计的新未来

新技术带动了 AI、云计算、芯片等大模型相关的产业链各个环节的发展跃迁。热潮奔涌&#xff0c;谁能成为 AGI 时代现象级产品&#xff1f;谁将站在热潮的巅峰定义和捕捉新的机会&#xff1f; 经过大量的调研实践&#xff0c;36氪于日前公布《中国ChatGPT梦之队&下一个百亿…

Notepad++统计文本字数

Notepad简介 Notepad 是免费的、开源编辑器和支持多种语言。它运行在MS Windows环境中&#xff0c;其使用受GPL许可证约束。 基于强大的编辑组件Scintilla&#xff0c;Notepad 是用C 编写的&#xff0c;并使用纯Win32 API和STL来确保更高的执行速度和更小的程序尺寸。通过优化…

如何快速统计网站所有页面的文本字数

文章目录 前言一、WinHTTrack Website Copier是什么&#xff1f;二、WinHTTrack Website Copier使用步骤三、什么是Python?四、Python实现的功能 前言 实现快速统计网站所有页面的文本字数&#xff0c;需要具备两个条件&#xff1a; 1.获取该网站的所有页面的html文件 2.提取…

小红书代运营 ,小红书运营必备的15个模型1.0版,建议收藏

文/企飞薯 本文一共4983字 大家好&#xff0c;我是小红书代运营圈的主理人的企飞薯。我们一直在研究小红书生态营销。 近年来小红书随着用户体量壮大和平台多元化发展&#xff0c;用户的兴趣点&#xff0c;早已从美妆独大变为渗透生活领域的各个方面。 据小红书最新数据显示&a…

移动软件开发五——仿微信发现界面

2022年夏季《移动软件开发》实验报告 一、实验目标 模仿微信“发现”页创建列表布局&#xff0c;学习使用Textview imageview、LinearLayout 二、实验步骤 1. 搭建开发环境 在此之前我的电脑已经安装并使用过android studio和java sdk 详情参见我大一写的博客 安卓小白实…

用AS实现微信界面设计

提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 设计目标一、结果展示二、top.xml三、bottom.xml四、4个fragment.xml五、activity_main.xml六、java文件总结仓库 设计目标 提示&#xff1a;这里可以添加本文要记…

仿QQ聊天软件(登录界面、好友界面、聊天界面)-Java(Swing、Socket)

文章目录 一、项目结构二、项目功能三、制作界面&#xff08;一&#xff09;、登录界面的制作&#xff08;二&#xff09;、好友列表界面&#xff08;三&#xff09;、聊天界面 四、制作服务器五、设计通信协议六、项目缺点 学习了socket通信后&#xff0c;就想来制作一个类似Q…

Android仿微信气泡聊天界面设计

微信的气泡聊天是仿iPhone自带短信而设计出来的&#xff0c;不过感觉还不错可以尝试一下仿着微信的气泡聊天做一个Demo&#xff0c;给大家分享一下&#xff01;效果图如下&#xff1a; 气泡聊天最终要的是素材&#xff0c;要用到9.png文件的素材&#xff0c;这样气泡会随着聊天…

计算机系统大作业

摘 要 尽管hello程序非常简单&#xff0c;但是为了让它实现运行&#xff0c;系统的每个主要组成部分都需要协调工作&#xff0c;本篇论文就是解释说明在系统上执行hello程序时&#xff0c;系统发生了什么以及为什么会这样。 我们通过跟踪hello程序的生命周期开始系统讲解——…

程序人生-Hello’s P2P

计算机系统 大作业 题 目 程序人生-Hello’s P2P 专 业 未来技术 学   号 2021112807 班 级 21WL021 学 生 马铭杨 指 导 教 师 史先俊 …

Google reCAPTCHA ----------验证码

现有验证码的产品形态调研范围如下&#xff0c;基本涵盖了比较主流的验证码平台&#xff1a; Google reCAPTCHA极验阿里云腾讯云点触网易易盾螺丝帽FunCaptcha 产品背景 ‍‍reCAPTCHA起初是由CMU&#xff08;卡耐基梅隆大学&#xff09;设计&#xff0c;将OCR&#xff08;光…

关于captcha验证码演示

转载&#xff1a;https://blog.csdn.net/dayonglove2018/article/details/106612549 import com.wf.captcha.SpecCaptcha; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springfr…

使用reCAPTCHA实现验证码

文章目录 HTML代码JS代码Java代码项目开源地址参考资料 HTML代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>登录</title><link rel"stylesheet" type"text/css" href"css/json-v…

手把手教你验证码检验的登录

在网站实际应用过程中&#xff0c;为了防止网站登录接口被机器人轻易地使用&#xff0c;产生一些没有意义的用户数据&#xff0c;所以&#xff0c;采用验证码进行一定程度上的拦截&#xff0c;当然&#xff0c;我们采用的还是一个数字与字母结合的图片验证码形式&#xff0c;后…

如何识别高级的验证码

http://sebug.net/paper/pst_WebZine/pst_WebZine_0x02/html/PSTZine_0x02_0x09.html Ph4nt0m Security TeamIssue 0x02, Phile #0x09 of 0x0A|---------------------------------------------------------------------------| |-----------------------[ 如何识别高级的验证码…

hcaptcha 我是人类验证码怎么跳过怎么验证自动识别

相信这个验证码很多人都见过&#xff0c;这个叫hcaptcha验证码 在网页上偶尔出现&#xff0c;提示需要你证明“我是人类” 这种验证码与谷歌的reCaptcha有异曲同工之处&#xff0c;但是其实hcaptcha与recaptcha是完全不同的产品&#xff0c;不是同一个公司出品的。 这种hcapt…

手把手教你识别FunCaptcha验证码

今天&#xff0c;我们将专注于FunCaptcha&#xff0c;这是一种独特而具有挑战性的CAPTCHA类型&#xff0c;在整个网络上越来越流行。我们将深入探讨FunCaptcha是什么&#xff0c;不同类型的FunCaptcha挑战&#xff0c;如何使用CapSolver解决它们等等。 什么是FunCaptcha&#…

基于openai chatgpt和embeddings制作私有知识库聊天机器人

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、原理、流程二、制作预料库三、制作问答功能总结 如果有问题可以联系我**&#xff1a;https://gitee.com/xiaoyuren/gpt3 前言 在当今信息爆炸的时代&#…

基于 Quivr 搭建个人知识库

目录 Quivr介绍 Quivr特性 Quivr演示 Demo with GPT3.5: Demo of the new version&#xff1a; Quivr实战 Quiv 使用的主要技术 Quiv 实践依赖 创建Supabase项目 部署Quiv项目 第一步&#xff1a;现在源码 第二步&#xff1a;设置环境变量 第三步&#xff1a;执行sql 第…