wsbuilder 1.2.13__tar.gz → 1.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. {wsbuilder-1.2.13/src/wsbuilder.egg-info → wsbuilder-1.3.0}/PKG-INFO +1 -1
  2. wsbuilder-1.3.0/docs/ai-predict.md +244 -0
  3. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/ia.md +15 -0
  4. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/pyproject.toml +1 -1
  5. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/__init__.py +11 -1
  6. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/ia.py +8 -0
  7. wsbuilder-1.3.0/src/wsbuilder/ia_audio.py +93 -0
  8. wsbuilder-1.3.0/src/wsbuilder/ia_text.py +100 -0
  9. {wsbuilder-1.2.13 → wsbuilder-1.3.0/src/wsbuilder.egg-info}/PKG-INFO +1 -1
  10. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder.egg-info/SOURCES.txt +3 -0
  11. wsbuilder-1.3.0/tests/test_ia_text_audio.py +165 -0
  12. wsbuilder-1.2.13/docs/ai-predict.md +0 -139
  13. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/LICENSE +0 -0
  14. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/MANIFEST.in +0 -0
  15. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/README.md +0 -0
  16. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/404.html +0 -0
  17. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/CNAME +0 -0
  18. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/advanced.md +0 -0
  19. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/api-map.md +0 -0
  20. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/app-http.md +0 -0
  21. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/architecture.md +0 -0
  22. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/assets/wsbuilder-mark.svg +0 -0
  23. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/beginners.md +0 -0
  24. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/cache-security.md +0 -0
  25. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/cache.md +0 -0
  26. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/capabilities.md +0 -0
  27. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/data-orm.md +0 -0
  28. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/dns.md +0 -0
  29. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/full-project.md +0 -0
  30. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/getting-started.md +0 -0
  31. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/help/index.md +0 -0
  32. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/http-versions.md +0 -0
  33. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/http.md +0 -0
  34. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/index.md +0 -0
  35. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/install.md +0 -0
  36. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/intermediate.md +0 -0
  37. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/mdns.md +0 -0
  38. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/network-edge.md +0 -0
  39. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/observability-tasks.md +0 -0
  40. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/observability.md +0 -0
  41. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/persistence.md +0 -0
  42. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/proxy.md +0 -0
  43. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/reference/index.md +0 -0
  44. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/security.md +0 -0
  45. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/stylesheets/extra.css +0 -0
  46. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/tasks.md +0 -0
  47. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/tls-certificates.md +0 -0
  48. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/docs/websocket.md +0 -0
  49. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/examples/full-project/.gitignore +0 -0
  50. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/examples/full-project/README.md +0 -0
  51. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/examples/full-project/app.py +0 -0
  52. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/examples/full-project/pyproject.toml +0 -0
  53. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/examples/full-project/upstream.py +0 -0
  54. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/mkdocs.yml +0 -0
  55. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/setup.cfg +0 -0
  56. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/__main__.py +0 -0
  57. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/_coerce.py +0 -0
  58. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/_pragma.py +0 -0
  59. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/app.py +0 -0
  60. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/cache.py +0 -0
  61. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/caches.py +0 -0
  62. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/constants.py +0 -0
  63. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/cookies.py +0 -0
  64. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/db_replicas.py +0 -0
  65. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/dns.py +0 -0
  66. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/framework.py +0 -0
  67. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/headers.py +0 -0
  68. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/hpack.py +0 -0
  69. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/http.py +0 -0
  70. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/http1.py +0 -0
  71. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/http2.py +0 -0
  72. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/http3.py +0 -0
  73. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/http3_server.py +0 -0
  74. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/http3_websocket.py +0 -0
  75. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/logs.py +0 -0
  76. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/mdns.py +0 -0
  77. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/metrics.py +0 -0
  78. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/orm.py +0 -0
  79. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/pki.py +0 -0
  80. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/predicts.py +0 -0
  81. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/proxyi.py +0 -0
  82. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/qpack.py +0 -0
  83. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/quic/__init__.py +0 -0
  84. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/quic/address.py +0 -0
  85. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/quic/connection.py +0 -0
  86. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/quic/crypto.py +0 -0
  87. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/quic/frames.py +0 -0
  88. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/quic/packet.py +0 -0
  89. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/quic/recovery.py +0 -0
  90. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/quic/tls.py +0 -0
  91. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/quic/varint.py +0 -0
  92. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/security.py +0 -0
  93. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/server.py +0 -0
  94. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/tasks.py +0 -0
  95. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder/ws.py +0 -0
  96. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder.egg-info/dependency_links.txt +0 -0
  97. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder.egg-info/entry_points.txt +0 -0
  98. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder.egg-info/requires.txt +0 -0
  99. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/src/wsbuilder.egg-info/top_level.txt +0 -0
  100. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_app_threads.py +0 -0
  101. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_cache.py +0 -0
  102. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_caches.py +0 -0
  103. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_contributing_policy.py +0 -0
  104. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_demo_monitor.py +0 -0
  105. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_dns.py +0 -0
  106. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_docs.py +0 -0
  107. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_documentation_files.py +0 -0
  108. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_example_full_project.py +0 -0
  109. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_headers_cookies.py +0 -0
  110. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_hpack.py +0 -0
  111. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_http.py +0 -0
  112. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_http1.py +0 -0
  113. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_http2.py +0 -0
  114. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_http3.py +0 -0
  115. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_http3_server.py +0 -0
  116. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_http3_streaming.py +0 -0
  117. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_http3_streaming_udp.py +0 -0
  118. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_ia.py +0 -0
  119. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_logs.py +0 -0
  120. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_mdns.py +0 -0
  121. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_metrics.py +0 -0
  122. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_optional_extras.py +0 -0
  123. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_orm.py +0 -0
  124. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_orm_replicas.py +0 -0
  125. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_pki.py +0 -0
  126. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_pr_identity_policy.py +0 -0
  127. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_predicts.py +0 -0
  128. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_proxyi.py +0 -0
  129. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_proxyi_routing.py +0 -0
  130. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_quic_address.py +0 -0
  131. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_quic_crypto.py +0 -0
  132. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_quic_protocol.py +0 -0
  133. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_quic_recovery.py +0 -0
  134. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_quic_tls.py +0 -0
  135. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_security.py +0 -0
  136. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_server.py +0 -0
  137. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_server_errors.py +0 -0
  138. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_tasks.py +0 -0
  139. {wsbuilder-1.2.13 → wsbuilder-1.3.0}/tests/test_ws.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wsbuilder
