Merge remote-tracking branch 'origin/main' into masenf/proxy

This commit is contained in:
Masen Furer 2024-11-01 09:23:53 -07:00
commit 13d4d38437
No known key found for this signature in database
GPG Key ID: 2AE2BD5531FF94F4
706 changed files with 56675 additions and 70215 deletions

View File

@ -18,7 +18,7 @@ inputs:
poetry-version:
description: 'Poetry version to install'
required: false
default: '1.3.1'
default: '1.8.3'
run-poetry-install:
description: 'Whether to run poetry install on current dir'
required: false
@ -106,3 +106,8 @@ runs:
run: |
source ${{ inputs.create-venv-at-path }}/*/activate
poetry install --only-root --no-interaction
- name: Install uv
shell: bash
run: |
poetry run pip install uv

View File

@ -17,20 +17,19 @@ defaults:
env:
PYTHONIOENCODING: 'utf8'
TELEMETRY_ENABLED: false
NODE_OPTIONS: '--max_old_space_size=4096'
DATABASE_URL: ${{ secrets.DATABASE_URL }}
NODE_OPTIONS: '--max_old_space_size=8192'
PR_TITLE: ${{ github.event.pull_request.title }}
jobs:
reflex-web:
if: github.event.pull_request.merged == true
# if: github.event.pull_request.merged == true
strategy:
fail-fast: false
matrix:
# Show OS combos first in GUI
os: [ubuntu-latest]
python-version: ['3.11.4']
node-version: ['16.x']
node-version: ['18.x']
runs-on: ${{ matrix.os }}
steps:
@ -49,12 +48,12 @@ jobs:
uses: actions/checkout@v4
with:
repository: reflex-dev/reflex-web
ref: reflex-ci
ref: main
path: reflex-web
- name: Install Requirements for reflex-web
working-directory: ./reflex-web
run: poetry run pip install -r requirements.txt
run: poetry run uv pip install -r requirements.txt
- name: Init Website for reflex-web
working-directory: ./reflex-web
run: poetry run reflex init
@ -62,17 +61,16 @@ jobs:
run: |
# Check that npm is home
npm -v
poetry run bash scripts/benchmarks/benchmarks.sh ./reflex-web prod
poetry run bash benchmarks/lighthouse.sh ./reflex-web prod
env:
LHCI_GITHUB_APP_TOKEN: $
- name: Run Benchmarks
# Only run if the database creds are available in this context.
if: ${{ env.DATABASE_URL }}
run: poetry run python scripts/benchmarks/lighthouse_score_upload.py "$GITHUB_SHA" ./integration/benchmarks/.lighthouseci
run: poetry run python benchmarks/benchmark_lighthouse.py "$GITHUB_SHA" ./integration/benchmarks/.lighthouseci
env:
GITHUB_SHA: ${{ github.sha }}
simple-apps-benchmarks:
simple-apps-benchmarks: # This app tests the compile times of various compoonents and pages
if: github.event.pull_request.merged == true
env:
OUTPUT_FILE: benchmarks.json
@ -83,17 +81,13 @@ jobs:
matrix:
# Show OS combos first in GUI
os: [ubuntu-latest, windows-latest, macos-12]
python-version: ['3.8.18', '3.9.18', '3.10.13', '3.11.5', '3.12.0']
python-version: ['3.9.18', '3.10.13', '3.11.5', '3.12.0']
exclude:
- os: windows-latest
python-version: '3.10.13'
- os: windows-latest
python-version: '3.9.18'
- os: windows-latest
python-version: '3.8.18'
# keep only one python version for MacOS
- os: macos-latest
python-version: '3.8.18'
- os: macos-latest
python-version: '3.9.18'
- os: macos-latest
@ -105,8 +99,6 @@ jobs:
python-version: '3.10.11'
- os: windows-latest
python-version: '3.9.13'
- os: windows-latest
python-version: '3.8.10'
runs-on: ${{ matrix.os }}
steps:
@ -116,8 +108,6 @@ jobs:
python-version: ${{ matrix.python-version }}
run-poetry-install: true
create-venv-at-path: .venv
- name: Install additional dependencies for DB access
run: poetry run pip install psycopg2-binary
- name: Run benchmark tests
env:
APP_HARNESS_HEADLESS: 1
@ -126,16 +116,14 @@ jobs:
poetry run pytest -v benchmarks/ --benchmark-json=${{ env.OUTPUT_FILE }} -s
- name: Upload benchmark results
# Only run if the database creds are available in this context.
if: ${{ env.DATABASE_URL }}
run:
poetry run python scripts/benchmarks/simple_app_benchmark_upload.py --os "${{ matrix.os }}"
poetry run python benchmarks/benchmark_compile_times.py --os "${{ matrix.os }}"
--python-version "${{ matrix.python-version }}" --commit-sha "${{ github.sha }}"
--benchmark-json "${{ env.OUTPUT_FILE }}"
--db-url "${{ env.DATABASE_URL }}" --branch-name "${{ github.head_ref || github.ref_name }}"
--event-type "${{ github.event_name }}" --actor "${{ github.actor }}" --pr-id "${{ github.event.pull_request.id }}"
--benchmark-json "${{ env.OUTPUT_FILE }}" --branch-name "${{ github.head_ref || github.ref_name }}"
--event-type "${{ github.event_name }}" --pr-id "${{ github.event.pull_request.id }}"
reflex-build-size:
if: github.event.pull_request.merged == true
reflex-dist-size: # This job is used to calculate the size of the Reflex distribution (wheel file)
if: github.event.pull_request.merged == true
timeout-minutes: 30
strategy:
# Prioritize getting more information out of the workflow (even if something fails)
@ -148,22 +136,19 @@ jobs:
python-version: 3.11.5
run-poetry-install: true
create-venv-at-path: .venv
- name: Install additional dependencies for DB access
run: poetry run pip install psycopg2-binary
- name: Build reflex
run: |
poetry build
- name: Upload benchmark results
# Only run if the database creds are available in this context.
if: ${{ env.DATABASE_URL }}
run:
poetry run python scripts/benchmarks/benchmark_reflex_size.py --os ubuntu-latest
poetry run python benchmarks/benchmark_package_size.py --os ubuntu-latest
--python-version 3.11.5 --commit-sha "${{ github.sha }}" --pr-id "${{ github.event.pull_request.id }}"
--db-url "${{ env.DATABASE_URL }}" --branch-name "${{ github.head_ref || github.ref_name }}"
--measurement-type "reflex-build" --path ./dist
--branch-name "${{ github.head_ref || github.ref_name }}"
--path ./dist
reflex-plus-dependency-size:
if: github.event.pull_request.merged == true
reflex-venv-size: # This job calculates the total size of Reflex and its dependencies
if: github.event.pull_request.merged == true
timeout-minutes: 30
strategy:
# Prioritize getting more information out of the workflow (even if something fails)
@ -192,14 +177,15 @@ jobs:
source .venv/*/activate
poetry install --without dev --no-interaction --no-root
- name: Install additional dependencies for DB access
run: poetry run pip install psycopg2-binary
- name: Install uv
shell: bash
run: |
poetry run pip install uv
- if: ${{ env.DATABASE_URL }}
name: calculate and upload size
- name: calculate and upload size
run:
poetry run python scripts/benchmarks/benchmark_reflex_size.py --os "${{ matrix.os }}"
poetry run python benchmarks/benchmark_package_size.py --os "${{ matrix.os }}"
--python-version "${{ matrix.python-version }}" --commit-sha "${{ github.sha }}"
--pr-id "${{ github.event.pull_request.id }}" --db-url "${{ env.DATABASE_URL }}"
--pr-id "${{ github.event.pull_request.id }}"
--branch-name "${{ github.head_ref || github.ref_name }}"
--measurement-type "reflex-package" --path ./.venv
--path ./.venv

40
.github/workflows/check_node_latest.yml vendored Normal file
View File

@ -0,0 +1,40 @@
name: integration-node-latest
on:
push:
branches:
- main
pull_request:
branches:
- main
env:
TELEMETRY_ENABLED: false
REFLEX_USE_SYSTEM_NODE: true
jobs:
check_latest_node:
runs-on: ubuntu-22.04
strategy:
matrix:
python-version: ['3.12']
node-version: ['node']
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup_build_env
with:
python-version: ${{ matrix.python-version }}
run-poetry-install: true
create-venv-at-path: .venv
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: |
poetry run uv pip install pyvirtualdisplay pillow
poetry run playwright install --with-deps
- run: |
poetry run pytest tests/test_node_version.py
poetry run pytest tests/integration

View File

@ -0,0 +1,88 @@
name: check-outdated-dependencies
on:
push: # This will trigger the action when a pull request is opened or updated.
branches:
- 'release/**' # This will trigger the action when any branch starting with "release/" is created.
workflow_dispatch: # Allow manual triggering if needed.
jobs:
backend:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- uses: ./.github/actions/setup_build_env
with:
python-version: '3.9'
run-poetry-install: true
create-venv-at-path: .venv
- name: Check outdated backend dependencies
run: |
outdated=$(poetry show -oT)
echo "Outdated:"
echo "$outdated"
filtered_outdated=$(echo "$outdated" | grep -vE 'pyright|ruff' || true)
if [ ! -z "$filtered_outdated" ]; then
echo "Outdated dependencies found:"
echo "$filtered_outdated"
exit 1
else
echo "All dependencies are up to date. (pyright and ruff are ignored)"
fi
frontend:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- uses: ./.github/actions/setup_build_env
with:
python-version: '3.10.11'
run-poetry-install: true
create-venv-at-path: .venv
- name: Clone Reflex Website Repo
uses: actions/checkout@v4
with:
repository: reflex-dev/reflex-web
ref: main
path: reflex-web
- name: Install Requirements for reflex-web
working-directory: ./reflex-web
run: poetry run uv pip install -r requirements.txt
- name: Install additional dependencies for DB access
run: poetry run uv pip install psycopg2-binary
- name: Init Website for reflex-web
working-directory: ./reflex-web
run: poetry run reflex init
- name: Run Website and Check for errors
run: |
poetry run bash scripts/integration.sh ./reflex-web dev
- name: Check outdated frontend dependencies
working-directory: ./reflex-web/.web
run: |
raw_outdated=$(/home/runner/.local/share/reflex/bun/bin/bun outdated)
outdated=$(echo "$raw_outdated" | grep -vE '\|\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\|' || true)
echo "Outdated:"
echo "$outdated"
# Ignore 3rd party dependencies that are not updated.
filtered_outdated=$(echo "$outdated" | grep -vE 'Package|@chakra-ui|lucide-react|@splinetool/runtime|ag-grid-react|framer-motion|react-markdown|remark-math|remark-gfm|rehype-katex|rehype-raw|remark-unwrap-images' || true)
no_extra=$(echo "$filtered_outdated" | grep -vE '\|\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-' || true)
if [ ! -z "$no_extra" ]; then
echo "Outdated dependencies found:"
echo "$filtered_outdated"
exit 1
else
echo "All dependencies are up to date. (3rd party packages are ignored)"
fi

17
.github/workflows/dependency-review.yml vendored Normal file
View File

@ -0,0 +1,17 @@
name: 'Dependency Review'
on: [pull_request]
permissions:
contents: read
jobs:
dependency-review:
runs-on: ubuntu-latest
steps:
- name: 'Checkout Repository'
uses: actions/checkout@v4
- name: 'Dependency Review'
uses: actions/dependency-review-action@v4
with:
allow-licenses: Apache-2.0, BSD-2-Clause, BSD-3-Clause, HPND, ISC, MIT, MPL-2.0, Unlicense, Python-2.0, Python-2.0.1, Apache-2.0 AND MIT, BSD-2-Clause AND BSD-3-Clause, Apache-2.0 AND BSD-3-Clause
allow-dependencies-licenses: 'pkg:pypi/lazy-loader'

View File

@ -23,8 +23,8 @@ jobs:
strategy:
matrix:
state_manager: ['redis', 'memory']
python-version: ['3.8.18', '3.11.5', '3.12.0']
runs-on: ubuntu-latest
python-version: ['3.11.5', '3.12.0']
runs-on: ubuntu-22.04
services:
# Label used to access the service container
redis:
@ -45,13 +45,14 @@ jobs:
python-version: ${{ matrix.python-version }}
run-poetry-install: true
create-venv-at-path: .venv
- run: poetry run pip install pyvirtualdisplay pillow
- run: poetry run uv pip install pyvirtualdisplay pillow
- name: Run app harness tests
env:
SCREENSHOT_DIR: /tmp/screenshots
REDIS_URL: ${{ matrix.state_manager == 'redis' && 'redis://localhost:6379' || '' }}
run: |
poetry run pytest integration
poetry run playwright install --with-deps
poetry run pytest tests/integration
- uses: actions/upload-artifact@v4
name: Upload failed test screenshots
if: always()

View File

@ -29,34 +29,31 @@ env:
# - Best effort print lines that contain illegal chars (map to some default char, etc.)
PYTHONIOENCODING: 'utf8'
TELEMETRY_ENABLED: false
NODE_OPTIONS: '--max_old_space_size=4096'
DATABASE_URL: ${{ secrets.DATABASE_URL }}
NODE_OPTIONS: '--max_old_space_size=8192'
PR_TITLE: ${{ github.event.pull_request.title }}
jobs:
example-counter:
env:
OUTPUT_FILE: import_benchmark.json
timeout-minutes: 30
strategy:
# Prioritize getting more information out of the workflow (even if something fails)
fail-fast: false
matrix:
# Show OS combos first in GUI
os: [ubuntu-latest, windows-latest, macos-12]
python-version: ['3.8.18', '3.9.18', '3.10.13', '3.11.5', '3.12.0']
os: [ubuntu-latest, windows-latest]
python-version: ['3.9.18', '3.10.13', '3.11.5', '3.12.0']
exclude:
- os: windows-latest
python-version: '3.10.13'
- os: windows-latest
python-version: '3.9.18'
- os: windows-latest
python-version: '3.8.18'
include:
- os: windows-latest
python-version: '3.10.11'
- os: windows-latest
python-version: '3.9.13'
- os: windows-latest
python-version: '3.8.10'
runs-on: ${{ matrix.os }}
steps:
@ -74,9 +71,9 @@ jobs:
- name: Install requirements for counter example
working-directory: ./reflex-examples/counter
run: |
poetry run pip install -r requirements.txt
poetry run uv pip install -r requirements.txt
- name: Install additional dependencies for DB access
run: poetry run pip install psycopg2-binary
run: poetry run uv pip install psycopg2-binary
- name: Check export --backend-only before init for counter example
working-directory: ./reflex-examples/counter
run: |
@ -98,20 +95,34 @@ jobs:
npm -v
poetry run bash scripts/integration.sh ./reflex-examples/counter dev
- name: Measure and upload .web size
if: ${{ env.DATABASE_URL }}
run:
poetry run python scripts/benchmarks/benchmark_reflex_size.py --os "${{ matrix.os }}"
poetry run python benchmarks/benchmark_web_size.py --os "${{ matrix.os }}"
--python-version "${{ matrix.python-version }}" --commit-sha "${{ github.sha }}"
--pr-id "${{ github.event.pull_request.id }}" --db-url "${{ env.DATABASE_URL }}"
--pr-id "${{ github.event.pull_request.id }}"
--branch-name "${{ github.head_ref || github.ref_name }}"
--measurement-type "counter-app-dot-web" --path ./reflex-examples/counter/.web
--path ./reflex-examples/counter/.web
--app-name "counter"
- name: Install hyperfine
run: cargo install hyperfine
- name: Benchmark imports
working-directory: ./reflex-examples/counter
run: hyperfine --warmup 3 "export POETRY_VIRTUALENVS_PATH=../../.venv; poetry run python counter/counter.py" --show-output --export-json "${{ env.OUTPUT_FILE }}" --shell bash
- name: Upload Benchmarks
run:
poetry run python benchmarks/benchmark_imports.py --os "${{ matrix.os }}"
--python-version "${{ matrix.python-version }}" --commit-sha "${{ github.sha }}"
--benchmark-json "./reflex-examples/counter/${{ env.OUTPUT_FILE }}"
--branch-name "${{ github.head_ref || github.ref_name }}" --pr-id "${{ github.event.pull_request.id }}"
--app-name "counter"
reflex-web:
strategy:
fail-fast: false
matrix:
# Show OS combos first in GUI
os: [ubuntu-latest, windows-latest, macos-12]
os: [ubuntu-latest]
python-version: ['3.10.11', '3.11.4']
env:
@ -134,9 +145,9 @@ jobs:
- name: Install Requirements for reflex-web
working-directory: ./reflex-web
run: poetry run pip install -r requirements.txt
run: poetry run uv pip install -r requirements.txt
- name: Install additional dependencies for DB access
run: poetry run pip install psycopg2-binary
run: poetry run uv pip install psycopg2-binary
- name: Init Website for reflex-web
working-directory: ./reflex-web
run: poetry run reflex init
@ -146,10 +157,49 @@ jobs:
npm -v
poetry run bash scripts/integration.sh ./reflex-web prod
- name: Measure and upload .web size
if: ${{ env.DATABASE_URL }}
run:
poetry run python scripts/benchmarks/benchmark_reflex_size.py --os "${{ matrix.os }}"
poetry run python benchmarks/benchmark_web_size.py --os "${{ matrix.os }}"
--python-version "${{ matrix.python-version }}" --commit-sha "${{ github.sha }}"
--pr-id "${{ github.event.pull_request.id }}"
--db-url "${{ env.DATABASE_URL }}" --branch-name "${{ github.head_ref || github.ref_name }}"
--measurement-type "reflex-web-dot-web" --path ./reflex-web/.web
--pr-id "${{ github.event.pull_request.id }}" --branch-name "${{ github.head_ref || github.ref_name }}"
--app-name "reflex-web" --path ./reflex-web/.web
reflex-web-macos:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
strategy:
fail-fast: false
matrix:
python-version: ['3.11.5', '3.12.0']
runs-on: macos-12
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup_build_env
with:
python-version: ${{ matrix.python-version }}
run-poetry-install: true
create-venv-at-path: .venv
- name: Clone Reflex Website Repo
uses: actions/checkout@v4
with:
repository: reflex-dev/reflex-web
ref: main
path: reflex-web
- name: Install Requirements for reflex-web
working-directory: ./reflex-web
run: poetry run uv pip install -r requirements.txt
- name: Install additional dependencies for DB access
run: poetry run uv pip install psycopg2-binary
- name: Init Website for reflex-web
working-directory: ./reflex-web
run: poetry run reflex init
- name: Run Website and Check for errors
run: |
# Check that npm is home
npm -v
poetry run bash scripts/integration.sh ./reflex-web prod
- name: Measure and upload .web size
run:
poetry run python benchmarks/benchmark_web_size.py --os "${{ matrix.os }}"
--python-version "${{ matrix.python-version }}" --commit-sha "${{ github.sha }}"
--pr-id "${{ github.event.pull_request.id }}" --branch-name "${{ github.head_ref || github.ref_name }}"
--app-name "reflex-web" --path ./reflex-web/.web

View File

@ -37,6 +37,8 @@ jobs:
path: reflex-examples
- uses: Vampire/setup-wsl@v3
with:
distribution: Ubuntu-24.04
- name: Install Python
shell: wsl-bash {0}
@ -56,11 +58,16 @@ jobs:
run: |
poetry install
- name: Install uv
shell: wsl-bash {0}
run: |
poetry run pip install uv
- name: Install requirements for counter example
working-directory: ./reflex-examples/counter
shell: wsl-bash {0}
run: |
poetry run pip install -r requirements.txt
poetry run uv pip install -r requirements.txt
- name: Check export --backend-only before init for counter example
working-directory: ./reflex-examples/counter
shell: wsl-bash {0}

View File

@ -28,7 +28,7 @@ jobs:
create-venv-at-path: .venv
# TODO pre-commit related stuff can be cached too (not a bottleneck yet)
- run: |
poetry run pip install pre-commit
poetry run uv pip install pre-commit
poetry run pre-commit run --all-files
env:
SKIP: update-pyi-files

View File

@ -28,5 +28,5 @@ jobs:
# Run reflex init in a docker container
# cwd is repo root
docker build -f integration/init-test/Dockerfile -t reflex-init-test integration/init-test
docker run --rm -v $(pwd):/reflex-repo/ reflex-init-test /reflex-repo/integration/init-test/in_docker_test_script.sh
docker build -f tests/integration/init-test/Dockerfile -t reflex-init-test tests/integration/init-test
docker run --rm -v $(pwd):/reflex-repo/ reflex-init-test /reflex-repo/tests/integration/init-test/in_docker_test_script.sh

View File

@ -27,24 +27,21 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-12]
python-version: ['3.8.18', '3.9.18', '3.10.13', '3.11.5', '3.12.0']
os: [ubuntu-latest, windows-latest]
python-version: ['3.9.18', '3.10.13', '3.11.5', '3.12.0']
# Windows is a bit behind on Python version availability in Github
exclude:
- os: windows-latest
python-version: '3.10.13'
- os: windows-latest
python-version: '3.9.18'
- os: windows-latest
python-version: '3.8.18'
include:
- os: windows-latest
python-version: '3.10.11'
- os: windows-latest
python-version: '3.9.13'
- os: windows-latest
python-version: '3.8.10'
runs-on: ${{ matrix.os }}
# Service containers to run with `runner-job`
services:
# Label used to access the service container
@ -69,17 +66,43 @@ jobs:
- name: Run unit tests
run: |
export PYTHONUNBUFFERED=1
poetry run pytest tests --cov --no-cov-on-fail --cov-report=
poetry run pytest tests/units --cov --no-cov-on-fail --cov-report=
- name: Run unit tests w/ redis
if: ${{ matrix.os == 'ubuntu-latest' }}
run: |
export PYTHONUNBUFFERED=1
export REDIS_URL=redis://localhost:6379
poetry run pytest tests --cov --no-cov-on-fail --cov-report=
poetry run pytest tests/units --cov --no-cov-on-fail --cov-report=
# Change to explicitly install v1 when reflex-hosting-cli is compatible with v2
- name: Run unit tests w/ pydantic v1
run: |
export PYTHONUNBUFFERED=1
poetry run pip install "pydantic~=1.10"
poetry run pytest tests --cov --no-cov-on-fail --cov-report=
- run: poetry run coverage html
poetry run uv pip install "pydantic~=1.10"
poetry run pytest tests/units --cov --no-cov-on-fail --cov-report=
- name: Generate coverage report
run: poetry run coverage html
unit-tests-macos:
timeout-minutes: 30
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
strategy:
fail-fast: false
matrix:
python-version: ['3.9.18', '3.10.13', '3.11.5', '3.12.0']
runs-on: macos-12
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup_build_env
with:
python-version: ${{ matrix.python-version }}
run-poetry-install: true
create-venv-at-path: .venv
- name: Run unit tests
run: |
export PYTHONUNBUFFERED=1
poetry run pytest tests/units --cov --no-cov-on-fail --cov-report=
- name: Run unit tests w/ pydantic v1
run: |
export PYTHONUNBUFFERED=1
poetry run uv pip install "pydantic~=1.10"
poetry run pytest tests/units --cov --no-cov-on-fail --cov-report=

3
.gitignore vendored
View File

