smart_prompt 0.4.4 → 0.5.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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -10
  3. data/README.cn.md +307 -64
  4. data/README.md +311 -64
  5. data/Rakefile +10 -1
  6. data/config/anthropic_config.yml +151 -0
  7. data/config/image_generation_config.yml +22 -0
  8. data/config/multimodal_config.yml +85 -0
  9. data/config/sensenova_config.yml +63 -0
  10. data/config/zhipu_config.yml +73 -0
  11. data/examples/anthropic_basic_chat.rb +143 -0
  12. data/examples/anthropic_example.rb +232 -0
  13. data/examples/anthropic_multimodal.rb +212 -0
  14. data/examples/anthropic_streaming.rb +312 -0
  15. data/examples/anthropic_tool_calling.rb +393 -0
  16. data/examples/automatic_cleanup_example.rb +109 -0
  17. data/examples/history_management_examples.rb +522 -0
  18. data/examples/image_generation_example.rb +130 -0
  19. data/examples/monitoring_example.rb +121 -0
  20. data/examples/multimodal_example.rb +63 -0
  21. data/examples/relevance_based_strategy_example.rb +87 -0
  22. data/examples/sensenova_example.rb +129 -0
  23. data/examples/stt_example.rb +287 -0
  24. data/examples/tts_example.rb +244 -0
  25. data/examples/video_generation_example.rb +189 -0
  26. data/examples/zhipu_example.rb +151 -0
  27. data/lib/smart_prompt/anthropic_adapter.rb +363 -281
  28. data/lib/smart_prompt/compression_engine.rb +201 -0
  29. data/lib/smart_prompt/context_strategy.rb +22 -0
  30. data/lib/smart_prompt/conversation.rb +81 -191
  31. data/lib/smart_prompt/engine.rb +36 -19
  32. data/lib/smart_prompt/history_manager.rb +596 -0
  33. data/lib/smart_prompt/hybrid_strategy.rb +222 -0
  34. data/lib/smart_prompt/image_generation_adapter.rb +297 -0
  35. data/lib/smart_prompt/lru_cache.rb +133 -0
  36. data/lib/smart_prompt/message.rb +57 -0
  37. data/lib/smart_prompt/multimodal_adapter.rb +277 -0
  38. data/lib/smart_prompt/openai_adapter.rb +1 -25
  39. data/lib/smart_prompt/persistence_layer.rb +197 -0
  40. data/lib/smart_prompt/relevance_based_strategy.rb +221 -0
  41. data/lib/smart_prompt/sensenova_adapter.rb +410 -0
  42. data/lib/smart_prompt/session.rb +140 -0
  43. data/lib/smart_prompt/sliding_window_strategy.rb +100 -0
  44. data/lib/smart_prompt/stt_adapter.rb +381 -0
  45. data/lib/smart_prompt/summary_based_strategy.rb +152 -0
  46. data/lib/smart_prompt/token_counter.rb +74 -0
  47. data/lib/smart_prompt/tts_adapter.rb +403 -0
  48. data/lib/smart_prompt/version.rb +1 -1
  49. data/lib/smart_prompt/video_generation_adapter.rb +330 -0
  50. data/lib/smart_prompt/worker.rb +25 -3
  51. data/lib/smart_prompt/zhipu_adapter.rb +616 -0
  52. data/lib/smart_prompt.rb +22 -2
  53. data/workers/history_management_examples.rb +407 -0
  54. data/workers/image_generation_workers.rb +119 -0
  55. data/workers/multimodal_workers.rb +110 -0
  56. data/workers/sensenova_workers.rb +62 -0
  57. data/workers/stt_workers.rb +195 -0
  58. data/workers/tts_workers.rb +388 -0
  59. data/workers/video_generation_workers.rb +264 -0
  60. data/workers/zhipu_workers.rb +113 -0
  61. metadata +84 -8
