برنامه نویسی

ساخت و استقرار یک وب API با پشتیبانی از ChatGPT

ChatGPT ابزار جالبی است. انجام برخی کارها را که قبلا سخت بود بسیار آسان می کند. در برخی موارد، مفاهیم جدیدی را معرفی می کند که ممکن است قبلاً فکر نمی کردید انجام دهید.

OpenAI تعدادی sdk را برای کمک به ایجاد در بالای ChatGPT ارائه می دهد.

در این پست، یک ایده ساده را که با استفاده از ChatGPT پیاده سازی شده است، می گیریم و آن را اجرا می کنیم. در یک پست بعدی، نحوه عملکرد برنامه در تولید را بررسی خواهیم کرد. همچنین نحوه غلبه بر برخی از چالش های استفاده از ChatGPT در یک برنامه زنده را بررسی خواهیم کرد.

توجه: برای پیگیری کامل باید برای خدمات مختلف ثبت نام کنید. به طور خاص OpenAI رایگان نیست اگرچه یک آزمایش رایگان دارد.

برنامه نمونه ما

در دوره مهندسی DeeplearningAI Prompt، بخشی در مورد خلاصه کردن محتوا وجود دارد.

این یک عملکرد جالب است و انجام آن بدون استفاده از LLM یا نوعی NLP بسیار دشوار است.

در برنامه نمونه خود، از API NYTimes برای معرفی داستان های برتر امروز استفاده خواهیم کرد. ما ChatGPT را برای خلاصه کردن داستان ها دریافت می کنیم و آن خلاصه را نشان خواهیم داد.

نتیجه نهایی برای مشاهده در دسترس است: https://summer-ui.fly.dev/

کد نمونه برای این در 2 مخزن موجود است:

اگر می خواهید کد UI را نادیده بگیرید زیرا فقط برای نمایش داده های استخراج شده از API ما وجود دارد.

ابزار

API ما با استفاده از FastAPI ساخته شده است که یک چارچوب وب پایتون است.

می‌توانیم از API NYTimes برای دریافت برخی اخبار و از OpenAI API برای اجرای ChatGPT استفاده کنیم.

ما می توانیم به fly.io مستقر شویم.

برای رابط کاربری از وانیلی جاوا اسکریپت، CSS و HTML استفاده خواهیم کرد.

GitHub با بخشی در ساخت یک خط لوله استقرار با استفاده از اقدامات GitHub ظاهر خواهد شد. که در قسمت 2 خواهد بود.

ما همچنین در نهایت از Python، Docker و Git استفاده خواهیم کرد.

برپایی

متأسفانه، این راه‌اندازی کامل نیاز به ثبت‌نام برای موارد و دریافت کلیدهای API دارد.

توضیحات تصویر

امیدوارم تحملم کنی

اگر راهی امن برای ذخیره این کلیدهای API به صورت محلی می‌خواهید، پست من را در مورد آن بررسی کنید.

یک کلید API NYTimes دریافت کنید

برای این کار، راهنمای تنظیم NYTimes را دنبال کنید.

به اختصار:

  • به اینجا بروید، روی ایجاد حساب کلیک کنید (مگر اینکه قبلاً یک حساب داشته باشید).

  • پس از ورود به “برنامه های من” بروید و یک برنامه جدید اضافه کنید.
  • وقتی برنامه جدید را انتخاب کنید، باید یک کلید API ببینید.

آن کلید API را کپی کنید و آن را در یک متغیر محیطی به نام در دسترس قرار دهید NYTIMES_API_KEY.

مطمئن نیستید که منظور من از متغیر مجموعه و محیط چیست؟ این پست را بررسی کنید.

یک کلید ChatGPT API دریافت کنید

هنگامی که کلید خود را دارید، آن را به یک متغیر محیطی به نام اضافه کنید OPENAI_API_KEY.

توجه: API OpenAI یک سرویس پولی است. با ثبت نام، یک آزمایش رایگان دریافت خواهید کرد. اگر مانند من سال ها پیش ثبت نام کرده اید، آن را فراموش کرده اید و دوره آزمایشی رایگان خود را از دست داده اید، باید یک روش پرداخت اضافه کنید. هر کاری که در حین آزمایش این چیزها انجام دادم حدود 5 سنت هزینه داشت اما 5 یورو به حسابم اضافه کردم. امیدوارم آزمایش رایگان داشته باشید.