@ -1,7 +1,9 @@
**/.DS_Store
**/*.pyc
assets/external/*
dist/*
examples/
.web
.idea
.vscode
.coverage
@ -11,3 +13,4 @@ venv
requirements.txt
.pyi_generator_last_run
.pyi_generator_diff
reflex.db

View File

@ -3,19 +3,29 @@ fail_fast: true
repos:
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.1.0
rev: v0.7.1
hooks:
- id: ruff-format
args: [integration, reflex, tests]
args: [reflex, tests]
- id: ruff
args: ["--fix", "--exit-non-zero-on-fix"]
exclude: '^integration/benchmarks/'
# Run pyi check before pyright because pyright can fail if pyi files are wrong.
- repo: local
hooks:
- id: update-pyi-files
name: update-pyi-files
always_run: true
language: system
description: 'Update pyi files as needed'
entry: python3 scripts/make_pyi.py
- repo: https://github.com/RobertCraigie/pyright-python
rev: v1.1.313
hooks:
- id: pyright
args: [integration, reflex, tests]
args: [reflex, tests]
language: system
- repo: https://github.com/terrencepreilly/darglint
@ -24,11 +34,3 @@ repos:
- id: darglint
exclude: '^reflex/reflex.py'
- repo: local
hooks:
- id: update-pyi-files
name: update-pyi-files
always_run: true
language: system
description: 'Update pyi files as needed'
entry: python scripts/make_pyi.py

View File

@ -8,7 +8,7 @@ Here is a quick guide on how to run Reflex repo locally so you can start contrib
**Prerequisites:**
- Python >= 3.8
- Python >= 3.9
- Poetry version >= 1.4.0 and add it to your path (see [Poetry Docs](https://python-poetry.org/docs/#installation) for more info).
**1. Fork this repository:**
@ -69,7 +69,7 @@ In your `reflex` directory run make sure all the unit tests are still passing us
This will fail if code coverage is below 70%.
``` bash
poetry run pytest tests --cov --no-cov-on-fail --cov-report=
poetry run pytest tests/units --cov --no-cov-on-fail --cov-report=
```
Next make sure all the following tests pass. This ensures that every new change has proper documentation and type checking.
@ -80,14 +80,14 @@ poetry run pyright reflex tests
find reflex tests -name "*.py" -not -path reflex/reflex.py | xargs poetry run darglint
```
Finally, run `black` to format your code.
Finally, run `ruff` to format your code.
``` bash
poetry run black reflex tests
poetry run ruff format .
```
Consider installing git pre-commit hooks so Ruff, Pyright, Darglint and Black will run automatically before each commit.
Note that pre-commit will only be installed when you use a Python version >= 3.8.
Consider installing git pre-commit hooks so Ruff, Pyright, Darglint and `make_pyi` will run automatically before each commit.
Note that pre-commit will only be installed when you use a Python version >= 3.9.
``` bash
pre-commit install

View File

@ -10,7 +10,6 @@
### **✨ Performant, customizable web apps in pure Python. Deploy in seconds. ✨**
[![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![tests](https://github.com/pynecone-io/pynecone/actions/workflows/integration.yml/badge.svg)
![versions](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentation](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
@ -18,7 +17,7 @@
---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md)
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md) | [Tiếng Việt](https://github.com/reflex-dev/reflex/blob/main/docs/vi/README.md)
---
@ -35,7 +34,7 @@ See our [architecture page](https://reflex.dev/blog/2024-03-21-reflex-architectu
## ⚙️ Installation
Open a terminal and run (Requires Python 3.8+):
Open a terminal and run (Requires Python 3.9+):
```bash
pip install reflex
@ -120,14 +119,15 @@ def index():
on_blur=State.set_prompt,
width="25em",
),
rx.button("Generate Image", on_click=State.get_image, width="25em"),
rx.button(
"Generate Image",
on_click=State.get_image,
width="25em",
loading=State.processing
),
rx.cond(
State.processing,
rx.chakra.circular_progress(is_indeterminate=True),
rx.cond(
State.complete,
rx.image(src=State.image_url, width="20em"),
),
State.complete,
rx.image(src=State.image_url, width="20em"),
),
align="center",
),
@ -185,7 +185,7 @@ class State(rx.State):
The state defines all the variables (called vars) in an app that can change and the functions that change them.
Here the state is comprised of a `prompt` and `image_url`. There are also the booleans `processing` and `complete` to indicate when to show the circular progress and image.
Here the state is comprised of a `prompt` and `image_url`. There are also the booleans `processing` and `complete` to indicate when to disable the button (during image generation) and when to show the resulting image.
### **Event Handlers**
@ -228,7 +228,7 @@ You can create a multi-page app by adding more pages.
<div align="center">
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Component Library](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Gallery](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy-quick-start) &nbsp;
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Component Library](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Templates](https://reflex.dev/templates/) &nbsp; | &nbsp; 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy-quick-start) &nbsp;
</div>

View File

@ -1,13 +1,12 @@
"""Runs the benchmarks and inserts the results into the database."""
"""Extracts the compile times from the JSON files in the specified directory and inserts them into the database."""
from __future__ import annotations
import argparse
import json
import os
from datetime import datetime
import psycopg2
from utils import send_data_to_posthog
def extract_stats_from_json(json_file: str) -> list[dict]:
@ -51,7 +50,6 @@ def extract_stats_from_json(json_file: str) -> list[dict]:
def insert_benchmarking_data(
db_connection_url: str,
os_type_version: str,
python_version: str,
performance_data: list[dict],
@ -59,52 +57,33 @@ def insert_benchmarking_data(
pr_title: str,
branch_name: str,
event_type: str,
actor: str,
pr_id: str,
):
"""Insert the benchmarking data into the database.
Args:
db_connection_url: The URL to connect to the database.
os_type_version: The OS type and version to insert.
python_version: The Python version to insert.
performance_data: The performance data of reflex web to insert.
commit_sha: The commit SHA to insert.
pr_title: The PR title to insert.
branch_name: The name of the branch.
event_type: Type of github event(push, pull request, etc)
actor: Username of the user that triggered the run.
event_type: Type of github event(push, pull request, etc).
pr_id: Id of the PR.
"""
# Serialize the JSON data
simple_app_performance_json = json.dumps(performance_data)
# Prepare the event data
properties = {
"os": os_type_version,
"python_version": python_version,
"distinct_id": commit_sha,
"pr_title": pr_title,
"branch_name": branch_name,
"event_type": event_type,
"performance": performance_data,
"pr_id": pr_id,
}
# Get the current timestamp
current_timestamp = datetime.now()
# Connect to the database and insert the data
with psycopg2.connect(db_connection_url) as conn, conn.cursor() as cursor:
insert_query = """
INSERT INTO simple_app_benchmarks (os, python_version, commit_sha, time, pr_title, branch_name, event_type, actor, performance, pr_id)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s);
"""
cursor.execute(
insert_query,
(
os_type_version,
python_version,
commit_sha,
current_timestamp,
pr_title,
branch_name,
event_type,
actor,
simple_app_performance_json,
pr_id,
),
)
# Commit the transaction
conn.commit()
send_data_to_posthog("simple_app_benchmark", properties)
def main():
@ -124,11 +103,6 @@ def main():
"--benchmark-json",
help="The JSON file containing the benchmark results.",
)
parser.add_argument(
"--db-url",
help="The URL to connect to the database.",
required=True,
)
parser.add_argument(
"--pr-title",
help="The PR title to insert into the database.",
@ -143,11 +117,6 @@ def main():
help="The github event type",
required=True,
)
parser.add_argument(
"--actor",
help="Username of the user that triggered the run.",
required=True,
)
parser.add_argument(
"--pr-id",
help="ID of the PR.",
@ -162,7 +131,6 @@ def main():
cleaned_benchmark_results = extract_stats_from_json(args.benchmark_json)
# Insert the data into the database
insert_benchmarking_data(
db_connection_url=args.db_url,
os_type_version=args.os,
python_version=args.python_version,
performance_data=cleaned_benchmark_results,
@ -170,7 +138,6 @@ def main():
pr_title=pr_title,
branch_name=args.branch_name,
event_type=args.event_type,
actor=args.actor,
pr_id=args.pr_id,
)

View File

@ -0,0 +1,127 @@
"""Extract and upload benchmarking data to PostHog."""
from __future__ import annotations
import argparse
import json
import os
from utils import send_data_to_posthog
def extract_stats_from_json(json_file: str) -> dict:
"""Extracts the stats from the JSON data and returns them as dictionaries.
Args:
json_file: The JSON file to extract the stats data from.
Returns:
dict: The stats for each test.
"""
with open(json_file, "r") as file:
json_data = json.load(file)
# Load the JSON data if it is a string, otherwise assume it's already a dictionary
data = json.loads(json_data) if isinstance(json_data, str) else json_data
result = data.get("results", [{}])[0]
return {
k: v
for k, v in result.items()
if k in ("mean", "stddev", "median", "min", "max")
}
def insert_benchmarking_data(
os_type_version: str,
python_version: str,
performance_data: dict,
commit_sha: str,
pr_title: str,
branch_name: str,
pr_id: str,
app_name: str,
):
"""Insert the benchmarking data into the database.
Args:
os_type_version: The OS type and version to insert.
python_version: The Python version to insert.
performance_data: The imports performance data to insert.
commit_sha: The commit SHA to insert.
pr_title: The PR title to insert.
branch_name: The name of the branch.
pr_id: Id of the PR.
app_name: The name of the app being measured.
"""
properties = {
"os": os_type_version,
"python_version": python_version,
"distinct_id": commit_sha,
"pr_title": pr_title,
"branch_name": branch_name,
"pr_id": pr_id,
"performance": performance_data,
"app_name": app_name,
}
send_data_to_posthog("import_benchmark", properties)
def main():
"""Runs the benchmarks and inserts the results."""
# Get the commit SHA and JSON directory from the command line arguments
parser = argparse.ArgumentParser(description="Run benchmarks and process results.")
parser.add_argument(
"--os", help="The OS type and version to insert into the database."
)
parser.add_argument(
"--python-version", help="The Python version to insert into the database."
)
parser.add_argument(
"--commit-sha", help="The commit SHA to insert into the database."
)
parser.add_argument(
"--benchmark-json",
help="The JSON file containing the benchmark results.",
)
parser.add_argument(
"--pr-title",
help="The PR title to insert into the database.",
)
parser.add_argument(
"--branch-name",
help="The current branch",
required=True,
)
parser.add_argument(
"--app-name",
help="The name of the app measured.",
required=True,
)
parser.add_argument(
"--pr-id",
help="ID of the PR.",
required=True,
)
args = parser.parse_args()
# Get the PR title from env or the args. For the PR merge or push event, there is no PR title, leaving it empty.
pr_title = args.pr_title or os.getenv("PR_TITLE", "")
cleaned_benchmark_results = extract_stats_from_json(args.benchmark_json)
# Insert the data into the database
insert_benchmarking_data(
os_type_version=args.os,
python_version=args.python_version,
performance_data=cleaned_benchmark_results,
commit_sha=args.commit_sha,
pr_title=pr_title,
branch_name=args.branch_name,
app_name=args.app_name,
pr_id=args.pr_id,
)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,75 @@
"""Extracts the Lighthouse scores from the JSON files in the specified directory and inserts them into the database."""
from __future__ import annotations
import json
import sys
from pathlib import Path
from utils import send_data_to_posthog
def insert_benchmarking_data(
lighthouse_data: dict,
commit_sha: str,
):
"""Insert the benchmarking data into the database.
Args:
lighthouse_data: The Lighthouse data to insert.
commit_sha: The commit SHA to insert.
"""
properties = {
"distinct_id": commit_sha,
"lighthouse_data": lighthouse_data,
}
# Send the data to PostHog
send_data_to_posthog("lighthouse_benchmark", properties)
def get_lighthouse_scores(directory_path: str | Path) -> dict:
"""Extracts the Lighthouse scores from the JSON files in the specified directory.
Args:
directory_path (str): The path to the directory containing the JSON files.
Returns:
dict: The Lighthouse scores.
"""
scores = {}
directory_path = Path(directory_path)
try:
for filename in directory_path.iterdir():
if filename.suffix == ".json" and filename.stem != "manifest":
data = json.loads(filename.read_text())
# Extract scores and add them to the dictionary with the filename as key
scores[data["finalUrl"].replace("http://localhost:3000/", "/")] = {
"performance_score": data["categories"]["performance"]["score"],
"accessibility_score": data["categories"]["accessibility"]["score"],
"best_practices_score": data["categories"]["best-practices"][
"score"
],
"seo_score": data["categories"]["seo"]["score"],
}
except Exception as e:
return {"error": e}
return scores
def main():
"""Runs the benchmarks and inserts the results into the database."""
# Get the commit SHA and JSON directory from the command line arguments
commit_sha = sys.argv[1]
json_dir = sys.argv[2]
# Get the Lighthouse scores
lighthouse_scores = get_lighthouse_scores(json_dir)
# Insert the data into the database
insert_benchmarking_data(lighthouse_scores, commit_sha)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,135 @@
"""Checks the size of a specific directory and uploads result to Posthog."""
import argparse
import os
from pathlib import Path
from utils import get_directory_size, get_python_version, send_data_to_posthog
def get_package_size(venv_path: Path, os_name):
"""Get the size of a specified package.
Args:
venv_path: The path to the venv.
os_name: Name of os.
Returns:
The total size of the package in bytes.
Raises:
ValueError: when venv does not exist or python version is None.
"""
python_version = get_python_version(venv_path, os_name)
print("Python version:", python_version)
if python_version is None:
raise ValueError("Error: Failed to determine Python version.")
is_windows = "windows" in os_name
package_dir: Path = (
venv_path / "lib" / f"python{python_version}" / "site-packages"
if not is_windows
else venv_path / "Lib" / "site-packages"
)
if not package_dir.exists():
raise ValueError(
"Error: Virtual environment does not exist or is not activated."
)
total_size = get_directory_size(package_dir)
return total_size
def insert_benchmarking_data(
os_type_version: str,
python_version: str,
commit_sha: str,
pr_title: str,
branch_name: str,
pr_id: str,
path: str,
):
"""Insert the benchmarking data into PostHog.
Args:
os_type_version: The OS type and version to insert.
python_version: The Python version to insert.
commit_sha: The commit SHA to insert.
pr_title: The PR title to insert.
branch_name: The name of the branch.
pr_id: The id of the PR.
path: The path to the dir or file to check size.
"""
if "./dist" in path:
size = get_directory_size(Path(path))
else:
size = get_package_size(Path(path), os_type_version)
# Prepare the event data
properties = {
"path": path,
"os": os_type_version,
"python_version": python_version,
"distinct_id": commit_sha,
"pr_title": pr_title,
"branch_name": branch_name,
"pr_id": pr_id,
"size_mb": round(
size / (1024 * 1024), 3
), # save size in MB and round to 3 places
}
send_data_to_posthog("package_size", properties)
def main():
"""Runs the benchmarks and inserts the results."""
parser = argparse.ArgumentParser(description="Run benchmarks and process results.")
parser.add_argument(
"--os", help="The OS type and version to insert into the database."
)
parser.add_argument(
"--python-version", help="The Python version to insert into the database."
)
parser.add_argument(
"--commit-sha", help="The commit SHA to insert into the database."
)
parser.add_argument(
"--pr-title",
help="The PR title to insert into the database.",
)
parser.add_argument(
"--branch-name",
help="The current branch",
required=True,
)
parser.add_argument(
"--pr-id",
help="The pr id",
required=True,
)
parser.add_argument(
"--path",
help="The path to the vnenv.",
required=True,
)
args = parser.parse_args()
# Get the PR title from env or the args. For the PR merge or push event, there is no PR title, leaving it empty.
pr_title = args.pr_title or os.getenv("PR_TITLE", "")
# Insert the data into the database
insert_benchmarking_data(
os_type_version=args.os,
python_version=args.python_version,
commit_sha=args.commit_sha,
pr_title=pr_title,
branch_name=args.branch_name,
pr_id=args.pr_id,
path=args.path,
)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,106 @@
"""Checks the size of a specific directory and uploads result to Posthog."""
import argparse
import os
from pathlib import Path
from utils import get_directory_size, send_data_to_posthog
def insert_benchmarking_data(
os_type_version: str,
python_version: str,
app_name: str,
commit_sha: str,
pr_title: str,
branch_name: str,
pr_id: str,
path: str,
):
"""Insert the benchmarking data into PostHog.
Args:
app_name: The name of the app being measured.
os_type_version: The OS type and version to insert.
python_version: The Python version to insert.
commit_sha: The commit SHA to insert.
pr_title: The PR title to insert.
branch_name: The name of the branch.
pr_id: The id of the PR.
path: The path to the dir or file to check size.
"""
size = get_directory_size(Path(path))
# Prepare the event data
properties = {
"app_name": app_name,
"os": os_type_version,
"python_version": python_version,
"distinct_id": commit_sha,
"pr_title": pr_title,
"branch_name": branch_name,
"pr_id": pr_id,
"size_mb": round(
size / (1024 * 1024), 3
), # save size in MB and round to 3 places
}
send_data_to_posthog("web-size", properties)
def main():
"""Runs the benchmarks and inserts the results."""
parser = argparse.ArgumentParser(description="Run benchmarks and process results.")
parser.add_argument(
"--os", help="The OS type and version to insert into the database."
)
parser.add_argument(
"--python-version", help="The Python version to insert into the database."
)
parser.add_argument(
"--commit-sha", help="The commit SHA to insert into the database."
)
parser.add_argument(
"--pr-title",
help="The PR title to insert into the database.",
)
parser.add_argument(
"--branch-name",
help="The current branch",
required=True,
)
parser.add_argument(
"--app-name",
help="The name of the app measured.",
required=True,
)
parser.add_argument(
"--pr-id",
help="The pr id",
required=True,
)
parser.add_argument(
"--path",
help="The current path to app to check.",
required=True,
)
args = parser.parse_args()
# Get the PR title from env or the args. For the PR merge or push event, there is no PR title, leaving it empty.
pr_title = args.pr_title or os.getenv("PR_TITLE", "")
# Insert the data into the database
insert_benchmarking_data(
app_name=args.app_name,
os_type_version=args.os,
python_version=args.python_version,
commit_sha=args.commit_sha,
pr_title=pr_title,
branch_name=args.branch_name,
pr_id=args.pr_id,
path=args.path,
)
if __name__ == "__main__":
main()

View File

@ -13,6 +13,9 @@ from reflex import constants
from reflex.compiler import utils
from reflex.testing import AppHarness, chdir
from reflex.utils import build
from reflex.utils.prerequisites import get_web_dir
web_pages = get_web_dir() / constants.Dirs.PAGES
def render_component(num: int):
@ -231,7 +234,7 @@ def test_app_10_compile_time_cold(benchmark, app_with_10_components):
def setup():
with chdir(app_with_10_components.app_path):
utils.empty_dir(constants.Dirs.WEB_PAGES, keep_files=["_app.js"])
utils.empty_dir(web_pages, ["_app.js"])
app_with_10_components._initialize_app()
build.setup_frontend(app_with_10_components.app_path)
@ -284,7 +287,7 @@ def test_app_100_compile_time_cold(benchmark, app_with_100_components):
def setup():
with chdir(app_with_100_components.app_path):
utils.empty_dir(constants.Dirs.WEB_PAGES, keep_files=["_app.js"])
utils.empty_dir(web_pages, ["_app.js"])
app_with_100_components._initialize_app()
build.setup_frontend(app_with_100_components.app_path)
@ -337,7 +340,7 @@ def test_app_1000_compile_time_cold(benchmark, app_with_1000_components):
def setup():
with chdir(app_with_1000_components.app_path):
utils.empty_dir(constants.Dirs.WEB_PAGES, keep_files=["_app.js"])
utils.empty_dir(web_pages, keep_files=["_app.js"])
app_with_1000_components._initialize_app()
build.setup_frontend(app_with_1000_components.app_path)

View File

@ -13,6 +13,9 @@ from reflex import constants
from reflex.compiler import utils
from reflex.testing import AppHarness, chdir
from reflex.utils import build
from reflex.utils.prerequisites import get_web_dir
web_pages = get_web_dir() / constants.Dirs.PAGES
def render_multiple_pages(app, num: int):
@ -141,7 +144,7 @@ def AppWithOnePage():
def index() -> rx.Component:
return rx.center(
rx.chakra.input(
rx.input(
id="token", value=State.router.session.client_token, is_read_only=True
),
rx.vstack(
@ -320,7 +323,7 @@ def test_app_1_compile_time_cold(benchmark, app_with_one_page):
def setup():
with chdir(app_with_one_page.app_path):
utils.empty_dir(constants.Dirs.WEB_PAGES, keep_files=["_app.js"])
utils.empty_dir(web_pages, keep_files=["_app.js"])
app_with_one_page._initialize_app()
build.setup_frontend(app_with_one_page.app_path)
@ -375,7 +378,7 @@ def test_app_10_compile_time_cold(benchmark, app_with_ten_pages):
def setup():
with chdir(app_with_ten_pages.app_path):
utils.empty_dir(constants.Dirs.WEB_PAGES, keep_files=["_app.js"])
utils.empty_dir(web_pages, keep_files=["_app.js"])
app_with_ten_pages._initialize_app()
build.setup_frontend(app_with_ten_pages.app_path)
@ -430,7 +433,7 @@ def test_app_100_compile_time_cold(benchmark, app_with_hundred_pages):
def setup():
with chdir(app_with_hundred_pages.app_path):
utils.empty_dir(constants.Dirs.WEB_PAGES, keep_files=["_app.js"])
utils.empty_dir(web_pages, keep_files=["_app.js"])
app_with_hundred_pages._initialize_app()
build.setup_frontend(app_with_hundred_pages.app_path)
@ -485,7 +488,7 @@ def test_app_1000_compile_time_cold(benchmark, app_with_thousand_pages):
def setup():
with chdir(app_with_thousand_pages.app_path):
utils.empty_dir(constants.Dirs.WEB_PAGES, keep_files=["_app.js"])
utils.empty_dir(web_pages, keep_files=["_app.js"])
app_with_thousand_pages._initialize_app()
build.setup_frontend(app_with_thousand_pages.app_path)
@ -540,7 +543,7 @@ def test_app_10000_compile_time_cold(benchmark, app_with_ten_thousand_pages):
def setup():
with chdir(app_with_ten_thousand_pages.app_path):
utils.empty_dir(constants.Dirs.WEB_PAGES, keep_files=["_app.js"])
utils.empty_dir(web_pages, keep_files=["_app.js"])
app_with_ten_thousand_pages._initialize_app()
build.setup_frontend(app_with_ten_thousand_pages.app_path)

74
benchmarks/utils.py Normal file
View File

@ -0,0 +1,74 @@
"""Utility functions for the benchmarks."""
import os
import subprocess
from pathlib import Path
import httpx
from httpx import HTTPError
def get_python_version(venv_path: Path, os_name):
"""Get the python version of python in a virtual env.
Args:
venv_path: Path to virtual environment.
os_name: Name of os.
Returns:
The python version.
"""
python_executable = (
venv_path / "bin" / "python"
if "windows" not in os_name
else venv_path / "Scripts" / "python.exe"
)
try:
output = subprocess.check_output(
[str(python_executable), "--version"], stderr=subprocess.STDOUT
)
python_version = output.decode("utf-8").strip().split()[1]
return ".".join(python_version.split(".")[:-1])
except subprocess.CalledProcessError:
return None
def get_directory_size(directory: Path):
"""Get the size of a directory in bytes.
Args:
directory: The directory to check.
Returns:
The size of the dir in bytes.
"""
total_size = 0
for dirpath, _, filenames in os.walk(directory):
for f in filenames:
fp = Path(dirpath) / f
total_size += fp.stat().st_size
return total_size
def send_data_to_posthog(event, properties):
"""Send data to PostHog.
Args:
event: The event to send.
properties: The properties to send.
Raises:
HTTPError: When there is an error sending data to PostHog.
"""
event_data = {
"api_key": "phc_JoMo0fOyi0GQAooY3UyO9k0hebGkMyFJrrCw1Gt5SGb",
"event": event,
"properties": properties,
}
with httpx.Client() as client:
response = client.post("https://app.posthog.com/capture/", json=event_data)
if response.status_code != 200:
raise HTTPError(
f"Error sending data to PostHog: {response.status_code} - {response.text}"
)

View File

@ -1,133 +1,30 @@
# Reflex Docker Container
# Reflex Docker Examples
This example describes how to create and use a container image for Reflex with your own code.
This directory contains several examples of how to deploy Reflex apps using docker.
## Update Requirements
In all cases, ensure that your `requirements.txt` file is up to date and
includes the `reflex` package.
The `requirements.txt` includes the reflex package which is needed to install
Reflex framework. If you use additional packages in your project you have to add
this in the `requirements.txt` first. Copy the `Dockerfile`, `.dockerignore` and
the `requirements.txt` file in your project folder.
## `simple-two-port`
## Build Simple Reflex Container Image
The most basic production deployment exposes two HTTP ports and relies on an
existing load balancer to forward the traffic appropriately.
The main `Dockerfile` is intended to build a very simple, single container deployment that runs
the Reflex frontend and backend together, exposing ports 3000 and 8000.
## `simple-one-port`
To build your container image run the following command:
This deployment exports the frontend statically and serves it via a single HTTP
port using Caddy. This is useful for platforms that only support a single port
or where running a node server in the container is undesirable.
```bash
docker build -t reflex-app:latest .
```
## `production-compose`
## Start Container Service
This deployment is intended for use with a standalone VPS that is only hosting a
single Reflex app. It provides the entire stack in a single `compose.yaml`
including a webserver, one or more backend instances, redis, and a postgres
database.
Finally, you can start your Reflex container service as follows:
## `production-app-platform`
```bash
docker run -it --rm -p 3000:3000 -p 8000:8000 --name app reflex-app:latest
```
It may take a few seconds for the service to become available.
Access your app at http://localhost:3000.
Note that this container has _no persistence_ and will lose all data when
stopped. You can use bind mounts or named volumes to persist the database and
uploaded_files directories as needed.
# Production Service with Docker Compose and Caddy
An example production deployment uses automatic TLS with Caddy serving static files
for the frontend and proxying requests to both the frontend and backend.
Copy the following files to your project directory:
* `compose.yaml`
* `compose.prod.yaml`
* `compose.tools.yaml`
* `prod.Dockerfile`
* `Caddy.Dockerfile`
* `Caddyfile`
The production app container, based on `prod.Dockerfile`, builds and exports the
frontend statically (to be served by Caddy). The resulting image only runs the
backend service.
The `webserver` service, based on `Caddy.Dockerfile`, copies the static frontend
and `Caddyfile` into the container to configure the reverse proxy routes that will
forward requests to the backend service. Caddy will automatically provision TLS
for localhost or the domain specified in the environment variable `DOMAIN`.
This type of deployment should use less memory and be more performant since
nodejs is not required at runtime.
## Customize `Caddyfile` (optional)
If the app uses additional backend API routes, those should be added to the
`@backend_routes` path matcher to ensure they are forwarded to the backend.
## Build Reflex Production Service
During build, set `DOMAIN` environment variable to the domain where the app will
be hosted! (Do not include http or https, it will always use https).
**If `DOMAIN` is not provided, the service will default to `localhost`.**
```bash
DOMAIN=example.com docker compose build
```
This will build both the `app` service from the `prod.Dockerfile` and the `webserver`
service via `Caddy.Dockerfile`.
## Run Reflex Production Service
```bash
DOMAIN=example.com docker compose up
```
The app should be available at the specified domain via HTTPS. Certificate
provisioning will occur automatically and may take a few minutes.
### Data Persistence
Named docker volumes are used to persist the app database (`db-data`),
uploaded_files (`upload-data`), and caddy TLS keys and certificates
(`caddy-data`).
## More Robust Deployment
For a more robust deployment, consider bringing the service up with
`compose.prod.yaml` which includes postgres database and redis cache, allowing
the backend to run with multiple workers and service more requests.
```bash
DOMAIN=example.com docker compose -f compose.yaml -f compose.prod.yaml up -d
```
Postgres uses its own named docker volume for data persistence.
## Admin Tools
When needed, the services in `compose.tools.yaml` can be brought up, providing
graphical database administration (Adminer on http://localhost:8080) and a
redis cache browser (redis-commander on http://localhost:8081). It is not recommended
to deploy these services if they are not in active use.
```bash
DOMAIN=example.com docker compose -f compose.yaml -f compose.prod.yaml -f compose.tools.yaml up -d
```
# Container Hosting
Most container hosting services automatically terminate TLS and expect the app
to be listening on a single port (typically `$PORT`).
To host a Reflex app on one of these platforms, like Google Cloud Run, Render,
Railway, etc, use `app.Dockerfile` to build a single image containing a reverse
proxy that will serve that frontend as static files and proxy requests to the
backend for specific endpoints.
If the chosen platform does not support buildx and thus heredoc, you can copy
the Caddyfile configuration into a separate Caddyfile in the root of the
project.
This example deployment is intended for use with App hosting platforms, like
Azure, AWS, or Google Cloud Run. It is the backend of the deployment, which
depends on a separately hosted redis instance and static frontend deployment.

View File

@ -0,0 +1,5 @@
.web
.git
__pycache__/*
Dockerfile
uploaded_files

View File

@ -0,0 +1,65 @@
# This docker file is intended to be used with container hosting services
#
# After deploying this image, get the URL pointing to the backend service
# and run API_URL=https://path-to-my-container.example.com reflex export frontend
# then copy the contents of `frontend.zip` to your static file server (github pages, s3, etc).
#
# Azure Static Web App example:
# npx @azure/static-web-apps-cli deploy --env production --app-location .web/_static
#
# For dynamic routes to function properly, ensure that 404s are redirected to /404 on the
# static file host (for github pages, this works out of the box; remember to create .nojekyll).
#
# For azure static web apps, add `staticwebapp.config.json` to to `.web/_static` with the following:
# {
# "responseOverrides": {
# "404": {
# "rewrite": "/404.html"
# }
# }
# }
#
# Note: many container hosting platforms require amd64 images, so when building on an M1 Mac
# for example, pass `docker build --platform=linux/amd64 ...`
# Stage 1: init
FROM python:3.11 as init
ARG uv=/root/.cargo/bin/uv
# Install `uv` for faster package boostrapping
ADD --chmod=755 https://astral.sh/uv/install.sh /install.sh
RUN /install.sh && rm /install.sh
# Copy local context to `/app` inside container (see .dockerignore)
WORKDIR /app
COPY . .
RUN mkdir -p /app/data /app/uploaded_files
# Create virtualenv which will be copied into final container
ENV VIRTUAL_ENV=/app/.venv
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
RUN $uv venv
# Install app requirements and reflex inside virtualenv
RUN $uv pip install -r requirements.txt
# Deploy templates and prepare app
RUN reflex init
# Stage 2: copy artifacts into slim image
FROM python:3.11-slim
WORKDIR /app
RUN adduser --disabled-password --home /app reflex
COPY --chown=reflex --from=init /app /app
# Install libpq-dev for psycopg2 (skip if not using postgres).
RUN apt-get update -y && apt-get install -y libpq-dev && rm -rf /var/lib/apt/lists/*
USER reflex
ENV PATH="/app/.venv/bin:$PATH" PYTHONUNBUFFERED=1
# Needed until Reflex properly passes SIGTERM on backend.
STOPSIGNAL SIGKILL
# Always apply migrations before starting the backend.
CMD [ -d alembic ] && reflex db migrate; \
exec reflex run --env prod --backend-only --backend-port ${PORT:-8000}

View File

@ -0,0 +1,113 @@
# production-app-platform
This example deployment is intended for use with App hosting platforms, like
Azure, AWS, or Google Cloud Run.
## Architecture
The production deployment consists of a few pieces:
* Backend container - built by `Dockerfile` Runs the Reflex backend
service on port 8000 and is scalable to multiple instances.
* Redis container - A single instance the standard `redis` docker image should
share private networking with the backend
* Static frontend - HTML/CSS/JS files that are hosted via a CDN or static file
server. This is not included in the docker image.
## Deployment
These general steps do not cover the specifics of each platform, but all platforms should
support the concepts described here.
### Vnet
All containers in the deployment should be hooked up to the same virtual private
network so they can access the redis service and optionally the database server.
The vnet should not be exposed to the internet, use an ingress rule to terminate
TLS at the load balancer and forward the traffic to a backend service replica.
### Redis
Deploy a `redis` instance on the vnet.
### Backend
The backend is built by the `Dockerfile` in this directory. When deploying the
backend, be sure to set REDIS_URL=redis://internal-redis-hostname to connect to
the redis service.
### Ingress
Configure the load balancer for the app to forward traffic to port 8000 on the
backend service replicas. Most platforms will generate an ingress hostname
automatically. Make sure when you access the ingress endpoint on `/ping` that it
returns "pong", indicating that the backend is up an available.
### Frontend
The frontend should be hosted on a static file server or CDN.
**Important**: when exporting the frontend, set the API_URL environment variable
to the ingress hostname of the backend service.
If you will host the frontend from a path other than the root, set the
`FRONTEND_PATH` environment variable appropriately when exporting the frontend.
Most static hosts will automatically use the `/404.html` file to handle 404
errors. _This is essential for dynamic routes to work correctly._ Ensure that
missing routes return the `/404.html` content to the user if this is not the
default behavior.
_For Github Pages_: ensure the file `.nojekyll` is present in the root of the repo
to avoid special processing of underscore-prefix directories, like `_next`.
## Platform Notes
The following sections are currently a work in progress and may be incomplete.
### Azure
In the Azure load balancer, per-message deflate is not supported. Add the following
to your `rxconfig.py` to workaround this issue.
```python
import uvicorn.workers
import reflex as rx
class NoWSPerMessageDeflate(uvicorn.workers.UvicornH11Worker):
CONFIG_KWARGS = {
**uvicorn.workers.UvicornH11Worker.CONFIG_KWARGS,
"ws_per_message_deflate": False,
}
config = rx.Config(
app_name="my_app",
gunicorn_worker_class="rxconfig.NoWSPerMessageDeflate",
)
```
#### Persistent Storage
If you need to use a database or upload files, you cannot save them to the
container volume. Use Azure Files and mount it into the container at /app/uploaded_files.
#### Resource Types
* Create a new vnet with 10.0.0.0/16
* Create a new subnet for redis, database, and containers
* Deploy redis as a Container Instances
* Deploy database server as "Azure Database for PostgreSQL"
* Create a new database for the app
* Set db-url as a secret containing the db user/password connection string
* Deploy Storage account for uploaded files
* Enable access from the vnet and container subnet
* Create a new file share
* In the environment, create a new files share (get the storage key)
* Deploy the backend as a Container App
* Create a custom Container App Environment linked up to the same vnet as the redis container.
* Set REDIS_URL and DB_URL environment variables
* Add the volume from the environment
* Add the volume mount to the container
* Deploy the frontend as a Static Web App

View File

@ -42,10 +42,11 @@ COPY --chown=reflex --from=init /app /app
# Install libpq-dev for psycopg2 (skip if not using postgres).
RUN apt-get update -y && apt-get install -y libpq-dev && rm -rf /var/lib/apt/lists/*
USER reflex
ENV PATH="/app/.venv/bin:$PATH"
ENV PATH="/app/.venv/bin:$PATH" PYTHONUNBUFFERED=1
# Needed until Reflex properly passes SIGTERM on backend.
STOPSIGNAL SIGKILL
# Always apply migrations before starting the backend.
CMD reflex db migrate && reflex run --env prod --backend-only
CMD [ -d alembic ] && reflex db migrate; \
exec reflex run --env prod --backend-only

View File

@ -0,0 +1,75 @@
# production-compose
This example production deployment uses automatic TLS with Caddy serving static
files for the frontend and proxying requests to both the frontend and backend.
It is intended for use with a standalone VPS that is only hosting a single
Reflex app.
The production app container (`Dockerfile`), builds and exports the frontend
statically (to be served by Caddy). The resulting image only runs the backend
service.
The `webserver` service, based on `Caddy.Dockerfile`, copies the static frontend
and `Caddyfile` into the container to configure the reverse proxy routes that will
forward requests to the backend service. Caddy will automatically provision TLS
for localhost or the domain specified in the environment variable `DOMAIN`.
This type of deployment should use less memory and be more performant since
nodejs is not required at runtime.
## Customize `Caddyfile` (optional)
If the app uses additional backend API routes, those should be added to the
`@backend_routes` path matcher to ensure they are forwarded to the backend.
## Build Reflex Production Service
During build, set `DOMAIN` environment variable to the domain where the app will
be hosted! (Do not include http or https, it will always use https).
**If `DOMAIN` is not provided, the service will default to `localhost`.**
```bash
DOMAIN=example.com docker compose build
```
This will build both the `app` service from the `prod.Dockerfile` and the `webserver`
service via `Caddy.Dockerfile`.
## Run Reflex Production Service
```bash
DOMAIN=example.com docker compose up
```
The app should be available at the specified domain via HTTPS. Certificate
provisioning will occur automatically and may take a few minutes.
### Data Persistence
Named docker volumes are used to persist the app database (`db-data`),
uploaded_files (`upload-data`), and caddy TLS keys and certificates
(`caddy-data`).
## More Robust Deployment
For a more robust deployment, consider bringing the service up with
`compose.prod.yaml` which includes postgres database and redis cache, allowing
the backend to run with multiple workers and service more requests.
```bash
DOMAIN=example.com docker compose -f compose.yaml -f compose.prod.yaml up -d
```
Postgres uses its own named docker volume for data persistence.
## Admin Tools
When needed, the services in `compose.tools.yaml` can be brought up, providing
graphical database administration (Adminer on http://localhost:8080) and a
redis cache browser (redis-commander on http://localhost:8081). It is not recommended
to deploy these services if they are not in active use.
```bash
DOMAIN=example.com docker compose -f compose.yaml -f compose.prod.yaml -f compose.tools.yaml up -d
```

View File

@ -12,7 +12,6 @@ services:
DB_URL: sqlite:///data/reflex.db
build:
context: .
dockerfile: prod.Dockerfile
volumes:
- db-data:/app/data
- upload-data:/app/uploaded_files

View File

@ -1 +0,0 @@
reflex

View File

@ -0,0 +1,5 @@
.web
.git
__pycache__/*
Dockerfile
uploaded_files

View File

@ -0,0 +1,14 @@
:{$PORT}
encode gzip
@backend_routes path /_event/* /ping /_upload /_upload/*
handle @backend_routes {
reverse_proxy localhost:8000
}
root * /srv
route {
try_files {path} {path}/ /404.html
file_server
}

View File

@ -10,31 +10,13 @@ FROM python:3.11
ARG PORT=8080
# Only set for local/direct access. When TLS is used, the API_URL is assumed to be the same as the frontend.
ARG API_URL
ENV PORT=$PORT API_URL=${API_URL:-http://localhost:$PORT}
ENV PORT=$PORT API_URL=${API_URL:-http://localhost:$PORT} REDIS_URL=redis://localhost PYTHONUNBUFFERED=1
# Install Caddy server inside image
RUN apt-get update -y && apt-get install -y caddy && rm -rf /var/lib/apt/lists/*
# Install Caddy and redis server inside image
RUN apt-get update -y && apt-get install -y caddy redis-server && rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Create a simple Caddyfile to serve as reverse proxy
RUN cat > Caddyfile <<EOF
:{\$PORT}
encode gzip
@backend_routes path /_event/* /ping /_upload /_upload/*
handle @backend_routes {
reverse_proxy localhost:8000
}
root * /srv
route {
try_files {path} {path}/ /404.html
file_server
}
EOF
# Copy local context to `/app` inside container (see .dockerignore)
COPY . .
@ -54,4 +36,6 @@ EXPOSE $PORT
# Apply migrations before starting the backend.
CMD [ -d alembic ] && reflex db migrate; \
caddy start && reflex run --env prod --backend-only --loglevel debug
caddy start && \
redis-server --daemonize yes && \
exec reflex run --env prod --backend-only

View File

@ -0,0 +1,36 @@
# simple-one-port
This docker deployment runs Reflex in prod mode, exposing a single HTTP port:
* `8080` (`$PORT`) - Caddy server hosting the frontend statically and proxying requests to the backend.
The deployment also runs a local Redis server to store state for each user.
Using this method may be preferable for deploying in memory constrained
environments, because it serves a static frontend export, rather than running
the NextJS server via node.
For platforms which only terminate TLS to a single port, this container can be
deployed instead of the `simple-two-port` example.
## Build
```console
docker build -t reflex-simple-one-port .
```
## Run
```console
docker run -p 8080:8080 reflex-simple-one-port
```
Note that this container has _no persistence_ and will lose all data when
stopped. You can use bind mounts or named volumes to persist the database and
uploaded_files directories as needed.
## Usage
This container should be used with an existing load balancer or reverse proxy to
terminate TLS.
It is also useful for deploying to simple app platforms, such as Render or Heroku.

View File

@ -0,0 +1,5 @@
.web
.git
__pycache__/*
Dockerfile
uploaded_files

View File

@ -1,5 +1,8 @@
# This Dockerfile is used to deploy a simple single-container Reflex app instance.
FROM python:3.11
FROM python:3.12
RUN apt-get update && apt-get install -y redis-server && rm -rf /var/lib/apt/lists/*
ENV REDIS_URL=redis://localhost PYTHONUNBUFFERED=1
# Copy local context to `/app` inside container (see .dockerignore)
WORKDIR /app
@ -18,4 +21,6 @@ RUN reflex export --frontend-only --no-zip
STOPSIGNAL SIGKILL
# Always apply migrations before starting the backend.
CMD [ -d alembic ] && reflex db migrate; reflex run --env prod
CMD [ -d alembic ] && reflex db migrate; \
redis-server --daemonize yes && \
exec reflex run --env prod

View File

@ -0,0 +1,44 @@
# simple-two-port
This docker deployment runs Reflex in prod mode, exposing two HTTP ports:
* `3000` - node NextJS server using optimized production build
* `8000` - python gunicorn server hosting the Reflex backend
The deployment also runs a local Redis server to store state for each user.
## Build
```console
docker build -t reflex-simple-two-port .
```
## Run
```console
docker run -p 3000:3000 -p 8000:8000 reflex-simple-two-port
```
Note that this container has _no persistence_ and will lose all data when
stopped. You can use bind mounts or named volumes to persist the database and
uploaded_files directories as needed.
## Usage
This container should be used with an existing load balancer or reverse proxy to
route traffic to the appropriate port inside the container.
For example, the following Caddyfile can be used to terminate TLS and forward
traffic to the frontend and backend from outside the container.
```
my-domain.com
encode gzip
@backend_routes path /_event/* /ping /_upload /_upload/*
handle @backend_routes {
reverse_proxy localhost:8000
}
reverse_proxy localhost:3000
```

261
docs/de/README.md Normal file
View File

@ -0,0 +1,261 @@
```diff
+ Suchst du nach Pynecone? Dann bist du hier in der richtigen Repository. Pynecone wurde in Reflex umbenannt. +
```
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_dark.svg#gh-light-mode-only" alt="Reflex Logo" width="300px">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_light.svg#gh-dark-mode-only" alt="Reflex Logo" width="300px">
<hr>
### **✨ Performante, anpassbare Web-Apps in purem Python. Bereitstellung in Sekunden. ✨**
[![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![versions](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentation](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
</div>
---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md)
---
# Reflex
Reflex ist eine Bibliothek, mit der man Full-Stack-Web-Applikationen in purem Python erstellen kann.
Wesentliche Merkmale:
* **Pures Python** - Schreibe dein Front- und Backend in Python, es gibt also keinen Grund, JavaScript zu lernen.
* **Volle Flexibilität** - Reflex ist einfach zu handhaben, kann aber auch für komplexe Anwendungen skaliert werden.
* **Sofortige Bereitstellung** - Nach dem Erstellen kannst du deine App mit einem [einzigen Befehl](https://reflex.dev/docs/hosting/deploy-quick-start/) bereitstellen oder auf deinem eigenen Server hosten.
Auf unserer [Architektur-Seite](https://reflex.dev/blog/2024-03-21-reflex-architecture/#the-reflex-architecture) erfahren Sie, wie Reflex unter der Haube funktioniert.
## ⚙️ Installation
Öffne ein Terminal und führe den folgenden Befehl aus (benötigt Python 3.9+):
```bash
pip install reflex
```
## 🥳 Erstelle deine erste App
Die Installation von `reflex` installiert auch das `reflex`-Kommandozeilen-Tool.
Teste, ob die Installation erfolgreich war, indem du ein neues Projekt erstellst. (Ersetze `my_app_name` durch deinen Projektnamen):
```bash
mkdir my_app_name
cd my_app_name
reflex init
```
Dieser Befehl initialisiert eine Vorlage in deinem neuen Verzeichnis.
Du kannst diese App im Entwicklungsmodus ausführen:
```bash
reflex run
```
Du solltest deine App unter http://localhost:3000 laufen sehen.
Nun kannst du den Quellcode in `my_app_name/my_app_name.py` ändern. Reflex hat schnelle Aktualisierungen, sodass du deine Änderungen sofort siehst, wenn du deinen Code speicherst.
## 🫧 Beispiel-App
Lass uns ein Beispiel durchgehen: die Erstellung einer Benutzeroberfläche für die Bildgenerierung mit [DALL·E](https://platform.openai.com/docs/guides/images/image-generation?context=node). Zur Vereinfachung rufen wir einfach die [OpenAI-API](https://platform.openai.com/docs/api-reference/authentication) auf, aber du könntest dies auch durch ein lokal ausgeführtes ML-Modell ersetzen.
&nbsp;
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/dalle.gif" alt="Eine Benutzeroberfläche für DALL·E, die im Prozess der Bildgenerierung gezeigt wird." width="550" />
</div>
&nbsp;
Hier ist der komplette Code, um dies zu erstellen. Das alles wird in einer Python-Datei gemacht!
```python
import reflex as rx
import openai
openai_client = openai.OpenAI()
class State(rx.State):
"""Der Zustand der App."""
prompt = ""
image_url = ""
processing = False
complete = False
def get_image(self):
"""Hole das Bild aus dem Prompt."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
def index():
return rx.center(
rx.vstack(
rx.heading("DALL-E", font_size="1.5em"),
rx.input(
placeholder="Enter a prompt..",
on_blur=State.set_prompt,
width="25em",
),
rx.button(
"Generate Image",
on_click=State.get_image,
width="25em",
loading=State.processing
),
rx.cond(
State.complete,
rx.image(src=State.image_url, width="20em"),
),
align="center",
),
width="100%",
height="100vh",
)
# Füge Zustand und Seite zur App hinzu.
app = rx.App()
app.add_page(index, title="Reflex:DALL-E")
```
## Schauen wir uns das mal genauer an.
<div align="center">
<img src="docs/images/dalle_colored_code_example.png" alt="Erläuterung der Unterschiede zwischen Backend- und Frontend-Teilen der DALL-E-App." width="900" />
</div>
### **Reflex-UI**
Fangen wir mit der Benutzeroberfläche an.
```python
def index():
return rx.center(
...
)
```
Diese `index`-Funktion definiert das Frontend der App.
Wir verwenden verschiedene Komponenten wie `center`, `vstack`, `input` und `button`, um das Frontend zu erstellen. Komponenten können ineinander verschachtelt werden, um komplexe Layouts zu erstellen. Und du kannst Schlüsselwortargumente verwenden, um sie mit der vollen Kraft von CSS zu stylen.
Reflex wird mit [über 60 eingebauten Komponenten](https://reflex.dev/docs/library) geliefert, die dir den Einstieg erleichtern. Wir fügen aktiv weitere Komponenten hinzu, und es ist einfach, [eigene Komponenten zu erstellen](https://reflex.dev/docs/wrapping-react/overview/).
### **State**
Reflex stellt deine Benutzeroberfläche als Funktion deines Zustands dar.
```python
class State(rx.State):
"""Der Zustand der App."""
prompt = ""
image_url = ""
processing = False
complete = False
```
Der Zustand definiert alle Variablen (genannt Vars) in einer App, die sich ändern können, und die Funktionen, die sie ändern.
Hier besteht der Zustand aus einem `prompt` und einer `image_url`. Es gibt auch die Booleans `processing` und `complete`, um anzuzeigen, wann der Button deaktiviert werden soll (während der Bildgenerierung) und wann das resultierende Bild angezeigt werden soll.
### **Event-Handler**
```python
def get_image(self):
"""Hole das Bild aus dem Prompt."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
```
Innerhalb des Zustands definieren wir Funktionen, die als Event-Handler bezeichnet werden und die Zustand-Variablen ändern. Event-Handler sind die Art und Weise, wie wir den Zustand in Reflex ändern können. Sie können als Reaktion auf Benutzeraktionen aufgerufen werden, z.B. beim Klicken auf eine Schaltfläche oder bei der Eingabe in ein Textfeld. Diese Aktionen werden als Ereignisse bezeichnet.
Unsere DALL-E.-App hat einen Event-Handler, `get_image`, der dieses Bild von der OpenAI-API abruft. Die Verwendung von `yield` in der Mitte eines Event-Handlers führt zu einer Aktualisierung der Benutzeroberfläche. Andernfalls wird die Benutzeroberfläche am Ende des Ereignishandlers aktualisiert.
### **Routing**
Schließlich definieren wir unsere App.
```python
app = rx.App()
```
Wir fügen der Indexkomponente eine Seite aus dem Stammverzeichnis der Anwendung hinzu. Wir fügen auch einen Titel hinzu, der in der Seitenvorschau/Browser-Registerkarte angezeigt wird.
```python
app.add_page(index, title="DALL-E")
```
Du kannst eine mehrseitige App erstellen, indem du weitere Seiten hinzufügst.
## 📑 Ressourcen
<div align="center">
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Komponentenbibliothek](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Galerie](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [Bereitstellung](https://reflex.dev/docs/hosting/deploy-quick-start) &nbsp;
</div>
## ✅ Status
Reflex wurde im Dezember 2022 unter dem Namen Pynecone gestartet.
Ab Februar 2024 befindet sich unser Hosting-Service in der Alpha-Phase! In dieser Zeit kann jeder seine Apps kostenlos bereitstellen. Siehe unsere [Roadmap](https://github.com/reflex-dev/reflex/issues/2727), um zu sehen, was geplant ist.
Reflex hat wöchentliche Veröffentlichungen und neue Features! Stelle sicher, dass du dieses Repository mit einem :star: Stern markierst und :eyes: beobachtest, um auf dem Laufenden zu bleiben.
## Beitragende
Wir begrüßen Beiträge jeder Größe! Hier sind einige gute Möglichkeiten, um in der Reflex-Community zu starten.
- **Tritt unserem Discord bei**: Unser [Discord](https://discord.gg/T5WSbC2YtQ) ist der beste Ort, um Hilfe für dein Reflex-Projekt zu bekommen und zu besprechen, wie du beitragen kannst.
- **GitHub-Diskussionen**: Eine großartige Möglichkeit, über Funktionen zu sprechen, die du hinzugefügt haben möchtest oder Dinge, die verwirrend sind/geklärt werden müssen.
- **GitHub-Issues**: [Issues](https://github.com/reflex-dev/reflex/issues) sind eine ausgezeichnete Möglichkeit, Bugs zu melden. Außerdem kannst du versuchen, ein bestehendes Problem zu lösen und eine PR einzureichen.
Wir suchen aktiv nach Mitwirkenden, unabhängig von deinem Erfahrungslevel oder deiner Erfahrung. Um beizutragen, sieh dir [CONTRIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md) an.
## Vielen Dank an unsere Mitwirkenden:
<a href="https://github.com/reflex-dev/reflex/graphs/contributors">
<img src="https://contrib.rocks/image?repo=reflex-dev/reflex" />
</a>
## Lizenz
Reflex ist Open-Source und lizenziert unter der [Apache License 2.0](LICENSE).

View File

@ -1,5 +1,5 @@
```diff
+ ¿Buscando Pynecone? Estas en el repositorio correcto. Pynecone ha sido renomabrado a Reflex. +
+ ¿Buscando Pynecone? Estás en el repositorio correcto. Pynecone ha sido renombrado a Reflex. +
```
<div align="center">
@ -8,28 +8,42 @@
<hr>
### **✨ Aplicaciones web personalizables y eficaces en Python puro. Despliega tú aplicación en segundos. ✨**
### **✨ Aplicaciones web personalizables y eficaces en Python puro. Despliega tu aplicación en segundos. ✨**
[![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![tests](https://github.com/pynecone-io/pynecone/actions/workflows/integration.yml/badge.svg)
![versions](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentaiton](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
![Pruebas](https://github.com/pynecone-io/pynecone/actions/workflows/integration.yml/badge.svg)
![Versiones](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentación](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
</div>
---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md)
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md)
---
# Reflex
Reflex es una biblioteca para construir aplicaciones web full-stack en Python puro.
Características clave:
* **Python puro** - Escribe el frontend y backend de tu aplicación en Python, sin necesidad de aprender JavaScript.
* **Flexibilidad total** - Reflex es fácil para empezar, pero también puede escalar a aplicaciones complejas.
* **Despliegue instantáneo** - Después de construir, despliega tu aplicación con un [solo comando](https://reflex.dev/docs/hosting/deploy-quick-start/) u hospédala en tu propio servidor.
Consulta nuestra [página de arquitectura](https://reflex.dev/blog/2024-03-21-reflex-architecture/#the-reflex-architecture) para aprender cómo funciona Reflex en detalle.
## ⚙️ Instalación
Abra un terminal y ejecute (Requiere Python 3.7+):
Abra un terminal y ejecute (Requiere Python 3.9+):
```bash
pip install reflex
```
## 🥳 Crea tú primera aplicación
## 🥳 Crea tu primera aplicación
Al instalar `reflex` tambien se instala la herramienta de línea de comandos `reflex`.
Al instalar `reflex` también se instala la herramienta de línea de comandos `reflex`.
Compruebe que la instalación se ha realizado correctamente creando un nuevo proyecto. (Sustituye `my_app_name` por el nombre de tu proyecto):
@ -39,7 +53,7 @@ cd my_app_name
reflex init
```
Este comando inicializa una aplicación de ejemplo (plantilla) en tu nuevo directorio.
Este comando inicializa una plantilla en tu nuevo directorio.
Puedes iniciar esta aplicación en modo de desarrollo:
@ -54,12 +68,12 @@ Ahora puede modificar el código fuente en `my_app_name/my_app_name.py`. Reflex
## 🫧 Ejemplo de una Aplicación
Veamos un ejemplo: crearemos una UI de generación de imágenes en torno a DALL-E. Para simplificar, solo llamamos a la API de OpenAI, pero podrías reeemplazar esto con un modelo ML ejecutado localmente.
Veamos un ejemplo: crearemos una UI de generación de imágenes en torno a [DALL·E](https://platform.openai.com/docs/guides/images/image-generation?context=node). Para simplificar, solo llamamos a la [API de OpenAI](https://platform.openai.com/docs/api-reference/authentication), pero podrías reemplazar esto con un modelo ML ejecutado localmente.
&nbsp;
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/dalle.gif" alt="A frontend wrapper for DALL·E, shown in the process of generating an image." width="550" />
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/dalle.gif" alt="Un envoltorio frontend para DALL·E, mostrado en el proceso de generar una imagen." width="550" />
</div>
&nbsp;
@ -70,61 +84,65 @@ Aquí está el código completo para crear esto. ¡Todo esto se hace en un archi
import reflex as rx
import openai
openai.api_key = "YOUR_API_KEY"
openai_client = openai.OpenAI()
class State(rx.State):
"""The app state."""
"""El estado de la aplicación"""
prompt = ""
image_url = ""
processing = False
complete = False
def get_image(self):
"""Get the image from the prompt."""
"""Obtiene la imagen desde la consulta."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai.Image.create(prompt=self.prompt, n=1, size="1024x1024")
self.image_url = response["data"][0]["url"]
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
def index():
return rx.center(
rx.vstack(
rx.heading("DALL·E"),
rx.input(placeholder="Enter a prompt", on_blur=State.set_prompt),
rx.heading("DALL-E", font_size="1.5em"),
rx.input(
placeholder="Enter a prompt..",
on_blur=State.set_prompt,
width="25em",
),
rx.button(
"Generate Image",
"Generate Image",
on_click=State.get_image,
is_loading=State.processing,
width="100%",
width="25em",
loading=State.processing
),
rx.cond(
State.complete,
rx.image(
src=State.image_url,
height="25em",
width="25em",
)
rx.image(src=State.image_url, width="20em"),
),
padding="2em",
shadow="lg",
border_radius="lg",
align="center",
),
width="100%",
height="100vh",
)
# Add state and page to the app.
# Agrega el estado y la pagina a la aplicación
app = rx.App()
app.add_page(index, title="reflex:DALL·E")
app.add_page(index, title="Reflex:DALL-E")
```
## Vamos a analizarlo.
<div align="center">
<img src="https://github.com/reflex-dev/reflex/blob/main/docs/images/dalle_colored_code_example.png?raw=true" alt="Explicando las diferencias entre las partes del backend y frontend de la aplicación DALL-E." width="900" />
</div>
### **Reflex UI**
Empezemos por la interfaz de usuario (UI).
@ -138,17 +156,17 @@ def index():
Esta función `index` define el frontend de la aplicación.
Utilizamos diferentes componentes como `center`, `vstack`, `input`, y `button` para construir el frontend. Los componentes pueden anidarse unos dentro de otros para crear diseños complejos. Además, puedes usar argumentos (keyword args) para darles estilo con toda la potencia de CSS.
Utilizamos diferentes componentes como `center`, `vstack`, `input`, y `button` para construir el frontend. Los componentes pueden anidarse unos dentro de otros para crear diseños complejos. Además, puedes usar argumentos de tipo keyword para darles estilo con toda la potencia de CSS.
Reflex viene con [mas de 60+ componentes incorporados](https://reflex.dev/docs/library) para ayudarle a empezar. Estamos añadiendo activamente más componentes y es fácil [crear sus propios componentes](https://reflex.dev/docs/advanced-guide/wrapping-react).
Reflex viene con [mas de 60 componentes incorporados](https://reflex.dev/docs/library) para ayudarle a empezar. Estamos añadiendo activamente más componentes y es fácil [crear sus propios componentes](https://reflex.dev/docs/wrapping-react/overview/).
### **State**
### **Estado**
Reflex representa su UI en función de su estado (State).
Reflex representa su UI como una función de su estado (State).
```python
class State(rx.State):
"""The app state."""
"""El estado de la aplicación"""
prompt = ""
image_url = ""
processing = False
@ -157,28 +175,30 @@ class State(rx.State):
El estado (State) define todas las variables (llamadas vars) de una aplicación que pueden cambiar y las funciones que las modifican.
Aquí el estado (State) se compone de `prompt` e `image_url`. También están los booleanos `processing` y `complete` para poder indicar cuándo mostrar el progreso circular y la imagen.
Aquí el estado se compone de `prompt` e `image_url`. También están los booleanos `processing` y `complete` para indicar cuando se deshabilite el botón (durante la generación de la imagen) y cuando se muestre la imagen resultante.
### **Event Handlers**
### **Manejadores de Evento**
```python
def get_image(self):
"""Get the image from the prompt."""
"""Obtiene la imagen desde la consulta."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai.Image.create(prompt=self.prompt, n=1, size="1024x1024")
self.image_url = response["data"][0]["url"]
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
```
Dentro del estado (State), definimos funciones llamadas "event handlers" que cambian los 'state vars'. Event handlers, son la manera que podemos modificar el 'state' en Reflex. Pueden ser activados en respuesta a las acciones del usuario, como hacer clic en un botón o escribir en un cuadro de texto. Estas acciones se llaman eventos 'events'.
Dentro del estado, definimos funciones llamadas manejadores de eventos que cambian las variables de estado. Los Manejadores de Evento son la manera que podemos modificar el estado en Reflex. Pueden ser activados en respuesta a las acciones del usuario, como hacer clic en un botón o escribir en un cuadro de texto. Estas acciones se llaman eventos.
Nuestra aplicación DALL·E. tiene un controlador de eventos "event handler", `get_image` que recibe esta imagen del OpenAI API. El uso de `yield` en medio de un controlador de eventos "event handler" hará que la UI se actualice. De lo contrario, la interfaz se actualizará al final del controlador de eventos "event handler".
Nuestra aplicación DALL·E tiene un manipulador de eventos, `get_image` que recibe esta imagen del OpenAI API. El uso de `yield` en medio de un manipulador de eventos hará que la UI se actualice. De lo contrario, la interfaz se actualizará al final del manejador de eventos.
### **Routing**
### **Enrutamiento**
Por último, definimos nuestra app.
@ -198,36 +218,28 @@ Puedes crear una aplicación multipágina añadiendo más páginas.
<div align="center">
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Biblioteca de Componentes](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Galería](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [Hospedaje](https://reflex.dev/docs/hosting/deploy) &nbsp;
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Librería de componentes](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Galería](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [Despliegue](https://reflex.dev/docs/hosting/deploy-quick-start) &nbsp;
</div>
## ✅ Estado
Reflex se lanzó en diciembre de 2022 con el nombre de Pynecone.
¡Desde febrero de 2024, nuestro servicio de alojamiento está en fase alfa! Durante este tiempo, cualquiera puede implementar sus aplicaciones de forma gratuita. Consulta nuestra [hoja de ruta](https://github.com/reflex-dev/reflex/issues/2727) para ver qué está planeado.
## ✅ Estatus
¡Reflex tiene nuevas versiones y características cada semana! Asegúrate de :star: marcar como favorito y :eyes: seguir este repositorio para mantenerte actualizado.
Reflex se lanzó en Diciembre de 2022 con el nombre Pynecone.
A partir de julio de 2023, nos encontramos en la etapa de **Beta Pública**.
- :white_check_mark: **Alpha Pública**: Cualquier persona puede instalar y usar Reflex. Puede haber problemas, pero estamos trabajando activamente para resolverlos.
- :large_orange_diamond: **Beta Pública**: Suficientemente estable para casos de uso no empresariales.
- **Beta de Hospedaje Público**: ¡_Opcionalmente_, despliega y hospeda tus aplicaciónes en Reflex!
- **Público**: Reflex está listo para producción.
¡Reflex tiene nuevas versiones y características que se lanzan cada semana! Aseguraté de darnos una :star: estrella y :eyes: revisa este repositorio para mantenerte actualizado.
## Contribuyendo
## Contribuciones
¡Aceptamos contribuciones de cualquier tamaño! A continuación encontrará algunas buenas formas de iniciarse en la comunidad Reflex.
- **Únete a nuestro Discord**: Nuestro [Discord](https://discord.gg/T5WSbC2YtQ) es el mejor lugar para obtener ayuda en su proyecto Reflex y discutir cómo puedes contribuir.
- **Discusiones de GitHub**: Una excelente manera de hablar sobre las características que deseas agregar o las cosas que te resusltan confusas o necesitan aclaración.
- **GitHub Issues**: Las incidencias son una forma excelente de informar de errores. Además, puedes intentar resolver un problema exixtente y enviar un PR.
- **Discusiones de GitHub**: Una excelente manera de hablar sobre las características que deseas agregar o las cosas que te resultan confusas o necesitan aclaración.
- **GitHub Issues**: Las incidencias son una forma excelente de informar de errores. Además, puedes intentar resolver un problema existente y enviar un PR.
Buscamos colaboradores, sin importar su nivel o experiencia.
Buscamos colaboradores, sin importar su nivel o experiencia. Para contribuir consulta [CONTIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md)
## Licencia

Binary file not shown.

Before

Width:  |  Height:  |  Size: 455 KiB

After

Width:  |  Height:  |  Size: 370 KiB

View File

@ -1,37 +1,51 @@
```diff
Pynecone की तलाश हैं? आप सही रेपो में हैं। Pynecone का नाम Reflex में बदल दिया गया है। + +
```
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_dark.svg#gh-light-mode-only" alt="Reflex Logo" width="300px">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_light.svg#gh-dark-mode-only" alt="Reflex Logo" width="300px">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_dark.svg#gh-light-mode-only" alt="Reflex लोगो" width="300px">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_light.svg#gh-dark-mode-only" alt="Reflex लोगो" width="300px">
<hr>
### **✨ Python (पायथन) में परफॉर्मेंट, अनुकूलनयोग्य वेब ऐप्स। कुछ सेकंड्स में ही डिप्लॉय करें ✨**
### **✨ प्रदर्शनकारी, अनुकूलित वेब ऐप्स, शुद्ध Python में। सेकंडों में तैनात करें। ✨**
[![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![tests](https://github.com/pynecone-io/pynecone/actions/workflows/integration.yml/badge.svg)
![versions](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentaiton](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
</div>
---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md)
---
## ⚙️ इंस्टॉलेशन
## [English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md)
एक टर्मिनल खोलें और चलाएं (Python 3.8+ की आवश्यकता है):
# Reflex
Reflex शुद्ध पायथन में पूर्ण-स्टैक वेब ऐप्स बनाने के लिए एक लाइब्रेरी है।
मुख्य विशेषताएँ:
- **शुद्ध पायथन** - अपने ऐप के फ्रंटएंड और बैकएंड को पायथन में लिखें, जावास्क्रिप्ट सीखने की जरूरत नहीं है।
- **पूर्ण लचीलापन** - Reflex के साथ शुरुआत करना आसान है, लेकिन यह जटिल ऐप्स के लिए भी स्केल कर सकता है।
- **तुरंत तैनाती** - बिल्डिंग के बाद, अपने ऐप को [एकल कमांड](https://reflex.dev/docs/hosting/deploy-quick-start/) के साथ तैनात करें या इसे अपने सर्वर पर होस्ट करें।
Reflex के अंदर के कामकाज को जानने के लिए हमारे [आर्किटेक्चर पेज](https://reflex.dev/blog/2024-03-21-reflex-architecture/#the-reflex-architecture) को देखें।
## ⚙️ इंस्टॉलेशन (Installation)
एक टर्मिनल खोलें और चलाएं (Python 3.9+ की आवश्यकता है):
```bash
pip install reflex
```
## 🥳 अपना पहला ऐप बनाएं
## 🥳 अपना पहला ऐप बनाएं (Create your first App)
reflex को इंस्टॉल करने से ही reflex कमांड लाइन टूल भी इंस्टॉल हो जाता है।
सुनिश्चित करें कि इंस्टॉलेशन सफल थी, एक नया प्रोजेक्ट बनाकर इसे टेस्ट करें। ('my_app_name' की जगह अपने प्रोजेक्ट का नाम रखें):
सुनिश्चित करें कि इंस्टॉलेशन सफल थी, एक नया प्रोजेक्ट बनाकर इसे टेस्ट करें। ('my_app_name' की जगह अपने प्रोजेक्ट का नाम रखें):
```bash
mkdir my_app_name
@ -51,14 +65,14 @@ reflex run
अब आप my_app_name/my_app_name.py में source कोड को संशोधित कर सकते हैं। Reflex में तेज रिफ्रेश की सुविधा है, इसलिए जब आप अपनी कोड को सहेजते हैं, तो आप अपने बदलावों को तुरंत देख सकते हैं।
## 🫧 उदाहरण ऐप
## 🫧 उदाहरण ऐप (Example App)
एक उदाहरण पर चलते हैं: DALL·E से एक इमेज उत्पन्न करने के लिए UI। सरलता के लिए, हम सिर्फ OpenAI API को बुलाते हैं, लेकिन आप इसे ML मॉडल से बदल सकते हैं locally।
&nbsp;
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/dalle.gif" alt="A frontend wrapper for DALL·E, shown in the process of generating an image." width="550" />
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/dalle.gif" alt="DALL·E के लिए एक फ्रंटएंड रैपर, छवि उत्पन्न करने की प्रक्रिया में दिखाया गया।" width="550" />
</div>
&nbsp;
@ -69,10 +83,12 @@ reflex run
import reflex as rx
import openai
openai.api_key = "YOUR_API_KEY"
openai_client = openai.OpenAI()
class State(rx.State):
"""The app state."""
prompt = ""
image_url = ""
processing = False
@ -85,33 +101,33 @@ class State(rx.State):
self.processing, self.complete = True, False
yield
response = openai.Image.create(prompt=self.prompt, n=1, size="1024x1024")
self.image_url = response["data"][0]["url"]
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
def index():
return rx.center(
rx.vstack(
rx.heading("DALL·E"),
rx.input(placeholder="Enter a prompt", on_blur=State.set_prompt),
rx.heading("DALL-E", font_size="1.5em"),
rx.input(
placeholder="Enter a prompt..",
on_blur=State.set_prompt,
width="25em",
),
rx.button(
"Generate Image",
on_click=State.get_image,
is_loading=State.processing,
width="100%",
width="25em",
loading=State.processing
),
rx.cond(
State.complete,
rx.image(
src=State.image_url,
height="25em",
width="25em",
)
rx.image(src=State.image_url, width="20em"),
),
padding="2em",
shadow="lg",
border_radius="lg",
align="center",
),
width="100%",
height="100vh",
@ -119,10 +135,14 @@ def index():
# Add state and page to the app.
app = rx.App()
app.add_page(index, title="reflex:DALL·E")
app.add_page(index, title="Reflex:DALL-E")
```
## चलो इसे विस्तार से देखते हैं।
## इसे समझते हैं।
<div align="center">
<img src="https://github.com/reflex-dev/reflex/blob/main/docs/images/dalle_colored_code_example.png?raw=true" alt="DALL-E ऐप के बैकएंड और फ्रंटएंड भागों के बीच के अंतर की व्याख्या करता है।" width="900" />
</div>
### **Reflex UI**
@ -156,7 +176,7 @@ class State(rx.State):
स्टेट (state) ऐप में उन सभी वेरिएबल्स (vars) को परिभाषित करती है जो बदल सकती हैं और उन फ़ंक्शनों को जो उन्हें बदलते हैं।
यहां स्टेट (state) में `prompt` और `image_url` शामिल हैं। प्रगति और छवि दिखाने के लिए `processing` और `complete` बूलियन भी हैं।
यहां स्टेट (state) में `prompt` और `image_url` शामिल हैं। प्रगति और छवि दिखाने के लिए `processing` और `complete` बूलियन भी हैं।
### **इवेंट हैंडलर (Event Handlers)**
@ -168,8 +188,10 @@ def get_image(self):
self.processing, self.complete = True, False
yield
response = openai.Image.create(prompt=self.prompt, n=1, size="1024x1024")
self.image_url = response["data"][0]["url"]
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
```
@ -197,33 +219,34 @@ app.add_page(index, title="DALL-E")
<div align="center">
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Component Library](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Gallery](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy) &nbsp;
📑 [दस्तावेज़](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [ब्लॉग](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [कॉम्पोनेंट लाइब्रेरी](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [गैलरी](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [तैनाती](https://reflex.dev/docs/hosting/deploy) &nbsp;
</div>
## ✅ स्टेटस (Status)
रिफ्लेक्स को दिसंबर 2022 में पाइनकोन नाम से लॉन्च किया गया
Reflex दिसंबर 2022 में Pynecone नाम से शुरू हुआ
जुलाई 2023 तक, हम **Public Beta** (सार्वजनिक बीटा) चरण में हैं
फरवरी 2024 तक, हमारी होस्टिंग सेवा अल्फा में है! इस समय कोई भी अपने ऐप्स को मुफ्त में तैनात कर सकता है। देखें हमारी [रोडमैप](https://github.com/reflex-dev/reflex/issues/2727) योजनाबद्ध चीज़ों को जानने के लिए
- :white_check_mark: **Public Alpha** (सार्वजनिक अल्फा): कोई भी रिफ्लेक्स इंस्टॉल और उपयोग कर सकता है। कुछ इशू हो सकते हैं, लेकिन हम उन्हें सुलझाने के लिए सक्रिय रूप से काम कर रहे हैं।
- :large_orange_diamond: **Public Beta** (सार्वजनिक बीटा): गैर-उद्यम उपयोग-मामलों के लिए स्थिर।
- **Public Hosting Beta** (सार्वजनिक होस्टिंग बीटा): _Optionally_, अपने ऐप्स को रिफ्लेक्स पर डिप्लॉइ और होस्ट करें!
- **Public** (सार्वजनिक): रिफ्लेक्स उत्पादन के लिए तैयार है।
रिफ्लेक्स में हर सप्ताह नई रिलीज़ और सुविधाएँ आ रही हैं! अपडेट रहने के लिए इस रिपॉजिटरी को :star: स्टार करें और समय-समय पर अवश्य देखें :eyes:।
Reflex में हर सप्ताह नए रिलीज़ और फीचर्स आ रहे हैं! सुनिश्चित करें कि ⭐ स्टार और 👀 वॉच इस रेपोजिटरी को अपडेट रहने के लिए।
## (योगदान) Contributing
हम हर तरह के योगदान का स्वागत करते हैं! रिफ्लेक्स कम्यूनिटी में शुरुआत करने के कुछ अच्छे तरीके नीचे दिए गए हैं।
- **Join Our Discord** (डिस्कॉर्ड सर्वर से जुड़ें): Our [Discord](https://discord.gg/T5WSbC2YtQ) हमारा डिस्कॉर्ड रिफ्लेक्स प्रोजेक्ट पर सहायता प्राप्त करने और आप कैसे योगदान दे सकते हैं, इस पर चर्चा करने के लिए सबसे अच्छी जगह है।
- **GitHub Discussions** (गिटहब चर्चाएँ): उन सुविधाओं के बारे में बात करने का एक शानदार तरीका जिन्हें आप जोड़ना चाहते हैं या ऐसी चीज़ें जो भ्रमित करने वाली हैं/स्पष्टीकरण की आवश्यकता है।
- **GitHub Issues** (गिटहब समस्याएं): ये बग की रिपोर्ट करने का एक शानदार तरीका है। इसके अतिरिक्त, आप किसी मौजूदा समस्या को हल करने का प्रयास कर सकते हैं और एक पीआर सबमिट कर सकते हैं।
- **Join Our Discord** (डिस्कॉर्ड सर्वर से जुड़ें): Our [Discord](https://discord.gg/T5WSbC2YtQ) हमारा डिस्कॉर्ड रिफ्लेक्स प्रोजेक्ट पर सहायता प्राप्त करने और आप कैसे योगदान दे सकते हैं, इस पर चर्चा करने के लिए सबसे अच्छी जगह है।
- **GitHub Discussions** (गिटहब चर्चाएँ): उन सुविधाओं के बारे में बात करने का एक शानदार तरीका जिन्हें आप जोड़ना चाहते हैं या ऐसी चीज़ें जो भ्रमित करने वाली हैं/स्पष्टीकरण की आवश्यकता है।
- **GitHub Issues** (गिटहब समस्याएं): ये [बग](https://github.com/reflex-dev/reflex/issues) की रिपोर्ट करने का एक शानदार तरीका है। इसके अतिरिक्त, आप किसी मौजूदा समस्या को हल करने का प्रयास कर सकते हैं और एक पीआर सबमिट कर सकते हैं।
हम सक्रिय रूप से योगदानकर्ताओं की तलाश कर रहे हैं, चाहे आपका कौशल स्तर या अनुभव कुछ भी हो।
हम सक्रिय रूप से योगदानकर्ताओं की तलाश कर रहे हैं, चाहे आपका कौशल स्तर या अनुभव कुछ भी हो।योगदान करने के लिए [CONTIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md) देखें।
## हमारे सभी योगदानकर्ताओं का धन्यवाद:
<a href="https://github.com/reflex-dev/reflex/graphs/contributors">
<img src="https://contrib.rocks/image?repo=reflex-dev/reflex" />
</a>
## लाइसेंस (License)
रिफ्लेक्स ओपन-सोर्स है और [अपाचे लाइसेंस 2.0] (लाइसेंस) के तहत लाइसेंस प्राप्त है।
रिफ्लेक्स ओपन-सोर्स है और [अपाचे लाइसेंस 2.0](https://github.com/reflex-dev/reflex/blob/main/LICENSE) के तहत लाइसेंस प्राप्त है।

View File

@ -10,7 +10,6 @@
### **✨ App web performanti e personalizzabili in puro Python. Distribuisci in pochi secondi. ✨**
[![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![tests](https://github.com/pynecone-io/pynecone/actions/workflows/integration.yml/badge.svg)
![versions](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentaiton](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
@ -18,12 +17,12 @@
---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) |
[Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md)
[Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md)
---
## ⚙️ Installazione
Apri un terminale ed esegui (Richiede Python 3.8+):
Apri un terminale ed esegui (Richiede Python 3.9+):
```bash
pip install reflex

View File

@ -8,34 +8,36 @@
<hr>
### **✨ 即時デプロイが可能な、Pure Pythonで作ったパフォーマンスと汎用性が高いWebアプリケーション✨**
### **✨ 即時デプロイが可能な、Pure Python で作ったパフォーマンスと汎用性が高い Web アプリケーション ✨**
[![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![tests](https://github.com/pynecone-io/pynecone/actions/workflows/integration.yml/badge.svg)
![versions](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentation](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
</div>
---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md)
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md)
---
# Reflex
ReflexはPythonのみでフルスタックWebアプリケーションを作成できるライブラリです。
Reflex Python のみでフルスタック Web アプリケーションを作成できるライブラリです。
主な特徴:
* **Pure Python** - WebアプリケーションのフロントエンドとバックエンドをPythonのみで実装できるため、Javascriptを学ぶ必要がありません。
* **高い柔軟性** - Reflexは簡単に始められて、複雑なアプリケーションまで作成できます。
* **即時デプロイ** - ビルド後、すぐにデプロイが可能です。[単純なCLIコマンド](https://reflex.dev/docs/hosting/deploy-quick-start/)を使ったアプリケーションのデプロイや、自身のサーバーへのホストができます。
Reflexがどのように動作しているかを知るには、[アーキテクチャページ](https://reflex.dev/blog/2024-03-21-reflex-architecture/#the-reflex-architecture)をご覧ください。
- **Pure Python** - Web アプリケーションのフロントエンドとバックエンドを Python のみで実装できるため、Javascript を学ぶ必要がありません。
- **高い柔軟性** - Reflex は簡単に始められて、複雑なアプリケーションまで作成できます。
- **即時デプロイ** - ビルド後、すぐにデプロイが可能です。[単純な CLI コマンド](https://reflex.dev/docs/hosting/deploy-quick-start/)を使ったアプリケーションのデプロイや、自身のサーバーへのホストができます。
Reflex がどのように動作しているかを知るには、[アーキテクチャページ](https://reflex.dev/blog/2024-03-21-reflex-architecture/#the-reflex-architecture)をご覧ください。
## ⚙️ インストール
ターミナルを開いて以下のコマンドを実行してください。Python 3.8以上が必要です。):
ターミナルを開いて以下のコマンドを実行してください。Python 3.9 以上が必要です。):
```bash
pip install reflex
@ -43,7 +45,7 @@ pip install reflex
## 🥳 最初のアプリケーションを作ろう
`reflex`をインストールすると、`reflex`のCLIツールが自動でインストールされます。
`reflex`をインストールすると、`reflex`の CLI ツールが自動でインストールされます。
新しいプロジェクトを作成して、インストールが成功しているかを確認しましょう。(`my_app_name`を自身のプロジェクト名に書き換えて実行ください。):
@ -63,11 +65,11 @@ reflex run
http://localhost:3000 にアクセスしてアプリの動作を見ることができます。
`my_app_name/my_app_name.py`のソースコードを編集してみましょうReflexはfast refreshなので、ソースを保存した直後に変更がWebページに反映されます。
`my_app_name/my_app_name.py`のソースコードを編集してみましょうReflex fast refresh なので、ソースを保存した直後に変更が Web ページに反映されます。
## 🫧 実装例
実装例を見てみましょう: [DALL·E](https://platform.openai.com/docs/guides/images/image-generation?context=node)を中心とした画像生成UIを作成しました。説明を簡単にするためにここでは[OpenAI API](https://platform.openai.com/docs/api-reference/authentication)を呼んでいますが、ローカルで動作している機械学習モデルに置き換えることも可能です。
実装例を見てみましょう: [DALL·E](https://platform.openai.com/docs/guides/images/image-generation?context=node)を中心とした画像生成 UI を作成しました。説明を簡単にするためにここでは[OpenAI API](https://platform.openai.com/docs/api-reference/authentication)を呼んでいますが、ローカルで動作している機械学習モデルに置き換えることも可能です。
&nbsp;
@ -77,7 +79,7 @@ http://localhost:3000 にアクセスしてアプリの動作を見ることが
&nbsp;
画像生成UIのソースコードの全貌を見てみましょう。下記のように、単一のPythonファイルで作れます
画像生成 UI のソースコードの全貌を見てみましょう。下記のように、単一の Python ファイルで作れます!
```python
import reflex as rx
@ -117,14 +119,15 @@ def index():
on_blur=State.set_prompt,
width="25em",
),
rx.button("Generate Image", on_click=State.get_image, width="25em"),
rx.button(
"Generate Image",
on_click=State.get_image,
width="25em",
loading=State.processing
),
rx.cond(
State.processing,
rx.chakra.circular_progress(is_indeterminate=True),
rx.cond(
State.complete,
rx.image(src=State.image_url, width="20em"),
),
State.complete,
rx.image(src=State.image_url, width="20em"),
),
align="center",
),
@ -137,17 +140,15 @@ app = rx.App()
app.add_page(index, title="Reflex:DALL-E")
```
## それぞれの実装を見てみましょう
<div align="center">
<img src="../../docs/images/dalle_colored_code_example.png" alt="DALL-E appのフロントエンドとバックエンドのパーツの違いを説明しています。" width="900" />
</div>
### **Reflex UI**
UIから見てみましょう。
UI から見てみましょう。
```python
def index():
@ -158,13 +159,13 @@ def index():
`index`関数において、アプリのフロントエンドを定義しています。
フロントエンドを実装するにあたり、`center`、`vstack`、`input`、`button`など異なるコンポーネントを使用しています。コンポーネントはお互いにネストが可能であり、複雑なレイアウトを作成できます。また、keyword argsを使うことで、CSSの機能をすべて使ったスタイルが可能です。
フロントエンドを実装するにあたり、`center`、`vstack`、`input`、`button`など異なるコンポーネントを使用しています。コンポーネントはお互いにネストが可能であり、複雑なレイアウトを作成できます。また、keyword args を使うことで、CSS の機能をすべて使ったスタイルが可能です。
Reflexは[60を超える内臓コンポーネント](https://reflex.dev/docs/library)があるため、すぐに始められます。私たちは、積極的にコンポーネントを追加していますが、簡単に[自身のコンポーネントを追加](https://reflex.dev/docs/wrapping-react/overview/)することも可能です。
Reflex は[60 を超える内臓コンポーネント](https://reflex.dev/docs/library)があるため、すぐに始められます。私たちは、積極的にコンポーネントを追加していますが、簡単に[自身のコンポーネントを追加](https://reflex.dev/docs/wrapping-react/overview/)することも可能です。
### **ステート**
Reflexはステートの関数を用いてUIを表示します。
Reflex はステートの関数を用いて UI を表示します。
```python
class State(rx.State):
@ -176,9 +177,9 @@ class State(rx.State):
```
ステートでは、アプリで変更が可能な全ての変数varsと呼びますと、varsの変更が可能な関数を定義します。
ステートでは、アプリで変更が可能な全ての変数vars と呼びますと、vars の変更が可能な関数を定義します。
この例では、ステートを`prompt`と`image_url`で構成しています。そして、ブール型の`processing`と`complete`を用いて、プログレスサークルと画像の表示を切り替えています。
この例では、ステートを`prompt`と`image_url`で構成しています。そして、ブール型の`processing`と`complete`を用いて、ボタンを無効にするタイミング(画像生成中)や生成された画像を表示するタイミングを示しています。
### **イベントハンドラ**
@ -197,9 +198,9 @@ def get_image(self):
self.processing, self.complete = False, True
```
ステートにおいて、ステートのvarsを変更できるイベントハンドラ関数を定義しています。イベントハンドラはReflexにおいて、ステートのvarsを変更する方法です。ボタンクリックやテキストボックスの入力など、ユーザのアクションに応じてイベントハンドラが呼ばれます。
ステートにおいて、ステートの vars を変更できるイベントハンドラ関数を定義しています。イベントハンドラは Reflex において、ステートの vars を変更する方法です。ボタンクリックやテキストボックスの入力など、ユーザのアクションに応じてイベントハンドラが呼ばれます。
DALL·E.アプリには、OpenAI APIからイメージを取得する`get_image`関数があります。イベントハンドラの最後でUIの更新がかかるため、関数の途中に`yield`を入れることで先にUIを更新しています。
DALL·E.アプリには、OpenAI API からイメージを取得する`get_image`関数があります。イベントハンドラの最後で UI の更新がかかるため、関数の途中に`yield`を入れることで先に UI を更新しています。
### **ルーティング**
@ -209,7 +210,7 @@ DALL·E.アプリには、OpenAI APIからイメージを取得する`get_image`
app = rx.App()
```
アプリにページを追加し、ドキュメントルートをindexコンポーネントにルーティングしています。更に、ページのプレビューやブラウザタブに表示されるタイトルを記載しています。
アプリにページを追加し、ドキュメントルートを index コンポーネントにルーティングしています。更に、ページのプレビューやブラウザタブに表示されるタイトルを記載しています。
```python
app.add_page(index, title="DALL-E")
@ -221,35 +222,34 @@ app.add_page(index, title="DALL-E")
<div align="center">
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Component Library](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Gallery](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy-quick-start) &nbsp;
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Component Library](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Gallery](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy-quick-start) &nbsp;
</div>
## ✅ ステータス
2022年12月に、ReflexはPyneconeという名前でローンチしました。
2022 12 月に、Reflex Pynecone という名前でローンチしました。
2024年2月に、ホスティングサービスをアルファ版でリリースしましたアルファ版では、だれでもReflexアプリケーションを無料でデプロイできます。今後の予定は[ロードマップ](https://github.com/reflex-dev/reflex/issues/2727)において見れます。
2024 2 月に、ホスティングサービスをアルファ版でリリースしました!アルファ版では、だれでも Reflex アプリケーションを無料でデプロイできます。今後の予定は[ロードマップ](https://github.com/reflex-dev/reflex/issues/2727)において見れます。
Reflexは毎週、新しいリリースや機能追加を行っています最新情報を逃さないために、 :star: Starや :eyes: Watchをお願いします。
Reflex は毎週、新しいリリースや機能追加を行っています!最新情報を逃さないために、 :star: Star や :eyes: Watch をお願いします。
## コントリビュート
様々なサイズのコントリビュートを歓迎していますReflexコミュニティに入るための方法を、いくつかリストアップします。
様々なサイズのコントリビュートを歓迎していますReflex コミュニティに入るための方法を、いくつかリストアップします。
- **Discordに参加**: [Discord](https://discord.gg/T5WSbC2YtQ)は、Reflexプロジェクトの相談や、コントリビュートについての話し合いをするための、最適な場所です。
- **GitHub Discussions**: GitHub Discussionsでは、追加したい機能や、複雑で解明が必要な事柄についての議論に適している場所です。
- **GitHub Issues**: [Issues](https://github.com/reflex-dev/reflex/issues)はバグの報告に適している場所です。また、課題を解決したPRのサブミットにチャレンジしていただくことも、可能です。
- **Discord に参加**: [Discord](https://discord.gg/T5WSbC2YtQ)は、Reflex プロジェクトの相談や、コントリビュートについての話し合いをするための、最適な場所です。
- **GitHub Discussions**: GitHub Discussions では、追加したい機能や、複雑で解明が必要な事柄についての議論に適している場所です。
- **GitHub Issues**: [Issues](https://github.com/reflex-dev/reflex/issues)はバグの報告に適している場所です。また、課題を解決した PR のサブミットにチャレンジしていただくことも、可能です。
スキルや経験に関わらず、私たちはコントリビュータを積極的に探しています。コントリビュートするために、[CONTIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md)をご覧ください。
## 私たちのコントリビュータに感謝!:
<a href="https://github.com/reflex-dev/reflex/graphs/contributors">
<img src="https://contrib.rocks/image?repo=reflex-dev/reflex" />
</a>
## ライセンス
Reflexはオープンソースであり、[Apache License 2.0](LICENSE)に基づいてライセンス供与されます。
Reflex はオープンソースであり、[Apache License 2.0](LICENSE)に基づいてライセンス供与されます。

View File

@ -10,18 +10,17 @@
### **✨ 순수 Python으로 고성능 사용자 정의 웹앱을 만들어 보세요. 몇 초만에 배포 가능합니다. ✨**
[![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![tests](https://github.com/pynecone-io/pynecone/actions/workflows/integration.yml/badge.svg)
![versions](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentaiton](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
</div>
---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md)
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md)
---
## ⚙️ 설치
터미널을 열고 실행하세요. (Python 3.8+ 필요):
터미널을 열고 실행하세요. (Python 3.9+ 필요):
```bash
pip install reflex
@ -70,10 +69,12 @@ http://localhost:3000 에서 앱이 실행 됩니다.
import reflex as rx
import openai
openai.api_key = "YOUR_API_KEY"
openai_client = openai.OpenAI()
class State(rx.State):
"""The app state."""
prompt = ""
image_url = ""
processing = False
@ -86,33 +87,33 @@ class State(rx.State):
self.processing, self.complete = True, False
yield
response = openai.Image.create(prompt=self.prompt, n=1, size="1024x1024")
self.image_url = response["data"][0]["url"]
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
def index():
return rx.center(
rx.vstack(
rx.heading("DALL·E"),
rx.input(placeholder="Enter a prompt", on_blur=State.set_prompt),
rx.heading("DALL-E", font_size="1.5em"),
rx.input(
placeholder="Enter a prompt..",
on_blur=State.set_prompt,
width="25em",
),
rx.button(
"Generate Image",
"Generate Image",
on_click=State.get_image,
is_loading=State.processing,
width="100%",
width="25em",
loading=State.processing
),
rx.cond(
State.complete,
rx.image(
src=State.image_url,
height="25em",
width="25em",
)
rx.image(src=State.image_url, width="20em"),
),
padding="2em",
shadow="lg",
border_radius="lg",
align="center",
),
width="100%",
height="100vh",
@ -120,7 +121,7 @@ def index():
# Add state and page to the app.
app = rx.App()
app.add_page(index, title="reflex:DALL·E")
app.add_page(index, title="Reflex:DALL-E")
```
## 하나씩 살펴보겠습니다.
@ -160,7 +161,7 @@ class State(rx.State):
state는 앱에서 변경될 수 있는 모든 변수(vars로 불림)와 이러한 변수를 변경하는 함수를 정의합니다.
여기서 state는 `prompt``image_url`로 구성됩니다. 또한 `processing``complete`라는 불리언 값이 있습니다. 이 값들은 원형 진행률과 이미지를 표시할 때를 나타냅니다.
여기서 state는 `prompt``image_url`로 구성됩니다. 또한 `processing``complete`라는 불리언 값이 있습니다. 이 값들은 이미지 생성 중 버튼을 비활성화할 때와, 결과 이미지를 표시할 때를 나타냅니다.
### **Event Handlers**
@ -172,8 +173,10 @@ def get_image(self):
self.processing, self.complete = True, False
yield
response = openai.Image.create(prompt=self.prompt, n=1, size="1024x1024")
self.image_url = response["data"][0]["url"]
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
```

262
docs/pe/README.md Normal file
View File

@ -0,0 +1,262 @@
```diff
+ دنبال Pynecone میگردی؟ شما در مخزن درستی قرار داری. Pynecone به Reflex تغییر نام داده است. +
```
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_dark.svg#gh-light-mode-only" alt="Reflex Logo" width="300px">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_light.svg#gh-dark-mode-only" alt="Reflex Logo" width="300px">
<hr>
### **✨ برنامه های تحت وب قابل تنظیم، کارآمد تماما پایتونی که در چند ثانیه مستقر(دپلوی) می‎شود. ✨**
[![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![versions](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentation](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
</div>
---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md)
---
# Reflex - رفلکس
رفلکس(Reflex) یک کتابخانه برای ساخت برنامه های وب فول استک تماما پایتونی است.
ویژگی های کلیدی:
* **تماما پایتونی** - فرانت اند و بک اند برنامه خود را همه در پایتون بنویسید، بدون نیاز به یادگیری جاوا اسکریپت.
* **انعطاف پذیری کامل** - شروع به کار با Reflex آسان است، اما می تواند به برنامه های پیچیده نیز تبدیل شود.
* **دپلوی فوری** - پس از ساخت، برنامه خود را با [یک دستور](https://reflex.dev/docs/hosting/deploy-quick-start/) دپلوی کنید یا آن را روی سرور خود میزبانی کنید.
برای آشنایی با نحوه عملکرد Reflex [صفحه معماری](https://reflex.dev/blog/2024-03-21-reflex-architecture/#the-reflex-architecture) را ببینید.
## ⚙️ Installation - نصب و راه اندازی
یک ترمینال را باز کنید و اجرا کنید (نیازمند Python 3.9+):
```bash
pip install reflex
```
## 🥳 اولین برنامه خود را ایجاد کنید
نصب `reflex` همچنین `reflex` در خط فرمان را نصب میکند.
با ایجاد یک پروژه جدید موفقیت آمیز بودن نصب را تست کنید. (`my_app_name` را با اسم پروژه خودتان جایگزین کنید):
```bash
mkdir my_app_name
cd my_app_name
reflex init
```
این دستور یک برنامه الگو(تمپلیت) را در فهرست(دایرکتوری) جدید شما مقداردهی اولیه می کند
می توانید این برنامه را در حالت توسعه(development) اجرا کنید:
```bash
reflex run
```
باید برنامه خود را در حال اجرا ببینید در http://localhost:3000.
اکنون می‌توانید کد منبع را در «my_app_name/my_app_name.py» تغییر دهید. Reflex دارای تازه‌سازی‌های سریعی است، بنابراین می‌توانید تغییرات خود را بلافاصله پس از ذخیره کد خود مشاهده کنید.
## 🫧 Example App - برنامه نمونه
بیایید یک مثال بزنیم: ایجاد یک رابط کاربری برای تولید تصویر [DALL·E](https://platform.openai.com/docs/guides/images/image-generation?context=node). برای سادگی، ما فراخوانی میکنیم [OpenAI API](https://platform.openai.com/docs/api-reference/authentication), اما می توانید آن را با یک مدل ML که به صورت محلی اجرا می شود جایگزین کنید.
&nbsp;
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/dalle.gif" alt="A frontend wrapper for DALL·E, shown in the process of generating an image." width="550" />
</div>
&nbsp;
در اینجا کد کامل برای ایجاد این پروژه آمده است. همه اینها در یک فایل پایتون انجام می شود!
```python
import reflex as rx
import openai
openai_client = openai.OpenAI()
class State(rx.State):
"""The app state."""
prompt = ""
image_url = ""
processing = False
complete = False
def get_image(self):
"""Get the image from the prompt."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
def index():
return rx.center(
rx.vstack(
rx.heading("DALL-E", font_size="1.5em"),
rx.input(
placeholder="Enter a prompt..",
on_blur=State.set_prompt,
width="25em",
),
rx.button(
"Generate Image",
on_click=State.get_image,
width="25em",
loading=State.processing
),
rx.cond(
State.complete,
rx.image(src=State.image_url, width="20em"),
),
align="center",
),
width="100%",
height="100vh",
)
# Add state and page to the app.
app = rx.App()
app.add_page(index, title="Reflex:DALL-E")
```
## بیاید سادش کنیم
<div align="center">
<img src="docs/images/dalle_colored_code_example.png" alt="Explaining the differences between backend and frontend parts of the DALL-E app." width="900" />
</div>
### **Reflex UI - رابط کاربری رفلکس**
بیایید با رابط کاربری شروع کنیم.
```python
def index():
return rx.center(
...
)
```
تابع `index` قسمت فرانت اند برنامه را تعریف می کند.
ما از اجزای مختلفی مثل `center`, `vstack`, `input` و `button` استفاده میکنیم تا فرانت اند را بسازیم. اجزاء را می توان درون یکدیگر قرار داد
برای ایجاد طرح بندی های پیچیده می توانید از args کلمات کلیدی برای استایل دادن به آنها از CSS استفاده کنید.
رفلکس دارای [بیش از 60 جزء](https://reflex.dev/docs/library) برای کمک به شما برای شروع. ما به طور فعال اجزای بیشتری را اضافه می کنیم, و این خیلی آسان است که [اجزا خود را بسازید](https://reflex.dev/docs/wrapping-react/overview/).
### **State - حالت**
رفلکس رابط کاربری شما را به عنوان تابعی از وضعیت شما نشان می دهد.
```python
class State(rx.State):
"""The app state."""
prompt = ""
image_url = ""
processing = False
complete = False
```
حالت تمام متغیرها(variables) (به نام vars) را در یک برنامه که می توانند تغییر دهند و توابعی که آنها را تغییر می دهند تعریف می کند..
در اینجا حالت از یک `prompt` و `image_url` تشکیل شده است. همچنین دو بولی `processing` و `complete` برای نشان دادن زمان غیرفعال کردن دکمه (در طول تولید تصویر) و زمان نمایش تصویر نتیجه وجود دارد.
### **Event Handlers - کنترل کنندگان رویداد**
```python
def get_image(self):
"""Get the image from the prompt."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
```
در داخل حالت، توابعی به نام کنترل کننده رویداد تعریف می کنیم که متغیرهای حالت را تغییر می دهند. کنترل کننده های رویداد راهی هستند که می توانیم وضعیت را در Reflex تغییر دهیم. آنها را می توان در پاسخ به اقدامات کاربر، مانند کلیک کردن روی یک دکمه یا تایپ کردن در یک متن، فراخوانی کرد. به این اعمال وقایع می گویند.
برنامه DALL·E ما دارای یک کنترل کننده رویداد، `get_image` است که این تصویر را از OpenAI API دریافت می کند. استفاده از `yield` در وسط کنترل‌کننده رویداد باعث به‌روزرسانی رابط کاربری می‌شود. در غیر این صورت رابط کاربری در پایان کنترل کننده رویداد به روز می شود.
### **Routing - مسیریابی**
بالاخره اپلیکیشن خود را تعریف می کنیم.
```python
app = rx.App()
```
ما یک صفحه از root برنامه را به جزء index اضافه می کنیم. ما همچنین عنوانی را اضافه می کنیم که در برگه پیش نمایش/مرورگر صفحه نمایش داده می شود.
```python
app.add_page(index, title="DALL-E")
```
با افزودن صفحات بیشتر می توانید یک برنامه چند صفحه ای ایجاد کنید.
## 📑 Resources - منابع
<div align="center">
📑 [اسناد](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [وبلاگ](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [کتابخانه جزء](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [گالری](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [استقرار](https://reflex.dev/docs/hosting/deploy-quick-start) &nbsp;
</div>
## ✅ Status - وضعیت
رفلکس(reflex) در دسامبر 2022 با نام Pynecone راه اندازی شد.
از فوریه 2024، سرویس میزبانی ما در آلفا است! در این مدت هر کسی می‌تواند برنامه‌های خود را به صورت رایگان اجرا کند. [نقشه راه](https://github.com/reflex-dev/reflex/issues/2727) را ببینید تا متوجه شوید چه برنامه‌ریزی شده است.
رفلکس(reflex) هر هفته نسخه ها و ویژگی های جدیدی دارد! مطمئن شوید که :star: ستاره و :eyes: این مخزن را تماشا کنید تا به روز بمانید.
## Contributing - مشارکت کردن
ما از مشارکت در هر اندازه استقبال می کنیم! در زیر چند راه خوب برای شروع در انجمن رفلکس آورده شده است.
- **به Discord ما بپیوندید**: [Discord](https://discord.gg/T5WSbC2YtQ) ما بهترین مکان برای دریافت کمک در مورد پروژه Reflex و بحث در مورد اینکه چگونه می توانید کمک کنید است.
- **بحث های GitHub**: راهی عالی برای صحبت در مورد ویژگی هایی که می خواهید اضافه کنید یا چیزهایی که گیج کننده هستند/نیاز به توضیح دارند.
- **قسمت مشکلات GitHub**: [قسمت مشکلات](https://github.com/reflex-dev/reflex/issues) یک راه عالی برای گزارش اشکال هستند. علاوه بر این، می توانید یک مشکل موجود را حل کنید و یک PR(pull request) ارسال کنید.
ما فعالانه به دنبال مشارکت کنندگان هستیم، فارغ از سطح مهارت یا تجربه شما. برای مشارکت [CONTIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md) را بررسی کنید.
## All Thanks To Our Contributors - با تشکر از همکاران ما:
<a href="https://github.com/reflex-dev/reflex/graphs/contributors">
<img src="https://contrib.rocks/image?repo=reflex-dev/reflex" />
</a>
## License - مجوز
رفلکس متن باز و تحت مجوز [Apache License 2.0](LICENSE) است.

View File

@ -17,11 +17,11 @@
</div>
---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md)
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md)
---
## ⚙️ Instalação
Abra um terminal e execute (Requer Python 3.8+):
Abra um terminal e execute (Requer Python 3.9+):
```bash
pip install reflex

View File

@ -11,7 +11,6 @@
### **✨ Saf Python'da performanslı, özelleştirilebilir web uygulamaları. Saniyeler içinde dağıtın. ✨**
[![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![tests](https://github.com/pynecone-io/pynecone/actions/workflows/integration.yml/badge.svg)
![versions](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentaiton](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
@ -19,13 +18,13 @@
---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md)
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md)
---
## ⚙️ Kurulum
Bir terminal açın ve çalıştırın (Python 3.8+ gerekir):
Bir terminal açın ve çalıştırın (Python 3.9+ gerekir):
```bash
pip install reflex

267
docs/vi/README.md Normal file
View File

@ -0,0 +1,267 @@
```diff
+ Bạn đang tìm kiếm Pynecone? Bạn đã tìm đúng. Pynecone đã được đổi tên thành Reflex. +
```
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_dark.svg#gh-light-mode-only" alt="Reflex Logo" width="300px">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_light.svg#gh-dark-mode-only" alt="Reflex Logo" width="300px">
<hr>
### **✨ Ứng dụng web hiệu suất cao, tùy chỉnh bằng Python thuần. Deploy trong vài giây. ✨**
[![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![versions](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentation](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
</div>
---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md) | [Tiếng Việt](https://github.com/reflex-dev/reflex/blob/main/docs/vi/README.md)
---
# Reflex
Reflex là một thư viện để xây dựng ứng dụng web toàn bộ bằng Python thuần.
Các tính năng chính:
* **Python thuần tuý** - Viết toàn bộ ứng dụng cả backend và frontend hoàn toàn bằng Python, không cần học JavaScript.
* **Full Flexibility** - Reflex dễ dàng để bắt đầu, nhưng cũng có thể mở rộng lên các ứng dụng phức tạp.
* **Deploy Instantly** - Sau khi xây dựng ứng dụng, bạn có thể triển khai bằng [một dòng lệnh](https://reflex.dev/docs/hosting/deploy-quick-start/) hoặc triển khai trên server của riêng bạn.
Đọc [bài viết về kiến trúc hệ thống](https://reflex.dev/blog/2024-03-21-reflex-architecture/#the-reflex-architecture) để hiểu rõ các hoạt động của Reflex.
## ⚙️ Cài đặt
Mở cửa sổ lệnh và chạy (Yêu cầu Python phiên bản 3.9+):
```bash
pip install reflex
```
## 🥳 Tạo ứng dụng đầu tiên
Cài đặt `reflex` cũng như cài đặt công cụ dòng lệnh `reflex`.
Kiểm tra việc cài đặt đã thành công hay chưa bằng cách tạo mới một ứng dụng. (Thay `my_app_name` bằng tên ứng dụng của bạn):
```bash
mkdir my_app_name
cd my_app_name
reflex init
```
Lệnh này tạo ra một ứng dụng mẫu trong một thư mục mới.
Bạn có thể chạy ứng dụng ở chế độ phát triển.
```bash
reflex run
```
Bạn có thể xem ứng dụng của bạn ở địa chỉ http://localhost:3000.
Bạn có thể thay đổi mã nguồn ở `my_app_name/my_app_name.py`. Reflex nhanh chóng làm mới và bạn có thể thấy thay đổi trên ứng dụng của bạn ngay lập tức khi bạn lưu file.
## 🫧 Ứng dụng ví dụ
Bắt đầu với ví dụ: tạo một ứng dụng tạo ảnh bằng [DALL·E](https://platform.openai.com/docs/guides/images/image-generation?context=node). Để cho đơn giản, chúng ta sẽ sử dụng [OpenAI API](https://platform.openai.com/docs/api-reference/authentication), nhưng bạn có thể sử dụng model của chính bạn được triển khai trên local.
&nbsp;
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/dalle.gif" alt="A frontend wrapper for DALL·E, shown in the process of generating an image." width="550" />
</div>
&nbsp;
Đây là toàn bộ đoạn mã để xây dựng ứng dụng trên. Nó được viết hoàn toàn trong một file Python!
```python
import reflex as rx
import openai
openai_client = openai.OpenAI()
class State(rx.State):
"""The app state."""
prompt = ""
image_url = ""
processing = False
complete = False
def get_image(self):
"""Get the image from the prompt."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
def index():
return rx.center(
rx.vstack(
rx.heading("DALL-E", font_size="1.5em"),
rx.input(
placeholder="Enter a prompt..",
on_blur=State.set_prompt,
width="25em",
),
rx.button(
"Generate Image",
on_click=State.get_image,
width="25em",
loading=State.processing
),
rx.cond(
State.complete,
rx.image(src=State.image_url, width="20em"),
),
align="center",
),
width="100%",
height="100vh",
)
# Add state and page to the app.
app = rx.App()
app.add_page(index, title="Reflex:DALL-E")
```
## Hãy phân tích chi tiết.
<div align="center">
<img src="../images/dalle_colored_code_example.png" alt="Explaining the differences between backend and frontend parts of the DALL-E app." width="900" />
</div>
### **Reflex UI**
Bắt đầu với giao diện chính.
```python
def index():
return rx.center(
...
)
```
Hàm `index` định nghĩa phần giao diện chính của ứng dụng.
Chúng tôi sử dụng các component (thành phần) khác nhau như `center`, `vstack`, `input``button` để xây dựng giao diện phía trước.
Các component có thể được lồng vào nhau để tạo ra các bố cục phức tạp. Và bạn cũng có thể sử dụng từ khoá `args` để tận dụng đầy đủ sức mạnh của CSS.
Reflex có đến hơn [60 component được xây dựng sẵn](https://reflex.dev/docs/library) để giúp bạn bắt đầu. Chúng ta có thể tạo ra một component mới khá dễ dàng, thao khảo: [xây dựng component của riêng bạn](https://reflex.dev/docs/wrapping-react/overview/).
### **State**
Reflex biểu diễn giao diện bằng các hàm của state (trạng thái).
```python
class State(rx.State):
"""The app state."""
prompt = ""
image_url = ""
processing = False
complete = False
```
Một state định nghĩa các biến (được gọi là vars) có thể thay đổi trong một ứng dụng và cho phép các hàm có thể thay đổi chúng.
Tại đây state được cấu thành từ một `prompt``image_url`.
Có cũng những biến boolean `processing``complete`
để chỉ ra khi nào tắt nút (trong quá trình tạo hình ảnh)
và khi nào hiển thị hình ảnh kết quả.
### **Event Handlers**
```python
def get_image(self):
"""Get the image from the prompt."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
```
Với các state, chúng ta định nghĩa các hàm có thể thay đổi state vars được gọi là event handlers. Event handler là cách chúng ta có thể thay đổi state trong Reflex. Chúng có thể là phản hồi khi người dùng thao tác, chằng hạn khi nhấn vào nút hoặc khi đang nhập trong text box. Các hành động này được gọi là event.
Ứng dụng DALL·E. của chúng ta có một event handler, `get_image` để lấy hình ảnh từ OpenAI API. Sử dụng từ khoá `yield` in ở giữa event handler để cập nhật giao diện. Hoặc giao diện có thể cập nhật ở cuối event handler.
### **Routing**
Cuối cùng, chúng ta định nghĩa một ứng dụng.
```python
app = rx.App()
```
Chúng ta thêm một trang ở đầu ứng dụng bằng index component. Chúng ta cũng thêm tiêu đề của ứng dụng để hiển thị lên trình duyệt.
```python
app.add_page(index, title="DALL-E")
```
Bạn có thể tạo một ứng dụng nhiều trang bằng cách thêm trang.
## 📑 Tài liệu
<div align="center">
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Component Library](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Gallery](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy-quick-start) &nbsp;
</div>
## ✅ Status
Reflex phát hành vào tháng 12/2022 với tên là Pynecone.
Đến tháng 02/2024, chúng tôi tạo ra dịch vụ dưới phiên bản alpha! Trong thời gian này mọi người có thể triển khai ứng dụng hoàn toàn miễn phí. Xem [roadmap](https://github.com/reflex-dev/reflex/issues/2727) để biết thêm chi tiết.
Reflex ra phiên bản mới với các tính năng mới hàng tuần! Hãy :star: star và :eyes: watch repo này để thấy các cập nhật mới nhất.
## Contributing
Chúng tôi chào đón mọi đóng góp dù lớn hay nhỏ. Dưới đây là các cách để bắt đầu với cộng đồng Reflex.
- **Discord**: [Discord](https://discord.gg/T5WSbC2YtQ) của chúng tôi là nơi tốt nhất để nhờ sự giúp đỡ và thảo luận các bạn có thể đóng góp.
- **GitHub Discussions**: Là cách tốt nhất để thảo luận về các tính năng mà bạn có thể đóng góp hoặc những điều bạn chưa rõ.
- **GitHub Issues**: [Issues](https://github.com/reflex-dev/reflex/issues) là nơi tốt nhất để thông báo. Ngoài ra bạn có thể sửa chữa các vấn đề bằng cách tạo PR.
Chúng tôi luôn sẵn sàng tìm kiếm các contributor, bất kể kinh nghiệm. Để tham gia đóng góp, xin mời xem
[CONTIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md)
## Xin cảm ơn các Contributors:
<a href="https://github.com/reflex-dev/reflex/graphs/contributors">
<img src="https://contrib.rocks/image?repo=reflex-dev/reflex" />
</a>
## License
Reflex là mã nguồn mở và sử dụng giấy phép [Apache License 2.0](LICENSE).

View File

@ -8,25 +8,35 @@
<hr>
**✨ 使用 Python 创建高效且可自定义的网页应用程序,几秒钟内即可部署.**
### **✨ 使用 Python 创建高效且可自定义的网页应用程序,几秒钟内即可部署.✨**
[![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![tests](https://github.com/pynecone-io/pynecone/actions/workflows/integration.yml/badge.svg)
![versions](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentaiton](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
</div>
---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md)
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md)
---
# Reflex
Reflex 是一个使用纯Python构建全栈web应用的库。
关键特性:
* **纯Python** - 前端、后端开发全都使用Python不需要学习Javascript。
* **完整的灵活性** - Reflex很容易上手, 并且也可以扩展到复杂的应用程序。
* **立即部署** - 构建后,使用[单个命令](https://reflex.dev/docs/hosting/deploy-quick-start/)就能部署应用程序;或者也可以将其托管在您自己的服务器上。
请参阅我们的[架构页](https://reflex.dev/blog/2024-03-21-reflex-architecture/#the-reflex-architecture)了解Reflex如何工作。
## ⚙️ 安装
打开一个终端并且运行(要求Python3.8+):
打开一个终端并且运行(要求Python3.9+):
```
```bash
pip install reflex
```
@ -36,7 +46,7 @@ pip install reflex
通过创建一个新项目来测试是否安装成功(请把 my_app_name 替代为您的项目名字):
```
```bash
mkdir my_app_name
cd my_app_name
reflex init
@ -45,6 +55,7 @@ reflex init
这段命令会在新文件夹初始化一个应用程序模板.
您可以在开发者模式下运行这个应用程序:
```bash
reflex run
```
@ -55,7 +66,7 @@ reflex run
## 🫧 范例
让我们来看一个例子: 创建一个使用 DALL·E 进行图像生成的图形界面.为了保持范例简单,我们只使用 OpenAI API,但是您可以将其替换成本地端的 ML 模型.
让我们来看一个例子: 创建一个使用 [DALL·E](https://platform.openai.com/docs/guides/images/image-generation?context=node) 进行图像生成的图形界面.为了保持范例简单,我们只使用 OpenAI API,但是您可以将其替换成本地端的 ML 模型.
&nbsp;
@ -67,14 +78,19 @@ reflex run
这是这个范例的完整代码,只需要一个 Python 文件就可以完成!
```python
import reflex as rx
import openai
openai.api_key = "YOUR_API_KEY"
openai_client = openai.OpenAI()
class State(rx.State):
"""The app state."""
prompt = ""
image_url = ""
processing = False
@ -87,33 +103,33 @@ class State(rx.State):
self.processing, self.complete = True, False
yield
response = openai.Image.create(prompt=self.prompt, n=1, size="1024x1024")
self.image_url = response["data"][0]["url"]
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
def index():
return rx.center(
rx.vstack(
rx.heading("DALL·E"),
rx.input(placeholder="Enter a prompt", on_blur=State.set_prompt),
rx.heading("DALL-E", font_size="1.5em"),
rx.input(
placeholder="Enter a prompt..",
on_blur=State.set_prompt,
width="25em",
),
rx.button(
"Generate Image",
"Generate Image",
on_click=State.get_image,
is_loading=State.processing,
width="100%",
width="25em",
loading=State.processing
),
rx.cond(
State.complete,
rx.image(
src=State.image_url,
height="25em",
width="25em",
)
rx.image(src=State.image_url, width="20em"),
),
padding="2em",
shadow="lg",
border_radius="lg",
align="center",
),
width="100%",
height="100vh",
@ -121,11 +137,20 @@ def index():
# Add state and page to the app.
app = rx.App()
app.add_page(index, title="reflex:DALL·E")
app.add_page(index, title="Reflex:DALL-E")
```
## 让我们分解以上步骤.
<div align="center">
<img src="../../images/dalle_colored_code_example.png" alt="解释 DALL-E app 的前端和后端部分的区别。" width="900" />
</div>
### **Reflex UI**
让我们从UI开始.
@ -142,7 +167,7 @@ def index():
我们用不同的组件比如 `center`, `vstack`, `input`, 和 `button` 来创建前端, 组件之间可以相互嵌入,来创建复杂的布局.
并且您可以使用关键字参数来使用 CSS 的全部功能.
Reflex 拥有 [60+ 个内置组件](https://reflex.dev/docs/library) 来帮助您开始创建应用程序. 我们正在积极添加组件, 但是您也可以 [创建自己的组件](https://reflex.dev/docs/wrapping-react/overview/).
Reflex 拥有 [60+ 个内置组件](https://reflex.dev/docs/library) 来帮助您开始创建应用程序. 我们正在积极添加组件, 但是您也可以容易的 [创建自己的组件](https://reflex.dev/docs/wrapping-react/overview/).
### **State**
@ -155,12 +180,12 @@ class State(rx.State):
image_url = ""
processing = False
complete = False
```
```
State定义了所有可能会发生变化的变量(称为 vars)以及能够改变这些变量的函数.
在这个范例中,State由 prompt 和 image_url 组成.此外,State还包含有两个布尔值 processing 和 complete,用于指示何时显示循环进度指示器和图像.
在这个范例中,State由 `prompt``image_url` 组成.此外,State还包含有两个布尔值 `processing``complete`,用于指示何时显示循环进度指示器和图像.
### **Event Handlers**
@ -172,14 +197,16 @@ def get_image(self):
self.processing, self.complete = True, False
yield
response = openai.Image.create(prompt=self.prompt, n=1, size="1024x1024")
self.image_url = response["data"][0]["url"]
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
```
在 State 中,我们定义了称为事件处理器(event handlers)的函数,用于改变状态变量(state vars).在Reflex中,事件处理器是我们可以修改状态的方式.它们可以作为对用户操作的响应而被调用,例如点击一个按钮或在文本框中输入.这些操作被称为事件.
我们的DALL·E应用有一个事件处理器,名为 get_image,它用于从OpenAI API获取图像.在事件处理器中使用 yield 将导致UI进行更新.否则,UI将在事件处理器结束时进行更新.
我们的DALL·E应用有一个事件处理器,名为 `get_image`,它用于从OpenAI API获取图像.在事件处理器中使用 `yield` 将导致UI进行更新.否则,UI将在事件处理器结束时进行更新.
### **Routing**
@ -206,19 +233,13 @@ app.add_page(index, title="DALL-E")
</div>
## ✅ Reflex 的状态
Reflex 于 2022 年 12 月以Pynecone的名称推出.
在2023年7月, 我们处于 **Public Beta** 阶段.
截至2024年2月我们的托管服务处于alpha测试阶段在此期间任何人都可以免费部署他们的应用程序。请查看我们的[路线图](https://github.com/reflex-dev/reflex/issues/2727)以了解我们的计划。
- :white_check_mark: **Public Alpha**: 任何人都可以安装与使用 Reflex,或许包含问题, 但我们正在积极的解决他们.
- :large_orange_diamond: **Public Beta**: 对于非软件产品来说足够稳定.
- **Public Hosting Beta**: _Optionally_, 部属跟托管您的 Reflex!
- **Public**: 这版本的 Reflex 是可用于软件产品的.
Reflex 每周都有新功能和发布新版本! 确保您按下 :star: 和 :eyes: watch 这个 repository 来确保知道最新信息.
Reflex 每周都有新功能和发布新版本! 确保您按下 :star: 收藏和 :eyes: 关注 这个 仓库来确保知道最新信息.
## 贡献
@ -226,10 +247,16 @@ Reflex 每周都有新功能和发布新版本! 确保您按下 :star: 和 :eyes
- **加入我们的 Discord**: 我们的 [Discord](https://discord.gg/T5WSbC2YtQ) 是帮助您加入 Reflex 项目和讨论或贡献最棒的地方.
- **GitHub Discussions**: 一个来讨论您想要添加的功能或是需要澄清的事情的好地方.
- **GitHub Issues**: 报告错误的绝佳地方,另外您可以试着解决一些 issue 和送出 PR.
- **GitHub Issues**: [报告错误](https://github.com/reflex-dev/reflex/issues)的绝佳地方,另外您可以试着解决一些 issue 和送出 PR.
我们正在积极寻找贡献者,无关您的技能或经验水平.
## 感谢我们所有的贡献者:
<a href="https://github.com/reflex-dev/reflex/graphs/contributors">
<img src="https://contrib.rocks/image?repo=reflex-dev/reflex" />
</a>
## 授权
Reflex 是一个开源项目,使用 [Apache License 2.0](LICENSE) 授权.

View File

@ -11,18 +11,32 @@
**✨ 使用 Python 建立高效且可自訂的網頁應用程式,幾秒鐘內即可部署。✨**
[![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![tests](https://github.com/pynecone-io/pynecone/actions/workflows/integration.yml/badge.svg)
![versions](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentaiton](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
</div>
---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md)
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md)
---
# Reflex
Reflex 是一個可以用純 Python 構建全端網頁應用程式的函式庫。
主要特色:
* **純 Python** - 您可以用 Python 撰寫應用程式的前端和後端,無需學習 Javascript。
* **完全靈活性** - Reflex 易於上手,但也可以擴展到複雜的應用程式。
* **立即部署** - 構建後,只需使用[單一指令](https://reflex.dev/docs/hosting/deploy-quick-start/)即可部署您的應用程式,或在您自己的伺服器上託管。
請參閱我們的[架構頁面](https://reflex.dev/blog/2024-03-21-reflex-architecture/#the-reflex-architecture)了解 Reflex 如何在底層運作。
## ⚙️ 安裝
開啟一個終端機並且執行 (需要 Python 3.8+):
開啟一個終端機並且執行 (需要 Python 3.9+):
```bash
pip install reflex
@ -70,7 +84,8 @@ reflex run
import reflex as rx
import openai
openai.api_key = "YOUR_API_KEY"
openai_client = openai.OpenAI()
class State(rx.State):
"""應用程式狀態"""
@ -86,33 +101,33 @@ class State(rx.State):
self.processing, self.complete = True, False
yield
response = openai.Image.create(prompt=self.prompt, n=1, size="1024x1024")
self.image_url = response["data"][0]["url"]
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
def index():
return rx.center(
rx.vstack(
rx.heading("DALL·E"),
rx.input(placeholder="Enter a prompt", on_blur=State.set_prompt),
rx.heading("DALL-E", font_size="1.5em"),
rx.input(
placeholder="Enter a prompt..",
on_blur=State.set_prompt,
width="25em",
),
rx.button(
"Generate Image",
"Generate Image",
on_click=State.get_image,
is_loading=State.processing,
width="100%",
width="25em",
loading=State.processing
),
rx.cond(
State.complete,
rx.image(
src=State.image_url,
height="25em",
width="25em",
)
rx.image(src=State.image_url, width="20em"),
),
padding="2em",
shadow="lg",
border_radius="lg",
align="center",
),
width="100%",
height="100vh",
@ -120,10 +135,22 @@ def index():
# 把狀態跟頁面添加到應用程式。
app = rx.App()
app.add_page(index, title="reflex:DALL·E")
app.add_page(index, title="Reflex:DALL-E")
```
## 讓我們來拆解一下。
<div align="center">
<img src="../../images/dalle_colored_code_example.png" alt="解釋 DALL-E app 的前端和後端部分的區別。" width="900" />
</div>
### **Reflex 使用者介面**
讓我們從使用介面開始。
@ -150,8 +177,9 @@ class State(rx.State):
"""應用程式狀態"""
prompt = ""
image_url = ""
image_processing = False
image_made = False
processing = False
complete = False
```
應用程式狀態定義了應用程式中所有可以更改的變數及變更他們的函式 (稱為 vars)。
@ -168,8 +196,10 @@ def get_image(self):
self.processing, self.complete = True, False
yield
response = openai.Image.create(prompt=self.prompt, n=1, size="1024x1024")
self.image_url = response["data"][0]["url"]
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
```
@ -199,34 +229,35 @@ app.add_page(index, title="DALL-E")
<div align="center">
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Component Library](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Gallery](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy) &nbsp;
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Component Library](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Gallery](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy-quick-start) &nbsp;
</div>
## ✅ Reflex 狀態
## ✅ 產品狀態
Reflex 於 2022 年 12 月推出,當時名為 Pynecone
Reflex 在 2022 年 12 月以 Pynecone 的名字推出
截至 2023 年 7 月,我們處於 **Public Beta** 階段。
- :white_check_mark: **Public Alpha**: 任何人都可以安裝與使用 Reflex或許包含問題 但我們正在積極的解決他們。
- :large_orange_diamond: **Public Beta**: 對於不涉及商業目的使用情境來說足夠穩定。
- **Public Hosting Beta**: _Optionally_, 部屬跟託管你的 Reflex!
- **Public**: 這版本的 Reflex 是可用於軟體產品的。
截至 2024 年 2 月,我們的託管服務已進入 alpha 階段!在此期間,任何人都可以免費部署他們的應用程式。請參閱我們的[產品地圖](https://github.com/reflex-dev/reflex/issues/2727)了解未來的計劃。
Reflex 每周都有新功能和釋出新版本! 確保你按下 :star: 和 :eyes: watch 這個 repository 來確保知道最新資訊。
## 貢獻
我們歡迎任何大小的貢獻,以下是幾個好的方法來加入 Reflex 社群
我們歡迎任何大小的貢獻,以下是一些加入 Reflex 社群的好方法
- **加入我們的 Discord**: 我們的 [Discord](https://discord.gg/T5WSbC2YtQ) 是幫助你加入 Reflex 專案和討論或貢獻最棒的地方。
- **GitHub Discussions**: 一個來討論你想要添加的功能或是需要澄清的事情的好地方
- **GitHub Issues**: 報告錯誤的絕佳地方,另外你可以試著解決一些 issue 和送出 PR。
- **加入我們的 Discord**: 我們的 [Discord](https://discord.gg/T5WSbC2YtQ) 是獲取 Reflex 專案幫助和討論如何貢獻的最佳地方。
- **GitHub Discussions**: 這是一個討論您想新增的功能或對於一些困惑/需要澄清事項的好方法
- **GitHub Issues**: 在 [Issues](https://github.com/reflex-dev/reflex/issues) 頁面報告錯誤是一個絕佳的方式。此外,您也可以嘗試解決現有 Issue 並提交 PR。
我們正在積極尋找貢獻者,無關你的技能水平或經驗。
我們積極尋找貢獻者,不論您的技能水平或經驗如何。要貢獻,請查看 [CONTIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md)
## 感謝所有貢獻者:
<a href="https://github.com/reflex-dev/reflex/graphs/contributors">
<img src="https://contrib.rocks/image?repo=reflex-dev/reflex" />
</a>
## 授權

View File

@ -1,107 +0,0 @@
"""Test that per-component state scaffold works and operates independently."""
from typing import Generator
import pytest
from selenium.webdriver.common.by import By
from reflex.testing import AppHarness
from . import utils
def ComponentStateApp():
"""App using per component state."""
import reflex as rx
class MultiCounter(rx.ComponentState):
count: int = 0
def increment(self):
self.count += 1
@classmethod
def get_component(cls, *children, **props):
return rx.vstack(
*children,
rx.heading(cls.count, id=f"count-{props.get('id', 'default')}"),
rx.button(
"Increment",
on_click=cls.increment,
id=f"button-{props.get('id', 'default')}",
),
**props,
)
app = rx.App(state=rx.State) # noqa
@rx.page()
def index():
mc_a = MultiCounter.create(id="a")
mc_b = MultiCounter.create(id="b")
assert mc_a.State != mc_b.State
return rx.vstack(
mc_a,
mc_b,
rx.button(
"Inc A",
on_click=mc_a.State.increment, # type: ignore
id="inc-a",
),
)
@pytest.fixture()
def component_state_app(tmp_path) -> Generator[AppHarness, None, None]:
"""Start ComponentStateApp app at tmp_path via AppHarness.
Args:
tmp_path: pytest tmp_path fixture
Yields:
running AppHarness instance
"""
with AppHarness.create(
root=tmp_path,
app_source=ComponentStateApp, # type: ignore
) as harness:
yield harness
@pytest.mark.asyncio
async def test_component_state_app(component_state_app: AppHarness):
"""Increment counters independently.
Args:
component_state_app: harness for ComponentStateApp app
"""
assert component_state_app.app_instance is not None, "app is not running"
driver = component_state_app.frontend()
ss = utils.SessionStorage(driver)
token = AppHarness._poll_for(lambda: ss.get("token") is not None)
assert token is not None
count_a = driver.find_element(By.ID, "count-a")
count_b = driver.find_element(By.ID, "count-b")
button_a = driver.find_element(By.ID, "button-a")
button_b = driver.find_element(By.ID, "button-b")
button_inc_a = driver.find_element(By.ID, "inc-a")
assert count_a.text == "0"
button_a.click()
assert component_state_app.poll_for_content(count_a, exp_not_equal="0") == "1"
button_a.click()
assert component_state_app.poll_for_content(count_a, exp_not_equal="1") == "2"
button_inc_a.click()
assert component_state_app.poll_for_content(count_a, exp_not_equal="2") == "3"
assert count_b.text == "0"
button_b.click()
assert component_state_app.poll_for_content(count_b, exp_not_equal="0") == "1"
button_b.click()
assert component_state_app.poll_for_content(count_b, exp_not_equal="1") == "2"

View File

@ -1,170 +0,0 @@
"""Integration tests for table and related components."""
from typing import Generator
import pytest
from selenium.webdriver.common.by import By
from reflex.testing import AppHarness
def Table():
"""App using table component."""
from typing import List
import reflex as rx
class TableState(rx.State):
rows: List[List[str]] = [
["John", "30", "New York"],
["Jane", "31", "San Fransisco"],
["Joe", "32", "Los Angeles"],
]
headers: List[str] = ["Name", "Age", "Location"]
footers: List[str] = ["footer1", "footer2", "footer3"]
caption: str = "random caption"
app = rx.App(state=rx.State)
@app.add_page
def index():
return rx.center(
rx.chakra.input(
id="token",
value=TableState.router.session.client_token,
is_read_only=True,
),
rx.chakra.table_container(
rx.chakra.table(
headers=TableState.headers,
rows=TableState.rows,
footers=TableState.footers,
caption=TableState.caption,
variant="striped",
color_scheme="blue",
width="100%",
),
),
)
@app.add_page
def another():
return rx.center(
rx.chakra.table_container(
rx.chakra.table( # type: ignore
rx.chakra.thead( # type: ignore
rx.chakra.tr( # type: ignore
rx.chakra.th("Name"),
rx.chakra.th("Age"),
rx.chakra.th("Location"),
)
),
rx.chakra.tbody( # type: ignore
rx.chakra.tr( # type: ignore
rx.chakra.td("John"),
rx.chakra.td(30),
rx.chakra.td("New York"),
),
rx.chakra.tr( # type: ignore
rx.chakra.td("Jane"),
rx.chakra.td(31),
rx.chakra.td("San Francisco"),
),
rx.chakra.tr( # type: ignore
rx.chakra.td("Joe"),
rx.chakra.td(32),
rx.chakra.td("Los Angeles"),
),
),
rx.chakra.tfoot( # type: ignore
rx.chakra.tr(
rx.chakra.td("footer1"),
rx.chakra.td("footer2"),
rx.chakra.td("footer3"),
) # type: ignore
),
rx.chakra.table_caption("random caption"),
variant="striped",
color_scheme="teal",
)
)
)
@pytest.fixture()
def table(tmp_path_factory) -> Generator[AppHarness, None, None]:
"""Start Table app at tmp_path via AppHarness.
Args:
tmp_path_factory: pytest tmp_path_factory fixture
Yields:
running AppHarness instance
"""
with AppHarness.create(
root=tmp_path_factory.mktemp("table"),
app_source=Table, # type: ignore
) as harness:
assert harness.app_instance is not None, "app is not running"
yield harness
@pytest.fixture
def driver(table: AppHarness):
"""GEt an instance of the browser open to the table app.
Args:
table: harness for Table app
Yields:
WebDriver instance.
"""
driver = table.frontend()
try:
token_input = driver.find_element(By.ID, "token")
assert token_input
# wait for the backend connection to send the token
token = table.poll_for_value(token_input)
assert token is not None
yield driver
finally:
driver.quit()
@pytest.mark.parametrize("route", ["", "/another"])
def test_table(driver, table: AppHarness, route):
"""Test that a table component is rendered properly.
Args:
driver: Selenium WebDriver open to the app
table: Harness for Table app
route: Page route or path.
"""
driver.get(f"{table.frontend_url}/{route}")
assert table.app_instance is not None, "app is not running"
thead = driver.find_element(By.TAG_NAME, "thead")
# poll till page is fully loaded.
table.poll_for_content(element=thead)
# check headers
assert thead.find_element(By.TAG_NAME, "tr").text == "NAME AGE LOCATION"
# check first row value
assert (
driver.find_element(By.TAG_NAME, "tbody")
.find_elements(By.TAG_NAME, "tr")[0]
.text
== "John 30 New York"
)
# check footer
assert (
driver.find_element(By.TAG_NAME, "tfoot")
.find_element(By.TAG_NAME, "tr")
.text.lower()
== "footer1 footer2 footer3"
)
# check caption
assert driver.find_element(By.TAG_NAME, "caption").text == "random caption"

View File

@ -1,67 +0,0 @@
"""Integration tests for all urls in Reflex."""
import os
import re
from pathlib import Path
import pytest
import requests
def check_urls(repo_dir):
"""Check that all URLs in the repo are valid and secure.
Args:
repo_dir: The directory of the repo.
Returns:
A list of errors.
"""
url_pattern = re.compile(r'http[s]?://reflex\.dev[^\s")]*')
errors = []
for root, _dirs, files in os.walk(repo_dir):
if "__pycache__" in root:
continue
for file_name in files:
if not file_name.endswith(".py") and not file_name.endswith(".md"):
continue
file_path = os.path.join(root, file_name)
try:
with open(file_path, "r", encoding="utf-8", errors="ignore") as file:
for line in file:
urls = url_pattern.findall(line)
for url in set(urls):
if url.startswith("http://"):
errors.append(
f"Found insecure HTTP URL: {url} in {file_path}"
)
url = url.strip('"\n')
try:
response = requests.head(
url, allow_redirects=True, timeout=5
)
response.raise_for_status()
except requests.RequestException as e:
errors.append(
f"Error accessing URL: {url} in {file_path} | Error: {e}, , Check your path ends with a /"
)
except Exception as e:
errors.append(f"Error reading file: {file_path} | Error: {e}")
return errors
@pytest.mark.parametrize(
"repo_dir",
[Path(__file__).resolve().parent.parent / "reflex"],
)
def test_find_and_check_urls(repo_dir):
"""Test that all URLs in the repo are valid and secure.
Args:
repo_dir: The directory of the repo.
"""
errors = check_urls(repo_dir)
assert not errors, "\n".join(errors)

3616
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
[tool.poetry]
name = "reflex"
version = "0.5.0"
version = "0.6.5dev1"
description = "Web apps in pure Python."
license = "Apache-2.0"
authors = [
@ -26,12 +26,11 @@ packages = [
]
[tool.poetry.dependencies]
python = "^3.8"
dill = ">=0.3.8,<0.4"
fastapi = ">=0.96.0,<1.0"
gunicorn = ">=20.1.0,<23.0"
python = "^3.9"
fastapi = ">=0.96.0,!=0.111.0,!=0.111.1"
gunicorn = ">=20.1.0,<24.0"
jinja2 = ">=3.1.2,<4.0"
psutil = ">=5.9.4,<6.0"
psutil = ">=5.9.4,<7.0"
pydantic = ">=1.10.2,<3.0"
python-multipart = ">=0.0.5,<0.1"
python-socketio = ">=5.7.0,<6.0"
@ -39,12 +38,7 @@ redis = ">=4.3.5,<6.0"
rich = ">=13.0.0,<14.0"
sqlmodel = ">=0.0.14,<0.1"
typer = ">=0.4.2,<1.0"
uvicorn = [
{version = "^0.24.0", python = ">=3.12"},
{version = "^0.20.0", python = "<3.12"},
]
watchdog = ">=2.3.1,<5.0"
watchfiles = ">=0.19.0,<1.0"
uvicorn = ">=0.20.0"
starlette-admin = ">=0.11.0,<1.0"
alembic = ">=1.11.1,<2.0"
platformdirs = ">=3.10.0,<5.0"
@ -59,34 +53,33 @@ reflex-hosting-cli = ">=0.1.2,<2.0"
charset-normalizer = ">=3.3.2,<4.0"
wheel = ">=0.42.0,<1.0"
build = ">=1.0.3,<2.0"
setuptools = ">=69.1.1,<70.0"
setuptools = ">=75.0"
httpx = ">=0.25.1,<1.0"
twine = ">=4.0.0,<6.0"
tomlkit = ">=0.12.4,<1.0"
asgiproxy = { version = "==0.1.1", optional = true }
lazy_loader = ">=0.4"
reflex-chakra = ">=0.6.0"
[tool.poetry.group.dev.dependencies]
pytest = ">=7.1.2,<8.0"
pytest = ">=7.1.2,<9.0"
pytest-mock = ">=3.10.0,<4.0"
pyright = ">=1.1.229,<1.1.335"
darglint = ">=1.8.1,<2.0"
dill = ">=0.3.8"
toml = ">=0.10.2,<1.0"
pytest-asyncio = ">=0.20.1,<0.22.0" # https://github.com/pytest-dev/pytest-asyncio/issues/706
pytest-cov = ">=4.0.0,<5.0"
black = "^22.10.0,<23.0"
ruff = "0.1.0"
pandas = [
{version = ">=2.1.1,<3.0", python = ">=3.9,<3.13"},
{version = ">=1.5.3,<2.0", python = ">=3.8,<3.9"},
]
pillow = [
{version = ">=10.0.0,<11.0", python = ">=3.8,<4.0"}
]
pytest-asyncio = ">=0.24.0"
pytest-cov = ">=4.0.0,<6.0"
ruff = "0.7.1"
pandas = ">=2.1.1,<3.0"
pillow = ">=10.0.0,<12.0"
plotly = ">=5.13.0,<6.0"
asynctest = ">=0.13.0,<1.0"
pre-commit = {version = ">=3.2.1", python = ">=3.8,<4.0"}
pre-commit = ">=3.2.1"
selenium = ">=4.11.0,<5.0"
pytest-benchmark = ">=4.0.0,<5.0"
playwright = ">=1.46.0"
pytest-playwright = ">=0.5.1"
[tool.poetry.scripts]
reflex = "reflex.reflex:cli"
@ -101,13 +94,18 @@ build-backend = "poetry.core.masonry.api"
[tool.pyright]
[tool.ruff]
exclude = ["*.pyi"]
target-version = "py37"
target-version = "py39"
lint.select = ["B", "D", "E", "F", "I", "SIM", "W"]
lint.ignore = ["B008", "D203", "D205", "D213", "D401", "D406", "D407", "E501", "F403", "F405", "F541"]
lint.ignore = ["B008", "D203", "D205", "D213", "D401", "D406", "D407", "E501", "F403", "F405", "F541", "SIM115"]
lint.pydocstyle.convention = "google"
[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401"]
"tests/*.py" = ["D100", "D103", "D104", "B018"]
"reflex/.templates/*.py" = ["D100", "D103", "D104"]
"*.pyi" = ["ALL"]
"*.pyi" = ["D301", "D415", "D417", "D418", "E742"]
"*/blank.py" = ["I001"]
[tool.pytest.ini_options]
asyncio_default_fixture_loop_scope = "function"
asyncio_mode = "auto"

