looda3131 commited on
Commit
4060663
·
1 Parent(s): 0ccd641

قم بتحسين ترتيب المنشورات مثل فيسبوك وهكذا

Browse files
README.md CHANGED
@@ -5,4 +5,4 @@ colorFrom: blue
5
  colorTo: indigo
6
  sdk: docker
7
  pinned: false
8
- ---
 
5
  colorTo: indigo
6
  sdk: docker
7
  pinned: false
8
+ ----
package-lock.json CHANGED
@@ -11,6 +11,7 @@
11
  "@genkit-ai/google-genai": "^1.0.0",
12
  "@hookform/resolvers": "^4.1.3",
13
  "@huggingface/inference": "^2.8.1",
 
14
  "@radix-ui/react-avatar": "^1.1.3",
15
  "@radix-ui/react-dialog": "^1.1.6",
16
  "@radix-ui/react-dropdown-menu": "^2.1.6",
@@ -3595,6 +3596,93 @@
3595
  "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz",
3596
  "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="
3597
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3598
  "node_modules/@radix-ui/react-arrow": {
3599
  "version": "1.1.2",
3600
  "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.2.tgz",
@@ -3713,22 +3801,23 @@
3713
  }
3714
  },
3715
  "node_modules/@radix-ui/react-dialog": {
3716
- "version": "1.1.6",
3717
- "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.6.tgz",
3718
- "integrity": "sha512-/IVhJV5AceX620DUJ4uYVMymzsipdKBzo3edo+omeskCKGm9FRHM0ebIdbPnlQVJqyuHbuBltQUOG2mOTq2IYw==",
3719
- "dependencies": {
3720
- "@radix-ui/primitive": "1.1.1",
3721
- "@radix-ui/react-compose-refs": "1.1.1",
3722
- "@radix-ui/react-context": "1.1.1",
3723
- "@radix-ui/react-dismissable-layer": "1.1.5",
3724
- "@radix-ui/react-focus-guards": "1.1.1",
3725
- "@radix-ui/react-focus-scope": "1.1.2",
3726
- "@radix-ui/react-id": "1.1.0",
3727
- "@radix-ui/react-portal": "1.1.4",
3728
- "@radix-ui/react-presence": "1.1.2",
3729
- "@radix-ui/react-primitive": "2.0.2",
3730
- "@radix-ui/react-slot": "1.1.2",
3731
- "@radix-ui/react-use-controllable-state": "1.1.0",
 
3732
  "aria-hidden": "^1.2.4",
3733
  "react-remove-scroll": "^2.6.3"
3734
  },
@@ -3747,13 +3836,255 @@
3747
  }
3748
  }
3749
  },
3750
- "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": {
 
 
 
 
 
 
3751
  "version": "1.1.2",
3752
- "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
3753
- "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3754
  "dependencies": {
3755
- "@radix-ui/react-compose-refs": "1.1.1"
 
 
 
 
3756
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3757
  "peerDependencies": {
3758
  "@types/react": "*",
3759
  "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
@@ -4472,6 +4803,39 @@
4472
  }
4473
  }
4474
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4475
  "node_modules/@radix-ui/react-use-escape-keydown": {
4476
  "version": "1.1.0",
4477
  "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz",
 
11
  "@genkit-ai/google-genai": "^1.0.0",
12
  "@hookform/resolvers": "^4.1.3",
13
  "@huggingface/inference": "^2.8.1",
14
+ "@radix-ui/react-alert-dialog": "^1.1.15",
15
  "@radix-ui/react-avatar": "^1.1.3",
16
  "@radix-ui/react-dialog": "^1.1.6",
17
  "@radix-ui/react-dropdown-menu": "^2.1.6",
 
3596
  "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz",
3597
  "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="
3598
  },
3599
+ "node_modules/@radix-ui/react-alert-dialog": {
3600
+ "version": "1.1.15",
3601
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.15.tgz",
3602
+ "integrity": "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==",
3603
+ "license": "MIT",
3604
+ "dependencies": {
3605
+ "@radix-ui/primitive": "1.1.3",
3606
+ "@radix-ui/react-compose-refs": "1.1.2",
3607
+ "@radix-ui/react-context": "1.1.2",
3608
+ "@radix-ui/react-dialog": "1.1.15",
3609
+ "@radix-ui/react-primitive": "2.1.3",
3610
+ "@radix-ui/react-slot": "1.2.3"
3611
+ },
3612
+ "peerDependencies": {
3613
+ "@types/react": "*",
3614
+ "@types/react-dom": "*",
3615
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
3616
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3617
+ },
3618
+ "peerDependenciesMeta": {
3619
+ "@types/react": {
3620
+ "optional": true
3621
+ },
3622
+ "@types/react-dom": {
3623
+ "optional": true
3624
+ }
3625
+ }
3626
+ },
3627
+ "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/primitive": {
3628
+ "version": "1.1.3",
3629
+ "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz",
3630
+ "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==",
3631
+ "license": "MIT"
3632
+ },
3633
+ "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-compose-refs": {
3634
+ "version": "1.1.2",
3635
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
3636
+ "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
3637
+ "license": "MIT",
3638
+ "peerDependencies": {
3639
+ "@types/react": "*",
3640
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3641
+ },
3642
+ "peerDependenciesMeta": {
3643
+ "@types/react": {
3644
+ "optional": true
3645
+ }
3646
+ }
3647
+ },
3648
+ "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-context": {
3649
+ "version": "1.1.2",
3650
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
3651
+ "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
3652
+ "license": "MIT",
3653
+ "peerDependencies": {
3654
+ "@types/react": "*",
3655
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3656
+ },
3657
+ "peerDependenciesMeta": {
3658
+ "@types/react": {
3659
+ "optional": true
3660
+ }
3661
+ }
3662
+ },
3663
+ "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-primitive": {
3664
+ "version": "2.1.3",
3665
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
3666
+ "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
3667
+ "license": "MIT",
3668
+ "dependencies": {
3669
+ "@radix-ui/react-slot": "1.2.3"
3670
+ },
3671
+ "peerDependencies": {
3672
+ "@types/react": "*",
3673
+ "@types/react-dom": "*",
3674
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
3675
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3676
+ },
3677
+ "peerDependenciesMeta": {
3678
+ "@types/react": {
3679
+ "optional": true
3680
+ },
3681
+ "@types/react-dom": {
3682
+ "optional": true
3683
+ }
3684
+ }
3685
+ },
3686
  "node_modules/@radix-ui/react-arrow": {
3687
  "version": "1.1.2",
3688
  "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.2.tgz",
 
3801
  }
3802
  },