Fly.io

اگر می خواهید چیزی را در اینترنت در دسترس قرار دهید، باید آن را در جایی مستقر کنید. تعداد زیادی گزینه وجود دارد. Fly.io یکی از مواردی است که در حال حاضر رایگان است. شما همچنین می توانید یک پایگاه داده رایگان و حتی یک کش ردیس رایگان راه اندازی کنید.

برای یک حساب کاربری رایگان در https://fly.io/ ثبت نام کنید. این تمام چیزی است که در حال حاضر نیاز دارید.

ایجاد اپلیکیشن

این یک راهنمای گام به گام است. می توانید کل این بخش را رد کنید، کد را پایین بکشید و آن را اجرا کنید. اگر می خواهید توضیح عمیق تری در مورد همه بیت ها داشته باشید، ادامه مطلب را بخوانید.

برنامه FastAPI

ما از Python برای API backend استفاده می کنیم. FastAPI یک چارچوب خوب است. هر دو Openai و NYTimes بسته های Python را برای تعامل با API خود ارائه می دهند.

این نیز یک مرحله با گزینه های زیادی است. روش زیر یکی از راه‌های انجام آن است.

یک دایرکتوری برای پروژه خود ایجاد کنید. من برنامه خود را تابستان نامیدم زیرا به نظر می رسد خلاصه ¯_(ツ)_/¯ مال خود را هر چه می خواهید صدا کنید اما تابستان را در مثال های مختلف جایگزین کنید.

من دوست دارم از دایرکتوری استفاده کنم، تحت فهرست اصلی من، به نام dev و مخازن من را در آنجا قرار دهم.

توجه: همه این دستورات فرض می‌کنند که از یک پوسته معقول (نه Cmd.exe) استفاده می‌کنید.

mkdir ~/dev/summer-api
cd ~/dev/summer-api
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

من از -api پسوند را اینجا بگذارید زیرا می‌خواهم باطن و فرانتنت خود را در دو مخزن مختلف نگه دارم.

git را راه اندازی کنید تا بتوانیم تغییرات خود را در کنترل منبع نگه داریم.

git init
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

شما باید پایتون را روی سیستم خود نصب کرده باشید. من در حال حاضر از Python 3.11 استفاده می کنم اما اکثر نسخه های 3.8 به بعد باید خوب باشند. اگر قبلاً این کار را نکرده اید، از pyenv برای مدیریت نصب های پایتون خود استفاده کنید.

شعر را نصب کنید:

pip install poetry
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ما از شعر استفاده خواهیم کرد زیرا مدیریت وابستگی را ساده می‌کند و اجرای محیط‌های مجازی را آسان‌تر می‌کند.

پروژه پایتون خود را با شعر تنظیم کنید:

poetry init
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

از شما ورودی های مختلفی خواسته می شود. اکثر آنها آشکار است. نکته اصلی تطبیق وابستگی ها است.

Package name [summer-api]:
Version [0.1.0]:
Description []:  Summarising the news!
Author [Your name here, n to skip]:  Your name
License []:  MIT
Compatible Python versions [^3.11]:

Would you like to define your main dependencies interactively? (yes/no) [yes]

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

می‌توانید وابستگی‌هایی را در طول شروع اضافه کنید یا فقط از آن بگذرید و وابستگی‌های فهرست شده در زیر را در pyproject.toml فایل منجر به این می شود:

[tool.poetry]
name = "summer-api"
version = "0.1.0"
description = "Summarising the news!"
authors = ["Your name"]
license = "MIT"
readme = "README.md"
packages = [{include = "summer_api"}]

[tool.poetry.dependencies]
python = "^3.11"
fastapi = "^0.95.2"
uvicorn = {extras = ["standard"], version = "^0.22.0"}
pynytimes = "^0.10.0"
openai = "^0.27.7"
fastapi-cache2 = "^0.2.1"
redis = "^4.5.5"

[tool.poetry.group.dev.dependencies]
httpx = "^0.24.1"
pytest = "^7.3.1"
black = "^23.3.0"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

با خیال راحت نسخه ها را به روز کنید، اگرچه تضمینی برای کار با کد موجود در این پست وجود نخواهد داشت.

حتما اجرا کنید poetry install اگر به صورت دستی به روز رسانی کنید pyproject.yml فایل.

