webscout 2025.10.15__py3-none-any.whl → 2025.10.16__py3-none-any.whl

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.

Potentially problematic release.


This version of webscout might be problematic. Click here for more details.

Files changed (60) hide show
  1. webscout/Extra/YTToolkit/README.md +1 -1
  2. webscout/Extra/tempmail/README.md +3 -3
  3. webscout/Provider/OPENAI/README.md +1 -1
  4. webscout/Provider/TTI/bing.py +4 -4
  5. webscout/__init__.py +1 -1
  6. webscout/client.py +4 -5
  7. webscout/litprinter/__init__.py +0 -42
  8. webscout/scout/README.md +59 -8
  9. webscout/scout/core/scout.py +62 -0
  10. webscout/scout/element.py +251 -45
  11. webscout/search/__init__.py +3 -4
  12. webscout/search/engines/bing/images.py +5 -2
  13. webscout/search/engines/bing/news.py +6 -4
  14. webscout/search/engines/bing/text.py +5 -2
  15. webscout/search/engines/yahoo/__init__.py +41 -0
  16. webscout/search/engines/yahoo/answers.py +16 -0
  17. webscout/search/engines/yahoo/base.py +34 -0
  18. webscout/search/engines/yahoo/images.py +324 -0
  19. webscout/search/engines/yahoo/maps.py +16 -0
  20. webscout/search/engines/yahoo/news.py +258 -0
  21. webscout/search/engines/yahoo/suggestions.py +140 -0
  22. webscout/search/engines/yahoo/text.py +273 -0
  23. webscout/search/engines/yahoo/translate.py +16 -0
  24. webscout/search/engines/yahoo/videos.py +302 -0
  25. webscout/search/engines/yahoo/weather.py +220 -0
  26. webscout/search/http_client.py +1 -1
  27. webscout/search/yahoo_main.py +54 -0
  28. webscout/{auth → server}/__init__.py +2 -23
  29. webscout/server/config.py +84 -0
  30. webscout/{auth → server}/request_processing.py +3 -28
  31. webscout/{auth → server}/routes.py +6 -148
  32. webscout/server/schemas.py +23 -0
  33. webscout/{auth → server}/server.py +11 -43
  34. webscout/server/simple_logger.py +84 -0
  35. webscout/version.py +1 -1
  36. webscout/version.py.bak +1 -1
  37. webscout/zeroart/README.md +17 -9
  38. webscout/zeroart/__init__.py +78 -6
  39. webscout/zeroart/effects.py +51 -1
  40. webscout/zeroart/fonts.py +559 -1
  41. {webscout-2025.10.15.dist-info → webscout-2025.10.16.dist-info}/METADATA +10 -52
  42. {webscout-2025.10.15.dist-info → webscout-2025.10.16.dist-info}/RECORD +49 -45
  43. {webscout-2025.10.15.dist-info → webscout-2025.10.16.dist-info}/entry_points.txt +1 -1
  44. webscout/auth/api_key_manager.py +0 -189
  45. webscout/auth/auth_system.py +0 -85
  46. webscout/auth/config.py +0 -175
  47. webscout/auth/database.py +0 -755
  48. webscout/auth/middleware.py +0 -248
  49. webscout/auth/models.py +0 -185
  50. webscout/auth/rate_limiter.py +0 -254
  51. webscout/auth/schemas.py +0 -103
  52. webscout/auth/simple_logger.py +0 -236
  53. webscout/search/engines/yahoo.py +0 -65
  54. webscout/search/engines/yahoo_news.py +0 -64
  55. /webscout/{auth → server}/exceptions.py +0 -0
  56. /webscout/{auth → server}/providers.py +0 -0
  57. /webscout/{auth → server}/request_models.py +0 -0
  58. {webscout-2025.10.15.dist-info → webscout-2025.10.16.dist-info}/WHEEL +0 -0
  59. {webscout-2025.10.15.dist-info → webscout-2025.10.16.dist-info}/licenses/LICENSE.md +0 -0
  60. {webscout-2025.10.15.dist-info → webscout-2025.10.16.dist-info}/top_level.txt +0 -0
@@ -2,10 +2,10 @@ webscout/AIauto.py,sha256=oVgK_iMgz2cmb2fYz88p0qq7TY4uXHyxyFd4UmCKw9g,10307
2
2
  webscout/AIbase.py,sha256=pmqdGdDepp5iBM47J8POqOqu7sL3LlzCThtfgT0V0Ho,14150
3
3
  webscout/AIutel.py,sha256=bIdaIPLs8lnXzboGP_ffQNitoYg2LL_B1krrMxYhzho,2054
4
4
  webscout/Bard.py,sha256=TWQ3paoCe5Tk2DXoxue0Jpfocx3S9l-_NaMtV7lkMQM,43785
5
- webscout/__init__.py,sha256=8BwXquDTrNOs_UVFUiSzvpcG8Mpp2x6b0jknLs830aA,740
5
+ webscout/__init__.py,sha256=lmDZlwaGqaXw-Aa7Cb0bys0mo1Go5QbyfnoW5xMYlJI,702
6
6
  webscout/__main__.py,sha256=pBm2E3ZZiMcCH37b1YCz7qKdKdX_i_S5En6fZDeJKFw,103
7
7
  webscout/cli.py,sha256=8DPRSP1fB8pdIeC5Ed6FH7mewOhCTH78RPvo9xwtxSU,14463
8
- webscout/client.py,sha256=HHnOL9I14uEJHCpGcyjlpZwna_DEJehHD5sqmti7sd8,5588
8
+ webscout/client.py,sha256=puNIpyQBMd0qysXij12_uveJmcN4brQhvQiheLJgkt4,5517
9
9
  webscout/conversation.py,sha256=FZy8eviJVq16SIVjXr-lfOrPPqWV6AjjO_uF_DLOtJ0,16651
10
10
  webscout/exceptions.py,sha256=5Y15eEjQkZcAjL4Rh68uo776MrQzmTINwi1fKzOXkGU,12472
11
11
  webscout/models.py,sha256=oZGSv6Mg74OMCvsuDngoyDPmyPnNZy8g7Q24lO69KwY,6385
@@ -14,8 +14,8 @@ webscout/prompt_manager.py,sha256=ysKFgPhkV3uqrOCilqcS9rG8xhzdU_d2wx0grC9WCCc,98
14
14
  webscout/sanitize.py,sha256=pw2Dzn-Jw9mOD4mpALYAvAf-medA-9AqdzsOmdXQbl0,46577
15
15
  webscout/update_checker.py,sha256=bz0TzRxip9DOIVMFyNz9HsGj4RKB0xZgo57AUVSJINo,3708
16
16
  webscout/utils.py,sha256=o2hU3qaVPk25sog3e4cyVZO3l8xwaZpYRziZPotEzNo,3075