View File

@ -1,4 +0,0 @@
*.db
*.py[cod]
.web
__pycache__/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -1,10 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Github" clip-path="url(#clip0_469_1929)">
<path id="Vector" d="M8.0004 0.587524C3.80139 0.587524 0.400391 3.98851 0.400391 8.1875C0.400391 11.5505 2.57589 14.391 5.59689 15.398C5.97689 15.4645 6.11939 15.2365 6.11939 15.037C6.11939 14.8565 6.10989 14.258 6.10989 13.6215C4.20039 13.973 3.70639 13.156 3.55439 12.7285C3.46889 12.51 3.09839 11.8355 2.77539 11.655C2.50939 11.5125 2.12939 11.161 2.76589 11.1515C3.36439 11.142 3.79189 11.7025 3.93439 11.9305C4.61839 13.08 5.71089 12.757 6.14789 12.5575C6.21439 12.0635 6.41388 11.731 6.6324 11.541C4.94139 11.351 3.17439 10.6955 3.17439 7.7885C3.17439 6.962 3.46889 6.27801 3.95339 5.74601C3.87739 5.55601 3.61139 4.77701 4.02939 3.73201C4.02939 3.73201 4.66589 3.53251 6.11939 4.51101C6.7274 4.34001 7.3734 4.25451 8.0194 4.25451C8.6654 4.25451 9.3114 4.34001 9.9194 4.51101C11.3729 3.52301 12.0094 3.73201 12.0094 3.73201C12.4274 4.77701 12.1614 5.55601 12.0854 5.74601C12.5699 6.27801 12.8644 6.9525 12.8644 7.7885C12.8644 10.705 11.0879 11.351 9.3969 11.541C9.6724 11.7785 9.9099 12.2345 9.9099 12.947C9.9099 13.9635 9.9004 14.7805 9.9004 15.037C9.9004 15.2365 10.0429 15.474 10.4229 15.398C13.5165 14.3536 15.5996 11.4527 15.6004 8.1875C15.6004 3.98851 12.1994 0.587524 8.0004 0.587524Z" fill="#494369"/>
</g>
<defs>
<clipPath id="clip0_469_1929">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1,37 +0,0 @@
<svg width="67" height="14" viewBox="0 0 67 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="67" height="14" fill="#1E1E1E"/>
<g id="Nav Template &#62; Initial" clip-path="url(#clip0_0_1)">
<rect width="1440" height="1024" transform="translate(-16 -17)" fill="white"/>
<g id="Sidebar">
<g clip-path="url(#clip1_0_1)">
<path d="M-16 -17H264V1007H-16V-17Z" fill="white"/>
<g id="Header">
<path d="M-16 -17H264V31H-16V-17Z" fill="white"/>
<g id="Button">
<rect x="-4" y="-3" width="74.316" height="20" rx="6" fill="white"/>
<g id="Logo">
<g id="Reflex">
<path d="M0 13.6316V0.368408H10.6106V5.67369H7.95792V3.02105H2.65264V5.67369H7.95792V8.32633H2.65264V13.6316H0ZM7.95792 13.6316V8.32633H10.6106V13.6316H7.95792Z" fill="#110F1F"/>
<path d="M13.2632 13.6316V0.368408H21.2211V3.02105H15.9158V5.67369H21.2211V8.32633H15.9158V10.979H21.2211V13.6316H13.2632Z" fill="#110F1F"/>
<path d="M23.8738 13.6316V0.368408H31.8317V3.02105H26.5264V5.67369H31.8317V8.32633H26.5264V13.6316H23.8738Z" fill="#110F1F"/>
<path d="M34.4843 13.6316V0.368408H37.137V10.979H42.4422V13.6316H34.4843Z" fill="#110F1F"/>
<path d="M45.0949 13.6316V0.368408H53.0528V3.02105H47.7475V5.67369H53.0528V8.32633H47.7475V10.979H53.0528V13.6316H45.0949Z" fill="#110F1F"/>
<path d="M55.7054 5.67369V0.368408H58.3581V5.67369H55.7054ZM63.6634 5.67369V0.368408H66.316V5.67369H63.6634ZM58.3581 8.32633V5.67369H63.6634V8.32633H58.3581ZM55.7054 13.6316V8.32633H58.3581V13.6316H55.7054ZM63.6634 13.6316V8.32633H66.316V13.6316H63.6634Z" fill="#110F1F"/>
</g>
</g>
</g>
<path d="M264 30.5H-16V31.5H264V30.5Z" fill="#F4F3F6"/>
</g>
</g>
<path d="M263.5 -17V1007H264.5V-17H263.5Z" fill="#F4F3F6"/>
</g>
</g>
<defs>
<clipPath id="clip0_0_1">
<rect width="1440" height="1024" fill="white" transform="translate(-16 -17)"/>
</clipPath>
<clipPath id="clip1_0_1">
<path d="M-16 -17H264V1007H-16V-17Z" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -1,68 +0,0 @@
<svg width="80" height="78" viewBox="0 0 80 78" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_ddddi_449_2821)">
<path d="M13 11C13 6.58172 16.5817 3 21 3H59C63.4183 3 67 6.58172 67 11V49C67 52.3137 64.3137 55 61 55H19C15.6863 55 13 52.3137 13 49V11Z" fill="url(#paint0_radial_449_2821)"/>
<path d="M13 11C13 6.58172 16.5817 3 21 3H59C63.4183 3 67 6.58172 67 11V49C67 52.3137 64.3137 55 61 55H19C15.6863 55 13 52.3137 13 49V11Z" fill="url(#paint1_radial_449_2821)"/>
<g filter="url(#filter1_i_449_2821)">
<path d="M31 37.5C30.4477 37.5 30 37.0523 30 36.5V13.5001C30 12.9478 30.4477 12.5001 31 12.5001H49C49.5523 12.5001 50 12.9478 50 13.5001V21.5001C50 22.0524 49.5523 22.5001 49 22.5001H45V18.5001C45 17.9478 44.5523 17.5001 44 17.5001H36C35.4477 17.5001 35 17.9478 35 18.5001V21.5001C35 22.0524 35.4477 22.5001 36 22.5001H45V27.5001H36C35.4477 27.5001 35 27.9478 35 28.5001V36.5C35 37.0523 34.5523 37.5 34 37.5H31ZM46 37.5C45.4477 37.5 45 37.0523 45 36.5V27.5001H49C49.5523 27.5001 50 27.9478 50 28.5001V36.5C50 37.0523 49.5523 37.5 49 37.5H46Z" fill="url(#paint2_radial_449_2821)"/>
</g>
<path d="M13 11C13 6.58172 16.5817 3 21 3H59C63.4183 3 67 6.58172 67 11V49C67 52.3137 64.3137 55 61 55H19C15.6863 55 13 52.3137 13 49V11Z" stroke="#20117E" stroke-opacity="0.04"/>
</g>
<defs>
<filter id="filter0_ddddi_449_2821" x="0.5" y="0.5" width="79" height="77" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feMorphology radius="4" operator="erode" in="SourceAlpha" result="effect1_dropShadow_449_2821"/>
<feOffset dy="10"/>
<feGaussianBlur stdDeviation="8"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.0784314 0 0 0 0 0.0705882 0 0 0 0 0.231373 0 0 0 0.06 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_449_2821"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feMorphology radius="6" operator="erode" in="SourceAlpha" result="effect2_dropShadow_449_2821"/>
<feOffset dy="12"/>
<feGaussianBlur stdDeviation="3"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.0784314 0 0 0 0 0.0705882 0 0 0 0 0.231373 0 0 0 0.1 0"/>
<feBlend mode="normal" in2="effect1_dropShadow_449_2821" result="effect2_dropShadow_449_2821"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feMorphology radius="4" operator="erode" in="SourceAlpha" result="effect3_dropShadow_449_2821"/>
<feOffset dy="10"/>
<feGaussianBlur stdDeviation="3"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.12549 0 0 0 0 0.0666667 0 0 0 0 0.494118 0 0 0 0.16 0"/>
<feBlend mode="normal" in2="effect2_dropShadow_449_2821" result="effect3_dropShadow_449_2821"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feMorphology radius="1" operator="dilate" in="SourceAlpha" result="effect4_dropShadow_449_2821"/>
<feOffset dy="2"/>
<feGaussianBlur stdDeviation="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.12549 0 0 0 0 0.0666667 0 0 0 0 0.494118 0 0 0 0.05 0"/>
<feBlend mode="normal" in2="effect3_dropShadow_449_2821" result="effect4_dropShadow_449_2821"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect4_dropShadow_449_2821" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="-8"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.678431 0 0 0 0 0.607843 0 0 0 0 0.972549 0 0 0 0.2 0"/>
<feBlend mode="normal" in2="shape" result="effect5_innerShadow_449_2821"/>
</filter>
<filter id="filter1_i_449_2821" x="30" y="12.5001" width="20" height="26.9999" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="2"/>
<feGaussianBlur stdDeviation="1.5"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.12549 0 0 0 0 0.0666667 0 0 0 0 0.494118 0 0 0 0.32 0"/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_449_2821"/>
</filter>
<radialGradient id="paint0_radial_449_2821" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(40 3) rotate(90) scale(52 54)">
<stop stop-color="white" stop-opacity="0.9"/>
<stop offset="1" stop-color="#4E3DB9" stop-opacity="0.24"/>
</radialGradient>
<radialGradient id="paint1_radial_449_2821" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(40 3) rotate(90) scale(52 54)">
<stop stop-color="white"/>
<stop offset="1" stop-color="#F7F7F7"/>
</radialGradient>
<radialGradient id="paint2_radial_449_2821" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(40 12.5001) rotate(90) scale(24.9999 20)">
<stop stop-color="#F5F3FF"/>
<stop stop-color="white"/>
<stop offset="1" stop-color="#E1DDF4"/>
</radialGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -1,13 +0,0 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="PaneLeft" clip-path="url(#clip0_469_1942)">
<g id="Vector">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.80217 0.525009C7.34654 0.525009 6.97717 0.894373 6.97717 1.35001V10.65C6.97717 11.1056 7.34654 11.475 7.80217 11.475H10.6522C11.1078 11.475 11.4772 11.1056 11.4772 10.65V1.35001C11.4772 0.894373 11.1078 0.525009 10.6522 0.525009H7.80217ZM8.02717 10.425V1.57501H10.4272V10.425H8.02717Z" fill="#494369"/>
<path d="M3.78215 8.14502L2.16213 6.525H5.92717V5.475H2.16213L3.78215 3.85498L3.03969 3.11252L0.523438 5.62877V6.37123L3.03969 8.88748L3.78215 8.14502Z" fill="#494369"/>
</g>
</g>
<defs>
<clipPath id="clip0_469_1942">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 807 B