3
- Version: 1.2.13
3
+ Version: 1.3.0
4
4
  Summary: Lightweight HTTP + WebSocket framework for Python.
5
5
  Author: wsbuilder Authors
6
6
  License-Expression: MIT
@@ -0,0 +1,244 @@
1
+ # IA y Prediccion
2
+
3
+ ## `DataSet`
4
+
5
+ `DataSet` es el contenedor basico para pares `X` y `Y`.
6
+
7
+ ```python
8
+ from wsbuilder import DataSet
9
+
10
+ dataset = DataSet(
11
+ [[1, 2], [2, 3], [3, 4], [4, 5]],
12
+ [[0], [1], [1], [1]],
13
+ )
14
+ train, test = dataset.split(train_ratio=0.75, shuffle=False)
15
+ ```
16
+
17
+ Metodos utiles:
18
+
19
+ - `sample_count`, `feature_count`, `target_count`
20
+ - `copy()`, `as_xy()`
21
+ - `shuffle()`, `split()`, `batches()`
22
+ - `describe_features()`, `describe_targets()`
23
+ - `standardize()`, `normalize_min_max()`
24
+
25
+ `split()` puede mezclar datos con `shuffle=True` y `seed` para resultados
26
+ repetibles. `batches()` permite entrenar por lotes.
27
+
28
+ ## `NeuralNetwork`
29
+
30
+ La red neuronal es completamente Python puro.
31
+
32
+ ```python
33
+ from wsbuilder import NeuralNetwork
34
+
35
+ net = NeuralNetwork(
36
+ seed=7,
37
+ learning_rate=0.3,
38
+ loss="binary_cross_entropy",
39
+ task="classification",
40
+ )
41
+ net.add_dense(6, input_size=2, activation="tanh")
42
+ net.add_dense(1, activation="sigmoid")
43
+ history = net.fit(
44
+ [[0, 0], [0, 1], [1, 0], [1, 1]],
45
+ [[0], [1], [1], [0]],
46
+ epochs=5000,
47
+ batch_size=4,
48
+ shuffle=False,
49
+ )
50
+ ```
51
+
52
+ Capacidades mas visibles:
53
+
54
+ - `fit` para regresion.
55
+ - `fit_classification` para etiquetas simbolicas.
56
+ - `predict`, `predict_batch`, `predict_proba`, `predict_class`.
57
+ - `evaluate`, `accuracy`, `classification_metrics`.
58
+ - `predict_with_metrics` para reportes de error y confianza.
59
+
60
+ Activaciones soportadas por la red:
61
+
62
+ - `linear`
63
+ - `sigmoid`
64
+ - `tanh`
65
+ - `relu`
66
+ - `leaky_relu`
67
+ - `softmax`
68
+
69
+ Losses soportadas:
70
+
71
+ - `mse`
72
+ - `binary_cross_entropy`
73
+ - `categorical_cross_entropy`
74
+
75
+ ## `DenseLayer`
76
+
77
+ `DenseLayer` permite definir capas manuales y se usa como bloque interno del
78
+ `NeuralNetwork`.
79
+
80
+ Tambien puedes crear capas con `net.add_dense(units, input_size=..., activation=...)`,
81
+ que es la forma mas directa para usuarios de la libreria.
82
+
83
+ ## Estadistica y error
84
+
85
+ Helpers exportados:
86
+
87
+ - `describe_data(values)`
88
+ - `evaluate_errors(expected, predicted, permissible_error=...)`
89
+
90
+ Devuelven `DataSummary` y `ErrorSummary`, ambos con la propiedad `uncertainty`.
91
+
92
+ ## Entrenamiento en background
93
+
94
+ ```python
95
+ from wsbuilder import NeuralNetwork, TaskManager, submit_training_task
96
+
97
+ X = [[0, 0], [0, 1], [1, 0], [1, 1]]
98
+ labels = ["no", "yes", "yes", "no"]
99
+
100
+ net = NeuralNetwork(
101
+ seed=7,
102
+ learning_rate=0.3,
103
+ loss="binary_cross_entropy",
104
+ task="classification",
105
+ )
106
+ net.add_dense(6, input_size=2, activation="tanh")
107
+ net.add_dense(1, activation="sigmoid")
108
+
109
+ tasks = TaskManager(max_concurrent=1)
110
+ task = submit_training_task(
111
+ tasks,
112
+ net,
113
+ X,
114
+ labels,
115
+ classification=True,
116
+ epochs=1000,
117
+ batch_size=4,
118
+ shuffle=False,
119
+ name="ia-train",
120
+ )
121
+ history = task.get(timeout=5)
122
+ ```
123
+
124
+ ## Texto Unicode y tokens
125
+
126
+ `ByteTokenizer` representa texto como IDs de bytes UTF-8 entre 0 y 255. No
127
+ necesita vocabulario entrenado y conserva exactamente el texto valido, incluidos
128
+ acentos, arabe, chino, emoji y codigo fuente. No aplica normalizacion. Estos IDs
129
+ no son los tokens de un modelo externo ni una estimacion de su facturacion.
130
+
131
+ ```python
132
+ from wsbuilder import ByteTokenizer
133
+
134
+ tokenizer = ByteTokenizer(max_bytes=1_000_000)
135
+ text = "Hola, 世界! مرحبا 👋\nprint('hola')"
136
+ tokens = tokenizer.encode(text)
137
+ assert tokenizer.decode(tokens) == text
138
+ assert tokenizer.vocab_size == 256
139
+ ```
140
+
141
+ `encode` rechaza texto que exceda `max_bytes`; `decode` rechaza secuencias
142
+ demasiado largas, IDs no enteros o fuera de rango y bytes que no formen UTF-8
143
+ valido. Un token individual puede ser solo parte de un caracter multibyte:
144
+ decodifica secuencias completas. No pases IDs de longitud variable directamente
145
+ a una capa densa de dimension fija.
146
+
147
+ ### Vectores de texto para la red
148
+
149
+ `HashingTextVectorizer` convierte ngramas de caracteres Unicode en vectores de
150
+ dimension fija usando un hash estable. Funciona tambien con idiomas que no
151
+ separan palabras con espacios; no necesita `fit` ni un vocabulario mutable.
152
+ Dos ngramas pueden caer en la misma posicion (colisiones). Estos vectores
153
+ describen patrones de caracteres, no son embeddings semanticos preentrenados.
154
+
155
+ ```python
156
+ from wsbuilder import DataSet, HashingTextVectorizer, NeuralNetwork
157
+
158
+ vectorizer = HashingTextVectorizer(n_features=64, ngram_range=(1, 3))
159
+ texts = ["hola", "buen dia", "adios", "hasta luego"]
160
+ X = vectorizer.transform_batch(texts)
161
+ dataset = DataSet(X, [[1], [1], [0], [0]])
162
+
163
+ model = NeuralNetwork(
164
+ seed=7, learning_rate=0.3,
165
+ loss="binary_cross_entropy", task="classification",
166
+ )
167
+ model.add_dense(8, input_size=64, activation="tanh")
168
+ model.add_dense(1, activation="sigmoid")
169
+ model.fit_classification(
170
+ dataset.X, ["saludo", "saludo", "despedida", "despedida"],
171
+ epochs=300, batch_size=4, shuffle=False,
172
+ )
173
+ label = model.predict_class(vectorizer.transform("hola"))
174
+ ```
175
+
176
+ Este conjunto diminuto ilustra la API; no demuestra comprension del lenguaje ni
177
+ generalizacion a otros idiomas. Conserva la misma configuracion del vectorizador
178
+ en entrenamiento e inferencia. El texto vacio produce un vector de ceros.
179
+ `max_chars` limita la longitud por texto (100 000 por defecto).
180
+ Por defecto se aplica `casefold` (`lowercase=True`), normalizacion Unicode NFC
181
+ y norma euclidea unitaria (`normalize=True`). NFC se aplica incluso con
182
+ `lowercase=False`; el tokenizador reversible no realiza estas transformaciones.
183
+ `n_features` admite 1 a 65 536 y los extremos de `ngram_range`, 1 a 8.
184
+ `transform_batch` no limita el numero de documentos: procesa tus colecciones
185
+ en lotes acotados.
186
+
187
+ ## Audio WAV y caracteristicas
188
+
189
+ `load_wav` lee una ruta o un archivo binario seekable con WAV PCM entero de
190
+ 8, 16, 24 o 32 bits. Convierte los canales a mono mediante su promedio: canales
191
+ en contrafase pueden cancelarse. No remuestrea ni decodifica MP3, AAC o audio
192
+ comprimido. No cierra el archivo proporcionado por el llamador.
193
+
194
+ ```python
195
+ from wsbuilder import AudioData, NeuralNetwork, audio_features, load_wav
196
+
197
+ audio = load_wav("grabacion.wav", max_frames=1_000_000, max_channels=8)
198
+ features = audio_features(audio)
199
+ # Orden: duracion en segundos, media, RMS, pico absoluto, cruces por cero.
200
+ assert len(features) == 5
201
+
202
+ silence = AudioData(samples=(0.0,) * 8000, sample_rate=8000)
203
+ assert audio_features(silence) == [1.0, 0.0, 0.0, 0.0, 0.0]
204
+
205
+ audio_model = NeuralNetwork(seed=7)
206
+ audio_model.add_dense(1, input_size=5, activation="linear")
207
+ # Entrenar audio_model.fit(...) con ejemplos y objetivos propios antes de inferir.
208
+ ```
209
+
210
+ Los limites de frames y canales se verifican antes de leer las muestras; los
211
+ archivos truncados se rechazan. Un frame contiene una muestra por canal, por lo
212
+ que un millon de frames equivale aproximadamente a 20,8 segundos a 48 kHz.
213
+ `AudioData` contiene una tupla de muestras mono finitas entre -1 y 1 y una
214
+ frecuencia entera en Hz positiva. `duration` devuelve la duracion en segundos;
215
+ una tupla vacia produce cinco caracteristicas cero. Los cruces por cero son
216
+ la fraccion de pares adyacentes que cambian de signo, considerando cero positivo.
217
+ Las caracteristicas resumen amplitud y duracion: no transcriben voz, reconocen
218
+ idiomas ni generan audio. Usa la misma frecuencia de muestreo para comparar
219
+ tasas de cruces por cero; divide los datos de entrenamiento y evaluacion por
220
+ grabacion para evitar evaluar sobre fragmentos del mismo audio.
221
+
222
+ Texto y audio pueden combinarse concatenando sus vectores y configurando
223
+ `input_size` con la suma de dimensiones. Entrena con ejemplos emparejados y
224
+ escalas consistentes; concatenar vectores no aporta por si solo comprension
225
+ multimodal. Los adaptadores no cambian las condiciones de concurrencia de
226
+ `NeuralNetwork`: evita compartir una instancia entre entrenamientos e
227
+ inferencias simultaneos.
228
+
229
+ ## `Predictor`
230
+
231
+ `Predictor` es una utilidad matematica aparte para regresion lineal simple.
232
+
233
+ ```python
234
+ from wsbuilder import Predictor
235
+
236
+ predictor = Predictor()
237
+ predictor.fit([[1], [2], [3], [4]], [[2], [4], [6], [8]])
238
+ prediction, sigma, lower, upper = predictor.predict([5])
239
+ ```
240
+
241
+ Es util cuando quieres prediccion rapida sin configurar una red neuronal.
242
+
243
+ Despues de `fit`, la instancia expone informacion como `rank`, coeficientes y
244
+ residuos internos usados para calcular desviacion e intervalo estimado.
@@ -13,6 +13,21 @@ WSBuilder incluye herramientas sencillas de data science y redes neuronales hech
13
13
  - `describe_data`