17
- webscout/version.py,sha256=lFdrFaHswFMDr9VdMdSSpxeTuXjC5Z2DIrPJbWo9KtQ,51
18
- webscout/version.py.bak,sha256=mAYbMZvjx0FZh0om6ye0R7i_CmftBy0GpvRsRL0zcxY,41
17
+ webscout/version.py,sha256=bau6psbS6y1YovrRr6K7N3uBj_p0yf9WmHDqSK16bMs,51
18
+ webscout/version.py.bak,sha256=lFdrFaHswFMDr9VdMdSSpxeTuXjC5Z2DIrPJbWo9KtQ,51
19
19
  webscout/Extra/Act.md,sha256=_C2VW_Dc-dc7eejpGYKAOZhImHKPiQ7NSwE3bkzr6fg,18952
20
20
  webscout/Extra/__init__.py,sha256=KvJRsRBRO-fZp2jSCl6KQnPppi93hriA6O_U1O1s31c,177
21
21
  webscout/Extra/gguf.md,sha256=McXGz5sTfzOO9X4mH8yIqu5K3CgjzyXKi4_HQtezdZ4,12435
@@ -29,7 +29,7 @@ webscout/Extra/GitToolkit/gitapi/__init__.py,sha256=G5CeHDuQQEoJvE5rLttV1Z_hsTRn
29
29
  webscout/Extra/GitToolkit/gitapi/repository.py,sha256=AMeNXlfAIicM47_18z9i3kRZUobZNKeAePUrMqA_NqY,7124
30
30
  webscout/Extra/GitToolkit/gitapi/user.py,sha256=SO795ulRXYmr4fKPccCKedlCoUNWTKBvpgd4ueH4B0o,3534
31
31
  webscout/Extra/GitToolkit/gitapi/utils.py,sha256=PBUcc9gdmmV48g66uzJBP-YqxhGZoKJkV5eXs3WP6Lc,1835
32
- webscout/Extra/YTToolkit/README.md,sha256=G6eFyc_33DE4TSJyt84TC2LHqQ4w7W51DOOwJB-yabE,10919
32
+ webscout/Extra/YTToolkit/README.md,sha256=zULb30daDNwKkGLGpKKaRYtMKJGAHwESgshnp5morDk,10918
33
33
  webscout/Extra/YTToolkit/YTdownloader.py,sha256=58hA9wjZY3tQyn2NptXviS6saoE2ewdWF2q7YrpMgWg,32095
34
34
  webscout/Extra/YTToolkit/__init__.py,sha256=Wn1K-f6OjZ4GuWvL3FTM4zlTaF3xdb4v_K60YDxKdXg,75
35
35
  webscout/Extra/YTToolkit/transcriber.py,sha256=ur1lpZgNO2oNRBvLSFWFbwnE11FcArKXvSqmBy03aus,18575
@@ -49,7 +49,7 @@ webscout/Extra/YTToolkit/ytapi/video.py,sha256=71lM8KVS0kRyo6dnLmM00Sszs5bKIHWcG
49
49
  webscout/Extra/autocoder/__init__.py,sha256=Oj25K3UxPK3q5C222BI5wfoKAW_j853_0br9-kyt4_I,221
50
50
  webscout/Extra/autocoder/autocoder.py,sha256=YlP-z-CEaSgSygD95c9ijoNmzUy4nxfYkbhVR4IeIPQ,41371
51
51
  webscout/Extra/autocoder/autocoder_utiles.py,sha256=79O4O3dR7cKCdpUAh2Ek7rTt-ZfTmYmcQXeqdy5eoMg,21611
52
- webscout/Extra/tempmail/README.md,sha256=NzGMOh6RjDL8Sey_0hUdnxI5NjvNW6vJFZrQ34aDx5o,20826
52
+ webscout/Extra/tempmail/README.md,sha256=5PJH7F7Pv7y7u4GXE-HbFA5m6k9zFLL7ZrL7YUcPlyg,20838
53
53
  webscout/Extra/tempmail/__init__.py,sha256=27ntzaiFDBmw-QyIc4tkoBRCJ45uNmPP0zdaIiSh02Q,614
54
54
  webscout/Extra/tempmail/async_utils.py,sha256=F1v8oqqXWEmzim9e4jJGAOKrGdYHpkdDqjE0xpzNaU4,4275
55
55
  webscout/Extra/tempmail/base.py,sha256=kCtCVmbb6mdDsqmI19Q_gyg80nBrhOMvEits7XPKhy4,5386
@@ -148,7 +148,7 @@ webscout/Provider/OPENAI/GeminiProxy.py,sha256=9_6VHFylM3-ct0m5XDvxfZ1tmd70RnyZl
148
148
  webscout/Provider/OPENAI/K2Think.py,sha256=bNdq-oy2ie8PH7r6RDX7ZosYKFGjqzLSBvC2d_HAWAg,14822
149
149
  webscout/Provider/OPENAI/NEMOTRON.py,sha256=kRxqwDlWSPh3UbNA6qdaOdmD1nma1oStbcSXIWaJgh4,9470
150
150
  webscout/Provider/OPENAI/PI.py,sha256=Jn7bdqpz-Nofngajh8z2XWydVP2YHugJMerRLulRQ7M,14818
151
- webscout/Provider/OPENAI/README.md,sha256=Rp-KDOPdMMNBB1pAU6K6x3AOcaWK3ENeG5TMfO85eJs,24136
151
+ webscout/Provider/OPENAI/README.md,sha256=4uyOUwcUgfaYG-rSx8jnqTyOL5lAAW1uMEPGkHxmSSI,24135
152
152
  webscout/Provider/OPENAI/TogetherAI.py,sha256=6m1e2N0uqAuppnKiTadHzVqvLdkXs_QH8SIqlnEPRNg,13768
153
153
  webscout/Provider/OPENAI/TwoAI.py,sha256=bwuj7vCI5DkY_0d1rPMuKUmbL4ePAyUVrKvwFtU5CtM,17489
154
154
  webscout/Provider/OPENAI/__init__.py,sha256=EwtLtQs6VEpLFOBeXi9hC9FTJIJdHPZTZtu3iFFqhP0,1210
@@ -192,7 +192,7 @@ webscout/Provider/TTI/README.md,sha256=Qc9uXdEV2tGB6PyaM-HsLu_FZ7NcxHjGBwsNM5Gd0
192
192
  webscout/Provider/TTI/__init__.py,sha256=EwtLtQs6VEpLFOBeXi9hC9FTJIJdHPZTZtu3iFFqhP0,1210
193
193
  webscout/Provider/TTI/aiarta.py,sha256=aWIATT_xQU7AmH3rK9mDCrUyN_7yOqkpXFPKicrGKfY,14956
194
194
  webscout/Provider/TTI/base.py,sha256=SnNs-mJH8tcmcygNnfNtwPvWBk11FUO6nLTfnHnZADQ,5088
