cleanup
This commit is contained in:
32
Dockerfile
32
Dockerfile
@ -1,32 +0,0 @@
|
|||||||
# Multi-stage build for ailog
|
|
||||||
FROM rust:1.75 as builder
|
|
||||||
|
|
||||||
WORKDIR /usr/src/app
|
|
||||||
COPY Cargo.toml Cargo.lock ./
|
|
||||||
COPY src ./src
|
|
||||||
|
|
||||||
RUN cargo build --release
|
|
||||||
|
|
||||||
FROM debian:bookworm-slim
|
|
||||||
|
|
||||||
# Install runtime dependencies
|
|
||||||
RUN apt-get update && apt-get install -y \
|
|
||||||
ca-certificates \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Copy the binary
|
|
||||||
COPY --from=builder /usr/src/app/target/release/ailog /usr/local/bin/ailog
|
|
||||||
|
|
||||||
# Copy blog content
|
|
||||||
COPY my-blog ./blog
|
|
||||||
|
|
||||||
# Build static site
|
|
||||||
RUN ailog build blog
|
|
||||||
|
|
||||||
# Expose port
|
|
||||||
EXPOSE 8080
|
|
||||||
|
|
||||||
# Run server
|
|
||||||
CMD ["ailog", "serve", "blog"]
|
|
128
action.yml
128
action.yml
@ -1,128 +0,0 @@
|
|||||||
name: 'ailog Static Site Generator'
|
|
||||||
description: 'AI-powered static blog generator with atproto integration'
|
|
||||||
author: 'syui'
|
|
||||||
|
|
||||||
branding:
|
|
||||||
icon: 'book-open'
|
|
||||||
color: 'orange'
|
|
||||||
|
|
||||||
inputs:
|
|
||||||
content-dir:
|
|
||||||
description: 'Content directory containing markdown files'
|
|
||||||
required: false
|
|
||||||
default: 'content'
|
|
||||||
output-dir:
|
|
||||||
description: 'Output directory for generated site'
|
|
||||||
required: false
|
|
||||||
default: 'public'
|
|
||||||
template-dir:
|
|
||||||
description: 'Template directory'
|
|
||||||
required: false
|
|
||||||
default: 'templates'
|
|
||||||
static-dir:
|
|
||||||
description: 'Static assets directory'
|
|
||||||
required: false
|
|
||||||
default: 'static'
|
|
||||||
config-file:
|
|
||||||
description: 'Configuration file path'
|
|
||||||
required: false
|
|
||||||
default: 'ailog.toml'
|
|
||||||
ai-integration:
|
|
||||||
description: 'Enable AI features'
|
|
||||||
required: false
|
|
||||||
default: 'true'
|
|
||||||
atproto-integration:
|
|
||||||
description: 'Enable atproto/OAuth features'
|
|
||||||
required: false
|
|
||||||
default: 'true'
|
|
||||||
|
|
||||||
outputs:
|
|
||||||
site-url:
|
|
||||||
description: 'Generated site URL'
|
|
||||||
value: ${{ steps.generate.outputs.site-url }}
|
|
||||||
build-time:
|
|
||||||
description: 'Build time in seconds'
|
|
||||||
value: ${{ steps.generate.outputs.build-time }}
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: 'composite'
|
|
||||||
steps:
|
|
||||||
- name: Cache ailog binary
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: ./bin
|
|
||||||
key: ailog-bin-${{ runner.os }}
|
|
||||||
restore-keys: |
|
|
||||||
ailog-bin-${{ runner.os }}
|
|
||||||
|
|
||||||
- name: Setup ailog binary
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
# Check if pre-built binary exists
|
|
||||||
if [ -f "./bin/ailog-linux-x86_64" ]; then
|
|
||||||
echo "Using pre-built binary from repository"
|
|
||||||
chmod +x ./bin/ailog-linux-x86_64
|
|
||||||
CURRENT_VERSION=$(./bin/ailog-linux-x86_64 --version 2>/dev/null || echo "unknown")
|
|
||||||
echo "Binary version: $CURRENT_VERSION"
|
|
||||||
else
|
|
||||||
echo "No pre-built binary found, trying to build from source..."
|
|
||||||
if command -v cargo >/dev/null 2>&1; then
|
|
||||||
cargo build --release
|
|
||||||
mkdir -p ./bin
|
|
||||||
cp ./target/release/ailog ./bin/ailog-linux-x86_64
|
|
||||||
echo "Built from source: $(./bin/ailog-linux-x86_64 --version 2>/dev/null)"
|
|
||||||
else
|
|
||||||
echo "Error: No binary found and cargo not available"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Setup Node.js for OAuth app
|
|
||||||
if: ${{ inputs.atproto-integration == 'true' }}
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: '20'
|
|
||||||
|
|
||||||
- name: Build OAuth app
|
|
||||||
if: ${{ inputs.atproto-integration == 'true' }}
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
if [ -d "oauth" ]; then
|
|
||||||
cd oauth
|
|
||||||
npm install
|
|
||||||
npm run build
|
|
||||||
cp -r dist/* ../${{ inputs.static-dir }}/
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Generate site
|
|
||||||
id: generate
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
start_time=$(date +%s)
|
|
||||||
|
|
||||||
# Change to blog directory and run build
|
|
||||||
# Note: ailog build only takes a path argument, not options
|
|
||||||
if [ -d "my-blog" ]; then
|
|
||||||
cd my-blog
|
|
||||||
../bin/ailog-linux-x86_64 build
|
|
||||||
else
|
|
||||||
# If no my-blog directory, use current directory
|
|
||||||
./bin/ailog-linux-x86_64 build .
|
|
||||||
fi
|
|
||||||
|
|
||||||
end_time=$(date +%s)
|
|
||||||
build_time=$((end_time - start_time))
|
|
||||||
|
|
||||||
echo "build-time=${build_time}" >> $GITHUB_OUTPUT
|
|
||||||
echo "site-url=file://$(pwd)/${{ inputs.output-dir }}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Display build summary
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "✅ ailog build completed successfully"
|
|
||||||
echo "📁 Output directory: ${{ inputs.output-dir }}"
|
|
||||||
echo "⏱️ Build time: ${{ steps.generate.outputs.build-time }}s"
|
|
||||||
if [ -d "${{ inputs.output-dir }}" ]; then
|
|
||||||
echo "📄 Generated files:"
|
|
||||||
find ${{ inputs.output-dir }} -type f | head -10
|
|
||||||
fi
|
|
103
templates/api.md
103
templates/api.md
@ -1,103 +0,0 @@
|
|||||||
# API Documentation
|
|
||||||
|
|
||||||
## Public Functions
|
|
||||||
|
|
||||||
{{#each api.public_functions}}
|
|
||||||
### `{{this.name}}`
|
|
||||||
|
|
||||||
{{#if this.docs}}
|
|
||||||
{{this.docs}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
**Visibility:** `{{this.visibility}}`
|
|
||||||
{{#if this.is_async}}**Async:** Yes{{/if}}
|
|
||||||
|
|
||||||
{{#if this.parameters}}
|
|
||||||
**Parameters:**
|
|
||||||
{{#each this.parameters}}
|
|
||||||
- `{{this.name}}`: `{{this.param_type}}`{{#if this.is_mutable}} (mutable){{/if}}
|
|
||||||
{{/each}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if this.return_type}}
|
|
||||||
**Returns:** `{{this.return_type}}`
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
{{/each}}
|
|
||||||
|
|
||||||
## Public Structs
|
|
||||||
|
|
||||||
{{#each api.public_structs}}
|
|
||||||
### `{{this.name}}`
|
|
||||||
|
|
||||||
{{#if this.docs}}
|
|
||||||
{{this.docs}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
**Visibility:** `{{this.visibility}}`
|
|
||||||
|
|
||||||
{{#if this.fields}}
|
|
||||||
**Fields:**
|
|
||||||
{{#each this.fields}}
|
|
||||||
- `{{this.name}}`: `{{this.field_type}}` ({{this.visibility}})
|
|
||||||
{{#if this.docs}} - {{this.docs}}{{/if}}
|
|
||||||
{{/each}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
{{/each}}
|
|
||||||
|
|
||||||
## Public Enums
|
|
||||||
|
|
||||||
{{#each api.public_enums}}
|
|
||||||
### `{{this.name}}`
|
|
||||||
|
|
||||||
{{#if this.docs}}
|
|
||||||
{{this.docs}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
**Visibility:** `{{this.visibility}}`
|
|
||||||
|
|
||||||
{{#if this.variants}}
|
|
||||||
**Variants:**
|
|
||||||
{{#each this.variants}}
|
|
||||||
- `{{this.name}}`
|
|
||||||
{{#if this.docs}} - {{this.docs}}{{/if}}
|
|
||||||
{{#if this.fields}}
|
|
||||||
**Fields:**
|
|
||||||
{{#each this.fields}}
|
|
||||||
- `{{this.name}}`: `{{this.field_type}}`
|
|
||||||
{{/each}}
|
|
||||||
{{/if}}
|
|
||||||
{{/each}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
{{/each}}
|
|
||||||
|
|
||||||
## Public Traits
|
|
||||||
|
|
||||||
{{#each api.public_traits}}
|
|
||||||
### `{{this.name}}`
|
|
||||||
|
|
||||||
{{#if this.docs}}
|
|
||||||
{{this.docs}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
**Visibility:** `{{this.visibility}}`
|
|
||||||
|
|
||||||
{{#if this.methods}}
|
|
||||||
**Methods:**
|
|
||||||
{{#each this.methods}}
|
|
||||||
- `{{this.name}}({{#each this.parameters}}{{this.name}}: {{this.param_type}}{{#unless @last}}, {{/unless}}{{/each}}){{#if this.return_type}} -> {{this.return_type}}{{/if}}`
|
|
||||||
{{#if this.docs}} - {{this.docs}}{{/if}}
|
|
||||||
{{/each}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
{{/each}}
|
|
@ -1,19 +0,0 @@
|
|||||||
# Changelog
|
|
||||||
|
|
||||||
## Recent Changes
|
|
||||||
|
|
||||||
{{#each commits}}
|
|
||||||
### {{this.date}}
|
|
||||||
|
|
||||||
**{{this.hash}}** by {{this.author}}
|
|
||||||
|
|
||||||
{{this.message}}
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
{{/each}}
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
- **Total Commits:** {{commits.length}}
|
|
||||||
- **Contributors:** {{#unique commits "author"}}{{this.author}}{{#unless @last}}, {{/unless}}{{/unique}}
|
|
@ -1,76 +0,0 @@
|
|||||||
# {{project.name}}
|
|
||||||
|
|
||||||
{{#if project.description}}
|
|
||||||
{{project.description}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
This project contains {{project.modules.length}} modules with a total of {{project.metrics.total_lines}} lines of code.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cargo install {{project.name}}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
```bash
|
|
||||||
{{project.name}} --help
|
|
||||||
```
|
|
||||||
|
|
||||||
## Dependencies
|
|
||||||
|
|
||||||
{{#each project.dependencies}}
|
|
||||||
- `{{@key}}`: {{this}}
|
|
||||||
{{/each}}
|
|
||||||
|
|
||||||
## Project Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
{{#each project.structure.directories}}
|
|
||||||
{{this.name}}/
|
|
||||||
{{/each}}
|
|
||||||
```
|
|
||||||
|
|
||||||
## API Documentation
|
|
||||||
|
|
||||||
{{#each project.modules}}
|
|
||||||
### {{this.name}}
|
|
||||||
|
|
||||||
{{#if this.docs}}
|
|
||||||
{{this.docs}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if this.functions}}
|
|
||||||
**Functions:** {{this.functions.length}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if this.structs}}
|
|
||||||
**Structs:** {{this.structs.length}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{/each}}
|
|
||||||
|
|
||||||
## Metrics
|
|
||||||
|
|
||||||
- **Lines of Code:** {{project.metrics.total_lines}}
|
|
||||||
- **Total Files:** {{project.metrics.total_files}}
|
|
||||||
- **Test Files:** {{project.metrics.test_files}}
|
|
||||||
- **Dependencies:** {{project.metrics.dependency_count}}
|
|
||||||
- **Complexity Score:** {{project.metrics.complexity_score}}
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
{{#if project.license}}
|
|
||||||
{{project.license}}
|
|
||||||
{{else}}
|
|
||||||
MIT
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
## Authors
|
|
||||||
|
|
||||||
{{#each project.authors}}
|
|
||||||
- {{this}}
|
|
||||||
{{/each}}
|
|
@ -1,39 +0,0 @@
|
|||||||
# Project Structure
|
|
||||||
|
|
||||||
## Directory Overview
|
|
||||||
|
|
||||||
```
|
|
||||||
{{#each structure.directories}}
|
|
||||||
{{this.name}}/
|
|
||||||
{{#each this.subdirectories}}
|
|
||||||
├── {{this}}/
|
|
||||||
{{/each}}
|
|
||||||
{{#if this.file_count}}
|
|
||||||
└── ({{this.file_count}} files)
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{/each}}
|
|
||||||
```
|
|
||||||
|
|
||||||
## File Distribution
|
|
||||||
|
|
||||||
{{#each structure.files}}
|
|
||||||
- **{{this.name}}** ({{this.language}}) - {{this.lines_of_code}} lines{{#if this.is_test}} [TEST]{{/if}}
|
|
||||||
{{/each}}
|
|
||||||
|
|
||||||
## Statistics
|
|
||||||
|
|
||||||
- **Total Directories:** {{structure.directories.length}}
|
|
||||||
- **Total Files:** {{structure.files.length}}
|
|
||||||
- **Languages Used:**
|
|
||||||
{{#group structure.files by="language"}}
|
|
||||||
- {{@key}}: {{this.length}} files
|
|
||||||
{{/group}}
|
|
||||||
|
|
||||||
{{#if structure.dependency_graph}}
|
|
||||||
## Dependencies
|
|
||||||
|
|
||||||
{{#each structure.dependency_graph}}
|
|
||||||
- **{{@key}}** depends on: {{#each this}}{{this}}{{#unless @last}}, {{/unless}}{{/each}}
|
|
||||||
{{/each}}
|
|
||||||
{{/if}}
|
|
@ -1,93 +0,0 @@
|
|||||||
// Cloudflare Worker for secure Ollama proxy
|
|
||||||
export default {
|
|
||||||
async fetch(request, env, ctx) {
|
|
||||||
// CORS preflight
|
|
||||||
if (request.method === 'OPTIONS') {
|
|
||||||
return new Response(null, {
|
|
||||||
headers: {
|
|
||||||
'Access-Control-Allow-Origin': 'https://log.syui.ai',
|
|
||||||
'Access-Control-Allow-Methods': 'POST, OPTIONS',
|
|
||||||
'Access-Control-Allow-Headers': 'Content-Type, X-User-Token',
|
|
||||||
'Access-Control-Max-Age': '86400',
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify origin
|
|
||||||
const origin = request.headers.get('Origin');
|
|
||||||
const referer = request.headers.get('Referer');
|
|
||||||
|
|
||||||
// 許可されたオリジンのみ
|
|
||||||
const allowedOrigins = [
|
|
||||||
'https://log.syui.ai',
|
|
||||||
'https://log.pages.dev' // Cloudflare Pages preview
|
|
||||||
];
|
|
||||||
|
|
||||||
if (!origin || !allowedOrigins.some(allowed => origin.startsWith(allowed))) {
|
|
||||||
return new Response('Forbidden', { status: 403 });
|
|
||||||
}
|
|
||||||
|
|
||||||
// ユーザー認証トークン検証(オプション)
|
|
||||||
const userToken = request.headers.get('X-User-Token');
|
|
||||||
if (env.REQUIRE_AUTH && !userToken) {
|
|
||||||
return new Response('Unauthorized', { status: 401 });
|
|
||||||
}
|
|
||||||
|
|
||||||
// リクエストボディを取得
|
|
||||||
const body = await request.json();
|
|
||||||
|
|
||||||
// プロンプトサイズ制限
|
|
||||||
if (body.prompt && body.prompt.length > 1000) {
|
|
||||||
return new Response(JSON.stringify({
|
|
||||||
error: 'Prompt too long. Maximum 1000 characters.'
|
|
||||||
}), {
|
|
||||||
status: 400,
|
|
||||||
headers: { 'Content-Type': 'application/json' }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// レート制限(CF Workers KV使用)
|
|
||||||
if (env.RATE_LIMITER) {
|
|
||||||
const clientIP = request.headers.get('CF-Connecting-IP');
|
|
||||||
const rateLimitKey = `rate:${clientIP}`;
|
|
||||||
const currentCount = await env.RATE_LIMITER.get(rateLimitKey) || 0;
|
|
||||||
|
|
||||||
if (currentCount >= 20) {
|
|
||||||
return new Response(JSON.stringify({
|
|
||||||
error: 'Rate limit exceeded. Try again later.'
|
|
||||||
}), {
|
|
||||||
status: 429,
|
|
||||||
headers: { 'Content-Type': 'application/json' }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// カウント増加(1時間TTL)
|
|
||||||
await env.RATE_LIMITER.put(rateLimitKey, currentCount + 1, {
|
|
||||||
expirationTtl: 3600
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ollamaへプロキシ
|
|
||||||
const ollamaResponse = await fetch(env.OLLAMA_API_URL || 'https://ollama.syui.ai/api/generate', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
// 内部認証ヘッダー(必要に応じて)
|
|
||||||
'X-Internal-Token': env.OLLAMA_INTERNAL_TOKEN || ''
|
|
||||||
},
|
|
||||||
body: JSON.stringify(body)
|
|
||||||
});
|
|
||||||
|
|
||||||
// レスポンスを返す
|
|
||||||
const responseData = await ollamaResponse.text();
|
|
||||||
|
|
||||||
return new Response(responseData, {
|
|
||||||
status: ollamaResponse.status,
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Access-Control-Allow-Origin': origin,
|
|
||||||
'Cache-Control': 'no-store'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,20 +0,0 @@
|
|||||||
name = "ollama-proxy"
|
|
||||||
main = "ollama-proxy.js"
|
|
||||||
compatibility_date = "2024-01-01"
|
|
||||||
|
|
||||||
# 環境変数
|
|
||||||
[vars]
|
|
||||||
REQUIRE_AUTH = false
|
|
||||||
|
|
||||||
# 本番環境
|
|
||||||
[env.production.vars]
|
|
||||||
OLLAMA_API_URL = "https://ollama.syui.ai/api/generate"
|
|
||||||
REQUIRE_AUTH = true
|
|
||||||
|
|
||||||
# KVネームスペース(レート制限用)
|
|
||||||
[[kv_namespaces]]
|
|
||||||
binding = "RATE_LIMITER"
|
|
||||||
id = "your-kv-namespace-id"
|
|
||||||
|
|
||||||
# シークレット(wrangler secret putで設定)
|
|
||||||
# OLLAMA_INTERNAL_TOKEN = "your-internal-token"
|
|
Reference in New Issue
Block a user