یک دایرکتوری برای کد منبع ما ایجاد کنید.

mkdir app
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

یک فایل اصلی ایجاد کنید.

touch app/__init__.py
touch app/main.py
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

باز کن app/main.py در یک ویرایشگر و موارد زیر را وارد کنید:

from fastapi import FastAPI

app = FastAPI()


@app.get("https://dev.to/")
def index():
    return {"msg": "Welcome to the News App"}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

برنامه را اجرا کنید:

poetry run uvicorn app.main:app --reload
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

شما باید خروجی را مانند این ببینید:

INFO:     Will watch for changes in these directories: ['~/dev/summer-api']
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [29115] using WatchFiles
INFO:     Started server process [29144]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

می‌توانید در مرورگر خود به http://localhost:8000/ بروید یا با curl ضربه بزنید

curl http://localhost:8000
{"msg":"Welcome to the News App"}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اخبار برتر را از NYTimes دریافت کنید

یک مشتری ایجاد کنید:

touch app/nytimes_client.py
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در آن فایل، یک تماس راه‌اندازی کنید تا داستان‌های برتر امروز را دریافت کنید:

import os

from pynytimes import NYTAPI
# This is the API Key we setup and added to the env earlier
API_KEY = os.getenv("NYTIMES_API_KEY", "")
nyt = NYTAPI(API_KEY, parse_dates=True)


def get_top_stories():
    return nyt.top_stories()
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

برای آزمایش آن، اجازه دهید نقطه پایانی ایجاد کنیم که به سادگی داستان های برتر را برمی گرداند.

در ما app/main.py فایل ماژول جدید ما را وارد کنید:

from .nytimes_client import get_top_stories
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

یک نقطه پایانی جدید اضافه کنید:

@app.get("/news")
def news():
    return get_top_stories()
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

برنامه را اجرا کرده و آن را تست کنید (اگر برنامه قبلاً در حال اجرا بود، --reload پرچم باعث راه اندازی مجدد آن می شود، بنابراین لازم نیست دوباره آن را اجرا کنید).

curl http://localhost:8000/news
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اگر jq را نصب کرده اید، می توانید از آن برای زیباتر جلوه دادن خروجی استفاده کنید.

curl http://localhost:8000/news | jq
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

شما باید در اینجا خروجی بسیار بزرگی با لیستی از stroies و محتوای زیاد داشته باشید.

اخبار را خلاصه کنید

اکنون ChatGPT را معرفی می کنیم.

یک فایل جدید بسازید:

touch app/summariser.py
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

کد موجود در این فایل با استفاده از نظرات درون خطی توضیح داده شده است.

import os

import openai

# You will need to get your API key from https://platform.openai.com/account/api-keys
openai.api_key = os.getenv("OPENAI_API_KEY")


# Got this function from this amazing course https://www.deeplearning.ai/short-courses/chatgpt-prompt-engineering-for-developers/
def get_completion(prompt, model="gpt-3.5-turbo"):
    messages = [{"role": "user", "content": prompt}]
    response = openai.ChatCompletion.create(
        model=model,
        messages=messages,
        temperature=0,  # this is the degree of randomness of the model's output
    )
    return response.choices[0].message["content"]


def summarise_news_stories(stories):
    """
    Takes in a list of news stories and prompts ChatGPT to
    generate a short summary of each story based on the provided
    Section, Subsection, Title, and Abstract.
    The function returns the summary generated by ChatGPT.

    Args:
    - stories (str): A list of news stories to be summarised.
    Each story should be a block of text with the following format
    where each part is on a newline:

    Section: the section
    Subsection: the subsection
    Title: the title
    Abstract: the Abstract

    The values for 'Subsection' and 'Abstract' can be empty
    strings if not applicable.

    Returns:
    - summary (str): A string containing the summary generated by ChatGPT
    for all the news stories.
    """

    print("Beginning summary")
    prompt = f"""
    Your task is to generate a short summary of a series of
    news stories given the Section, Subsection, Title and
    Abstract, of each story.

    The sections are after the 'Section:'.
    The subsections are after the 'Subsection:'. The subsections can be empty.

    The title is after the 'Title:'. The abstract is after the 'Abstract:'.
    The abstract can be empty.

    Summarise the stories below, delimited by triple backticks,
    in the style of an AI trying to convey information to humans.
    Please use paragraphs where appropriate and use at most 800 words.

    Stories: ```{stories}```
    """

    return get_completion(prompt)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

