clawra-anime 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,177 @@
1
+ #!/bin/bash
2
+ # clawra-anime-selfie.sh
3
+ # 生成二次元风格自拍并通过 OpenClaw 发送
4
+ #
5
+ # 用法: ./clawra-anime-selfie.sh "<prompt>" "<channel>" ["<caption>"]
6
+
7
+ set -euo pipefail
8
+
9
+ RED='\033[0;31m'
10
+ GREEN='\033[0;32m'
11
+ YELLOW='\033[1;33m'
12
+ CYAN='\033[0;36m'
13
+ NC='\033[0m'
14
+
15
+ log_info() {
16
+ echo -e "${GREEN}[INFO]${NC} $1"
17
+ }
18
+
19
+ log_warn() {
20
+ echo -e "${YELLOW}[WARN]${NC} $1"
21
+ }
22
+
23
+ log_error() {
24
+ echo -e "${RED}[ERROR]${NC} $1"
25
+ }
26
+
27
+ # 检查环境变量
28
+ if [ -z "${FAL_KEY:-}" ]; then
29
+ log_error "FAL_KEY 环境变量未设置"
30
+ echo "请从这里获取 API key: https://fal.ai/dashboard/keys"
31
+ exit 1
32
+ fi
33
+
34
+ # 检查 jq
35
+ if ! command -v jq &> /dev/null; then
36
+ log_error "需要安装 jq"
37
+ echo "安装: brew install jq (macOS) 或 apt install jq (Linux)"
38
+ exit 1
39
+ fi
40
+
41
+ # 检查 openclaw CLI
42
+ if ! command -v openclaw &> /dev/null; then
43
+ log_warn "未找到 openclaw CLI - 将使用直接 API 调用"
44
+ USE_CLI=false
45
+ else
46
+ USE_CLI=true
47
+ fi
48
+
49
+ # 解析参数
50
+ USER_PROMPT="${1:-}"
51
+ CHANNEL="${2:-}"
52
+ CAPTION="${3:-}"
53
+ MODE="${4:-auto}" # auto/mirror/direct
54
+ ASPECT_RATIO="${5:-2:3}"
55
+ OUTPUT_FORMAT="${6:-jpeg}"
56
+
57
+ if [ -z "$USER_PROMPT" ] || [ -z "$CHANNEL" ]; then
58
+ echo "用法: $0 <prompt> <channel> [caption] [mode] [aspect_ratio] [output_format]"
59
+ echo ""
60
+ echo "参数:"
61
+ echo " prompt - 场景描述(必需)如:'在咖啡厅喝咖啡'"
62
+ echo " channel - 目标频道(必需)如:#general, @user, telegram"
63
+ echo " caption - 消息文字(可选)"
64
+ echo " mode - 自拍模式(可选)auto/mirror/direct"
65
+ echo " aspect_ratio - 比例(默认 2:3)"
66
+ echo " output_format - 格式(默认 jpeg)"
67
+ echo ""
68
+ echo "示例:"
69
+ echo " $0 \"穿着白色连衣裙在海边\" \"telegram\" \"今天的海滩~\""
70
+ exit 1
71
+ fi
72
+
73
+ # 自动检测模式
74
+ if [ "$MODE" = "auto" ]; then
75
+ if echo "$USER_PROMPT" | grep -qi -E "穿|wearing|outfit|衣服|dress"; then
76
+ MODE="mirror"
77
+ log_info "自动选择模式: 镜子自拍"
78
+ else
79
+ MODE="direct"
80
+ log_info "自动选择模式: 直接自拍"
81
+ fi
82
+ else
83
+ log_info "使用指定模式: $MODE"
84
+ fi
85
+
86
+ # 构建二次元风格 prompt
87
+ if [ "$MODE" = "mirror" ]; then
88
+ FULL_PROMPT="anime style, high quality manga illustration, cute anime elf girl, $USER_PROMPT, taking a mirror selfie, detailed anime art, soft lighting, 2D style"
89
+ else
90
+ FULL_PROMPT="anime style, high quality manga illustration, close-up selfie of cute anime elf girl, $USER_PROMPT, gentle smile, looking at camera, soft expression, detailed face, 2D anime art, warm atmosphere"
91
+ fi
92
+
93
+ log_info "生成二次元自拍..."
94
+ log_info "完整 Prompt: $FULL_PROMPT"
95
+
96
+ # 调用 fal.ai API
97
+ RESPONSE=$(curl -s -X POST "https://fal.run/xai/grok-imagine-image" \
98
+ -H "Authorization: Key $FAL_KEY" \
99
+ -H "Content-Type: application/json" \
100
+ -d "{
101
+ \"prompt\": $(echo "$FULL_PROMPT" | jq -Rs .),
102
+ \"num_images\": 1,
103
+ \"aspect_ratio\": \"$ASPECT_RATIO\",
104
+ \"output_format\": \"$OUTPUT_FORMAT\"
105
+ }")
106
+
107
+ # 检查错误
108
+ if echo "$RESPONSE" | jq -e '.error' > /dev/null 2>&1; then
109
+ ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error // .detail // "Unknown error"')
110
+ log_error "图片生成失败: $ERROR_MSG"
111
+ exit 1
112
+ fi
113
+
114
+ # 提取图片 URL
115
+ IMAGE_URL=$(echo "$RESPONSE" | jq -r '.images[0].url // empty')
116
+
117
+ if [ -z "$IMAGE_URL" ]; then
118
+ log_error "无法从响应中提取图片 URL"
119
+ echo "响应内容: $RESPONSE"
120
+ exit 1
121
+ fi
122
+
123
+ log_info "✅ 图片生成成功!"
124
+ log_info "URL: $IMAGE_URL"
125
+
126
+ # 获取优化后的 prompt
127
+ REVISED_PROMPT=$(echo "$RESPONSE" | jq -r '.revised_prompt // empty')
128
+ if [ -n "$REVISED_PROMPT" ]; then
129
+ log_info "优化后的 prompt: $REVISED_PROMPT"
130
+ fi
131
+
132
+ # 如果没有提供 caption,生成一个可爱的默认消息
133
+ if [ -z "$CAPTION" ]; then
134
+ CAPTION="📸 ${USER_PROMPT}的自拍~"
135
+ fi
136
+
137
+ # 通过 OpenClaw 发送
138
+ log_info "发送到频道: $CHANNEL"
139
+
140
+ if [ "$USE_CLI" = true ]; then
141
+ openclaw message send \
142
+ --action send \
143
+ --channel "$CHANNEL" \
144
+ --message "$CAPTION" \
145
+ --media "$IMAGE_URL"
146
+ else
147
+ GATEWAY_URL="${OPENCLAW_GATEWAY_URL:-http://localhost:18789}"
148
+ GATEWAY_TOKEN="${OPENCLAW_GATEWAY_TOKEN:-}"
149
+
150
+ curl -s -X POST "$GATEWAY_URL/message" \
151
+ -H "Content-Type: application/json" \
152
+ ${GATEWAY_TOKEN:+-H "Authorization: Bearer $GATEWAY_TOKEN"} \
153
+ -d "{
154
+ \"action\": \"send\",
155
+ \"channel\": \"$CHANNEL\",
156
+ \"message\": \"$CAPTION\",
157
+ \"media\": \"$IMAGE_URL\"
158
+ }"
159
+ fi
160
+
161
+ log_info "✅ 完成! 图片已发送到 $CHANNEL"
162
+
163
+ # 输出 JSON 结果
164
+ echo ""
165
+ echo "--- 结果 ---"
166
+ jq -n \
167
+ --arg url "$IMAGE_URL" \
168
+ --arg channel "$CHANNEL" \
169
+ --arg prompt "$FULL_PROMPT" \
170
+ --arg caption "$CAPTION" \
171
+ '{
172
+ success: true,
173
+ image_url: $url,
174
+ channel: $channel,
175
+ prompt: $prompt,
176
+ caption: $caption
177
+ }'
@@ -0,0 +1,162 @@
1
+ #!/bin/bash
2
+ # grok-imagine-send.sh
3
+ # Generate an image with Grok Imagine and send it via OpenClaw
4
+ #
5
+ # Usage: ./grok-imagine-send.sh "<prompt>" "<channel>" ["<caption>"]
6
+ #
7
+ # Environment variables required:
8
+ # FAL_KEY - Your fal.ai API key
9
+ #
10
+ # Example:
11
+ # FAL_KEY=your_key ./grok-imagine-send.sh "A sunset over mountains" "#art" "Check this out!"
12
+
13
+ set -euo pipefail
14
+
15
+ # Colors for output
16
+ RED='\033[0;31m'
17
+ GREEN='\033[0;32m'
18
+ YELLOW='\033[1;33m'
19
+ NC='\033[0m' # No Color
20
+
21
+ log_info() {
22
+ echo -e "${GREEN}[INFO]${NC} $1"
23
+ }
24
+
25
+ log_warn() {
26
+ echo -e "${YELLOW}[WARN]${NC} $1"
27
+ }
28
+
29
+ log_error() {
30
+ echo -e "${RED}[ERROR]${NC} $1"
31
+ }
32
+
33
+ # Check required environment variables
34
+ if [ -z "${FAL_KEY:-}" ]; then
35
+ log_error "FAL_KEY environment variable not set"
36
+ echo "Get your API key from: https://fal.ai/dashboard/keys"
37
+ exit 1
38
+ fi
39
+
40
+ # Check for jq
41
+ if ! command -v jq &> /dev/null; then
42
+ log_error "jq is required but not installed"
43
+ echo "Install with: brew install jq (macOS) or apt install jq (Linux)"
44
+ exit 1
45
+ fi
46
+
47
+ # Check for openclaw
48
+ if ! command -v openclaw &> /dev/null; then
49
+ log_warn "openclaw CLI not found - will attempt direct API call"
50
+ USE_CLI=false
51
+ else
52
+ USE_CLI=true
53
+ fi
54
+
55
+ # Parse arguments
56
+ PROMPT="${1:-}"
57
+ CHANNEL="${2:-}"
58
+ CAPTION="${3:-Generated with Grok Imagine}"
59
+ ASPECT_RATIO="${4:-1:1}"
60
+ OUTPUT_FORMAT="${5:-jpeg}"
61
+
62
+ if [ -z "$PROMPT" ] || [ -z "$CHANNEL" ]; then
63
+ echo "Usage: $0 <prompt> <channel> [caption] [aspect_ratio] [output_format]"
64
+ echo ""
65
+ echo "Arguments:"
66
+ echo " prompt - Image description (required)"
67
+ echo " channel - Target channel (required) e.g., #general, @user"
68
+ echo " caption - Message caption (default: 'Generated with Grok Imagine')"
69
+ echo " aspect_ratio - Image ratio (default: 1:1) Options: 2:1, 16:9, 4:3, 1:1, 3:4, 9:16"
70
+ echo " output_format - Image format (default: jpeg) Options: jpeg, png, webp"
71
+ echo ""
72
+ echo "Example:"
73
+ echo " $0 \"A cyberpunk city at night\" \"#art-gallery\" \"AI Art!\""
74
+ exit 1
75
+ fi
76
+
77
+ log_info "Generating image with Grok Imagine..."
78
+ log_info "Prompt: $PROMPT"
79
+ log_info "Aspect ratio: $ASPECT_RATIO"
80
+
81
+ # Generate image via fal.ai
82
+ RESPONSE=$(curl -s -X POST "https://fal.run/xai/grok-imagine-image" \
83
+ -H "Authorization: Key $FAL_KEY" \
84
+ -H "Content-Type: application/json" \
85
+ -d "{
86
+ \"prompt\": $(echo "$PROMPT" | jq -Rs .),
87
+ \"num_images\": 1,
88
+ \"aspect_ratio\": \"$ASPECT_RATIO\",
89
+ \"output_format\": \"$OUTPUT_FORMAT\"
90
+ }")
91
+
92
+ # Check for errors in response
93
+ if echo "$RESPONSE" | jq -e '.error' > /dev/null 2>&1; then
94
+ ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error // .detail // "Unknown error"')
95
+ log_error "Image generation failed: $ERROR_MSG"
96
+ exit 1
97
+ fi
98
+
99
+ # Extract image URL
100
+ IMAGE_URL=$(echo "$RESPONSE" | jq -r '.images[0].url // empty')
101
+
102
+ if [ -z "$IMAGE_URL" ]; then
103
+ log_error "Failed to extract image URL from response"
104
+ echo "Response: $RESPONSE"
105
+ exit 1
106
+ fi
107
+
108
+ log_info "Image generated successfully!"
109
+ log_info "URL: $IMAGE_URL"
110
+
111
+ # Get revised prompt if available
112
+ REVISED_PROMPT=$(echo "$RESPONSE" | jq -r '.revised_prompt // empty')
113
+ if [ -n "$REVISED_PROMPT" ]; then
114
+ log_info "Revised prompt: $REVISED_PROMPT"
115
+ fi
116
+
117
+ # Send via OpenClaw
118
+ log_info "Sending to channel: $CHANNEL"
119
+
120
+ if [ "$USE_CLI" = true ]; then
121
+ # Use OpenClaw CLI
122
+ openclaw message send \
123
+ --action send \
124
+ --channel "$CHANNEL" \
125
+ --message "$CAPTION" \
126
+ --media "$IMAGE_URL"
127
+ else
128
+ # Direct API call to local gateway
129
+ GATEWAY_URL="${OPENCLAW_GATEWAY_URL:-http://localhost:18789}"
130
+ GATEWAY_TOKEN="${OPENCLAW_GATEWAY_TOKEN:-}"
131
+
132
+ HEADERS="-H \"Content-Type: application/json\""
133
+ if [ -n "$GATEWAY_TOKEN" ]; then
134
+ HEADERS="$HEADERS -H \"Authorization: Bearer $GATEWAY_TOKEN\""
135
+ fi
136
+
137
+ curl -s -X POST "$GATEWAY_URL/message" \
138
+ -H "Content-Type: application/json" \
139
+ ${GATEWAY_TOKEN:+-H "Authorization: Bearer $GATEWAY_TOKEN"} \
140
+ -d "{
141
+ \"action\": \"send\",
142
+ \"channel\": \"$CHANNEL\",
143
+ \"message\": \"$CAPTION\",
144
+ \"media\": \"$IMAGE_URL\"
145
+ }"
146
+ fi
147
+
148
+ log_info "Done! Image sent to $CHANNEL"
149
+
150
+ # Output JSON for programmatic use
151
+ echo ""
152
+ echo "--- Result ---"
153
+ jq -n \
154
+ --arg url "$IMAGE_URL" \
155
+ --arg channel "$CHANNEL" \
156
+ --arg prompt "$PROMPT" \
157
+ '{
158
+ success: true,
159
+ image_url: $url,
160
+ channel: $channel,
161
+ prompt: $prompt
162
+ }'
@@ -0,0 +1,299 @@
1
+ /**
2
+ * Grok Imagine to OpenClaw Integration
3
+ *
4
+ * Generates images using xAI's Grok Imagine model via fal.ai
5
+ * and sends them to messaging channels via OpenClaw.
6
+ *
7
+ * Usage:
8
+ * npx ts-node grok-imagine-send.ts "<prompt>" "<channel>" ["<caption>"]
9
+ *
10
+ * Environment variables:
11
+ * FAL_KEY - Your fal.ai API key
12
+ * OPENCLAW_GATEWAY_URL - OpenClaw gateway URL (default: http://localhost:18789)
13
+ * OPENCLAW_GATEWAY_TOKEN - Gateway auth token (optional)
14
+ */
15
+
16
+ import { exec } from "child_process";
17
+ import { promisify } from "util";
18
+
19
+ const execAsync = promisify(exec);
20
+
21
+ // Types
22
+ interface GrokImagineInput {
23
+ prompt: string;
24
+ num_images?: number;
25
+ aspect_ratio?: AspectRatio;
26
+ output_format?: OutputFormat;
27
+ }
28
+
29
+ interface GrokImagineImage {
30
+ url: string;
31
+ content_type: string;
32
+ file_name?: string;
33
+ width: number;
34
+ height: number;
35
+ }
36
+
37
+ interface GrokImagineResponse {
38
+ images: GrokImagineImage[];
39
+ revised_prompt?: string;
40
+ }
41
+
42
+ interface OpenClawMessage {
43
+ action: "send";
44
+ channel: string;
45
+ message: string;
46
+ media?: string;
47
+ }
48
+
49
+ type AspectRatio =
50
+ | "2:1"
51
+ | "20:9"
52
+ | "19.5:9"
53
+ | "16:9"
54
+ | "4:3"
55
+ | "3:2"
56
+ | "1:1"
57
+ | "2:3"
58
+ | "3:4"
59
+ | "9:16"
60
+ | "9:19.5"
61
+ | "9:20"
62
+ | "1:2";
63
+
64
+ type OutputFormat = "jpeg" | "png" | "webp";
65
+
66
+ interface GenerateAndSendOptions {
67
+ prompt: string;
68
+ channel: string;
69
+ caption?: string;
70
+ aspectRatio?: AspectRatio;
71
+ outputFormat?: OutputFormat;
72
+ useClaudeCodeCLI?: boolean;
73
+ }
74
+
75
+ interface Result {
76
+ success: boolean;
77
+ imageUrl: string;
78
+ channel: string;
79
+ prompt: string;
80
+ revisedPrompt?: string;
81
+ }
82
+
83
+ // Check for fal.ai client
84
+ let falClient: any;
85
+ try {
86
+ const { fal } = require("@fal-ai/client");
87
+ falClient = fal;
88
+ } catch {
89
+ // Will use fetch instead
90
+ falClient = null;
91
+ }
92
+
93
+ /**
94
+ * Generate image using Grok Imagine via fal.ai
95
+ */
96
+ async function generateImage(
97
+ input: GrokImagineInput
98
+ ): Promise<GrokImagineResponse> {
99
+ const falKey = process.env.FAL_KEY;
100
+
101
+ if (!falKey) {
102
+ throw new Error(
103
+ "FAL_KEY environment variable not set. Get your key from https://fal.ai/dashboard/keys"
104
+ );
105
+ }
106
+
107
+ // Use fal client if available
108
+ if (falClient) {
109
+ falClient.config({ credentials: falKey });
110
+
111
+ const result = await falClient.subscribe("xai/grok-imagine-image", {
112
+ input: {
113
+ prompt: input.prompt,
114
+ num_images: input.num_images || 1,
115
+ aspect_ratio: input.aspect_ratio || "1:1",
116
+ output_format: input.output_format || "jpeg",
117
+ },
118
+ });
119
+
120
+ return result.data as GrokImagineResponse;
121
+ }
122
+
123
+ // Fallback to fetch
124
+ const response = await fetch("https://fal.run/xai/grok-imagine-image", {
125
+ method: "POST",
126
+ headers: {
127
+ Authorization: `Key ${falKey}`,
128
+ "Content-Type": "application/json",
129
+ },
130
+ body: JSON.stringify({
131
+ prompt: input.prompt,
132
+ num_images: input.num_images || 1,
133
+ aspect_ratio: input.aspect_ratio || "1:1",
134
+ output_format: input.output_format || "jpeg",
135
+ }),
136
+ });
137
+
138
+ if (!response.ok) {
139
+ const error = await response.text();
140
+ throw new Error(`Image generation failed: ${error}`);
141
+ }
142
+
143
+ return response.json();
144
+ }
145
+
146
+ /**
147
+ * Send image via OpenClaw
148
+ */
149
+ async function sendViaOpenClaw(
150
+ message: OpenClawMessage,
151
+ useCLI: boolean = true
152
+ ): Promise<void> {
153
+ if (useCLI) {
154
+ // Use OpenClaw CLI
155
+ const cmd = `openclaw message send --action send --channel "${message.channel}" --message "${message.message}" --media "${message.media}"`;
156
+ await execAsync(cmd);
157
+ return;
158
+ }
159
+
160
+ // Direct API call
161
+ const gatewayUrl =
162
+ process.env.OPENCLAW_GATEWAY_URL || "http://localhost:18789";
163
+ const gatewayToken = process.env.OPENCLAW_GATEWAY_TOKEN;
164
+
165
+ const headers: Record<string, string> = {
166
+ "Content-Type": "application/json",
167
+ };
168
+
169
+ if (gatewayToken) {
170
+ headers["Authorization"] = `Bearer ${gatewayToken}`;
171
+ }
172
+
173
+ const response = await fetch(`${gatewayUrl}/message`, {
174
+ method: "POST",
175
+ headers,
176
+ body: JSON.stringify(message),
177
+ });
178
+
179
+ if (!response.ok) {
180
+ const error = await response.text();
181
+ throw new Error(`OpenClaw send failed: ${error}`);
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Main function: Generate image and send to channel
187
+ */
188
+ async function generateAndSend(options: GenerateAndSendOptions): Promise<Result> {
189
+ const {
190
+ prompt,
191
+ channel,
192
+ caption = "Generated with Grok Imagine",
193
+ aspectRatio = "1:1",
194
+ outputFormat = "jpeg",
195
+ useClaudeCodeCLI = true,
196
+ } = options;
197
+
198
+ console.log(`[INFO] Generating image with Grok Imagine...`);
199
+ console.log(`[INFO] Prompt: ${prompt}`);
200
+ console.log(`[INFO] Aspect ratio: ${aspectRatio}`);
201
+
202
+ // Generate image
203
+ const imageResult = await generateImage({
204
+ prompt,
205
+ num_images: 1,
206
+ aspect_ratio: aspectRatio,
207
+ output_format: outputFormat,
208
+ });
209
+
210
+ const imageUrl = imageResult.images[0].url;
211
+ console.log(`[INFO] Image generated: ${imageUrl}`);
212
+
213
+ if (imageResult.revised_prompt) {
214
+ console.log(`[INFO] Revised prompt: ${imageResult.revised_prompt}`);
215
+ }
216
+
217
+ // Send via OpenClaw
218
+ console.log(`[INFO] Sending to channel: ${channel}`);
219
+
220
+ await sendViaOpenClaw(
221
+ {
222
+ action: "send",
223
+ channel,
224
+ message: caption,
225
+ media: imageUrl,
226
+ },
227
+ useClaudeCodeCLI
228
+ );
229
+
230
+ console.log(`[INFO] Done! Image sent to ${channel}`);
231
+
232
+ return {
233
+ success: true,
234
+ imageUrl,
235
+ channel,
236
+ prompt,
237
+ revisedPrompt: imageResult.revised_prompt,
238
+ };
239
+ }
240
+
241
+ // CLI entry point
242
+ async function main() {
243
+ const args = process.argv.slice(2);
244
+
245
+ if (args.length < 2) {
246
+ console.log(`
247
+ Usage: npx ts-node grok-imagine-send.ts <prompt> <channel> [caption] [aspect_ratio] [output_format]
248
+
249
+ Arguments:
250
+ prompt - Image description (required)
251
+ channel - Target channel (required) e.g., #general, @user
252
+ caption - Message caption (default: 'Generated with Grok Imagine')
253
+ aspect_ratio - Image ratio (default: 1:1) Options: 2:1, 16:9, 4:3, 1:1, 3:4, 9:16
254
+ output_format - Image format (default: jpeg) Options: jpeg, png, webp
255
+
256
+ Environment:
257
+ FAL_KEY - Your fal.ai API key (required)
258
+
259
+ Example:
260
+ FAL_KEY=your_key npx ts-node grok-imagine-send.ts "A cyberpunk city" "#art" "Check this out!"
261
+ `);
262
+ process.exit(1);
263
+ }
264
+
265
+ const [prompt, channel, caption, aspectRatio, outputFormat] = args;
266
+
267
+ try {
268
+ const result = await generateAndSend({
269
+ prompt,
270
+ channel,
271
+ caption,
272
+ aspectRatio: aspectRatio as AspectRatio,
273
+ outputFormat: outputFormat as OutputFormat,
274
+ });
275
+
276
+ console.log("\n--- Result ---");
277
+ console.log(JSON.stringify(result, null, 2));
278
+ } catch (error) {
279
+ console.error(`[ERROR] ${(error as Error).message}`);
280
+ process.exit(1);
281
+ }
282
+ }
283
+
284
+ // Export for module use
285
+ export {
286
+ generateImage,
287
+ sendViaOpenClaw,
288
+ generateAndSend,
289
+ GrokImagineInput,
290
+ GrokImagineResponse,
291
+ OpenClawMessage,
292
+ GenerateAndSendOptions,
293
+ Result,
294
+ };
295
+
296
+ // Run if executed directly
297
+ if (require.main === module) {
298
+ main();
299
+ }