npcpy 1.2.36__tar.gz → 1.3.1__tar.gz

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 (77) hide show
  1. {npcpy-1.2.36/npcpy.egg-info → npcpy-1.3.1}/PKG-INFO +175 -4
  2. {npcpy-1.2.36 → npcpy-1.3.1}/README.md +174 -3
  3. npcpy-1.3.1/npcpy/__init__.py +14 -0
  4. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/gen/image_gen.py +5 -2
  5. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/gen/response.py +262 -64
  6. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/llm_funcs.py +478 -832
  7. npcpy-1.3.1/npcpy/ml_funcs.py +746 -0
  8. npcpy-1.3.1/npcpy/npc_array.py +1294 -0
  9. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/npc_compiler.py +522 -341
  10. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/npc_sysenv.py +17 -2
  11. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/serve.py +162 -14
  12. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/sql/npcsql.py +96 -59
  13. {npcpy-1.2.36 → npcpy-1.3.1/npcpy.egg-info}/PKG-INFO +175 -4
  14. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy.egg-info/SOURCES.txt +3 -0
  15. {npcpy-1.2.36 → npcpy-1.3.1}/setup.py +1 -1
  16. npcpy-1.3.1/tests/test_npc_array.py +539 -0
  17. {npcpy-1.2.36 → npcpy-1.3.1}/tests/test_npc_compiler.py +28 -19
  18. npcpy-1.2.36/npcpy/__init__.py +0 -6
  19. {npcpy-1.2.36 → npcpy-1.3.1}/LICENSE +0 -0
  20. {npcpy-1.2.36 → npcpy-1.3.1}/MANIFEST.in +0 -0
  21. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/data/__init__.py +0 -0
  22. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/data/audio.py +0 -0
  23. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/data/data_models.py +0 -0
  24. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/data/image.py +0 -0
  25. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/data/load.py +0 -0
  26. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/data/text.py +0 -0
  27. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/data/video.py +0 -0
  28. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/data/web.py +0 -0
  29. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/ft/__init__.py +0 -0
  30. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/ft/diff.py +0 -0
  31. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/ft/ge.py +0 -0
  32. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/ft/memory_trainer.py +0 -0
  33. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/ft/model_ensembler.py +0 -0
  34. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/ft/rl.py +0 -0
  35. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/ft/sft.py +0 -0
  36. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/ft/usft.py +0 -0
  37. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/gen/__init__.py +0 -0
  38. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/gen/audio_gen.py +0 -0
  39. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/gen/embeddings.py +0 -0
  40. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/gen/ocr.py +0 -0
  41. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/gen/video_gen.py +0 -0
  42. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/main.py +0 -0
  43. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/memory/__init__.py +0 -0
  44. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/memory/command_history.py +0 -0
  45. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/memory/kg_vis.py +0 -0
  46. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/memory/knowledge_graph.py +0 -0
  47. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/memory/memory_processor.py +0 -0
  48. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/memory/search.py +0 -0
  49. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/mix/__init__.py +0 -0
  50. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/mix/debate.py +0 -0
  51. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/npcs.py +0 -0
  52. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/sql/__init__.py +0 -0
  53. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/sql/ai_function_tools.py +0 -0
  54. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/sql/database_ai_adapters.py +0 -0
  55. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/sql/database_ai_functions.py +0 -0
  56. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/sql/model_runner.py +0 -0
  57. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/sql/sql_model_compiler.py +0 -0
  58. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/tools.py +0 -0
  59. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/work/__init__.py +0 -0
  60. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/work/desktop.py +0 -0
  61. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/work/plan.py +0 -0
  62. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy/work/trigger.py +0 -0
  63. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy.egg-info/dependency_links.txt +0 -0
  64. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy.egg-info/requires.txt +0 -0
  65. {npcpy-1.2.36 → npcpy-1.3.1}/npcpy.egg-info/top_level.txt +0 -0
  66. {npcpy-1.2.36 → npcpy-1.3.1}/setup.cfg +0 -0
  67. {npcpy-1.2.36 → npcpy-1.3.1}/tests/test_audio.py +0 -0
  68. {npcpy-1.2.36 → npcpy-1.3.1}/tests/test_command_history.py +0 -0
  69. {npcpy-1.2.36 → npcpy-1.3.1}/tests/test_image.py +0 -0
  70. {npcpy-1.2.36 → npcpy-1.3.1}/tests/test_llm_funcs.py +0 -0
  71. {npcpy-1.2.36 → npcpy-1.3.1}/tests/test_load.py +0 -0
  72. {npcpy-1.2.36 → npcpy-1.3.1}/tests/test_npcsql.py +0 -0
  73. {npcpy-1.2.36 → npcpy-1.3.1}/tests/test_response.py +0 -0
  74. {npcpy-1.2.36 → npcpy-1.3.1}/tests/test_serve.py +0 -0
  75. {npcpy-1.2.36 → npcpy-1.3.1}/tests/test_text.py +0 -0
  76. {npcpy-1.2.36 → npcpy-1.3.1}/tests/test_tools.py +0 -0
  77. {npcpy-1.2.36 → npcpy-1.3.1}/tests/test_web.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: npcpy
