shadow-tools 0.7.2__tar.gz → 0.8.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 (25) hide show
  1. {shadow_tools-0.7.2 → shadow_tools-0.8.0}/PKG-INFO +17 -1
  2. {shadow_tools-0.7.2 → shadow_tools-0.8.0}/README.md +16 -0
  3. {shadow_tools-0.7.2 → shadow_tools-0.8.0}/pyproject.toml +1 -1
  4. {shadow_tools-0.7.2 → shadow_tools-0.8.0}/src/shadowtools/__init__.py +4 -4
  5. {shadow_tools-0.7.2 → shadow_tools-0.8.0}/src/shadowtools/generator.py +23 -1
  6. {shadow_tools-0.7.2 → shadow_tools-0.8.0}/.gitignore +0 -0
  7. {shadow_tools-0.7.2 → shadow_tools-0.8.0}/LICENSE +0 -0
  8. {shadow_tools-0.7.2 → shadow_tools-0.8.0}/src/shadowtools/ai.py +0 -0
  9. {shadow_tools-0.7.2 → shadow_tools-0.8.0}/src/shadowtools/async_tools.py +0 -0
  10. {shadow_tools-0.7.2 → shadow_tools-0.8.0}/src/shadowtools/bpe.py +0 -0
  11. {shadow_tools-0.7.2 → shadow_tools-0.8.0}/src/shadowtools/cli.py +0 -0
  12. {shadow_tools-0.7.2 → shadow_tools-0.8.0}/src/shadowtools/config.py +0 -0
  13. {shadow_tools-0.7.2 → shadow_tools-0.8.0}/src/shadowtools/data.py +0 -0
  14. {shadow_tools-0.7.2 → shadow_tools-0.8.0}/src/shadowtools/files.py +0 -0
  15. {shadow_tools-0.7.2 → shadow_tools-0.8.0}/src/shadowtools/hashing.py +0 -0
  16. {shadow_tools-0.7.2 → shadow_tools-0.8.0}/src/shadowtools/http.py +0 -0
  17. {shadow_tools-0.7.2 → shadow_tools-0.8.0}/src/shadowtools/ids.py +0 -0
  18. {shadow_tools-0.7.2 → shadow_tools-0.8.0}/src/shadowtools/network.py +0 -0
  19. {shadow_tools-0.7.2 → shadow_tools-0.8.0}/src/shadowtools/retry.py +0 -0
  20. {shadow_tools-0.7.2 → shadow_tools-0.8.0}/src/shadowtools/security.py +0 -0
  21. {shadow_tools-0.7.2 → shadow_tools-0.8.0}/src/shadowtools/text.py +0 -0
  22. {shadow_tools-0.7.2 → shadow_tools-0.8.0}/src/shadowtools/training.py +0 -0
  23. {shadow_tools-0.7.2 → shadow_tools-0.8.0}/src/shadowtools/validation.py +0 -0
  24. {shadow_tools-0.7.2 → shadow_tools-0.8.0}/src/shadowtools/websocket.py +0 -0
  25. {shadow_tools-0.7.2 → shadow_tools-0.8.0}/tests/test_core.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: shadow-tools
3
- Version: 0.7.2
3
+ Version: 0.8.0
4
4
  Summary: A practical all-in-one Python toolkit for HTTP, WebSockets, files, data, validation, async work, and CLIs.
5
5
  Project-URL: Homepage, https://github.com/WilliamLaurento/shadow-tools
6
6
  Project-URL: Issues, https://github.com/WilliamLaurento/shadow-tools/issues
@@ -76,6 +76,22 @@ bot.save("my_text_model")
76
76
  Training prints the tokenizer status plus each epoch and loss. Use
77
77
  `learn("corpus.txt", epochs=20, verbose=False)` when you do not want updates.
78
78
 
79
+ ## Train a question-and-answer bot
80
+
81
+ ```python
82
+ from shadowtools import ask, teach
83
+
84
+ bot = teach({
85
+ "What is ChatGPT?": "ChatGPT is an AI system that predicts useful next tokens to answer a prompt.",
86
+ "How does a tokenizer work?": "A tokenizer splits text into smaller tokens a model can process.",
87
+ "What is machine learning?": "Machine learning is when a model learns patterns from examples.",
88
+ }, epochs=20)
89
+
90
+ print(ask(bot, "What is ChatGPT?"))
91
+ ```
92
+
93
+ Add many more real Q&A pairs for better answers.
94
+
79
95
  Install it with `pip install "shadow-tools[ml,nlp]"`. The package trains the
80
96
  tokenizer and Transformer together, then converts predicted token IDs back to
81
97
  normal text for you.
@@ -48,6 +48,22 @@ bot.save("my_text_model")
48
48
  Training prints the tokenizer status plus each epoch and loss. Use
49
49
  `learn("corpus.txt", epochs=20, verbose=False)` when you do not want updates.
50
50
 
51
+ ## Train a question-and-answer bot
52
+
53
+ ```python
54
+ from shadowtools import ask, teach
55
+
56
+ bot = teach({
57
+ "What is ChatGPT?": "ChatGPT is an AI system that predicts useful next tokens to answer a prompt.",
58
+ "How does a tokenizer work?": "A tokenizer splits text into smaller tokens a model can process.",
59
+ "What is machine learning?": "Machine learning is when a model learns patterns from examples.",
60
+ }, epochs=20)
61
+
62
+ print(ask(bot, "What is ChatGPT?"))
63
+ ```
64
+
65
+ Add many more real Q&A pairs for better answers.
66
+
51
67
  Install it with `pip install "shadow-tools[ml,nlp]"`. The package trains the