View File

@ -1 +0,0 @@
"""Base template for Reflex."""

View File

@ -1,126 +0,0 @@
"""Welcome to Reflex! This file outlines the steps to create a basic app."""
from typing import Callable
import reflex as rx
from .pages import chatapp_page, datatable_page, forms_page, graphing_page, home_page
from .sidebar import sidebar
from .state import State
from .styles import *
meta = [
{
"name": "viewport",
"content": "width=device-width, shrink-to-fit=no, initial-scale=1",
},
]
def template(main_content: Callable[[], rx.Component]) -> rx.Component:
"""The template for each page of the app.
Args:
main_content (Callable[[], rx.Component]): The main content of the page.
Returns:
rx.Component: The template for each page of the app.
"""
menu_button = rx.chakra.box(
rx.chakra.menu(
rx.chakra.menu_button(
rx.chakra.icon(
tag="hamburger",
size="4em",
color=text_color,
),
),
rx.chakra.menu_list(
rx.chakra.menu_item(rx.chakra.link("Home", href="/", width="100%")),
rx.chakra.menu_divider(),
rx.chakra.menu_item(
rx.chakra.link(
"About", href="https://github.com/reflex-dev", width="100%"
)
),
rx.chakra.menu_item(
rx.chakra.link(
"Contact", href="mailto:founders@reflex.dev", width="100%"
)
),
),
),
position="fixed",
right="1.5em",
top="1.5em",
z_index="500",
)
return rx.chakra.hstack(
sidebar(),
main_content(),
rx.chakra.spacer(),
menu_button,
align_items="flex-start",
transition="left 0.5s, width 0.5s",
position="relative",
left=rx.cond(State.sidebar_displayed, "0px", f"-{sidebar_width}"),
)
@rx.page("/", meta=meta)
@template
def home() -> rx.Component:
"""Home page.
Returns:
rx.Component: The home page.
"""
return home_page()
@rx.page("/forms", meta=meta)
@template
def forms() -> rx.Component:
"""Forms page.
Returns:
rx.Component: The settings page.
"""
return forms_page()
@rx.page("/graphing", meta=meta)
@template
def graphing() -> rx.Component:
"""Graphing page.
Returns:
rx.Component: The graphing page.
"""
return graphing_page()
@rx.page("/datatable", meta=meta)
@template
def datatable() -> rx.Component:
"""Data Table page.
Returns:
rx.Component: The chatapp page.
"""
return datatable_page()
@rx.page("/chatapp", meta=meta)
@template
def chatapp() -> rx.Component:
"""Chatapp page.
Returns:
rx.Component: The chatapp page.
"""
return chatapp_page()
# Create the app.
app = rx.App(style=base_style)