195
- webscout/Provider/TTI/bing.py,sha256=kPCkKwi7XgOxtkgUFDukJhonISfLDK4f6KDPduEjoP0,10640
195
+ webscout/Provider/TTI/bing.py,sha256=wzUtAprlptlvuA3wndn3i-5UBQIL-YSe8rmjhqb1T-Q,10632
196
196
  webscout/Provider/TTI/gpt1image.py,sha256=PKqc0JU7hweypnSooI7gWuXqJbKz52xfGQny90-Uin0,4831
197
197
  webscout/Provider/TTI/imagen.py,sha256=VtSTJzTao4oUje4viEuYbcAw2Fol-JhBPax3XeXuByM,6488
198
198
  webscout/Provider/TTI/infip.py,sha256=qAzcym5hyxHyuW5PFqcWN__ebs5s9wLCADakO_28aD4,7083
@@ -230,34 +230,18 @@ webscout/Provider/UNFINISHED/liner_api_request.py,sha256=13-38YyFMUyjaJQcdfsJC-W
230
230
  webscout/Provider/UNFINISHED/puterjs.py,sha256=jpTfTh8QWDqeDU3KO0OwAyLborGiPyAYH-v1bz34ekA,27591
231
231
  webscout/Provider/UNFINISHED/samurai.py,sha256=nw17DIz8DrgodhhekHRhO6mVqhor-2KmTTnLdBz6X3I,8223
232
232
  webscout/Provider/UNFINISHED/test_lmarena.py,sha256=JvN1Yr9E4sdrSuUcfKnR1fEtisp0oQkswRMTSBHn9wI,3734
233
- webscout/auth/__init__.py,sha256=tcgG2dottPjoBRSLMFx7fHl4C0zSssWbkaLW0JNF3Z0,1848
234
- webscout/auth/api_key_manager.py,sha256=a3F4d2r7h3GqV-wxNj2vNLkU9o0-ld-XU9udt_CQL0g,6954
235
- webscout/auth/auth_system.py,sha256=Uyqa9-IOOYIC_qvU5Mc5LwQM16rFHJJ5F-715VdMlGg,2926
236
- webscout/auth/config.py,sha256=kYZ7Dnul_P16wMSlfNem9nkSeY8Hh-plJrcUA0of2q4,6947
237
- webscout/auth/database.py,sha256=Q0thfSnTg8IXrAUQkpD-9CXhV6OBzrmwdnIHtc2I51o,30076
238
- webscout/auth/exceptions.py,sha256=FGqNLQmjv2i3Jk_P3csJzT4qkmVdBMdH7vFkM37Xa3Y,2048
239
- webscout/auth/middleware.py,sha256=zSQBIt0LacbeyNjwRIfnO-tdE7-p0w77UkPd7aUTri0,9863
240
- webscout/auth/models.py,sha256=gL7R1iazFM2-y1wiiOqxhmnrWfNMJcE5TlSQvSjj0-Q,7162
241
- webscout/auth/providers.py,sha256=gE0zKl8gwCD2P0e16y6YnbhmBM1qut0wKwAk5jmt8LI,11646
242
- webscout/auth/rate_limiter.py,sha256=8l1CpUY5YkY8SPHvZxL2SejAkO93uNklwQeSbjRxU5A,9925
243
- webscout/auth/request_models.py,sha256=hgo0AZ5CknEWCmZ4KBMs8T0xjmtlecbk645yU622Ujs,5804
244
- webscout/auth/request_processing.py,sha256=UB2JykZ98Acxd67VtFsLGOT9UwwwPQ8OeXzc9fkOrp4,17232
245
- webscout/auth/routes.py,sha256=1s-g3xK5og0MCQnVHiCzwy4hOxCZLR1pp_5cEy2QMGw,29167
246
- webscout/auth/schemas.py,sha256=fu3-V9F0n5AZ65A-fGGiBiuQcwk1Ec3urO7N30Nv90o,4577
247
- webscout/auth/server.py,sha256=-_KTByk7CMgsEeXPlCT4xuLYzC2ae1NiFCStGQr-ytc,13850
248
- webscout/auth/simple_logger.py,sha256=Tcj6HdfvUxQTF1SU-IPXlLjaLKSLeoFm9b0RN8_csT8,8264
249
233
  webscout/litagent/Readme.md,sha256=kwBG41HOjACdLfwJbluSyePc0RueITffwfplDEd2JJ0,7265
250
234
  webscout/litagent/__init__.py,sha256=rJCD_8ytXnUXMtNXG6O7nOnDHks8dbucf7S4WO7i7Go,854
251
235
  webscout/litagent/agent.py,sha256=dOXqdWq8Cdko2FX_CY3gg5IYBeq53DrkU5iFuAy5mHU,24045
252
236
  webscout/litagent/constants.py,sha256=uEx60lV6XKtY1yPOgl7mo4CaP0HAlfdoVjDaiPzmlHE,2116
253
- webscout/litprinter/__init__.py,sha256=iBYLF0IapDD7piPbNsBHWshg0WQWyP4EvodEPrP3lwI,2452
254
- webscout/scout/README.md,sha256=wZmPsrlUwHy7IaWzd9v9c8ATwPf509JXWE9SGb4x_-w,12218
237
+ webscout/litprinter/__init__.py,sha256=ggBHU4rFpQyaiX-flGdJW9R7eE_C5NWiOm8QCcC_uSQ,712
238
+ webscout/scout/README.md,sha256=n8hRiCr8Y2u68p0G3DoR-RV54HWuopH4KpCjKfbZL00,14146
255
239
  webscout/scout/__init__.py,sha256=C-uYGqVR7iiScetSxUTHc76i0OLQnWJO7WFTfhgafW4,325
256
- webscout/scout/element.py,sha256=UVRt_2vZgfxmvVrjqMhaCNVzULbyWqTyIyhOznDVJ4k,19469
240
+ webscout/scout/element.py,sha256=OmTdWBcVPMs1ox5c5vvqfpljw22fhZJ8YCmhozWKq10,27741
257
241
  webscout/scout/utils.py,sha256=I7ag7oeaUn07Q8vccGQpgJG9qEnpczvJ2Xh0K9z5NKw,969
258
242
  webscout/scout/core/__init__.py,sha256=Ujr53szROD5gAvi3ZDCa3OufJNIN1eCHqLmsbKxpwDw,290
259
243
  webscout/scout/core/crawler.py,sha256=QDVsqhTFGHt3YsGrJ6stSUgnYolQN_8Y0HFu3MxrUCs,10388
