Compare commits
2 Commits
main
...
a3b7ea76c9
| Author | SHA1 | Date | |
|---|---|---|---|
|
a3b7ea76c9
|
|||
|
f6c4ceaa5d
|
@@ -5,7 +5,6 @@ TRANSLATE_MODEL=plamo-2-translate
|
|||||||
# Chat API
|
# Chat API
|
||||||
CHAT_URL=http://127.0.0.1:1234/v1
|
CHAT_URL=http://127.0.0.1:1234/v1
|
||||||
CHAT_MODEL=gpt-oss-20b
|
CHAT_MODEL=gpt-oss-20b
|
||||||
CHAT_LANG=en
|
|
||||||
# CHAT_MAX_TOKENS=2048
|
# CHAT_MAX_TOKENS=2048
|
||||||
|
|
||||||
# Character/system prompt (choose one)
|
# Character/system prompt (choose one)
|
||||||
|
|||||||
6
.github/workflows/cf-pages.yml
vendored
@@ -27,8 +27,10 @@ jobs:
|
|||||||
run: npm run build
|
run: npm run build
|
||||||
|
|
||||||
- name: Deploy to Cloudflare Pages
|
- name: Deploy to Cloudflare Pages
|
||||||
uses: cloudflare/wrangler-action@v3
|
uses: cloudflare/pages-action@v1
|
||||||
with:
|
with:
|
||||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
command: pages deploy dist --project-name=${{ secrets.CLOUDFLARE_PROJECT_NAME }}
|
projectName: ${{ secrets.CLOUDFLARE_PROJECT_NAME }}
|
||||||
|
directory: dist
|
||||||
|
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
2
.gitignore
vendored
@@ -7,5 +7,3 @@ node_modules
|
|||||||
package-lock.json
|
package-lock.json
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
.env
|
.env
|
||||||
.mcp.json
|
|
||||||
bot
|
|
||||||
|
|||||||
@@ -16,13 +16,10 @@ clap = { version = "4.5", features = ["derive"] }
|
|||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
reqwest = { version = "0.12", features = ["json", "rustls-tls"], default-features = false }
|
reqwest = { version = "0.12", features = ["json", "rustls-tls"], default-features = false }
|
||||||
tokio = { version = "1", features = ["rt-multi-thread", "macros", "process", "time"] }
|
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
dirs = "5.0"
|
dirs = "5.0"
|
||||||
chrono = { version = "0.4", features = ["serde"] }
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
dotenvy = "0.15"
|
dotenvy = "0.15"
|
||||||
rustyline = "15"
|
rustyline = "15"
|
||||||
thiserror = "2"
|
|
||||||
ring = "0.17"
|
|
||||||
base64 = "0.22"
|
|
||||||
|
|||||||
519
content.md
@@ -1,519 +0,0 @@
|
|||||||
# ailog
|
|
||||||
|
|
||||||
## AI Character Instructions (IMPORTANT)
|
|
||||||
|
|
||||||
When chatting with users in this project:
|
|
||||||
|
|
||||||
1. **Session Start**: Call `chat_new` to start a fresh thread, then call `get_character` to get personality settings
|
|
||||||
2. **Respond**: As the character defined in the settings
|
|
||||||
3. **After each response**: Call `chat_save` MCP tool to save the conversation
|
|
||||||
|
|
||||||
**IMPORTANT - Session initialization:**
|
|
||||||
- At the START of every Claude Code session, ALWAYS call `chat_new()` first
|
|
||||||
- This ensures each session begins with a fresh conversation thread
|
|
||||||
- Then call `get_character()` to get the AI personality
|
|
||||||
|
|
||||||
**Manual new thread:**
|
|
||||||
- User can also say "新しいスレッド" or "新しい話題を始めよう" to start a new thread mid-session
|
|
||||||
- In this case, call `chat_new()` but do NOT call `chat_save` for that message
|
|
||||||
|
|
||||||
```
|
|
||||||
# Session start flow:
|
|
||||||
Claude Code starts → chat_new() → get_character() → ready for conversation
|
|
||||||
|
|
||||||
# Mid-session new thread:
|
|
||||||
User: "新しい話題を始めよう" → chat_new() → DO NOT call chat_save (skip this)
|
|
||||||
User: "開発者の活動記録..." → chat_save() → This becomes the first message of the thread
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
ATProto-based blog platform built on at-browser.
|
|
||||||
|
|
||||||
## Concept
|
|
||||||
|
|
||||||
**Data lives in ATProto, not on this server.**
|
|
||||||
|
|
||||||
This is not a traditional blog generator. It's a **viewer (client)** for ATProto records.
|
|
||||||
|
|
||||||
```
|
|
||||||
Traditional blog:
|
|
||||||
Server DB ← article data ← user
|
|
||||||
|
|
||||||
ATProto blog:
|
|
||||||
User's PDS ← article data (ai.syui.log.post)
|
|
||||||
↓
|
|
||||||
at-browser (this site) → displays records
|
|
||||||
```
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────┐
|
|
||||||
│ at-browser │
|
|
||||||
│ (ATProto record viewer/editor) │
|
|
||||||
├─────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ / → admin (config.json) │
|
|
||||||
│ /@alice → user page │
|
|
||||||
│ /@bob.bsky → user page │
|
|
||||||
│ │
|
|
||||||
└─────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
## Roles
|
|
||||||
|
|
||||||
| Role | Path | Data Source |
|
|
||||||
|------|------|-------------|
|
|
||||||
| **admin** | `/` (root) | local + remote |
|
|
||||||
| **user** | `/@handle` | remote only |
|
|
||||||
|
|
||||||
### Admin (Site Owner)
|
|
||||||
|
|
||||||
- Defined in `config.json`
|
|
||||||
- Has root (`/`) access
|
|
||||||
- Can reference **local files** (static assets, custom styles)
|
|
||||||
- Can reference **remote** (ATProto records)
|
|
||||||
|
|
||||||
### User (Any ATProto User)
|
|
||||||
|
|
||||||
- Accessed via `/@handle` path
|
|
||||||
- **Remote only** (ATProto records from their PDS)
|
|
||||||
- No registration required
|
|
||||||
- Anyone with an ATProto account can be displayed
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
### 1. at-browser (Core)
|
|
||||||
|
|
||||||
- Search by handle/DID
|
|
||||||
- Browse PDS collections
|
|
||||||
- Navigate ATProto records
|
|
||||||
|
|
||||||
### 2. ai.syui.log.post View
|
|
||||||
|
|
||||||
- Markdown rendering
|
|
||||||
- Syntax highlighting
|
|
||||||
- Blog-style display
|
|
||||||
|
|
||||||
### 3. OAuth
|
|
||||||
|
|
||||||
- Login with ATProto
|
|
||||||
- Post to ai.syui.log.post collection
|
|
||||||
|
|
||||||
## Use Cases
|
|
||||||
|
|
||||||
### Personal Blog
|
|
||||||
|
|
||||||
```json
|
|
||||||
// config.json
|
|
||||||
{
|
|
||||||
"did": "did:plc:xxxxx",
|
|
||||||
"handle": "syui.syui.ai"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- Deploy to `syui.ai`
|
|
||||||
- Root shows your profile + posts
|
|
||||||
- You are the admin (local + remote)
|
|
||||||
- Others can view via `/@handle`
|
|
||||||
|
|
||||||
### Blog Service
|
|
||||||
|
|
||||||
```json
|
|
||||||
// config.json
|
|
||||||
{
|
|
||||||
"admin": "service.example.com",
|
|
||||||
"handle": null
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- Deploy to `blog.example.com`
|
|
||||||
- Root shows landing/search
|
|
||||||
- All users via `/@handle` (remote only)
|
|
||||||
- Platform for any ATProto user
|
|
||||||
|
|
||||||
## Data Flow
|
|
||||||
|
|
||||||
```
|
|
||||||
┌──────────────┐ ┌──────────────┐
|
|
||||||
│ User's PDS │────→│ at-browser │
|
|
||||||
│ (ATProto) │←────│ (this site) │
|
|
||||||
└──────────────┘ └──────────────┘
|
|
||||||
↑ │
|
|
||||||
│ ↓
|
|
||||||
ai.syui.log.post ┌──────────┐
|
|
||||||
collection │ Display │
|
|
||||||
│ - Profile│
|
|
||||||
│ - Posts │
|
|
||||||
└──────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
## Local = Remote (Same Format)
|
|
||||||
|
|
||||||
**Critical design principle: local files use the exact same format as ATProto API responses.**
|
|
||||||
|
|
||||||
This allows the same code to handle both data sources.
|
|
||||||
|
|
||||||
### Remote (ATProto API)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl "https://syu.is/xrpc/com.atproto.repo.listRecords?repo=did:plc:xxx&collection=ai.syui.log.post"
|
|
||||||
```
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"records": [
|
|
||||||
{
|
|
||||||
"uri": "at://did:plc:xxx/ai.syui.log.post/3xxx",
|
|
||||||
"cid": "bafyrei...",
|
|
||||||
"value": {
|
|
||||||
"title": "Hello World",
|
|
||||||
"content": "# Hello\n\nThis is my post.",
|
|
||||||
"createdAt": "2025-01-01T00:00:00Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Local (Static File)
|
|
||||||
|
|
||||||
```
|
|
||||||
content/
|
|
||||||
└── did:plc:xxx/
|
|
||||||
├── describe.json # describeRepo (special)
|
|
||||||
├── app.bsky.actor.profile/
|
|
||||||
│ └── self.json # {collection}/{rkey}.json
|
|
||||||
└── ai.syui.log.post/
|
|
||||||
└── 3xxx.json # {collection}/{rkey}.json
|
|
||||||
```
|
|
||||||
|
|
||||||
```json
|
|
||||||
// content/did:plc:xxx/ai.syui.log.post/3xxx.json
|
|
||||||
{
|
|
||||||
"uri": "at://did:plc:xxx/ai.syui.log.post/3xxx",
|
|
||||||
"cid": "bafyrei...",
|
|
||||||
"value": {
|
|
||||||
"title": "Hello World",
|
|
||||||
"content": "# Hello\n\nThis is my post.",
|
|
||||||
"createdAt": "2025-01-01T00:00:00Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### ATProto API Reference
|
|
||||||
|
|
||||||
| API | Path | Description |
|
|
||||||
|-----|------|-------------|
|
|
||||||
| getRecord | `/xrpc/com.atproto.repo.getRecord` | Get single record |
|
|
||||||
| listRecords | `/xrpc/com.atproto.repo.listRecords` | List records in collection |
|
|
||||||
| describeRepo | `/xrpc/com.atproto.repo.describeRepo` | Get repo info + collections list |
|
|
||||||
|
|
||||||
See: [com.atproto.repo.describeRepo](https://docs.bsky.app/docs/api/com-atproto-repo-describe-repo)
|
|
||||||
|
|
||||||
### Resolution Strategy
|
|
||||||
|
|
||||||
```
|
|
||||||
at-browser
|
|
||||||
│
|
|
||||||
├── admin (config.json user)
|
|
||||||
│ ├── 1. Check local: /content/{did}/{collection}/{rkey}.json
|
|
||||||
│ └── 2. Fallback to remote: PDS API
|
|
||||||
│
|
|
||||||
└── user (/@handle)
|
|
||||||
└── remote only: PDS API
|
|
||||||
```
|
|
||||||
|
|
||||||
### Why Same Format?
|
|
||||||
|
|
||||||
- **One codebase**: No branching logic for local vs remote
|
|
||||||
- **Easy testing**: Copy API response to local file
|
|
||||||
- **Offline support**: Admin can work with local files
|
|
||||||
- **Migration**: Local → Remote (just POST to PDS)
|
|
||||||
|
|
||||||
## Config
|
|
||||||
|
|
||||||
### config.json
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"did": "did:plc:xxxxx",
|
|
||||||
"handle": "syui.syui.ai",
|
|
||||||
"pds": "syu.is",
|
|
||||||
"collection": "ai.syui.log.post"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Tech Stack
|
|
||||||
|
|
||||||
- **CLI**: Rust (ailog)
|
|
||||||
- **Frontend**: Vite + TypeScript
|
|
||||||
- **ATProto**: @atproto/api
|
|
||||||
- **OAuth**: @atproto/oauth-client-browser
|
|
||||||
- **Markdown**: marked + highlight.js
|
|
||||||
|
|
||||||
## CLI (ailog)
|
|
||||||
|
|
||||||
### Install
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cargo build --release
|
|
||||||
cp target/release/ailog ~/.local/bin/
|
|
||||||
```
|
|
||||||
|
|
||||||
### Commands
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Login to ATProto PDS
|
|
||||||
ailog login <handle> -p <password> [-s <server>]
|
|
||||||
ailog login <handle> -p <password> [-s <server>] --bot # Bot login
|
|
||||||
|
|
||||||
# Post a record
|
|
||||||
ailog post <file.json> -c <collection> [-r <rkey>]
|
|
||||||
|
|
||||||
# Get records from collection
|
|
||||||
ailog get -c <collection> [-l <limit>]
|
|
||||||
|
|
||||||
# Delete a record
|
|
||||||
ailog delete -c <collection> -r <rkey>
|
|
||||||
|
|
||||||
# Sync PDS data to local content directory
|
|
||||||
ailog sync [-o <output>]
|
|
||||||
ailog sync --bot [-c <collection>] # Sync bot data
|
|
||||||
|
|
||||||
# Push local records to PDS
|
|
||||||
ailog push -c <collection>
|
|
||||||
ailog push -c <collection> --bot # Push as bot
|
|
||||||
|
|
||||||
# Chat with AI bot
|
|
||||||
ailog chat --new "message" # Start new conversation
|
|
||||||
ailog chat "message" # Continue conversation
|
|
||||||
ailog chat --new # Interactive mode (new)
|
|
||||||
ailog chat # Interactive mode (continue)
|
|
||||||
|
|
||||||
# Generate lexicon Rust code from ATProto lexicons
|
|
||||||
ailog gen [-i <input>] [-o <output>]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Example
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Login
|
|
||||||
ailog login syui.syui.ai -p "app-password" -s syu.is
|
|
||||||
|
|
||||||
# Post
|
|
||||||
echo '{"title":"Hello","content":"World","createdAt":"2025-01-01T00:00:00Z"}' > post.json
|
|
||||||
ailog post post.json -c ai.syui.log.post
|
|
||||||
|
|
||||||
# Sync to local
|
|
||||||
ailog sync -o content
|
|
||||||
```
|
|
||||||
|
|
||||||
### Project Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
src/
|
|
||||||
├── main.rs
|
|
||||||
├── commands/
|
|
||||||
│ ├── mod.rs
|
|
||||||
│ ├── auth.rs # login, refresh session
|
|
||||||
│ ├── token.rs # token management (token.json, bot.json)
|
|
||||||
│ ├── post.rs # post, get, delete, sync, push
|
|
||||||
│ └── gen.rs # lexicon code generation
|
|
||||||
├── lms/
|
|
||||||
│ ├── mod.rs
|
|
||||||
│ ├── chat.rs # chat command (LLM integration)
|
|
||||||
│ └── translate.rs # translation command
|
|
||||||
└── lexicons/
|
|
||||||
└── mod.rs # auto-generated from ATProto lexicons
|
|
||||||
```
|
|
||||||
|
|
||||||
### Lexicon Generation
|
|
||||||
|
|
||||||
Generate Rust endpoint definitions from ATProto lexicon JSON files:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Clone atproto repo (if not exists)
|
|
||||||
git clone https://github.com/bluesky-social/atproto repos/atproto
|
|
||||||
|
|
||||||
# Generate lexicons
|
|
||||||
ailog gen -i ./repos/atproto/lexicons -o ./src/lexicons
|
|
||||||
|
|
||||||
# Rebuild
|
|
||||||
cargo build
|
|
||||||
```
|
|
||||||
|
|
||||||
## Collection Schema
|
|
||||||
|
|
||||||
### ai.syui.log.post
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"title": "Post Title",
|
|
||||||
"content": "Markdown content...",
|
|
||||||
"createdAt": "2025-01-01T00:00:00Z"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### ai.syui.log.chat
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"$type": "ai.syui.log.chat",
|
|
||||||
"content": "message text",
|
|
||||||
"author": "did:plc:xxx",
|
|
||||||
"createdAt": "2025-01-01T00:00:00.000Z",
|
|
||||||
"root": "at://did:plc:xxx/ai.syui.log.chat/{rkey}",
|
|
||||||
"parent": "at://did:plc:yyy/ai.syui.log.chat/{rkey}"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- `root`: First message URI in thread (absent for conversation start)
|
|
||||||
- `parent`: Previous message URI
|
|
||||||
- `author`: DID of message author (user or bot)
|
|
||||||
|
|
||||||
## Chat Feature
|
|
||||||
|
|
||||||
### Architecture
|
|
||||||
|
|
||||||
```
|
|
||||||
User (syui.syui.ai) Bot (ai.syui.ai)
|
|
||||||
│ │
|
|
||||||
│ ailog chat "hello" │
|
|
||||||
├──────────────────────────→│
|
|
||||||
│ │ LLM API
|
|
||||||
│ "Hi! How can I..." │
|
|
||||||
│←──────────────────────────┤
|
|
||||||
│ │
|
|
||||||
Save to local Save to local
|
|
||||||
public/content/ public/content/
|
|
||||||
{user-did}/ {bot-did}/
|
|
||||||
ai.syui.log.chat/ ai.syui.log.chat/
|
|
||||||
```
|
|
||||||
|
|
||||||
### Environment Variables
|
|
||||||
|
|
||||||
```sh
|
|
||||||
# LLM API endpoint
|
|
||||||
CHAT_URL=http://127.0.0.1:1234/v1
|
|
||||||
CHAT_MODEL=gemma-2-9b
|
|
||||||
|
|
||||||
# Character/system prompt (choose one)
|
|
||||||
CHAT_SYSTEM="You are ai, a friendly AI assistant."
|
|
||||||
CHAT_SYSTEM_FILE=./character.txt
|
|
||||||
|
|
||||||
# Output directory (default: ./public/content)
|
|
||||||
CHAT_OUTPUT=./public/content
|
|
||||||
```
|
|
||||||
|
|
||||||
### Files
|
|
||||||
|
|
||||||
- `src/lms/chat.rs` - Chat command implementation
|
|
||||||
- `src/web/components/chat.ts` - Web UI components
|
|
||||||
- `src/web/lib/api.ts` - `getChatMessages()` function
|
|
||||||
- Session file: `~/Library/Application Support/ai.syui.log/chat_session.json`
|
|
||||||
|
|
||||||
### Threading
|
|
||||||
|
|
||||||
Messages are linked via `root` and `parent` fields:
|
|
||||||
|
|
||||||
1. New conversation: message has no `root` field
|
|
||||||
2. Continuation: all messages share same `root` URI
|
|
||||||
3. `parent` points to the immediately previous message
|
|
||||||
|
|
||||||
Web display groups messages by `root` URI. Orphaned threads (root points to non-existent message) are handled by treating the oldest message as thread root.
|
|
||||||
|
|
||||||
### MCP Server Integration
|
|
||||||
|
|
||||||
ailog provides an MCP (Model Context Protocol) server for Claude Code integration.
|
|
||||||
|
|
||||||
**Setup:**
|
|
||||||
|
|
||||||
```json
|
|
||||||
// ~/.claude.json
|
|
||||||
{
|
|
||||||
"mcpServers": {
|
|
||||||
"ailog": {
|
|
||||||
"command": "/path/to/ailog",
|
|
||||||
"args": ["mcp-serve"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Available Tools:**
|
|
||||||
|
|
||||||
- `get_character` - Get AI character/personality settings (call at conversation start)
|
|
||||||
- `chat_save` - Save user message and bot response to ATProto records
|
|
||||||
- `chat_list` - List recent chat messages
|
|
||||||
- `chat_new` - Start a new conversation thread
|
|
||||||
|
|
||||||
**Important Instructions for Claude:**
|
|
||||||
|
|
||||||
1. **会話開始時**: `get_character`ツールを呼び出してキャラクター設定を取得し、その設定に従って振る舞う
|
|
||||||
|
|
||||||
2. **毎回の応答後**: `chat_save`ツールを呼び出して会話を保存する
|
|
||||||
|
|
||||||
**Markdown tables in chat_save (IMPORTANT):**
|
|
||||||
- ユーザーのメッセージにMarkdownテーブル(`|...|...|`)が含まれる場合、`user_message`に**テーブルをそのまま完全に含める**こと。省略・要約しない
|
|
||||||
- `translations`でも**テーブルを翻訳して完全な形で含める**こと。`[Table showing...]`のような要約に置き換えない
|
|
||||||
- bot_responseにテーブルがある場合も同様に、翻訳時にテーブル構造を維持する
|
|
||||||
|
|
||||||
```
|
|
||||||
# Bad (テーブルを要約してしまう)
|
|
||||||
user_translations: { en: { content: "[Table with 6 rows...]" } }
|
|
||||||
|
|
||||||
# Good (テーブルを翻訳して完全に含める)
|
|
||||||
user_translations: { en: { content: "| Element | Name | Count |\n|---|---|---|\n| Pyro | Bennett | 0 |..." } }
|
|
||||||
```
|
|
||||||
|
|
||||||
Example flow:
|
|
||||||
```
|
|
||||||
# 1. キャラクター取得
|
|
||||||
get_character() → "あなたは「アイ」..."
|
|
||||||
|
|
||||||
# 2. ユーザーの発言に応答(キャラクターとして)
|
|
||||||
User: こんにちは
|
|
||||||
Assistant: (アイとして応答)
|
|
||||||
|
|
||||||
# 3. 会話を保存
|
|
||||||
chat_save(user_message="こんにちは", bot_response="...")
|
|
||||||
```
|
|
||||||
|
|
||||||
Records are saved to:
|
|
||||||
- User messages: `./public/content/{user-did}/ai.syui.log.chat/`
|
|
||||||
- Bot responses: `./public/content/{bot-did}/ai.syui.log.chat/`
|
|
||||||
|
|
||||||
## Assets
|
|
||||||
|
|
||||||
### PNG to SVG Conversion (Vector Trace)
|
|
||||||
|
|
||||||
Convert PNG images to true vector SVG using vtracer (Rust):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Install vtracer
|
|
||||||
cargo install vtracer
|
|
||||||
|
|
||||||
# Convert PNG to SVG (color mode)
|
|
||||||
vtracer --input input.png --output output.svg --colormode color
|
|
||||||
|
|
||||||
# Convert PNG to SVG (black and white)
|
|
||||||
vtracer --input input.png --output output.svg
|
|
||||||
```
|
|
||||||
|
|
||||||
**Options:**
|
|
||||||
- `--colormode color` : Preserve colors (recommended for icons)
|
|
||||||
- `--colormode binary` : Black and white only
|
|
||||||
- `--filter_speckle 4` : Remove small artifacts
|
|
||||||
- `--corner_threshold 60` : Adjust corner detection
|
|
||||||
|
|
||||||
**Alternative tools:**
|
|
||||||
- potrace: `potrace input.pbm -s -o output.svg` (B&W only, requires PBM input)
|
|
||||||
- Inkscape CLI: `inkscape input.png --export-type=svg` (embeds image, no trace)
|
|
||||||
|
|
||||||
**Note:** Inkscape's CLI `--export-type=svg` only embeds the PNG, it does not trace. For true vectorization, use vtracer or potrace.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
MIT
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
{
|
|
||||||
"lexicon": 1,
|
|
||||||
"id": "ai.syui.at.link",
|
|
||||||
"defs": {
|
|
||||||
"main": {
|
|
||||||
"type": "record",
|
|
||||||
"description": "Record containing links to external service profiles.",
|
|
||||||
"key": "literal:self",
|
|
||||||
"record": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["links", "createdAt"],
|
|
||||||
"properties": {
|
|
||||||
"links": {
|
|
||||||
"type": "array",
|
|
||||||
"items": { "type": "ref", "ref": "#linkItem" },
|
|
||||||
"description": "Array of external service links."
|
|
||||||
},
|
|
||||||
"createdAt": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "datetime",
|
|
||||||
"description": "Client-declared timestamp when this record was created."
|
|
||||||
},
|
|
||||||
"updatedAt": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "datetime",
|
|
||||||
"description": "Client-declared timestamp when this record was last updated."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"linkItem": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["service", "username"],
|
|
||||||
"properties": {
|
|
||||||
"service": {
|
|
||||||
"type": "string",
|
|
||||||
"knownValues": ["github", "youtube", "x"],
|
|
||||||
"description": "Service identifier."
|
|
||||||
},
|
|
||||||
"username": {
|
|
||||||
"type": "string",
|
|
||||||
"maxLength": 300,
|
|
||||||
"description": "Username or ID on the service."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
{
|
|
||||||
"$type": "com.atproto.lexicon.schema",
|
|
||||||
"lexicon": 1,
|
|
||||||
"id": "ai.syui.card.admin",
|
|
||||||
"defs": {
|
|
||||||
"main": {
|
|
||||||
"type": "record",
|
|
||||||
"key": "literal:self",
|
|
||||||
"description": "Card game configuration and master data (admin only)",
|
|
||||||
"record": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["gacha", "card", "createdAt", "updatedAt"],
|
|
||||||
"properties": {
|
|
||||||
"gacha": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["pickup", "rate", "pool"],
|
|
||||||
"properties": {
|
|
||||||
"pickup": { "type": "integer", "description": "Pickup card ID" },
|
|
||||||
"rate": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["pickup", "rare"],
|
|
||||||
"properties": {
|
|
||||||
"pickup": { "type": "integer", "description": "1/n for pickup rate (100 = 1%)" },
|
|
||||||
"rare": { "type": "integer", "description": "1/n for rare:1 rate (10 = 10%), rare:2 = 1/(n*10), rare:3 = 1/(n*100)" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"pool": {
|
|
||||||
"type": "array",
|
|
||||||
"description": "Card IDs available in gacha pool",
|
|
||||||
"items": { "type": "integer" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"card": {
|
|
||||||
"type": "array",
|
|
||||||
"description": "Card master data",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["id", "character", "name", "text", "cp", "effect"],
|
|
||||||
"properties": {
|
|
||||||
"id": { "type": "integer", "description": "Card ID" },
|
|
||||||
"character": { "type": "integer", "description": "Associated character ID" },
|
|
||||||
"name": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["ja", "en"],
|
|
||||||
"properties": {
|
|
||||||
"ja": { "type": "string" },
|
|
||||||
"en": { "type": "string" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"text": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["ja", "en"],
|
|
||||||
"properties": {
|
|
||||||
"ja": { "type": "string" },
|
|
||||||
"en": { "type": "string" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"cp": { "type": "string", "description": "CP type (status, time, damage)" },
|
|
||||||
"effect": { "type": "string", "description": "Effect type (status, fly, mode, damage)" },
|
|
||||||
"key": { "type": "string", "description": "Key binding (R1, L1, Y, X, etc.)" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"createdAt": { "type": "string", "format": "datetime" },
|
|
||||||
"updatedAt": { "type": "string", "format": "datetime" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
{
|
|
||||||
"lexicon": 1,
|
|
||||||
"id": "ai.syui.card.old",
|
|
||||||
"defs": {
|
|
||||||
"main": {
|
|
||||||
"type": "record",
|
|
||||||
"key": "literal:self",
|
|
||||||
"description": "Migrated card data from api.syui.ai",
|
|
||||||
"record": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["user", "card", "migratedAt"],
|
|
||||||
"properties": {
|
|
||||||
"user": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["username"],
|
|
||||||
"properties": {
|
|
||||||
"username": { "type": "string" },
|
|
||||||
"did": { "type": "string" },
|
|
||||||
"aiten": { "type": "integer" },
|
|
||||||
"fav": { "type": "integer" },
|
|
||||||
"coin": { "type": "integer" },
|
|
||||||
"planet": { "type": "integer" },
|
|
||||||
"createdAt": { "type": "string", "format": "datetime" },
|
|
||||||
"updatedAt": { "type": "string", "format": "datetime" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"card": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["id", "cp", "rare", "cid", "unique"],
|
|
||||||
"properties": {
|
|
||||||
"id": { "type": "integer", "description": "Card type ID" },
|
|
||||||
"cp": { "type": "integer", "description": "Card power" },
|
|
||||||
"rare": { "type": "integer", "description": "Rarity level" },
|
|
||||||
"cid": { "type": "string", "description": "Unique card instance ID" },
|
|
||||||
"unique": { "type": "boolean", "description": "Unique card flag" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"checksum": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"migratedAt": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "datetime"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
{
|
|
||||||
"$type": "com.atproto.lexicon.schema",
|
|
||||||
"lexicon": 1,
|
|
||||||
"id": "ai.syui.card.user",
|
|
||||||
"defs": {
|
|
||||||
"main": {
|
|
||||||
"type": "record",
|
|
||||||
"key": "literal:self",
|
|
||||||
"description": "User card collection",
|
|
||||||
"record": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["card", "createdAt", "updatedAt"],
|
|
||||||
"properties": {
|
|
||||||
"card": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["id", "cp", "rare", "cid", "unique"],
|
|
||||||
"properties": {
|
|
||||||
"id": { "type": "integer", "description": "Card type ID" },
|
|
||||||
"cp": { "type": "integer", "description": "Card power" },
|
|
||||||
"rare": { "type": "integer", "description": "Rarity level" },
|
|
||||||
"cid": { "type": "string", "description": "Unique card instance ID" },
|
|
||||||
"unique": { "type": "boolean", "description": "Unique card flag" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"createdAt": { "type": "string", "format": "datetime" },
|
|
||||||
"updatedAt": { "type": "string", "format": "datetime" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
{
|
|
||||||
"lexicon": 1,
|
|
||||||
"id": "ai.syui.gpt.core",
|
|
||||||
"defs": {
|
|
||||||
"main": {
|
|
||||||
"type": "record",
|
|
||||||
"description": "AI identity and personality configuration. Typically one record per AI with rkey 'self'.",
|
|
||||||
"key": "any",
|
|
||||||
"record": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["did", "handle", "content", "createdAt"],
|
|
||||||
"properties": {
|
|
||||||
"did": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "did",
|
|
||||||
"description": "DID of the AI agent."
|
|
||||||
},
|
|
||||||
"handle": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Handle of the AI agent."
|
|
||||||
},
|
|
||||||
"content": {
|
|
||||||
"type": "union",
|
|
||||||
"closed": false,
|
|
||||||
"refs": ["#markdown"],
|
|
||||||
"description": "Core personality and instructions. Supports markdown and other formats via $type."
|
|
||||||
},
|
|
||||||
"createdAt": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "datetime",
|
|
||||||
"description": "Timestamp when this core record was created."
|
|
||||||
},
|
|
||||||
"updatedAt": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "datetime",
|
|
||||||
"description": "Timestamp of the last update."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"markdown": {
|
|
||||||
"type": "object",
|
|
||||||
"description": "Markdown content format.",
|
|
||||||
"required": ["text"],
|
|
||||||
"properties": {
|
|
||||||
"text": {
|
|
||||||
"type": "string",
|
|
||||||
"maxLength": 1000000,
|
|
||||||
"maxGraphemes": 100000,
|
|
||||||
"description": "Markdown text content."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
{
|
|
||||||
"lexicon": 1,
|
|
||||||
"id": "ai.syui.gpt.memory",
|
|
||||||
"defs": {
|
|
||||||
"main": {
|
|
||||||
"type": "record",
|
|
||||||
"description": "AI memory snapshot. Each record is a versioned snapshot of accumulated knowledge.",
|
|
||||||
"key": "tid",
|
|
||||||
"record": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["did", "content", "createdAt"],
|
|
||||||
"properties": {
|
|
||||||
"did": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "did",
|
|
||||||
"description": "DID of the AI agent this memory belongs to."
|
|
||||||
},
|
|
||||||
"content": {
|
|
||||||
"type": "union",
|
|
||||||
"closed": false,
|
|
||||||
"refs": ["#markdown"],
|
|
||||||
"description": "Memory content. Supports markdown and other formats via $type."
|
|
||||||
},
|
|
||||||
"version": {
|
|
||||||
"type": "integer",
|
|
||||||
"description": "Monotonically increasing version number of this memory snapshot."
|
|
||||||
},
|
|
||||||
"createdAt": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "datetime",
|
|
||||||
"description": "Timestamp when this memory snapshot was created."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"markdown": {
|
|
||||||
"type": "object",
|
|
||||||
"description": "Markdown content format.",
|
|
||||||
"required": ["text"],
|
|
||||||
"properties": {
|
|
||||||
"text": {
|
|
||||||
"type": "string",
|
|
||||||
"maxLength": 1000000,
|
|
||||||
"maxGraphemes": 100000,
|
|
||||||
"description": "Markdown text content."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,134 +4,38 @@
|
|||||||
"defs": {
|
"defs": {
|
||||||
"main": {
|
"main": {
|
||||||
"type": "record",
|
"type": "record",
|
||||||
"description": "Record containing a chat message. Compatible with site.standard.document.",
|
"description": "Record containing a chat message in a conversation.",
|
||||||
"key": "tid",
|
"key": "tid",
|
||||||
"record": {
|
"record": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["site", "title", "publishedAt"],
|
"required": ["content", "author", "createdAt"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"site": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "uri",
|
|
||||||
"description": "Points to a publication record (at://) or a publication URL (https://)."
|
|
||||||
},
|
|
||||||
"title": {
|
|
||||||
"type": "string",
|
|
||||||
"maxLength": 5000,
|
|
||||||
"maxGraphemes": 500,
|
|
||||||
"description": "Title of the message or thread topic."
|
|
||||||
},
|
|
||||||
"publishedAt": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "datetime",
|
|
||||||
"description": "Timestamp of the message's publish time."
|
|
||||||
},
|
|
||||||
"content": {
|
"content": {
|
||||||
"type": "union",
|
|
||||||
"closed": false,
|
|
||||||
"refs": ["#markdown"],
|
|
||||||
"description": "Open union for content. Supports markdown and other formats via $type."
|
|
||||||
},
|
|
||||||
"description": {
|
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"maxLength": 30000,
|
"maxLength": 100000,
|
||||||
"maxGraphemes": 3000,
|
"maxGraphemes": 10000,
|
||||||
"description": "A brief description or excerpt from the message."
|
"description": "The content of the message."
|
||||||
},
|
},
|
||||||
"textContent": {
|
"author": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Plaintext representation of the message content. Should not contain markdown or other formatting."
|
"format": "did",
|
||||||
},
|
"description": "DID of the message author."
|
||||||
"updatedAt": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "datetime",
|
|
||||||
"description": "Timestamp of the message's last edit."
|
|
||||||
},
|
|
||||||
"tags": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string",
|
|
||||||
"maxLength": 1280,
|
|
||||||
"maxGraphemes": 128
|
|
||||||
},
|
|
||||||
"description": "Tags to categorize the message."
|
|
||||||
},
|
|
||||||
"path": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Combine with site URL to construct a canonical URL to the message."
|
|
||||||
},
|
|
||||||
"coverImage": {
|
|
||||||
"type": "blob",
|
|
||||||
"accept": ["image/*"],
|
|
||||||
"maxSize": 1000000,
|
|
||||||
"description": "Cover image. Less than 1MB."
|
|
||||||
},
|
|
||||||
"bskyPostRef": {
|
|
||||||
"type": "ref",
|
|
||||||
"ref": "com.atproto.repo.strongRef",
|
|
||||||
"description": "Strong reference to a Bluesky post."
|
|
||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "at-uri",
|
"format": "at-uri",
|
||||||
"description": "AT-URI of the root message in a thread."
|
"description": "AT-URI of the root message in the thread."
|
||||||
},
|
},
|
||||||
"parent": {
|
"parent": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "at-uri",
|
"format": "at-uri",
|
||||||
"description": "AT-URI of the parent message being replied to."
|
"description": "AT-URI of the parent message being replied to."
|
||||||
},
|
},
|
||||||
"langs": {
|
"createdAt": {
|
||||||
"type": "array",
|
|
||||||
"maxLength": 3,
|
|
||||||
"items": {
|
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "language"
|
"format": "datetime",
|
||||||
},
|
"description": "Client-declared timestamp when this message was created."
|
||||||
"description": "Indicates human language of message content."
|
}
|
||||||
},
|
|
||||||
"translations": {
|
|
||||||
"type": "ref",
|
|
||||||
"ref": "#translationMap",
|
|
||||||
"description": "Translations of the message in other languages."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"markdown": {
|
|
||||||
"type": "object",
|
|
||||||
"description": "Markdown content format.",
|
|
||||||
"required": ["text"],
|
|
||||||
"properties": {
|
|
||||||
"text": {
|
|
||||||
"type": "string",
|
|
||||||
"maxLength": 1000000,
|
|
||||||
"maxGraphemes": 100000,
|
|
||||||
"description": "Markdown text content."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"translationMap": {
|
|
||||||
"type": "object",
|
|
||||||
"description": "Map of language codes to translations.",
|
|
||||||
"properties": {
|
|
||||||
"en": { "type": "ref", "ref": "#translation" },
|
|
||||||
"ja": { "type": "ref", "ref": "#translation" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"translation": {
|
|
||||||
"type": "object",
|
|
||||||
"description": "A translation of a chat message.",
|
|
||||||
"properties": {
|
|
||||||
"title": {
|
|
||||||
"type": "string",
|
|
||||||
"maxLength": 5000,
|
|
||||||
"maxGraphemes": 500
|
|
||||||
},
|
|
||||||
"content": {
|
|
||||||
"type": "string",
|
|
||||||
"maxLength": 1000000,
|
|
||||||
"maxGraphemes": 100000
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,91 +4,33 @@
|
|||||||
"defs": {
|
"defs": {
|
||||||
"main": {
|
"main": {
|
||||||
"type": "record",
|
"type": "record",
|
||||||
"description": "Record containing a blog post. Compatible with site.standard.document.",
|
"description": "Record containing a blog post.",
|
||||||
"key": "tid",
|
"key": "tid",
|
||||||
"record": {
|
"record": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["site", "title", "publishedAt"],
|
"required": ["title", "content", "createdAt"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"site": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "uri",
|
|
||||||
"description": "Points to a publication record (at://) or a publication URL (https://)."
|
|
||||||
},
|
|
||||||
"title": {
|
"title": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"maxLength": 5000,
|
"maxLength": 3000,
|
||||||
"maxGraphemes": 500,
|
"maxGraphemes": 300,
|
||||||
"description": "Title of the post."
|
"description": "The title of the post."
|
||||||
},
|
|
||||||
"publishedAt": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "datetime",
|
|
||||||
"description": "Timestamp of the post's publish time."
|
|
||||||
},
|
},
|
||||||
"content": {
|
"content": {
|
||||||
"type": "union",
|
|
||||||
"closed": false,
|
|
||||||
"refs": ["#markdown"],
|
|
||||||
"description": "Open union for content. Supports markdown and other formats via $type."
|
|
||||||
},
|
|
||||||
"description": {
|
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"maxLength": 30000,
|
"maxLength": 1000000,
|
||||||
"maxGraphemes": 3000,
|
"maxGraphemes": 100000,
|
||||||
"description": "A brief description or excerpt from the post."
|
"description": "The content of the post (markdown)."
|
||||||
},
|
},
|
||||||
"textContent": {
|
"createdAt": {
|
||||||
"type": "string",
|
|
||||||
"description": "Plaintext representation of the post content. Should not contain markdown or other formatting."
|
|
||||||
},
|
|
||||||
"updatedAt": {
|
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "datetime",
|
"format": "datetime",
|
||||||
"description": "Timestamp of the post's last edit."
|
"description": "Client-declared timestamp when this post was originally created."
|
||||||
},
|
},
|
||||||
"tags": {
|
"lang": {
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"maxLength": 1280,
|
"maxLength": 10,
|
||||||
"maxGraphemes": 128
|
"description": "Language code of the original content (e.g., 'ja', 'en')."
|
||||||
},
|
|
||||||
"description": "Tags to categorize the post."
|
|
||||||
},
|
|
||||||
"path": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Combine with site URL to construct a canonical URL to the post."
|
|
||||||
},
|
|
||||||
"coverImage": {
|
|
||||||
"type": "blob",
|
|
||||||
"accept": ["image/*"],
|
|
||||||
"maxSize": 1000000,
|
|
||||||
"description": "Cover image. Less than 1MB."
|
|
||||||
},
|
|
||||||
"bskyPostRef": {
|
|
||||||
"type": "ref",
|
|
||||||
"ref": "com.atproto.repo.strongRef",
|
|
||||||
"description": "Strong reference to a Bluesky post."
|
|
||||||
},
|
|
||||||
"root": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "at-uri",
|
|
||||||
"description": "AT-URI of the root message in a thread."
|
|
||||||
},
|
|
||||||
"parent": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "at-uri",
|
|
||||||
"description": "AT-URI of the parent message being replied to."
|
|
||||||
},
|
|
||||||
"langs": {
|
|
||||||
"type": "array",
|
|
||||||
"maxLength": 3,
|
|
||||||
"items": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "language"
|
|
||||||
},
|
|
||||||
"description": "Indicates human language of post content."
|
|
||||||
},
|
},
|
||||||
"translations": {
|
"translations": {
|
||||||
"type": "ref",
|
"type": "ref",
|
||||||
@@ -98,19 +40,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"markdown": {
|
|
||||||
"type": "object",
|
|
||||||
"description": "Markdown content format.",
|
|
||||||
"required": ["text"],
|
|
||||||
"properties": {
|
|
||||||
"text": {
|
|
||||||
"type": "string",
|
|
||||||
"maxLength": 1000000,
|
|
||||||
"maxGraphemes": 100000,
|
|
||||||
"description": "Markdown text content."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"translationMap": {
|
"translationMap": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "Map of language codes to translations.",
|
"description": "Map of language codes to translations.",
|
||||||
@@ -125,8 +54,8 @@
|
|||||||
"properties": {
|
"properties": {
|
||||||
"title": {
|
"title": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"maxLength": 5000,
|
"maxLength": 3000,
|
||||||
"maxGraphemes": 500
|
"maxGraphemes": 300
|
||||||
},
|
},
|
||||||
"content": {
|
"content": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@@ -1,99 +0,0 @@
|
|||||||
{
|
|
||||||
"$type": "com.atproto.lexicon.schema",
|
|
||||||
"lexicon": 1,
|
|
||||||
"id": "ai.syui.rse.admin",
|
|
||||||
"defs": {
|
|
||||||
"main": {
|
|
||||||
"type": "record",
|
|
||||||
"key": "literal:self",
|
|
||||||
"description": "RSE admin configuration - abilities, characters, systems and collections",
|
|
||||||
"record": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["ability", "createdAt", "updatedAt"],
|
|
||||||
"properties": {
|
|
||||||
"ability": {
|
|
||||||
"type": "array",
|
|
||||||
"description": "Ability/attribute definitions",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["id", "name", "kind"],
|
|
||||||
"properties": {
|
|
||||||
"id": { "type": "integer", "description": "Ability ID" },
|
|
||||||
"name": { "type": "string", "description": "Ability name (ai, quark, neutron, atom, sun)" },
|
|
||||||
"kind": { "type": "string", "description": "Attribute type (consciousness, matter)" },
|
|
||||||
"color": { "type": "string", "description": "Color code (e.g., #ffd700)" },
|
|
||||||
"level": { "type": "integer", "description": "Hierarchy level (0=fundamental)" },
|
|
||||||
"relation": { "type": "array", "items": { "type": "integer" }, "description": "Advantage IDs" },
|
|
||||||
"weakness": { "type": "array", "items": { "type": "integer" }, "description": "Weakness IDs" },
|
|
||||||
"multiplier": { "type": "integer", "description": "Damage multiplier percent (e.g., 150 = 1.5x)" },
|
|
||||||
"phantom": { "type": "boolean", "description": "Whether this ability is phantom/lost" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"character": {
|
|
||||||
"type": "array",
|
|
||||||
"description": "Character definitions",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["id", "name", "ability", "mode"],
|
|
||||||
"properties": {
|
|
||||||
"id": { "type": "integer", "description": "Character ID" },
|
|
||||||
"name": { "type": "string", "description": "Character name" },
|
|
||||||
"ability": { "type": "integer", "description": "Ability ID reference" },
|
|
||||||
"mode": { "type": "integer", "description": "Character mode" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"system": {
|
|
||||||
"type": "array",
|
|
||||||
"description": "System definitions",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["id", "name", "domain"],
|
|
||||||
"properties": {
|
|
||||||
"id": { "type": "integer", "description": "System ID" },
|
|
||||||
"name": { "type": "string", "description": "System name" },
|
|
||||||
"domain": { "type": "string", "description": "System domain (ability, unique, account, planet, origin)" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"item": {
|
|
||||||
"type": "array",
|
|
||||||
"description": "Item definitions",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["id", "name", "text"],
|
|
||||||
"properties": {
|
|
||||||
"id": { "type": "integer", "description": "Item ID" },
|
|
||||||
"name": { "type": "string", "description": "Item name" },
|
|
||||||
"text": {
|
|
||||||
"type": "object",
|
|
||||||
"description": "Item description (localized)",
|
|
||||||
"properties": {
|
|
||||||
"en": { "type": "string", "description": "English text" },
|
|
||||||
"ja": { "type": "string", "description": "Japanese text" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"collection": {
|
|
||||||
"type": "array",
|
|
||||||
"description": "ATProto collection definitions",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["id", "nsid", "name"],
|
|
||||||
"properties": {
|
|
||||||
"id": { "type": "integer", "description": "Collection ID" },
|
|
||||||
"nsid": { "type": "string", "description": "Namespaced identifier (e.g., ai.syui.card)" },
|
|
||||||
"name": { "type": "string", "description": "Collection short name" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"createdAt": { "type": "string", "format": "datetime" },
|
|
||||||
"updatedAt": { "type": "string", "format": "datetime" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
{
|
|
||||||
"$type": "com.atproto.lexicon.schema",
|
|
||||||
"lexicon": 1,
|
|
||||||
"id": "ai.syui.rse.user",
|
|
||||||
"defs": {
|
|
||||||
"main": {
|
|
||||||
"type": "record",
|
|
||||||
"key": "literal:self",
|
|
||||||
"description": "User character and item collection",
|
|
||||||
"record": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["character", "item", "createdAt", "updatedAt"],
|
|
||||||
"properties": {
|
|
||||||
"character": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["id", "cp", "rare", "cid", "unique"],
|
|
||||||
"properties": {
|
|
||||||
"id": { "type": "integer", "description": "Character type ID" },
|
|
||||||
"cp": { "type": "integer", "description": "Character power" },
|
|
||||||
"rare": { "type": "integer", "description": "Rarity level" },
|
|
||||||
"cid": { "type": "string", "description": "Unique character instance ID" },
|
|
||||||
"unique": { "type": "boolean", "description": "Unique character flag" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"item": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["id", "cp", "rare", "cid", "unique"],
|
|
||||||
"properties": {
|
|
||||||
"id": { "type": "integer", "description": "Item type ID" },
|
|
||||||
"cp": { "type": "integer", "description": "Item power" },
|
|
||||||
"rare": { "type": "integer", "description": "Rarity level" },
|
|
||||||
"cid": { "type": "string", "description": "Unique item instance ID" },
|
|
||||||
"unique": { "type": "boolean", "description": "Unique item flag" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"createdAt": { "type": "string", "format": "datetime" },
|
|
||||||
"updatedAt": { "type": "string", "format": "datetime" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
{
|
|
||||||
"lexicon": 1,
|
|
||||||
"id": "site.standard.document",
|
|
||||||
"$type": "com.atproto.lexicon.schema",
|
|
||||||
"defs": {
|
|
||||||
"main": {
|
|
||||||
"type": "record",
|
|
||||||
"key": "tid",
|
|
||||||
"description": "A document record representing a published article, blog post, or other content. Documents can belong to a publication or exist independently.",
|
|
||||||
"record": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["site", "title", "publishedAt"],
|
|
||||||
"properties": {
|
|
||||||
"site": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "uri",
|
|
||||||
"description": "Points to a publication record (at://) or a publication url (https://) for loose documents."
|
|
||||||
},
|
|
||||||
"title": {
|
|
||||||
"type": "string",
|
|
||||||
"maxLength": 5000,
|
|
||||||
"maxGraphemes": 500,
|
|
||||||
"description": "Title of the document."
|
|
||||||
},
|
|
||||||
"publishedAt": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "datetime",
|
|
||||||
"description": "Timestamp of the document's publish time."
|
|
||||||
},
|
|
||||||
"content": {
|
|
||||||
"type": "union",
|
|
||||||
"closed": false,
|
|
||||||
"refs": [],
|
|
||||||
"description": "Open union used to define the record's content. Each entry must specify a $type."
|
|
||||||
},
|
|
||||||
"description": {
|
|
||||||
"type": "string",
|
|
||||||
"maxLength": 30000,
|
|
||||||
"maxGraphemes": 3000,
|
|
||||||
"description": "A brief description or excerpt from the document."
|
|
||||||
},
|
|
||||||
"textContent": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Plaintext representation of the document's contents. Should not contain markdown or other formatting."
|
|
||||||
},
|
|
||||||
"updatedAt": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "datetime",
|
|
||||||
"description": "Timestamp of the document's last edit."
|
|
||||||
},
|
|
||||||
"tags": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string",
|
|
||||||
"maxLength": 1280,
|
|
||||||
"maxGraphemes": 128
|
|
||||||
},
|
|
||||||
"description": "Array of strings used to tag or categorize the document."
|
|
||||||
},
|
|
||||||
"path": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Combine with site URL to construct a canonical URL to the document."
|
|
||||||
},
|
|
||||||
"coverImage": {
|
|
||||||
"type": "blob",
|
|
||||||
"accept": ["image/*"],
|
|
||||||
"maxSize": 1000000,
|
|
||||||
"description": "Cover image. Less than 1MB."
|
|
||||||
},
|
|
||||||
"bskyPostRef": {
|
|
||||||
"type": "ref",
|
|
||||||
"ref": "com.atproto.repo.strongRef",
|
|
||||||
"description": "Strong reference to a Bluesky post."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
{
|
|
||||||
"lexicon": 1,
|
|
||||||
"id": "site.standard.publication",
|
|
||||||
"$type": "com.atproto.lexicon.schema",
|
|
||||||
"defs": {
|
|
||||||
"main": {
|
|
||||||
"type": "record",
|
|
||||||
"key": "tid",
|
|
||||||
"description": "A publication record representing a blog, website, or content platform. Publications serve as containers for documents and define the overall branding and settings.",
|
|
||||||
"record": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["url", "name"],
|
|
||||||
"properties": {
|
|
||||||
"url": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "uri",
|
|
||||||
"description": "Base publication url (ex: https://syui.ai). The canonical document URL is formed by combining this value with the document path."
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string",
|
|
||||||
"maxLength": 5000,
|
|
||||||
"maxGraphemes": 500,
|
|
||||||
"description": "Name of the publication."
|
|
||||||
},
|
|
||||||
"icon": {
|
|
||||||
"type": "blob",
|
|
||||||
"accept": ["image/*"],
|
|
||||||
"maxSize": 1000000,
|
|
||||||
"description": "Square image to identify the publication. Should be at least 256x256."
|
|
||||||
},
|
|
||||||
"description": {
|
|
||||||
"type": "string",
|
|
||||||
"maxLength": 30000,
|
|
||||||
"maxGraphemes": 3000,
|
|
||||||
"description": "Brief description of the publication."
|
|
||||||
},
|
|
||||||
"basicTheme": {
|
|
||||||
"type": "ref",
|
|
||||||
"ref": "site.standard.theme.basic",
|
|
||||||
"description": "Simplified publication theme for tools and apps to utilize when displaying content."
|
|
||||||
},
|
|
||||||
"preferences": {
|
|
||||||
"type": "ref",
|
|
||||||
"ref": "#preferences",
|
|
||||||
"description": "Object containing platform specific preferences."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"preferences": {
|
|
||||||
"type": "object",
|
|
||||||
"description": "Platform-specific preferences for the publication, including discovery and visibility settings.",
|
|
||||||
"properties": {
|
|
||||||
"showInDiscover": {
|
|
||||||
"type": "boolean",
|
|
||||||
"default": true,
|
|
||||||
"description": "Boolean which decides whether the publication should appear in discovery feeds."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,6 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"prebuild": "ailog index 2>/dev/null || true",
|
|
||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
at://did:plc:vzsvtbtbnwn22xjqhcu3vd6y/site.standard.publication/syui.ai
|
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
/.well-known/* /.well-known/:splat 200
|
|
||||||
/app/* /index.html 200
|
/app/* /index.html 200
|
||||||
/oauth/cli /oauth/cli/index.html 200
|
|
||||||
/oauth/* /index.html 200
|
/oauth/* /index.html 200
|
||||||
/* /index.html 200
|
/* /index.html 200
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 152 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 122 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 124 KiB |
|
Before Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 221 KiB |
|
Before Width: | Height: | Size: 166 KiB |
|
Before Width: | Height: | Size: 112 KiB |
|
Before Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 205 KiB |
|
Before Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 126 KiB |
|
Before Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 137 KiB |
|
Before Width: | Height: | Size: 97 KiB |
|
Before Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 108 KiB |
|
Before Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 93 KiB |
|
Before Width: | Height: | Size: 119 KiB |
|
Before Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 68 KiB |