webscout 8.2.6__py3-none-any.whl → 8.2.8__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 (150) hide show
  1. webscout/AIauto.py +1 -1
  2. webscout/AIutel.py +298 -239
  3. webscout/Extra/Act.md +309 -0
  4. webscout/Extra/GitToolkit/gitapi/README.md +110 -0
  5. webscout/Extra/YTToolkit/README.md +375 -0
  6. webscout/Extra/YTToolkit/ytapi/README.md +44 -0
  7. webscout/Extra/YTToolkit/ytapi/extras.py +92 -19
  8. webscout/Extra/autocoder/autocoder.py +309 -114
  9. webscout/Extra/autocoder/autocoder_utiles.py +15 -15
  10. webscout/Extra/gguf.md +430 -0
  11. webscout/Extra/tempmail/README.md +488 -0
  12. webscout/Extra/weather.md +281 -0
  13. webscout/Litlogger/Readme.md +175 -0
  14. webscout/Provider/AISEARCH/DeepFind.py +41 -37
  15. webscout/Provider/AISEARCH/README.md +279 -0
  16. webscout/Provider/AISEARCH/__init__.py +0 -1
  17. webscout/Provider/AISEARCH/genspark_search.py +228 -86
  18. webscout/Provider/AISEARCH/hika_search.py +11 -11
  19. webscout/Provider/AISEARCH/scira_search.py +324 -322
  20. webscout/Provider/AllenAI.py +7 -14
  21. webscout/Provider/Blackboxai.py +518 -74
  22. webscout/Provider/Cloudflare.py +0 -1
  23. webscout/Provider/Deepinfra.py +23 -21
  24. webscout/Provider/Flowith.py +217 -0
  25. webscout/Provider/FreeGemini.py +250 -0
  26. webscout/Provider/GizAI.py +15 -5
  27. webscout/Provider/Glider.py +11 -8
  28. webscout/Provider/HeckAI.py +80 -52
  29. webscout/Provider/Koboldai.py +7 -4
  30. webscout/Provider/LambdaChat.py +2 -2
  31. webscout/Provider/Marcus.py +10 -18
  32. webscout/Provider/OPENAI/BLACKBOXAI.py +735 -0
  33. webscout/Provider/OPENAI/Cloudflare.py +378 -0
  34. webscout/Provider/OPENAI/FreeGemini.py +282 -0
  35. webscout/Provider/OPENAI/NEMOTRON.py +244 -0
  36. webscout/Provider/OPENAI/README.md +1253 -0
  37. webscout/Provider/OPENAI/__init__.py +8 -0
  38. webscout/Provider/OPENAI/ai4chat.py +293 -286
  39. webscout/Provider/OPENAI/api.py +810 -0
  40. webscout/Provider/OPENAI/base.py +217 -14
  41. webscout/Provider/OPENAI/c4ai.py +373 -367
  42. webscout/Provider/OPENAI/chatgpt.py +7 -0
  43. webscout/Provider/OPENAI/chatgptclone.py +7 -0
  44. webscout/Provider/OPENAI/chatsandbox.py +172 -0
  45. webscout/Provider/OPENAI/deepinfra.py +30 -20
  46. webscout/Provider/OPENAI/e2b.py +6 -0
  47. webscout/Provider/OPENAI/exaai.py +7 -0
  48. webscout/Provider/OPENAI/exachat.py +6 -0
  49. webscout/Provider/OPENAI/flowith.py +162 -0
  50. webscout/Provider/OPENAI/freeaichat.py +359 -352
  51. webscout/Provider/OPENAI/glider.py +323 -316
  52. webscout/Provider/OPENAI/groq.py +361 -354
  53. webscout/Provider/OPENAI/heckai.py +30 -64
  54. webscout/Provider/OPENAI/llmchatco.py +8 -0
  55. webscout/Provider/OPENAI/mcpcore.py +7 -0
  56. webscout/Provider/OPENAI/multichat.py +8 -0
  57. webscout/Provider/OPENAI/netwrck.py +356 -350
  58. webscout/Provider/OPENAI/opkfc.py +8 -0
  59. webscout/Provider/OPENAI/scirachat.py +471 -462
  60. webscout/Provider/OPENAI/sonus.py +9 -0
  61. webscout/Provider/OPENAI/standardinput.py +9 -1
  62. webscout/Provider/OPENAI/textpollinations.py +339 -329
  63. webscout/Provider/OPENAI/toolbaz.py +7 -0
  64. webscout/Provider/OPENAI/typefully.py +355 -0
  65. webscout/Provider/OPENAI/typegpt.py +358 -346
  66. webscout/Provider/OPENAI/uncovrAI.py +7 -0
  67. webscout/Provider/OPENAI/utils.py +103 -7
  68. webscout/Provider/OPENAI/venice.py +12 -0
  69. webscout/Provider/OPENAI/wisecat.py +19 -19
  70. webscout/Provider/OPENAI/writecream.py +7 -0
  71. webscout/Provider/OPENAI/x0gpt.py +7 -0
  72. webscout/Provider/OPENAI/yep.py +50 -21
  73. webscout/Provider/OpenGPT.py +1 -1
  74. webscout/Provider/TTI/AiForce/README.md +159 -0
  75. webscout/Provider/TTI/FreeAIPlayground/README.md +99 -0
  76. webscout/Provider/TTI/ImgSys/README.md +174 -0
  77. webscout/Provider/TTI/MagicStudio/README.md +101 -0
  78. webscout/Provider/TTI/Nexra/README.md +155 -0
  79. webscout/Provider/TTI/PollinationsAI/README.md +146 -0
  80. webscout/Provider/TTI/README.md +128 -0
  81. webscout/Provider/TTI/aiarta/README.md +134 -0
  82. webscout/Provider/TTI/artbit/README.md +100 -0
  83. webscout/Provider/TTI/fastflux/README.md +129 -0
  84. webscout/Provider/TTI/huggingface/README.md +114 -0
  85. webscout/Provider/TTI/piclumen/README.md +161 -0
  86. webscout/Provider/TTI/pixelmuse/README.md +79 -0
  87. webscout/Provider/TTI/talkai/README.md +139 -0
  88. webscout/Provider/TTS/README.md +192 -0
  89. webscout/Provider/TTS/__init__.py +2 -1
  90. webscout/Provider/TTS/speechma.py +500 -100
  91. webscout/Provider/TTS/sthir.py +94 -0
  92. webscout/Provider/TeachAnything.py +3 -7
  93. webscout/Provider/TextPollinationsAI.py +4 -2
  94. webscout/Provider/{aimathgpt.py → UNFINISHED/ChatHub.py} +88 -68
  95. webscout/Provider/UNFINISHED/liner_api_request.py +263 -0
  96. webscout/Provider/UNFINISHED/oivscode.py +351 -0
  97. webscout/Provider/UNFINISHED/test_lmarena.py +119 -0
  98. webscout/Provider/Writecream.py +11 -2
  99. webscout/Provider/__init__.py +8 -14
  100. webscout/Provider/ai4chat.py +4 -58
  101. webscout/Provider/asksteve.py +17 -9
  102. webscout/Provider/cerebras.py +3 -1
  103. webscout/Provider/koala.py +170 -268
  104. webscout/Provider/llmchat.py +3 -0
  105. webscout/Provider/lmarena.py +198 -0
  106. webscout/Provider/meta.py +7 -4
  107. webscout/Provider/samurai.py +223 -0
  108. webscout/Provider/scira_chat.py +4 -2
  109. webscout/Provider/typefully.py +23 -151
  110. webscout/__init__.py +4 -2
  111. webscout/cli.py +3 -28
  112. webscout/conversation.py +35 -35
  113. webscout/litagent/Readme.md +276 -0
  114. webscout/scout/README.md +402 -0
  115. webscout/swiftcli/Readme.md +323 -0
  116. webscout/version.py +1 -1
  117. webscout/webscout_search.py +2 -182
  118. webscout/webscout_search_async.py +1 -179
  119. webscout/zeroart/README.md +89 -0
  120. webscout/zeroart/__init__.py +134 -54
  121. webscout/zeroart/base.py +19 -13
  122. webscout/zeroart/effects.py +101 -99
  123. webscout/zeroart/fonts.py +1239 -816
  124. {webscout-8.2.6.dist-info → webscout-8.2.8.dist-info}/METADATA +116 -74
  125. {webscout-8.2.6.dist-info → webscout-8.2.8.dist-info}/RECORD +130 -103
  126. {webscout-8.2.6.dist-info → webscout-8.2.8.dist-info}/WHEEL +1 -1
  127. webscout-8.2.8.dist-info/entry_points.txt +3 -0
  128. webscout-8.2.8.dist-info/top_level.txt +1 -0
  129. webscout/Provider/AISEARCH/ISou.py +0 -256
  130. webscout/Provider/ElectronHub.py +0 -773
  131. webscout/Provider/Free2GPT.py +0 -241
  132. webscout/Provider/GPTWeb.py +0 -249
  133. webscout/Provider/bagoodex.py +0 -145
  134. webscout/Provider/geminiprorealtime.py +0 -160
  135. webscout/scout/core.py +0 -881
  136. webscout-8.2.6.dist-info/entry_points.txt +0 -3
  137. webscout-8.2.6.dist-info/top_level.txt +0 -2
  138. webstoken/__init__.py +0 -30
  139. webstoken/classifier.py +0 -189
  140. webstoken/keywords.py +0 -216
  141. webstoken/language.py +0 -128
  142. webstoken/ner.py +0 -164
  143. webstoken/normalizer.py +0 -35
  144. webstoken/processor.py +0 -77
  145. webstoken/sentiment.py +0 -206
  146. webstoken/stemmer.py +0 -73
  147. webstoken/tagger.py +0 -60
  148. webstoken/tokenizer.py +0 -158
  149. /webscout/Provider/{Youchat.py → UNFINISHED/Youchat.py} +0 -0
  150. {webscout-8.2.6.dist-info → webscout-8.2.8.dist-info}/licenses/LICENSE.md +0 -0