14
14
  - `evaluate_errors`
15
15
  - `submit_training_task`
16
+ - `ByteTokenizer`
17
+ - `HashingTextVectorizer`
18
+ - `AudioData`, `load_wav`, `audio_features`
19
+
20
+ ## Texto, tokens y audio
21
+
22
+ La IA acepta texto Unicode, incluidos idiomas sin espacios, emoji y codigo,
23
+ mediante tokens UTF-8 reversibles y vectores numericos de caracteres. Tambien
24
+ convierte audio WAV PCM en muestras mono y caracteristicas numericas para
25
+ entrenar o ejecutar las redes existentes. Todo funciona con la biblioteca
26
+ estandar, sin descargar modelos ni enviar datos a servicios externos.
27
+
28
+ Consulta los [ejemplos de texto y audio](ai-predict.md#texto-unicode-y-tokens).
29
+ Estos adaptadores preparan datos: no incorporan un modelo de conversacion,
30
+ traduccion, reconocimiento de voz, generacion de audio, imagen o video.
16
31
 
17
32
  ## Datos
18
33
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "wsbuilder"
7
- version = "1.2.13"
7
+ version = "1.3.0"
8
8
  description = "Lightweight HTTP + WebSocket framework for Python."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -63,13 +63,18 @@ from .framework import (
63
63
  )
64
64
  from .headers import add_header, get_header, has_header, normalize_header_name, set_header
65
65
  from .ia import (
66
+ AudioData,
67
+ ByteTokenizer,
66
68
  DataSet,
67
69
  DataSummary,
68
70
  DenseLayer,
69
71
  ErrorSummary,
72
+ HashingTextVectorizer,
70
73
  NeuralNetwork,
74
+ audio_features,
71
75
  describe_data,
72
76
  evaluate_errors,
77
+ load_wav,
73
78
  submit_training_task,
74
79
  )
75
80
  from .logs import NDJSONLog, install_logs
@@ -152,7 +157,7 @@ def __dir__():
152
157
  names |= _PKI_EXPORTS
153
158
  return sorted(names)
154
159
 
155
- __version__ = "1.2.13"
160
+ __version__ = "1.3.0"
156
161
 
157
162
  __all__ = [
158
163
  "App",
@@ -250,6 +255,11 @@ __all__ = [
250
255
  "OptimizedDatabase",
251
256
  "SQLite3OptimizationConfig",
252
257
  "DataSet",
258
+ "AudioData",
259
+ "ByteTokenizer",
260
+ "HashingTextVectorizer",
261
+ "audio_features",
262
+ "load_wav",
253
263
  "DataSummary",
254
264
  "ErrorSummary",
255
265
  "DenseLayer",
@@ -20,7 +20,15 @@ import random
20
20
  from dataclasses import dataclass
21
21
  from statistics import NormalDist
22
22
 
23
+ from .ia_audio import AudioData, audio_features, load_wav
24
+ from .ia_text import ByteTokenizer, HashingTextVectorizer
25
+
23
26
  __all__ = [
27
+ "AudioData",
28
+ "ByteTokenizer",
29
+ "HashingTextVectorizer",
30
+ "audio_features",
31
+ "load_wav",
24
32
  "DataSet",
25
33
  "DataSummary",
26
34
  "DenseLayer",
@@ -0,0 +1,93 @@
1
+ """Bounded PCM WAV decoding and numeric mono audio features (no speech model)."""
2
+
3
+ import math
4
+ import os
5
+ import wave
6
+ from dataclasses import dataclass
7
+
8
+ from .ia_text import _positive_integer
9
+
10
+ __all__ = ["AudioData", "load_wav", "audio_features"]
11
+
12
+
13
+ @dataclass(frozen=True)
14
+ class AudioData:
15
+ """Mono samples in [-1, 1] and a positive sample rate in Hz.
16
+
17
+ Direct construction accepts a tuple only, so it never consumes an unbounded
18
+ iterable. ``load_wav`` supplies bounded decoded samples.
19
+ """
20
+
21
+ samples: tuple[float, ...]
22
+ sample_rate: int
23
+
24
+ def __post_init__(self):
25
+ _positive_integer(self.sample_rate, "sample_rate")
26
+ if not isinstance(self.samples, tuple):
27
+ raise TypeError("samples must be a tuple")
28
+ if any(isinstance(value, bool) or not isinstance(value, (int, float))
29
+ or not math.isfinite(value) or not -1 <= value <= 1
30
+ for value in self.samples):
31
+ raise ValueError("samples must contain finite numbers in [-1, 1]")
32
+
33
+ @property
34
+ def duration(self):
35
+ return len(self.samples) / self.sample_rate
36
+
37
+
38
+ def load_wav(source, *, max_frames=1_000_000, max_channels=8):
39
+ """Read integer PCM WAV (8/16/24/32 bit), averaging channels to mono.
40
+
41
+ Opposite-phase channels can cancel during averaging. Source is a path or
42
+ binary seekable file; caller-owned files remain open. Declared frame count
43
+ and channels are checked before sample allocation. Malformed/truncated PCM
44
+ is rejected. Compressed audio and float WAV are not supported.
45
+ """
46
+ _positive_integer(max_frames, "max_frames")
47
+ _positive_integer(max_channels, "max_channels")
48
+ if isinstance(source, os.PathLike):
49
+ source = os.fspath(source)
50
+ with wave.open(source, "rb") as stream:
51
+ channels = stream.getnchannels()
52
+ width = stream.getsampwidth()
53
+ rate = stream.getframerate()
54
+ frames = stream.getnframes()
55
+ if not 1 <= channels <= max_channels:
56
+ raise ValueError("WAV channel count exceeds max_channels")
57
+ if frames > max_frames:
58
+ raise ValueError("WAV frame count exceeds max_frames")
59
+ if stream.getcomptype() != "NONE" or width not in (1, 2, 3, 4):
60
+ raise ValueError("WAV must use 8/16/24/32-bit integer PCM")
61
+ raw = stream.readframes(frames)
62
+ frame_size = width * channels
63
+ if len(raw) != frames * frame_size or stream.readframes(1):
64
+ raise ValueError("WAV contains truncated or incomplete PCM frames")
65
+ samples = []
66
+ scale = 1 << (width * 8 - 1)
67
+ for offset in range(0, len(raw), frame_size):
68
+ total = 0
69
+ for channel in range(channels):
70
+ start = offset + channel * width
71
+ value = int.from_bytes(raw[start:start + width], "little", signed=width != 1)
72
+ total += value - 128 if width == 1 else value
73
+ samples.append(total / (scale * channels))
74
+ return AudioData(tuple(samples), rate)
75
+
76
+
77
+ def audio_features(audio):
78
+ """Return [duration seconds, mean, RMS, peak, zero-crossing fraction].
79
+
80
+ Zero crossings compare adjacent signs (zero is nonnegative). Empty audio
81
+ returns five zeros. These summaries discard temporal/spectral information;
82
+ they are suitable for basic signal classification, not transcription.
83
+ """
84
+ if not isinstance(audio, AudioData):
85
+ raise TypeError("audio must be AudioData")
86
+ samples = audio.samples
87
+ if not samples:
88
+ return [0.0] * 5
89
+ crossings = sum((samples[i - 1] < 0) != (samples[i] < 0)
90
+ for i in range(1, len(samples)))
91
+ return [audio.duration, math.fsum(samples) / len(samples),
92
+ math.sqrt(math.fsum(value * value for value in samples) / len(samples)),
93
+ max(abs(value) for value in samples), crossings / max(1, len(samples) - 1)]
@@ -0,0 +1,100 @@
1
+ """Bounded UTF-8 tokens and deterministic character features, using only stdlib."""
2
+
3
+ import hashlib
4
+ import math
5
+ import unicodedata
6
+
7
+ __all__ = ["ByteTokenizer", "HashingTextVectorizer"]
8
+
9
+
10
+ def _positive_integer(value, name):
11
+ if type(value) is not int or value < 1:
12
+ raise ValueError(f"{name} must be a positive integer")
13
+ return value
14
+
15
+
16
+ class ByteTokenizer:
17
+ """Reversible UTF-8 bytes (IDs 0..255), without text normalization.
18
+
19
+ These are byte tokens, not a provider/model's token accounting scheme.
20
+ Invalid UTF-8 and isolated Unicode surrogates are rejected.
21
+ """
22
+
23
+ vocab_size = 256
24
+
25
+ def __init__(self, *, max_bytes=1_000_000):
26
+ self.max_bytes = _positive_integer(max_bytes, "max_bytes")
27
+
28
+ def encode(self, text):
29
+ if not isinstance(text, str):
30
+ raise TypeError("text must be a string")
31
+ if len(text) > self.max_bytes:
32
+ raise ValueError("text exceeds max_bytes")
33
+ encoded = text.encode("utf-8")
34
+ if len(encoded) > self.max_bytes:
35
+ raise ValueError("text exceeds max_bytes")
36
+ return list(encoded)
37
+
38
+ def decode(self, tokens):
39
+ encoded = bytearray()
40
+ for token in tokens:
41
+ if len(encoded) >= self.max_bytes:
42
+ raise ValueError("tokens exceed max_bytes")
43
+ if type(token) is not int or not 0 <= token < self.vocab_size:
44
+ raise ValueError("tokens must be integer byte IDs in 0..255")
45
+ encoded.append(token)
46
+ return encoded.decode("utf-8")
47
+
48
+
49
+ class HashingTextVectorizer:
50
+ """Fixed-width counts of Unicode character n-grams, with stable hashing.
51
+
52
+ NFC normalization and optional casefolding are applied only to features.
53
+ Hash collisions are possible; these are lexical features, not semantic
54
+ embeddings. ``normalize=True`` scales each vector to unit Euclidean norm.
55
+ Empty text produces zeros. Configuration must match training and inference.
56
+ """
57
+
58
+ def __init__(self, n_features=256, *, ngram_range=(1, 3), lowercase=True,
59
+ normalize=True, max_chars=100_000):
60
+ self.n_features = _positive_integer(n_features, "n_features")
61
+ if self.n_features > 65_536:
62
+ raise ValueError("n_features must not exceed 65536")
63
+ if not isinstance(ngram_range, (tuple, list)) or len(ngram_range) != 2:
64
+ raise ValueError("ngram_range must contain two integers")
65
+ low, high = ngram_range
66
+ if type(low) is not int or type(high) is not int or not 1 <= low <= high <= 8:
67
+ raise ValueError("ngram_range must satisfy 1 <= low <= high <= 8")
68
+ if type(lowercase) is not bool or type(normalize) is not bool:
69
+ raise TypeError("lowercase and normalize must be booleans")
70
+ self.ngram_range = (low, high)
71
+ self.lowercase = lowercase
72
+ self.normalize = normalize
73
+ self.max_chars = _positive_integer(max_chars, "max_chars")
74
+
75
+ def transform(self, text):
76
+ if not isinstance(text, str):
77
+ raise TypeError("text must be a string")
78
+ if len(text) > self.max_chars:
79
+ raise ValueError("text exceeds max_chars")
80
+ text = unicodedata.normalize("NFC", text.casefold() if self.lowercase else text)
81
+ if len(text) > self.max_chars:
82
+ raise ValueError("normalized text exceeds max_chars")
83
+ vector = [0.0] * self.n_features
84
+ for width in range(self.ngram_range[0], self.ngram_range[1] + 1):
85
+ for offset in range(len(text) - width + 1):
86
+ digest = hashlib.blake2b(text[offset:offset + width].encode("utf-8"),
87
+ digest_size=8).digest()
88
+ index = int.from_bytes(digest, "big") % self.n_features
89
+ vector[index] += 1.0
90
+ if self.normalize:
91
+ norm = math.sqrt(sum(value * value for value in vector))
92
+ if norm:
93
+ vector = [value / norm for value in vector]
94
+ return vector
95
+
96
+ def transform_batch(self, texts):
97
+ """Transform a batch; the caller controls the number of documents."""
98
+ if isinstance(texts, str):
99
+ raise TypeError("texts must be an iterable of strings, not a string")
100
+ return [self.transform(text) for text in texts]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wsbuilder
3
- Version: 1.2.13
3
+ Version: 1.3.0
4
4
  Summary: Lightweight HTTP + WebSocket framework for Python.
5
5
  Author: wsbuilder Authors
6
6
  License-Expression: MIT
@@ -64,6 +64,8 @@ src/wsbuilder/http3.py
64
64
  src/wsbuilder/http3_server.py
65
65
  src/wsbuilder/http3_websocket.py
66
66
  src/wsbuilder/ia.py
67
+ src/wsbuilder/ia_audio.py
68
+ src/wsbuilder/ia_text.py
67
69
  src/wsbuilder/logs.py
68
70
  src/wsbuilder/mdns.py
69
71
  src/wsbuilder/metrics.py
@@ -110,6 +112,7 @@ tests/test_http3_server.py
110
112
  tests/test_http3_streaming.py
111
113
  tests/test_http3_streaming_udp.py
112
114
  tests/test_ia.py
115
+ tests/test_ia_text_audio.py
113
116
  tests/test_logs.py
114
117
  tests/test_mdns.py
115
118
  tests/test_metrics.py