diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..692e368 Binary files /dev/null and b/.DS_Store differ diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 76b5b7e..737c04c 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: jobs: - push-to-acr: + build-and-push-backend: runs-on: ubuntu-latest steps: - name: Checkout repository @@ -29,6 +29,22 @@ jobs: push: true tags: pypiscoutacr.azurecr.io/pypi-scout-backend:latest + build-and-push-frontend: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to Azure Container Registry + uses: azure/docker-login@v1 + with: + login-server: pypiscoutacr.azurecr.io + username: ${{ secrets.ACR_USERNAME }} + password: ${{ secrets.ACR_PASSWORD }} + - name: Build and Push Frontend Docker image uses: docker/build-push-action@v4 with: @@ -37,3 +53,5 @@ jobs: platforms: linux/amd64 push: true tags: pypiscoutacr.azurecr.io/pypi-scout-frontend:latest + build-args: | + NEXT_PUBLIC_API_URL=https://pypiscout.com/api diff --git a/Dockerfile b/Dockerfile index 66c2eaa..7c271b1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,14 +22,10 @@ RUN poetry install --no-interaction --no-ansi --no-root --no-dev && \ # Copy Python code to the Docker image COPY pypi_scout /code/pypi_scout/ -# Copy the start script and make executable -COPY start.sh /start.sh -RUN chmod +x /start.sh - # Make empty data directory RUN mkdir -p /code/data ENV PYTHONPATH=/code # Use the script as the entrypoint -ENTRYPOINT ["/start.sh"] +CMD ["uvicorn", "pypi_scout.api.main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/DockerfileCPU b/DockerfileCPU index 7f391b1..775c2a5 100644 --- a/DockerfileCPU +++ b/DockerfileCPU @@ -23,14 +23,10 @@ RUN pip install --no-cache-dir -r requirements-cpu.txt # Copy the rest of the application code COPY pypi_scout /code/pypi_scout/ -# Copy the start script and make it executable -COPY start.sh /start.sh -RUN chmod +x /start.sh - # Make empty data directory RUN mkdir -p /code/data ENV PYTHONPATH=/code # Use the script as the entrypoint -ENTRYPOINT ["/start.sh"] +CMD ["uvicorn", "pypi_scout.api.main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/docker-compose.yml b/docker-compose.yml index f106db6..83c37d9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,12 +5,10 @@ services: build: context: . dockerfile: Dockerfile - working_dir: / - command: uvicorn pypi_scout.api.main:app --host 0.0.0.0 --port 8000 ports: - "8000:8000" volumes: - - ./data:/data + - ./data:/code/data env_file: - .env @@ -18,9 +16,9 @@ services: build: context: ./frontend dockerfile: Dockerfile + args: + NEXT_PUBLIC_API_URL: http://localhost:8000/api ports: - "3000:3000" - environment: - - NODE_ENV=production depends_on: - backend diff --git a/frontend/.dockerignore b/frontend/.dockerignore new file mode 100644 index 0000000..8fd9192 --- /dev/null +++ b/frontend/.dockerignore @@ -0,0 +1,5 @@ +# .dockerignore +node_modules +.next +.env +.git diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 290190a..ac7d507 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -13,6 +13,12 @@ RUN npm install # Copy the rest of the application code to the container COPY . . +# Build argument to accept the API URL during build time +ARG NEXT_PUBLIC_API_URL + +# Set environment variable within the container +ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL} + # Build the Next.js application RUN npm run build diff --git a/frontend/app/components/GitHubButton.tsx b/frontend/app/components/GitHubButton.tsx new file mode 100644 index 0000000..8104cc5 --- /dev/null +++ b/frontend/app/components/GitHubButton.tsx @@ -0,0 +1,25 @@ +import React from "react"; + +const GitHubButton: React.FC = () => { + return ( + + + + + GitHub + + ); +}; + +export default GitHubButton; diff --git a/frontend/app/components/InfoBox.tsx b/frontend/app/components/InfoBox.tsx index f41bf90..c13857a 100644 --- a/frontend/app/components/InfoBox.tsx +++ b/frontend/app/components/InfoBox.tsx @@ -12,16 +12,17 @@ const InfoBox: React.FC = ({ infoBoxVisible }) => {

