Skip to content

Commit

Permalink
add dockerfile and deploy.yml (#1)
Browse files Browse the repository at this point in the history
* add dockerfile and deploy.yml

* remove groq_api_key from env_var

* add footer; improve readme, page title and subheader

* render a default state for sidebar content

* cleanup

* allow traffic on first creation

* reset no_traffic to true for preview urls

* remove the footer file

* rename service to audiora

* revert no_traffic

* set concurrency to 80

* set max-instances to 10
  • Loading branch information
nwaughachukwuma authored Oct 30, 2024
1 parent 830f029 commit 3822b58
Show file tree
Hide file tree
Showing 12 changed files with 235 additions and 23 deletions.
141 changes: 141 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
name: Deploy app to Google Cloudrun
on:
pull_request:
paths:
- "src/**"
- ".github/workflows/deploy.yml"
push:
branches:
- main
paths:
- "src/**"
- ".github/workflows/deploy.yml"
tags:
- "release-*"

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
CI: true
PROJECT_ID: ${{ secrets.PROJECT_ID }}
MAIN: ${{ github.ref == 'refs/heads/main' }}
SERVICE: audiora
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
ELEVENLABS_API_KEY: ${{ secrets.ELEVENLABS_API_KEY }}

jobs:
prepare:
runs-on: ubuntu-latest
outputs:
VERSION: ${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.number) || format('main-{0}', steps.prepare_env.outputs.SHORT_SHA) }}
MAIN_OR_TAGGED: ${{ fromJSON(env.MAIN) || (fromJSON(steps.prepare_env.outputs.TAGGED) && steps.prepare_env.outputs.TAG_BRANCH_NAME == 'main') }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- id: prepare_env
run: |
echo "TAGGED=${{ startsWith(github.ref, 'refs/tags/api') }}" >> $GITHUB_OUTPUT
SHORT_SHA=$(git rev-parse --short HEAD)
echo "SHORT_SHA=$SHORT_SHA" >> $GITHUB_OUTPUT
RAW=$(git branch -r --contains $SHORT_SHA)
TAG_BRANCH_NAME="${RAW##*/}"
echo "TAG_BRANCH_NAME=$TAG_BRANCH_NAME" >> $GITHUB_OUTPUT
lint:
runs-on: ubuntu-latest
needs: prepare
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- id: setup-python
uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: "pip" # caching pip dependencies
check-latest: true

- run: pip install --force-reinstall -r requirements.txt
if: ${{ steps.setup-python.outputs.cache-hit != 'true' }}

- run: pip install -r requirements.txt
if: ${{ steps.setup-python.outputs.cache-hit == 'true' }}

- uses: chartboost/ruff-action@v1

deploy:
runs-on: ubuntu-latest
needs: [prepare, lint]
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: "pip" # caching pip dependencies
check-latest: true

- uses: google-github-actions/auth@v2
with:
credentials_json: "${{ secrets.GCP_SA_KEY }}"

- uses: google-github-actions/setup-gcloud@v2
- run: gcloud config set app/cloud_build_timeout 300

- id: deploy
uses: google-github-actions/deploy-cloudrun@v2
with:
service: ${{ env.SERVICE }}
source: ./
tag: ${{ needs.prepare.outputs.VERSION }}
no_traffic: true
timeout: "5m"
gcloud_version: "482.0.0"
env_vars: |
ENV=prod
OPENAI_API_KEY=${{ secrets.OPENAI_API_KEY }}
GEMINI_API_KEY=${{ secrets.GEMINI_API_KEY }}
ANTHROPIC_API_KEY=${{ secrets.ANTHROPIC_API_KEY }}
ELEVENLABS_API_KEY=${{ secrets.ELEVENLABS_API_KEY }}
flags: "--allow-unauthenticated --memory=32Gi --cpu=8 --execution-environment=gen2 --concurrency=80 --max-instances=10"

- name: health-check
run: curl -f "${{ steps.deploy.outputs.url }}"
- uses: marocchino/sticky-pull-request-comment@v2
with:
header: api
message: |
app: ${{ steps.deploy.outputs.url }} (${{ github.event.pull_request.head.sha }})
promote:
runs-on: ubuntu-latest
if: (needs.prepare.outputs.MAIN_OR_TAGGED == 'true')
needs: [prepare, deploy, lint]
timeout-minutes: 3
steps:
- uses: google-github-actions/auth@v2
with:
credentials_json: "${{ secrets.GCP_SA_KEY }}"

- uses: google-github-actions/setup-gcloud@v2
- run: gcloud run services update-traffic ${{ env.SERVICE }} --to-tags=${{ needs.prepare.outputs.VERSION }}=100 --project=${{ env.PROJECT_ID }} --region=us-central1

cleanup:
runs-on: ubuntu-latest
needs: promote
timeout-minutes: 3
steps:
- uses: google-github-actions/auth@v2
with:
credentials_json: "${{ secrets.GCP_SA_KEY }}"
- uses: google-github-actions/setup-gcloud@v2
- name: cleanup old revisions
run: |
gcloud run revisions list --service=${{ env.SERVICE }} --project=${{ env.PROJECT_ID }} --region=us-central1 --sort-by=CREATE_TIME --format="value(REVISION)" | tail -n +4 | xargs -I {} gcloud run revisions delete {} --project=${{ env.PROJECT_ID }} --region=us-central1 --quiet
24 changes: 24 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Use the official lightweight Python image.
# https://hub.docker.com/_/python
FROM python:3.12-slim

# Allow statements and log messages to immediately appear in the Knative logs
ENV PYTHONUNBUFFERED True
ENV PYTHONDONTWRITEBYTECODE 1

WORKDIR /app

# Install FFmpeg and any other required dependencies
RUN apt-get -yqq update && apt-get -yqq install build-essential ffmpeg && \
rm -rf /var/lib/apt/lists/*

COPY . ./

# Install production dependencies.
RUN pip install --no-cache-dir -r requirements.txt

ENV HOST '0.0.0.0'
EXPOSE $PORT
HEALTHCHECK CMD curl --fail http://$HOST:$PORT/_stcore/health

CMD exec streamlit run app.py --server.port=$PORT --server.address=$HOST
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Audiora

> Learn or listen to anything, anytime, through the power of AI-generated audio.
> Listen to anything, anytime, leveraging AI-generated audio.
Audiora is an AI-enhanced audio platform that transforms user preferences into personalized engaging audio experiences.

Expand Down
25 changes: 18 additions & 7 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,33 @@


async def main():
init_session_state()

# Configure page
st.set_page_config(page_title="Audiora", page_icon="🎧", layout="wide")

st.title("🎧 Audiora")
st.subheader("Listen to anything, anytime, leveraging AI")

st.sidebar.markdown(
"""
<p>
A <a href="https://veedo.ai">VeedoAI</a> project. (c) 2024
</p>
""",
unsafe_allow_html=True,
)

# Sidebar for content type selection
st.sidebar.title("Audiocast Info")

init_session_state()

if st.session_state.content_category:
st.sidebar.subheader(
f"Content Category: {st.session_state.content_category.capitalize()}"
)

# Main chat interface
st.title("🎧 Audiora")
st.subheader("Learn anything, anytime, through the power of AI-generated audio.")
else:
st.sidebar.markdown(
"> Your preferences and audiocast metadata will appear here"
)

# Declare chat interface container
uichat = st.empty()
Expand Down
38 changes: 38 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from setuptools import find_packages, setup

setup(
name="audiora",
version="1.0.0",
description="Learn or listen to anything, anytime, through the power of AI-generated audio",
author="Chukwuma Nwaugha",
author_email="chuks@veedo.ai",
url="https://github.com/nwaughachukwuma/audiora",
packages=find_packages(),
install_requires=[
"streamlit",
"httpx",
"asyncio",
"openai",
"anthropic",
"pyperclip",
"python-multipart",
"python-slugify",
"python-dotenv",
"pydub",
"firebase-admin",
"google-auth",
"google-cloud-storage",
"google-api-python-client",
"google-generativeai",
"ruff",
],
classifiers=[
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
],
)
7 changes: 2 additions & 5 deletions src/env_var.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,9 @@
else:
load_dotenv()

BACKEND_URL = environ.get("BACKEND_URL", "http://localhost:8000")
APP_URL = environ.get("APP_URL", "http://localhost:8501")

OPENAI_API_KEY = environ["OPENAI_API_KEY"]
ANTHROPIC_API_KEY = environ["ANTHROPIC_API_KEY"]
GEMINI_API_KEY = environ["GEMINI_API_KEY"]
GROQ_API_KEY = environ["GROQ_API_KEY"]

ELEVENLABS_API_KEY = environ["ELEVENLABS_API_KEY"]

APP_URL = environ.get("APP_URL", "http://localhost:8501")
5 changes: 3 additions & 2 deletions src/uis/audioui.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import streamlit as st
from streamlit.delta_generator import DeltaGenerator

from src.utils.chat_thread import use_audiocast_request
from src.utils.render_audiocast import render_audiocast


async def audioui(uichat=st.empty()):
async def audioui(uichat: DeltaGenerator):
"""
Audiocast interface
"""
uichat.chat_input("What would you like to listen to?", disabled=True)
uichat.empty()

if not st.session_state.current_audiocast:
st.info("Using your specifications")
st.info("Using your preferences")

summary = st.session_state.user_specification
content_category = st.session_state.content_category
Expand Down
3 changes: 2 additions & 1 deletion src/uis/chatui.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import streamlit as st
from streamlit.delta_generator import DeltaGenerator

from src.utils.chat_thread import (
evaluate_final_response,
Expand All @@ -9,7 +10,7 @@
from src.utils.render_chat import render_chat_history


async def chatui(uichat=st.empty()):
async def chatui(uichat: DeltaGenerator):
"""
Chat interface
"""
Expand Down
2 changes: 1 addition & 1 deletion src/utils/chat_thread.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ async def use_audiocast_request(summary: str, content_category: ContentCategory)
Call audiocast creating workflow
Args:
summary (str): user request summary or user specification
summary (str): user request summary or preferences
content_category (ContentCategory): content category
"""
try:
Expand Down
2 changes: 1 addition & 1 deletion src/utils/chat_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class SessionChatRequest(BaseModel):

def display_example_cards():
"""Display example content cards if there are no messages"""
st.markdown("#### You can start with one of the following")
st.markdown("##### You can start with one of the following")

# CSS for fixed-height buttons and responsive columns
st.markdown(
Expand Down
5 changes: 3 additions & 2 deletions src/utils/render_audiocast.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ class GenerateAudiocastDict(TypedDict):

def render_audiocast():
"""
Render the audiocast based on the user's specifications
Render the audiocast based on the user's preferences
- Display current audiocast if available
"""
st.header("Your Audiocast")
st.markdown("#### Your Audiocast")
current_audiocast: GenerateAudiocastDict = st.session_state.current_audiocast

# Audio player
Expand Down Expand Up @@ -53,4 +53,5 @@ def render_audiocast():
st.rerun()

if st.session_state.get("show_copy_success", False):
st.session_state.show_copy_succes = False
st.success("Share link copied successfully!", icon="✅")
4 changes: 1 addition & 3 deletions src/utils/render_chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,11 @@ def on_value_change():
st.session_state.messages.append({"role": "human", "content": content})
st.session_state.content_category = content_category

st.rerun()

with st.container():
col1, _ = st.columns(2)
with col1:
st.selectbox(
"Select Content Type",
"Select Content Category",
content_categories,
format_func=lambda x: x.title(),
key="selected_content_category",
Expand Down

0 comments on commit 3822b58

Please sign in to comment.