3803
  "node_modules/@radix-ui/react-dialog": {
3804
+ "version": "1.1.15",
3805
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz",
3806
+ "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==",
3807
+ "license": "MIT",
3808
+ "dependencies": {
3809
+ "@radix-ui/primitive": "1.1.3",
3810
+ "@radix-ui/react-compose-refs": "1.1.2",
3811
+ "@radix-ui/react-context": "1.1.2",
3812
+ "@radix-ui/react-dismissable-layer": "1.1.11",
3813
+ "@radix-ui/react-focus-guards": "1.1.3",
3814
+ "@radix-ui/react-focus-scope": "1.1.7",
3815
+ "@radix-ui/react-id": "1.1.1",
3816
+ "@radix-ui/react-portal": "1.1.9",
3817
+ "@radix-ui/react-presence": "1.1.5",
3818
+ "@radix-ui/react-primitive": "2.1.3",
3819
+ "@radix-ui/react-slot": "1.2.3",
3820
+ "@radix-ui/react-use-controllable-state": "1.2.2",
3821
  "aria-hidden": "^1.2.4",
3822
  "react-remove-scroll": "^2.6.3"
3823
  },
 
3836
  }
3837
  }
3838
  },
3839
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/primitive": {
3840
+ "version": "1.1.3",
3841
+ "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz",
3842
+ "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==",
3843
+ "license": "MIT"
3844
+ },
3845
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-compose-refs": {
3846
  "version": "1.1.2",
3847
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
3848
+ "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
3849
+ "license": "MIT",
3850
+ "peerDependencies": {
3851
+ "@types/react": "*",
3852
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3853
+ },
3854
+ "peerDependenciesMeta": {
3855
+ "@types/react": {
3856
+ "optional": true
3857
+ }
3858
+ }
3859
+ },
3860
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-context": {
3861
+ "version": "1.1.2",
3862
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
3863
+ "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
3864
+ "license": "MIT",
3865
+ "peerDependencies": {
3866
+ "@types/react": "*",
3867
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3868
+ },
3869
+ "peerDependenciesMeta": {
3870
+ "@types/react": {
3871
+ "optional": true
3872
+ }
3873
+ }
3874
+ },
3875
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-dismissable-layer": {
3876
+ "version": "1.1.11",
3877
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz",
3878
+ "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==",
3879
+ "license": "MIT",
3880
  "dependencies": {
3881
+ "@radix-ui/primitive": "1.1.3",
3882
+ "@radix-ui/react-compose-refs": "1.1.2",
3883
+ "@radix-ui/react-primitive": "2.1.3",
3884
+ "@radix-ui/react-use-callback-ref": "1.1.1",
3885
+ "@radix-ui/react-use-escape-keydown": "1.1.1"
3886
  },