View File

@ -1,6 +0,0 @@
"""The pages of the app."""
from .chatapp import chatapp_page
from .datatable import datatable_page
from .forms import forms_page
from .graphing import graphing_page
from .home import home_page

View File

@ -1,31 +0,0 @@
"""The main Chat app."""
import reflex as rx
from ..styles import *
from ..webui import styles
from ..webui.components import chat, modal, navbar, sidebar
def chatapp_page() -> rx.Component:
"""The main app.
Returns:
The UI for the main app.
"""
return rx.chakra.box(
rx.chakra.vstack(
navbar(),
chat.chat(),
chat.action_bar(),
sidebar(),
modal(),
bg=styles.bg_dark_color,
color=styles.text_light_color,
min_h="100vh",
align_items="stretch",
spacing="0",
style=template_content_style,
),
style=template_page_style,
)

View File

@ -1,359 +0,0 @@
"""The settings page for the template."""
from typing import Any
import reflex as rx
from reflex.components.datadisplay.dataeditor import DataEditorTheme
from ..styles import *
from ..webui.state import State
class DataTableState(State):
"""Datatable state."""
cols: list[Any] = [
{"title": "Title", "type": "str"},
{
"title": "Name",
"type": "str",
"group": "Data",
"width": 300,
},
{
"title": "Birth",
"type": "str",
"group": "Data",
"width": 150,
},
{
"title": "Human",
"type": "bool",
"group": "Data",
"width": 80,
},
{
"title": "House",
"type": "str",
"group": "Data",
},
{
"title": "Wand",
"type": "str",
"group": "Data",
"width": 250,
},
{
"title": "Patronus",
"type": "str",
"group": "Data",
},
{
"title": "Blood status",
"type": "str",
"group": "Data",
"width": 200,
},
]
data = [
[
"1",
"Harry James Potter",
"31 July 1980",
True,
"Gryffindor",
"11' Holly phoenix feather",
"Stag",
"Half-blood",
],
[
"2",
"Ronald Bilius Weasley",
"1 March 1980",
True,
"Gryffindor",
"12' Ash unicorn tail hair",
"Jack Russell terrier",
"Pure-blood",
],
[
"3",
"Hermione Jean Granger",
"19 September, 1979",
True,
"Gryffindor",
"10¾' vine wood dragon heartstring",
"Otter",
"Muggle-born",
],
[
"4",
"Albus Percival Wulfric Brian Dumbledore",
"Late August 1881",
True,
"Gryffindor",
"15' Elder Thestral tail hair core",
"Phoenix",
"Half-blood",
],
[
"5",
"Rubeus Hagrid",
"6 December 1928",
False,
"Gryffindor",
"16' Oak unknown core",
"None",
"Part-Human (Half-giant)",
],
[
"6",
"Fred Weasley",
"1 April, 1978",
True,
"Gryffindor",
"Unknown",
"Unknown",
"Pure-blood",
],
[
"7",
"George Weasley",
"1 April, 1978",
True,
"Gryffindor",
"Unknown",
"Unknown",
"Pure-blood",
],
]
code_show = """rx.chakra.hstack(
rx.chakra.divider(orientation="vertical", height="100vh", border="solid black 1px"),
rx.chakra.vstack(
rx.chakra.box(
rx.data_editor(
columns=DataTableState.cols,
data=DataTableState.data,
draw_focus_ring=True,
row_height=50,
smooth_scroll_x=True,
smooth_scroll_y=True,
column_select="single",
# style
theme=DataEditorTheme(**darkTheme),
width="80vw",
height="80vh",
),
),
rx.chakra.spacer(),
height="100vh",
spacing="25",
),
)"""
state_show = """class DataTableState(State):
cols: list[Any] = [
{"title": "Title", "type": "str"},
{
"title": "Name",
"type": "str",
"group": "Data",
"width": 300,
},
{
"title": "Birth",
"type": "str",
"group": "Data",
"width": 150,
},
{
"title": "Human",
"type": "bool",
"group": "Data",
"width": 80,
},
{
"title": "House",
"type": "str",
"group": "Data",
},
{
"title": "Wand",
"type": "str",
"group": "Data",
"width": 250,
},
{
"title": "Patronus",
"type": "str",
"group": "Data",
},
{
"title": "Blood status",
"type": "str",
"group": "Data",
"width": 200,
},
]"""
data_show = """[
["1", "Harry James Potter", "31 July 1980", True, "Gryffindor", "11' Holly phoenix feather", "Stag", "Half-blood"],
["2", "Ronald Bilius Weasley", "1 March 1980", True,"Gryffindor", "12' Ash unicorn tail hair", "Jack Russell terrier", "Pure-blood"],
["3", "Hermione Jean Granger", "19 September, 1979", True, "Gryffindor", "10¾' vine wood dragon heartstring", "Otter", "Muggle-born"],
["4", "Albus Percival Wulfric Brian Dumbledore", "Late August 1881", True, "Gryffindor", "15' Elder Thestral tail hair core", "Phoenix", "Half-blood"],
["5", "Rubeus Hagrid", "6 December 1928", False, "Gryffindor", "16' Oak unknown core", "None", "Part-Human (Half-giant)"],
["6", "Fred Weasley", "1 April, 1978", True, "Gryffindor", "Unknown", "Unknown", "Pure-blood"],
["7", "George Weasley", "1 April, 1978", True, "Gryffindor", "Unknown", "Unknown", "Pure-blood"],
]"""
darkTheme = {
"accent_color": "#8c96ff",
"accent_light": "rgba(202, 206, 255, 0.253)",
"text_dark": "#ffffff",
"text_medium": "#b8b8b8",
"text_light": "#a0a0a0",
"text_bubble": "#ffffff",
"bg_icon_header": "#b8b8b8",
"fg_icon_header": "#000000",
"text_header": "#a1a1a1",
"text_header_selected": "#000000",
"bg_cell": "#16161b",
"bg_cell_medium": "#202027",
"bg_header": "#212121",
"bg_header_has_focus": "#474747",
"bg_header_hovered": "#404040",
"bg_bubble": "#212121",
"bg_bubble_selected": "#000000",
"bg_search_result": "#423c24",
"border_color": "rgba(225,225,225,0.2)",
"drilldown_border": "rgba(225,225,225,0.4)",
"link_color": "#4F5DFF",
"header_font_style": "bold 14px",
"base_font_style": "13px",
"font_family": "Inter, Roboto, -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Ubuntu, noto, arial, sans-serif",
}
darkTheme_show = """darkTheme={
"accent_color": "#8c96ff",
"accent_light": "rgba(202, 206, 255, 0.253)",
"text_dark": "#ffffff",
"text_medium": "#b8b8b8",
"text_light": "#a0a0a0",
"text_bubble": "#ffffff",
"bg_icon_header": "#b8b8b8",
"fg_icon_header": "#000000",
"text_header": "#a1a1a1",
"text_header_selected": "#000000",
"bg_cell": "#16161b",
"bg_cell_medium": "#202027",
"bg_header": "#212121",
"bg_header_has_focus": "#474747",
"bg_header_hovered": "#404040",
"bg_bubble": "#212121",
"bg_bubble_selected": "#000000",
"bg_search_result": "#423c24",
"border_color": "rgba(225,225,225,0.2)",
"drilldown_border": "rgba(225,225,225,0.4)",
"link_color": "#4F5DFF",
"header_font_style": "bold 14px",
"base_font_style": "13px",
"font_family": "Inter, Roboto, -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Ubuntu, noto, arial, sans-serif",
}"""
def datatable_page() -> rx.Component:
"""The UI for the settings page.
Returns:
rx.Component: The UI for the settings page.
"""
return rx.chakra.box(
rx.chakra.vstack(
rx.chakra.heading(
"Data Table Demo",
font_size="3em",
),
rx.chakra.hstack(
rx.chakra.vstack(
rx.chakra.box(
rx.data_editor(
columns=DataTableState.cols,
data=DataTableState.data,
draw_focus_ring=True,
row_height=50,
smooth_scroll_x=True,
smooth_scroll_y=True,
column_select="single",
# style
theme=DataEditorTheme(**darkTheme),
width="80vw",
),
),
rx.chakra.spacer(),
spacing="25",
),
),
rx.chakra.tabs(
rx.chakra.tab_list(
rx.chakra.tab("Code", style=tab_style),
rx.chakra.tab("Data", style=tab_style),
rx.chakra.tab("State", style=tab_style),
rx.chakra.tab("Styling", style=tab_style),
padding_x=0,
),
rx.chakra.tab_panels(
rx.chakra.tab_panel(
rx.code_block(
code_show,
language="python",
show_line_numbers=True,
),
width="100%",
padding_x=0,
padding_y=".25em",
),
rx.chakra.tab_panel(
rx.code_block(
data_show,
language="python",
show_line_numbers=True,
),
width="100%",
padding_x=0,
padding_y=".25em",
),
rx.chakra.tab_panel(
rx.code_block(
state_show,
language="python",
show_line_numbers=True,
),
width="100%",
padding_x=0,
padding_y=".25em",
),
rx.chakra.tab_panel(
rx.code_block(
darkTheme_show,
language="python",
show_line_numbers=True,
),
width="100%",
padding_x=0,
padding_y=".25em",
),
width="100%",
),
variant="unstyled",
color_scheme="purple",
align="end",
width="100%",
padding_top=".5em",
),
style=template_content_style,
),
style=template_page_style,
)