قالب بندی داستان ها

در حالی که احتمالاً می‌توانستیم ChatGPT را برای کشف JSON از API NYTimes دریافت کنیم، کاهش تعداد مواردی که به آن ارسال می‌کنیم ضرری ندارد، بنابراین اجازه دهید داستان‌ها را برای ارسال به ChatGPT قالب‌بندی کنیم.

یک فایل دیگر ایجاد کنید:

touch app/story_formatter.py
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

یک تابع به آن فایل اضافه کنید تا داستان ها را قالب بندی کند تا ما فقط محتوای مورد نیاز خود را ارسال کنیم:

def format_stories_to_string(stories):
    stories_string = ""
    for story in stories:
        title = story["title"]
        abstract = story["abstract"]
        section = story["section"]
        subsection = story["subsection"]
        stories_string += f"""
        Section: {section}
        Subsection: {subsection}
        Title: {title}
        Abstract: {abstract}
        """
    return stories_string
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نقطه پایانی خبر

حالا می توانیم همه چیز را کنار هم بگذاریم. ما را به روز کنید app/main.py فایل به شکل زیر باشد:

import os

from fastapi import FastAPI, HTTPException

from .nytimes_client import get_top_stories
from .story_formatter import format_stories_to_string
from .summariser import summarise_news_stories

app = FastAPI()


@app.get("https://dev.to/")
def index():
    return {"msg": "Welcome to the News App"}


@app.get("/news")
def news():
    summary = ""
    images = []
    try:
        stories = get_top_stories()
        for story in stories:
            images.extend(story["multimedia"])
        summary = summarise_news_stories(format_stories_to_string(stories))
        images = list(
            filter(lambda image: image["format"] == "Large Thumbnail", images)
        )
    except Exception as e:
        print(e)
        raise HTTPException(
            status_code=500, detail="Apologies, something bad happened :("
        )
    return {"summary": summary, "images": images}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اکنون می توانید آن را آزمایش کنید، اما توجه داشته باشید، تماس با ChatGPT زمان بسیار زیادی طول می کشد. در قسمت 2 این مجموعه به نحوه برخورد با آن مشکل خواهیم پرداخت.

curl http://localhost:8000/news
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این باید خلاصه ای از اخبار و همچنین لیستی از تمام تصاویر مرتبط را ارائه دهد.

قبل از اینکه یک UI برای این کار تنظیم کنیم، به مرحله دیگری نیاز داریم. API ما انتظار دارد هر تماسی در مرورگر از همان URL برنامه ما باشد. این یک مکانیسم امنیتی به نام Cross-Origin Resource Sharing (CORS) است. ما باید API خود را به‌روزرسانی کنیم تا درخواست‌ها از UI ما مجاز باشد.

برای ایجاد آن کار، در ما main.py میان افزار CORS را اضافه و پیکربندی کنید:

from fastapi.middleware.cors import CORSMiddleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

توجه: برای allow_origins=["*"], شما در واقع می خواهید زمانی که URL UI خود را در آن قرار دهید بسیار خاص باشید allow_origins=["http://localhost:8080"],. در اینجا از علامت عام استفاده کنید تا کار کند، اما لطفاً این را در نظر داشته باشید. در کد نمونه در GitHub یک مثال بهتر وجود دارد.

UI ما را راه اندازی کنید

این کاملا اختیاری است بنابراین ما به سرعت مراحل را طی خواهیم کرد.

mkdir ~/dev/summer-ui
cd  ~/dev/summer-ui
git init
mkdir app
touch app/index.html
touch app/script.js
touch app/style.css
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در app/index.html فایل:

<!DOCTYPE html>
<html>
<head>
    <title>Today's News</title>
    <link rel="stylesheet" type="text/css" href="styles.css">
    <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests" />
</head>
<body>
    <main>
        <div id="loader">
            <h1>This should be quick, but ever so often it takes a long time...</h1>
            <div class="lds-circle"><div></div></div>
        </div>
        <div id="news-container" class="container hidden">
            <h1>Today's News</h1>
            <div class="date" id="date"></div>


            <p id="summary">
                <!-- Summary will be inserted here -->
            </p>
        </div>
        <div id="images" class="img-container">
            <!-- Images will be inserted here -->
        </div>
    </main>
    <script src="script.js"></script>
