Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions .github/workflows/publish-to-pypi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: Build and Publish to PyPI

on:
workflow_dispatch:
release:
types: [published]

jobs:
build-and-publish:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # Required for trusted publishing to PyPI

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
persist-credentials: false

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '22'

- name: Build frontend
run: |
cd web
npm install
npm run build

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.10'

- name: Install build dependencies
run: |
python -m pip install --upgrade pip
pip install build twine

- name: Build package
run: |
python -m build

- name: Check package
run: |
twine check dist/*

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
skip-existing: true
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,8 @@ uv.lock
plugins.bak
coverage.xml
.coverage

# Build artifacts
/dist
/build
*.egg-info
23 changes: 23 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
include README.md
include LICENSE
include pyproject.toml

# Include all Python packages
recursive-include langbot *.py
recursive-include pkg *.py
recursive-include libs *.py

# Include templates and resources
recursive-include langbot/templates *
recursive-include res *

# Include compiled frontend files (will be added during build)
recursive-include web/out *

# Exclude unnecessary files
global-exclude *.pyc
global-exclude *.pyo
global-exclude __pycache__
global-exclude .DS_Store
global-exclude *.so
global-exclude *.dylib
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,25 @@ LangBot 是一个开源的大语言模型原生即时通信机器人开发平台

## 📦 开始使用

#### 快速体验(推荐)

使用 `uvx` 一键启动(无需安装):

```bash
uvx langbot
```

或使用 `pip` 安装后运行:

```bash
pip install langbot
langbot
```

访问 http://localhost:5300 即可开始使用。

详细文档[PyPI 安装](docs/PYPI_INSTALLATION.md)。

#### Docker Compose 部署

```bash
Expand Down
19 changes: 19 additions & 0 deletions README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,25 @@ LangBot is an open-source LLM native instant messaging robot development platfor

## 📦 Getting Started

#### Quick Start (Recommended)

Use `uvx` to start with one command (no installation required):

```bash
uvx langbot
```

Or install with `pip` and run:

```bash
pip install langbot
langbot
```

Visit http://localhost:5300 to start using it.

Detailed documentation [PyPI Installation](docs/PYPI_INSTALLATION.md).

#### Docker Compose Deployment

```bash
Expand Down
117 changes: 117 additions & 0 deletions docs/PYPI_INSTALLATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# LangBot PyPI Package Installation

## Quick Start with uvx

The easiest way to run LangBot is using `uvx` (recommended for quick testing):

```bash
uvx langbot
```

This will automatically download and run the latest version of LangBot.

## Install with pip/uv

You can also install LangBot as a regular Python package:

```bash
# Using pip
pip install langbot

# Using uv
uv pip install langbot
```

Then run it:

```bash
langbot
```

Or using Python module syntax:

```bash
python -m langbot
```

## Installation with Frontend

When published to PyPI, the LangBot package includes the pre-built frontend files. You don't need to build the frontend separately.

## Data Directory

When running LangBot as a package, it will create a `data/` directory in your current working directory to store configuration, logs, and other runtime data. You can run LangBot from any directory, and it will set up its data directory there.

## Command Line Options

LangBot supports the following command line options:

- `--standalone-runtime`: Use standalone plugin runtime
- `--debug`: Enable debug mode

Example:

```bash
langbot --debug
```

## Comparison with Other Installation Methods

### PyPI Package (uvx/pip)
- **Pros**: Easy to install and update, no need to clone repository or build frontend
- **Cons**: Less flexible for development/customization

### Docker
- **Pros**: Isolated environment, easy deployment
- **Cons**: Requires Docker

### Manual Source Installation
- **Pros**: Full control, easy to customize and develop
- **Cons**: Requires building frontend, managing dependencies manually

## Development

If you want to contribute or customize LangBot, you should still use the manual installation method by cloning the repository:

```bash
git clone https://github.com/langbot-app/LangBot
cd LangBot
uv sync
cd web
npm install
npm run build
cd ..
uv run main.py
```

## Updating

To update to the latest version:

```bash
# With pip
pip install --upgrade langbot

# With uv
uv pip install --upgrade langbot

# With uvx (automatically uses latest)
uvx langbot
```

## System Requirements

- Python 3.10.1 or higher
- Operating System: Linux, macOS, or Windows

## Differences from Source Installation

When running LangBot from the PyPI package (via uvx or pip), there are a few behavioral differences compared to running from source:

1. **Version Check**: The package version does not prompt for user input when the Python version is incompatible. It simply prints an error message and exits. This makes it compatible with non-interactive environments like containers and CI/CD.

2. **Working Directory**: The package version does not require being run from the LangBot project root. You can run `langbot` from any directory, and it will create a `data/` directory in your current working directory.

3. **Frontend Files**: The frontend is pre-built and included in the package, so you don't need to run `npm build` separately.

These differences are intentional to make the package more user-friendly and suitable for various deployment scenarios.
3 changes: 3 additions & 0 deletions langbot/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""LangBot - Easy-to-use global IM bot platform designed for LLM era"""

__version__ = "4.4.1"
103 changes: 103 additions & 0 deletions langbot/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
"""LangBot entry point for package execution"""
import asyncio
import argparse
import sys
import os

# ASCII art banner
asciiart = r"""
_ ___ _
| | __ _ _ _ __ _| _ ) ___| |_
| |__/ _` | ' \/ _` | _ \/ _ \ _|
|____\__,_|_||_\__, |___/\___/\__|
|___/

⭐️ Open Source 开源地址: https://github.com/langbot-app/LangBot
📖 Documentation 文档地址: https://docs.langbot.app
"""


async def main_entry(loop: asyncio.AbstractEventLoop):
"""Main entry point for LangBot"""
parser = argparse.ArgumentParser(description='LangBot')
parser.add_argument(
'--standalone-runtime',
action='store_true',
help='Use standalone plugin runtime / 使用独立插件运行时',
default=False,
)
parser.add_argument('--debug', action='store_true', help='Debug mode / 调试模式', default=False)
args = parser.parse_args()

if args.standalone_runtime:
from pkg.utils import platform

platform.standalone_runtime = True

if args.debug:
from pkg.utils import constants

constants.debug_mode = True

print(asciiart)

# Check dependencies
from pkg.core.bootutils import deps

missing_deps = await deps.check_deps()

if missing_deps:
print('以下依赖包未安装,将自动安装,请完成后重启程序:')
print(
'These dependencies are missing, they will be installed automatically, please restart the program after completion:'
)
for dep in missing_deps:
print('-', dep)
await deps.install_deps(missing_deps)
print('已自动安装缺失的依赖包,请重启程序。')
print('The missing dependencies have been installed automatically, please restart the program.')
sys.exit(0)

# Check configuration files
from pkg.core.bootutils import files

generated_files = await files.generate_files()

if generated_files:
print('以下文件不存在,已自动生成:')
print('Following files do not exist and have been automatically generated:')
for file in generated_files:
print('-', file)

from pkg.core import boot

await boot.main(loop)


def main():
"""Main function to be called by console script entry point"""
# Check Python version
if sys.version_info < (3, 10, 1):
print('需要 Python 3.10.1 及以上版本,当前 Python 版本为:', sys.version)
print('Your Python version is not supported.')
print('Python 3.10.1 or higher is required. Current version:', sys.version)
sys.exit(1)

# Set up the working directory
# When installed as a package, we need to handle the working directory differently
# We'll create data directory in current working directory if not exists
os.makedirs('data', exist_ok=True)

loop = asyncio.new_event_loop()

try:
loop.run_until_complete(main_entry(loop))
except KeyboardInterrupt:
print('\n正在退出...')
print('Exiting...')
finally:
loop.close()


if __name__ == '__main__':
main()
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
4 changes: 3 additions & 1 deletion pkg/api/http/controller/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ async def healthz():
ginst = g(self.ap, self.quart_app)
await ginst.initialize()

frontend_path = 'web/out'
from ....utils import paths

frontend_path = paths.get_frontend_path()

@self.quart_app.route('/')
async def index():
Expand Down
Loading
Loading