260
- webscout/scout/core/scout.py,sha256=7Y8fDyuX5zgDmvvU5Ln95EG6pCHrpJpAeQEcWJCsNnY,23698
244
+ webscout/scout/core/scout.py,sha256=IfN6ekpQB1zgLCcVlbdwGQruu7g8yLPYxaq_bz3_MMk,25756
261
245
  webscout/scout/core/search_result.py,sha256=SbNOkDB10uu4LCZraFDOoXmsXveS1mz79NGbNeUnJh0,2862
262
246
  webscout/scout/core/text_analyzer.py,sha256=QwLnCPM9hDhq9vDcJHWpW1qH6MGzmUYnLz7j6JMNG3A,1784
263
247
  webscout/scout/core/text_utils.py,sha256=HifZXsCAvpnLVFztGP1wDeYVmlEwfW-KXmU4e0-fyEo,10536
@@ -266,26 +250,25 @@ webscout/scout/parsers/__init__.py,sha256=a0gysttcAnIxfY8UBbkNJdmMHEhfeI9VmfnQGZ
266
250
  webscout/scout/parsers/html5lib_parser.py,sha256=VRCQIDh7Z9XbS8-zSOsmRtR2Oyx_DEz85hjRvabBQ2Y,5627
267
251
  webscout/scout/parsers/html_parser.py,sha256=OxQcFYjK-cWduKAbcxqChfRvKgqNjPqfN1Uit_dkJwQ,6792
268
252
  webscout/scout/parsers/lxml_parser.py,sha256=fDaxFuBSlU9x5hH5nDj5BHd72r9XHZ24Z5lt6FYPt_8,6053
269
- webscout/search/__init__.py,sha256=0XIql7nUSAOnpf0L---dM5GMPMTRhu1DeQO4jf_oGAQ,1007
253
+ webscout/search/__init__.py,sha256=0XpynvIDRPbO73aGYNr36PKEhjloWsmf5mA5WB6qIPA,958
270
254
  webscout/search/base.py,sha256=IFBHh0s-b3SXXDbi5cCzqwepnsoVVUTn2XfXX2iGUqE,6817
271
255
  webscout/search/bing_main.py,sha256=NAhM1rgbDOo5QEWLdNulGJ-9CVaSmYn3JhM3Jj7AZ58,2008
272
256
  webscout/search/duckduckgo_main.py,sha256=LL3ROo9iJS7S791JTfmN3-0zxnKAoTYFjCKDDCiRjOU,3531
273
- webscout/search/http_client.py,sha256=mL5WaKrItu0hLzK-sTK99yKuAjw0iwBYs1w6911yWUU,5140
257
+ webscout/search/http_client.py,sha256=HOUuC1iE1kvnR-NJYNWSNSYBKt8lAX6AGacKOmCHI7k,5114
274
258
  webscout/search/results.py,sha256=HM8Cf6DW8ET2yqbb3piaTa07ciox4f917pvKZli2EgU,3301
259
+ webscout/search/yahoo_main.py,sha256=RW_Zm_-5kxAfAShMwwS2eRTAX_Fzp3fH6uf2OmK2sHE,2798
275
260
  webscout/search/yep_main.py,sha256=SNh4Wu8cnMA21xeC13ZWK0ConY_dfAMcpnfedYdZRJE,1933
276
261
  webscout/search/engines/__init__.py,sha256=TzO5GqdlhquqOW9o-QFVuXdrnX99TEsJlcTNtuhA8VU,1615
277
262
  webscout/search/engines/brave.py,sha256=iO2KMFARt8QMZmbL2BHV5HZmAiFTFmOMAUkpr4ridcA,1337
278
263
  webscout/search/engines/mojeek.py,sha256=i86JB6n2lPaRMaYSqIj2EOo4KHnJICWJK-plRj-oudc,1097
279
264
  webscout/search/engines/wikipedia.py,sha256=tM4OI7UKFtRBcQqwgcm0y_uNqn8JVLKxVzTdixlZ7bU,1769
280
- webscout/search/engines/yahoo.py,sha256=69cxr7X9xpD2cUzI0TbD_ZsjSuUrcFfHiEvZDGnSztk,2018
281
- webscout/search/engines/yahoo_news.py,sha256=iiiy0Z8ZGruU8SvkW5bsM_BOpUFo6epWyFTG08ufSNs,1956
282
265
  webscout/search/engines/yandex.py,sha256=hjWn4I-ZYaKkLtX6816d2sxmBDM4O9zCHzjnf6byfio,1190
283
266
  webscout/search/engines/bing/__init__.py,sha256=bhKvLliFzwEbHqjMISkC6L-VvBNyi0_PhgVaV-Jdw98,26
284
267
  webscout/search/engines/bing/base.py,sha256=dRPtSmrPlmfPkfkYWyVrDGSM3btLP7fB48gNPCAo8JU,915
285
- webscout/search/engines/bing/images.py,sha256=-kMQKeuu2VVZ6ykGKO4Y4VqcEaJA5jgXMgMl8hAqlvs,3323
286
- webscout/search/engines/bing/news.py,sha256=w3Yl2wn4ipw-bPfL0gV0RCklRLL-YVZ5c1_7c-UxoS0,2852
268
+ webscout/search/engines/bing/images.py,sha256=wXEF2H-BmKjCOE4J0LnbEHbHaF1o5nPKt2M5FAIHtto,3365
269
+ webscout/search/engines/bing/news.py,sha256=N8DhSnHCaftAW1oftp8LR7uIWyIV2XnlxG5u2xKeoEI,2852
287
270
  webscout/search/engines/bing/suggestions.py,sha256=U7v0hjthChZ8D6JMNYw9nOa5NsCqo4GsUfFT3CQP4Uk,1042
288
- webscout/search/engines/bing/text.py,sha256=xbcDs7J8xIHDCiZG6wkYRjEMaUM59Xoj7_a6IM1HqMQ,3952
271
+ webscout/search/engines/bing/text.py,sha256=Op936jpQMd_Jr4CrhlJeEtZZq1-tIUfbI2RUmiCiF1U,3994
289
272
  webscout/search/engines/duckduckgo/__init__.py,sha256=IWa20CNW1IIyi86cXjuyqhm8famhUFUPH7Aiuly0bU4,685
290
273
  webscout/search/engines/duckduckgo/answers.py,sha256=amdVAZujdeokzQm0XsQ0187hdNc44J14XCAVDzvSebM,2432
291
274
  webscout/search/engines/duckduckgo/base.py,sha256=1GzmQhWjHMPc_U57Cyd1YuM303CtrnH0UIy7yQx-MHg,6387
@@ -297,11 +280,32 @@ webscout/search/engines/duckduckgo/text.py,sha256=yY39dnCN7_0WlFNqqYvHVqfUBd-4Xz
297
280
  webscout/search/engines/duckduckgo/translate.py,sha256=J3QVBkJsqw-yZD7Arx_bNFN-jNcj1i26VxnGNB0zk_g,1379
