ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

23KB PHP源码打造AI聊天网站:从部署到二次开发全解析

23KB PHP源码打造AI聊天网站:从部署到二次开发全解析 简介这份压缩包是一套面向 PHP 开发者的莲匸 AI 网站系统源码主打轻量级在线 AI 对话能力适合有一定 PHP 建站基础、希望快速接入多模型聊天及相关图像生成功能的个人开发者或小型团队。资源整体仅 42KB共含 22 个文件其中 17 个 PHP 文件承担用户管理、接口配置、一键添加/修改接口、聊天交互等核心逻辑3 个 TXT 文件用于接口说明与部署提示另有 1 个 HTML 演示页和 1 个 ZIP 内嵌资源包方便参考整体结构。源码内置 5 个在线 AI 模型的聊天模式支持文转图、图转图并提供 5 套不同模式的 API 接口源码供二次对接还附带一个 demo 示例代码便于初学者理解调用流程。已有 208 人学习浏览适合用来快速生成 AI 对话站点也可作为 PHP 项目实战参考学习多模型切换、接口封装和上传识别等功能的实现思路。1. 23KB的PHP源码凭什么做成AI聊天网站一个能跑起来的AI聊天网站系统后端代码量通常以兆为单位但这个莲匸AI源码包解压后只有23KB装下的是一套完整的PHP网站系统。用户可以在线注册登录管理员能一键添加/修改大模型接口前端能切换5个AI模型聊天还支持文转图、图转图更关键的是包里另外给了5个不同模式的API接口源码和一个演示demo方便你把AI能力开放给别人使用。对不打算买服务器、只想用现有PHP空间跑一个AI工具站的人来说这个包几乎没有学习成本对想研究“PHP怎么封装第三方大模型接口”的开发者它又是一个可以直接拆解的样例。2. PHP源码结构与上线前的五个环境检查2.1 解开压缩包后先找这三个文件23KB能装下的东西不多但模块划分并不含糊。我建议你解压后先看三个入口负责页面输出的入口文件负责转发大模型请求的网关文件以及集中放密钥和模型参数的配置文件。这是这类PHP轻量站最常见的做法——前端一个入口后端一个接口网关配置单独拎出来。这样后面加模型、换key都不需要动业务代码出问题也容易定位。文件常见示例职责改动频率index.php页面渲染、聊天窗口、登录入口低api.php接收前端请求、curl转发到第三方模型中config.phpAPI key、模型列表、接口模式高文件具体名字视打包者习惯而定你只要按“页面/网关/配置”三个维度去找逻辑就是一目了然的。2.2 环境检查清单它是纯PHP项目没有框架依赖运行条件比很多开源CMS低。但有几个扩展必须提前确认否则后台能登录、聊天接口却静默失败。即使是很基础的php免费网站空间只要面板里能开curl这个系统就能跑起来。PHP扩展建议状态影响curl必须启用所有第三方大模型请求都要走curljson必须启用配置、接口响应都是JSONfileinfo建议打开图生图上传时识别二进制类型openssl建议打开部分API key鉴权需要php -m可以一次性列出已加载模块。如果发现curl没开在宝塔或小皮面板里直接勾选后重载PHP进程即可。2.3 上传、伪静态与目录权限拿到压缩包后先别急着双击打开。我一般这样操作上传zip文件到站点目录再在命令行解压避免Windows解压工具把文件权限搞乱。unzip lianxi_ai.zip -d /var/www/html/ai chown -R www-data:www-data /var/www/html/ai chmod -R 755 /var/www/html/ai chmod -R 775 /var/www/html/ai/data第一条命令把压缩包解压到指定目录第二条把运行用户调整为PHP-FPM对应的www-data第三条给目录读权限第四条给data目录写权限——用户注册、配置缓存都要写文件这一步漏了后台能进但一保存配置就白屏。nginx环境建议在站点配置里加一段伪静态把不存在的路径全部交给入口文件处理location / { try_files $uri $uri/ /index.php?$query_string; }这段配置保证当你访问一个不存在路径时不会直接返回404而是交给index.php去路由。Apache环境则检查 .htaccess 是否随包带出没有就自己加一行 RewriteRule。2.4 首次部署后怎么验证部署完不要急着注册。先做两件事第一访问入口地址看页面是否正常渲染第二浏览器打开F12的Network面板随便发一条消息观察是否有一个发往网关接口的POST请求。如果没有多半是伪静态没生效。此时去PHP错误日志看一眼典型路径在 /var/log/nginx/error.log。用tail实时跟踪是排错最快的方式tail -f /var/log/php-fpm.log /var/log/nginx/error.log日志里出现 undefined index 多半是PHP 8版本下某处数组取值没加空值判断出现 Permission denied 就是前面说的目录权限问题。把这两个坑排掉系统就跑得起来了。3. session用户管理到一键接口配置的实现细节3.1 注册/登录用session就可以这个源码没有用数据库用户数据落在JSON文件里所以身份态用PHP自带session就够。不要一上来就引入Redis、JWT那对这个规模的项目是过度设计。登录接口的核心是校验密码时用 password_verify而不是直接把明文取出来比较。?php session_start(); $users json_decode(file_get_contents(__DIR__ . /data/users.json), true); if ($_POST[username] $_POST[password]) { foreach ($users as $user) { if (hash_equals($user[name], $_POST[username]) password_verify($_POST[password], $user[hash])) { session_regenerate_id(true); $_SESSION[user] $user[name]; header(Location: /chat.php); exit; } } }这里用了两个容易被忽略的函数hash_equals做字符串比对可以防时序攻击session_regenerate_id(true)在登录成功后更换session ID避免会话固定攻击。如果你要在这个基础上加“管理员”角色只需在用户数组里加一个admin字段登录后写入session。3.2 一键添加/修改接口把模型配置独立成数组后台“一键添加接口”的本质不是写死代码而是往配置数组里插入一段新的连接信息。我建议把config.php变成返回数组的纯配置文件而不是直接放一堆define。// config.php 只返回一个数组后面通过加载函数读取 return [ models [ openai_chat [ name 通用对话模型, base_url https://api.example.com/v1, api_key sk-xxxx, model gpt-4o, mode text_chat, temperature 0.7 ], image_draw [ name 文生图, base_url https://api.example.com/v1, api_key sk-yyyy, model image-gen-1, mode image_create ] ] ];在PHP里接口配置本身就是“数组对象化”的典型场景数组作为容器json_encode之后就变成可以被前端和第三方消费者读取的JSON对象。你需要让后台保存接口时把整个models数组重新写回config.php或data/cache.php代码如下$models $config[models]; $models[$_POST[alias]] [ name $_POST[name], base_url rtrim($_POST[base_url], /), api_key $_POST[api_key], model $_POST[model], mode $_POST[mode] ]; file_put_contents(__DIR__ . /data/cache.php, ?php return . var_export($models, true) . ;);rtrim函数去掉base_url末尾的斜杠避免后面拼接/chat/completions时出现双斜杠var_export能把数组转成可执行的PHP代码这是轻量级项目里最常用的“缓存配置”方式。所谓“一键修改接口”其实就是重新提交一遍这个表单让新配置覆盖旧配置。3.3 5个模型切换时前端传什么参数前端的聊天框一般是一个下拉框切换时把模型别名发给网关。我建议统一用一个mode字段来区分业务能力而不是直接暴露具体模型名。包里附带的5个API接口源码正好覆盖五种常见模式mode值用途典型请求方text_chat多轮对话聊天窗口text_complete单轮续写编辑器内容生成image_create文转图图片生成页image_edit图转图图片编辑页vision_chat图片理解传图后提问前端切换时实际上是一段很短的JS把mode塞进请求体async function send() { const resp await fetch(/api.php, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ mode: currentMode, // 来自下拉框 model: currentModel, // 具体的模型别名 message: input.value }) }); return resp.json(); }后端拿到mode后先去models数组里找对应的配置根据配置里的模式决定调用对话接口还是图像接口。这一步决定了后续请求转发逻辑所以用mode而不是model作为第一层判断能避免一个模型同时支持多种模式时把逻辑写乱。4. 文生图/图生图与API接口源码的对接实战4.1 PHP curl转发对话请求只要模型API兼容OpenAI格式就可以用同一段curl代码完成转发。你需要把前端的消息、系统提示词、温度和模型名拼成标准负载再带Authorization头发出去。function chat_request(array $config, array $messages): array { $ch curl_init($config[base_url] . /chat/completions); $payload [ model $config[model], messages $messages, temperature $config[temperature] ?? 0.7 ]; curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER true, CURLOPT_POST true, CURLOPT_HTTPHEADER [ Content-Type: application/json, Authorization: Bearer . $config[api_key] ], CURLOPT_POSTFIELDS json_encode($payload) ]); $resp curl_exec($ch); $status curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); return [http_code $status, data json_decode($resp, true)]; }CURLOPT_RETURNTRANSFER让curl_exec返回响应体而不是直接输出CURLINFO_HTTP_CODE用来区分“模型正常返回”和“鉴权失败”。很多新手只处理返回内容忽略状态码导致拿到的错误信息被当成正常业务数据展示给用户。建议遇到非200状态时把响应体里的error原文记录到日志。4.2 文生图和图生图图片响应与base64处理文生图的响应通常是两个字段之一返回图片URL或返回base64编码。URL直接放给前端img标签即可base64则要在PHP里解码后存文件或直接输出。图生图逻辑正好相反前端先把图片用canvas转成base64再POST到网关由PHP解回二进制传给模型接口。// 图生图接收前端上传的图片base64 $image_b64 $_POST[image_b64] ?? ; // 去掉 data:image/png;base64, 这种前缀 if (strpos($image_b64, ,) ! false) { $image_b64 explode(,, $image_b64, 2)[1]; } $image_bin base64_decode($image_b64); $ch curl_init($config[base_url] . /images/edits); curl_setopt_array($ch, [ CURLOPT_POST true, CURLOPT_RETURNTRANSFER true, CURLOPT_HTTPHEADER [Authorization: Bearer . $config[api_key]], CURLOPT_POSTFIELDS [ image new CURLFile( data://text/plain;base64, . base64_encode($image_bin), image/png, input.png ), prompt $_POST[prompt] ] ]);CURLFile封装文件变量是PHP里对接multipart/form-data的标准姿势data流方式可以不用把图片落盘。注意如果你的PHP版本没有开allow_url_fopendata://协议可能被禁这时建议先把图片写入临时目录再构造CURLFile路径用 sys_get_temp_dir() 拼一个随机文件名。还有个小坑前端canvas转出来的data URL可能包含空格要先trim再解码。4.3 5个API接口源码怎么用资源包里附带的那份API接口源码本质是把网关能力开放给其他站点。使用方只需要拿一个分配好的key按固定格式POST即可。常见的对接协议就是php接口数组对象的标准玩法表单或JSON提交返回统一结构。// 接入方demo调用莲匸AI网关 $payload [ api_key 分配给用户的key, mode text_chat, model openai_chat, message 写一段PHP实现线程池的代码 ]; $ch curl_init(https://你的域名/api/v1/chat); curl_setopt_array($ch, [ CURLOPT_POST true, CURLOPT_POSTFIELDS http_build_query($payload), CURLOPT_RETURNTRANSFER true, CURLOPT_TIMEOUT 60 ]); $result curl_exec($ch); $data json_decode($result, true); // 返回示例{code:0,data:{reply:...,tokens:123}}http_build_query会把数组转成application/x-www-form-urlencoded格式适合老系统、低版本cURL环境如果你做的是新项目更推荐直接用JSON body并在header里写Content-Type: application/json。CURLOPT_TIMEOUT要设长一点大模型回复经常超过20秒默认超时时间会直接掐断请求。网关那侧收到请求后先校验api_key是否在允许列表里再根据mode调用对应的处理函数。建议处理函数按表结构维护比如一个handlers数组mode作索引这样后面每加一种能力就注册一个回调不用改动入口逻辑。5. 生产环境必做的限流、日志与手机端适配5.1 给聊天接口加一个简单的IP限流AI接口比普通页面更容易被刷因为每次请求都在消耗第三方模型额度。不用上Redis用PHP文件锁就能实现临时限流$ip $_SERVER[REMOTE_ADDR]; $file sys_get_temp_dir() . /limit_ . md5($ip); $count (int)file_get_contents($file); if ($count 10) { exit(json_encode([code 429, msg 请求太频繁])); } file_put_contents($file, $count 1);这里用IP哈希做文件名避免不同用户互相干扰文件里只存数字每请求加1。要支持按时间窗口重置就把expire时间一并写进文件判断过期后清0。5.2 把API请求和错误响应写入日志建议在网关入口统一写一行访问日志包含时间、IP、mode、http_code和耗时。这样排查“为什么某个模型偶尔超时”时有数据可以对着看。$start microtime(true); // 原有业务逻辑 error_log(json_encode([ time date(Y-m-d H:i:s), ip $_SERVER[REMOTE_ADDR], mode $_POST[mode], model $_POST[model], http_code $http_code, cost_ms round((microtime(true) - $start) * 1000) ]) . PHP_EOL, 3, __DIR__ . /data/api.log);error_log的第三个参数是文件路径第三个是消息类型。注意日志文件权限要跟运行用户一致否则会白屏。正式上线后建议把api.log排除出备份目录避免日志膨胀。5.3 手机端适配和免登录演示入口这个系统最后落到使用端最常见的两个诉求手机端打开好看以及给访客发一个不用注册就能体验的入口。聊天界面用viewport meta对齐textarea用flex布局就能在手机端获得不错的体验。免登录入口不要直接跳过session而是建一个guest用户请求时自动把token挂在header里。这样既能控制额度又不会破坏登录用户的数据隔离。测试时用curl带cookie访问一次确认guest会落到同一个限流IP维度防止有人换着游客身份无限刷。本文还有配套的精品资源点击获取
返回列表