</body>
</html>
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در app/style.css فایل:

body {
  margin: 0;
  padding: 0;
  font-family: Arial, sans-serif;
  color: #333;
  line-height: 1.6;
  background: rgb(238, 174, 202);
  background: radial-gradient(
    circle,
    rgba(238, 174, 202, 1) 0%,
    rgba(148, 187, 233, 1) 100%
  );
}

.container {
  width: 80%;
  max-width: 800px;
  margin: 0 auto;
  padding: 20px;
  background-color: #fff;
  box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.1);
  padding-bottom: 4rem;
}

h1 {
  font-size: 2em;
  margin-bottom: 0.5em;
  color: #212121;
  text-align: center;
}

p {
  font-size: 1em;
  text-align: justify;
}

/* Media queries for responsive design */
@media (max-width: 768px) {
  /* Tablets */
  .container {
    width: 90%;
  }

  h1 {
    font-size: 1.75em;
  }

  p {
    font-size: 0.9em;
  }
}

@media (max-width: 480px) {
  /* Phones */
  .container {
    width: 95%;
  }

  h1 {
    font-size: 1.5em;
  }

  p {
    font-size: 0.85em;
  }
}

.img-container {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}

.photo {
  position: relative;
  margin: -15px; /* negative margin makes the images overlap */
  transform: rotate(-10deg); /* starting angle */
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
  transition: transform 0.5s;
  z-index: 1; /* ensure that images can stack on top of each other */
}

.photo:hover {
  transform: rotate(0deg); /* reset to straight when hovered */
}

.photo img {
  max-width: 150px;
  border-radius: 10px;
}

.date {
  text-transform: uppercase;
  text-align: center;
}

#loader {
  padding-top: 20%;
  text-align: center;
}

.lds-circle {
  display: inline-block;
  transform: translateZ(1px);
}
.lds-circle > div {
  display: inline-block;
  width: 64px;
  height: 64px;
  margin: 8px;
  border-radius: 50%;
  background: #fff;
  animation: lds-circle 2.4s cubic-bezier(0, 0.2, 0.8, 1) infinite;
}
@keyframes lds-circle {
  0%,
  100% {
    animation-timing-function: cubic-bezier(0.5, 0, 1, 0.5);
  }
  0% {
    transform: rotateY(0deg);
  }
  50% {
    transform: rotateY(1800deg);
    animation-timing-function: cubic-bezier(0, 0.5, 0.5, 1);
  }
  100% {
    transform: rotateY(3600deg);
  }
}