298
281
  webscout/search/engines/duckduckgo/videos.py,sha256=K6VRDC0EcNDvdMbx7rIRrb8mgKaJuUl_U5GfPxStbT4,2503
299
282
  webscout/search/engines/duckduckgo/weather.py,sha256=iYwKkaT8VL3pVp91mDX5CpRgRcF7VZy8KhXeCh9J96Q,3401
283
+ webscout/search/engines/yahoo/__init__.py,sha256=v3QcSUqotOxFP6KWWHrUtewrI0vHyiq5lmKQPnYDhhI,1093
284
+ webscout/search/engines/yahoo/answers.py,sha256=QT_NfK2yhn-2iWagXd_BK1Y93hQkwjEQ_RDnSxA-3iQ,390
285
+ webscout/search/engines/yahoo/base.py,sha256=Kf-xJmZ1vSL8_qGKv3eoEe_LFv4dogmCZEHjJFI7fBE,1061
286
+ webscout/search/engines/yahoo/images.py,sha256=Whvtw83CK3o9dNJvO_K0F0qYRqZrRc9lyXX_A0iKUfc,9928
287
+ webscout/search/engines/yahoo/maps.py,sha256=4zQXCEPYMZ4BxfL3J_OaiIWGulu5lVbI24SGTGsrnsY,373
288
+ webscout/search/engines/yahoo/news.py,sha256=8M8hQ6KJ8DLf-DryE8PiuE-Nw_lwwxN0R5eGPVGgOLw,7443
289
+ webscout/search/engines/yahoo/suggestions.py,sha256=pG8i9F9TG1RFyG2eEUQUsnmOhsfCyVHlXadMwZln2WY,3863
290
+ webscout/search/engines/yahoo/text.py,sha256=ftd62I9LAdkspSAym6t5wwxdGmFhROpLUY51shaIv9U,8286
291
+ webscout/search/engines/yahoo/translate.py,sha256=dGfun-lW4mW6pkVV4smSWt6SWb-0HoKVTBto_Bor_og,382
292
+ webscout/search/engines/yahoo/videos.py,sha256=0SxVv5RIKIrwp0WSfs6CY7EAzJMHYNGWLTCTAhYAxoQ,9083
293
+ webscout/search/engines/yahoo/weather.py,sha256=q4kSB-D9XycBAMROrS_d1yrcX_eYYKVznjvv0AG0awQ,9172
300
294
  webscout/search/engines/yep/__init__.py,sha256=2LCKP-5DUxE_iFaaBAbviD6fqAeKvKojn1G7nntLxjc,266
301
295
  webscout/search/engines/yep/base.py,sha256=05PkYCx5_ltgwbn-RhUAx6QSq2IcnWPjIhqXNaZE_eM,828
302
296
  webscout/search/engines/yep/images.py,sha256=vT4Tn1C-3UGH69DgyxVxrJLZwvWZPXs3SPXHjbgtzvk,3228
303
297
  webscout/search/engines/yep/suggestions.py,sha256=vv_upKlhFTHotNGDluMgKLxJ23Fm0MHYwfWPVS6rkZY,1085
304
298
  webscout/search/engines/yep/text.py,sha256=OpSJFW0sos99g6HYcUI-RySfi2ryj61RTF8FZkkyhAQ,3790
299
+ webscout/server/__init__.py,sha256=lXm3AO5GPe6-_CzZ5RxiG5X9AmSAXDUEjuCTnNKPerM,1293
300
+ webscout/server/config.py,sha256=05yQfddXNnjC8TmLV5ny57AkljJkeHA46HzbhFXlT5A,3086
301
+ webscout/server/exceptions.py,sha256=FGqNLQmjv2i3Jk_P3csJzT4qkmVdBMdH7vFkM37Xa3Y,2048
302
+ webscout/server/providers.py,sha256=gE0zKl8gwCD2P0e16y6YnbhmBM1qut0wKwAk5jmt8LI,11646
303
+ webscout/server/request_models.py,sha256=hgo0AZ5CknEWCmZ4KBMs8T0xjmtlecbk645yU622Ujs,5804
304
+ webscout/server/request_processing.py,sha256=9VkOB4g6OlWw9k6AEGZdeQNSHr6RCSJhr5N0fxe7lYk,16204
305
+ webscout/server/routes.py,sha256=vgkHlowNjX7PQx4Yhm89JwtL7BdGv_DxuFZLkbmij4A,22566
306
+ webscout/server/schemas.py,sha256=_FWsWwibXY4TzL4mhsL_-SyAwhJYeAcyRk00NzJZYlM,720
307
+ webscout/server/server.py,sha256=w1si2jVGwNsgrnUKp8CMRdRFj0tzk1ku1KBpRr1kXt4,12095
308
+ webscout/server/simple_logger.py,sha256=nw5GDuuYQ51PPWI2mHA8uBiFa2hqlCLu-nEBn2q9H78,2340
305
309
  webscout/swiftcli/Readme.md,sha256=ifqIIM1455tOGXqf_jQvT_toeIugpVF6lzrZiQjkkq4,7295
306
310
  webscout/swiftcli/__init__.py,sha256=goKgkz5USas833EhzpepEDB8b4uQBCunma9gLtGIRt4,1769
307
311
  webscout/swiftcli/exceptions.py,sha256=gjcpH7H-CO-pWU94AJE04tr02_BUJxmorhqu5VJ9AMo,508
@@ -319,14 +323,14 @@ webscout/swiftcli/plugins/manager.py,sha256=UlSk8j_pA38hsOIUR_G12CrB4OZ_7mtkTSG-
319
323
  webscout/swiftcli/utils/__init__.py,sha256=pF_Iva6sYD__gPFOjQjJ0Tpj2XYlkqL297VvMjvxauE,1055
320
324
  webscout/swiftcli/utils/formatting.py,sha256=5t7IlbMbsj2VvF42ehC6Zk_i4CVbIVemKfpJbcimXiw,5361
321
325
  webscout/swiftcli/utils/parsing.py,sha256=1jyVr914h-eNjN3YSnBOrxFjBwHZiq_FLNKuVfJinp4,7026
322
- webscout/zeroart/README.md,sha256=zSHLnjAT6zJqRSCQYTwt5aNcg7NrYDKqmEzVnSNr__Y,1970
323
- webscout/zeroart/__init__.py,sha256=Rg2jc6cfpmvKzmtIq3aNOKQH2I5d8GqLybtGNr1VQQY,3979
326
+ webscout/zeroart/README.md,sha256=BZ3OI9KFzwxVZgAix5mmiTETYKOdWPq_Ub6Ckdx6j8E,2425
327
+ webscout/zeroart/__init__.py,sha256=Cy9AUtXnOaFBQjNvCpN19IXJo7Lg15VTaNcTBxOTFek,6400
324
328
  webscout/zeroart/base.py,sha256=I-xhDEfArBb6q7hiF5oPoyXeu2hzL6orp7uWgS_YtG8,2299
