# 一言
**Repository Path**: byusistudio/hitokoto-api
## Basic Information
- **Project Name**: 一言
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: AGPL-3.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-08-01
- **Last Updated**: 2026-09-05
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# ByUsi Studio · 一言 API
> 一个轻量、自托管的随机一言(Hitokoto)API,基于 PHP 实现,收录动画、漫画、游戏、文学、诗词、网易云热评等 12 大分类,为你的网站、小程序、应用提供优美的随机句子接口。
本一言库基于 [hitokoto-osc/sentences-bundle](https://github.com/hitokoto-osc/sentences-bundle) 构建,感谢原作者及所有贡献者。
---
## 特性
- **纯 PHP 零依赖** —— 无需数据库,无需 Composer,上传即用。核心逻辑由 `index.php`(分发器)、`lib/helpers.php`(共享辅助函数)与 `templates/`(独立输出模板)组成。
- **12 大分类** —— 动画 / 漫画 / 游戏 / 文学 / 原创 / 网络 / 其他 / 影视 / 诗词 / 网易云 / 哲学 / 抖机灵。
- **十种输出格式** —— 支持 `text` / `json` / `json5` / `xml` / `ini` / `toml` / `js` / `sh` / `bat` / `ps1`,覆盖前后端与脚本场景。
- **元信息自描述** —— 除 `text` 格式外,其余格式均在响应中包含 API 地址、开源仓库地址与开源协议(AGPLv3)。
- **模板可扩展** —— 每种输出格式对应 `templates/` 下一个独立文件,支持的格式列表由目录自动发现,新增格式只需新增模板文件。
- **灵活筛选** —— 支持单分类或多分类组合随机,参数向下兼容原一言协议。
- **性能优化** —— 先随机选定分类,再按需加载对应 JSON 文件,避免一次性载入全部数据。
- **内置文档界面** —— 基于 VitePress + vitepress-plugin-tabs 构建,无参数访问时自动重定向至 `./docs/`,提供分类预览、参数说明、多格式标签页示例与在线测试 Playground。
- **子路径友好** —— API 与文档资源均使用相对路径,VitePress 以 `base: './'` 构建,可部署在域名根目录或任意子路径(如 `/yy/`),同一份构建产物无需重新构建。
---
## 项目结构
```
hitokoto/
├── index.php # API 入口(参数处理、数据加载、元信息准备、模板分发;无参数时 302 至 ./docs/)
├── categories.json # 分类元数据(名称、描述、key、路径)
├── LICENSE # AGPL-3.0 协议
├── README.md # 本文件
├── package.json # 文档构建脚本与依赖(vitepress / vitepress-plugin-tabs / vue)
├── docs/ # VitePress 构建产物(gitignored,部署为 ./docs/)
├── docs-src/ # VitePress 文档源码
│ ├── .vitepress/
│ │ ├── config.ts # base:'./' / cleanUrls:false / outDir:'../docs' / tabs 插件
│ │ └── theme/ # 主题定制(蓝黄配色)+ Playground.vue / CategoryGrid.vue 组件
│ ├── index.md # 单页文档源(hero + 分类 + 参数 + 格式示例 tabs + 在线测试)
│ └── router.php # dev-only:给 .json 加 CORS 头(不部署)
├── lib/
│ └── helpers.php # 共享辅助函数(JSON 编码、API 基址、Shell/PS1 转义)
├── templates/ # 输出格式模板(每格式一个文件,自动发现)
│ ├── text.php # 纯文本(仅一言内容,无元信息)
│ ├── json.php # JSON 完整元数据
│ ├── json5.php # JSON5(带注释、未加引号键名)
│ ├── xml.php # XML
│ ├── ini.php # INI
│ ├── toml.php # TOML
│ ├── js.php # JavaScript 变量赋值
│ ├── sh.php # POSIX Shell 变量
│ ├── bat.php # Windows 批处理变量
│ └── ps1.php # PowerShell 变量
└── sentences-bundle/
└── sentences/
├── a.json # 动画
├── b.json # 漫画
├── c.json # 游戏
├── d.json # 文学
├── e.json # 原创
├── f.json # 网络
├── g.json # 其他
├── h.json # 影视
├── i.json # 诗词
├── j.json # 网易云
├── k.json # 哲学
└── l.json # 抖机灵
```
---
## 快速开始
### 环境要求
- PHP ≥ 7.0(需启用 `json`、`mbstring` 扩展)
- 任意 Web 服务器(Apache / Nginx / IIS 等)或 PHP 内置服务器
### 部署方式
1. **构建文档**(需 Node.js ≥ 18,仅在开发机执行一次):在项目根运行 `npm install` 与 `npm run docs:build`,产物生成在 `docs/`。
2. 将 `index.php`、`categories.json`、`lib/`、`templates/`、`sentences/` 与构建出的 `docs/` 一起上传至 Web 服务器(站点根目录或子目录均可)。
3. 确保 `sentences/` 与 `templates/` 目录及其下文件可被 PHP 读取。
4. 访问 `https://your-domain/` 即会 302 跳转至文档界面,或直接调用 API。
> `docs/` 是 VitePress 构建产物(已 gitignore),同一份产物可部署到根目录或任意子路径而无需重新构建。
### 本地预览
API(PHP 内置服务器)+ 文档(VitePress dev)联调:
```bash
# 终端 A:API(用 router.php 给 .json 补 CORS 头,供 5173 跨域 fetch)
php -S 127.0.0.1:8080 docs-src/router.php -t .
# 终端 B:文档开发模式
npm install
npm run docs:dev # http://localhost:5173/
```
文档构建预览(产物在 `docs/`):
```bash
npm run docs:build
npm run docs:preview # http://localhost:4173/
```
---
## API 文档
### 请求地址
```
GET /
```
> 服务器会将对该目录的请求自动解析为 `/index.php`,故请求地址无需显式写出脚本名。
### 参数说明
| 参数名 | 类型 | 默认值 | 说明 |
| --------- | ------ | ------------ | --------------------------------------------------------------------------------------------- |
| `form` | string | `text` | **(保留原有)** 输出格式。可选:`text` / `json` / `json5` / `xml` / `ini` / `toml` / `js` / `sh` / `bat` / `ps1` |
| `encode` | string | — | **(新增)** 输出格式别名,优先级高于 `form`,便于与其他一言服务兼容。支持与 `form` 相同的全部 10 种格式。 |
| `c` | string | (全部分类) | **(新增)** 分类筛选。单个:`?c=a`;多个用英文逗号:`?c=a,b,c`。不传则随机全部分类。 |
| `charset` | string | `utf-8` | **(新增)** 响应字符集,如 `?charset=gbk`。 |
> **优先级规则**:当 `encode` 与 `form` 同时存在时,以 `encode` 为准。
> **无参数访问**:当请求未携带任何 API 参数时,将自动 `302` 重定向至 `./docs.html`。
> **无效格式**:请求不支持的格式时返回 `400`,响应体为 JSON,包含 `supported` 数组列出当前所有可用格式。
### 元信息说明
除 `text` 格式仅返回一言内容外,其余 9 种格式都会在响应中包含以下元信息:
| 字段 | 说明 |
| -------------- | --------------------------------------------------------------------- |
| `api` | 当前 API 的基础地址(根据请求自动计算,含协议、主机与所在子路径)。 |
| `repository` | 开源仓库地址,包含 `gitee` / `github` / `codeberg` 三个镜像。 |
| `license` | 开源协议名称,固定为 `AGPLv3`。 |
| `license_url` | 开源协议全文地址 `https://www.gnu.org/licenses/agpl-3.0.html`。 |
### 输出格式
#### `text`(默认)
纯文本,仅返回一言内容,不包含任何元信息。
```
樱花飘落的速度,是每秒五厘米哦。
```
#### `json`
返回完整元数据,同时保留兼容旧版的 `message` 字段,并附带 API 地址、仓库与协议信息。
```json
{
"id": 1,
"uuid": "9818ecda-9cbf-4f2a-9af8-8136ef39cfcd",
"hitokoto": "与众不同的生活方式很累人呢,因为找不到借口。",
"message": "与众不同的生活方式很累人呢,因为找不到借口。",
"type": "a",
"from": "幸运星",
"from_who": null,
"creator": "跳舞的果果",
"creator_uid": 0,
"reviewer": 0,
"commit_from": "web",
"created_at": "1468605909",
"length": 22,
"api": "https://your-domain/",
"repository": {
"gitee": "https://gitee.com/byusistudio/hitokoto-api",
"github": "https://github.com/ByUsiStudio/hitokoto-api",
"codeberg": "https://codeberg.org/ByUsiStudio/hitokoto-api"
},
"license": "AGPLv3",
"license_url": "https://www.gnu.org/licenses/agpl-3.0.html"
}
```
#### `json5`
带注释、未加引号键名、尾随逗号的 [JSON5](https://json5.org/),便于人工阅读。字段与 `json` 一致。
```json5
{
// 一言数据
id: 1,
hitokoto: "与众不同的生活方式很累人呢,因为找不到借口。",
message: "与众不同的生活方式很累人呢,因为找不到借口。", // 兼容旧版
type: "a",
from: "幸运星",
length: 22,
// 元信息:API 地址、开源仓库、开源协议
api: "https://your-domain/",
repository: {
gitee: "https://gitee.com/byusistudio/hitokoto-api",
github: "https://github.com/ByUsiStudio/hitokoto-api",
codeberg: "https://codeberg.org/ByUsiStudio/hitokoto-api",
},
license: "AGPLv3",
license_url: "https://www.gnu.org/licenses/agpl-3.0.html",
}
```
#### `xml`
```xml
1
9818ecda-9cbf-4f2a-9af8-8136ef39cfcd
a
幸运星
跳舞的果果
1468605909
22
https://your-domain/
https://gitee.com/byusistudio/hitokoto-api
https://github.com/ByUsiStudio/hitokoto-api
https://codeberg.org/ByUsiStudio/hitokoto-api
AGPLv3
https://www.gnu.org/licenses/agpl-3.0.html
```
#### `ini`
```ini
; Random Hitokoto API
; Category: a
; License: AGPLv3
[hitokoto]
content = 与众不同的生活方式很累人呢,因为找不到借口。
[quote]
content = 与众不同的生活方式很累人呢,因为找不到借口。
[meta]
type = a
from = 幸运星
from_who =
creator = 跳舞的果果
created_at = 1468605909
length = 22
[api]
url = https://your-domain/
[repository]
gitee = https://gitee.com/byusistudio/hitokoto-api
github = https://github.com/ByUsiStudio/hitokoto-api
codeberg = https://codeberg.org/ByUsiStudio/hitokoto-api
[license]
name = AGPLv3
url = https://www.gnu.org/licenses/agpl-3.0.html
```
#### `toml`
```toml
# Random Hitokoto API
# Category: a
# License: AGPLv3
[hitokoto]
content = "与众不同的生活方式很累人呢,因为找不到借口。"
[meta]
id = 1
uuid = "9818ecda-9cbf-4f2a-9af8-8136ef39cfcd"
type = "a"
from = "幸运星"
from_who = null
creator = "跳舞的果果"
creator_uid = 0
created_at = "1468605909"
length = 22
[api]
url = "https://your-domain/"
[repository]
gitee = "https://gitee.com/byusistudio/hitokoto-api"
github = "https://github.com/ByUsiStudio/hitokoto-api"
codeberg = "https://codeberg.org/ByUsiStudio/hitokoto-api"
[license]
name = "AGPLv3"
url = "https://www.gnu.org/licenses/agpl-3.0.html"
```
#### `js`
赋值给全局变量 `hitokoto`,前端可通过 `` |
| Shell 脚本中取值 | `eval "$(curl -s '/?encode=sh')"; echo $HITOKOTO` |
| GBK 字符集 | `GET /?encode=json&charset=gbk` |
### cURL 示例
```bash
# 纯文本一言
curl "https://your-domain/"
# JSON 格式,限定动画与游戏分类
curl "https://your-domain/?encode=json&c=a,c"
# Shell 变量并直接取值
eval "$(curl -s 'https://your-domain/?encode=sh')"
echo "$HITOKOTO —— $HITOKOTO_FROM"
```
---
## 分类一览
| key | 名称 | 说明 |
| --- | ------ | ------------------------------------------------ |
| `a` | 动画 | Anime - 动画 |
| `b` | 漫画 | Comic - 漫画 |
| `c` | 游戏 | Game - 游戏 |
| `d` | 文学 | Literature - 主要收录现代文学:小说、散文、戏剧 |
| `e` | 原创 | Original - 原创 |
| `f` | 网络 | Internet - 来自网络 |
| `g` | 其他 | Other - 其他 |
| `h` | 影视 | Video - 影视 |
| `i` | 诗词 | Poem - 主要收录中国古代文学:诗、歌、词、赋、曲 |
| `j` | 网易云 | NCM - 主要收录网易云音乐热评 |
| `k` | 哲学 | Philosophy - 哲学 |
| `l` | 抖机灵 | Funny - 抖机灵 |
---
## 工作原理
为避免一次性将全部 12 个 JSON 文件载入内存,API 采用「先随机分类、再按需加载」的策略:
1. 根据参数 `c` 确定候选分类集合(未传则为全部 `a-l`)。
2. 过滤出本地实际存在的有效分类文件。
3. 从有效分类中**随机选取一个**分类。
4. 仅读取该分类对应的 `sentences/{key}.json` 文件。
5. 从句子数组中随机抽取一条,准备元信息(API 地址、仓库、协议)。
6. 包含 `templates/{form}.php` 输出对应格式。
这样无论总数据量多大,每次请求的内存占用都仅与单个分类文件大小相关。
> 支持的格式列表由 `templates/` 目录自动扫描得到,新增格式只需在该目录新增一个 `{form}.php` 文件即可,无需修改 `index.php`。
---
## 文档界面
项目内置一个基于 **VitePress + vitepress-plugin-tabs** 的可视化文档站点,源码位于 `docs-src/`,构建产物位于 `docs/`(部署为 `./docs/`),提供:
- 分类卡片预览与实时句子数统计(`CategoryGrid` 组件)
- 参数说明表与元信息说明
- 10 种输出格式示例(`vitepress-plugin-tabs` 标签页展示)
- 在线测试 Playground(`Playground` 组件,支持全部 10 种格式 / 字符集 / 分类筛选,实时预览请求 URL 与响应结果)
文档界面在客户端根据当前地址自动计算 API 基址(取文档所在目录的上一级,即 `index.php` 所在目录),因此无论部署在根目录还是任意子路径均能正确显示与请求。VitePress 以 `base: './'` 构建,所有资源为相对路径,同一份产物可部署到任意子路径而无需重新构建。
### 构建文档
```bash
npm install
npm run docs:build
```
将 `docs/` 内容上传至服务器 `docs/` 目录即可。直接访问站点根目录会 302 跳转至 `./docs/`。
---
## 更新句子库
句子数据来自 [hitokoto-osc/sentences-bundle](https://github.com/hitokoto-osc/sentences-bundle) 仓库的 `dist/` 目录,按分类拆分为 `a.json` ~ `l.json`。
更新方式:
```bash
# 克隆官方句子包
git clone https://github.com/hitokoto-osc/sentences-bundle.git /tmp/bundle
# 用 dist 目录下的分类文件覆盖本地 sentences/
cp /tmp/bundle/dist/*.json ./sentences/
```
更新后无需重启服务,下一次请求即生效。
---
## 新增输出格式
得益于模板化架构,扩展一种新的输出格式只需两步:
1. 在 `templates/` 目录下新建 `{form}.php` 文件,文件内可使用 `index.php` 准备好的变量(`$hitokoto`、`$from`、`$type`、`$apiUrl`、`$repositories`、`$licenseName`、`$licenseUrl` 等)与 `lib/helpers.php` 中的辅助函数(`JSON_OUT`、`escSh()`、`escPs1()`)。
2. 完成。`index.php` 会自动发现该格式并加入 `supported` 列表,无需注册或修改入口逻辑。
模板文件只需负责设置 `Content-Type` 头并输出对应格式的内容即可,可参考现有的 `templates/json.php` 等实现。
---
## 许可协议
本项目采用 [GNU Affero General Public License v3.0](./LICENSE) 协议。
句子数据版权归各句子原作者所有,数据来源遵循 [hitokoto-osc/sentences-bundle](https://github.com/hitokoto-osc/sentences-bundle) 的相关声明。
---
## 鸣谢
- [hitokoto-osc/sentences-bundle](https://github.com/hitokoto-osc/sentences-bundle) —— 句子数据来源
- [hitokoto.cn](https://hitokoto.cn) —— 一言官方服务,本项目接口设计参考其协议
---
> Powered by ByUsi Studio