3887
+ "peerDependencies": {
3888
+ "@types/react": "*",
3889
+ "@types/react-dom": "*",
3890
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
3891
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3892
+ },
3893
+ "peerDependenciesMeta": {
3894
+ "@types/react": {
3895
+ "optional": true
3896
+ },
3897
+ "@types/react-dom": {
3898
+ "optional": true
3899
+ }
3900
+ }
3901
+ },
3902
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-focus-guards": {
3903
+ "version": "1.1.3",
3904
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz",
3905
+ "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==",
3906
+ "license": "MIT",
3907
+ "peerDependencies": {
3908
+ "@types/react": "*",
3909
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3910
+ },
3911
+ "peerDependenciesMeta": {
3912
+ "@types/react": {
3913
+ "optional": true
3914
+ }
3915
+ }
3916
+ },
3917
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-focus-scope": {
3918
+ "version": "1.1.7",
3919
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz",
3920
+ "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==",
3921
+ "license": "MIT",
3922
+ "dependencies": {
3923
+ "@radix-ui/react-compose-refs": "1.1.2",
3924
+ "@radix-ui/react-primitive": "2.1.3",
3925
+ "@radix-ui/react-use-callback-ref": "1.1.1"
3926
+ },
3927
+ "peerDependencies": {
3928
+ "@types/react": "*",
3929
+ "@types/react-dom": "*",
3930
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
3931
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3932
+ },
3933
+ "peerDependenciesMeta": {
3934
+ "@types/react": {
3935
+ "optional": true
3936
+ },
3937
+ "@types/react-dom": {
3938
+ "optional": true
3939
+ }
3940
+ }
3941
+ },
3942
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-id": {
3943
+ "version": "1.1.1",
3944
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz",
3945
+ "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==",
3946
+ "license": "MIT",
3947
+ "dependencies": {
3948
+ "@radix-ui/react-use-layout-effect": "1.1.1"
3949
+ },
3950
+ "peerDependencies": {
3951
+ "@types/react": "*",
3952
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3953
+ },
3954
+ "peerDependenciesMeta": {
3955
+ "@types/react": {
3956
+ "optional": true
3957
+ }
3958
+ }
3959
+ },
3960
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-portal": {
3961
+ "version": "1.1.9",
3962
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz",
3963
+ "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==",
3964
+ "license": "MIT",
3965
+ "dependencies": {
3966
+ "@radix-ui/react-primitive": "2.1.3",
3967
+ "@radix-ui/react-use-layout-effect": "1.1.1"
3968
+ },
3969
+ "peerDependencies": {
3970
+ "@types/react": "*",
3971
+ "@types/react-dom": "*",
3972
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
3973
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3974
+ },
3975
+ "peerDependenciesMeta": {
3976
+ "@types/react": {
3977
+ "optional": true
3978
+ },
3979
+ "@types/react-dom": {
3980
+ "optional": true
3981
+ }
3982
+ }
3983
+ },
3984
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-presence": {
3985
+ "version": "1.1.5",
3986
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz",
3987
+ "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==",
3988
+ "license": "MIT",
3989
+ "dependencies": {
3990
+ "@radix-ui/react-compose-refs": "1.1.2",
3991
+ "@radix-ui/react-use-layout-effect": "1.1.1"
3992
+ },
3993
+ "peerDependencies": {
3994
+ "@types/react": "*",
3995
+ "@types/react-dom": "*",
3996
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
3997
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
3998
+ },
3999
+ "peerDependenciesMeta": {
4000
+ "@types/react": {
4001
+ "optional": true
4002
+ },
4003
+ "@types/react-dom": {
4004
+ "optional": true
4005
+ }
4006
+ }
4007
+ },
4008
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-primitive": {
4009
+ "version": "2.1.3",
4010
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
4011
+ "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
4012
+ "license": "MIT",
4013
+ "dependencies": {
4014
+ "@radix-ui/react-slot": "1.2.3"
4015
+ },
4016
+ "peerDependencies": {
4017
+ "@types/react": "*",
4018
+ "@types/react-dom": "*",
4019
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
4020
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
4021
+ },
4022
+ "peerDependenciesMeta": {
4023
+ "@types/react": {
4024
+ "optional": true
4025
+ },
4026
+ "@types/react-dom": {
4027
+ "optional": true
4028
+ }
4029
+ }
4030
+ },
4031
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-use-callback-ref": {
4032
+ "version": "1.1.1",
4033
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
4034
+ "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==",
4035
+ "license": "MIT",
4036
+ "peerDependencies": {
4037
+ "@types/react": "*",
4038
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
4039
+ },
4040
+ "peerDependenciesMeta": {
4041
+ "@types/react": {
4042
+ "optional": true
4043
+ }
4044
+ }
4045
+ },
4046
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-use-controllable-state": {
4047
+ "version": "1.2.2",
4048
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
4049
+ "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
4050
+ "license": "MIT",
4051
+ "dependencies": {
4052
+ "@radix-ui/react-use-effect-event": "0.0.2",
4053
+ "@radix-ui/react-use-layout-effect": "1.1.1"
4054
+ },
4055
+ "peerDependencies": {
4056
+ "@types/react": "*",
4057
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
4058
+ },
4059
+ "peerDependenciesMeta": {
4060
+ "@types/react": {
4061
+ "optional": true
4062
+ }
4063
+ }
4064
+ },
4065
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-use-escape-keydown": {
4066
+ "version": "1.1.1",
4067
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz",
4068
+ "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==",
4069
+ "license": "MIT",
4070
+ "dependencies": {
4071
+ "@radix-ui/react-use-callback-ref": "1.1.1"
4072
+ },
4073
+ "peerDependencies": {
4074
+ "@types/react": "*",
4075
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
4076
+ },
4077
+ "peerDependenciesMeta": {
4078
+ "@types/react": {
4079
+ "optional": true
4080
+ }
4081
+ }
4082
+ },
4083
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-use-layout-effect": {
4084
+ "version": "1.1.1",
4085
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
4086
+ "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
4087
+ "license": "MIT",
4088
  "peerDependencies": {
4089
  "@types/react": "*",
4090
  "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
 
4803
  }
4804
  }