52
68
  tokenizer and Transformer together, then converts predicted token IDs back to
53
69
  normal text for you.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "shadow-tools"
7
- version = "0.7.2"
7
+ version = "0.8.0"
8
8
  description = "A practical all-in-one Python toolkit for HTTP, WebSockets, files, data, validation, async work, and CLIs."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -5,7 +5,7 @@ from .bpe import BPETokenizer
5
5
  from .config import env, require_env, to_bool
6
6
  from .files import append_text, ensure_dir, read_text, write_text
7
7
  from .hashing import file_hash, hash_text
8
- from .generator import GeneratorConfig, TextGenerator, generate_text, learn, say, train_generator
8
+ from .generator import GeneratorConfig, TextGenerator, ask, generate_text, learn, say, teach, train_generator
9
9
  from .http import get, request
10
10
  from .ids import random_token, timestamp_id, uuid4
11
11
  from .network import generate_random_ips, generate_test_ips, is_subdomain_of, make_subdomain, resolve_dns, reverse_dns
@@ -15,10 +15,10 @@ from .text import chunks, slugify, to_camel, to_snake
15
15
  from .training import SmartTokenizer, fine_tune, make_loaders, predict_text, train, train_text
16
16
  from .validation import is_email, is_url, require_keys
17
17
 
18
- __version__ = "0.7.2"
18
+ __version__ = "0.8.0"
19
19
 
20
20
  __all__ = [
21
- "append_text", "audit_headers", "BPETokenizer", "chunks", "ensure_dir", "env", "file_hash", "GeneratorConfig", "generate_random_ips", "generate_test_ips", "generate_text", "get", "hash_text", "is_email", "is_subdomain_of", "is_url", "learn", "make_password", "make_subdomain", "random_token", "read_csv",
22
- "read_json", "read_text", "request", "require_env", "require_keys", "retry", "reverse_dns", "resolve_dns", "say", "slugify", "timestamp_id", "to_bool", "to_camel", "to_snake", "TextGenerator", "train", "train_generator", "fine_tune", "make_loaders", "SmartTokenizer", "train_text", "predict_text", "uuid4", "write_csv",
21
+ "append_text", "ask", "audit_headers", "BPETokenizer", "chunks", "ensure_dir", "env", "file_hash", "GeneratorConfig", "generate_random_ips", "generate_test_ips", "generate_text", "get", "hash_text", "is_email", "is_subdomain_of", "is_url", "learn", "make_password", "make_subdomain", "random_token", "read_csv",
22
+ "read_json", "read_text", "request", "require_env", "require_keys", "retry", "reverse_dns", "resolve_dns", "say", "slugify", "teach", "timestamp_id", "to_bool", "to_camel", "to_snake", "TextGenerator", "train", "train_generator", "fine_tune", "make_loaders", "SmartTokenizer", "train_text", "predict_text", "uuid4", "write_csv",
23
23
  "write_json", "write_text", "redact_secrets", "verify_file_hash",
24
24
  ]
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
 
4
4
  from dataclasses import asdict, dataclass
5
5
  from pathlib import Path
6
- from typing import Any, Sequence
6
+ from typing import Any, Mapping, Sequence
7
7
 
8
8
  from .bpe import BPETokenizer
9
9
 
@@ -226,3 +226,25 @@ def learn(source: str | Path | Sequence[str], *, epochs: int = 10,
226
226
  def say(generator: TextGenerator, prompt: str, **options: Any) -> str:
227
227
  """Beginner-friendly name for generating text from a trained model."""
228
228
  return generator.generate(prompt, **options)
229
+
230
+
231
+ def teach(questions_and_answers: Mapping[str, str] | Sequence[tuple[str, str]], *,
232
+ epochs: int = 10, verbose: bool = True, **options: Any) -> TextGenerator:
233
+ """Train a small Q&A bot from question-and-answer pairs."""
234
+ pairs = list(questions_and_answers.items()) if isinstance(questions_and_answers, Mapping) else list(questions_and_answers)
235
+ if len(pairs) < 2:
236
+ raise ValueError("Give teach() at least two question-and-answer pairs.")
237
+ sections: list[str] = []
238
+ for question, answer in pairs:
239
+ if not isinstance(question, str) or not isinstance(answer, str) or not question.strip() or not answer.strip():
240
+ raise ValueError("Every question and answer must be non-empty text.")
241
+ sections.append(f"Question: {question.strip()}\nAnswer: {answer.strip()}")
242
+ return learn("\n\n".join(sections), epochs=epochs, verbose=verbose, **options)
243
+
244
+
245
+ def ask(generator: TextGenerator, question: str, *, max_tokens: int = 200,
246
+ **options: Any) -> str:
247
+ """Ask a Q&A bot a question and get its generated answer."""
248
+ if not isinstance(question, str) or not question.strip():
249
+ raise ValueError("question must be non-empty text.")
250
+ return generator.generate(f"Question: {question.strip()}\nAnswer:", max_tokens=max_tokens, **options)
File without changes
File without changes