View File

@ -1,256 +0,0 @@
"""The settings page for the template."""
import reflex as rx
from ..states.form_state import FormState, UploadState
from ..styles import *
forms_1_code = """rx.chakra.vstack(
rx.chakra.form(
rx.chakra.vstack(
rx.chakra.input(
placeholder="First Name",
id="first_name",
),
rx.chakra.input(
placeholder="Last Name", id="last_name"
),
rx.chakra.hstack(
rx.chakra.checkbox("Checked", id="check"),
rx.chakra.switch("Switched", id="switch"),
),
rx.chakra.button("Submit",
type_="submit",
bg="#ecfdf5",
color="#047857",
border_radius="lg",
),
),
on_submit=FormState.handle_submit,
),
rx.chakra.divider(),
rx.chakra.heading("Results"),
rx.chakra.text(FormState.form_data.to_string()),
width="100%",
)"""
color = "rgb(107,99,246)"
forms_1_state = """class FormState(rx.State):
form_data: dict = {}
def handle_submit(self, form_data: dict):
"Handle the form submit."
self.form_data = form_data"""
forms_2_code = """rx.chakra.vstack(
rx.upload(
rx.chakra.vstack(
rx.chakra.button(
"Select File",
color=color,
bg="white",
border=f"1px solid {color}",
),
rx.chakra.text(
"Drag and drop files here or click to select files"
),
),
border=f"1px dotted {color}",
padding="5em",
),
rx.chakra.hstack(rx.foreach(rx.selected_files, rx.chakra.text)),
rx.chakra.button(
"Upload",
on_click=lambda: UploadState.handle_upload(
rx.upload_files()
),
),
rx.chakra.button(
"Clear",
on_click=rx.clear_selected_files,
),
rx.foreach(
UploadState.img, lambda img: rx.chakra.image(src=img, width="20%", height="auto",)
),
padding="5em",
width="100%",
)"""
forms_2_state = """class UploadState(State):
"The app state."
# The images to show.
img: list[str]
async def handle_upload(
self, files: list[rx.UploadFile]
):
"Handle the upload of file(s).
Args:
files: The uploaded files.
"
for file in files:
upload_data = await file.read()
outfile = rx.get_asset_path(file.filename)
# Save the file.
with open(outfile, "wb") as file_object:
file_object.write(upload_data)
# Update the img var.
self.img.append(f"/{file.filename}")"""
def forms_page() -> rx.Component:
"""The UI for the settings page.
Returns:
rx.Component: The UI for the settings page.
"""
return rx.chakra.box(
rx.chakra.vstack(
rx.chakra.heading(
"Forms Demo",
font_size="3em",
),
rx.chakra.vstack(
rx.chakra.form(
rx.chakra.vstack(
rx.chakra.input(
placeholder="First Name",
id="first_name",
),
rx.chakra.input(placeholder="Last Name", id="last_name"),
rx.chakra.hstack(
rx.chakra.checkbox("Checked", id="check"),
rx.chakra.switch("Switched", id="switch"),
),
rx.chakra.button(
"Submit",
type_="submit",
bg="#ecfdf5",
color="#047857",
border_radius="lg",
),
),
on_submit=FormState.handle_submit,
),
rx.chakra.divider(),
rx.chakra.heading("Results"),
rx.chakra.text(FormState.form_data.to_string()),
width="100%",
),
rx.chakra.tabs(
rx.chakra.tab_list(
rx.chakra.tab("Code", style=tab_style),
rx.chakra.tab("State", style=tab_style),
padding_x=0,
),
rx.chakra.tab_panels(
rx.chakra.tab_panel(
rx.code_block(
forms_1_code,
language="python",
show_line_numbers=True,
),
width="100%",
padding_x=0,
padding_y=".25em",
),
rx.chakra.tab_panel(
rx.code_block(
forms_1_state,
language="python",
show_line_numbers=True,
),
width="100%",
padding_x=0,
padding_y=".25em",
),
width="100%",
),
variant="unstyled",
color_scheme="purple",
align="end",
width="100%",
padding_top=".5em",
),
rx.chakra.heading("Upload Example", font_size="3em"),
rx.chakra.text("Try uploading some images and see how they look."),
rx.chakra.vstack(
rx.upload(
rx.chakra.vstack(
rx.chakra.button(
"Select File",
color=color,
bg="white",
border=f"1px solid {color}",
),
rx.chakra.text(
"Drag and drop files here or click to select files"
),
),
border=f"1px dotted {color}",
padding="5em",
),
rx.chakra.hstack(rx.foreach(rx.selected_files, rx.chakra.text)),
rx.chakra.button(
"Upload",
on_click=lambda: UploadState.handle_upload(rx.upload_files()),
),
rx.chakra.button(
"Clear",
on_click=rx.clear_selected_files,
),
rx.foreach(
UploadState.img,
lambda img: rx.chakra.image(
src=img,
width="20%",
height="auto",
),
),
padding="5em",
width="100%",
),
rx.chakra.tabs(
rx.chakra.tab_list(
rx.chakra.tab("Code", style=tab_style),
rx.chakra.tab("State", style=tab_style),
padding_x=0,
),
rx.chakra.tab_panels(
rx.chakra.tab_panel(
rx.code_block(
forms_2_code,
language="python",
show_line_numbers=True,
),
width="100%",
padding_x=0,
padding_y=".25em",
),
rx.chakra.tab_panel(
rx.code_block(
forms_2_state,
language="python",
show_line_numbers=True,
),
width="100%",
padding_x=0,
padding_y=".25em",
),
width="100%",
),
variant="unstyled",
color_scheme="purple",
align="end",
width="100%",
padding_top=".5em",
),
style=template_content_style,
),
style=template_page_style,
)