325
- webscout/zeroart/effects.py,sha256=yxv6xRDxVU0FHhUdzamVv0eA_d8a8ckCDAitXQMhVZU,3245
326
- webscout/zeroart/fonts.py,sha256=FsuVQZL28Gi30NB5QPPjwUhC8sQt7vKJDMeu6km7N-I,37574
327
- webscout-2025.10.15.dist-info/licenses/LICENSE.md,sha256=hyfFlVn7pWcrvuvs-piB8k4J8DlXdOsYje9RyPxc6Ik,7543
328
- webscout-2025.10.15.dist-info/METADATA,sha256=FZnrkvKg2JWkjwo31hGs193LpJdgfRloBWH8uY6xXc0,23421
329
- webscout-2025.10.15.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
330
- webscout-2025.10.15.dist-info/entry_points.txt,sha256=WooZuMBei-kQl5qByoRMkc2cHsaDL1Jd2_tSYsNiUGg,116
331
- webscout-2025.10.15.dist-info/top_level.txt,sha256=nYIw7OKBQDr_Z33IzZUKidRD3zQEo8jOJYkMVMeN334,9
332
- webscout-2025.10.15.dist-info/RECORD,,
329
+ webscout/zeroart/effects.py,sha256=XUNZY1-wMPd6GNL3glFXtWaF9wDis_z55qTyCdnzHDo,5063
330
+ webscout/zeroart/fonts.py,sha256=S7qDhUmDXl1makMreZl_eVW_7-sqVQiGn-kQKl0Hg_A,51006
331
+ webscout-2025.10.16.dist-info/licenses/LICENSE.md,sha256=hyfFlVn7pWcrvuvs-piB8k4J8DlXdOsYje9RyPxc6Ik,7543
332
+ webscout-2025.10.16.dist-info/METADATA,sha256=1jpCGVNGZrYgLltqLS8-vUlre_bLwQdq_O5XT4XljKQ,21690
333
+ webscout-2025.10.16.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
334
+ webscout-2025.10.16.dist-info/entry_points.txt,sha256=4xAgKHWwNhAvJyShLCFs_IU8Reb8zR3wqf8egrsDr8g,118
335
+ webscout-2025.10.16.dist-info/top_level.txt,sha256=nYIw7OKBQDr_Z33IzZUKidRD3zQEo8jOJYkMVMeN334,9
336
+ webscout-2025.10.16.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  [console_scripts]
2
2
  WEBS = webscout.cli:main
3
3
  webscout = webscout.cli:main
