v1.2修复优化

This commit is contained in:
2026-05-08 10:05:31 +08:00
parent 80b71a973a
commit 4cf6bd4b4b
12 changed files with 238 additions and 128 deletions

View File

@@ -35,7 +35,7 @@
1. 登录宝塔面板
2. 点击"网站" → "添加站点"
3. 填写域名PHP 版本选择 **PHP 8.0**
4. 数据库选择"不创建"安装向导中会创建
4. 数据库选择"不创建"需在安装前手动创建,安装向导不会自动创建数据库
#### 3. 上传代码
@@ -52,25 +52,33 @@ composer install
#### 5. 设置目录权限
```bash
chmod 755 uploads/
chmod 755 public/uploads/
chmod 755 config/
```
#### 6. 配置 Nginx
#### 6. 配置伪静态
1. 在宝塔面板中找到你的站点 → 设置 → 配置文件
2. 将网站根目录修改为 `/www/wwwroot/your-domain.com/public`
3. 参考 `docs/baota-nginx-snippet.conf` 中的配置片段,添加到 server 块中
4. 保存配置
1. 在宝塔面板中找到你的站点 → 设置 → **网站目录** → 运行目录改为 `/public`
2. 站点设置 → **伪静态** → 将 `docs/baota-nginx-snippet.conf` 的内容粘贴进去
3. 保存配置
#### 7. 运行安装向导
> 注意:如 PHP 版本不是 8.0,需将配置中的 `php-cgi-80` 改为对应版本号。
#### 7. 创建数据库
安装向导不会自动创建数据库,需要提前手动创建:
1. 宝塔面板 → 数据库 → 添加数据库
2. 记录数据库名、用户名和密码,安装向导中需要填写
#### 8. 运行安装向导
访问 `http://your-domain.com/install.php`,按照向导步骤:
1. **环境检查** — 系统自动检查 PHP 版本和扩展
2. **数据库配置** — 填写 MySQL 连接信息
2. **数据库配置** — 填写 MySQL 连接信息(数据库需提前创建)
3. **应用配置** — JWT 密钥(可自动生成)
4. **管理员账户** — 设置管理员用户名和密码
5. **AI 供应商** — 配置至少一个 AI 服务供应商
5. **AI 供应商**(可选)配置 AI 服务供应商,安装后也可在设置页面添加
### 方式二:手动安装
@@ -96,17 +104,40 @@ composer install
```bash
chown -R www-data:www-data /var/www/ai-chat
chmod 755 uploads/ config/
chmod 755 public/uploads/ config/
```
#### 4. 配置 Nginx
参考 `docs/nginx.conf` 配置 Nginx 站点。
使用 `docs/nginx.conf` 作为完整站点配置:
```bash
cp docs/nginx.conf /etc/nginx/sites-available/ai-chat
ln -s /etc/nginx/sites-available/ai-chat /etc/nginx/sites-enabled/
# 编辑 server_name 和 root 路径
nginx -t && nginx -s reload
```
#### 5. 运行安装向导
#### 5. 创建数据库
```sql
CREATE DATABASE ai_chat DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'ai_chat'@'localhost' IDENTIFIED BY 'your_password';
GRANT ALL PRIVILEGES ON ai_chat.* TO 'ai_chat'@'localhost';
FLUSH PRIVILEGES;
```
#### 6. 运行安装向导
访问 `http://your-domain.com/install.php` 完成安装。
### 方式三:本地开发
```bash
php -S localhost:8080 -t public/ public/router.php
```
> 必须使用 `public/router.php` 作为路由文件,否则 `/api/*` 请求无法正确路由。
## 常见问题
### Q: 安装页面空白?
@@ -116,7 +147,10 @@ chmod 755 uploads/ config/
检查 Nginx 错误日志:`tail -f /var/log/nginx/error.log`
### Q: 数据库连接失败?
确认 MySQL 服务正在运行,且数据库账号密码正确。
确认 MySQL 服务正在运行,且数据库已提前创建、账号密码正确。
### Q: SSE 流式响应不工作?
确认 Nginx 配置中已禁用缓冲(参考 baota-nginx-snippet.conf
确认 Nginx 配置中已禁用缓冲(参考 `docs/baota-nginx-snippet.conf`)。
### Q: API 返回非 JSON 响应?
检查 Web 服务器是否正确配置了 `/api/` 路由转发。本地开发需使用 `public/router.php`

View File

@@ -91,9 +91,10 @@ ai-chat/
```
然后访问 `http://localhost:8080/`
4. **或配置 Nginx**(生产部署)
- 将网站根目录指向 `public/` 目录
- 参考 `docs/nginx.conf` 或 `docs/baota-nginx-snippet.conf` 配置 Nginx
4. **或配置 Web 服务器**(生产部署)
- 宝塔面板:网站运行目录设为 `/public`,伪静态填入 `docs/baota-nginx-snippet.conf` 的内容
- 手动 Nginx使用 `docs/nginx.conf` 作为完整站点配置
- 两种方式的详细说明见 [DEPLOY.md](docs/DEPLOY.md)
5. **设置目录权限**(生产部署)
```bash
@@ -101,11 +102,16 @@ ai-chat/
chown -R www:www .
```
6. **运行安装向导**
- 访问 `http://your-domain.com/install.php`
- 按照向导步骤完成安装
6. **创建数据库**
- 安装向导不会自动创建数据库,请提前手动创建
- 宝塔面板:数据库 → 添加数据库
- 手动:`CREATE DATABASE ai_chat DEFAULT CHARSET utf8mb4;`
详细安装说明请查看 [INSTALL.md](INSTALL.md) 和 [DEPLOY.md](docs/DEPLOY.md)。
7. **运行安装向导**
- 访问 `http://your-domain.com/install.php`
- 填写数据库连接信息和 AI 服务商配置,完成安装
详细部署说明请查看 [DEPLOY.md](docs/DEPLOY.md)。
## 页面说明
@@ -136,4 +142,11 @@ ai-chat/
| 版本 | 日期 | 说明 |
|------|------|------|
| v1.0.0 | 2026.5.5 | 初始版本PHP 8.0 全栈实现 |
| v1.0.0 | 2026-05-05 | 初始版本PHP 8.0 全栈实现 |
| v1.0.1 | 2026-05-06 | 修复首页 403 错误 |
| v1.0.2 | 2026-05-06 | 移除页面 Emoji优化排版与交互 |
| v1.0.3 | 2026-05-06 | 全面 UI 重构(登录页 / 安装页 / CSS 变量体系) |
| v1.0.4 | 2026-05-06 | 内联脚本与样式全部迁移至外部文件 |
| v1.1.0 | 2026-05-06 | 升级 firebase/php-jwt 至 7.0.5 |
| v1.1.1 | 2026-05-07 | 资源目录迁移至 public/ 下;修复安装页 JSON 解析错误;新增 router.php |
| v1.2.0 | 2026-05-08 | 修复 3 个致命 Bug数据库配置键名、Provider 路由、人格 Prompt 传递AI 提供商改为安装可选;文档全面规范化 |

View File

@@ -19,7 +19,8 @@ class Database
$config = json_decode(file_get_contents($configPath), true);
$dsn = "mysql:host={$config['host']};port={$config['port']};dbname={$config['dbname']};charset=utf8mb4";
$dbname = $config['database'] ?? $config['dbname'] ?? '';
$dsn = "mysql:host={$config['host']};port={$config['port']};dbname={$dbname};charset=utf8mb4";
self::$instance = new PDO($dsn, $config['user'], $config['password'], [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,

View File

@@ -84,6 +84,9 @@ class ChatController
ob_end_flush();
}
// 使用供应商配置中的 type 字段确定实际驱动
$providerType = $providerConfig['type'] ?? 'newapi';
$options = [
'provider' => $providerConfig,
'systemPrompt' => $systemPrompt,
@@ -91,7 +94,7 @@ class ChatController
];
try {
AIService::streamChat($providerKey, $model, $messages, $options, function ($chunk, $type = 'content') {
AIService::streamChat($providerType, $model, $messages, $options, function ($chunk, $type = 'content') {
if ($type === 'thinking') {
self::sendSSE(['thinking' => $chunk]);
} else {

View File

@@ -72,10 +72,9 @@ class InstallController
echo json_encode(['success' => false, 'message' => '请填写数据库配置']);
return;
}
if (!is_array($providers) || count($providers) === 0) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => '请至少配置一个AI服务提供商']);
return;
// 供应商配置可选,安装后可在设置页面添加
if (!is_array($providers)) {
$providers = [];
}
try {

View File

@@ -54,13 +54,32 @@
```
ai-chat/
├── public/ # Web 根目录
├── public/ # Web 根目录Nginx 指向此目录)
│ ├── index.php # 首页入口(自动路由到登录/安装页)
│ ├── api.php # API 统一入口(路由分发)
│ ├── router.php # PHP 内置开发服务器路由文件
│ ├── login.php # 登录页面
│ ├── chat.php # 聊天主页面
│ ├── config.php # 配置管理页面
── install.php # 安装向导页面
├── app/ # 应用代码(命名空间 App\
── install.php # 安装向导页面
├── assets/ # 前端静态资源
│ │ ├── css/ # 样式文件
│ │ │ ├── style.css # 全局样式
│ │ │ ├── chat.css # 聊天界面样式
│ │ │ └── markdown.css # Markdown 渲染样式
│ │ ├── js/ # JavaScript
│ │ │ ├── api.js # API 调用封装
│ │ │ ├── chat.js # 聊天核心功能
│ │ │ ├── config.js # 配置页面逻辑
│ │ │ ├── install.js # 安装向导逻辑
│ │ │ ├── login.js # 登录页面逻辑
│ │ │ ├── session.js # 会话管理
│ │ │ ├── upload.js # 文件上传
│ │ │ ├── markdown.js # Markdown 渲染
│ │ │ └── storage.js # 本地存储
│ │ └── img/ # 图片
│ └── uploads/ # 用户上传文件
├── app/ # 应用代码(命名空间 App\PSR-4 自动加载)
│ ├── Config/ # 配置类
│ │ ├── Database.php # 数据库连接(单例 PDO
│ │ └── AppConfig.php # 应用配置读写
@@ -95,21 +114,7 @@ ai-chat/
│ └── layout/
│ ├── header.php
│ └── footer.php
├── assets/ # 前端静态资源
│ ├── css/ # 样式
│ │ ├── style.css # 全局样式
│ │ ├── chat.css # 聊天界面样式
│ │ └── markdown.css # Markdown 渲染样式
│ ├── js/ # JavaScript
│ │ ├── api.js # API 调用封装
│ │ ├── chat.js # 聊天核心功能
│ │ ├── session.js # 会话管理
│ │ ├── upload.js # 文件上传
│ │ ├── markdown.js # Markdown 渲染
│ │ └── storage.js # 本地存储
│ └── img/ # 图片
├── config/ # JSON 配置文件
├── uploads/ # 用户上传文件
├── config/ # JSON 配置文件(安装后生成)
├── docs/ # 文档
└── composer.json # Composer 配置
```

View File

@@ -14,7 +14,7 @@
1. 网站 → 添加站点
2. 填写域名
3. PHP 版本选择 **PHP 8.0**
4. 数据库选择"不创建"
4. 数据库选择"不创建"(安装向导会连接你手动创建的数据库)
### 3. 部署代码
@@ -31,30 +31,65 @@ chmod -R 755 .
chown -R www:www .
```
### 5. 配置 Nginx
### 5. 配置伪静态
1. 站点设置 → 网站目录 → 运行目录改为 `/public`
2. 站点设置 → 配置文件添加 `docs/baota-nginx-snippet.conf` 中的配置
2. 站点设置 → **伪静态** `docs/baota-nginx-snippet.conf` 的内容粘贴进去,保存
### 6. 运行安装向导
> 注意:是粘贴到"伪静态"输入框,不是"配置文件"。
> 如 PHP 版本不是 8.0,需将 `php-cgi-80` 改为对应版本号(如 `php-cgi-81`)。
访问 `http://your-domain.com/install.php`
### 6. 创建数据库
### 7. SSL 配置(可选)
安装向导不会自动创建数据库,需要你提前手动创建:
1. 宝塔面板 → 数据库 → 添加数据库
2. 记录数据库名、用户名和密码,安装向导中需要填写
### 7. 运行安装向导
访问 `http://your-domain.com/install.php`,按步骤完成安装。
### 8. SSL 配置(可选)
站点设置 → SSL → Let's Encrypt → 申请证书
## 手动部署
---
### Nginx 配置
## 手动部署Nginx + PHP-FPM
参考 `docs/nginx.conf` 文件,将 `root` 指向 `public/` 目录。
### 1. 安装依赖
### PHP-FPM 配置
```bash
composer install
```
确保 PHP-FPM 监听 socket 配置正确(通常为 `/tmp/php-cgi-80.sock``127.0.0.1:9000`)。
### 2. Nginx 站点配置
### 目录权限
使用 `docs/nginx.conf` 作为完整的站点配置文件:
```bash
# 复制到 Nginx 配置目录
cp docs/nginx.conf /etc/nginx/sites-available/ai-chat
ln -s /etc/nginx/sites-available/ai-chat /etc/nginx/sites-enabled/
# 编辑配置,修改 server_name 和 root 路径
vim /etc/nginx/sites-available/ai-chat
# 测试并重载
nginx -t && nginx -s reload
```
### 3. 创建数据库
```sql
CREATE DATABASE ai_chat DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'ai_chat'@'localhost' IDENTIFIED BY 'your_password';
GRANT ALL PRIVILEGES ON ai_chat.* TO 'ai_chat'@'localhost';
FLUSH PRIVILEGES;
```
### 4. 目录权限
```bash
chown -R www-data:www-data /path/to/ai-chat
@@ -62,6 +97,22 @@ chmod 755 /path/to/ai-chat/public/uploads
chmod 755 /path/to/ai-chat/config
```
### 5. 运行安装向导
访问 `http://your-domain.com/install.php`
---
## 本地开发PHP 内置服务器)
```bash
php -S localhost:8080 -t public/ public/router.php
```
> 必须使用 `public/router.php` 作为路由文件,否则 `/api/*` 请求无法正确路由到 `api.php`。
---
## 安全建议
1. 配置 SSL 证书HTTPS

View File

@@ -1,35 +1,24 @@
# ============================================================
# AI Chat 宝塔面板 Nginx 配置片段PHP-FPM 版本)
# AI Chat - 宝塔面板伪静态规则
# ============================================================
#
# 使用说明】
# 1. 本文件为宝塔面板专用的 Nginx 配置片段,不是完整的站点配置文件。
# 2. 使用步骤:
# a. 在宝塔面板中创建网站PHP 版本选择 PHP 8.0
# b. 将网站根目录指向 /path/to/ai-chat/public
# c. 登录宝塔面板 → 网站 → 找到你的站点 → 点击"设置"
# d. 在左侧菜单选择"配置文件"
# e. 将下方"配置内容开始"到"配置内容结束"之间的内容,
# 复制并粘贴到 server { } 块内(注意不要重复嵌套 server 块)
# f. 保存即可生效
# 3. 前置准备:
# - 在宝塔面板中安装 PHP 8.0 并启用
# - 安装 MySQL 5.7+ 或 8.0
# - 安装 Composer
# - 运行 composer install 安装 PHP 依赖
# 使用方法:
# 宝塔面板 → 网站 → 找到你的站点 → 设置 → 伪静态
# 将本文件内容完整粘贴到伪静态输入框中,保存即可
#
# 前置条件:
# - 网站根目录已指向 public/ 目录
# - PHP 8.0 已在宝塔中安装并启用
# - 如 PHP 版本非 8.0,需将下方 php-cgi-80 改为对应版本号
#
# ============================================================
# ↓↓↓ 配置内容开始 ↓↓↓
# === AI Chat 网站配置PHP-FPM ===
# 1. 默认路由
# 默认路由
location / {
try_files $uri $uri/ /login.php;
}
# 2. API 路由 - 转发到 api.php
# API 路由 — 将 /api/* 请求转发到 api.php 处理
location /api/ {
try_files $uri /api.php$is_args$args;
fastcgi_pass unix:/tmp/php-cgi-80.sock;
@@ -40,47 +29,39 @@ location /api/ {
fastcgi_param REQUEST_URI $request_uri;
}
# 3. SSE 流式响应特殊配置(AI对话需要
# 针对 Chat API 的 SSEServer-Sent Events流式响应
# 需要禁用所有缓冲以确保实时输出
# SSE 流式响应AI 对话需要禁用缓冲以实现实时输出
location /api/chat/completions {
fastcgi_pass unix:/tmp/php-cgi-80.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/api.php;
fastcgi_param REQUEST_URI $request_uri;
# SSE 关键配置
fastcgi_buffering off;
fastcgi_cache off;
proxy_buffering off;
add_header X-Accel-Buffering no;
# 超时设置5分钟
fastcgi_read_timeout 300s;
}
# 4. 静态资源缓存assets/ 和 uploads/ 已在 public 目录下,无需 alias
# 静态资源缓存
location /assets/ {
expires 30d;
add_header Cache-Control "public, immutable";
}
# 5. 上传文件缓存
# 上传文件缓存
location /uploads/ {
expires 7d;
add_header Cache-Control "public";
}
# 6. 禁止访问非公开目录(安全)
location ~ /(app|config|vendor|tests|scripts|)/ {
# 禁止访问非公开目录
location ~ /(app|config|vendor|tests|scripts|\.cospec)/ {
deny all;
return 404;
}
# 7. 禁止访问隐藏文件
# 禁止访问隐藏文件
location ~ /\. {
deny all;
return 404;
}
# 8. 上传文件大小限制
client_max_body_size 10m;
# ↑↑↑ 配置内容结束 ↑↑↑

View File

@@ -1,14 +1,25 @@
# AI Chat 应用 Nginx 配置PHP-FPM 版本)
# 将此文件复制到 /etc/nginx/sites-available/ 并创建软链接到 sites-enabled/
# ============================================================
# AI Chat - Nginx 完整站点配置文件
# ============================================================
#
# 注意:本文件为完整的 Nginx 站点配置,适用于直接部署到 Nginx + PHP-FPM 的场景。
# 如果你使用宝塔面板管理服务器,请参考 baota-nginx-snippet.conf 文件中的配置片段。
# 适用场景:直接部署到 Nginx + PHP-FPM(不使用宝塔面板)
#
# 使用方法:
# 1. 将本文件复制到 /etc/nginx/sites-available/ai-chat
# 2. 创建软链接ln -s /etc/nginx/sites-available/ai-chat /etc/nginx/sites-enabled/
# 3. 修改下方 server_name 和 root 为实际值
# 4. 如 PHP 版本非 8.0,需将 php-cgi-80 改为对应版本号
# 5. nginx -t 测试配置nginx -s reload 重载生效
#
# 注意:
# 如果你使用宝塔面板,请勿使用本文件,改用 baota-nginx-snippet.conf伪静态规则
#
# 前置条件:
# - PHP 8.0+ 已安装并启用 PHP-FPM
# - MySQL 5.7+ 已安装
# - Composer 已安装
# - 项目已部署到 /path/to/ai-chat/ 目录
# - PHP 8.0+ 已安装并启用 PHP-FPM
# - MySQL 5.7+ 已安装
# - Composer 已安装
# - 项目已部署到服务器目录
#
server {
listen 80;

View File

@@ -97,28 +97,37 @@ const ChatManager = {
// 清除文件
UploadManager.clearFiles();
// 获取当前配置
const provider = document.getElementById('providerSelect')?.value || 'newapi';
const model = document.getElementById('modelSelect')?.value || 'gpt-3.5-turbo';
const thinkingMode = document.getElementById('thinkingMode')?.checked || false;
// 获取当前配置
const provider = document.getElementById('providerSelect')?.value || 'newapi';
const model = document.getElementById('modelSelect')?.value || 'gpt-3.5-turbo';
const thinkingMode = document.getElementById('thinkingMode')?.checked || false;
// 获取人格提示词
let systemPrompt = '';
const personalitySelect = document.getElementById('personalitySelect');
if (personalitySelect && personalitySelect.value) {
const personality = personalitiesData.find(p => p.id == personalitySelect.value);
if (personality) {
systemPrompt = personality.prompt || '';
}
}
// SSE 流式请求
this.isStreaming = true;
this.updateSendButton();
// SSE 流式请求
this.isStreaming = true;
this.updateSendButton();
try {
await this.streamChat(provider, model, thinkingMode);
} catch (err) {
this.addErrorMessage(err.message);
} finally {
this.isStreaming = false;
this.updateSendButton();
}
},
try {
await this.streamChat(provider, model, thinkingMode, systemPrompt);
} catch (err) {
this.addErrorMessage(err.message);
} finally {
this.isStreaming = false;
this.updateSendButton();
}
},
async streamChat(provider, model, thinkingMode) {
const token = Storage.getToken();
async streamChat(provider, model, thinkingMode, systemPrompt) {
const token = Storage.getToken();
// 构建消息历史(只取 role 和 content
const messages = this.messages.map(m => ({
@@ -138,7 +147,8 @@ const ChatManager = {
'Authorization': 'Bearer ' + token
},
body: JSON.stringify({
provider, model, messages, stream: true, thinkingMode
provider, model, messages, stream: true, thinkingMode,
systemPrompt: systemPrompt || ''
})
});

View File

@@ -158,8 +158,10 @@ const InstallWizard = {
});
});
if (providers.length === 0 || !providers[0].name || !providers[0].apiKey) {
alert('请至少配置一个完整的供应商');
// 供应商配置可选,跳过不完整的条目
const validProviders = providers.filter(p => p.name && p.apiKey);
if (validProviders.length === 0 && providers.length > 0) {
alert('供应商信息不完整,请填写名称和 API Key或删除该条目');
return;
}
@@ -180,7 +182,7 @@ const InstallWizard = {
jwtSecret: document.getElementById('jwtSecret').value || undefined,
jwtExpiry: parseInt(document.getElementById('jwtExpiry').value) || 86400
},
providers: providers
providers: validProviders.length > 0 ? validProviders : []
};
try {

View File

@@ -84,7 +84,7 @@ $envChecks = json_encode([
<div class="step-content" id="step2">
<div class="step-header">
<h2>数据库配置</h2>
<p class="step-desc">填写 MySQL 数据库连接信息</p>
<p class="step-desc">填写 MySQL 数据库连接信息。请确保数据库已提前创建。</p>
</div>
<div class="form-row">
<div class="form-group col-flex-2">
@@ -175,7 +175,7 @@ $envChecks = json_encode([
<div class="step-content" id="step5">
<div class="step-header">
<h2>AI 供应商配置</h2>
<p class="step-desc">至少配置一个 AI 供应商,安装后在设置中添加更多</p>
<p class="step-desc">可选步骤。现在配置或安装后在设置页面中添加</p>
</div>
<div id="providerList">
<!-- 由 JS 动态管理 -->