nex-fw 0.2.0
NexFramework - AI 对话框架，支持多模型切换、工具调用、流式输出、多会话管理
License: MIT
Requires Python: >=3.9
Keywords: ai, chatbot, openai, llm, framework, nex, multi-session

# NexFramework

[![PyPI version](https://img.shields.io/pypi/v/nex-fw.svg)](https://pypi.org/project/nex-fw/)
[![Python versions](https://img.shields.io/pypi/pyversions/nex-fw.svg)](https://pypi.org/project/nex-fw/)
[![Downloads](https://img.shields.io/pypi/dm/nex-fw.svg)](https://pypi.org/project/nex-fw/)
[![License](https://img.shields.io/pypi/l/nex-fw.svg)](https://pypi.org/project/nex-fw/)
[![Gitee](https://img.shields.io/badge/Gitee-仓库-red)](https://gitee.com/candy_xt/NexFW)

AI 对话框架，支持多模型切换、多会话管理、工具调用、流式输出。

## 特性

- 🔄 多模型切换 - 支持配置多个 AI 模型，运行时切换
- 💬 多会话管理 - 独立会话上下文，支持创建、切换、删除
- 🔧 工具调用 - 内置 shell/http 工具，支持自定义扩展
- 📡 流式输出 - 实时返回生成内容
- 🗄️ SQLite 存储 - 可靠的本地数据持久化
- 🌐 WebUI - 开箱即用的聊天界面

## 安装

```bash
pip install nex-fw        # 基础安装
pip install nex-fw[api]   # 包含 API 服务
pip install nex-fw[all]   # 完整安装
```

## 快速开始

```bash
# 初始化工作目录
nex init

# 编辑 model_config.json 配置 API Key

# 启动控制台
nex console

# 或启动 Web 服务
nex serve --port 8000
```

## 工作目录结构

```
your_project/
├── model_config.json     # 模型配置
├── prompt_config.txt     # 系统提示词
├── nex_data.db           # SQLite 数据库（自动生成）
└── tools/                # 自定义工具目录
    ├── get_time.json     # 工具定义
    ├── get_time.py       # 工具实现
    └── calculator.py     # 纯 Python 工具
```

## 配置文件

### model_config.json

```json
{
  "gpt-4": {
    "name": "GPT-4",
    "api_key": "sk-xxx",
    "base_url": "https://api.openai.com/v1",
    "model": "gpt-4o"
  },
  "deepseek": {
    "name": "DeepSeek",
    "api_key": "sk-xxx",
    "base_url": "https://api.deepseek.com/v1",
    "model": "deepseek-chat"
  }
}
```

## 代码使用

```python
from nex_fw import NexFramework

nex = NexFramework(work_dir="./my_project")

# 创建会话
session_id = nex.create_session("测试会话", "user1")

# 对话（指定会话）
reply = nex.chat("user1", "你好", session_id=session_id)

# 流式对话
for chunk in nex.chat_stream("user1", "讲个故事", session_id=session_id):
    print(chunk, end="", flush=True)

# 获取会话列表
sessions = nex.get_sessions()

# 获取会话消息
messages = nex.get_session_messages(session_id)

# 切换模型
nex.switch_model("deepseek")
```

## API 接口

### 对话
```
POST /nex/chat
{
  "user": "guest",
  "message": "你好",
  "session_id": 1,    // 可选，不传则自动创建会话
  "stream": true
}
```

### 会话管理
```
GET    /nex/sessions                    # 获取会话列表
POST   /nex/sessions                    # 创建会话
GET    /nex/sessions/{id}               # 获取会话详情
PUT    /nex/sessions/{id}               # 更新会话名称
DELETE /nex/sessions/{id}               # 删除会话
GET    /nex/sessions/{id}/messages      # 获取会话消息
DELETE /nex/sessions/{id}/messages      # 清空会话消息
DELETE /nex/messages/{id}               # 删除单条消息
```

### 模型管理
```
GET  /nex/models          # 获取模型列表
POST /nex/models/switch   # 切换模型
```

## 控制台命令

| 命令 | 说明 |
|------|------|
| /start [port] | 启动 Web 服务 |
| /stop | 停止 Web 服务 |
| /status | 查看状态 |
| /models | 查看模型列表 |
| /use \<key\> | 切换模型 |
| /sessions | 查看会话列表 |
| /new [name] | 创建新会话 |
| /switch \<id\> | 切换会话 |
| /rename \<name\> | 重命名当前会话 |
| /delete [id] | 删除会话 |
| /messages [n] | 查看当前会话消息 |
| /clear | 清空当前会话消息 |
| /quit | 退出 |

## 自定义工具

### 方式1: JSON + Python

`tools/get_weather.json`:
```json
{
  "name": "get_weather",
  "description": "获取天气信息",
  "parameters": {
    "type": "object",
    "properties": {
      "city": {"type": "string", "description": "城市名"}
    },
    "required": ["city"]
  }
}
```

`tools/get_weather.py`:
```python
def execute(args):
    city = args.get("city")
    return f"{city}天气晴朗"
```

### 方式2: 纯 Python

`tools/calculator.py`:
```python
TOOL_DEF = {
    "name": "calculator",
    "description": "计算器",
    "parameters": {
        "type": "object",
        "properties": {
            "expression": {"type": "string"}
        },
        "required": ["expression"]
    }
}

def execute(args):
    return str(eval(args["expression"]))
```

## License

MIT