View File

@ -1,252 +0,0 @@
"""The dashboard page for the template."""
import reflex as rx
from ..states.pie_state import PieChartState
from ..styles import *
data_1 = [
{"name": "Page A", "uv": 4000, "pv": 2400, "amt": 2400},
{"name": "Page B", "uv": 3000, "pv": 1398, "amt": 2210},
{"name": "Page C", "uv": 2000, "pv": 9800, "amt": 2290},
{"name": "Page D", "uv": 2780, "pv": 3908, "amt": 2000},
{"name": "Page E", "uv": 1890, "pv": 4800, "amt": 2181},
{"name": "Page F", "uv": 2390, "pv": 3800, "amt": 2500},
{"name": "Page G", "uv": 3490, "pv": 4300, "amt": 2100},
]
data_1_show = """[
{"name": "Page A", "uv": 4000, "pv": 2400, "amt": 2400},
{"name": "Page B", "uv": 3000, "pv": 1398, "amt": 2210},
{"name": "Page C", "uv": 2000, "pv": 9800, "amt": 2290},
{"name": "Page D", "uv": 2780, "pv": 3908, "amt": 2000},
{"name": "Page E", "uv": 1890, "pv": 4800, "amt": 2181},
{"name": "Page F", "uv": 2390, "pv": 3800, "amt": 2500},
{"name": "Page G", "uv": 3490, "pv": 4300, "amt": 2100},
]"""
graph_1_code = """rx.recharts.composed_chart(
rx.recharts.area(
data_key="uv", stroke="#8884d8", fill="#8884d8"
),
rx.recharts.bar(
data_key="amt", bar_size=20, fill="#413ea0"
),
rx.recharts.line(
data_key="pv", type_="monotone", stroke="#ff7300"
),
rx.recharts.x_axis(data_key="name"),
rx.recharts.y_axis(),
rx.recharts.cartesian_grid(stroke_dasharray="3 3"),
rx.recharts.graphing_tooltip(),
data=data,
)"""
graph_2_code = """rx.recharts.pie_chart(
rx.recharts.pie(
data=PieChartState.resources,
data_key="count",
name_key="type_",
cx="50%",
cy="50%",
start_angle=180,
end_angle=0,
fill="#8884d8",
label=True,
),
rx.recharts.graphing_tooltip(),
),
rx.chakra.vstack(
rx.foreach(
PieChartState.resource_types,
lambda type_, i: rx.chakra.hstack(
rx.chakra.button(
"-",
on_click=PieChartState.decrement(type_),
),
rx.chakra.text(
type_,
PieChartState.resources[i]["count"],
),
rx.chakra.button(
"+",
on_click=PieChartState.increment(type_),
),
),
),
)"""
graph_2_state = """class PieChartState(rx.State):
resources: list[dict[str, Any]] = [
dict(type_="🏆", count=1),
dict(type_="🪵", count=1),
dict(type_="🥑", count=1),
dict(type_="🧱", count=1),
]
@rx.cached_var
def resource_types(self) -> list[str]:
return [r["type_"] for r in self.resources]
def increment(self, type_: str):
for resource in self.resources:
if resource["type_"] == type_:
resource["count"] += 1
break
def decrement(self, type_: str):
for resource in self.resources:
if (
resource["type_"] == type_
and resource["count"] > 0
):
resource["count"] -= 1
break
"""
def graphing_page() -> rx.Component:
"""The UI for the dashboard page.
Returns:
rx.Component: The UI for the dashboard page.
"""
return rx.chakra.box(
rx.chakra.vstack(
rx.chakra.heading(
"Graphing Demo",
font_size="3em",
),
rx.chakra.heading(
"Composed Chart",
font_size="2em",
),
rx.chakra.stack(
rx.recharts.composed_chart(
rx.recharts.area(data_key="uv", stroke="#8884d8", fill="#8884d8"),
rx.recharts.bar(data_key="amt", bar_size=20, fill="#413ea0"),
rx.recharts.line(data_key="pv", type_="monotone", stroke="#ff7300"),
rx.recharts.x_axis(data_key="name"),
rx.recharts.y_axis(),
rx.recharts.cartesian_grid(stroke_dasharray="3 3"),
rx.recharts.graphing_tooltip(),
data=data_1,
# height="15em",
),
width="100%",
height="20em",
),
rx.chakra.tabs(
rx.chakra.tab_list(
rx.chakra.tab("Code", style=tab_style),
rx.chakra.tab("Data", style=tab_style),
padding_x=0,
),
rx.chakra.tab_panels(
rx.chakra.tab_panel(
rx.code_block(
graph_1_code,
language="python",
show_line_numbers=True,
),
width="100%",
padding_x=0,
padding_y=".25em",
),
rx.chakra.tab_panel(
rx.code_block(
data_1_show,
language="python",
show_line_numbers=True,
),
width="100%",
padding_x=0,
padding_y=".25em",
),
width="100%",
),
variant="unstyled",
color_scheme="purple",
align="end",
width="100%",
padding_top=".5em",
),
rx.chakra.heading("Interactive Example", font_size="2em"),
rx.chakra.hstack(
rx.recharts.pie_chart(
rx.recharts.pie(
data=PieChartState.resources,
data_key="count",
name_key="type_",
cx="50%",
cy="50%",
start_angle=180,
end_angle=0,
fill="#8884d8",
label=True,
),
rx.recharts.graphing_tooltip(),
),
rx.chakra.vstack(
rx.foreach(
PieChartState.resource_types,
lambda type_, i: rx.chakra.hstack(
rx.chakra.button(
"-",
on_click=PieChartState.decrement(type_),
),
rx.chakra.text(
type_,
PieChartState.resources[i]["count"],
),
rx.chakra.button(
"+",
on_click=PieChartState.increment(type_),
),
),
),
),
width="100%",
height="15em",
),
rx.chakra.tabs(
rx.chakra.tab_list(
rx.chakra.tab("Code", style=tab_style),
rx.chakra.tab("State", style=tab_style),
padding_x=0,
),
rx.chakra.tab_panels(
rx.chakra.tab_panel(
rx.code_block(
graph_2_code,
language="python",
show_line_numbers=True,
),
width="100%",
padding_x=0,
padding_y=".25em",
),
rx.chakra.tab_panel(
rx.code_block(
graph_2_state,
language="python",
show_line_numbers=True,
),
width="100%",
padding_x=0,
padding_y=".25em",
),
width="100%",
),
variant="unstyled",
color_scheme="purple",
align="end",
width="100%",
padding_top=".5em",
),
style=template_content_style,
min_h="100vh",
),
style=template_page_style,
min_h="100vh",
)

View File

@ -1,55 +0,0 @@
"""The home page of the app."""
import reflex as rx
from ..styles import *
def home_page() -> rx.Component:
"""The UI for the home page.
Returns:
rx.Component: The UI for the home page.
"""
return rx.chakra.box(
rx.chakra.vstack(
rx.chakra.heading(
"Welcome to Reflex! 👋",
font_size="3em",
),
rx.chakra.text(
"Reflex is an open-source app framework built specifically to allow you to build web apps in pure python. 👈 Select a demo from the sidebar to see some examples of what Reflex can do!",
),
rx.chakra.heading(
"Things to check out:",
font_size="2em",
),
rx.chakra.unordered_list(
rx.chakra.list_item(
"Take a look at ",
rx.chakra.link(
"reflex.dev",
href="https://reflex.dev",
color="rgb(107,99,246)",
),
),
rx.chakra.list_item(
"Check out our ",
rx.chakra.link(
"docs",
href="https://reflex.dev/docs/getting-started/introduction/",
color="rgb(107,99,246)",
),
),
rx.chakra.list_item(
"Ask a question in our ",
rx.chakra.link(
"community",
href="https://discord.gg/T5WSbC2YtQ",
color="rgb(107,99,246)",
),
),
),
style=template_content_style,
),
style=template_page_style,
)

View File