3
- Version: 1.2.36
3
+ Version: 1.3.1
4
4
  Summary: npcpy is the premier open-source library for integrating LLMs and Agents into python systems.
5
5
  Home-page: https://github.com/NPC-Worldwide/npcpy
6
6
  Author: Christopher Agostino
@@ -275,9 +275,8 @@ output = context['research_summary']
275
275
  "code": '''
276
276
  # Access outputs from previous steps.
277
277
  research_summary = context['initial_llm_research']
278
- # The output of a declarative jinx call (like 'file_reader') is stored under its step name.
279
- # The actual content we want is the 'output' of the *last step* within that sub-jinx.
280
- file_summary = context['read_and_process_source_file'].get('output', 'No file summary available.')
278
+ # The file_reader jinx returns its output directly; also keep a fallback of file_raw_content.
279
+ file_summary = context.get('read_and_process_source_file', '') or context.get('file_raw_content', 'No file summary available.')
281
280
 
282
281
  prompt = f"""Based on the following information:
283
282
  1. Comprehensive Research Summary:
@@ -607,6 +606,178 @@ else:
607
606
  The intention for this model ensembler system is to mimic human cognition: pattern-matched gut reactions (System 1 of Kahneman) for familiar queries, falling back to deliberate reasoning (System 2 of Kahneman) for novel problems. Genetic algorithms evolve both knowledge structures and model specializations over time.
608
607
 
609
608
 
609
+ ## NPCArray - NumPy for AI
610
+
611
+ `npcpy` provides `NPCArray`, a NumPy-like interface for working with populations of models (LLMs, sklearn, PyTorch) at scale. Think of it as vectorized operations over AI models.
612
+
613
+ ### Core Concepts
614
+ - Model arrays support vectorized operations
615
+ - Operations are lazy until `.collect()` is called (like Spark)
616
+ - Same interface works for single models (treated as length-1 arrays)
617
+ - Supports ensemble voting, consensus, evolution, and more
618
+
619
+ ### Basic Usage
620
+
621
+ ```python
622
+ from npcpy.npc_array import NPCArray
623
+
624
+ # Create array of LLMs
625
+ models = NPCArray.from_llms(
626
+ ['llama3.2', 'gemma3:1b'],
627
+ providers='ollama'
628
+ )
629
+
630
+ print(f"Model array shape: {models.shape}") # (2,)
631
+
632
+ # Inference across all models - returns shape (n_models, n_prompts)
633
+ result = models.infer("What is 2+2? Just the number.").collect()
634
+
635
+ print(f"Model 1: {result.data[0, 0]}")
636
+ print(f"Model 2: {result.data[1, 0]}")
637
+ ```
638
+
639
+ ### Lazy Chaining & Ensemble Operations
640
+
641
+ ```python
642
+ from npcpy.npc_array import NPCArray
643
+
644
+ models = NPCArray.from_llms(['llama3.2', 'gemma3:1b', 'mistral:7b'])
645
+
646
+ # Build lazy computation graph - nothing executed yet
647
+ result = (
648
+ models
649
+ .infer("Is Python compiled or interpreted? One word.")
650
+ .map(lambda r: r.strip().lower()) # Clean responses
651
+ .vote(axis=0) # Majority voting across models
652
+ )
653
+
654
+ # Show the computation plan
655
+ result.explain()
656
+
657
+ # Now execute
658
+ answer = result.collect()
659
+ print(f"Consensus: {answer.data[0]}")
660
+ ```
661
+
662
+ ### Parameter Sweeps with Meshgrid
663
+
664
+ ```python
665
+ from npcpy.npc_array import NPCArray
666
+
667
+ # Cartesian product over parameters
668
+ configs = NPCArray.meshgrid(
669
+ models=['llama3.2', 'gemma3:1b'],
670
+ temperatures=[0.0, 0.5, 1.0]
671
+ )
672
+
673
+ print(f"Config array shape: {configs.shape}") # (6,) = 2 models × 3 temps
674
+
675
+ # Run inference with each config
676
+ result = configs.infer("Complete: The quick brown fox").collect()
677
+ ```
678
+
679
+ ### Matrix Sampling with get_llm_response
680
+
681
+ The `get_llm_response` function supports `matrix` and `n_samples` parameters for exploration:
682
+
683
+ ```python
684
+ from npcpy.llm_funcs import get_llm_response
685
+
686
+ # Matrix parameter - cartesian product over specified params
687
+ result = get_llm_response(
688
+ "Write a creative opening line.",
689
+ matrix={
690
+ 'model': ['llama3.2', 'gemma3:1b'],
691
+ 'temperature': [0.5, 1.0]
692
+ }
693
+ )
694
+ print(f"Number of runs: {len(result['runs'])}") # 4 = 2×2
695
+
696
+ # n_samples - multiple samples from same config
697
+ result = get_llm_response(
698
+ "Pick a random number 1-100.",
699
+ model='llama3.2',
700
+ n_samples=5
701
+ )
702
+ print(f"Samples: {[r['response'] for r in result['runs']]}")
703
+
704
+ # Combine both for full exploration
705
+ result = get_llm_response(
706
+ "Flip a coin: heads or tails?",
707
+ matrix={'model': ['llama3.2', 'gemma3:1b']},
708
+ n_samples=3 # 2 models × 3 samples = 6 runs
709
+ )
710
+ ```
711
+
712
+ ### sklearn Integration
713
+
714
+ ```python
715
+ from npcpy.npc_array import NPCArray
716
+ from sklearn.ensemble import RandomForestClassifier
717
+ from sklearn.linear_model import LogisticRegression
718
+ import numpy as np
719
+
720
+ # Create sample data
721
+ X_train = np.random.randn(100, 4)
722
+ y_train = (X_train[:, 0] > 0).astype(int)
723
+
724
+ # Pre-fit models
725
+ rf = RandomForestClassifier(n_estimators=10).fit(X_train, y_train)
726
+ lr = LogisticRegression().fit(X_train, y_train)
727
+
728
+ # Create array from fitted models
729
+ models = NPCArray.from_sklearn([rf, lr])
730
+
731
+ # Vectorized prediction
732
+ X_test = np.random.randn(20, 4)
733
+ predictions = models.predict(X_test).collect()
734
+
735
+ print(f"RF predictions: {predictions.data[0]}")
736
+ print(f"LR predictions: {predictions.data[1]}")
737
+ ```
738
+
739
+ ### ML Functions with Grid Search
740
+
741
+ ```python
742
+ from npcpy.ml_funcs import fit_model, score_model, ensemble_predict
743
+
744
+ # Grid search via matrix parameter
745
+ result = fit_model(
746
+ X_train, y_train,
747
+ model='RandomForestClassifier',
748
+ matrix={
749
+ 'n_estimators': [10, 50, 100],
750
+ 'max_depth': [3, 5, 10]
751
+ }
752
+ )
753
+
754
+ print(f"Fitted {len(result['models'])} model configurations")
755
+
756
+ # Ensemble voting with multiple models
757
+ predictions = ensemble_predict(X_test, result['models'], method='vote')
758
+ ```
759
+
760
+ ### Quick Utilities
761
+
762
+ ```python
763
+ from npcpy.npc_array import infer_matrix, ensemble_vote
764
+
765
+ # Quick matrix inference
766
+ result = infer_matrix(
767
+ prompts=["Hello", "Goodbye"],
768
+ models=['llama3.2', 'gemma3:1b']
769
+ )
770
+
771
+ # Quick ensemble vote
772
+ answer = ensemble_vote(
773
+ "What is the capital of France? One word.",
774
+ models=['llama3.2', 'gemma3:1b']
775
+ )
776
+ print(f"Voted answer: {answer}")
777
+ ```
778
+
779
+ See `examples/npc_array_examples.py` for more comprehensive examples.
780
+
610
781
 
611
782
  ## Serving an NPC Team
612
783
 
@@ -179,9 +179,8 @@ output = context['research_summary']
179
179
  "code": '''