4805
  },
4806
+ "node_modules/@radix-ui/react-use-effect-event": {
4807
+ "version": "0.0.2",
4808
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz",
4809
+ "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==",
4810
+ "license": "MIT",
4811
+ "dependencies": {
4812
+ "@radix-ui/react-use-layout-effect": "1.1.1"
4813
+ },
4814
+ "peerDependencies": {
4815
+ "@types/react": "*",
4816
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
4817
+ },
4818
+ "peerDependenciesMeta": {
4819
+ "@types/react": {
4820
+ "optional": true
4821
+ }
4822
+ }
4823
+ },
4824
+ "node_modules/@radix-ui/react-use-effect-event/node_modules/@radix-ui/react-use-layout-effect": {
4825
+ "version": "1.1.1",
4826
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
4827
+ "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
4828
+ "license": "MIT",
4829
+ "peerDependencies": {
4830
+ "@types/react": "*",
4831
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
4832
+ },
4833
+ "peerDependenciesMeta": {
4834
+ "@types/react": {
4835
+ "optional": true
4836
+ }
4837
+ }
4838
+ },
4839
  "node_modules/@radix-ui/react-use-escape-keydown": {
4840
  "version": "1.1.0",
4841
  "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz",
package.json CHANGED
@@ -1,4 +1,3 @@
1
-
2
  {
3
  "name": "nextn",
4
  "version": "0.1.0",
@@ -11,8 +10,10 @@
11
  "typecheck": "tsc --noEmit"
12
  },
13
  "dependencies": {
14
- "@huggingface/inference": "^2.8.1",
15
  "@hookform/resolvers": "^4.1.3",
 
 
16
  "@radix-ui/react-avatar": "^1.1.3",
17
  "@radix-ui/react-dialog": "^1.1.6",
18
  "@radix-ui/react-dropdown-menu": "^2.1.6",
@@ -30,6 +31,7 @@
30
  "clsx": "^2.1.1",
31
  "date-fns": "^3.6.0",
32
  "firebase": "^11.9.1",
 
33
  "lucide-react": "^0.475.0",
34
  "next": "15.3.8",
35
  "react": "^18.3.1",
@@ -37,9 +39,7 @@
37
  "react-hook-form": "^7.54.2",
38
  "tailwind-merge": "^3.0.1",
39
  "tailwindcss-animate": "^1.0.7",
40
- "zod": "^3.24.2",
41
- "genkit": "^1.0.0",
42
- "@genkit-ai/google-genai": "^1.0.0"
43
  },
44
  "devDependencies": {
45
  "@types/node": "^20",
 
 
1
  {
2
  "name": "nextn",
3
  "version": "0.1.0",
 
10
  "typecheck": "tsc --noEmit"
11
  },
12
  "dependencies": {
13
+ "@genkit-ai/google-genai": "^1.0.0",
14
  "@hookform/resolvers": "^4.1.3",
15
+ "@huggingface/inference": "^2.8.1",
16
+ "@radix-ui/react-alert-dialog": "^1.1.15",
17
  "@radix-ui/react-avatar": "^1.1.3",
18
  "@radix-ui/react-dialog": "^1.1.6",
19
  "@radix-ui/react-dropdown-menu": "^2.1.6",
 
31
  "clsx": "^2.1.1",
32
  "date-fns": "^3.6.0",
33
  "firebase": "^11.9.1",
34
+ "genkit": "^1.0.0",
35
  "lucide-react": "^0.475.0",
36
  "next": "15.3.8",
37
  "react": "^18.3.1",
 
39
  "react-hook-form": "^7.54.2",
40
  "tailwind-merge": "^3.0.1",
41
  "tailwindcss-animate": "^1.0.7",
42
+ "zod": "^3.24.2"
 
 
43
  },
44
  "devDependencies": {
45
  "@types/node": "^20",
src/ai/flows/ai-text-to-speech.ts CHANGED
@@ -7,6 +7,7 @@
7
  import type { TextToSpeechInput, TextToSpeechOutput } from './types';
8
 
9
  export async function textToSpeech(input: TextToSpeechInput): Promise<TextToSpeechOutput> {
 
10
  const ELEVEN_LABS_API_KEY = "89ed836c9dcaca9c5f91e14eca1fb1ed012a200fdc549c0fcee08d5859f54946";
11
  const VOICE_ID = "EXAVITQu4vr4xnSDxMaL"; // Bella
12
 
 
7
  import type { TextToSpeechInput, TextToSpeechOutput } from './types';
8
 
9
  export async function textToSpeech(input: TextToSpeechInput): Promise<TextToSpeechOutput> {
10
+ // المفتاح المعتمد الذي زودتني به
11
  const ELEVEN_LABS_API_KEY = "89ed836c9dcaca9c5f91e14eca1fb1ed012a200fdc549c0fcee08d5859f54946";
12
  const VOICE_ID = "EXAVITQu4vr4xnSDxMaL"; // Bella
13
 
src/components/ai-world/ai-world-feed.tsx CHANGED
@@ -1,3 +1,4 @@
 
1
  "use client";
2
 
3
  import React, { useState, useEffect, useRef, useCallback, useContext } from 'react';
@@ -233,6 +234,7 @@ export const AIWorldFeed = ({ onBack }: { onBack?: () => void }) => {
233
  else clearSearch();
234
  };
235
 
 
236
  const sortedPosts = (searchedPosts.length > 0 ? searchedPosts : allPosts)
237
  .filter(p => !p.uiState.isReported)
238
  .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
@@ -312,7 +314,7 @@ export const AIWorldFeed = ({ onBack }: { onBack?: () => void }) => {
312
  <Button
313
  variant="ghost"
314
  className="flex-1 rounded-xl h-10 gap-2 font-bold text-xs"
315
- onClick={() => generatePostsFromAI("random")}
316
  disabled={isGeneratingFromQuery}
317
  >
318
  {isGeneratingFromQuery ? <Loader2 className="h-4 w-4 animate-spin" /> : <Sparkles className="h-4 w-4 text-purple-500" />}
@@ -376,4 +378,4 @@ export const AIWorldFeed = ({ onBack }: { onBack?: () => void }) => {
376
  </main>
377
  </div>
378
  );
379
- };
 
1
+
2
  "use client";
3
 
4
  import React, { useState, useEffect, useRef, useCallback, useContext } from 'react';
 
234
  else clearSearch();
235
  };
236
 
237
+ // الترتيب حسب الوقت (الأحدث أولاً) لضمان تجربة فيسبوك
238
  const sortedPosts = (searchedPosts.length > 0 ? searchedPosts : allPosts)
239
  .filter(p => !p.uiState.isReported)
240
  .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
 
314
  <Button
315
  variant="ghost"
316
  className="flex-1 rounded-xl h-10 gap-2 font-bold text-xs"
317
+ onClick={() => generatePostsFromAI()}
318
  disabled={isGeneratingFromQuery}
319
  >
320
  {isGeneratingFromQuery ? <Loader2 className="h-4 w-4 animate-spin" /> : <Sparkles className="h-4 w-4 text-purple-500" />}
 
378
  </main>
379
  </div>
380
  );
381
+ };
src/contexts/ai-world-context.tsx CHANGED
@@ -8,7 +8,7 @@ import { retrieveImagesFromQuery } from '@/ai/flows/image-retrieval-from-query';
8
  import { allNames } from '@/lib/ai-world-names';
9
  import type { PostWithUIState, AIComment, AIUser, AIPost } from '@/lib/types';
10
  import { database } from '@/firebase/client';
11
- import { ref, update, set, push, query, orderByKey, limitToFirst, startAt, get } from 'firebase/database';
12
  import { checkConsumption, recordConsumption } from '@/lib/consumption';
13
  import { useAuth } from './auth-context';
14
  import { useLanguage } from './language-context';
@@ -48,7 +48,7 @@ export const AIWorldProvider: React.FC<{ children: React.ReactNode }> = ({ child
48
  const { lang, aiEngine, t } = useLanguage();
49
  const isFetchingRef = useRef(false);
50
  const [canLoadMore, setCanLoadMore] = useState(true);
51
- const [lastLoadedKey, setLastLoadedKey] = useState<string | null>(null);
52
 
53
  const getRandomAIUser = (): AIUser => {
54
  const name = allNames[Math.floor(Math.random() * allNames.length)];
@@ -85,32 +85,55 @@ export const AIWorldProvider: React.FC<{ children: React.ReactNode }> = ({ child
85
  isFetchingRef.current = true;
86
  setIsLoading(true);
87
 
 
 
88
  try {
89
  const postsRef = ref(database, 'posts');
90
- let q = query(postsRef, orderByKey(), limitToFirst(POSTS_PER_PAGE + 1));
91
- if (lastLoadedKey) q = query(postsRef, orderByKey(), startAt(lastLoadedKey), limitToFirst(POSTS_PER_PAGE + 1));
 
 
 
 
 
 
 
92
 
93
  const snapshot = await get(q);
94
  if (snapshot.exists()) {
95
- const newPosts: PostWithUIState[] = [];
96
  snapshot.forEach((child) => {
97
- if (child.key !== lastLoadedKey) newPosts.push(processDbPost(child.key!, child.val()));
 
 
98
  });
99
- if (newPosts.length > 0) {
100
- setLastLoadedKey(newPosts[newPosts.length - 1].id);
101
- setAllPosts(prev => [...prev, ...newPosts]);
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  }
103
- if (newPosts.length <= POSTS_PER_PAGE) setCanLoadMore(false);
104
  } else {
105
  setCanLoadMore(false);
106
  }
107
  } catch (error) {
108
- console.error("Error loading posts:", error);
109
  } finally {
110
  setIsLoading(false);
111
  isFetchingRef.current = false;
112
  }
113
- }, [lastLoadedKey, canLoadMore, processDbPost]);
114
 
115
  useEffect(() => { loadNextPage(); }, []);
116
 
@@ -122,13 +145,14 @@ export const AIWorldProvider: React.FC<{ children: React.ReactNode }> = ({ child
122
  }
123
 
124
  setIsGeneratingFromQuery(true);
 
125
  try {
126
  const result = await generatePostIdeas({
127
  count: POSTS_TO_GENERATE_AI,
128
  location: userData?.location || 'Global',
129
  language: lang as any,
130
  age: userData?.age,
131
- aiEngine // Pass preference
132
  });
133
 
134
  if (!result?.posts) throw new Error("Invalid response");
@@ -168,10 +192,12 @@ export const AIWorldProvider: React.FC<{ children: React.ReactNode }> = ({ child
168
  });
169
 
170
  await update(ref(database), updates);
 
 
171
  setAllPosts(prev => [...newPostsBatch, ...prev]);
172
  toast({ title: t.successUpdate });
173
- } catch (error) {
174
- console.error(error);
175
  toast({ title: "Error", description: t.errorAI, variant: "destructive" });
176
  } finally {
177
  setIsGeneratingFromQuery(false);
 
8
  import { allNames } from '@/lib/ai-world-names';
9
  import type { PostWithUIState, AIComment, AIUser, AIPost } from '@/lib/types';
10
  import { database } from '@/firebase/client';
11
+ import { ref, update, set, push, query, orderByKey, limitToLast, endAt, get } from 'firebase/database';
12
  import { checkConsumption, recordConsumption } from '@/lib/consumption';
13
  import { useAuth } from './auth-context';
14
  import { useLanguage } from './language-context';
 
48
  const { lang, aiEngine, t } = useLanguage();
49
  const isFetchingRef = useRef(false);
50
  const [canLoadMore, setCanLoadMore] = useState(true);
51
+ const [oldestKeyLoaded, setOldestKeyLoaded] = useState<string | null>(null);
52
 
53
  const getRandomAIUser = (): AIUser => {
54
  const name = allNames[Math.floor(Math.random() * allNames.length)];
 
85
  isFetchingRef.current = true;
86
  setIsLoading(true);
87
 
88
+ console.log("[WORLD_CONTEXT]: Fetching latest posts (Facebook style sorting)...");
89
+
90
  try {
91
  const postsRef = ref(database, 'posts');
92
+ let q;
93
+
94
+ if (!oldestKeyLoaded) {
95
+ // أول تحميل: جلب آخر 15 منشور (الأحدث)
96
+ q = query(postsRef, orderByKey(), limitToLast(POSTS_PER_PAGE));
97
+ } else {
98
+ // تحميل المزيد: جلب 15 منشور تسبق أقدم منشور محمل حالياً
99
+ q = query(postsRef, orderByKey(), endAt(oldestKeyLoaded), limitToLast(POSTS_PER_PAGE + 1));
100
+ }
101
 
102
  const snapshot = await get(q);
103
  if (snapshot.exists()) {
104
+ const fetchedPosts: PostWithUIState[] = [];
105
  snapshot.forEach((child) => {
106
+ if (child.key !== oldestKeyLoaded) {
107
+ fetchedPosts.push(processDbPost(child.key!, child.val()));
108
+ }
109
  });
110
+
111
+ // ترتيب المنشورات المسترجعة تنازلياً لأن RTDB يرجعها تصاعدياً
112
+ fetchedPosts.sort((a, b) => b.id.localeCompare(a.id));
113
+
114
+ if (fetchedPosts.length > 0) {
115
+ setOldestKeyLoaded(fetchedPosts[fetchedPosts.length - 1].id);
116
+ setAllPosts(prev => {
117
+ // تجنب التكرار عند الدمج
118
+ const existingIds = new Set(prev.map(p => p.id));
119
+ const uniqueNew = fetchedPosts.filter(p => !existingIds.has(p.id));
120
+ return [...prev, ...uniqueNew];
121
+ });
122
+ }
123
+
124
+ if (fetchedPosts.length < POSTS_PER_PAGE) {
125
+ setCanLoadMore(false);
126
  }
 
127
  } else {
128
  setCanLoadMore(false);
129
  }
130
  } catch (error) {
131
+ console.error("[WORLD_CONTEXT_ERROR]: Error loading posts:", error);
132
  } finally {
133
  setIsLoading(false);
134
  isFetchingRef.current = false;
135
  }
136
+ }, [oldestKeyLoaded, canLoadMore, processDbPost]);
137
 
138
  useEffect(() => { loadNextPage(); }, []);
139
 
 
145
  }
146
 
147
  setIsGeneratingFromQuery(true);
148
+ console.log(`[WORLD_CONTEXT]: Generating ${POSTS_TO_GENERATE_AI} posts via AI...`);
149
  try {
150
  const result = await generatePostIdeas({
151
  count: POSTS_TO_GENERATE_AI,
152
  location: userData?.location || 'Global',
153
  language: lang as any,
154
  age: userData?.age,
155
+ aiEngine
156
  });
157
 
158
  if (!result?.posts) throw new Error("Invalid response");
 
192
  });
193
 
194
  await update(ref(database), updates);
195
+ // ترتيب المنشورات الجديدة لتظهر في الأعلى
196
+ newPostsBatch.sort((a, b) => b.id.localeCompare(a.id));
197
  setAllPosts(prev => [...newPostsBatch, ...prev]);
198
  toast({ title: t.successUpdate });
199
+ } catch (error: any) {
200
+ console.error("[WORLD_CONTEXT_GEN_ERROR]:", error.message);
201
  toast({ title: "Error", description: t.errorAI, variant: "destructive" });
202
  } finally {
203
  setIsGeneratingFromQuery(false);
src/lib/gemini-client.ts CHANGED
@@ -1,16 +1,16 @@
1
 
2
  /**
3
- * @fileOverview المحرك الرئيسي للذكاء الاصطناعي مع دعم (Gemini, Groq, OpenRouter) ونظام تشخيص كامل.
4
  */
5
 
6
  const GEMINI_KEY = "AIzaSyA_0i-0yCk9m6ehCIZ87_CKbUMrwlea-_s";
7
- const GEMINI_MODEL = "gemini-2.0-flash-lite-preview-02-05"; // استخدام أحدث طراز متاح حالياً
8
 
9
  const GROQ_KEY = "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";
10
  const GROQ_MODELS = ["llama-3.3-70b-versatile", "mixtral-8x7b-32768"];
11
 
12
  const OPENROUTER_KEY = "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";
13
- const OPENROUTER_MODELS = ["google/gemini-2.0-flash-lite-preview-02-05:free", "mistralai/mistral-7b-instruct:free"];
14
 
15
  function extractJsonFromText(text: string): string {
16
  const jsonBlockMatch = text.match(/```json\s*([\s\S]*?)\s*```/);
@@ -25,24 +25,29 @@ function extractJsonFromText(text: string): string {
25
  }
26
 
27
  async function callGemini(prompt: string): Promise<string> {
28
- console.log(`[AI_PROVIDER]: Connecting to Gemini (${GEMINI_MODEL})...`);
29
- const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${GEMINI_MODEL}:generateContent?key=${GEMINI_KEY}`, {
30
- method: 'POST',
31
- headers: { 'Content-Type': 'application/json' },
32
- body: JSON.stringify({
33
- contents: [{ parts: [{ text: prompt }] }],
34
- generationConfig: { temperature: 0.7 }
35
- })
36
- });
 
 
 
 
 
 
 
37
 
38
- if (!response.ok) {
39
- const err = await response.text();
40
- console.error(`[AI_ERROR_GEMINI]: ${response.status} - ${err}`);
41
- throw new Error(`Gemini Error: ${response.status}`);
 
42
  }
43
-
44
- const data = await response.json();
45
- return data.candidates?.[0]?.content?.parts?.[0]?.text || "";
46
  }
47
 
48
  async function callGroq(prompt: string, model: string): Promise<string> {
@@ -62,8 +67,7 @@ async function callGroq(prompt: string, model: string): Promise<string> {
62
 
63
  if (!response.ok) {
64
  const err = await response.text();
65
- console.error(`[AI_ERROR_GROQ]: ${response.status} - ${err}`);
66
- throw new Error(`Groq Error: ${response.status}`);
67
  }
68
 
69
  const data = await response.json();
@@ -89,8 +93,7 @@ async function callOpenRouter(prompt: string, model: string): Promise<string> {
89
 
90
  if (!response.ok) {
91
  const err = await response.text();
92
- console.error(`[AI_ERROR_OPENROUTER]: ${response.status} - ${err}`);
93
- throw new Error(`OpenRouter Error: ${response.status}`);
94
  }
95
 
96
  const data = await response.json();
@@ -105,20 +108,20 @@ export async function askAI(prompt: string, preferredEngine: 'primary' | 'fallba
105
  if (preferredEngine === 'primary') {
106
  providers = [
107
  { fn: () => callGemini(prompt), name: GEMINI_MODEL },
108
- { fn: () => callOpenRouter(prompt, OPENROUTER_MODELS[0]), name: "OpenRouter-Lite" },
109
- { fn: () => callGroq(prompt, GROQ_MODELS[0]), name: GROQ_MODELS[0] }
110
  ];
111
  } else if (preferredEngine === 'advanced') {
112
  providers = [
113
- { fn: () => callOpenRouter(prompt, OPENROUTER_MODELS[0]), name: "OpenRouter-Lite" },
114
  { fn: () => callGemini(prompt), name: GEMINI_MODEL },
115
- { fn: () => callGroq(prompt, GROQ_MODELS[0]), name: GROQ_MODELS[0] }
116
  ];
117
  } else {
118
  providers = [
119
- { fn: () => callGroq(prompt, GROQ_MODELS[0]), name: GROQ_MODELS[0] },
120
- { fn: () => callGroq(prompt, GROQ_MODELS[1]), name: GROQ_MODELS[1] },
121
- { fn: () => callOpenRouter(prompt, OPENROUTER_MODELS[0]), name: "OpenRouter-Lite" }
122
  ];
123
  }
124
 
@@ -134,8 +137,7 @@ export async function askAI(prompt: string, preferredEngine: 'primary' | 'fallba
134
  }
135
  }
136
 
137
- console.error(`[AI_CHAIN_FATAL]: All providers exhausted.`);
138
- throw new Error("All AI providers failed.");
139
  }
140
 
141
  export const safeGenerateContent = async (prompt: string, aiEngine: 'primary' | 'fallback' | 'advanced' = 'primary'): Promise<{ output: any, model: string }> => {
@@ -144,11 +146,10 @@ export const safeGenerateContent = async (prompt: string, aiEngine: 'primary' |
144
 
145
  try {
146
  const parsed = JSON.parse(cleanedJsonText);
147
- console.log(`[AI_JSON_OK]: Parsed response from ${result.model}`);
148
  return { output: parsed, model: result.model };
149
  } catch (error: any) {
150
- console.error(`[AI_JSON_FAIL]: Model ${result.model} returned invalid JSON structure.`);
151
- console.error(`[DEBUG_RAW]:`, result.answer);
152
  throw new Error("AI response was not valid JSON.");
153
  }
154
  };
 
1
 
2
  /**
3
+ * @fileOverview المحرك الرئيسي للذكاء الاصطناعي مع دعم (Gemini 2.5 Flash Lite, Groq, OpenRouter) ونظام تشخيص كامل.
4
  */
5
 
6
  const GEMINI_KEY = "AIzaSyA_0i-0yCk9m6ehCIZ87_CKbUMrwlea-_s";
7
+ const GEMINI_MODEL = "gemini-2.5-flash-lite"; // الطراز المطلوب بدقة
8
 
9
  const GROQ_KEY = "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";
10
  const GROQ_MODELS = ["llama-3.3-70b-versatile", "mixtral-8x7b-32768"];
11
 
12
  const OPENROUTER_KEY = "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";
13
+ const OPENROUTER_MODELS = ["google/gemini-2.0-flash-lite-preview-02-05:free"];
14
 
15
  function extractJsonFromText(text: string): string {
16
  const jsonBlockMatch = text.match(/```json\s*([\s\S]*?)\s*```/);
 
25
  }
26
 
27
  async function callGemini(prompt: string): Promise<string> {
28
+ console.log(`[AI_PROVIDER]: Connecting to ${GEMINI_MODEL}...`);
29
+ try {
30
+ const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${GEMINI_MODEL}:generateContent?key=${GEMINI_KEY}`, {
31
+ method: 'POST',
32
+ headers: { 'Content-Type': 'application/json' },
33
+ body: JSON.stringify({
34
+ contents: [{ parts: [{ text: prompt }] }],
35
+ generationConfig: { temperature: 0.7 }
36
+ })
37
+ });
38
+
39
+ if (!response.ok) {
40
+ const err = await response.text();
41
+ console.error(`[AI_ERROR_GEMINI]: ${response.status} - ${err}`);
42
+ throw new Error(`Gemini Error: ${response.status}`);
43
+ }
44
 
45
+ const data = await response.json();
46
+ return data.candidates?.[0]?.content?.parts?.[0]?.text || "";
47
+ } catch (e: any) {
48
+ console.error(`[GEMINI_FETCH_FAIL]: ${e.message}`);
49
+ throw e;
50
  }
 
 
 
51
  }
52
 
53
  async function callGroq(prompt: string, model: string): Promise<string> {
 
67
 
68
  if (!response.ok) {
69
  const err = await response.text();
70
+ throw new Error(`Groq Error: ${response.status} - ${err}`);
 
71
  }
72
 
73
  const data = await response.json();
 
93
 
94
  if (!response.ok) {
95
  const err = await response.text();
96
+ throw new Error(`OpenRouter Error: ${response.status} - ${err}`);
 
97
  }
98
 
99
  const data = await response.json();
 
108
  if (preferredEngine === 'primary') {
109
  providers = [
110
  { fn: () => callGemini(prompt), name: GEMINI_MODEL },
111
+ { fn: () => callGroq(prompt, GROQ_MODELS[0]), name: "Groq-Llama" },
112
+ { fn: () => callOpenRouter(prompt, OPENROUTER_MODELS[0]), name: "OpenRouter" }
113
  ];
114
  } else if (preferredEngine === 'advanced') {
115
  providers = [
116
+ { fn: () => callOpenRouter(prompt, OPENROUTER_MODELS[0]), name: "OpenRouter" },
117
  { fn: () => callGemini(prompt), name: GEMINI_MODEL },
118
+ { fn: () => callGroq(prompt, GROQ_MODELS[0]), name: "Groq-Llama" }
119
  ];
120
  } else {
121
  providers = [
122
+ { fn: () => callGroq(prompt, GROQ_MODELS[0]), name: "Groq-Llama" },
123
+ { fn: () => callGroq(prompt, GROQ_MODELS[1]), name: "Groq-Mixtral" },
124
+ { fn: () => callGemini(prompt), name: GEMINI_MODEL }
125
  ];
126
  }
127
 
 
137
  }
138
  }
139
 
140
+ throw new Error("All AI providers and models in fallback chain failed.");
 
141
  }
142
 
143
  export const safeGenerateContent = async (prompt: string, aiEngine: 'primary' | 'fallback' | 'advanced' = 'primary'): Promise<{ output: any, model: string }> => {
 
146
 
147
  try {
148
  const parsed = JSON.parse(cleanedJsonText);
 
149
  return { output: parsed, model: result.model };
150
  } catch (error: any) {
151
+ console.error("[GEMINI_CLIENT_JSON_ERROR]: Failed to parse JSON ->", error.message);
152
+ console.error("[RAW_AI_OUTPUT]:", result.answer);
153
  throw new Error("AI response was not valid JSON.");
154
  }
155
  };