之前我们制作了一个简洁的小命令行工具,可以用来帮助我们构建更好的简历。现在我们将该应用程序部署到云中!
我将使用 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>
现在我们已经设置了存储库,以下是我们要放入其中的内容。
- 包含 Lambda 代码的目录(我们将对其进行一些修改)
- 用于创建 S3 存储桶来存储我们的对话“状态”的 CDK 代码
- 用于创建 Lambda 函数来运行我们的代码的 CDK 代码
- CDK代码创建一个函数URL以便我们可以调用该函数
让我们开始吧!
Python 应用程序的新栖息地
在 CDK 存储库的根目录中创建一个名为的新文件夹,并从我们之前会话的目录中chat_lambda
复制您的文件app.py
和requirements.txt
文件。chat_app
我们本质上是分叉这些代码,并将以不同的方式修改它们中的每一个,以达到我们想要的目标。chat_lambda
CDK 将被告知 lambda 函数的代码所在的目录。假设您正在运行 docker(确保您正在运行 docker),CDK 将根据您指定的运行时创建一个容器,在requirements.txt 中安装依赖项,添加您的代码,然后将整个内容压缩并将其部署为拉姆达函数。它太酷了。让我们开始 Lambda-fying 我们的代码。
首先,由于最近的一些原因,我们需要减少
lambda_handler
传统规定我们通过带有一些参数(特别是参数)的方法进入函数event
。让我们重构lambda_handler
并期望我们要发送的请求将位于body
中event
。
<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 中可用,以帮助我们在做错了什么时进行故障排除。我们通常这样做!
您还会注意到,该函数将在事件正文中查找简历和工作描述作为 和 的值resume
。jd
当我们调用这个函数时,我们需要确保提供它们。
最后,我们以一种实际上不允许我们继续对话的方式返回助理的响应。那将在以后出现。
S3 状态桶
桶很简单。我们将确保对象是加密且非公开的,并设置索引。因为我们只是玩玩,所以我们还将 和 设置removal_policy
为auto_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_policy
和auto_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 函数所期望的内容。
首次提交:
- 简历中的简历:
- jd的职位描述:
- uuid 处的空 uuid:
- user_response 的空回复:
后续提交
- 简历中的空白简历:
- jd 的空职位描述:
- uuid 处的 uuid:
- user_response 的回复:
这就是为什么我们将创建handleSubmit
和handleReply
函数,以便我们可以向 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 代码中需要修改哪些内容。您可以通过以下一些方法来改进它:
- 当 OpenAI API 关闭时会发生什么?当您达到账单限额时怎么办?(你最好设置一个!)添加一些合理的例外情况。
- 如果用户不输入任何信息会发生什么?添加一些验证。
- 你能让网站变得更加用户友好吗?添加加载或“思考”动画。一旦用户提交了初始输入,就将其折叠起来。
- 我们正在保存可能违反 GDPR 和其他法律的各种对话。在存储桶上设置生命周期规则,以便在对话结束后立即删除对话或允许用户清除对话。
- 做点别的事并让我知道你做了什么!我很想听听!