How does this work?

This application allows you to search for Python packages on PyPI using - natural language. An example query would be "a package that creates - plots and beautiful visualizations". + natural language queries. For example, a query could be "a package + that creates plots and beautiful visualizations".


Once you click search, your query will be matched against the summary - and the first part of the description of all PyPI packages with more - than 50 weekly downloads. The results are then scored based on their - similarity and their number of weekly downloads, and the best results - are displayed in the table below. + and the first part of the description of the ~30.000 most popular + packages on PyPI, which are all packages with at least ~600 downloads + per week. The results are then scored based on their similarity to the + query and their number of weekly downloads, and the best results are + displayed in the table below.

); diff --git a/frontend/app/components/SearchResultsTable.tsx b/frontend/app/components/SearchResultsTable.tsx index 4e866c3..befefa5 100644 --- a/frontend/app/components/SearchResultsTable.tsx +++ b/frontend/app/components/SearchResultsTable.tsx @@ -25,6 +25,12 @@ const SearchResultsTable: React.FC = ({ return sortField === field ? (sortDirection === "asc" ? "โ–ฒ" : "โ–ผ") : ""; }; + const truncateText = (text: string, maxLength: number) => { + return text.length > maxLength + ? `${text.substring(0, maxLength)}...` + : text; + }; + return (
@@ -70,7 +76,7 @@ const SearchResultsTable: React.FC = ({ {results.map((result, index) => ( -
- {result.name} + {truncateText(result.name, 20)} {result.similarity.toFixed(3)} @@ -78,7 +84,7 @@ const SearchResultsTable: React.FC = ({ {result.weekly_downloads.toLocaleString()} + {result.summary} diff --git a/frontend/app/components/SupportButton.tsx b/frontend/app/components/SupportButton.tsx new file mode 100644 index 0000000..a55a2fb --- /dev/null +++ b/frontend/app/components/SupportButton.tsx @@ -0,0 +1,23 @@ +import React from "react"; + +const SupportButton: React.FC = () => { + return ( + + Ko-fi logo + Support + + ); +}; + +export default SupportButton; diff --git a/frontend/app/globals.css b/frontend/app/globals.css index 3216bc2..7c5c7b4 100644 --- a/frontend/app/globals.css +++ b/frontend/app/globals.css @@ -6,8 +6,8 @@ --foreground-rgb: 0, 0, 0; --background-start-rgb: 214, 219, 220; --background-end-rgb: 255, 255, 255; - --dark-bg-start-rgb: 10, 10, 35; /* Very dark blue almost grey */ - --dark-bg-end-rgb: 25, 25, 50; /* Dark blue */ + --dark-bg-start-rgb: 17, 24, 39; /* Dark gray (bg-gray-900) */ + --dark-bg-end-rgb: 17, 24, 39; /* Dark gray (bg-gray-900) */ --dark-foreground-rgb: 255, 255, 255; } @@ -21,12 +21,7 @@ body { color: rgb(var(--foreground-rgb)); - background: linear-gradient( - to bottom, - transparent, - rgb(var(--background-end-rgb)) - ) - rgb(var(--background-start-rgb)); + background: rgb(var(--background-start-rgb)); /* Solid background color */ } @layer utilities { diff --git a/frontend/app/page.tsx b/frontend/app/page.tsx index c3ce2cc..b539365 100644 --- a/frontend/app/page.tsx +++ b/frontend/app/page.tsx @@ -5,6 +5,8 @@ import { handleSearch, sortResults } from "./utils/search"; import SearchResultsTable from "./components/SearchResultsTable"; import InfoBox from "./components/InfoBox"; import { ClipLoader } from "react-spinners"; +import GitHubButton from "./components/GitHubButton"; +import SupportButton from "./components/SupportButton"; interface Match { name: string; @@ -31,20 +33,29 @@ export default function Home() { }; return ( -
-
+
+
+
+ + +
+
+ +
pypi-scout logo

Enter your query to search for Python packages

-
+ +