@ -1,178 +0,0 @@
"""Sidebar component for the app."""
import reflex as rx
from .state import State
from .styles import *
def sidebar_header() -> rx.Component:
"""Sidebar header.
Returns:
rx.Component: The sidebar header component.
"""
return rx.chakra.hstack(
rx.chakra.image(
src="/icon.svg",
height="2em",
),
rx.chakra.spacer(),
rx.chakra.link(
rx.chakra.center(
rx.chakra.image(
src="/github.svg",
height="3em",
padding="0.5em",
),
box_shadow=box_shadow,
bg="transparent",
border_radius=border_radius,
_hover={
"bg": accent_color,
},
),
href="https://github.com/reflex-dev/reflex",
),
width="100%",
border_bottom=border,
padding="1em",
)
def sidebar_footer() -> rx.Component:
"""Sidebar footer.
Returns:
rx.Component: The sidebar footer component.
"""
return rx.chakra.hstack(
rx.chakra.link(
rx.chakra.center(
rx.chakra.image(
src="/paneleft.svg",
height="2em",
padding="0.5em",
),
bg="transparent",
border_radius=border_radius,
**hover_accent_bg,
),
on_click=State.toggle_sidebar_displayed,
transform=rx.cond(~State.sidebar_displayed, "rotate(180deg)", ""),
transition="transform 0.5s, left 0.5s",
position="relative",
left=rx.cond(State.sidebar_displayed, "0px", "20.5em"),
**overlapping_button_style,
),
rx.chakra.spacer(),
rx.chakra.link(
rx.chakra.text(
"Docs",
),
href="https://reflex.dev/docs/getting-started/introduction/",
),
rx.chakra.link(
rx.chakra.text(
"Blog",
),
href="https://reflex.dev/blog/",
),
width="100%",
border_top=border,
padding="1em",
)
def sidebar_item(text: str, icon: str, url: str) -> rx.Component:
"""Sidebar item.
Args:
text (str): The text of the item.
icon (str): The icon of the item.
url (str): The URL of the item.
Returns:
rx.Component: The sidebar item component.
"""
return rx.chakra.link(
rx.chakra.hstack(
rx.chakra.image(
src=icon,
height="2.5em",
padding="0.5em",
),
rx.chakra.text(
text,
),
bg=rx.cond(
State.origin_url == f"/{text.lower()}/",
accent_color,
"transparent",
),
color=rx.cond(
State.origin_url == f"/{text.lower()}/",
accent_text_color,
text_color,
),
border_radius=border_radius,
box_shadow=box_shadow,
width="100%",
padding_x="1em",
),
href=url,
width="100%",
)
def sidebar() -> rx.Component:
"""Sidebar.
Returns:
rx.Component: The sidebar component.
"""
return rx.chakra.box(
rx.chakra.vstack(
sidebar_header(),
rx.chakra.vstack(
sidebar_item(
"Welcome",
"/github.svg",
"/",
),
sidebar_item(
"Graphing Demo",
"/github.svg",
"/graphing",
),
sidebar_item(
"Data Table Demo",
"/github.svg",
"/datatable",
),
sidebar_item(
"Forms Demo",
"/github.svg",
"/forms",
),
sidebar_item(
"Chat App Demo",
"/github.svg",
"/chatapp",
),
width="100%",
overflow_y="auto",
align_items="flex-start",
padding="1em",
),
rx.chakra.spacer(),
sidebar_footer(),
height="100dvh",
),
display=["none", "none", "block"],
min_width=sidebar_width,
height="100%",
position="sticky",
top="0px",
border_right=border,
)

View File

@ -1,22 +0,0 @@
"""Base state for the app."""
import reflex as rx
class State(rx.State):
"""State for the app."""
sidebar_displayed: bool = True
@rx.var
def origin_url(self) -> str:
"""Get the url of the current page.
Returns:
str: The url of the current page.
"""
return self.router_data.get("asPath", "")
def toggle_sidebar_displayed(self) -> None:
"""Toggle the sidebar displayed."""
self.sidebar_displayed = not self.sidebar_displayed

View File

@ -1,40 +0,0 @@
import reflex as rx
from ..state import State
class FormState(State):
"""Form state."""
form_data: dict = {}
def handle_submit(self, form_data: dict):
"""Handle the form submit.
Args:
form_data: The form data.
"""
self.form_data = form_data
class UploadState(State):
"""The app state."""
# The images to show.
img: list[str]
async def handle_upload(self, files: list[rx.UploadFile]):
"""Handle the upload of file(s).
Args:
files: The uploaded files.
"""
for file in files:
upload_data = await file.read()
outfile = rx.get_asset_path(file.filename)
# Save the file.
with open(outfile, "wb") as file_object:
file_object.write(upload_data)
# Update the img var.
self.img.append(f"/{file.filename}")

View File

@ -1,47 +0,0 @@
from typing import Any
import reflex as rx
from ..state import State
class PieChartState(State):
"""Pie Chart State."""
resources: list[dict[str, Any]] = [
dict(type_="🏆", count=1),
dict(type_="🪵", count=1),
dict(type_="🥑", count=1),
dict(type_="🧱", count=1),
]
@rx.cached_var
def resource_types(self) -> list[str]:
"""Get the resource types.
Returns:
The resource types.
"""
return [r["type_"] for r in self.resources]
def increment(self, type_: str):
"""Increment the count of a resource type.
Args:
type_: The type of resource to increment.
"""
for resource in self.resources:
if resource["type_"] == type_:
resource["count"] += 1
break
def decrement(self, type_: str):
"""Decrement the count of a resource type.
Args:
type_: The type of resource to decrement.
"""
for resource in self.resources:
if resource["type_"] == type_ and resource["count"] > 0:
resource["count"] -= 1
break

View File

@ -1,67 +0,0 @@
"""Styles for the app."""
import reflex as rx
from .state import State
border_radius = "0.375rem"
box_shadow = "0px 0px 0px 1px rgba(84, 82, 95, 0.14)"
border = "1px solid #F4F3F6"
text_color = "black"
accent_text_color = "#1A1060"
accent_color = "#F5EFFE"
hover_accent_color = {"_hover": {"color": accent_color}}
hover_accent_bg = {"_hover": {"bg": accent_color}}
content_width_vw = "90vw"
sidebar_width = "20em"
template_page_style = {
"padding_top": "5em",
"padding_x": "2em",
}
template_content_style = {
"width": rx.cond(
State.sidebar_displayed,
f"calc({content_width_vw} - {sidebar_width})",
content_width_vw,
),
"min-width": sidebar_width,
"align_items": "flex-start",
"box_shadow": box_shadow,
"border_radius": border_radius,
"padding": "1em",
"margin_bottom": "2em",
}
link_style = {
"color": text_color,
"text_decoration": "none",
**hover_accent_color,
}
overlapping_button_style = {
"background_color": "white",
"border": border,
"border_radius": border_radius,
}
base_style = {
rx.chakra.MenuButton: {
"width": "3em",
"height": "3em",
**overlapping_button_style,
},
rx.chakra.MenuItem: hover_accent_bg,
}
tab_style = {
"color": "#494369",
"font_weight": 600,
"_selected": {
"color": "#5646ED",
"bg": "#F5EFFE",
"padding_x": "0.5em",
"padding_y": "0.25em",
"border_radius": "8px",
},
}

View File

@ -1,4 +0,0 @@
from .loading_icon import loading_icon
from .modal import modal
from .navbar import navbar
from .sidebar import sidebar

View File

@ -1,118 +0,0 @@
import reflex as rx
from ...webui import styles
from ...webui.components import loading_icon
from ...webui.state import QA, State
def message(qa: QA) -> rx.Component:
"""A single question/answer message.
Args:
qa: The question/answer pair.
Returns:
A component displaying the question/answer pair.
"""
return rx.chakra.box(
rx.chakra.box(
rx.chakra.text(
qa.question,
bg=styles.border_color,
shadow=styles.shadow_light,
**styles.message_style,
),
text_align="right",
margin_top="1em",
),
rx.chakra.box(
rx.chakra.text(
qa.answer,
bg=styles.accent_color,
shadow=styles.shadow_light,
**styles.message_style,
),
text_align="left",
padding_top="1em",
),
width="100%",
)
def chat() -> rx.Component:
"""List all the messages in a single conversation.
Returns:
A component displaying all the messages in a single conversation.
"""
return rx.chakra.vstack(
rx.chakra.box(rx.foreach(State.chats[State.current_chat], message)),
py="8",
flex="1",
width="100%",
max_w="3xl",
padding_x="4",
align_self="center",
overflow="hidden",
padding_bottom="5em",
**styles.base_style[rx.chakra.Vstack],
)
def action_bar() -> rx.Component:
"""The action bar to send a new message.
Returns:
The action bar to send a new message.
"""
return rx.chakra.box(
rx.chakra.vstack(
rx.chakra.form(
rx.chakra.form_control(
rx.chakra.hstack(
rx.chakra.input(
placeholder="Type something...",
value=State.question,
on_change=State.set_question,
_placeholder={"color": "#fffa"},
_hover={"border_color": styles.accent_color},
style=styles.input_style,
),
rx.chakra.button(
rx.cond(
State.processing,
loading_icon(height="1em"),
rx.chakra.text("Send"),
),
type_="submit",
_hover={"bg": styles.accent_color},
style=styles.input_style,
),
**styles.base_style[rx.chakra.Hstack],
),
is_disabled=State.processing,
),
on_submit=State.process_question,
width="100%",
),
rx.chakra.text(
"ReflexGPT may return factually incorrect or misleading responses. Use discretion.",
font_size="xs",
color="#fff6",
text_align="center",
),
width="100%",
max_w="3xl",
mx="auto",
**styles.base_style[rx.chakra.Vstack],
),
position="sticky",
bottom="0",
left="0",
py="4",
backdrop_filter="auto",
backdrop_blur="lg",
border_top=f"1px solid {styles.border_color}",
align_items="stretch",
width="100%",
)

View File

@ -1,26 +0,0 @@
import reflex as rx
class LoadingIcon(rx.Component):
"""A custom loading icon component."""
library = "react-loading-icons"
tag = "SpinningCircles"
stroke: rx.Var[str]
stroke_opacity: rx.Var[str]
fill: rx.Var[str]
fill_opacity: rx.Var[str]
stroke_width: rx.Var[str]
speed: rx.Var[str]
height: rx.Var[str]
def get_event_triggers(self) -> dict:
"""Get the event triggers that pass the component's value to the handler.
Returns:
A dict mapping the event trigger to the var that is passed to the handler.
"""
return {"on_change": lambda status: [status]}
loading_icon = LoadingIcon.create

View File

@ -1,56 +0,0 @@
import reflex as rx
from ...webui.state import State
def modal() -> rx.Component:
"""A modal to create a new chat.
Returns:
The modal component.
"""
return rx.chakra.modal(
rx.chakra.modal_overlay(
rx.chakra.modal_content(
rx.chakra.modal_header(
rx.chakra.hstack(
rx.chakra.text("Create new chat"),
rx.chakra.icon(
tag="close",
font_size="sm",
on_click=State.toggle_modal,
color="#fff8",
_hover={"color": "#fff"},
cursor="pointer",
),
align_items="center",
justify_content="space-between",
)
),
rx.chakra.modal_body(
rx.chakra.input(
placeholder="Type something...",
on_blur=State.set_new_chat_name,
bg="#222",
border_color="#fff3",
_placeholder={"color": "#fffa"},
),
),
rx.chakra.modal_footer(
rx.chakra.button(
"Create",
bg="#5535d4",
box_shadow="md",
px="4",
py="2",
h="auto",
_hover={"bg": "#4c2db3"},
on_click=State.create_chat,
),
),
bg="#222",
color="#fff",
),
),
is_open=State.modal_open,
)

View File

@ -1,70 +0,0 @@
import reflex as rx
from ...webui import styles
from ...webui.state import State
def navbar():
return rx.chakra.box(
rx.chakra.hstack(
rx.chakra.hstack(
rx.chakra.icon(
tag="hamburger",
mr=4,
on_click=State.toggle_drawer,
cursor="pointer",
),
rx.chakra.link(
rx.chakra.box(
rx.chakra.image(src="favicon.ico", width=30, height="auto"),
p="1",
border_radius="6",
bg="#F0F0F0",
mr="2",
),
href="/",
),
rx.chakra.breadcrumb(
rx.chakra.breadcrumb_item(
rx.chakra.heading("ReflexGPT", size="sm"),
),
rx.chakra.breadcrumb_item(
rx.chakra.text(
State.current_chat, size="sm", font_weight="normal"
),
),
),
),
rx.chakra.hstack(
rx.chakra.button(
"+ New chat",
bg=styles.accent_color,
px="4",
py="2",
h="auto",
on_click=State.toggle_modal,
),
rx.chakra.menu(
rx.chakra.menu_button(
rx.chakra.avatar(name="User", size="md"),
rx.chakra.box(),
),
rx.chakra.menu_list(
rx.chakra.menu_item("Help"),
rx.chakra.menu_divider(),
rx.chakra.menu_item("Settings"),
),
),
spacing="8",
),
justify="space-between",
),
bg=styles.bg_dark_color,
backdrop_filter="auto",
backdrop_blur="lg",
p="4",
border_bottom=f"1px solid {styles.border_color}",
position="sticky",
top="0",
z_index="100",
)

View File

@ -1,66 +0,0 @@
import reflex as rx
from ...webui import styles
from ...webui.state import State
def sidebar_chat(chat: str) -> rx.Component:
"""A sidebar chat item.
Args:
chat: The chat item.
Returns:
The sidebar chat item.
"""
return rx.chakra.hstack(
rx.chakra.box(
chat,
on_click=lambda: State.set_chat(chat),
style=styles.sidebar_style,
color=styles.icon_color,
flex="1",
),
rx.chakra.box(
rx.chakra.icon(
tag="delete",
style=styles.icon_style,
on_click=State.delete_chat,
),
style=styles.sidebar_style,
),
color=styles.text_light_color,
cursor="pointer",
)
def sidebar() -> rx.Component:
"""The sidebar component.
Returns:
The sidebar component.
"""
return rx.chakra.drawer(
rx.chakra.drawer_overlay(
rx.chakra.drawer_content(
rx.chakra.drawer_header(
rx.chakra.hstack(
rx.chakra.text("Chats"),
rx.chakra.icon(
tag="close",
on_click=State.toggle_drawer,
style=styles.icon_style,
),
)
),
rx.chakra.drawer_body(
rx.chakra.vstack(
rx.foreach(State.chat_titles, lambda chat: sidebar_chat(chat)),
align_items="stretch",
)
),
),
),
placement="left",
is_open=State.drawer_open,
)

View File

@ -1,145 +0,0 @@
import asyncio
import reflex as rx
from ..state import State
# openai.api_key = os.environ["OPENAI_API_KEY"]
# openai.api_base = os.getenv("OPENAI_API_BASE", "https://api.openai.com/v1")
class QA(rx.Base):
"""A question and answer pair."""
question: str
answer: str
DEFAULT_CHATS = {
"Intros": [],
}
class State(State):
"""The app state."""
# A dict from the chat name to the list of questions and answers.
chats: dict[str, list[QA]] = DEFAULT_CHATS
# The current chat name.
current_chat = "Intros"
# The current question.
question: str
# Whether we are processing the question.
processing: bool = False
# The name of the new chat.
new_chat_name: str = ""
# Whether the drawer is open.
drawer_open: bool = False
# Whether the modal is open.
modal_open: bool = False
def create_chat(self):
"""Create a new chat."""
# Add the new chat to the list of chats.
self.current_chat = self.new_chat_name
self.chats[self.new_chat_name] = []
# Toggle the modal.
self.modal_open = False
def toggle_modal(self):
"""Toggle the new chat modal."""
self.modal_open = not self.modal_open
def toggle_drawer(self):
"""Toggle the drawer."""
self.drawer_open = not self.drawer_open
def delete_chat(self):
"""Delete the current chat."""
del self.chats[self.current_chat]
if len(self.chats) == 0:
self.chats = DEFAULT_CHATS
self.current_chat = list(self.chats.keys())[0]
self.toggle_drawer()
def set_chat(self, chat_name: str):
"""Set the name of the current chat.
Args:
chat_name: The name of the chat.
"""
self.current_chat = chat_name
self.toggle_drawer()
@rx.var
def chat_titles(self) -> list[str]:
"""Get the list of chat titles.
Returns:
The list of chat names.
"""
return list(self.chats.keys())
async def process_question(self, form_data: dict[str, str]):
"""Get the response from the API.
Args:
form_data: A dict with the current question.
Yields:
The current question and the response.
"""
# Check if the question is empty
if self.question == "":
return
# Add the question to the list of questions.
qa = QA(question=self.question, answer="")
self.chats[self.current_chat].append(qa)
# Clear the input and start the processing.
self.processing = True
self.question = ""
yield
# # Build the messages.
# messages = [
# {"role": "system", "content": "You are a friendly chatbot named Reflex."}
# ]
# for qa in self.chats[self.current_chat]:
# messages.append({"role": "user", "content": qa.question})
# messages.append({"role": "assistant", "content": qa.answer})
# # Remove the last mock answer.
# messages = messages[:-1]
# Start a new session to answer the question.
# session = openai.ChatCompletion.create(
# model=os.getenv("OPENAI_MODEL", "gpt-3.5-turbo"),
# messages=messages,
# stream=True,
# )
# Stream the results, yielding after every word.
# for item in session:
answer = "I don't know! This Chatbot still needs to add in AI API keys!"
for i in range(len(answer)):
# Pause to show the streaming effect.
await asyncio.sleep(0.1)
# Add one letter at a time to the output.
# if hasattr(item.choices[0].delta, "content"):
# answer_text = item.choices[0].delta.content
self.chats[self.current_chat][-1].answer += answer[i]
self.chats = self.chats
yield
# Toggle the processing flag.
self.processing = False

View File

@ -1,88 +0,0 @@
import reflex as rx
bg_dark_color = "#111"
bg_medium_color = "#222"
border_color = "#fff3"
accennt_light = "#6649D8"
accent_color = "#5535d4"
accent_dark = "#4c2db3"
icon_color = "#fff8"
text_light_color = "#fff"
shadow_light = "rgba(17, 12, 46, 0.15) 0px 48px 100px 0px;"
shadow = "rgba(50, 50, 93, 0.25) 0px 50px 100px -20px, rgba(0, 0, 0, 0.3) 0px 30px 60px -30px, rgba(10, 37, 64, 0.35) 0px -2px 6px 0px inset;"
message_style = dict(display="inline-block", p="4", border_radius="xl", max_w="30em")
input_style = dict(
bg=bg_medium_color,
border_color=border_color,
border_width="1px",
p="4",
)
icon_style = dict(
font_size="md",
color=icon_color,
_hover=dict(color=text_light_color),
cursor="pointer",
w="8",
)
sidebar_style = dict(
border="double 1px transparent;",
border_radius="10px;",
background_image=f"linear-gradient({bg_dark_color}, {bg_dark_color}), radial-gradient(circle at top left, {accent_color},{accent_dark});",
background_origin="border-box;",
background_clip="padding-box, border-box;",
p="2",
_hover=dict(
background_image=f"linear-gradient({bg_dark_color}, {bg_dark_color}), radial-gradient(circle at top left, {accent_color},{accennt_light});",
),
)
base_style = {
rx.chakra.Avatar: {
"shadow": shadow,
"color": text_light_color,
# "bg": border_color,
},
rx.chakra.Button: {
"shadow": shadow,
"color": text_light_color,
"_hover": {
"bg": accent_dark,
},
},
rx.chakra.Menu: {
"bg": bg_dark_color,
"border": f"red",
},
rx.chakra.MenuList: {
"bg": bg_dark_color,
"border": f"1.5px solid {bg_medium_color}",
},
rx.chakra.MenuDivider: {
"border": f"1px solid {bg_medium_color}",
},
rx.chakra.MenuItem: {
"bg": bg_dark_color,
"color": text_light_color,
},
rx.chakra.DrawerContent: {
"bg": bg_dark_color,
"color": text_light_color,
"opacity": "0.9",
},
rx.chakra.Hstack: {
"align_items": "center",
"justify_content": "space-between",
},
rx.chakra.Vstack: {
"align_items": "stretch",
"justify_content": "space-between",
},
}

View File

@ -8,11 +8,11 @@ version = "0.0.1"
description = "Reflex custom component {{ module_name }}"
readme = "README.md"
license = { text = "Apache-2.0" }
requires-python = ">=3.8"
requires-python = ">=3.9"
authors = [{ name = "", email = "YOUREMAIL@domain.com" }]
keywords = ["reflex","reflex-custom-components"]
dependencies = ["reflex>=0.4.2"]
dependencies = ["reflex>={{ reflex_version }}"]
classifiers = ["Development Status :: 4 - Beta"]

View File

@ -1,13 +1,15 @@
{% extends "web/pages/base_page.js.jinja2" %}
{% block early_imports %}
import '/styles/styles.css'
import '$/styles/styles.css'
{% endblock %}
{% block declaration %}
import { EventLoopProvider, StateProvider, defaultColorMode } from "/utils/context.js";
import { EventLoopProvider, StateProvider, defaultColorMode } from "$/utils/context.js";
import { ThemeProvider } from 'next-themes'
{% for library_alias, library_path in window_libraries %}
import * as {{library_alias}} from "{{library_path}}";
{% endfor %}
{% for custom_code in custom_codes %}
{{custom_code}}
@ -27,8 +29,17 @@ function AppWrap({children}) {
}
export default function MyApp({ Component, pageProps }) {
React.useEffect(() => {
// Make contexts and state objects available globally for dynamic eval'd components
let windowImports = {
{% for library_alias, library_path in window_libraries %}
"{{library_path}}": {{library_alias}},
{% endfor %}
};
window["__reflex"] = windowImports;
}, []);
return (
<ThemeProvider defaultTheme={ defaultColorMode } storageKey="chakra-ui-color-mode" attribute="class">
<ThemeProvider defaultTheme={ defaultColorMode } attribute="class">
<AppWrap>
<StateProvider>
<EventLoopProvider>

View File

@ -36,14 +36,10 @@
{# component: component dictionary #}
{% macro render_tag(component) %}
<{{component.name}} {{- render_props(component.props) }}>
{%- if component.args is not none -%}
{{- render_arg_content(component) }}
{%- else -%}
{{ component.contents }}
{% for child in component.children %}
{{ render(child) }}
{% endfor %}
{%- endif -%}
{{ component.contents }}
{% for child in component.children %}
{{ render(child) }}
{% endfor %}
</{{component.name}}>
{%- endmacro %}
@ -64,11 +60,11 @@
{# Args: #}
{# component: component dictionary #}
{% macro render_iterable_tag(component) %}
{ {%- if component.iterable_type == 'dict' -%}Object.entries({{- component.iterable_state }}){%- else -%}{{- component.iterable_state }}{%- endif -%}.map(({{ component.arg_name }}, {{ component.arg_index }}) => (
<>{ {%- if component.iterable_type == 'dict' -%}Object.entries({{- component.iterable_state }}){%- else -%}{{- component.iterable_state }}{%- endif -%}.map(({{ component.arg_name }}, {{ component.arg_index }}) => (
{% for child in component.children %}
{{ render(child) }}
{% endfor %}
))}
))}</>
{%- endmacro %}
@ -85,10 +81,10 @@
{% macro render_match_tag(component) %}
{
(() => {
switch (JSON.stringify({{ component.cond._var_name_unwrapped }})) {
switch (JSON.stringify({{ component.cond._js_expr }})) {
{% for case in component.match_cases %}
{% for condition in case[:-1] %}
case JSON.stringify({{ condition._var_name_unwrapped }}):
case JSON.stringify({{ condition._js_expr }}):
{% endfor %}
return {{ case[-1] }};
break;

View File

@ -1,5 +1,5 @@
import { createContext, useContext, useMemo, useReducer, useState } from "react"
import { applyDelta, Event, hydrateClientStorage, useEventLoop, refs } from "/utils/state.js"
import { applyDelta, Event, hydrateClientStorage, useEventLoop, refs } from "$/utils/state.js"
{% if initial_state %}
export const initialState = {{ initial_state|json_dumps }}
@ -7,7 +7,7 @@ export const initialState = {{ initial_state|json_dumps }}
export const initialState = {}
{% endif %}
export const defaultColorMode = "{{ default_color_mode }}"
export const defaultColorMode = {{ default_color_mode }}
export const ColorModeContext = createContext(null);
export const UploadFilesContext = createContext(null);
export const DispatchContext = createContext(null);
@ -26,6 +26,8 @@ export const clientStorage = {}
{% if state_name %}
export const state_name = "{{state_name}}"
export const exception_state_name = "{{const.frontend_exception_state}}"
// Theses events are triggered on initial load and each page navigation.
export const onLoadInternalEvent = () => {
const internal_events = [];
@ -57,6 +59,8 @@ export const initialEvents = () => [
{% else %}
export const state_name = undefined
export const exception_state_name = undefined
export const onLoadInternalEvent = () => []
export const initialEvents = () => []
@ -64,6 +68,8 @@ export const initialEvents = () => []
export const isDevMode = {{ is_dev_mode|json_dumps }}
export const lastCompiledTimeStamp = {{ last_compiled_time|json_dumps }}
export function UploadFilesProvider({ children }) {
const [filesById, setFilesById] = useState({})
refs["__clear_selected_files"] = (id) => setFilesById(filesById => {

View File

@ -1 +1 @@
export default {{ theme|json_dumps }}
export default {{ theme }}

View File

@ -1,21 +0,0 @@
import { useColorMode as chakraUseColorMode } from "@chakra-ui/react"
import { useTheme } from "next-themes"
import { useEffect } from "react"
import { ColorModeContext } from "/utils/context.js"
export default function ChakraColorModeProvider({ children }) {
const {colorMode, toggleColorMode} = chakraUseColorMode()
const {theme, setTheme} = useTheme()
useEffect(() => {
if (colorMode != theme) {
toggleColorMode()
}
}, [theme])
return (
<ColorModeContext.Provider value={[ colorMode, toggleColorMode ]}>
{children}
</ColorModeContext.Provider>
)
}

View File

@ -1,22 +1,53 @@
import { useTheme } from "next-themes"
import { useEffect, useState } from "react"
import { ColorModeContext, defaultColorMode } from "/utils/context.js"
import { useTheme } from "next-themes";
import { useEffect, useState } from "react";
import {
ColorModeContext,
defaultColorMode,
isDevMode,
lastCompiledTimeStamp,
} from "$/utils/context.js";
export default function RadixThemesColorModeProvider({ children }) {
const {theme, setTheme} = useTheme()
const [colorMode, setColorMode] = useState(defaultColorMode)
useEffect(() => {
setColorMode(theme)
}, [theme])
const toggleColorMode = () => {
setTheme(theme === "light" ? "dark" : "light")
const { theme, resolvedTheme, setTheme } = useTheme();
const [rawColorMode, setRawColorMode] = useState(defaultColorMode);
const [resolvedColorMode, setResolvedColorMode] = useState("dark");
useEffect(() => {
if (isDevMode) {
const lastCompiledTimeInLocalStorage =
localStorage.getItem("last_compiled_time");
if (
lastCompiledTimeInLocalStorage &&
lastCompiledTimeInLocalStorage !== lastCompiledTimeStamp
) {
// on app startup, make sure the application color mode is persisted correctly.
setTheme(defaultColorMode);
localStorage.setItem("last_compiled_time", lastCompiledTimeStamp);
return;
}
}
return (
<ColorModeContext.Provider value={[ colorMode, toggleColorMode ]}>
{children}
</ColorModeContext.Provider>
)
}
setRawColorMode(theme);
setResolvedColorMode(resolvedTheme);
}, [theme, resolvedTheme]);
const toggleColorMode = () => {
setTheme(resolvedTheme === "light" ? "dark" : "light");
};
const setColorMode = (mode) => {
const allowedModes = ["light", "dark", "system"];
if (!allowedModes.includes(mode)) {
console.error(
`Invalid color mode "${mode}". Defaulting to "${defaultColorMode}".`
);
mode = defaultColorMode;
}
setTheme(mode);
};
return (
<ColorModeContext.Provider
value={{ rawColorMode, resolvedColorMode, toggleColorMode, setColorMode }}
>
{children}
</ColorModeContext.Provider>
);
}

View File

@ -0,0 +1,34 @@
import { useEffect, useState } from "react"
import { codeToHtml} from "shiki"
/**
* Code component that uses Shiki to convert code to HTML and render it.
*
* @param code - The code to be highlighted.
* @param theme - The theme to be used for highlighting.
* @param language - The language of the code.
* @param transformers - The transformers to be applied to the code.
* @param decorations - The decorations to be applied to the code.
* @param divProps - Additional properties to be passed to the div element.
* @returns The rendered code block.
*/
export function Code ({code, theme, language, transformers, decorations, ...divProps}) {
const [codeResult, setCodeResult] = useState("")
useEffect(() => {
async function fetchCode() {
const result = await codeToHtml(code, {
lang: language,
theme,
transformers,
decorations
});
setCodeResult(result);
}
fetchCode();
}, [code, language, theme, transformers, decorations]
)
return (
<div dangerouslySetInnerHTML={{__html: codeResult}} {...divProps} ></div>
)
}

View File

@ -2,7 +2,8 @@
"compilerOptions": {
"baseUrl": ".",
"paths": {
"$/*": ["*"],
"@/*": ["public/*"]
}
}
}
}

View File

@ -1,5 +1,6 @@
module.exports = {
plugins: {
"postcss-import": {},
tailwindcss: {},
autoprefixer: {},
},

View File

@ -1,3 +1,6 @@
@tailwind base;
@import "tailwindcss/base";
@import "@radix-ui/themes/styles.css";
@tailwind components;
@tailwind utilities;

Some files were not shown because too many files have changed in this diff Show More