本文档介绍如何在小手机系统中开发自定义应用并调用系统API。
在小手机系统中,进入"应用商店" -> "创建应用",创建一个新的HTML应用。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>我的应用</title>
<style>
/* 你的样式 */
</style>
</head>
<body>
<h1>欢迎使用小手机API</h1>
<script>
// 在这里调用API
</script>
</body>
</html>
if (window.phoneAPI) {
console.log('小手机API已就绪');
} else {
console.log('API未就绪,请确保在小手机系统中运行');
}
| API方法 | 权限要求 | 说明 |
|---|---|---|
requestAuth() | 无 | 请求用户授权 |
checkPermission() | 无 | 检查权限状态 |
getAuthCode() | 无 | 获取已保存的授权码 |
| 聊天记录 | ||
getChatHistory() | read_chat | 获取聊天记录 |
getChatSessions() | read_chat | 获取会话列表 |
getMemories() | read_chat | 获取长期记忆列表 |
addMemory() | write_memory | 添加长期记忆 |
updateMemory() | write_memory | 修改长期记忆 |
addMessage() | write_chat | 添加聊天记录 |
| 用户 | ||
getUserInfo() | read_user | 获取用户信息 |
| AI功能 | ||
callLLM() | call_llm | 调用AI对话 |
callTTS() | call_tts | 语音合成 |
| 角色卡 | ||
getCharacterCards() | read_character | 获取所有角色卡 |
getCharacterCard() | read_character | 获取单个角色卡 |
createCharacterCard() | write_character | 创建角色卡 |
updateCharacterCard() | write_character | 更新角色卡 |
deleteCharacterCard() | write_character | 删除角色卡 |
| 世界书 | ||
getWorldBooks() | read_worldbook | 获取所有世界书 |
getWorldBookCategories() | read_worldbook | 获取世界书分类 |
createWorldBook() | write_worldbook | 创建世界书 |
updateWorldBook() | write_worldbook | 更新世界书 |
deleteWorldBook() | write_worldbook | 删除世界书 |
| 通讯录 | ||
getContacts() | read_contact | 获取所有联系人 |
getContact() | read_contact | 获取单个联系人 |
createContact() | write_contact | 创建联系人 |
updateContact() | write_contact | 更新联系人 |
deleteContact() | write_contact | 删除联系人 |
| 角色信息 | ||
getCharacterFullInfo() | read_contact | 获取角色完整信息(名称、头像、角色卡、世界书、记忆) |
| 权限 | 类型 | 说明 |
|---|---|---|
| 聊天记录 | ||
read_chat | 读取 | 获取完整的聊天记录内容 |
write_memory | 写入 | 添加和修改角色的长期记忆 |
write_chat | 写入 | 在聊天中发送消息 |
| 用户 | ||
read_user | 读取 | 获取你的昵称、头像等基本信息 |
| AI功能 | ||
call_llm | 写入 | 调用AI大模型进行对话 |
call_tts | 写入 | 将文字转换为语音 |
| 角色卡 | ||
read_character | 读取 | 查看和使用角色卡信息 |
write_character | 写入 | 创建和修改角色卡 |
| 世界书 | ||
read_worldbook | 读取 | 查看世界书内容 |
write_worldbook | 写入 | 创建和修改世界书 |
| 通讯录 | ||
read_contact | 读取 | 查看通讯录中的人物 |
write_contact | 写入 | 添加和修改通讯录人物 |
read_chat, read_user, read_character, read_worldbook, read_contactwrite_memory, write_chat, call_llm, call_tts, write_character, write_worldbook, write_contact| API | 权限类型 | 是否需要授权码 | 授权码类型 |
|---|---|---|---|
| 读取类API | |||
getChatHistory() | 读取 | ❌ 不需要 | - |
getChatSessions() | 读取 | ❌ 不需要 | - |
getUserInfo() | 读取 | ❌ 不需要 | - |
getMemories() | 读取 | ❌ 不需要 | - |
getCharacterCards() | 读取 | ❌ 不需要 | - |
getCharacterCard() | 读取 | ❌ 不需要 | - |
getWorldBooks() | 读取 | ❌ 不需要 | - |
getWorldBookCategories() | 读取 | ❌ 不需要 | - |
getContacts() | 读取 | ❌ 不需要 | - |
getContact() | 读取 | ❌ 不需要 | - |
| 写入类API | |||
callLLM() | 写入 | ✅ 需要 | call_llm |
callTTS() | 写入 | ✅ 需要 | call_tts |
addMemory() | 写入 | ✅ 需要 | write_memory |
updateMemory() | 写入 | ✅ 需要 | write_memory |
addMessage() | 写入 | ✅ 需要 | write_chat |
createCharacterCard() | 写入 | ✅ 需要 | write_character |
updateCharacterCard() | 写入 | ✅ 需要 | write_character |
deleteCharacterCard() | 写入 | ✅ 需要 | write_character |
createWorldBook() | 写入 | ✅ 需要 | write_worldbook |
updateWorldBook() | 写入 | ✅ 需要 | write_worldbook |
deleteWorldBook() | 写入 | ✅ 需要 | write_worldbook |
createContact() | 写入 | ✅ 需要 | write_contact |
updateContact() | 写入 | ✅ 需要 | write_contact |
deleteContact() | 写入 | ✅ 需要 | write_contact |
// 请求单个权限
const result = await window.phoneAPI.requestAuth(['read_chat']);
// 请求多个权限
const result = await window.phoneAPI.requestAuth([
'read_chat',
'call_llm',
'read_user'
]);
// 处理结果
if (result.success) {
console.log('授权成功');
// result.data 是授权结果数组,每个权限对应一个结果
result.data.forEach(authResult => {
console.log('权限:', authResult.permissionType);
console.log('授权码:', authResult.authCode); // 写入权限会有授权码
console.log('级别:', authResult.level); // 'always' 或 'once'
});
// 获取第一个权限的授权码(用于单个权限)
const authCode = result.data[0]?.authCode;
} else {
console.log('授权失败:', result.error);
if (result.error === '弹窗被阻止,请允许弹窗后重试') {
alert('请允许浏览器弹窗,然后重新点击授权按钮');
}
}
注意: 授权窗口会以弹窗形式打开,请确保浏览器允许弹窗,否则授权会失败。
const result = await window.phoneAPI.getChatHistory(
sessionId, // 会话ID(必需)
limit // 限制条数(可选,默认全部)
);
if (result.success) {
const messages = result.data;
messages.forEach(msg => {
console.log(msg.senderId, ':', msg.content);
});
}
注意: 此API需要 read_chat 权限,但不需要授权码。
返回数据格式:
{
id: string;
sessionId: string;
senderId: string;
content: string;
type: 'text' | 'voice' | 'image' | 'sticker';
timestamp: Date;
status: 'sent' | 'delivered' | 'read';
}
const result = await window.phoneAPI.addMemory(
sessionId, // 会话ID(必需)
content, // 记忆内容(必需)
authCode // 授权码(必需)
);
if (result.success) {
console.log('记忆已添加:', result.data.id);
}
const result = await window.phoneAPI.updateMemory(
memoryId, // 记忆ID(必需)
content, // 新内容(必需)
authCode // 授权码(必需)
);
if (result.success) {
console.log('记忆已更新');
}
const result = await window.phoneAPI.addMessage(
sessionId, // 会话ID(必需)
content, // 消息内容(必需)
authCode, // 授权码(必需)
senderId // 发送者ID(可选,默认为 app_应用ID)
);
if (result.success) {
console.log('消息已发送:', result.data.id);
}
const result = await window.phoneAPI.getUserInfo(authCode);
if (result.success) {
const user = result.data;
console.log('昵称:', user.name);
console.log('头像:', user.avatar);
}
返回数据格式:
{
id: string;
name: string;
avatar: string;
settings: object;
balance?: number;
createdAt: Date;
}
const result = await window.phoneAPI.callLLM(
[
{ role: 'system', content: '你是一个助手' },
{ role: 'user', content: '你好' }
],
authCode,
{
temperature: 0.7, // 可选,默认0.7
max_tokens: 2000 // 可选
}
);
if (result.success) {
console.log('AI回复:', result.data.content);
console.log('使用模型:', result.data.model);
}
const result = await window.phoneAPI.callTTS(
'你好,这是测试文本',
authCode,
{
voiceId: 'male-qn-qingse', // 可选,音色ID
speed: 1.0, // 可选,语速 (0.5-2.0)
vol: 1.0, // 可选,音量 (0.1-10.0)
pitch: 0, // 可选,音调 (-12 到 12)
emotion: 'happy' // 可选,情感 (happy, sad, angry, neutral等)
}
);
if (result.success) {
const audio = new Audio(result.data.audioUrl);
audio.play();
}
参数说明:
voiceId: 音色ID,不同TTS提供商支持的音色不同speed: 语速,范围通常是 0.5-2.0,1.0为正常语速vol: 音量,范围通常是 0.1-10.0,1.0为正常音量pitch: 音调,范围通常是 -12 到 12,0为正常音调emotion: 情感风格,如 happy, sad, angry, neutral 等注意: 具体支持的参数取决于系统配置的TTS提供商(MiniMax或其他)
const result = await window.phoneAPI.getChatSessions(authCode);
if (result.success) {
const sessions = result.data;
sessions.forEach(session => {
console.log('会话:', session.name, 'ID:', session.id);
});
}
const result = await window.phoneAPI.getMemories(sessionId, authCode);
if (result.success) {
const memories = result.data;
memories.forEach(memory => {
console.log('记忆:', memory.content);
});
}
const result = await window.phoneAPI.checkPermission('read_chat');
if (result.success) {
console.log('是否已授权:', result.data.granted);
console.log('授权级别:', result.data.level); // 'always' | 'once' | undefined
}
const result = await window.phoneAPI.getAuthCode('call_llm');
if (result.success && result.data) {
console.log('授权码:', result.data.code);
console.log('级别:', result.data.level);
}
获取所有角色卡:
const result = await window.phoneAPI.getCharacterCards();
if (result.success) {
result.data.forEach(character => {
console.log('角色:', character.name);
console.log('设定:', character.systemPrompt);
});
}
创建角色卡:
const result = await window.phoneAPI.createCharacterCard({
name: '新角色',
avatar: 'https://example.com/avatar.png', // 可选
systemPrompt: '你是一个友善的助手...',
tags: ['助手', 'AI']
}, authCode);
if (result.success) {
console.log('创建成功,ID:', result.data.id);
}
更新角色卡:
const result = await window.phoneAPI.updateCharacterCard(
characterId,
{ name: '新名称', systemPrompt: '新设定...' },
authCode
);
删除角色卡:
const result = await window.phoneAPI.deleteCharacterCard(characterId, authCode);
获取所有世界书:
const result = await window.phoneAPI.getWorldBooks();
if (result.success) {
result.data.forEach(book => {
console.log('世界书:', book.name);
});
}
获取世界书分类:
const result = await window.phoneAPI.getWorldBookCategories();
创建世界书:
const result = await window.phoneAPI.createWorldBook({
name: '新世界书',
categoryId: 'category-id', // 可选
content: '世界设定内容...'
}, authCode);
更新世界书:
const result = await window.phoneAPI.updateWorldBook(
bookId,
{ name: '新名称', content: '新内容...' },
authCode
);
删除世界书:
const result = await window.phoneAPI.deleteWorldBook(bookId, authCode);
获取所有联系人:
const result = await window.phoneAPI.getContacts();
if (result.success) {
result.data.forEach(contact => {
console.log('联系人:', contact.name);
console.log('类型:', contact.type); // 'private' | 'group'
});
}
获取单个联系人:
const result = await window.phoneAPI.getContact(contactId);
创建联系人:
const result = await window.phoneAPI.createContact({
name: '新联系人',
avatar: 'https://example.com/avatar.png', // 可选
type: 'private', // 'private' | 'group'
memberIds: [] // 群聊时填写成员ID
}, authCode);
更新联系人:
const result = await window.phoneAPI.updateContact(
contactId,
{ name: '新名称', avatar: '新头像URL' },
authCode
);
删除联系人:
const result = await window.phoneAPI.deleteContact(contactId, authCode);
获取角色完整信息(名称、头像、角色卡、世界书、记忆):
const result = await window.phoneAPI.getCharacterFullInfo(sessionId);
if (result.success) {
const { contact, characterCards, worldBooks, memories } = result.data;
// 角色名称和头像
console.log('角色名称:', contact.name);
console.log('角色头像:', contact.avatar);
console.log('角色类型:', contact.type); // 'private' | 'group'
// 角色卡信息
console.log('\n角色卡数量:', characterCards.length);
characterCards.forEach(card => {
console.log('- 角色卡名称:', card.name);
console.log(' 设定:', card.systemPrompt);
console.log(' 标签:', card.tags);
});
// 世界书信息
console.log('\n世界书数量:', worldBooks.length);
worldBooks.forEach(book => {
console.log('- 世界书名称:', book.name);
console.log(' 内容:', book.content);
});
// 长期记忆
console.log('\n长期记忆数量:', memories.length);
memories.forEach(memory => {
console.log('- 记忆内容:', memory.content);
console.log(' 创建时间:', memory.createdAt);
});
}
返回数据结构:
{
contact: {
id: string;
name: string; // 角色名称
avatar?: string; // 角色头像URL
type: 'private' | 'group';
memberIds?: string[]; // 关联的角色卡ID列表
worldId?: string; // 关联的世界书ID
// ... 其他字段
},
characterCards: [ // 关联的角色卡列表
{
id: string;
name: string;
avatar?: string;
systemPrompt: string;
tags?: string[];
createdAt: Date;
}
],
worldBooks: [ // 关联的世界书列表
{
id: string;
name: string;
content: string;
categoryId?: string;
createdAt: Date;
}
],
memories: [ // 长期记忆列表
{
id: string;
sessionId: string;
content: string;
createdAt: Date;
updatedAt: Date;
}
]
}
我们提供了一个完整的 API 测试应用 api_test.html,包含所有 API 的测试用例:
使用方法:
api_test.html 的内容复制到应用中| 错误码 | 说明 | 处理方式 |
|---|---|---|
AUTH_REQUIRED | 需要授权 | 调用 requestAuth() 获取授权 |
AUTH_INVALID | 授权码无效 | 重新请求授权 |
AUTH_EXPIRED | 授权码已过期 | 重新请求授权 |
AUTH_USED | 授权码已使用 | 重新请求授权(一次性授权码) |
PERMISSION_DENIED | 权限被拒绝 | 用户拒绝了权限申请 |
API_ERROR | API调用错误 | 检查API配置或重试 |
PARAM_INVALID | 参数无效 | 检查传入的参数 |
NOT_FOUND | 资源不存在 | 检查ID是否正确 |
async function safeAPICall() {
try {
const result = await window.phoneAPI.getChatHistory(sessionId, authCode);
if (!result.success) {
switch (result.errorCode) {
case 'AUTH_REQUIRED':
case 'AUTH_INVALID':
case 'AUTH_EXPIRED':
// 需要重新授权
const authResult = await window.phoneAPI.requestAuth(['read_chat']);
if (authResult.success) {
// 使用新授权码重试
return await window.phoneAPI.getChatHistory(
sessionId,
authResult.authCode
);
}
break;
case 'PERMISSION_DENIED':
alert('用户拒绝了权限申请');
break;
case 'NOT_FOUND':
alert('会话不存在');
break;
default:
alert('API调用失败:' + result.error);
}
return null;
}
return result.data;
} catch (error) {
console.error('API调用异常:', error);
alert('发生错误:' + error.message);
return null;
}
}
// 缓存授权码
const authCache = {};
async function getAuthCode(permissionType) {
// 检查缓存
if (authCache[permissionType]) {
// 检查权限状态
const check = await window.phoneAPI.checkPermission(permissionType);
if (check.success && check.data.granted) {
return authCache[permissionType];
}
}
// 重新申请
const result = await window.phoneAPI.requestAuth([permissionType]);
if (result.success) {
authCache[permissionType] = result.authCode;
return result.authCode;
}
return null;
}
async function loadDataWithLoading() {
showLoading();
try {
const result = await window.phoneAPI.getChatHistory(sessionId, authCode);
if (result.success) {
displayData(result.data);
} else {
showError('加载失败:' + result.error);
}
} finally {
hideLoading();
}
}
const result = await window.phoneAPI.getChatSessions(authCode);
if (result.success) {
const sessions = result.data;
// 显示会话列表让用户选择
}
重新调用 requestAuth() 申请新的授权码。
可以,传入权限数组即可:
await window.phoneAPI.requestAuth(['read_chat', 'call_llm', 'read_user']);
不可以,API只能在小手机系统的HTML应用中运行。
getCharacterFullInfo() API,可获取角色完整信息(名称、头像、角色卡、世界书、记忆)api_test.htmlgetAuthCode() API如有问题或建议,请联系:
文档版本: 1.2.0
最后更新: 2026-02-14