180
180
  # Access outputs from previous steps.
181
181
  research_summary = context['initial_llm_research']
182
- # The output of a declarative jinx call (like 'file_reader') is stored under its step name.
183
- # The actual content we want is the 'output' of the *last step* within that sub-jinx.
184
- file_summary = context['read_and_process_source_file'].get('output', 'No file summary available.')
182
+ # The file_reader jinx returns its output directly; also keep a fallback of file_raw_content.
183
+ file_summary = context.get('read_and_process_source_file', '') or context.get('file_raw_content', 'No file summary available.')
185
184
 
186
185
  prompt = f"""Based on the following information:
187
186
  1. Comprehensive Research Summary:
@@ -511,6 +510,178 @@ else:
511
510
  The intention for this model ensembler system is to mimic human cognition: pattern-matched gut reactions (System 1 of Kahneman) for familiar queries, falling back to deliberate reasoning (System 2 of Kahneman) for novel problems. Genetic algorithms evolve both knowledge structures and model specializations over time.
512
511
 
513
512
 
513
+ ## NPCArray - NumPy for AI
514
+
515
+ `npcpy` provides `NPCArray`, a NumPy-like interface for working with populations of models (LLMs, sklearn, PyTorch) at scale. Think of it as vectorized operations over AI models.
516
+
517
+ ### Core Concepts
518
+ - Model arrays support vectorized operations
519
+ - Operations are lazy until `.collect()` is called (like Spark)
520
+ - Same interface works for single models (treated as length-1 arrays)
521
+ - Supports ensemble voting, consensus, evolution, and more
522
+
523
+ ### Basic Usage
524
+
525
+ ```python
526
+ from npcpy.npc_array import NPCArray
527
+
528
+ # Create array of LLMs
529
+ models = NPCArray.from_llms(
530
+ ['llama3.2', 'gemma3:1b'],
531
+ providers='ollama'
532
+ )
533
+
534
+ print(f"Model array shape: {models.shape}") # (2,)
535
+
536
+ # Inference across all models - returns shape (n_models, n_prompts)
537
+ result = models.infer("What is 2+2? Just the number.").collect()
538
+
539
+ print(f"Model 1: {result.data[0, 0]}")
540
+ print(f"Model 2: {result.data[1, 0]}")
541
+ ```
542
+
543
+ ### Lazy Chaining & Ensemble Operations
544
+
545
+ ```python
546
+ from npcpy.npc_array import NPCArray
547
+
548
+ models = NPCArray.from_llms(['llama3.2', 'gemma3:1b', 'mistral:7b'])
549
+
550
+ # Build lazy computation graph - nothing executed yet
551
+ result = (
552
+ models
553
+ .infer("Is Python compiled or interpreted? One word.")
554
+ .map(lambda r: r.strip().lower()) # Clean responses
555
+ .vote(axis=0) # Majority voting across models
556
+ )
557
+
558
+ # Show the computation plan
559
+ result.explain()
560
+
561
+ # Now execute
562
+ answer = result.collect()
563
+ print(f"Consensus: {answer.data[0]}")
564
+ ```
565
+
566
+ ### Parameter Sweeps with Meshgrid
567
+
568
+ ```python
569
+ from npcpy.npc_array import NPCArray
570
+
571
+ # Cartesian product over parameters
572
+ configs = NPCArray.meshgrid(
573
+ models=['llama3.2', 'gemma3:1b'],
574
+ temperatures=[0.0, 0.5, 1.0]
575
+ )
576
+
577
+ print(f"Config array shape: {configs.shape}") # (6,) = 2 models × 3 temps
578
+
579
+ # Run inference with each config
580
+ result = configs.infer("Complete: The quick brown fox").collect()
581
+ ```
582
+
583
+ ### Matrix Sampling with get_llm_response
584
+
585
+ The `get_llm_response` function supports `matrix` and `n_samples` parameters for exploration:
586
+
587
+ ```python
588
+ from npcpy.llm_funcs import get_llm_response
589
+
590
+ # Matrix parameter - cartesian product over specified params
591
+ result = get_llm_response(
592
+ "Write a creative opening line.",
593
+ matrix={
594
+ 'model': ['llama3.2', 'gemma3:1b'],
595
+ 'temperature': [0.5, 1.0]
596
+ }
597
+ )
598
+ print(f"Number of runs: {len(result['runs'])}") # 4 = 2×2
599
+
600
+ # n_samples - multiple samples from same config
601
+ result = get_llm_response(
602
+ "Pick a random number 1-100.",
603
+ model='llama3.2',
604
+ n_samples=5
605
+ )
606
+ print(f"Samples: {[r['response'] for r in result['runs']]}")
607
+
608
+ # Combine both for full exploration
609
+ result = get_llm_response(
610
+ "Flip a coin: heads or tails?",
611
+ matrix={'model': ['llama3.2', 'gemma3:1b']},
612
+ n_samples=3 # 2 models × 3 samples = 6 runs
613
+ )
614
+ ```
615
+
616
+ ### sklearn Integration
617
+
618
+ ```python
619
+ from npcpy.npc_array import NPCArray
620
+ from sklearn.ensemble import RandomForestClassifier
621
+ from sklearn.linear_model import LogisticRegression
622
+ import numpy as np
623
+
624
+ # Create sample data
625
+ X_train = np.random.randn(100, 4)
626
+ y_train = (X_train[:, 0] > 0).astype(int)
627
+
628
+ # Pre-fit models
629
+ rf = RandomForestClassifier(n_estimators=10).fit(X_train, y_train)
630
+ lr = LogisticRegression().fit(X_train, y_train)
631
+
632
+ # Create array from fitted models
633
+ models = NPCArray.from_sklearn([rf, lr])
634
+
635
+ # Vectorized prediction
636
+ X_test = np.random.randn(20, 4)
637
+ predictions = models.predict(X_test).collect()
638
+
639
+ print(f"RF predictions: {predictions.data[0]}")
640
+ print(f"LR predictions: {predictions.data[1]}")
641
+ ```
642
+
643
+ ### ML Functions with Grid Search
644
+
645
+ ```python
646
+ from npcpy.ml_funcs import fit_model, score_model, ensemble_predict
647
+
648
+ # Grid search via matrix parameter
649
+ result = fit_model(
650
+ X_train, y_train,
651
+ model='RandomForestClassifier',
652
+ matrix={
653
+ 'n_estimators': [10, 50, 100],
654
+ 'max_depth': [3, 5, 10]
655
+ }
656
+ )
657
+
658
+ print(f"Fitted {len(result['models'])} model configurations")
659
+
660
+ # Ensemble voting with multiple models
661
+ predictions = ensemble_predict(X_test, result['models'], method='vote')
662
+ ```
663
+
664
+ ### Quick Utilities
665
+
666
+ ```python
667
+ from npcpy.npc_array import infer_matrix, ensemble_vote
668
+
669
+ # Quick matrix inference
670
+ result = infer_matrix(
671
+ prompts=["Hello", "Goodbye"],
672
+ models=['llama3.2', 'gemma3:1b']
673
+ )
674
+
675
+ # Quick ensemble vote
676
+ answer = ensemble_vote(
677
+ "What is the capital of France? One word.",
678
+ models=['llama3.2', 'gemma3:1b']
679
+ )
680
+ print(f"Voted answer: {answer}")
681
+ ```
682
+
683
+ See `examples/npc_array_examples.py` for more comprehensive examples.
684
+
514
685
 
515
686
  ## Serving an NPC Team
516
687
 
@@ -0,0 +1,14 @@
1
+ from . import npc_compiler
2
+ from . import npc_sysenv
3
+ from . import llm_funcs
4
+ from . import ml_funcs
5
+ from . import npc_array
6
+ from . import sql
7
+ from . import work
8
+ from . import gen
9
+
10
+ # Expose key classes at package level
11
+ from .npc_array import NPCArray, ResponseTensor, LazyResult, infer_matrix, ensemble_vote
12
+ from .npc_compiler import NPC, Team, Jinx
13
+ from .llm_funcs import get_llm_response, check_llm_command, execute_llm_command
14
+ from .ml_funcs import fit_model, predict_model, score_model, ensemble_predict
@@ -363,7 +363,8 @@ def generate_image(
363
363
  api_url: Optional[str] = None,
364
364
  attachments: Union[List[Union[str, bytes, Image.Image]], None] = None,
365
365
  save_path: Optional[str] = None,
366
- custom_model_path: Optional[str] = None, # <--- NEW: Accept custom_model_path
366
+ custom_model_path: Optional[str] = None, # <--- NEW: Accept custom_model_path,
367
+
367
368
  ):
368
369
  """
369
370
  Unified function to generate or edit images using various providers.
@@ -429,7 +430,9 @@ def generate_image(
429
430
  attachments=attachments,
430
431
  height=height,
431
432
  width=width,
432
- n_images=n_images
433
+ n_images=n_images,
434
+ api_key=api_key
435
+
433
436
  )
434
437
  all_generated_pil_images.extend(images)
435
438