4
- webscout-server = webscout.auth.server:main
4
+ webscout-server = webscout.server.server:main
@@ -1,189 +0,0 @@
1
- # webscout/auth/api_key_manager.py
2
-
3
- import secrets
4
- import string
5
- from datetime import datetime, timezone, timedelta
6
- from typing import Optional, Tuple
7
- import hashlib
8
- import logging
9
-
10
- from .models import User, APIKey
11
- from .database import DatabaseManager
12
-
13
- logger = logging.getLogger(__name__)
14
-
15
-
16
- class APIKeyManager:
17
- """Manages API key generation, validation, and lifecycle."""
18
-
19
- def __init__(self, database_manager: DatabaseManager):
20
- self.db = database_manager
21
- self.key_prefix = "ws_" # webscout prefix
22
- self.key_length = 32 # Length of the random part
23
-
24
- def generate_api_key(self) -> str:
25
- """Generate a secure API key."""
26
- # Generate random string
27
- alphabet = string.ascii_letters + string.digits
28
- random_part = ''.join(secrets.choice(alphabet) for _ in range(self.key_length))
29
-
30
- # Add prefix
31
- api_key = f"{self.key_prefix}{random_part}"
32
-
33
- return api_key
34
-
35
- def hash_api_key(self, api_key: str) -> str:
36
- """Hash an API key for secure storage (optional, for extra security)."""
37
- return hashlib.sha256(api_key.encode()).hexdigest()
38
-
39
- async def create_api_key(
40
- self,
41
- username: str,
42
- telegram_id: str,
43
- name: Optional[str] = None,
44
- rate_limit: int = 10,
45
- expires_in_days: Optional[int] = None
46
- ) -> Tuple[APIKey, User]:
47
- """Create a new API key and associated user if needed. Only one API key per user allowed."""
48
-
49
- # Check if user already exists by telegram_id
50
- user = await self.db.get_user_by_telegram_id(telegram_id)
51
-
52
- if user:
53
- # Check if user already has an API key
54
- existing_keys = await self.db.get_api_keys_by_user(user.id)
55
- active_keys = [key for key in existing_keys if key.is_active and not key.is_expired()]
56
-
57
- if active_keys:
58
- raise ValueError(f"User with Telegram ID {telegram_id} already has an active API key. Only one API key per user is allowed.")
59
- else:
60
- # Check if username is already taken
61
- existing_user = await self.db.get_user_by_username(username)
62
- if existing_user:
63
- raise ValueError(f"Username '{username}' is already taken")
64
-
65
- # Create new user
66
- user = User(
67
- username=username,
68
- telegram_id=telegram_id,
69
- created_at=datetime.now(timezone.utc),
70
- updated_at=datetime.now(timezone.utc)
71
- )
72
- try:
73
- user = await self.db.create_user(user)
74
- logger.info(f"Created new user: {user.username} (Telegram ID: {telegram_id})")
75
- except ValueError as e:
76
- # User might already exist, try to get it
77
- if "already exists" in str(e):
78
- user = await self.db.get_user_by_telegram_id(telegram_id)
79
- if not user:
80
- raise e
81
- else:
82
- raise e
83
-
84
- # Generate API key
85
- api_key_value = self.generate_api_key()
86
-
87
- # Calculate expiration
88
- expires_at = None
89
- if expires_in_days:
90
- expires_at = datetime.now(timezone.utc) + timedelta(days=expires_in_days)
91
-
92
- # Create API key object
93
- api_key = APIKey(
94
- key=api_key_value,
95
- user_id=user.id,
96
- name=name,
97
- created_at=datetime.now(timezone.utc),
98
- expires_at=expires_at,
99
- rate_limit=rate_limit,
100
- is_active=True
101
- )
102
-
103
- # Store in database
104
- try:
105
- api_key = await self.db.create_api_key(api_key)
106
- logger.info(f"Created API key for user {user.username}: {api_key.id}")
107
- return api_key, user
108
- except ValueError as e:
109
- # Key collision (very unlikely), try again
110
- if "already exists" in str(e):
111
- logger.warning("API key collision detected, regenerating...")
112
- return await self.create_api_key(username, telegram_id, name, rate_limit, expires_in_days)
113
- raise e
114
-
115
- async def validate_api_key(self, api_key: str) -> Tuple[bool, Optional[APIKey], Optional[str]]:
116
- """
117
- Validate an API key.
118
-
119
- Returns:
120
- Tuple of (is_valid, api_key_object, error_message)
121
- """
122
- if not api_key:
123
- return False, None, "API key is required"
124
-
125
- if not api_key.startswith(self.key_prefix):
126
- return False, None, "Invalid API key format"
127
-
128
- try:
129
- # Get API key from database
130
- key_obj = await self.db.get_api_key(api_key)
131
-
132
- if not key_obj:
133
- return False, None, "API key not found"
134
-
135
- if not key_obj.is_active:
136
- return False, None, "API key is inactive"
137
-
138
- if key_obj.is_expired():
139
- return False, None, "API key has expired"
140
-
141
- # Update last used timestamp
142
- key_obj.last_used_at = datetime.now(timezone.utc)
143
- key_obj.usage_count += 1
144
-
145
- try:
146
- await self.db.update_api_key(key_obj)
147
- except Exception as e:
148
- logger.warning(f"Failed to update API key usage: {e}")
149
-
150
- return True, key_obj, None
151
-
152
- except Exception as e:
153
- logger.error(f"Error validating API key: {e}")
154
- return False, None, "Internal error during validation"
155
-
156
- async def revoke_api_key(self, api_key: str) -> bool:
157
- """Revoke an API key by marking it as inactive."""
158
- try:
159
- key_obj = await self.db.get_api_key(api_key)
160
-
161
- if not key_obj:
162
- return False
163
-
164
- key_obj.is_active = False
165
- key_obj.updated_at = datetime.now(timezone.utc)
166
-
167
- await self.db.update_api_key(key_obj)
168
- logger.info(f"Revoked API key: {key_obj.id}")
169
- return True
170
-
171
- except Exception as e:
172
- logger.error(f"Error revoking API key: {e}")
173
- return False
174
-
175
- async def get_user_api_keys(self, user_id: str) -> list[APIKey]:
176
- """Get all API keys for a user."""
177
- try:
178
- return await self.db.get_api_keys_by_user(user_id)
179
- except Exception as e:
180
- logger.error(f"Error getting user API keys: {e}")
181
- return []
182
-
183
- async def cleanup_expired_keys(self) -> int:
184
- """Clean up expired API keys (mark as inactive)."""
185
- # This would require a method to get all API keys, which we haven't implemented
186
- # For now, we'll just return 0
187
- # In a production system, you'd want to implement this properly
188
- logger.info("Cleanup expired keys called (not implemented)")
189
- return 0
@@ -1,85 +0,0 @@
1
- """
2
- Authentication system initialization for the Webscout API.
3
- """
4
-
5
- import os
6
- import sys
7
- from typing import Optional
8
- from fastapi import FastAPI
9
-
10
- from webscout.Litlogger import Logger, LogLevel, LogFormat, ConsoleHandler
11
- from .database import DatabaseManager
12
- from .api_key_manager import APIKeyManager
13
- from .rate_limiter import RateLimiter
14
- from .middleware import AuthMiddleware
15
-
16
- # Setup logger
17
- logger = Logger(
18
- name="webscout.api",
19
- level=LogLevel.INFO,
20
- handlers=[ConsoleHandler(stream=sys.stdout)],
21
- fmt=LogFormat.DEFAULT
22
- )
23
-
24
- # Global authentication system instances
25
- db_manager: Optional[DatabaseManager] = None
26
- api_key_manager: Optional[APIKeyManager] = None
27
- rate_limiter: Optional[RateLimiter] = None
28
- auth_middleware: Optional[AuthMiddleware] = None
29
-
30
-
31
- def initialize_auth_system(app: FastAPI, auth_required: bool = True, rate_limit_enabled: bool = True) -> None:
32
- """Initialize the authentication system."""
33
- global db_manager, api_key_manager, rate_limiter, auth_middleware
34
-
35
- try:
36
- # Initialize database manager (always needed for request logging)
37
- mongo_url = os.getenv("MONGODB_URL")
38
- data_dir = os.getenv("WEBSCOUT_DATA_DIR", "data")
39
-
40
- db_manager = DatabaseManager(mongo_url, data_dir)
41
-
42
- if not auth_required:
43
- logger.info("Auth system is disabled (no-auth mode): initializing only database for request logging.")
44
- api_key_manager = None
45
- rate_limiter = None
46
- auth_middleware = None
47
- else:
48
- # Initialize API key manager
49
- api_key_manager = APIKeyManager(db_manager)
50
-
51
- # Initialize rate limiter
52
- rate_limiter = RateLimiter(db_manager)
53
-
54
- # Initialize auth middleware with configuration
55
- auth_middleware = AuthMiddleware(
56
- api_key_manager,
57
- rate_limiter,
58
- auth_required=auth_required,
59
- rate_limit_enabled=rate_limit_enabled
60
- )
61
-
62
- # Add auth middleware to app
63
- app.middleware("http")(auth_middleware)
64
-
65
- # Add startup event to initialize database
66
- async def startup_event():
67
- if db_manager:
68
- await db_manager.initialize()
69
- logger.info("Database system initialized successfully")
70
- logger.info(f"Auth required: {auth_required}, Rate limiting: {rate_limit_enabled}")
71
-
72
- # Store startup function for later use
73
- app.state.startup_event = startup_event
74
-
75
- logger.info("Authentication system setup completed")
76
-
77
- except Exception as e:
78
- logger.error(f"Failed to initialize authentication system: {e}")
79
- # Fall back to legacy auth if new system fails
80
- logger.warning("Falling back to legacy authentication system")
81
-
82
-
83
- def get_auth_components():
84
- """Get the initialized authentication components."""
85
- return api_key_manager, db_manager, rate_limiter
webscout/auth/config.py DELETED
@@ -1,175 +0,0 @@
1
- """
2
- Configuration management for the Webscout API server.
3
- """
4
-
5
- import os
6
- from typing import List, Dict, Optional, Any
7
- from webscout.Litlogger import Logger, LogLevel, LogFormat, ConsoleHandler
8
- import sys
9
-
10
- # Configuration constants
11
- DEFAULT_PORT = 8000
12
- DEFAULT_HOST = "0.0.0.0"
13
-
14
- # Setup logger
15
- logger = Logger(
16
- name="webscout.api",
17
- level=LogLevel.INFO,
18
- handlers=[ConsoleHandler(stream=sys.stdout)],
19
- fmt=LogFormat.DEFAULT
20
- )
21
-
22
-
23
- def _get_supabase_url() -> Optional[str]:
24
- """Get Supabase URL from environment variables or GitHub secrets."""
25
- # Try environment variable first
26
- url = os.getenv("SUPABASE_URL")
27
- if url:
28
- logger.info("📍 Using SUPABASE_URL from environment")
29
- return url
30
-
31
- # Try to get from GitHub secrets (if running in GitHub Actions)
32
- github_url = os.getenv("GITHUB_SUPABASE_URL") # GitHub Actions secret
33
- if github_url:
34
- logger.info("📍 Using SUPABASE_URL from GitHub secrets")
35
- return github_url
36
-
37
- # Don't log error during import - only when actually needed
38
- return None
39
-
40
-
41
- def _get_supabase_anon_key() -> Optional[str]:
42
- """Get Supabase anon key from environment variables or GitHub secrets."""
43
- # Try environment variable first
44
- key = os.getenv("SUPABASE_ANON_KEY")
45
- if key:
46
- logger.info("🔑 Using SUPABASE_ANON_KEY from environment")
47
- return key
48
-
49
- # Try to get from GitHub secrets (if running in GitHub Actions)
50
- github_key = os.getenv("GITHUB_SUPABASE_ANON_KEY") # GitHub Actions secret
51
- if github_key:
52
- logger.info("🔑 Using SUPABASE_ANON_KEY from GitHub secrets")
53
- return github_key
54
-
55
- # Don't log error during import - only when actually needed
56
- return None
57
-
58
-
59
- class ServerConfig:
60
- """Centralized configuration management for the API server."""
61
-
62
- def __init__(self):
63
- self.api_key: Optional[str] = None
64
- self.provider_map: Dict[str, Any] = {}
65
- self.default_provider: str = "ChatGPT"
66
- self.base_url: Optional[str] = None
67
- self.host: str = DEFAULT_HOST
68
- self.port: int = DEFAULT_PORT
69
- self.debug: bool = False
70
- self.cors_origins: List[str] = ["*"]
71
- self.max_request_size: int = 10 * 1024 * 1024 # 10MB
72
- self.request_timeout: int = 300 # 5 minutes
73
- self.auth_required: bool = os.getenv("WEBSCOUT_AUTH_REQUIRED", "false").lower() == "true" # Default to no auth
74
- self.rate_limit_enabled: bool = os.getenv("WEBSCOUT_RATE_LIMIT_ENABLED", "false").lower() == "true" # Default to no rate limit
75
- self.default_rate_limit: int = 60 # Default rate limit for no-auth mode
76
- self.request_logging_enabled: bool = os.getenv("WEBSCOUT_REQUEST_LOGGING", "true").lower() == "true" # Enable request logging by default
77
-
78
- # Database configuration - lazy initialization
79
- self._supabase_url: Optional[str] = None
80
- self._supabase_anon_key: Optional[str] = None
81
- self._supabase_url_checked: bool = False
82
- self._supabase_anon_key_checked: bool = False
83
- self.mongodb_url: Optional[str] = os.getenv("MONGODB_URL")
84
-
85
- @property
86
- def supabase_url(self) -> Optional[str]:
87
- """Get Supabase URL with lazy initialization."""
88
- if not self._supabase_url_checked:
89
- self._supabase_url = _get_supabase_url()
90
- self._supabase_url_checked = True
91
- return self._supabase_url
92
-
93
- @property
94
- def supabase_anon_key(self) -> Optional[str]:
95
- """Get Supabase anon key with lazy initialization."""
96
- if not self._supabase_anon_key_checked:
97
- self._supabase_anon_key = _get_supabase_anon_key()
98
- self._supabase_anon_key_checked = True
99
- return self._supabase_anon_key
100
-
101
- def update(self, **kwargs) -> None:
102
- """Update configuration with provided values."""
103
- for key, value in kwargs.items():
104
- if hasattr(self, key) and value is not None:
105
- setattr(self, key, value)
106
- logger.info(f"Config updated: {key} = {value}")
107
-
108
- def validate(self) -> None:
109
- """Validate configuration settings."""
110
- if self.port < 1 or self.port > 65535:
111
- raise ValueError(f"Invalid port number: {self.port}")
112
-
113
- if self.default_provider not in self.provider_map and self.provider_map:
114
- available_providers = list(set(v.__name__ for v in self.provider_map.values()))
115
- logger.warning(f"Default provider '{self.default_provider}' not found. Available: {available_providers}")
116
-
117
-
118
- class AppConfig:
119
- """Legacy configuration class for backward compatibility."""
120
- api_key: Optional[str] = None
121
- provider_map = {}
122
- tti_provider_map = {} # Add TTI provider map
123
- default_provider = "ChatGPT"
124
- default_tti_provider = "PollinationsAI" # Add default TTI provider
125
- base_url: Optional[str] = None
126
- auth_required: bool = os.getenv("WEBSCOUT_AUTH_REQUIRED", "false").lower() == "true" # Default to no auth
127
- rate_limit_enabled: bool = os.getenv("WEBSCOUT_RATE_LIMIT_ENABLED", "false").lower() == "true" # Default to no rate limit
128
- default_rate_limit: int = 60 # Default rate limit for no-auth mode
129
- request_logging_enabled: bool = os.getenv("WEBSCOUT_REQUEST_LOGGING", "true").lower() == "true" # Enable request logging by default
130
-
131
- # Database configuration - lazy initialization
132
- _supabase_url: Optional[str] = None
133
- _supabase_anon_key: Optional[str] = None
134
- _supabase_url_checked: bool = False
135
- _supabase_anon_key_checked: bool = False
136
- mongodb_url: Optional[str] = os.getenv("MONGODB_URL")
137
-
138
- @classmethod
139
- def get_supabase_url(cls) -> Optional[str]:
140
- """Get Supabase URL with lazy initialization."""
141
- if not cls._supabase_url_checked:
142
- cls._supabase_url = _get_supabase_url()
143
- cls._supabase_url_checked = True
144
- return cls._supabase_url
145
-
146
- @classmethod
147
- def get_supabase_anon_key(cls) -> Optional[str]:
148
- """Get Supabase anon key with lazy initialization."""
149
- if not cls._supabase_anon_key_checked:
150
- cls._supabase_anon_key = _get_supabase_anon_key()
151
- cls._supabase_anon_key_checked = True
152
- return cls._supabase_anon_key
153
-
154
- # For backward compatibility, provide properties that call the methods
155
- @property
156
- def supabase_url(self) -> Optional[str]:
157
- return self.__class__.get_supabase_url()
158
-
159
- @property
160
- def supabase_anon_key(self) -> Optional[str]:
161
- return self.__class__.get_supabase_anon_key()
162
-
163
- @classmethod
164
- def set_config(cls, **data):
165
- """Set configuration values."""
166
- for key, value in data.items():
167
- setattr(cls, key, value)
168
- # Sync with new config system
169
- try:
170
- from .server import get_config
171
- config = get_config()
172
- config.update(**data)
173
- except ImportError:
174
- # Handle case where server module is not available
175
- pass