webscout/AIauto.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """
2
2
  This module provides the AUTO provider, which automatically selects and uses
3
3
  an available LLM provider from the webscout library that doesn't require
4
- API keys or cookies.
4
+ API keys or cookies.
5
5
  """
6
6
 
7
7
  from webscout.AIbase import Provider
webscout/AIutel.py CHANGED
@@ -1,240 +1,299 @@
1
- import json
2
- import platform
3
- import subprocess
4
- from typing import Union, Optional, Dict, Any, Iterable, Generator, List, Callable, Literal, Tuple
5
- import io
6
- from collections import deque
7
- import codecs
8
-
9
- # Expanded encoding types
10
- EncodingType = Literal['utf-8', 'utf-16', 'utf-32', 'ascii', 'latin1', 'cp1252', 'iso-8859-1',
11
- 'iso-8859-2', 'windows-1250', 'windows-1251', 'windows-1252', 'gbk', 'big5',
12
- 'shift_jis', 'euc-jp', 'euc-kr']
13
-
14
- def _process_chunk(
15
- chunk: str,
16
- intro_value: str,
17
- to_json: bool,
18
- skip_markers: List[str],
19
- strip_chars: Optional[str],
20
- yield_raw_on_error: bool,
21
- ) -> Union[str, Dict[str, Any], None]:
22
- """Internal helper to sanitize and potentially parse a single chunk."""
23
- if not isinstance(chunk, str):
24
- return None
25
-
26
- sanitized_chunk = chunk
27
-
28
- # Check if chunk starts with intro_value + skip_marker combination
29
- if intro_value and skip_markers:
30
- for marker in skip_markers:
31
- combined_marker = f"{intro_value}{marker}"
32
- if sanitized_chunk.startswith(combined_marker):
33
- return None
34
-
35
- if intro_value and sanitized_chunk.startswith(intro_value):
36
- sanitized_chunk = sanitized_chunk[len(intro_value):]
37
-
38
- if strip_chars is not None:
39
- sanitized_chunk = sanitized_chunk.strip(strip_chars)
40
- else:
41
- sanitized_chunk = sanitized_chunk.lstrip()
42
-
43
- # Check both standalone skip_markers and stripped version
44
- if not sanitized_chunk or any(
45
- marker in sanitized_chunk or sanitized_chunk == marker
46
- for marker in skip_markers
47
- ):
48
- return None
49
-
50
- if to_json:
51
- try:
52
- return json.loads(sanitized_chunk)
53
- except (json.JSONDecodeError, Exception) as e:
54
- return sanitized_chunk if yield_raw_on_error else None
55
-
56
- return sanitized_chunk
57
-
58
- def _decode_byte_stream(
59
- byte_iterator: Iterable[bytes],
60
- encoding: EncodingType = 'utf-8',
61
- errors: str = 'replace'
62
- ) -> Generator[str, None, None]:
63
- """
64
- Realtime byte stream decoder with flexible encoding support.
65
-
66
- Args:
67
- byte_iterator: Iterator yielding bytes
68
- encoding: Character encoding to use
69
- errors: How to handle encoding errors ('strict', 'ignore', 'replace')
70
- """
71
- # Initialize decoder with the specified encoding
72
- try:
73
- decoder = codecs.getincrementaldecoder(encoding)(errors=errors)
74
- except LookupError:
75
- # Fallback to utf-8 if the encoding is not supported
76
- decoder = codecs.getincrementaldecoder('utf-8')(errors=errors)
77
-
78
- # Process byte stream in realtime
79
- for chunk_bytes in byte_iterator:
80
- if not chunk_bytes:
81
- continue
82
-
83
- try:
84
- # Decode chunk with specified encoding
85
- text = decoder.decode(chunk_bytes, final=False)
86
- if text:
87
- yield text
88
- except UnicodeDecodeError:
89
- yield f"[Encoding Error: Could not decode bytes with {encoding}]\n"
90
-
91
- # Final flush
92
- try:
93
- final_text = decoder.decode(b'', final=True)
94
- if final_text:
95
- yield final_text
96
- except UnicodeDecodeError:
97
- yield f"[Encoding Error: Could not decode final bytes with {encoding}]\n"
98
- def sanitize_stream(
99
- data: Union[str, bytes, Iterable[str], Iterable[bytes]],
100
- intro_value: str = "data:",
101
- to_json: bool = True,
102
- skip_markers: Optional[List[str]] = None,
103
- strip_chars: Optional[str] = None,
104
- start_marker: Optional[str] = None,
105
- end_marker: Optional[str] = None,
106
- content_extractor: Optional[Callable[[Union[str, Dict[str, Any]]], Optional[Any]]] = None,
107
- yield_raw_on_error: bool = True,
108
- encoding: EncodingType = 'utf-8',
109
- encoding_errors: str = 'replace',
110
- chunk_size: Optional[int] = None,
111
- ) -> Generator[Any, None, None]:
112
- """
113
- Realtime stream processor that handles string/byte streams with minimal latency.
114
-
115
- Features:
116
- - Direct realtime processing of byte streams
117
- - Optimized string handling and JSON parsing
118
- - Robust error handling and validation
119
- - Flexible encoding support
120
- - Drop-in replacement for response.iter_content/iter_lines
121
-
122
- Args:
123
- data: Input data (string, string iterator, or bytes iterator)
124
- intro_value: Prefix to remove from each chunk
125
- to_json: Whether to parse chunks as JSON
126
- skip_markers: Markers to skip
127
- strip_chars: Characters to strip
128
- start_marker: Processing start marker
129
- end_marker: Processing end marker
130
- content_extractor: Function to extract content
131
- yield_raw_on_error: Yield raw content on JSON errors
132
- encoding: Character encoding for byte streams ('utf-8', 'latin1', etc.)
133
- encoding_errors: How to handle encoding errors ('strict', 'ignore', 'replace')
134
- chunk_size: Chunk size for byte streams (None for default)
135
-
136
- Yields:
137
- Processed chunks (string or dictionary)
138
-
139
- Example:
140
- >>> # Process response content
141
- >>> for chunk in sanitize_stream(response.iter_content()):
142
- ... process_chunk(chunk)
143
-
144
- >>> # Process a stream with specific encoding
145
- >>> for text in sanitize_stream(byte_stream, encoding='latin1', to_json=False):
146
- ... process_text(text)
147
- """
148
- effective_skip_markers = skip_markers or []
149
- processing_active = start_marker is None
150
-
151
- if isinstance(data, (str, bytes)):
152
- # Optimized single string/bytes processing
153
- processed_item = None
154
- if isinstance(data, bytes):
155
- data = data.decode(encoding, errors=encoding_errors)
156
- if to_json:
157
- try:
158
- processed_item = json.loads(data)
159
- except json.JSONDecodeError:
160
- pass
161
-
162
- if processed_item is None:
163
- if not processing_active and data == start_marker:
164
- processing_active = True
165
- elif processing_active and end_marker is not None and data == end_marker:
166
- processing_active = False
167
-
168
- if processing_active:
169
- processed_item = _process_chunk(
170
- data, intro_value, to_json, effective_skip_markers,
171
- strip_chars, yield_raw_on_error
172
- )
173
-
174
- if processed_item is not None:
175
- if content_extractor:
176
- try:
177
- final_content = content_extractor(processed_item)
178
- if final_content is not None:
179
- yield final_content
180
- except Exception:
181
- pass
182
- else:
183
- yield processed_item
184
-
185
- elif hasattr(data, '__iter__') or hasattr(data, 'iter_content'):
186
- # Efficient stream processing
187
- try:
188
- if hasattr(data, 'iter_content'):
189
- data = data.iter_content(chunk_size=chunk_size)
190
- first_item = next(iter(data))
191
- except StopIteration:
192
- return
193
-
194
- from itertools import chain
195
- stream = chain([first_item], data)
196
-
197
- # Choose processing path based on type
198
- if isinstance(first_item, bytes):
199
- line_iterator = _decode_byte_stream(
200
- stream,
201
- encoding=encoding,
202
- errors=encoding_errors
203
- )
204
- elif isinstance(first_item, str):
205
- line_iterator = stream
206
- else:
207
- raise TypeError(f"Stream must yield strings or bytes, not {type(first_item).__name__}")
208
-
209
- # Process stream efficiently
210
- for line in line_iterator:
211
- if not processing_active and start_marker is not None and line == start_marker:
212
- processing_active = True
213
- continue
214
- if processing_active and end_marker is not None and line == end_marker:
215
- processing_active = False
216
- continue
217
-
218
- if processing_active:
219
- processed = _process_chunk(
220
- line, intro_value, to_json, effective_skip_markers,
221
- strip_chars, yield_raw_on_error
222
- )
223
-
224
- if processed is not None:
225
- if content_extractor:
226
- try:
227
- final_content = content_extractor(processed)
228
- if final_content is not None:
229
- yield final_content
230
- except Exception:
231
- pass
232
- else:
233
- yield processed
234
- else:
235
- raise TypeError(f"Input must be a string or an iterable, not {type(data).__name__}")
236
-
237
- from .conversation import Conversation
238
- from .optimizers import Optimizers
239
- from .Extra.autocoder import AutoCoder
1
+ import json
2
+ from typing import Union, Optional, Dict, Any, Iterable, Generator, List, Callable, Literal
3
+ import codecs
4
+
5
+ # Expanded encoding types
6
+ EncodingType = Literal['utf-8', 'utf-16', 'utf-32', 'ascii', 'latin1', 'cp1252', 'iso-8859-1',
7
+ 'iso-8859-2', 'windows-1250', 'windows-1251', 'windows-1252', 'gbk', 'big5',
8
+ 'shift_jis', 'euc-jp', 'euc-kr']
9
+
10
+ def _process_chunk(
11
+ chunk: str,
12
+ intro_value: str,
13
+ to_json: bool,
14
+ skip_markers: List[str],
15
+ strip_chars: Optional[str],
16
+ yield_raw_on_error: bool,
17
+ ) -> Union[str, Dict[str, Any], None]:
18
+ """Internal helper to sanitize and potentially parse a single chunk."""
19
+ if not isinstance(chunk, str):
20
+ return None
21
+
22
+ # Fast path for empty chunks
23
+ if not chunk:
24
+ return None
25
+
26
+ # Use slicing for prefix removal (faster than startswith+slicing)
27
+ sanitized_chunk = chunk
28
+ if intro_value and len(chunk) >= len(intro_value) and chunk[:len(intro_value)] == intro_value:
29
+ sanitized_chunk = chunk[len(intro_value):]
30
+
31
+ # Optimize string stripping operations
32
+ if strip_chars is not None:
33
+ sanitized_chunk = sanitized_chunk.strip(strip_chars)
34
+ else:
35
+ # lstrip() is faster than strip() when we only need leading whitespace removed
36
+ sanitized_chunk = sanitized_chunk.lstrip()
37
+
38
+ # Skip empty chunks and markers
39
+ if not sanitized_chunk or any(marker == sanitized_chunk for marker in skip_markers):
40
+ return None
41
+
42
+ # JSON parsing with optimized error handling
43
+ if to_json:
44
+ try:
45
+ # Only strip before JSON parsing if needed
46
+ if sanitized_chunk[0] not in '{[' or sanitized_chunk[-1] not in '}]':
47
+ sanitized_chunk = sanitized_chunk.strip()
48
+ return json.loads(sanitized_chunk)
49
+ except (json.JSONDecodeError, Exception):
50
+ return sanitized_chunk if yield_raw_on_error else None
51
+
52
+ return sanitized_chunk
53
+
54
+ def _decode_byte_stream(
55
+ byte_iterator: Iterable[bytes],
56
+ encoding: EncodingType = 'utf-8',
57
+ errors: str = 'replace',
58
+ buffer_size: int = 8192
59
+ ) -> Generator[str, None, None]:
60
+ """
61
+ Realtime byte stream decoder with flexible encoding support.
62
+
63
+ Args:
64
+ byte_iterator: Iterator yielding bytes
65
+ encoding: Character encoding to use
66
+ errors: How to handle encoding errors ('strict', 'ignore', 'replace')
67
+ buffer_size: Size of internal buffer for performance tuning
68
+ """
69
+ # Initialize decoder with the specified encoding
70
+ try:
71
+ decoder = codecs.getincrementaldecoder(encoding)(errors=errors)
72
+ except LookupError:
73
+ # Fallback to utf-8 if the encoding is not supported
74
+ decoder = codecs.getincrementaldecoder('utf-8')(errors=errors)
75
+
76
+ # Process byte stream in realtime
77
+ buffer = bytearray(buffer_size)
78
+ buffer_view = memoryview(buffer)
79
+
80
+ for chunk_bytes in byte_iterator:
81
+ if not chunk_bytes:
82
+ continue
83
+
84
+ try:
85
+ # Use buffer for processing if chunk size is appropriate
86
+ if len(chunk_bytes) <= buffer_size:
87
+ buffer[:len(chunk_bytes)] = chunk_bytes
88
+ text = decoder.decode(buffer_view[:len(chunk_bytes)], final=False)
89
+ else:
90
+ text = decoder.decode(chunk_bytes, final=False)
91
+
92
+ if text:
93
+ yield text
94
+ except UnicodeDecodeError:
95
+ yield f"[Encoding Error: Could not decode bytes with {encoding}]\n"
96
+
97
+ # Final flush
98
+ try:
99
+ final_text = decoder.decode(b'', final=True)
100
+ if final_text:
101
+ yield final_text
102
+ except UnicodeDecodeError:
103
+ yield f"[Encoding Error: Could not decode final bytes with {encoding}]\n"
104
+
105
+ def sanitize_stream(
106
+ data: Union[str, Iterable[str], Iterable[bytes]],
107
+ intro_value: str = "data:",
108
+ to_json: bool = True,
109
+ skip_markers: Optional[List[str]] = None,
110
+ strip_chars: Optional[str] = None,
111
+ start_marker: Optional[str] = None,
112
+ end_marker: Optional[str] = None,
113
+ content_extractor: Optional[Callable[[Union[str, Dict[str, Any]]], Optional[Any]]] = None,
114
+ yield_raw_on_error: bool = True,
115
+ encoding: EncodingType = 'utf-8',
116
+ encoding_errors: str = 'replace',
117
+ buffer_size: int = 8192,
118
+ ) -> Generator[Any, None, None]:
119
+ """
120
+ Robust realtime stream processor that handles string/byte streams with correct marker extraction/skipping.
121
+ Now handles split markers, partial chunks, and skips lines containing (not just equal to) skip markers.
122
+ """
123
+ effective_skip_markers = skip_markers or []
124
+ processing_active = start_marker is None
125
+ buffer = ""
126
+ found_start = False if start_marker else True
127
+
128
+ # Fast path for single string processing
129
+ if isinstance(data, str):
130
+ processed_item = None
131
+ if processing_active:
132
+ if to_json:
133
+ try:
134
+ data = data.strip()
135
+ if data:
136
+ processed_item = json.loads(data)
137
+ except json.JSONDecodeError:
138
+ processed_item = data if yield_raw_on_error else None
139
+ else:
140
+ processed_item = _process_chunk(
141
+ data, intro_value, False, effective_skip_markers,
142
+ strip_chars, yield_raw_on_error
143
+ )
144
+ if processed_item is not None:
145
+ if content_extractor:
146
+ try:
147
+ final_content = content_extractor(processed_item)
148
+ if final_content is not None:
149
+ yield final_content
150
+ except Exception:
151
+ pass
152
+ else:
153
+ yield processed_item
154
+ return
155
+
156
+ # Stream processing path
157
+ if not hasattr(data, '__iter__'):
158
+ raise TypeError(f"Input must be a string or an iterable, not {type(data).__name__}")
159
+
160
+ try:
161
+ iterator = iter(data)
162
+ first_item = next(iterator, None)
163
+ if first_item is None:
164
+ return
165
+ from itertools import chain
166
+ stream = chain([first_item], iterator)
167
+
168
+ # Determine if we're dealing with bytes or strings
169
+ if isinstance(first_item, bytes):
170
+ line_iterator = _decode_byte_stream(
171
+ stream,
172
+ encoding=encoding,
173
+ errors=encoding_errors,
174
+ buffer_size=buffer_size
175
+ )
176
+ elif isinstance(first_item, str):
177
+ line_iterator = stream
178
+ else:
179
+ raise TypeError(f"Stream must yield strings or bytes, not {type(first_item).__name__}")
180
+
181
+ for line in line_iterator:
182
+ if not line:
183
+ continue
184
+ buffer += line
185
+ while True:
186
+ # Look for start marker if needed
187
+ if not found_start and start_marker:
188
+ idx = buffer.find(start_marker)
189
+ if idx != -1:
190
+ found_start = True
191
+ buffer = buffer[idx + len(start_marker):]
192
+ else:
193
+ # Not found, keep buffering
194
+ buffer = buffer[-max(len(start_marker), 256):] # avoid unbounded growth
195
+ break
196
+ # Look for end marker if needed
197
+ if found_start and end_marker:
198
+ idx = buffer.find(end_marker)
199
+ if idx != -1:
200
+ chunk = buffer[:idx]
201
+ buffer = buffer[idx + len(end_marker):]
202
+ processing_active = False
203
+ else:
204
+ chunk = buffer
205
+ buffer = ""
206
+ processing_active = True
207
+ # Process chunk if we are in active region
208
+ if chunk and processing_active:
209
+ # Split into lines for skip marker logic
210
+ for subline in chunk.splitlines():
211
+ # Remove intro_value prefix if present
212
+ if intro_value and subline.startswith(intro_value):
213
+ subline = subline[len(intro_value):]
214
+ # Strip chars if needed
215
+ if strip_chars is not None:
216
+ subline = subline.strip(strip_chars)
217
+ else:
218
+ subline = subline.lstrip()
219
+ # Skip if matches any skip marker (using 'in')
220
+ if any(marker in subline for marker in effective_skip_markers):
221
+ continue
222
+ # Skip empty
223
+ if not subline:
224
+ continue
225
+ # JSON parse if needed
226
+ if to_json:
227
+ try:
228
+ if subline and (subline[0] in '{[' and subline[-1] in '}]'):
229
+ parsed = json.loads(subline)
230
+ result = parsed
231
+ else:
232
+ result = subline
233
+ except Exception:
234
+ result = subline if yield_raw_on_error else None
235
+ else:
236
+ result = subline
237
+ if result is not None:
238
+ if content_extractor:
239
+ try:
240
+ final_content = content_extractor(result)
241
+ if final_content is not None:
242
+ yield final_content
243
+ except Exception:
244
+ pass
245
+ else:
246
+ yield result
247
+ if not processing_active:
248
+ found_start = False
249
+ if idx == -1:
250
+ break
251
+ elif found_start:
252
+ # No end marker, process all buffered content
253
+ chunk = buffer
254
+ buffer = ""
255
+ if chunk:
256
+ for subline in chunk.splitlines():
257
+ if intro_value and subline.startswith(intro_value):
258
+ subline = subline[len(intro_value):]
259
+ if strip_chars is not None:
260
+ subline = subline.strip(strip_chars)
261
+ else:
262
+ subline = subline.lstrip()
263
+ if any(marker in subline for marker in effective_skip_markers):
264
+ continue
265
+ if not subline:
266
+ continue
267
+ if to_json:
268
+ try:
269
+ if subline and (subline[0] in '{[' and subline[-1] in '}]'):
270
+ parsed = json.loads(subline)
271
+ result = parsed
272
+ else:
273
+ result = subline
274
+ except Exception:
275
+ result = subline if yield_raw_on_error else None
276
+ else:
277
+ result = subline
278
+ if result is not None:
279
+ if content_extractor:
280
+ try:
281
+ final_content = content_extractor(result)
282
+ if final_content is not None:
283
+ yield final_content
284
+ except Exception:
285
+ pass
286
+ else:
287
+ yield result
288
+ break
289
+ else:
290
+ break
291
+ except Exception as e:
292
+ import sys
293
+ print(f"Stream processing error: {str(e)}", file=sys.stderr)
294
+
295
+
296
+ from .conversation import Conversation
297
+ from .optimizers import Optimizers
298
+ from .Extra.autocoder import AutoCoder
240
299
  from .prompt_manager import AwesomePrompts