Compare commits

..

2 Commits

Author SHA1 Message Date
fd583132d7 feat: 支持Matrix access_token登录,配置AI模型接口 2026-04-11 11:58:14 +08:00
c27fc8c02f docs: 添加README和.gitignore 2026-04-11 11:52:23 +08:00
10 changed files with 314 additions and 22 deletions

34
.gitignore vendored Normal file
View File

@@ -0,0 +1,34 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
venv/
env/
*.egg-info/
dist/
build/
# Database
*.db
*.sqlite
*.sqlite3
# Logs
logs/
*.log
# IDE
.idea/
.vscode/
*.swp
*.swo
# OS
.DS_Store
Thumbs.db
# Config (if contains secrets)
config.local.*
*.secret

94
README.md Normal file
View File

@@ -0,0 +1,94 @@
# AI 对话系统
支持网页端和Matrix端实时同步对话的AI聊天系统。
## 功能特性
- **网页端对话**: 通过浏览器与AI进行对话
- **Matrix端对话**: 配置Matrix Bot用户可通过Matrix与AI对话
- **实时同步**: 同一用户在网页端和Matrix端的对话自动同步
- **后台管理**: 用户管理、对话记录、系统配置
## 系统架构
```
┌─────────────────────────────────────────────────────────┐
│ AI 对话系统 │
├─────────────────────────────────────────────────────────┤
│ 网页端 (用户A) ←──┐ ┌──→ Matrix端 │
│ │ 同一会话同步 │ (用户A) │
├─────────────────────────────────────────────────────────┤
│ 后端服务 (FastAPI + WebSocket) │
│ - 会话管理 │
│ - 消息存储 │
│ - Matrix Bot 集成 │
│ - AI 模型调用 │
├─────────────────────────────────────────────────────────┤
│ 后台管理 │
│ - 用户管理 │
│ - 对话记录 │
│ - 系统配置 │
└─────────────────────────────────────────────────────────┘
```
## 端口分配
- 19020: 主服务(网页端 + API
- 后台管理: http://localhost:19020/admin
## 快速启动
```bash
# 安装依赖
pip3 install -r requirements.txt
# 启动服务
./start.sh
# 检查状态
./status.sh
# 停止服务
./stop.sh
```
## 配置Matrix Bot
在后台管理页面配置以下参数:
| 配置项 | 说明 |
|--------|------|
| matrix_homeserver | Matrix服务器地址如 https://matrix.tphai.com |
| matrix_username | Matrix Bot用户名@ai-bot:matrix.org |
| matrix_password | Matrix Bot密码 |
配置完成后其他Matrix用户可以直接与Bot对话。
## API接口
### 会话管理
- `GET /api/conversations` - 获取会话列表
- `POST /api/conversations` - 创建新会话
- `GET /api/conversations/{id}/messages` - 获取会话消息
- `DELETE /api/conversations/{id}` - 删除会话
### 后台管理
- `GET /api/admin/stats` - 获取统计数据
- `GET /api/admin/users` - 获取用户列表
- `GET /api/admin/conversations` - 获取对话列表
- `GET /api/admin/config` - 获取系统配置
- `POST /api/admin/config` - 更新系统配置
## 技术栈
- **后端**: FastAPI + WebSocket
- **数据库**: SQLite (SQLAlchemy)
- **Matrix**: matrix-nio
- **前端**: HTML + JavaScript (原生)
- **AI**: 可配置任意LLM API默认使用本地LLM Proxy
## 仓库地址
http://192.168.2.8:12007/coder/ai-chat-system

Binary file not shown.

40
init_config.py Normal file
View File

@@ -0,0 +1,40 @@
#!/usr/bin/env python3
"""初始化配置"""
import sys
sys.path.insert(0, '/home/xian/.openclaw/workspace-coder/works/ai-chat')
from models import SessionLocal, SystemConfig, init_db
# 初始化数据库
init_db()
db = SessionLocal()
# 配置AI模型
configs = [
{'key': 'ai_api_base', 'value': 'http://192.168.2.17:19007/v1', 'description': 'AI模型API地址'},
{'key': 'ai_api_key', 'value': 'xxxx', 'description': 'AI模型API Key'},
{'key': 'ai_model', 'value': 'auto', 'description': 'AI模型名称'},
# 配置Matrix Bot
{'key': 'matrix_homeserver', 'value': 'https://matrix.tphai.com', 'description': 'Matrix服务器地址'},
{'key': 'matrix_username', 'value': '@tester:matrix.tphai.com', 'description': 'Matrix Bot用户名'},
{'key': 'matrix_access_token', 'value': 'syt_dGVzdGVy_eMwWfezCXSyBgHzvkmly_4dWFtM', 'description': 'Matrix Bot Access Token'},
]
for config in configs:
existing = db.query(SystemConfig).filter(SystemConfig.key == config['key']).first()
if existing:
existing.value = config['value']
existing.description = config['description']
else:
db.add(SystemConfig(**config))
db.commit()
print("配置已写入数据库")
# 显示配置
for c in db.query(SystemConfig).all():
print(f"{c.key}: {c.value}")
db.close()

View File

@@ -1,18 +1,93 @@
Traceback (most recent call last):
File "/home/xian/.openclaw/workspace-coder/works/ai-chat/main.py", line 17, in <module>
from models import init_db, get_db, User, Conversation, Message, SystemConfig
File "/home/xian/.openclaw/workspace-coder/works/ai-chat/models/__init__.py", line 1, in <module>
from .database import Base, engine, SessionLocal, get_db, init_db
File "/home/xian/.openclaw/workspace-coder/works/ai-chat/models/database.py", line 33, in <module>
class Conversation(Base):
File "/home/xian/.local/lib/python3.10/site-packages/sqlalchemy/orm/decl_api.py", line 195, in __init__
_as_declarative(reg, cls, dict_)
File "/home/xian/.local/lib/python3.10/site-packages/sqlalchemy/orm/decl_base.py", line 247, in _as_declarative
return _MapperConfig.setup_mapping(registry, cls, dict_, None, {})
File "/home/xian/.local/lib/python3.10/site-packages/sqlalchemy/orm/decl_base.py", line 328, in setup_mapping
return _ClassScanMapperConfig(
File "/home/xian/.local/lib/python3.10/site-packages/sqlalchemy/orm/decl_base.py", line 574, in __init__
self._extract_mappable_attributes()
File "/home/xian/.local/lib/python3.10/site-packages/sqlalchemy/orm/decl_base.py", line 1507, in _extract_mappable_attributes
raise exc.InvalidRequestError(
sqlalchemy.exc.InvalidRequestError: Attribute name 'metadata' is reserved when using the Declarative API.
/home/xian/.openclaw/workspace-coder/works/ai-chat/main.py:445: DeprecationWarning:
on_event is deprecated, use lifespan event handlers instead.
Read more about it in the
[FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/).
@app.on_event("startup")
/home/xian/.openclaw/workspace-coder/works/ai-chat/main.py:470: DeprecationWarning:
on_event is deprecated, use lifespan event handlers instead.
Read more about it in the
[FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/).
@app.on_event("shutdown")
INFO: Started server process [1416772]
INFO: Waiting for application startup.
INFO:__main__:数据库初始化完成
INFO:services.ai_service:AI配置已更新: http://192.168.2.17:19007/v1, model=auto
INFO:__main__:AI配置已加载: http://192.168.2.17:19007/v1, model=auto
INFO:services.matrix_service:Matrix连接成功(使用token): @tester:matrix.tphai.com
INFO:__main__:Matrix Bot已启动
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:19020 (Press CTRL+C to quit)
WARNING:nio.client.async_client:Timed out, sleeping for 0s
WARNING:nio.client.async_client:Timed out, sleeping for 0s
WARNING:nio.client.async_client:Timed out, sleeping for 0s
WARNING:nio.client.async_client:Timed out, sleeping for 0s
WARNING:nio.client.async_client:Timed out, sleeping for 1s
WARNING:nio.client.async_client:Timed out, sleeping for 3s
WARNING: Unsupported upgrade request.
WARNING: No supported WebSocket library detected. Please use "pip install 'uvicorn[standard]'", or install 'websockets' or 'wsproto' manually.
INFO: 192.168.2.10:58534 - "GET /ws/web_c8teajbbm HTTP/1.1" 404 Not Found
WARNING:nio.client.async_client:Timed out, sleeping for 6s
WARNING: Unsupported upgrade request.
WARNING: No supported WebSocket library detected. Please use "pip install 'uvicorn[standard]'", or install 'websockets' or 'wsproto' manually.
INFO: 192.168.2.10:58535 - "GET /ws/web_c8teajbbm HTTP/1.1" 404 Not Found
WARNING:nio.client.async_client:Timed out, sleeping for 12s
WARNING: Unsupported upgrade request.
WARNING: No supported WebSocket library detected. Please use "pip install 'uvicorn[standard]'", or install 'websockets' or 'wsproto' manually.
INFO: 192.168.2.10:58536 - "GET /ws/web_c8teajbbm HTTP/1.1" 404 Not Found
WARNING: Unsupported upgrade request.
WARNING: No supported WebSocket library detected. Please use "pip install 'uvicorn[standard]'", or install 'websockets' or 'wsproto' manually.
INFO: 192.168.2.10:58541 - "GET /ws/web_c8teajbbm HTTP/1.1" 404 Not Found
WARNING: Unsupported upgrade request.
WARNING: No supported WebSocket library detected. Please use "pip install 'uvicorn[standard]'", or install 'websockets' or 'wsproto' manually.
INFO: 192.168.2.10:58542 - "GET /ws/web_c8teajbbm HTTP/1.1" 404 Not Found
WARNING:nio.client.async_client:Timed out, sleeping for 25s
WARNING: Unsupported upgrade request.
WARNING: No supported WebSocket library detected. Please use "pip install 'uvicorn[standard]'", or install 'websockets' or 'wsproto' manually.
INFO: 192.168.2.10:58544 - "GET /ws/web_c8teajbbm HTTP/1.1" 404 Not Found
WARNING: Unsupported upgrade request.
WARNING: No supported WebSocket library detected. Please use "pip install 'uvicorn[standard]'", or install 'websockets' or 'wsproto' manually.
INFO: 192.168.2.10:58549 - "GET /ws/web_c8teajbbm HTTP/1.1" 404 Not Found
INFO: 127.0.0.1:53464 - "GET /api/admin/config HTTP/1.1" 200 OK
WARNING: Unsupported upgrade request.
WARNING: No supported WebSocket library detected. Please use "pip install 'uvicorn[standard]'", or install 'websockets' or 'wsproto' manually.
INFO: 192.168.2.10:58554 - "GET /ws/web_c8teajbbm HTTP/1.1" 404 Not Found
WARNING: Unsupported upgrade request.
WARNING: No supported WebSocket library detected. Please use "pip install 'uvicorn[standard]'", or install 'websockets' or 'wsproto' manually.
INFO: 192.168.2.10:58555 - "GET /ws/web_c8teajbbm HTTP/1.1" 404 Not Found
WARNING: Unsupported upgrade request.
WARNING: No supported WebSocket library detected. Please use "pip install 'uvicorn[standard]'", or install 'websockets' or 'wsproto' manually.
INFO: 192.168.2.10:58560 - "GET /ws/web_c8teajbbm HTTP/1.1" 404 Not Found
WARNING: Unsupported upgrade request.
WARNING: No supported WebSocket library detected. Please use "pip install 'uvicorn[standard]'", or install 'websockets' or 'wsproto' manually.
INFO: 192.168.2.10:58561 - "GET /ws/web_c8teajbbm HTTP/1.1" 404 Not Found
WARNING:nio.client.async_client:Timed out, sleeping for 51s
WARNING: Unsupported upgrade request.
WARNING: No supported WebSocket library detected. Please use "pip install 'uvicorn[standard]'", or install 'websockets' or 'wsproto' manually.
INFO: 192.168.2.10:58562 - "GET /ws/web_c8teajbbm HTTP/1.1" 404 Not Found
WARNING: Unsupported upgrade request.
WARNING: No supported WebSocket library detected. Please use "pip install 'uvicorn[standard]'", or install 'websockets' or 'wsproto' manually.
INFO: 192.168.2.10:58567 - "GET /ws/web_c8teajbbm HTTP/1.1" 404 Not Found
WARNING: Unsupported upgrade request.
WARNING: No supported WebSocket library detected. Please use "pip install 'uvicorn[standard]'", or install 'websockets' or 'wsproto' manually.
INFO: 192.168.2.10:58572 - "GET /ws/web_c8teajbbm HTTP/1.1" 404 Not Found
WARNING: Unsupported upgrade request.
WARNING: No supported WebSocket library detected. Please use "pip install 'uvicorn[standard]'", or install 'websockets' or 'wsproto' manually.
INFO: 192.168.2.10:58573 - "GET /ws/web_c8teajbbm HTTP/1.1" 404 Not Found
WARNING: Unsupported upgrade request.
WARNING: No supported WebSocket library detected. Please use "pip install 'uvicorn[standard]'", or install 'websockets' or 'wsproto' manually.
INFO: 192.168.2.10:58574 - "GET /ws/web_c8teajbbm HTTP/1.1" 404 Not Found
WARNING: Unsupported upgrade request.
WARNING: No supported WebSocket library detected. Please use "pip install 'uvicorn[standard]'", or install 'websockets' or 'wsproto' manually.
INFO: 192.168.2.10:58579 - "GET /ws/web_c8teajbbm HTTP/1.1" 404 Not Found
WARNING: Unsupported upgrade request.
WARNING: No supported WebSocket library detected. Please use "pip install 'uvicorn[standard]'", or install 'websockets' or 'wsproto' manually.
INFO: 192.168.2.10:58580 - "GET /ws/web_c8teajbbm HTTP/1.1" 404 Not Found
INFO: 127.0.0.1:37888 - "GET / HTTP/1.1" 200 OK
INFO: 127.0.0.1:37892 - "GET /admin HTTP/1.1" 200 OK
WARNING: Unsupported upgrade request.
WARNING: No supported WebSocket library detected. Please use "pip install 'uvicorn[standard]'", or install 'websockets' or 'wsproto' manually.
INFO: 192.168.2.10:58583 - "GET /ws/web_c8teajbbm HTTP/1.1" 404 Not Found

24
main.py
View File

@@ -14,7 +14,7 @@ import logging
from datetime import datetime
import os
from models import init_db, get_db, User, Conversation, Message, SystemConfig
from models import init_db, get_db, SessionLocal, User, Conversation, Message, SystemConfig
from services import ai_service, ConversationService, matrix_bot
# 配置日志
@@ -379,7 +379,15 @@ async def update_config(data: dict, db: Session = Depends(get_db)):
db.commit()
# 如果更新了Matrix配置重新连接
# 根据配置类型执行相应操作
if key.startswith('ai_'):
# 更新AI服务配置
configs = {c.key: c.value for c in db.query(SystemConfig).all()}
api_base = configs.get('ai_api_base', 'http://192.168.2.17:19007/v1')
api_key = configs.get('ai_api_key', 'xxxx')
model = configs.get('ai_model', 'auto')
ai_service.update_config(api_base, api_key, model)
if key.startswith('matrix_') and matrix_bot.is_running:
await matrix_bot.disconnect()
await matrix_bot.init_from_config()
@@ -440,6 +448,18 @@ async def startup():
init_db()
logger.info("数据库初始化完成")
# 从数据库加载AI配置
db = SessionLocal()
try:
configs = {c.key: c.value for c in db.query(SystemConfig).all()}
api_base = configs.get('ai_api_base', 'http://192.168.2.17:19007/v1')
api_key = configs.get('ai_api_key', 'xxxx')
model = configs.get('ai_model', 'auto')
ai_service.update_config(api_base, api_key, model)
logger.info(f"AI配置已加载: {api_base}, model={model}")
finally:
db.close()
# 初始化Matrix Bot
await matrix_bot.init_from_config()
if matrix_bot.is_running:

View File

@@ -4,10 +4,28 @@ AI服务 - 调用大模型API
import httpx
from typing import List, Dict, Optional
import json
import logging
logger = logging.getLogger(__name__)
# 默认配置
DEFAULT_API_BASE = "http://192.168.2.17:19007/v1"
DEFAULT_API_KEY = "xxxx"
DEFAULT_MODEL = "auto"
class AIService:
def __init__(self, api_base: str = "http://192.168.2.17:19007/v1", api_key: str = "sk-local", model: str = "qwen3.5-4b"):
def __init__(self, api_base: str = None, api_key: str = None, model: str = None):
self.api_base = api_base or DEFAULT_API_BASE
self.api_key = api_key or DEFAULT_API_KEY
self.model = model or DEFAULT_MODEL
def update_config(self, api_base: str, api_key: str, model: str):
"""更新配置"""
self.api_base = api_base
self.api_key = api_key
self.model = model
logger.info(f"AI配置已更新: {api_base}, model={model}")
self.api_base = api_base
self.api_key = api_key
self.model = model

View File

@@ -19,6 +19,7 @@ class MatrixBot:
self.homeserver: str = ""
self.username: str = ""
self.password: str = ""
self.access_token: str = ""
self.is_running: bool = False
self.on_message_callback: Optional[Callable] = None
@@ -30,8 +31,9 @@ class MatrixBot:
self.homeserver = configs.get('matrix_homeserver', 'https://matrix.tphai.com')
self.username = configs.get('matrix_username', '')
self.password = configs.get('matrix_password', '')
self.access_token = configs.get('matrix_access_token', '')
if self.username and self.password:
if self.username and (self.password or self.access_token):
await self.connect()
finally:
db.close()
@@ -44,6 +46,15 @@ class MatrixBot:
try:
self.client = AsyncClient(self.homeserver, self.username)
# 如果有access_token直接使用
if self.access_token:
self.client.access_token = self.access_token
logger.info(f"Matrix连接成功(使用token): {self.username}")
self.is_running = True
return True
# 否则使用密码登录
response = await self.client.login(self.password)
if isinstance(response, LoginResponse):