This commit is contained in:
8
fal-platform/.skillshare-meta.json
Normal file
8
fal-platform/.skillshare-meta.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"source": "github.com/fal-ai-community/skills/tree/main/skills/claude.ai/fal-platform",
|
||||
"type": "github-subdir",
|
||||
"installed_at": "2026-01-30T02:27:27.47340156Z",
|
||||
"repo_url": "https://github.com/fal-ai-community/skills.git",
|
||||
"subdir": "skills/claude.ai/fal-platform",
|
||||
"version": "69efe6e"
|
||||
}
|
||||
160
fal-platform/SKILL.md
Normal file
160
fal-platform/SKILL.md
Normal file
@@ -0,0 +1,160 @@
|
||||
---
|
||||
name: fal-platform
|
||||
description: fal.ai Platform APIs for model management, pricing, usage tracking, and cost estimation. Use when user asks "show pricing", "check usage", "estimate cost", "setup fal", "add API key", or platform management tasks.
|
||||
metadata:
|
||||
author: fal-ai
|
||||
version: "1.0.0"
|
||||
---
|
||||
|
||||
# fal.ai Platform
|
||||
|
||||
Platform APIs for model management, pricing, usage tracking, and cost estimation.
|
||||
|
||||
## Scripts
|
||||
|
||||
| Script | Purpose |
|
||||
|--------|---------|
|
||||
| `setup.sh` | Setup FAL_KEY and configuration |
|
||||
| `pricing.sh` | Get model pricing information |
|
||||
| `usage.sh` | Check usage and billing |
|
||||
| `estimate-cost.sh` | Estimate costs for operations |
|
||||
| `requests.sh` | List and manage requests |
|
||||
|
||||
## Setup & Configuration
|
||||
|
||||
### Add FAL_KEY
|
||||
|
||||
```bash
|
||||
# Interactive setup
|
||||
bash /mnt/skills/user/fal-platform/scripts/setup.sh --add-fal-key
|
||||
|
||||
# Set key directly
|
||||
bash /mnt/skills/user/fal-platform/scripts/setup.sh --add-fal-key "your_key_here"
|
||||
|
||||
# Show current config
|
||||
bash /mnt/skills/user/fal-platform/scripts/setup.sh --show-config
|
||||
```
|
||||
|
||||
This adds FAL_KEY to your `.env` file for persistent use.
|
||||
|
||||
## Model Pricing
|
||||
|
||||
Get pricing for any model:
|
||||
|
||||
```bash
|
||||
# Single model pricing
|
||||
bash /mnt/skills/user/fal-platform/scripts/pricing.sh --model "fal-ai/flux/dev"
|
||||
|
||||
# Multiple models
|
||||
bash /mnt/skills/user/fal-platform/scripts/pricing.sh --model "fal-ai/flux/dev,fal-ai/kling-video/v2.1/pro"
|
||||
|
||||
# All pricing for a category
|
||||
bash /mnt/skills/user/fal-platform/scripts/pricing.sh --category "text-to-image"
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
fal-ai/flux/dev
|
||||
Price: $0.025 per image
|
||||
Unit: image
|
||||
|
||||
fal-ai/kling-video/v2.1/pro
|
||||
Price: $0.50 per second
|
||||
Unit: video_second
|
||||
```
|
||||
|
||||
## Usage Tracking
|
||||
|
||||
Check your usage and spending:
|
||||
|
||||
```bash
|
||||
# Current period usage
|
||||
bash /mnt/skills/user/fal-platform/scripts/usage.sh
|
||||
|
||||
# Filter by model
|
||||
bash /mnt/skills/user/fal-platform/scripts/usage.sh --model "fal-ai/flux/dev"
|
||||
|
||||
# Date range
|
||||
bash /mnt/skills/user/fal-platform/scripts/usage.sh --start "2024-01-01" --end "2024-01-31"
|
||||
|
||||
# Specific timeframe
|
||||
bash /mnt/skills/user/fal-platform/scripts/usage.sh --timeframe "day"
|
||||
```
|
||||
|
||||
**Timeframes:** `minute`, `hour`, `day`, `week`, `month`
|
||||
|
||||
## Estimate Cost
|
||||
|
||||
Estimate costs before running:
|
||||
|
||||
```bash
|
||||
# Estimate by API calls (historical pricing)
|
||||
bash /mnt/skills/user/fal-platform/scripts/estimate-cost.sh \
|
||||
--model "fal-ai/flux/dev" \
|
||||
--calls 100
|
||||
|
||||
# Estimate by units
|
||||
bash /mnt/skills/user/fal-platform/scripts/estimate-cost.sh \
|
||||
--model "fal-ai/kling-video/v2.1/pro" \
|
||||
--units 60 \
|
||||
--type "unit_price"
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
Cost Estimate for fal-ai/flux/dev
|
||||
Quantity: 100 calls
|
||||
Estimated Cost: $2.50
|
||||
```
|
||||
|
||||
## Request Management
|
||||
|
||||
List and manage requests:
|
||||
|
||||
```bash
|
||||
# List recent requests
|
||||
bash /mnt/skills/user/fal-platform/scripts/requests.sh --model "fal-ai/flux/dev" --limit 10
|
||||
|
||||
# Delete request payloads (cleanup)
|
||||
bash /mnt/skills/user/fal-platform/scripts/requests.sh --delete "request_id_here"
|
||||
```
|
||||
|
||||
## API Endpoints Reference
|
||||
|
||||
| Operation | Endpoint | Method |
|
||||
|-----------|----------|--------|
|
||||
| Model Search | `GET /models` | GET |
|
||||
| Pricing | `GET /models/pricing` | GET |
|
||||
| Usage | `GET /models/usage` | GET |
|
||||
| List Requests | `GET /models/requests/by-endpoint` | GET |
|
||||
| Delete Payloads | `DELETE /models/requests/{id}/payloads` | DELETE |
|
||||
|
||||
**Base URL:** `https://api.fal.ai/v1`
|
||||
|
||||
## Common Flags (All Scripts)
|
||||
|
||||
All scripts support these common flags:
|
||||
|
||||
```bash
|
||||
--add-fal-key [KEY] # Add/update FAL_KEY in .env
|
||||
--help, -h # Show help
|
||||
--json # Output raw JSON
|
||||
--quiet, -q # Suppress status messages
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### API Key Required
|
||||
```
|
||||
Error: FAL_KEY required for this operation
|
||||
|
||||
Run: bash /mnt/skills/user/fal-platform/scripts/setup.sh --add-fal-key
|
||||
```
|
||||
|
||||
### Permission Denied
|
||||
```
|
||||
Error: API key doesn't have permission for this operation
|
||||
|
||||
Some operations require admin API keys. Check your key permissions at:
|
||||
https://fal.ai/dashboard/keys
|
||||
```
|
||||
161
fal-platform/scripts/estimate-cost.sh
Executable file
161
fal-platform/scripts/estimate-cost.sh
Executable file
@@ -0,0 +1,161 @@
|
||||
#!/bin/bash
|
||||
|
||||
# fal.ai Cost Estimation Script
|
||||
# Usage: ./estimate-cost.sh --model MODEL --calls N | --units N
|
||||
# Returns estimated costs based on pricing data
|
||||
|
||||
set -e
|
||||
|
||||
FAL_API_BASE="https://api.fal.ai/v1"
|
||||
|
||||
# Default values
|
||||
MODEL=""
|
||||
CALLS=""
|
||||
UNITS=""
|
||||
OUTPUT_JSON=false
|
||||
|
||||
# Check for --add-fal-key first
|
||||
for arg in "$@"; do
|
||||
if [ "$arg" = "--add-fal-key" ]; then
|
||||
bash "$(dirname "$0")/setup.sh" "$@"
|
||||
exit $?
|
||||
fi
|
||||
done
|
||||
|
||||
# Parse arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--model|-m)
|
||||
MODEL="$2"
|
||||
shift 2
|
||||
;;
|
||||
--calls|-c)
|
||||
CALLS="$2"
|
||||
shift 2
|
||||
;;
|
||||
--units|-u)
|
||||
UNITS="$2"
|
||||
shift 2
|
||||
;;
|
||||
--json)
|
||||
OUTPUT_JSON=true
|
||||
shift
|
||||
;;
|
||||
--help|-h)
|
||||
echo "fal.ai Cost Estimation Script" >&2
|
||||
echo "" >&2
|
||||
echo "Usage:" >&2
|
||||
echo " ./estimate-cost.sh --model MODEL --calls N Estimate by API calls" >&2
|
||||
echo " ./estimate-cost.sh --model MODEL --units N Estimate by units" >&2
|
||||
echo "" >&2
|
||||
echo "Options:" >&2
|
||||
echo " --model, -m Model ID (required)" >&2
|
||||
echo " --calls, -c Number of API calls to estimate" >&2
|
||||
echo " --units, -u Number of billing units to estimate" >&2
|
||||
echo " --json Output raw JSON" >&2
|
||||
echo " --add-fal-key Setup FAL_KEY" >&2
|
||||
echo "" >&2
|
||||
echo "Examples:" >&2
|
||||
echo " ./estimate-cost.sh --model \"fal-ai/flux/dev\" --calls 100" >&2
|
||||
echo " ./estimate-cost.sh --model \"fal-ai/kling-video/v2.1/pro\" --units 60" >&2
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Load .env if exists
|
||||
if [ -f ".env" ]; then
|
||||
source .env 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Check for FAL_KEY
|
||||
if [ -z "$FAL_KEY" ]; then
|
||||
echo "Error: FAL_KEY required" >&2
|
||||
echo "" >&2
|
||||
echo "Run: ./setup.sh --add-fal-key" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$MODEL" ]; then
|
||||
echo "Error: --model is required" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$CALLS" ] && [ -z "$UNITS" ]; then
|
||||
echo "Error: --calls or --units is required" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Estimating cost for $MODEL..." >&2
|
||||
|
||||
# Get pricing info first
|
||||
ENCODED_MODEL=$(echo "$MODEL" | sed 's/\//%2F/g')
|
||||
|
||||
PRICING_RESPONSE=$(curl -s -X GET "$FAL_API_BASE/models/pricing?endpoint_id=$ENCODED_MODEL" \
|
||||
-H "Authorization: Key $FAL_KEY" \
|
||||
-H "Content-Type: application/json")
|
||||
|
||||
# Check for errors
|
||||
if echo "$PRICING_RESPONSE" | grep -q '"error"'; then
|
||||
ERROR_MSG=$(echo "$PRICING_RESPONSE" | grep -o '"message":"[^"]*"' | head -1 | cut -d'"' -f4)
|
||||
echo "Error: $ERROR_MSG" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Calculate estimate
|
||||
QUANTITY="${CALLS:-$UNITS}"
|
||||
ESTIMATE_TYPE="calls"
|
||||
if [ -n "$UNITS" ]; then
|
||||
ESTIMATE_TYPE="units"
|
||||
fi
|
||||
|
||||
echo "" >&2
|
||||
if command -v python3 &> /dev/null; then
|
||||
python3 << PYTHON_EOF - "$PRICING_RESPONSE" "$MODEL" "$QUANTITY" "$ESTIMATE_TYPE"
|
||||
import json
|
||||
import sys
|
||||
|
||||
response = json.loads(sys.argv[1])
|
||||
model = sys.argv[2]
|
||||
quantity = float(sys.argv[3])
|
||||
estimate_type = sys.argv[4]
|
||||
|
||||
print(f"Cost Estimate: {model}", file=sys.stderr)
|
||||
print("=" * (len(model) + 15), file=sys.stderr)
|
||||
print("", file=sys.stderr)
|
||||
|
||||
# Extract pricing data
|
||||
prices = response.get('prices', [response] if isinstance(response, dict) else response)
|
||||
if isinstance(prices, list) and len(prices) > 0:
|
||||
price_info = prices[0]
|
||||
unit_price = float(price_info.get('unit_price', 0))
|
||||
unit = price_info.get('unit', 'call')
|
||||
currency = price_info.get('currency', 'USD')
|
||||
|
||||
# Calculate estimated cost
|
||||
estimated_cost = unit_price * quantity
|
||||
|
||||
print(f" Unit Price: {unit_price} {currency} per {unit}", file=sys.stderr)
|
||||
print(f" Quantity: {quantity:.0f} {estimate_type}", file=sys.stderr)
|
||||
print(f" Estimated Cost: {estimated_cost:.4f} {currency}", file=sys.stderr)
|
||||
|
||||
# Output JSON
|
||||
result = {
|
||||
"model": model,
|
||||
"unit_price": unit_price,
|
||||
"unit": unit,
|
||||
"quantity": quantity,
|
||||
"estimated_cost": estimated_cost,
|
||||
"currency": currency
|
||||
}
|
||||
print(json.dumps(result))
|
||||
else:
|
||||
print(" Unable to calculate estimate - pricing data not found", file=sys.stderr)
|
||||
print(json.dumps({"error": "pricing data not found"}))
|
||||
PYTHON_EOF
|
||||
else
|
||||
echo " Python3 required for calculation" >&2
|
||||
fi
|
||||
143
fal-platform/scripts/pricing.sh
Executable file
143
fal-platform/scripts/pricing.sh
Executable file
@@ -0,0 +1,143 @@
|
||||
#!/bin/bash
|
||||
|
||||
# fal.ai Pricing Script
|
||||
# Usage: ./pricing.sh --model MODEL [--category CATEGORY]
|
||||
# Returns pricing information for models
|
||||
|
||||
set -e
|
||||
|
||||
FAL_API_BASE="https://api.fal.ai/v1"
|
||||
|
||||
# Default values
|
||||
MODELS=""
|
||||
CATEGORY=""
|
||||
OUTPUT_JSON=false
|
||||
|
||||
# Check for --add-fal-key first
|
||||
for arg in "$@"; do
|
||||
if [ "$arg" = "--add-fal-key" ]; then
|
||||
bash "$(dirname "$0")/setup.sh" "$@"
|
||||
exit $?
|
||||
fi
|
||||
done
|
||||
|
||||
# Parse arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--model|-m)
|
||||
MODELS="$2"
|
||||
shift 2
|
||||
;;
|
||||
--category|-c)
|
||||
CATEGORY="$2"
|
||||
shift 2
|
||||
;;
|
||||
--json)
|
||||
OUTPUT_JSON=true
|
||||
shift
|
||||
;;
|
||||
--help|-h)
|
||||
echo "fal.ai Pricing Script" >&2
|
||||
echo "" >&2
|
||||
echo "Usage:" >&2
|
||||
echo " ./pricing.sh --model MODEL Get pricing for model(s)" >&2
|
||||
echo " ./pricing.sh --category CATEGORY Get pricing for category" >&2
|
||||
echo "" >&2
|
||||
echo "Options:" >&2
|
||||
echo " --model, -m Model ID(s), comma-separated" >&2
|
||||
echo " --category, -c Filter by category" >&2
|
||||
echo " --json Output raw JSON" >&2
|
||||
echo " --add-fal-key Setup FAL_KEY" >&2
|
||||
echo "" >&2
|
||||
echo "Examples:" >&2
|
||||
echo " ./pricing.sh --model \"fal-ai/flux/dev\"" >&2
|
||||
echo " ./pricing.sh --model \"fal-ai/flux/dev,fal-ai/kling-video/v2.1/pro\"" >&2
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Load .env if exists
|
||||
if [ -f ".env" ]; then
|
||||
source .env 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Check for FAL_KEY
|
||||
if [ -z "$FAL_KEY" ]; then
|
||||
echo "Error: FAL_KEY required" >&2
|
||||
echo "" >&2
|
||||
echo "Run: ./setup.sh --add-fal-key" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$MODELS" ] && [ -z "$CATEGORY" ]; then
|
||||
echo "Error: --model or --category required" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Fetching pricing information..." >&2
|
||||
|
||||
# Build endpoint URL
|
||||
if [ -n "$MODELS" ]; then
|
||||
# URL encode the model IDs
|
||||
ENCODED_MODELS=$(echo "$MODELS" | sed 's/,/%2C/g' | sed 's/\//%2F/g')
|
||||
ENDPOINT="$FAL_API_BASE/models/pricing?endpoint_id=$ENCODED_MODELS"
|
||||
else
|
||||
ENDPOINT="$FAL_API_BASE/models?category=$CATEGORY&include_pricing=true"
|
||||
fi
|
||||
|
||||
# Make API request
|
||||
RESPONSE=$(curl -s -X GET "$ENDPOINT" \
|
||||
-H "Authorization: Key $FAL_KEY" \
|
||||
-H "Content-Type: application/json")
|
||||
|
||||
# Check for errors
|
||||
if echo "$RESPONSE" | grep -q '"error"'; then
|
||||
ERROR_MSG=$(echo "$RESPONSE" | grep -o '"message":"[^"]*"' | head -1 | cut -d'"' -f4)
|
||||
echo "Error: $ERROR_MSG" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$OUTPUT_JSON" = true ]; then
|
||||
echo "$RESPONSE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Parse and display pricing
|
||||
echo "" >&2
|
||||
if command -v python3 &> /dev/null; then
|
||||
python3 << 'PYTHON_EOF' - "$RESPONSE"
|
||||
import json
|
||||
import sys
|
||||
|
||||
response = json.loads(sys.argv[1])
|
||||
data = response.get('data', response)
|
||||
|
||||
if isinstance(data, list):
|
||||
for item in data:
|
||||
endpoint = item.get('endpoint_id', 'Unknown')
|
||||
pricing = item.get('pricing', {})
|
||||
print(f"{endpoint}", file=sys.stderr)
|
||||
|
||||
if pricing:
|
||||
price = pricing.get('price', 'N/A')
|
||||
unit = pricing.get('unit', 'call')
|
||||
print(f" Price: ${price} per {unit}", file=sys.stderr)
|
||||
else:
|
||||
print(f" Pricing: Not available", file=sys.stderr)
|
||||
print("", file=sys.stderr)
|
||||
elif isinstance(data, dict):
|
||||
for endpoint, info in data.items():
|
||||
print(f"{endpoint}", file=sys.stderr)
|
||||
if isinstance(info, dict):
|
||||
price = info.get('price', info.get('unit_price', 'N/A'))
|
||||
unit = info.get('unit', info.get('billing_unit', 'call'))
|
||||
print(f" Price: ${price} per {unit}", file=sys.stderr)
|
||||
print("", file=sys.stderr)
|
||||
PYTHON_EOF
|
||||
fi
|
||||
|
||||
echo "$RESPONSE"
|
||||
158
fal-platform/scripts/requests.sh
Executable file
158
fal-platform/scripts/requests.sh
Executable file
@@ -0,0 +1,158 @@
|
||||
#!/bin/bash
|
||||
|
||||
# fal.ai Requests Management Script
|
||||
# Usage: ./requests.sh --model MODEL [--limit N] | --delete REQUEST_ID
|
||||
# List and manage API requests
|
||||
|
||||
set -e
|
||||
|
||||
FAL_API_BASE="https://api.fal.ai/v1"
|
||||
|
||||
# Default values
|
||||
MODEL=""
|
||||
LIMIT=10
|
||||
DELETE_ID=""
|
||||
OUTPUT_JSON=false
|
||||
|
||||
# Check for --add-fal-key first
|
||||
for arg in "$@"; do
|
||||
if [ "$arg" = "--add-fal-key" ]; then
|
||||
bash "$(dirname "$0")/setup.sh" "$@"
|
||||
exit $?
|
||||
fi
|
||||
done
|
||||
|
||||
# Parse arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--model|-m)
|
||||
MODEL="$2"
|
||||
shift 2
|
||||
;;
|
||||
--limit|-l)
|
||||
LIMIT="$2"
|
||||
shift 2
|
||||
;;
|
||||
--delete|-d)
|
||||
DELETE_ID="$2"
|
||||
shift 2
|
||||
;;
|
||||
--json)
|
||||
OUTPUT_JSON=true
|
||||
shift
|
||||
;;
|
||||
--help|-h)
|
||||
echo "fal.ai Requests Management Script" >&2
|
||||
echo "" >&2
|
||||
echo "Usage:" >&2
|
||||
echo " ./requests.sh --model MODEL List requests for model" >&2
|
||||
echo " ./requests.sh --delete REQUEST_ID Delete request payloads" >&2
|
||||
echo "" >&2
|
||||
echo "Options:" >&2
|
||||
echo " --model, -m Model ID to filter" >&2
|
||||
echo " --limit, -l Max results (default: 10)" >&2
|
||||
echo " --delete, -d Request ID to delete payloads" >&2
|
||||
echo " --json Output raw JSON" >&2
|
||||
echo " --add-fal-key Setup FAL_KEY" >&2
|
||||
echo "" >&2
|
||||
echo "Examples:" >&2
|
||||
echo " ./requests.sh --model \"fal-ai/flux/dev\" --limit 5" >&2
|
||||
echo " ./requests.sh --delete \"req_abc123\"" >&2
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Load .env if exists
|
||||
if [ -f ".env" ]; then
|
||||
source .env 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Check for FAL_KEY
|
||||
if [ -z "$FAL_KEY" ]; then
|
||||
echo "Error: FAL_KEY required" >&2
|
||||
echo "" >&2
|
||||
echo "Run: ./setup.sh --add-fal-key" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Delete request payloads
|
||||
if [ -n "$DELETE_ID" ]; then
|
||||
echo "Deleting payloads for request $DELETE_ID..." >&2
|
||||
|
||||
RESPONSE=$(curl -s -X DELETE "$FAL_API_BASE/models/requests/$DELETE_ID/payloads" \
|
||||
-H "Authorization: Key $FAL_KEY" \
|
||||
-H "Content-Type: application/json")
|
||||
|
||||
if echo "$RESPONSE" | grep -q '"error"'; then
|
||||
ERROR_MSG=$(echo "$RESPONSE" | grep -o '"message":"[^"]*"' | head -1 | cut -d'"' -f4)
|
||||
echo "Error: $ERROR_MSG" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Payloads deleted successfully" >&2
|
||||
echo "$RESPONSE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# List requests
|
||||
if [ -z "$MODEL" ]; then
|
||||
echo "Error: --model is required for listing requests" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Fetching requests for $MODEL..." >&2
|
||||
|
||||
ENCODED_MODEL=$(echo "$MODEL" | sed 's/\//%2F/g')
|
||||
|
||||
RESPONSE=$(curl -s -X GET "$FAL_API_BASE/models/requests/by-endpoint?endpoint_id=$ENCODED_MODEL&limit=$LIMIT" \
|
||||
-H "Authorization: Key $FAL_KEY" \
|
||||
-H "Content-Type: application/json")
|
||||
|
||||
# Check for errors
|
||||
if echo "$RESPONSE" | grep -q '"error"'; then
|
||||
ERROR_MSG=$(echo "$RESPONSE" | grep -o '"message":"[^"]*"' | head -1 | cut -d'"' -f4)
|
||||
echo "Error: $ERROR_MSG" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$OUTPUT_JSON" = true ]; then
|
||||
echo "$RESPONSE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Parse and display requests
|
||||
echo "" >&2
|
||||
if command -v python3 &> /dev/null; then
|
||||
python3 << 'PYTHON_EOF' - "$RESPONSE"
|
||||
import json
|
||||
import sys
|
||||
|
||||
response = json.loads(sys.argv[1])
|
||||
data = response.get('data', response)
|
||||
|
||||
if isinstance(data, list):
|
||||
print(f"Recent Requests ({len(data)} shown)", file=sys.stderr)
|
||||
print("=" * 40, file=sys.stderr)
|
||||
|
||||
for req in data:
|
||||
request_id = req.get('request_id', req.get('id', 'unknown'))
|
||||
status = req.get('status', 'unknown')
|
||||
created = req.get('created_at', req.get('timestamp', ''))[:19]
|
||||
duration = req.get('duration', 0)
|
||||
|
||||
print(f"", file=sys.stderr)
|
||||
print(f" ID: {request_id}", file=sys.stderr)
|
||||
print(f" Status: {status}", file=sys.stderr)
|
||||
print(f" Created: {created}", file=sys.stderr)
|
||||
if duration:
|
||||
print(f" Duration: {duration:.2f}s", file=sys.stderr)
|
||||
else:
|
||||
print("No requests found", file=sys.stderr)
|
||||
PYTHON_EOF
|
||||
fi
|
||||
|
||||
echo "$RESPONSE"
|
||||
126
fal-platform/scripts/setup.sh
Executable file
126
fal-platform/scripts/setup.sh
Executable file
@@ -0,0 +1,126 @@
|
||||
#!/bin/bash
|
||||
|
||||
# fal.ai Setup Script
|
||||
# Usage: ./setup.sh --add-fal-key [KEY] | --show-config
|
||||
# Manages FAL_KEY and configuration
|
||||
|
||||
set -e
|
||||
|
||||
ENV_FILE=".env"
|
||||
ACTION=""
|
||||
FAL_KEY_VALUE=""
|
||||
|
||||
# Parse arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--add-fal-key)
|
||||
ACTION="add-key"
|
||||
if [[ -n "$2" && ! "$2" =~ ^-- ]]; then
|
||||
FAL_KEY_VALUE="$2"
|
||||
shift
|
||||
fi
|
||||
shift
|
||||
;;
|
||||
--show-config)
|
||||
ACTION="show-config"
|
||||
shift
|
||||
;;
|
||||
--help|-h)
|
||||
echo "fal.ai Setup Script" >&2
|
||||
echo "" >&2
|
||||
echo "Usage:" >&2
|
||||
echo " ./setup.sh --add-fal-key [KEY] Add or update FAL_KEY" >&2
|
||||
echo " ./setup.sh --show-config Show current configuration" >&2
|
||||
echo "" >&2
|
||||
echo "Examples:" >&2
|
||||
echo " ./setup.sh --add-fal-key # Interactive prompt" >&2
|
||||
echo " ./setup.sh --add-fal-key \"your_key_here\" # Direct set" >&2
|
||||
echo "" >&2
|
||||
echo "Get your API key at: https://fal.ai/dashboard/keys" >&2
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1" >&2
|
||||
echo "Use --help for usage information" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Show config
|
||||
if [ "$ACTION" = "show-config" ]; then
|
||||
echo "fal.ai Configuration" >&2
|
||||
echo "===================" >&2
|
||||
|
||||
if [ -f "$ENV_FILE" ]; then
|
||||
echo "Environment file: $ENV_FILE" >&2
|
||||
if grep -q "FAL_KEY" "$ENV_FILE" 2>/dev/null; then
|
||||
KEY=$(grep "FAL_KEY" "$ENV_FILE" | cut -d'=' -f2 | tr -d '"' | tr -d "'")
|
||||
MASKED="${KEY:0:8}...${KEY: -4}"
|
||||
echo "FAL_KEY: $MASKED (set)" >&2
|
||||
else
|
||||
echo "FAL_KEY: not set" >&2
|
||||
fi
|
||||
else
|
||||
echo "Environment file: not found" >&2
|
||||
fi
|
||||
|
||||
if [ -n "$FAL_KEY" ]; then
|
||||
MASKED="${FAL_KEY:0:8}...${FAL_KEY: -4}"
|
||||
echo "FAL_KEY (env): $MASKED" >&2
|
||||
fi
|
||||
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Add FAL_KEY
|
||||
if [ "$ACTION" = "add-key" ]; then
|
||||
# Get key value
|
||||
if [ -z "$FAL_KEY_VALUE" ]; then
|
||||
echo "Enter your fal.ai API key:" >&2
|
||||
echo "(Get it from https://fal.ai/dashboard/keys)" >&2
|
||||
read -r FAL_KEY_VALUE
|
||||
fi
|
||||
|
||||
if [ -z "$FAL_KEY_VALUE" ]; then
|
||||
echo "Error: No API key provided" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate key format (basic check)
|
||||
if [[ ! "$FAL_KEY_VALUE" =~ ^[a-zA-Z0-9_-]+$ ]]; then
|
||||
echo "Warning: API key contains unusual characters" >&2
|
||||
fi
|
||||
|
||||
# Update or create .env file
|
||||
if [ -f "$ENV_FILE" ]; then
|
||||
# Remove existing FAL_KEY line
|
||||
grep -v "^FAL_KEY=" "$ENV_FILE" > "$ENV_FILE.tmp" 2>/dev/null || true
|
||||
mv "$ENV_FILE.tmp" "$ENV_FILE"
|
||||
fi
|
||||
|
||||
# Add new FAL_KEY
|
||||
echo "FAL_KEY=$FAL_KEY_VALUE" >> "$ENV_FILE"
|
||||
|
||||
echo "" >&2
|
||||
echo "FAL_KEY saved to $ENV_FILE" >&2
|
||||
echo "" >&2
|
||||
echo "To use in current session, run:" >&2
|
||||
echo " source $ENV_FILE" >&2
|
||||
echo "" >&2
|
||||
echo "Or export directly:" >&2
|
||||
echo " export FAL_KEY=$FAL_KEY_VALUE" >&2
|
||||
|
||||
# Output JSON
|
||||
echo "{\"success\": true, \"env_file\": \"$ENV_FILE\"}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Default: show help
|
||||
echo "fal.ai Setup Script" >&2
|
||||
echo "" >&2
|
||||
echo "Usage:" >&2
|
||||
echo " ./setup.sh --add-fal-key [KEY] Add or update FAL_KEY" >&2
|
||||
echo " ./setup.sh --show-config Show current configuration" >&2
|
||||
echo "" >&2
|
||||
echo "Get your API key at: https://fal.ai/dashboard/keys" >&2
|
||||
183
fal-platform/scripts/usage.sh
Executable file
183
fal-platform/scripts/usage.sh
Executable file
@@ -0,0 +1,183 @@
|
||||
#!/bin/bash
|
||||
|
||||
# fal.ai Usage Script
|
||||
# Usage: ./usage.sh [--model MODEL] [--start DATE] [--end DATE] [--timeframe TF]
|
||||
# Returns usage information and billing
|
||||
|
||||
set -e
|
||||
|
||||
FAL_API_BASE="https://api.fal.ai/v1"
|
||||
|
||||
# Default values
|
||||
MODEL=""
|
||||
START_DATE=""
|
||||
END_DATE=""
|
||||
TIMEFRAME=""
|
||||
OUTPUT_JSON=false
|
||||
|
||||
# Check for --add-fal-key first
|
||||
for arg in "$@"; do
|
||||
if [ "$arg" = "--add-fal-key" ]; then
|
||||
bash "$(dirname "$0")/setup.sh" "$@"
|
||||
exit $?
|
||||
fi
|
||||
done
|
||||
|
||||
# Parse arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--model|-m)
|
||||
MODEL="$2"
|
||||
shift 2
|
||||
;;
|
||||
--start|-s)
|
||||
START_DATE="$2"
|
||||
shift 2
|
||||
;;
|
||||
--end|-e)
|
||||
END_DATE="$2"
|
||||
shift 2
|
||||
;;
|
||||
--timeframe|-t)
|
||||
TIMEFRAME="$2"
|
||||
shift 2
|
||||
;;
|
||||
--json)
|
||||
OUTPUT_JSON=true
|
||||
shift
|
||||
;;
|
||||
--help|-h)
|
||||
echo "fal.ai Usage Script" >&2
|
||||
echo "" >&2
|
||||
echo "Usage:" >&2
|
||||
echo " ./usage.sh Get current usage" >&2
|
||||
echo " ./usage.sh --model MODEL Filter by model" >&2
|
||||
echo " ./usage.sh --start DATE --end DATE Date range" >&2
|
||||
echo "" >&2
|
||||
echo "Options:" >&2
|
||||
echo " --model, -m Model ID to filter" >&2
|
||||
echo " --start, -s Start date (ISO8601 or YYYY-MM-DD)" >&2
|
||||
echo " --end, -e End date" >&2
|
||||
echo " --timeframe, -t Aggregation: minute, hour, day, week, month" >&2
|
||||
echo " --json Output raw JSON" >&2
|
||||
echo " --add-fal-key Setup FAL_KEY" >&2
|
||||
echo "" >&2
|
||||
echo "Examples:" >&2
|
||||
echo " ./usage.sh" >&2
|
||||
echo " ./usage.sh --model \"fal-ai/flux/dev\"" >&2
|
||||
echo " ./usage.sh --start \"2024-01-01\" --end \"2024-01-31\"" >&2
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Load .env if exists
|
||||
if [ -f ".env" ]; then
|
||||
source .env 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Check for FAL_KEY
|
||||
if [ -z "$FAL_KEY" ]; then
|
||||
echo "Error: FAL_KEY required" >&2
|
||||
echo "" >&2
|
||||
echo "Run: ./setup.sh --add-fal-key" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Fetching usage information..." >&2
|
||||
|
||||
# Build query parameters
|
||||
PARAMS="expand=time_series,summary"
|
||||
|
||||
if [ -n "$MODEL" ]; then
|
||||
ENCODED_MODEL=$(echo "$MODEL" | sed 's/\//%2F/g')
|
||||
PARAMS="$PARAMS&endpoint_id=$ENCODED_MODEL"
|
||||
fi
|
||||
|
||||
if [ -n "$START_DATE" ]; then
|
||||
PARAMS="$PARAMS&start=$START_DATE"
|
||||
fi
|
||||
|
||||
if [ -n "$END_DATE" ]; then
|
||||
PARAMS="$PARAMS&end=$END_DATE"
|
||||
fi
|
||||
|
||||
if [ -n "$TIMEFRAME" ]; then
|
||||
PARAMS="$PARAMS&timeframe=$TIMEFRAME"
|
||||
fi
|
||||
|
||||
# Make API request
|
||||
RESPONSE=$(curl -s -X GET "$FAL_API_BASE/models/usage?$PARAMS" \
|
||||
-H "Authorization: Key $FAL_KEY" \
|
||||
-H "Content-Type: application/json")
|
||||
|
||||
# Check for errors
|
||||
if echo "$RESPONSE" | grep -q '"error"'; then
|
||||
ERROR_MSG=$(echo "$RESPONSE" | grep -o '"message":"[^"]*"' | head -1 | cut -d'"' -f4)
|
||||
echo "Error: $ERROR_MSG" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$OUTPUT_JSON" = true ]; then
|
||||
echo "$RESPONSE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Parse and display usage
|
||||
echo "" >&2
|
||||
if command -v python3 &> /dev/null; then
|
||||
python3 << 'PYTHON_EOF' - "$RESPONSE"
|
||||
import json
|
||||
import sys
|
||||
|
||||
response = json.loads(sys.argv[1])
|
||||
|
||||
# Handle both dict and list responses
|
||||
if isinstance(response, list):
|
||||
data = response
|
||||
else:
|
||||
data = response.get('time_series', response.get('data', []))
|
||||
|
||||
# Summary if available
|
||||
summary = response.get('summary', {})
|
||||
if isinstance(summary, dict) and summary:
|
||||
print("Usage Summary", file=sys.stderr)
|
||||
print("=============", file=sys.stderr)
|
||||
total_cost = summary.get('total_cost', summary.get('cost', 0))
|
||||
total_requests = summary.get('total_requests', summary.get('request_count', 0))
|
||||
print(f" Total Cost: ${total_cost:.4f}", file=sys.stderr)
|
||||
print(f" Total Requests: {total_requests}", file=sys.stderr)
|
||||
print("", file=sys.stderr)
|
||||
|
||||
# Process time_series data
|
||||
if isinstance(data, list) and len(data) > 0:
|
||||
by_endpoint = {}
|
||||
for bucket in data:
|
||||
results = bucket.get('results', [bucket]) if isinstance(bucket, dict) else [bucket]
|
||||
for item in results:
|
||||
if not isinstance(item, dict):
|
||||
continue
|
||||
endpoint = item.get('endpoint_id', '')
|
||||
if not endpoint:
|
||||
continue
|
||||
if endpoint not in by_endpoint:
|
||||
by_endpoint[endpoint] = {'cost': 0, 'quantity': 0}
|
||||
by_endpoint[endpoint]['cost'] += float(item.get('cost', 0))
|
||||
by_endpoint[endpoint]['quantity'] += float(item.get('quantity', item.get('request_count', 0)))
|
||||
|
||||
if by_endpoint:
|
||||
print("Usage by Endpoint", file=sys.stderr)
|
||||
print("=================", file=sys.stderr)
|
||||
for endpoint, stats in by_endpoint.items():
|
||||
print(f" {endpoint}", file=sys.stderr)
|
||||
print(f" Cost: ${stats['cost']:.4f}", file=sys.stderr)
|
||||
print(f" Quantity: {stats['quantity']:.2f}", file=sys.stderr)
|
||||
else:
|
||||
print("No usage data found for this period", file=sys.stderr)
|
||||
PYTHON_EOF
|
||||
fi
|
||||
|
||||
echo "$RESPONSE"
|
||||
Reference in New Issue
Block a user