Dedicated Inference API Docs (#14992) #78
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Ultralytics YOLO 🚀, AGPL-3.0 license | |
# Publish pip package to PyPI https://pypi.org/project/ultralytics/ and Docs to https://docs.ultralytics.com | |
name: Publish to PyPI and Deploy Docs | |
on: | |
push: | |
branches: [main] | |
workflow_dispatch: | |
inputs: | |
pypi: | |
type: boolean | |
description: Publish to PyPI | |
docs: | |
type: boolean | |
description: Deploy Docs | |
jobs: | |
publish: | |
if: github.repository == 'ultralytics/ultralytics' && github.actor == 'glenn-jocher' | |
name: Publish | |
runs-on: macos-14 | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: "0" # pulls all commits (needed correct last updated dates in Docs) | |
- name: Git config | |
run: | | |
git config --global user.name "UltralyticsAssistant" | |
git config --global user.email "[email protected]" | |
- name: Set up Python environment | |
uses: actions/setup-python@v5 | |
with: | |
python-version: "3.11" | |
cache: "pip" # caching pip dependencies | |
- name: Install dependencies | |
run: | | |
python -m pip install --upgrade pip wheel build twine | |
pip install -e ".[dev]" openai --extra-index-url https://download.pytorch.org/whl/cpu | |
- name: Check PyPI version | |
shell: python | |
run: | | |
import os | |
import ultralytics | |
from ultralytics.utils.checks import check_latest_pypi_version | |
latest_pypi_version = check_latest_pypi_version() | |
v_local = tuple(map(int, ultralytics.__version__.split('.'))) | |
v_pypi = tuple(map(int, latest_pypi_version.split('.'))) | |
print(f'Local version is {v_local}') | |
print(f'PyPI version is {v_pypi}') | |
d = [a - b for a, b in zip(v_local, v_pypi)] # diff | |
increment_patch = (d[0] == d[1] == 0) and (0 < d[2] < 3) # publish if patch version increments by 1 or 2 | |
increment_minor = (d[0] == 0) and (d[1] == 1) and v_local[2] == 0 # publish if minor version increments | |
increment = increment_patch or increment_minor | |
os.system(f'echo "increment={increment}" >> $GITHUB_OUTPUT') | |
os.system(f'echo "version={ultralytics.__version__}" >> $GITHUB_OUTPUT') | |
os.system(f'echo "previous_version={latest_pypi_version}" >> $GITHUB_OUTPUT') | |
if increment: | |
print('Local version is higher than PyPI version. Publishing new version to PyPI ✅.') | |
id: check_pypi | |
- name: Publish new tag | |
if: (github.event_name == 'push' || github.event.inputs.pypi == 'true') && steps.check_pypi.outputs.increment == 'True' | |
run: | | |
git tag -a "v${{ steps.check_pypi.outputs.version }}" -m "$(git log -1 --pretty=%B)" || true # i.e. "v0.1.2 commit message" | |
git push origin "v${{ steps.check_pypi.outputs.version }}" || true | |
- name: Publish new release | |
if: (github.event_name == 'push' || github.event.inputs.pypi == 'true') && steps.check_pypi.outputs.increment == 'True' | |
env: | |
OPENAI_AZURE_API_KEY: ${{ secrets.OPENAI_AZURE_API_KEY }} | |
OPENAI_AZURE_ENDPOINT: ${{ secrets.OPENAI_AZURE_ENDPOINT }} | |
OPENAI_AZURE_API_VERSION: ${{ secrets.OPENAI_AZURE_API_VERSION }} | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
CURRENT_TAG: ${{ steps.check_pypi.outputs.version }} | |
PREVIOUS_TAG: ${{ steps.check_pypi.outputs.previous_version }} | |
shell: python | |
run: | | |
import openai | |
import os | |
import requests | |
import json | |
import subprocess | |
# Retrieve environment variables | |
OPENAI_AZURE_API_KEY = os.getenv('OPENAI_AZURE_API_KEY') | |
OPENAI_AZURE_ENDPOINT = os.getenv('OPENAI_AZURE_ENDPOINT') | |
OPENAI_AZURE_API_VERSION = os.getenv('OPENAI_AZURE_API_VERSION') | |
GITHUB_TOKEN = os.getenv('GITHUB_TOKEN') | |
CURRENT_TAG = os.getenv('CURRENT_TAG') | |
PREVIOUS_TAG = os.getenv('PREVIOUS_TAG') | |
# Check for required environment variables | |
if not all([OPENAI_AZURE_API_KEY, OPENAI_AZURE_ENDPOINT, OPENAI_AZURE_API_VERSION, GITHUB_TOKEN, CURRENT_TAG, PREVIOUS_TAG]): | |
print(OPENAI_AZURE_API_KEY) | |
print(OPENAI_AZURE_ENDPOINT) | |
print(OPENAI_AZURE_API_VERSION) | |
print(GITHUB_TOKEN) | |
print(CURRENT_TAG) | |
print(PREVIOUS_TAG) | |
raise ValueError("One or more required environment variables are missing.") | |
latest_tag = f"v{CURRENT_TAG}" | |
previous_tag = f"v{PREVIOUS_TAG}" | |
repo = 'ultralytics/ultralytics' | |
headers = {"Authorization": f"token {GITHUB_TOKEN}", "Accept": "application/vnd.github.v3.diff"} | |
# Get the diff between the tags | |
url = f"https://api.github.com/repos/{repo}/compare/{previous_tag}...{latest_tag}" | |
response = requests.get(url, headers=headers) | |
diff = response.text if response.status_code == 200 else f"Failed to get diff: {response.content}" | |
# Set up client | |
client = openai.AzureOpenAI( | |
api_key=OPENAI_AZURE_API_KEY, | |
api_version=OPENAI_AZURE_API_VERSION, | |
azure_endpoint=OPENAI_AZURE_ENDPOINT | |
) | |
messages = [ | |
{ | |
"role": "system", | |
"content": "You are an Ultralytics AI assistant skilled in software development and technical communication. Your task is to summarize GitHub releases from Ultralytics in a way that is detailed, accurate, and understandable to both expert developers and non-expert users. Focus on highlighting the key changes and their impact in simple and intuitive terms." | |
}, | |
{ | |
"role": "user", | |
"content": f"Summarize the updates made in the [Ultralytics](https://ultralytics.com) '{latest_tag}' tag, focusing on major changes, their purpose, and potential impact. Keep the summary clear and suitable for a broad audience. Add emojis to enliven the summary. Reply directly with a summary along these example guidelines, though feel free to adjust as appropriate:\n\n" | |
f"## 🌟 Summary (single-line synopsis)\n" | |
f"## 📊 Key Changes (bullet points highlighting any major changes)\n" | |
f"## 🎯 Purpose & Impact (bullet points explaining any benefits and potential impact to users)\n" | |
f"\n\nHere's the release diff:\n\n{diff[:300000]}", | |
} | |
] | |
completion = client.chat.completions.create(model="gpt-4o-2024-05-13", messages=messages) | |
summary = completion.choices[0].message.content.strip() | |
# Get the latest commit message | |
commit_message = subprocess.run(['git', 'log', '-1', '--pretty=%B'], check=True, text=True, capture_output=True).stdout.split("\n")[0].strip() | |
# Prepare release data | |
release = { | |
'tag_name': latest_tag, | |
'name': f"{latest_tag} - {commit_message}", | |
'body': summary, | |
'draft': False, | |
'prerelease': False | |
} | |
# Create the release on GitHub | |
release_url = f"https://api.github.com/repos/{repo}/releases" | |
release_response = requests.post(release_url, headers=headers, data=json.dumps(release)) | |
if release_response.status_code == 201: | |
print(f'Successfully created release {latest_tag}') | |
else: | |
print(f'Failed to create release {latest_tag}: {release_response.content}') | |
- name: Publish to PyPI | |
continue-on-error: true | |
if: (github.event_name == 'push' || github.event.inputs.pypi == 'true') && steps.check_pypi.outputs.increment == 'True' | |
env: | |
PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} | |
run: | | |
python -m build | |
python -m twine upload dist/* -u __token__ -p $PYPI_TOKEN | |
- name: Deploy Docs | |
continue-on-error: true | |
if: (github.event_name == 'push' || github.event.inputs.docs == 'true') && github.repository == 'ultralytics/ultralytics' && github.actor == 'glenn-jocher' | |
env: | |
PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} | |
INDEXNOW_KEY: ${{ secrets.INDEXNOW_KEY_DOCS }} | |
run: | | |
pip install black | |
export JUPYTER_PLATFORM_DIRS=1 | |
python docs/build_docs.py | |
git clone https://github.com/ultralytics/docs.git docs-repo | |
cd docs-repo | |
git checkout gh-pages || git checkout -b gh-pages | |
rm -rf * | |
cp -R ../site/* . | |
echo "$INDEXNOW_KEY" > "$INDEXNOW_KEY.txt" | |
git add . | |
LATEST_HASH=$(git rev-parse --short=7 HEAD) | |
git commit -m "Update Docs for 'ultralytics ${{ steps.check_pypi.outputs.version }} - $LATEST_HASH'" | |
git push https://[email protected]/ultralytics/docs.git gh-pages | |
- name: Extract PR Details | |
run: | | |
if [ "${{ github.event_name }}" = "pull_request" ]; then | |
PR_JSON=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}) | |
PR_NUMBER=${{ github.event.pull_request.number }} | |
PR_TITLE=$(echo $PR_JSON | jq -r '.title') | |
else | |
COMMIT_SHA=${{ github.event.after }} | |
PR_JSON=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" "https://api.github.com/search/issues?q=repo:${{ github.repository }}+is:pr+is:merged+sha:$COMMIT_SHA") | |
PR_NUMBER=$(echo $PR_JSON | jq -r '.items[0].number') | |
PR_TITLE=$(echo $PR_JSON | jq -r '.items[0].title') | |
fi | |
echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV | |
echo "PR_TITLE=$PR_TITLE" >> $GITHUB_ENV | |
- name: Notify on Slack (Success) | |
if: success() && github.event_name == 'push' && steps.check_pypi.outputs.increment == 'True' | |
uses: slackapi/[email protected] | |
with: | |
payload: | | |
{"text": "<!channel> GitHub Actions success for ${{ github.workflow }} ✅\n\n\n*Repository:* https://github.com/${{ github.repository }}\n*Action:* https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Author:* ${{ github.actor }}\n*Event:* NEW 'ultralytics ${{ steps.check_pypi.outputs.version }}' pip package published 😃\n*Job Status:* ${{ job.status }}\n*Pull Request:* <https://github.com/${{ github.repository }}/pull/${{ env.PR_NUMBER }}> ${{ env.PR_TITLE }}\n"} | |
env: | |
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL_YOLO }} | |
- name: Notify on Slack (Failure) | |
if: failure() | |
uses: slackapi/[email protected] | |
with: | |
payload: | | |
{"text": "<!channel> GitHub Actions error for ${{ github.workflow }} ❌\n\n\n*Repository:* https://github.com/${{ github.repository }}\n*Action:* https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Author:* ${{ github.actor }}\n*Event:* ${{ github.event_name }}\n*Job Status:* ${{ job.status }}\n*Pull Request:* <https://github.com/${{ github.repository }}/pull/${{ env.PR_NUMBER }}> ${{ env.PR_TITLE }}\n"} | |
env: | |
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL_YOLO }} |