pythonai-grounded-generator 0.1.0__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.
@@ -0,0 +1,5 @@
1
+ """Helpers for grounded generation with an already loaded causal language model."""
2
+
3
+ from .core import generate_answer
4
+
5
+ __all__ = ["generate_answer"]
@@ -0,0 +1,91 @@
1
+ """Grounded answer generation with configurable prompts and token budgets."""
2
+
3
+ from typing import Any
4
+
5
+ import torch
6
+
7
+
8
+ def generate_answer(
9
+ model: Any,
10
+ tokenizer: Any,
11
+ question: str,
12
+ context: str,
13
+ system_prompt: str,
14
+ max_new_tokens: int = 64,
15
+ device: str = "cpu",
16
+ ) -> str:
17
+ """Generate an answer using a preloaded model and retrieved context.
18
+
19
+ The caller owns retrieval, augmentation, model loading, and output schema.
20
+ This function formats the prompt, truncates context to the token budget,
21
+ generates an answer, and returns only the decoded completion.
22
+
23
+ Raises:
24
+ ValueError: If inputs are invalid or the prompt exceeds the budget.
25
+ """
26
+ if not question.strip() or not system_prompt.strip():
27
+ raise ValueError("Question and system prompt must not be empty")
28
+ if max_new_tokens <= 0:
29
+ raise ValueError("max_new_tokens must be positive")
30
+
31
+ user_prefix = "Retrieved context:\n"
32
+ user_suffix = (
33
+ f"\n\nQuestion:\n{question}\n\n"
34
+ "Important: copy technical identifiers exactly as written "
35
+ "in the retrieved context."
36
+ )
37
+ messages = [
38
+ {"role": "system", "content": system_prompt},
39
+ {"role": "user", "content": user_prefix + user_suffix},
40
+ ]
41
+
42
+ # Count tokens needed even when the retrieved context is empty.
43
+ fixed_ids = tokenizer.apply_chat_template(
44
+ messages,
45
+ tokenize=True,
46
+ return_dict=False,
47
+ add_generation_prompt=True,
48
+ enable_thinking=False,
49
+ )
50
+ model_limit = getattr(model.config, "max_position_embeddings", 32768)
51
+ budget = model_limit - len(fixed_ids) - max_new_tokens - 32
52
+ if budget <= 0:
53
+ raise ValueError("Not enough token budget for the prompt")
54
+
55
+ context_ids = tokenizer(
56
+ context,
57
+ add_special_tokens=False,
58
+ truncation=True,
59
+ max_length=budget,
60
+ )["input_ids"]
61
+ trimmed_context = tokenizer.decode(context_ids, skip_special_tokens=True)
62
+ messages[1]["content"] = user_prefix + trimmed_context + user_suffix
63
+
64
+ prompt = tokenizer.apply_chat_template(
65
+ messages,
66
+ tokenize=False,
67
+ add_generation_prompt=True,
68
+ enable_thinking=False,
69
+ )
70
+ inputs = tokenizer(
71
+ prompt,
72
+ return_tensors="pt",
73
+ add_special_tokens=False,
74
+ ).to(device)
75
+ input_length = inputs["input_ids"].shape[1]
76
+ if input_length + max_new_tokens > model_limit:
77
+ raise ValueError("Prompt exceeds the model token budget")
78
+
79
+ with torch.inference_mode():
80
+ output = model.generate(
81
+ **inputs,
82
+ max_new_tokens=max_new_tokens,
83
+ do_sample=False,
84
+ eos_token_id=tokenizer.eos_token_id,
85
+ pad_token_id=tokenizer.eos_token_id,
86
+ )
87
+
88
+ return tokenizer.decode(
89
+ output[0][input_length:],
90
+ skip_special_tokens=True,
91
+ ).strip()
File without changes
@@ -0,0 +1,88 @@
1
+ Metadata-Version: 2.4
2
+ Name: pythonai-grounded-generator
3
+ Version: 0.1.0
4
+ Summary: Lightweight grounded text generation from retrieved context
5
+ Keywords: llm,rag,grounded-generation,transformers,qwen
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: Programming Language :: Python :: 3 :: Only
8
+ Classifier: Operating System :: OS Independent
9
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
10
+ Requires-Python: >=3.10
11
+ Description-Content-Type: text/markdown
12
+ Requires-Dist: torch>=2.2
13
+ Requires-Dist: transformers>=4.51.0
14
+
15
+ # PythonAI Grounded Generator
16
+
17
+ A compact Python helper for generating answers from retrieved context with an already loaded Hugging Face causal language model.
18
+
19
+ It provides:
20
+
21
+ - Custom system prompts and questions
22
+ - Token-budget-aware context truncation
23
+ - Qwen3 non-thinking chat formatting
24
+ - CPU or CUDA inference (device controlled by the caller)
25
+ - A plain-text answer suitable for wrapping in application-specific Pydantic models
26
+
27
+ Retrieval, context assembly, and structured JSON serialization remain the responsibility of the calling application. This package does **not** guarantee factual correctness or replace source validation.
28
+
29
+ ## Installation
30
+
31
+ After publication:
32
+
33
+ ```bash
34
+ pip install pythonai-grounded-generator
35
+ ```
36
+
37
+ Or install the local project:
38
+
39
+ ```bash
40
+ pip install .
41
+ ```
42
+
43
+ ## Example
44
+
45
+ ```python
46
+ from transformers import AutoModelForCausalLM, AutoTokenizer
47
+ from pythonai_grounded import generate_answer
48
+
49
+ name = "Qwen/Qwen3-0.6B"
50
+ tokenizer = AutoTokenizer.from_pretrained(name)
51
+ model = AutoModelForCausalLM.from_pretrained(name).to("cpu")
52
+ model.eval()
53
+
54
+ answer = generate_answer(
55
+ model=model,
56
+ tokenizer=tokenizer,
57
+ question="Which endpoint loads an adapter?",
58
+ context="Use POST /v1/load_lora_adapter to load an adapter.",
59
+ system_prompt="Answer only from the context. Copy technical names exactly.",
60
+ max_new_tokens=64,
61
+ device="cpu",
62
+ )
63
+ print(answer)
64
+ ```
65
+
66
+ ## API
67
+
68
+ ```python
69
+ generate_answer(
70
+ model,
71
+ tokenizer,
72
+ question: str,
73
+ context: str,
74
+ system_prompt: str,
75
+ max_new_tokens: int = 64,
76
+ device: str = "cpu",
77
+ ) -> str
78
+ ```
79
+
80
+ The supplied `model` and `tokenizer` must be compatible. The model must already be on the requested device and in evaluation mode. Model context limits are read from `model.config.max_position_embeddings`, falling back to 32768 if absent. Check actual model capabilities when switching models.
81
+
82
+ ## Build
83
+
84
+ ```bash
85
+ uv build
86
+ ```
87
+
88
+ The distributions are created in `dist/`.
@@ -0,0 +1,7 @@
1
+ pythonai_grounded/__init__.py,sha256=VoALTJM08Vfh4Rt44qVd-xz_htWNsd2Rko18TWaw1w0,150
2
+ pythonai_grounded/core.py,sha256=V57eiU8LCgEAkdcNt8CkE2t69J-wI4mXLlQWiCpxb7Y,2879
3
+ pythonai_grounded/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ pythonai_grounded_generator-0.1.0.dist-info/METADATA,sha256=eediSxZCziHVRvbOiaxe_ubdGJsUgAjir-4gPVbmAdw,2494
5
+ pythonai_grounded_generator-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
6
+ pythonai_grounded_generator-0.1.0.dist-info/top_level.txt,sha256=WXeBLJShJI8NUnf3iz8bPytvdXFTcG7gwbnOFsc7VvA,18
7
+ pythonai_grounded_generator-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ pythonai_grounded