@@ -0,0 +1,522 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # History Management Example Workers
5
+ # These examples demonstrate the new intelligent history management features
6
+ # introduced in the history-optimization feature.
7
+
8
+ require_relative "../lib/smart_prompt"
9
+
10
+ =begin
11
+ # ============================================================================
12
+ # Example 1: Explicit Session Management
13
+ # ============================================================================
14
+ # This example demonstrates how to explicitly manage sessions with unique IDs.
15
+ # Each session maintains its own isolated conversation history.
16
+
17
+ puts "\n=== Example 1: Explicit Session Management ==="
18
+
19
+ # Initialize engine
20
+ engine = SmartPrompt::Engine.new("config/anthropic_config.yml")
21
+
22
+ # Define a worker with explicit session management
23
+ SmartPrompt.define_worker :explicit_session_chat do
24
+ use "deepseek_anthropic"
25
+ model "deepseek-chat"
26
+
27
+ # Use a unique session ID for each conversation
28
+ # This could be a user ID, conversation ID, or any unique identifier
29
+ # session_id is passed via params and automatically used by the conversation
30
+
31
+ sys_msg("You are a helpful AI assistant.")
32
+ prompt(params[:message])
33
+ send_msg
34
+ end
35
+
36
+ # Example usage: Multiple isolated conversations
37
+ puts "\nCreating two separate conversations..."
38
+
39
+ # Conversation 1 with Alice
40
+ response1 = engine.call_worker(:explicit_session_chat, {
41
+ session_id: "user_alice",
42
+ message: "My name is Alice and I love programming.",
43
+ with_history: true,
44
+ })
45
+ puts "Alice: #{response1}"
46
+
47
+ # Conversation 2 with Bob
48
+ response2 = engine.call_worker(:explicit_session_chat, {
49
+ session_id: "user_bob",
50
+ message: "My name is Bob and I enjoy cooking.",
51
+ with_history: true,
52
+ })
53
+ puts "Bob: #{response2}"
54
+
55
+ # Continue Alice's conversation - should remember her name
56
+ response3 = engine.call_worker(:explicit_session_chat, {
57
+ session_id: "user_alice",
58
+ message: "What did I say I love?",
59
+ with_history: true,
60
+ })
61
+ puts "Alice (follow-up): #{response3}"
62
+
63
+ # Continue Bob's conversation - should remember his name
64
+ response4 = engine.call_worker(:explicit_session_chat, {
65
+ session_id: "user_bob",
66
+ message: "What did I say I enjoy?",
67
+ with_history: true,
68
+ })
69
+ puts "Bob (follow-up): #{response4}"
70
+ =end
71
+
72
+ # ============================================================================
73
+ # Example 2: Different Context Strategies
74
+ # ============================================================================
75
+ # This example demonstrates the different context strategies available:
76
+ # - Sliding Window: Keeps most recent N messages
77
+ # - Relevance-Based: Selects semantically relevant messages
78
+ # - Summary-Based: Automatically compresses old messages
79
+ # - Hybrid: Adaptively combines strategies
80
+
81
+ puts "\n\n=== Example 2: Different Context Strategies ==="
82
+ engine = SmartPrompt::Engine.new("config/anthropic_config.yml")
83
+ # 2.1 Sliding Window Strategy
84
+ # Best for: Real-time chat, customer support, short conversations
85
+ SmartPrompt.define_worker :sliding_window_chat do
86
+ use "deepseek_anthropic"
87
+ model "deepseek-chat"
88
+
89
+ session_id = params[:session_id] || "sliding_window_session"
90
+
91
+ # Configure session with sliding window strategy
92
+ session_config = {
93
+ max_messages: 3, # Keep only last 10 messages
94
+ max_tokens: 2000, # Maximum 2000 tokens
95
+ context_strategy: :sliding_window,
96
+ preserve_system_messages: true,
97
+ }
98
+
99
+ sys_msg("You are a customer support assistant.", params)
100
+ prompt(params[:message], with_history: true, session_id: session_id)
101
+
102
+ # Apply session configuration
103
+ @engine.history_manager.get_session(session_id, session_config)
104
+
105
+ send_msg
106
+ end
107
+
108
+ puts "\nSliding Window Strategy Example:"
109
+ puts "This strategy keeps only the most recent messages."
110
+
111
+ # Simulate a conversation with many messages
112
+ 5.times do |i|
113
+ response = engine.call_worker(:sliding_window_chat, {
114
+ session_id: "sliding_demo",
115
+ message: "This is message number #{i + 1}. Can you count?",
116
+ })
117
+ puts "Message #{i + 1} response: #{response[0..50]}..."
118
+ end
119
+
120
+ =begin
121
+ # 2.2 Relevance-Based Strategy
122
+ # Best for: Q&A systems, knowledge bases, context-aware assistants
123
+ SmartPrompt.define_worker :relevance_chat do
124
+ use "deepseek_anthropic"
125
+ model "deepseek-chat"
126
+
127
+ session_id = params[:session_id] || "relevance_session"
128
+
129
+ # Configure session with relevance-based strategy
130
+ session_config = {
131
+ max_messages: 50,
132
+ max_tokens: 4000,
133
+ context_strategy: :relevance_based,
134
+ preserve_system_messages: true,
135
+ }
136
+
137
+ sys_msg("You are a knowledgeable AI assistant.", params)
138
+ prompt(params[:message], with_history: true, session_id: session_id)
139
+
140
+ @engine.history_manager.get_session(session_id, session_config)
141
+
142
+ send_msg
143
+ end
144
+
145
+ puts "\nRelevance-Based Strategy Example:"
146
+ puts "This strategy selects semantically relevant messages."
147
+
148
+ # Example conversation with topic changes
149
+ topics = [
150
+ "Tell me about Ruby programming.",
151
+ "What about Python?",
152
+ "Now explain JavaScript.",
153
+ "Going back to Ruby, what are its best features?",
154
+ ]
155
+
156
+ topics.each_with_index do |message, i|
157
+ response = engine.call_worker(:relevance_chat, {
158
+ session_id: "relevance_demo",
159
+ message: message,
160
+ })
161
+ puts "Topic #{i + 1}: #{message}"
162
+ puts "Response: #{response[0..80]}...\n"
163
+ end
164
+
165
+ # 2.3 Summary-Based Strategy
166
+ # Best for: Long conversations, documentation, extended dialogues
167
+ SmartPrompt.define_worker :summary_chat do
168
+ use "deepseek_anthropic"
169
+ model "deepseek-chat"
170
+
171
+ session_id = params[:session_id] || "summary_session"
172
+
173
+ # Configure session with summary-based strategy
174
+ session_config = {
175
+ max_messages: 100,
176
+ max_tokens: 8000,
177
+ context_strategy: :summary_based,
178
+ preserve_system_messages: true,
179
+ }
180
+
181
+ sys_msg("You are a thoughtful AI assistant for extended conversations.", params)
182
+ prompt(params[:message], with_history: true, session_id: session_id)
183
+
184
+ @engine.history_manager.get_session(session_id, session_config)
185
+
186
+ send_msg
187
+ end
188
+
189
+ puts "\nSummary-Based Strategy Example:"
190
+ puts "This strategy automatically compresses old messages into summaries."
191
+
192
+ # Simulate a long conversation
193
+ 10.times do |i|
194
+ response = engine.call_worker(:summary_chat, {
195
+ session_id: "summary_demo",
196
+ message: "Tell me fact number #{i + 1} about space exploration.",
197
+ })
198
+ puts "Fact #{i + 1} received (#{response.length} chars)"
199
+ end
200
+
201
+ # 2.4 Hybrid Strategy
202
+ # Best for: General-purpose applications, varied conversation types
203
+ SmartPrompt.define_worker :hybrid_chat do
204
+ use "deepseek_anthropic"
205
+ model "deepseek-chat"
206
+
207
+ session_id = params[:session_id] || "hybrid_session"
208
+
209
+ # Configure session with hybrid strategy
210
+ session_config = {
211
+ max_messages: 75,
212
+ max_tokens: 6000,
213
+ context_strategy: :hybrid,
214
+ preserve_system_messages: true,
215
+ }
216
+
217
+ sys_msg("You are an intelligent AI assistant that adapts to conversation context.", params)
218
+ prompt(params[:message], with_history: true, session_id: session_id)
219
+
220
+ @engine.history_manager.get_session(session_id, session_config)
221
+
222
+ send_msg
223
+ end
224
+
225
+ puts "\nHybrid Strategy Example:"
226
+ puts "This strategy adaptively combines multiple strategies."
227
+
228
+ response = engine.call_worker(:hybrid_chat, {
229
+ session_id: "hybrid_demo",
230
+ message: "Let's have a conversation that covers many topics.",
231
+ })
232
+ puts "Response: #{response[0..80]}..."
233
+
234
+ # ============================================================================
235
+ # Example 3: Session Operations (clear, export, search, stats, delete)
236
+ # ============================================================================
237
+ # This example demonstrates various session management operations.
238
+
239
+ puts "\n\n=== Example 3: Session Operations ==="
240
+
241
+ # Create a session with some messages
242
+ session_id = "operations_demo"
243
+ engine = SmartPrompt::Engine.new
244
+
245
+ # Add some messages
246
+ puts "\nAdding messages to session..."
247
+ engine.history_manager.add_message(session_id, {
248
+ role: "system",
249
+ content: "You are a helpful assistant.",
250
+ })
251
+ engine.history_manager.add_message(session_id, {
252
+ role: "user",
253
+ content: "Hello! My name is Alice.",
254
+ })
255
+ engine.history_manager.add_message(session_id, {
256
+ role: "assistant",
257
+ content: "Hello Alice! Nice to meet you.",
258
+ })
259
+ engine.history_manager.add_message(session_id, {
260
+ role: "user",
261
+ content: "Can you help me with Ruby programming?",
262
+ })
263
+ engine.history_manager.add_message(session_id, {
264
+ role: "assistant",
265
+ content: "Of course! I'd be happy to help with Ruby programming.",
266
+ })
267
+
268
+ # 3.1 Get Statistics
269
+ puts "\n--- Get Statistics ---"
270
+ stats = engine.history_manager.get_stats(session_id)
271
+ puts "Session Statistics:"
272
+ puts " Message Count: #{stats[:message_count]}"
273
+ puts " Total Tokens: #{stats[:total_tokens]}"
274
+ puts " Created At: #{stats[:created_at]}"
275
+ puts " Updated At: #{stats[:updated_at]}"
276
+
277
+ # 3.2 Search Messages
278
+ puts "\n--- Search Messages ---"
279
+ search_results = engine.history_manager.search_messages(session_id, "Ruby")
280
+ puts "Search results for 'Ruby': #{search_results.count} messages found"
281
+ search_results.each do |msg|
282
+ puts " [#{msg.role}]: #{msg.content[0..50]}..."
283
+ end
284
+
285
+ # 3.3 Export Session
286
+ puts "\n--- Export Session ---"
287
+ exported_data = engine.history_manager.export_session(session_id, format: :hash)
288
+ puts "Exported session data:"
289
+ puts " ID: #{exported_data[:id]}"
290
+ puts " Messages: #{exported_data[:messages].count}"
291
+ puts " First message: #{exported_data[:messages].first[:content][0..50]}..."
292
+
293
+ # 3.4 Clear Session (keeping system messages)
294
+ puts "\n--- Clear Session ---"
295
+ puts "Messages before clear: #{engine.history_manager.get_stats(session_id)[:message_count]}"
296
+ engine.history_manager.clear_session(session_id, keep_system_messages: true)
297
+ puts "Messages after clear: #{engine.history_manager.get_stats(session_id)[:message_count]}"
298
+
299
+ # 3.5 Delete Session
300
+ puts "\n--- Delete Session ---"
301
+ puts "Session exists before delete: #{engine.history_manager.session_exists?(session_id)}"
302
+ engine.history_manager.delete_session(session_id)
303
+ puts "Session exists after delete: #{engine.history_manager.session_exists?(session_id)}"
304
+
305
+ # ============================================================================
306
+ # Example 4: Backward Compatibility
307
+ # ============================================================================
308
+ # This example demonstrates backward compatibility with the old API.
309
+
310
+ puts "\n\n=== Example 4: Backward Compatibility ==="
311
+
312
+ # Old-style worker definition (still works!)
313
+ SmartPrompt.define_worker :legacy_chat do
314
+ use "deepseek_anthropic"
315
+ model "deepseek-chat"
316
+
317
+ sys_msg("You are a helpful AI assistant.")
318
+
319
+ # Old-style history usage - still works!
320
+ prompt(params[:message], with_history: true)
321
+
322
+ send_msg
323
+ end
324
+
325
+ puts "\nUsing legacy API (with_history: true)..."
326
+ response = engine.call_worker(:legacy_chat, {
327
+ message: "Hello! This is using the old API.",
328
+ })
329
+ puts "Response: #{response[0..80]}..."
330
+
331
+ # The new system automatically creates a default session
332
+ # and maintains backward compatibility
333
+
334
+ # ============================================================================
335
+ # Example 5: Advanced - Multi-User Chat Application
336
+ # ============================================================================
337
+ # This example shows how to build a multi-user chat application
338
+ # with isolated sessions per user.
339
+
340
+ puts "\n\n=== Example 5: Multi-User Chat Application ==="
341
+
342
+ SmartPrompt.define_worker :multi_user_chat do
343
+ use "deepseek_anthropic"
344
+ model "deepseek-chat"
345
+
346
+ # Use user ID as session ID for isolation
347
+ user_id = params[:user_id] || raise("user_id is required")
348
+ session_id = "user_#{user_id}"
349
+
350
+ # Configure per-user session
351
+ session_config = {
352
+ max_messages: 50,
353
+ max_tokens: 3000,
354
+ context_strategy: :sliding_window,
355
+ preserve_system_messages: true,
356
+ }
357
+
358
+ user_name = params[:user_name] || "User"
359
+ sys_msg("You are a personal AI assistant for #{user_name}.")
360
+ prompt(params[:message], with_history: true, session_id: session_id)
361
+
362
+ @engine.history_manager.get_session(session_id, session_config)
363
+
364
+ send_msg
365
+ end
366
+
367
+ puts "\nSimulating multi-user chat..."
368
+
369
+ # User 1
370
+ response1 = engine.call_worker(:multi_user_chat, {
371
+ user_id: "001",
372
+ user_name: "Alice",
373
+ message: "Hi! I'm working on a Ruby project.",
374
+ })
375
+ puts "Alice: #{response1[0..60]}..."
376
+
377
+ # User 2
378
+ response2 = engine.call_worker(:multi_user_chat, {
379
+ user_id: "002",
380
+ user_name: "Bob",
381
+ message: "Hello! I need help with Python.",
382
+ })
383
+ puts "Bob: #{response2[0..60]}..."
384
+
385
+ # User 1 continues (should remember Ruby context)
386
+ response3 = engine.call_worker(:multi_user_chat, {
387
+ user_id: "001",
388
+ user_name: "Alice",
389
+ message: "What language was I asking about?",
390
+ })
391
+ puts "Alice (follow-up): #{response3[0..60]}..."
392
+
393
+ # ============================================================================
394
+ # Example 6: Monitoring and Debugging
395
+ # ============================================================================
396
+ # This example demonstrates how to monitor and debug the history system.
397
+
398
+ puts "\n\n=== Example 6: Monitoring and Debugging ==="
399
+
400
+ engine = SmartPrompt::Engine.new
401
+
402
+ # Get system-wide statistics
403
+ puts "\n--- System-Wide Statistics ---"
404
+ system_stats = engine.history_manager.get_stats
405
+ puts "Active Sessions: #{system_stats[:active_sessions]}"
406
+ puts "Total Messages: #{system_stats[:total_messages]}"
407
+ puts "Total Tokens: #{system_stats[:total_tokens]}"
408
+ puts "Cache Hit Rate: #{(system_stats[:cache_hit_rate] * 100).round(2)}%"
409
+ puts "Messages Added: #{system_stats[:messages_added]}"
410
+ puts "Context Retrievals: #{system_stats[:context_retrievals]}"
411
+
412
+ # Export metrics in Prometheus format
413
+ puts "\n--- Prometheus Metrics ---"
414
+ prometheus_metrics = engine.history_manager.export_metrics(format: :prometheus)
415
+ puts prometheus_metrics.lines.first(10).join
416
+
417
+ # List all active sessions
418
+ puts "\n--- Active Sessions ---"
419
+ session_ids = engine.history_manager.session_ids
420
+ puts "Total active sessions: #{session_ids.count}"
421
+ session_ids.first(5).each do |sid|
422
+ puts " - #{sid}"
423
+ end
424
+
425
+ # ============================================================================
426
+ # Example 7: Custom Configuration
427
+ # ============================================================================
428
+ # This example shows how to fine-tune session configuration for specific use cases.
429
+
430
+ puts "\n\n=== Example 7: Custom Configuration ==="
431
+
432
+ SmartPrompt.define_worker :custom_config_chat do
433
+ use "deepseek_anthropic"
434
+ model "deepseek-chat"
435
+
436
+ session_id = params[:session_id] || "custom_session"
437
+
438
+ # Fine-tuned configuration for a code review assistant
439
+ session_config = {
440
+ max_messages: 100,
441
+ max_tokens: 8000,
442
+ context_strategy: :relevance_based,
443
+ preserve_system_messages: true,
444
+ }
445
+
446
+ sys_msg("You are an expert code reviewer. Analyze code and provide constructive feedback.")
447
+ prompt(params[:message], with_history: true, session_id: session_id)
448
+
449
+ @engine.history_manager.get_session(session_id, session_config)
450
+
451
+ send_msg
452
+ end
453
+
454
+ puts "\nCode review assistant with custom configuration..."
455
+ response = SmartPrompt.run_worker(:custom_config_chat, {
456
+ session_id: "code_review_001",
457
+ message: "Please review this Ruby code: def hello; puts 'world'; end",
458
+ })
459
+ puts "Review: #{response[0..100]}..."
460
+
461
+ # ============================================================================
462
+ # Example 8: Session Lifecycle Management
463
+ # ============================================================================
464
+ # This example demonstrates the complete lifecycle of a session.
465
+
466
+ puts "\n\n=== Example 8: Session Lifecycle Management ==="
467
+
468
+ engine = SmartPrompt::Engine.new
469
+ lifecycle_session_id = "lifecycle_demo"
470
+
471
+ # 1. Create session (implicitly through add_message)
472
+ puts "\n1. Creating session..."
473
+ engine.history_manager.add_message(lifecycle_session_id, {
474
+ role: "system",
475
+ content: "You are a helpful assistant.",
476
+ })
477
+ puts " Session created: #{engine.history_manager.session_exists?(lifecycle_session_id)}"
478
+
479
+ # 2. Add messages
480
+ puts "\n2. Adding messages..."
481
+ 3.times do |i|
482
+ engine.history_manager.add_message(lifecycle_session_id, {
483
+ role: "user",
484
+ content: "Message #{i + 1}",
485
+ })
486
+ end
487
+ stats = engine.history_manager.get_stats(lifecycle_session_id)
488
+ puts " Messages in session: #{stats[:message_count]}"
489
+
490
+ # 3. Retrieve context
491
+ puts "\n3. Retrieving context..."
492
+ context = engine.history_manager.get_context(lifecycle_session_id)
493
+ puts " Retrieved #{context.count} messages"
494
+
495
+ # 4. Export for backup
496
+ puts "\n4. Exporting session..."
497
+ backup = engine.history_manager.export_session(lifecycle_session_id, format: :json)
498
+ puts " Exported #{backup.length} bytes"
499
+
500
+ # 5. Clear session
501
+ puts "\n5. Clearing session..."
502
+ engine.history_manager.clear_session(lifecycle_session_id)
503
+ stats = engine.history_manager.get_stats(lifecycle_session_id)
504
+ puts " Messages after clear: #{stats[:message_count]}"
505
+
506
+ # 6. Delete session
507
+ puts "\n6. Deleting session..."
508
+ engine.history_manager.delete_session(lifecycle_session_id)
509
+ puts " Session exists: #{engine.history_manager.session_exists?(lifecycle_session_id)}"
510
+
511
+ puts "\n\n=== All Examples Completed ==="
512
+ puts "These examples demonstrate the key features of the new history management system:"
513
+ puts " ✓ Explicit session management with unique IDs"
514
+ puts " ✓ Multiple context strategies (sliding window, relevance, summary, hybrid)"
515
+ puts " ✓ Session operations (clear, export, search, stats, delete)"
516
+ puts " ✓ Backward compatibility with existing API"
517
+ puts " ✓ Multi-user applications with session isolation"
518
+ puts " ✓ Monitoring and debugging capabilities"
519
+ puts " ✓ Custom configuration for specific use cases"
520
+ puts " ✓ Complete session lifecycle management"
521
+
522
+ =end
@@ -0,0 +1,130 @@
1
+ # Image Generation Example for SmartPrompt
2
+ #
3
+ # Demonstrates calling SiliconFlow's image generation API
4
+ # (POST /v1/images/generations) through the ImageGenerationAdapter.
5
+ #
6
+ # Requires a valid SiliconFlow API key in the SILICONFLOW_API_KEY (or APIKey)
7
+ # environment variable.
8
+
9
+ require_relative "../lib/smart_prompt"
10
+
11
+ api_key = ENV["SILICONFLOW_API_KEY"] || ENV["APIKey"]
12
+
13
+ # Configuration for image generation capabilities.
14
+ config = {
15
+ "adapters" => {
16
+ "image_generation" => "ImageGenerationAdapter",
17
+ },
18
+ "llms" => {
19
+ "image_gen" => {
20
+ "adapter" => "image_generation",
21
+ "url" => "https://api.siliconflow.cn/v1/",
22
+ "api_key" => api_key,
23
+ # Kolors supports batch_size, guidance_scale and a range of image_size values.
24
+ "model" => "Kwai-Kolors/Kolors",
25
+ },
26
+ },
27
+ "default_llm" => "image_gen",
28
+ "template_path" => "./templates",
29
+ "worker_path" => "./workers",
30
+ "logger_file" => "./logs/smart_prompt.log",
31
+ }
32
+
33
+ # Write config to file
34
+ File.write("image_generation_config.yml", config.to_yaml)
35
+
36
+ # Initialize engine
37
+ engine = SmartPrompt::Engine.new("image_generation_config.yml")
38
+
39
+ puts "=== SmartPrompt Image Generation Demo ==="
40
+
41
+ unless api_key
42
+ puts "Note: SILICONFLOW_API_KEY is not set — the API calls below will fail at the network layer."
43
+ end
44
+
45
+ # Example 1: Simple text-to-image generation (Kolors)
46
+ puts "\n=== Example 1: Text-to-Image Generation ==="
47
+ begin
48
+ result = engine.call_worker(:image_generator, {
49
+ prompt: "A beautiful sunset over a mountain lake with pine trees, digital art style",
50
+ image_size: "1024x1024",
51
+ batch_size: 1,
52
+ save_to_file: true,
53
+ output_dir: "./generated_images",
54
+ filename_prefix: "sunset",
55
+ })
56
+
57
+ puts "Image generation successful!"
58
+ puts "Generated images: #{result[:images].size}"
59
+ puts "First image URL: #{result[:images].first[:url]}"
60
+ puts "Saved files: #{result[:saved_files]}"
61
+ rescue => e
62
+ puts "Error in image generation: #{e.message}"
63
+ end
64
+
65
+ # Example 2: Art generation with a specific style (more inference steps)
66
+ puts "\n=== Example 2: Artistic Image Generation ==="
67
+ begin
68
+ result = engine.call_worker(:art_generator, {
69
+ prompt: "A mystical forest with glowing mushrooms and fairies",
70
+ art_style: "fantasy art, detailed painting",
71
+ image_size: "960x1280",
72
+ num_inference_steps: 30,
73
+ guidance_scale: 7.5,
74
+ save_to_file: true,
75
+ output_dir: "./generated_images",
76
+ filename_prefix: "fantasy_forest",
77
+ })
78
+
79
+ puts "Art generation successful!"
80
+ puts "Generated art images: #{result[:images].size}"
81
+ puts "Saved files: #{result[:saved_files]}"
82
+ rescue => e
83
+ puts "Error in art generation: #{e.message}"
84
+ end
85
+
86
+ # Example 3: Product image generation (with a negative prompt)
87
+ puts "\n=== Example 3: Product Image Generation ==="
88
+ begin
89
+ result = engine.call_worker(:product_image_generator, {
90
+ prompt: "A modern smartphone on a marble surface",
91
+ image_size: "1024x1024",
92
+ negative_prompt: "text, watermark, logo",
93
+ save_to_file: true,
94
+ output_dir: "./generated_images",
95
+ filename_prefix: "smartphone",
96
+ })
97
+
98
+ puts "Product image generation successful!"
99
+ puts "Generated product images: #{result[:images].size}"
100
+ puts "Saved files: #{result[:saved_files]}"
101
+ rescue => e
102
+ puts "Error in product image generation: #{e.message}"
103
+ end
104
+
105
+ # Example 4: Direct adapter usage (without a worker)
106
+ puts "\n=== Example 4: Direct Adapter Usage ==="
107
+ begin
108
+ adapter = engine.llms["image_gen"]
109
+
110
+ images = adapter.generate_image(
111
+ "A cute robot reading a book in a cozy library",
112
+ image_size: "1024x1024",
113
+ seed: 42,
114
+ )
115
+
116
+ puts "Direct adapter usage successful!"
117
+ puts "Generated #{images.size} image(s)"
118
+ puts "First image URL: #{images.first[:url]}"
119
+
120
+ # Optionally save to disk
121
+ saved = adapter.save_image(images, "./generated_images", "robot")
122
+ puts "Saved files: #{saved}"
123
+ rescue => e
124
+ puts "Error in direct adapter usage: #{e.message}"
125
+ end
126
+
127
+ puts "\n=== All examples completed ==="
128
+
129
+ # Clean up
130
+ File.delete("image_generation_config.yml") if File.exist?("image_generation_config.yml")