Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fd583132d7 | |||
| c27fc8c02f |
34
.gitignore
vendored
Normal file
34
.gitignore
vendored
Normal 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
94
README.md
Normal 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
|
||||
BIN
ai_chat.db
BIN
ai_chat.db
Binary file not shown.
40
init_config.py
Normal file
40
init_config.py
Normal 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()
|
||||
111
logs/ai-chat.log
111
logs/ai-chat.log
@@ -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
24
main.py
@@ -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:
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -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
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user