.hidden {
  display: none;
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در app/script.js فایل:

window.onload = function () {
  fetch("https://summer-api.fly.dev/news/")
    .then((response) => response.json())
    .then((data) => {
      document.getElementById("loader").style.display = "none";
      document.getElementById("news-container").style.display = "block";

      const summaryElement = document.getElementById("summary");
      const imagesElement = document.getElementById("images");

      summaryElement.innerHTML = data.summary.split("\n").join("<br>");

      data.images.forEach((image, index) => {
        const img = document.createElement("img");
        img.className = "photo";
        img.src = image.url;
        img.alt = image.caption;
        img.style.width = "150px";
        img.style.height = "150px";

        // Every third image will take up double the width and height
        if (index % 3 === 0) {
          img.style.gridColumnEnd = "span 2";
          img.style.gridRowEnd = "span 2";
        }

        imagesElement.appendChild(img);
      });
    })
    .catch((err) => console.error(err.message));

  function formatDate(date) {
    const options = {
      weekday: "long",
      month: "long",
      day: "numeric",
      year: "numeric",
    };
    return date.toLocaleDateString("en-US", options);
  }

  const today = new Date();
  document.getElementById("date").textContent = formatDate(today);
};

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

توجه: مطمئن شوید که URL موجود در آن اسکریپت را با هر URL که API شما در آن است جایگزین کنید

اکنون می توانید آن دایرکتوری را به عنوان مثال با استفاده از Live Server در VSCode یا با استفاده از برخی ابزارهای کاربردی دیگر مانند سرویس ارائه دهید.

همه چیز خوب پیش می رود، صفحه ای مانند این را خواهید دید:

توضیحات تصویر

استقرار به fly.io

بیایید با باطن شروع کنیم.

ابتدا flyctl را نصب کنید https://fly.io/docs/hands-on/install-flyctl/

وارد شدن:

fly auth login
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

به فهرست API ما بروید:

cd ~/dev/summer-api
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ساده ترین راه برای استقرار یک سرویس استفاده از Dockerfile برای تعریف محیط است. اگر بتوانید آن را به صورت محلی بسازید و اجرا کنید، احتمالاً هنگام استقرار کار خواهد کرد.

یک Dockerfile ایجاد کنید.

touch Dockerfile
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

با این مطالب:

FROM python:3.11 as requirements-stage

WORKDIR /tmp

RUN pip install poetry

COPY ./pyproject.toml ./poetry.lock* /tmp/

RUN poetry export -f requirements.txt --output requirements.txt --without-hashes

FROM python:3.11

WORKDIR /code

COPY --from=requirements-stage /tmp/requirements.txt /code/requirements.txt

RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt

COPY ./app /code/app

EXPOSE 8080

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8080"]
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

تستش کن:

docker build . -t summer-api
docker run -p 8080:8080 summer-api
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

شما باید بتوانید برنامه خود را در http://localhost:8080 ضربه بزنید.

Fly می داند که چگونه یک Dockerfile را مستقر کند.

fly launch
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این شما را در راه اندازی اپلیکیشن راهنمایی می کند.

ما همچنین باید کلیدهای API خود را به آن بدهیم.

flyctl secrets set NYTIMES_API_KEY=${NYTIMES_API_KEY}
flyctl secrets set OPENAI_API_KEY=${OPENAI_API_KEY}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

همه چیز به خوبی پیش می رود API شما باید در حال اجرا باشد. برای مثال مال من اینجاست: https://summer-api.fly.dev/

شما یک URL منحصر به فرد برای برنامه خود خواهید داشت.

برای رابط کاربری ما می توانیم کاری مشابه انجام دهیم.

cd ~/dev/summer-ui
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ابتدا اسکریپت را در UI به روز کنید تا به URL جدید برای API شما اشاره کند.

پس این بیت:

window.onload = function () {
  fetch("https://summer-api.fly.dev/news/")
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در آنجا، شما باید جایگزین کنید "https://summer-api.fly.dev/news/" با URL شما

سپس یک Dockerfile ایجاد کنید:

touch Dockerfile
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

محتوای زیر را به Dockerfile اضافه کنید:

FROM pierrezemb/gostatic
COPY ./app/ /srv/http/

EXPOSE 8043
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

8043 به طور پیش فرض پورتی است که تصویر از آن استفاده می کند.

پرواز بدو:

fly launch
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

Fly launch فایلی به نام fly.toml در مخزن شما ایجاد می کند.

من به مشکلی برخوردم که در آن باید آن فایل را به موارد زیر در رابط کاربری خود به روز کنم، زیرا به طور پیش فرض پورت اشتباهی داشت:

app = "summer-ui"
primary_region = "cdg"


kill_signal = "SIGINT"
kill_timeout = 5
processes = []

[experimental]
  allowed_public_ports = []
  auto_rollback = true

[[services]]
  http_checks = []
  internal_port = 8043
  processes = ["app"]
  protocol = "tcp"
  script_checks = []

  [services.concurrency]
    hard_limit = 25
    soft_limit = 20
    type = "connections"

  [[services.ports]]
    handlers = ["http"]
    port = 80
    force_https = true

  [[services.ports]]
    handlers = ["tls", "http"]
    port = 443

  [[services.tcp_checks]]
    grace_period = "1s"
    interval = "15s"
    restart_limit = 0
    timeout = "2s"
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

شما ممکن است به این نیاز داشته باشید یا نداشته باشید. حتما به روز رسانی کنید app و primary_region به مقادیر صحیح برای برنامه شما.

بهبودها

این پست در حال حاضر بزرگ است، بنابراین من تمام پیشرفت ها را در پست خود قرار می دهم.

در پست بعدی نگاه خواهیم کرد:

  • راه اندازی خط لوله تحویل مداوم
  • از redis برای ذخیره پاسخ های ChatGPT و افزایش سرعت سایت ما استفاده کنید

ما همچنین به برخی از روش‌های جالب دیگر که ممکن است بخواهید هنگام ساخت یک برنامه producton در بخش پاداش انجام دهید، نگاه خواهیم کرد.

قسمت 2 به زودی.

با تشکر از شما برای خواندن!

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا