structguard 0.1.2__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 (36) hide show
  1. structguard-0.1.2/.env.example +25 -0
  2. structguard-0.1.2/LICENSE +21 -0
  3. structguard-0.1.2/PKG-INFO +126 -0
  4. structguard-0.1.2/README.md +84 -0
  5. structguard-0.1.2/examples/README.md +42 -0
  6. structguard-0.1.2/examples/anthropic_example.py +63 -0
  7. structguard-0.1.2/examples/dataclass_example.py +54 -0
  8. structguard-0.1.2/examples/error_handling_example.py +80 -0
  9. structguard-0.1.2/examples/gemini_example.py +78 -0
  10. structguard-0.1.2/examples/groq_example.py +77 -0
  11. structguard-0.1.2/examples/json_schema_example.py +53 -0
  12. structguard-0.1.2/examples/ollama_example.py +67 -0
  13. structguard-0.1.2/examples/openai_example.py +63 -0
  14. structguard-0.1.2/examples/typeddict_example.py +49 -0
  15. structguard-0.1.2/pyproject.toml +49 -0
  16. structguard-0.1.2/src/structguard/__init__.py +34 -0
  17. structguard-0.1.2/src/structguard/adapters/__init__.py +35 -0
  18. structguard-0.1.2/src/structguard/adapters/anthropic_adapter.py +34 -0
  19. structguard-0.1.2/src/structguard/adapters/base.py +42 -0
  20. structguard-0.1.2/src/structguard/adapters/gemini_adapter.py +36 -0
  21. structguard-0.1.2/src/structguard/adapters/groq_adapter.py +38 -0
  22. structguard-0.1.2/src/structguard/adapters/ollama_adapter.py +35 -0
  23. structguard-0.1.2/src/structguard/adapters/openai_adapter.py +38 -0
  24. structguard-0.1.2/src/structguard/core.py +153 -0
  25. structguard-0.1.2/src/structguard/exceptions.py +62 -0
  26. structguard-0.1.2/src/structguard/logging_utils.py +47 -0
  27. structguard-0.1.2/src/structguard/repair.py +125 -0
  28. structguard-0.1.2/src/structguard/report.py +62 -0
  29. structguard-0.1.2/src/structguard/retry.py +15 -0
  30. structguard-0.1.2/src/structguard/schema/__init__.py +3 -0
  31. structguard-0.1.2/src/structguard/schema/engine.py +100 -0
  32. structguard-0.1.2/src/structguard/validator.py +59 -0
  33. structguard-0.1.2/tests/test_core.py +74 -0
  34. structguard-0.1.2/tests/test_repair.py +47 -0
  35. structguard-0.1.2/tests/test_schema_engine.py +71 -0
  36. structguard-0.1.2/tests/test_validator.py +40 -0
@@ -0,0 +1,25 @@
1
+ # ---------------------------------------------------------------------------
2
+ # StructGuard examples — dummy environment file
3
+ # Copy to `.env` (already named .env here) and replace with your real keys.
4
+ # Loaded automatically by each example via python-dotenv's load_dotenv().
5
+ # NEVER commit a real .env file to version control — add it to .gitignore.
6
+ # ---------------------------------------------------------------------------
7
+
8
+ # --- Groq ---
9
+ GROQ_API_KEY=gsk_dummy_replace_with_your_real_groq_api_key
10
+ GROQ_MODEL=llama-3.3-70b-versatile # Replace with any other model
11
+
12
+ # --- OpenAI ---
13
+ OPENAI_API_KEY=sk-dummy_replace_with_your_real_openai_api_key
14
+ OPENAI_MODEL=gpt-4o-mini # Replace with any other model
15
+
16
+ # --- Anthropic ---
17
+ ANTHROPIC_API_KEY=sk-ant-dummy_replace_with_your_real_anthropic_api_key
18
+ ANTHROPIC_MODEL=claude-sonnet-4-6 # Replace with any other model
19
+
20
+ # --- Google Gemini ---
21
+ GOOGLE_API_KEY=dummy_replace_with_your_real_google_api_key
22
+ GEMINI_MODEL=gemini-1.5-pro # Replace with any other model
23
+
24
+ # --- Ollama (local, no key needed, only model name matters) ---
25
+ OLLAMA_MODEL=llama3.1 # Replace with any other model
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sujan Ghosh
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,126 @@
1
+ Metadata-Version: 2.4
2
+ Name: structguard
3
+ Version: 0.1.2
4
+ Summary: Reliable, provider-agnostic structured outputs for production LLM applications.
5
+ Project-URL: Homepage, https://github.com/yourusername/structguard
6
+ Project-URL: Repository, https://github.com/yourusername/structguard
7
+ Project-URL: Issues, https://github.com/yourusername/structguard/issues
8
+ Author-email: Sujan Ghosh <rupubally@gmail.com>
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: anthropic,gemini,json,llm,openai,pydantic,structured-output,validation
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.9
22
+ Requires-Dist: pydantic>=2.0
23
+ Provides-Extra: all
24
+ Requires-Dist: anthropic>=0.30; extra == 'all'
25
+ Requires-Dist: google-generativeai>=0.5; extra == 'all'
26
+ Requires-Dist: groq>=0.5; extra == 'all'
27
+ Requires-Dist: openai>=1.0; extra == 'all'
28
+ Provides-Extra: anthropic
29
+ Requires-Dist: anthropic>=0.30; extra == 'anthropic'
30
+ Provides-Extra: dev
31
+ Requires-Dist: build; extra == 'dev'
32
+ Requires-Dist: pytest-cov; extra == 'dev'
33
+ Requires-Dist: pytest>=7.0; extra == 'dev'
34
+ Requires-Dist: twine; extra == 'dev'
35
+ Provides-Extra: gemini
36
+ Requires-Dist: google-generativeai>=0.5; extra == 'gemini'
37
+ Provides-Extra: groq
38
+ Requires-Dist: groq>=0.5; extra == 'groq'
39
+ Provides-Extra: openai
40
+ Requires-Dist: openai>=1.0; extra == 'openai'
41
+ Description-Content-Type: text/markdown
42
+
43
+ # StructGuard
44
+
45
+ **Reliable, provider-agnostic structured outputs for production LLM applications.**
46
+
47
+ StructGuard makes sure every LLM response conforms to a schema you define —
48
+ `Pydantic`, `dataclass`, `TypedDict`, or raw JSON Schema — before it reaches
49
+ your application code. It handles prompting, JSON repair, validation, and
50
+ intelligent retries in one call, across OpenAI, Anthropic, Gemini, Groq, and
51
+ Ollama.
52
+
53
+ ## Install
54
+
55
+ ```bash
56
+ pip install structguard # core only
57
+ pip install structguard[openai] # + OpenAI SDK
58
+ pip install structguard[anthropic] # + Anthropic SDK
59
+ pip install structguard[all] # every provider SDK
60
+ ```
61
+
62
+ ## Quick start
63
+
64
+ ```python
65
+ from pydantic import BaseModel
66
+ from openai import OpenAI
67
+ from structguard import generate
68
+
69
+ class Incident(BaseModel):
70
+ summary: str
71
+ priority: str
72
+ confidence: float
73
+
74
+ client = OpenAI()
75
+
76
+ incident = generate(
77
+ llm=client,
78
+ prompt="Summarize this incident: Database connection pool exhausted, causing 500s.",
79
+ schema=Incident,
80
+ )
81
+
82
+ print(incident.summary, incident.priority, incident.confidence)
83
+ ```
84
+
85
+ ## With a full report
86
+
87
+ ```python
88
+ result = generate(llm=client, prompt=prompt, schema=Incident, return_report=True)
89
+ print(result.data)
90
+ print(result.report) # ✓ Success | provider=OpenAI model=gpt-4o-mini retries=0 ...
91
+ ```
92
+
93
+ ## Error handling
94
+
95
+ ```python
96
+ from structguard import RetryLimitExceeded, SchemaValidationError
97
+
98
+ try:
99
+ incident = generate(llm=client, prompt=prompt, schema=Incident, max_retries=2)
100
+ except RetryLimitExceeded as e:
101
+ print(f"Gave up after {e.attempts} attempts: {e.last_error}")
102
+ ```
103
+
104
+ ## Supported schema types
105
+
106
+ - `pydantic.BaseModel`
107
+ - stdlib `@dataclass`
108
+ - `TypedDict`
109
+ - raw JSON Schema `dict`
110
+
111
+ ## Supported providers
112
+
113
+ OpenAI · Anthropic · Google Gemini · Groq · Ollama
114
+
115
+ ## Development
116
+
117
+ ```bash
118
+ git clone https://github.com/sujanrupu/structguard
119
+ cd structguard
120
+ pip install -e ".[dev]"
121
+ pytest
122
+ ```
123
+
124
+ ## License
125
+
126
+ MIT
@@ -0,0 +1,84 @@
1
+ # StructGuard
2
+
3
+ **Reliable, provider-agnostic structured outputs for production LLM applications.**
4
+
5
+ StructGuard makes sure every LLM response conforms to a schema you define —
6
+ `Pydantic`, `dataclass`, `TypedDict`, or raw JSON Schema — before it reaches
7
+ your application code. It handles prompting, JSON repair, validation, and
8
+ intelligent retries in one call, across OpenAI, Anthropic, Gemini, Groq, and
9
+ Ollama.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ pip install structguard # core only
15
+ pip install structguard[openai] # + OpenAI SDK
16
+ pip install structguard[anthropic] # + Anthropic SDK
17
+ pip install structguard[all] # every provider SDK
18
+ ```
19
+
20
+ ## Quick start
21
+
22
+ ```python
23
+ from pydantic import BaseModel
24
+ from openai import OpenAI
25
+ from structguard import generate
26
+
27
+ class Incident(BaseModel):
28
+ summary: str
29
+ priority: str
30
+ confidence: float
31
+
32
+ client = OpenAI()
33
+
34
+ incident = generate(
35
+ llm=client,
36
+ prompt="Summarize this incident: Database connection pool exhausted, causing 500s.",
37
+ schema=Incident,
38
+ )
39
+
40
+ print(incident.summary, incident.priority, incident.confidence)
41
+ ```
42
+
43
+ ## With a full report
44
+
45
+ ```python
46
+ result = generate(llm=client, prompt=prompt, schema=Incident, return_report=True)
47
+ print(result.data)
48
+ print(result.report) # ✓ Success | provider=OpenAI model=gpt-4o-mini retries=0 ...
49
+ ```
50
+
51
+ ## Error handling
52
+
53
+ ```python
54
+ from structguard import RetryLimitExceeded, SchemaValidationError
55
+
56
+ try:
57
+ incident = generate(llm=client, prompt=prompt, schema=Incident, max_retries=2)
58
+ except RetryLimitExceeded as e:
59
+ print(f"Gave up after {e.attempts} attempts: {e.last_error}")
60
+ ```
61
+
62
+ ## Supported schema types
63
+
64
+ - `pydantic.BaseModel`
65
+ - stdlib `@dataclass`
66
+ - `TypedDict`
67
+ - raw JSON Schema `dict`
68
+
69
+ ## Supported providers
70
+
71
+ OpenAI · Anthropic · Google Gemini · Groq · Ollama
72
+
73
+ ## Development
74
+
75
+ ```bash
76
+ git clone https://github.com/sujanrupu/structguard
77
+ cd structguard
78
+ pip install -e ".[dev]"
79
+ pytest
80
+ ```
81
+
82
+ ## License
83
+
84
+ MIT
@@ -0,0 +1,42 @@
1
+ # StructGuard Examples
2
+
3
+ Each script is runnable on its own once you `pip install` the right extra and
4
+ export the relevant API key.
5
+
6
+ | Script | Shows |
7
+ |---|---|
8
+ | `openai_example.py` | Basic usage with OpenAI + Pydantic schema + report |
9
+ | `anthropic_example.py` | Same, with Anthropic (drop-in client swap) |
10
+ | `gemini_example.py` | Gemini — note on `GenerativeModel` instance requirement |
11
+ | `groq_example.py` | Groq — note on model selection / JSON mode support |
12
+ | `ollama_example.py` | Fully local, no API key |
13
+ | `dataclass_example.py` | Using a stdlib `@dataclass` instead of Pydantic |
14
+ | `typeddict_example.py` | Using `TypedDict` |
15
+ | `json_schema_example.py` | Using a raw JSON Schema dict (no Python class) |
16
+ | `error_handling_example.py` | Catching `RetryLimitExceeded`, `SchemaValidationError`, etc. + debug logging |
17
+
18
+ ## Run any example
19
+
20
+ ```bash
21
+ pip install structguard[openai] # or [anthropic], [gemini], [groq]
22
+ export OPENAI_API_KEY=sk-... # matching env var for the provider
23
+ python examples/openai_example.py
24
+ ```
25
+
26
+ ## Gemini quirk to know
27
+
28
+ `llm=` must be a `genai.GenerativeModel(...)` instance, not the `google.generativeai`
29
+ module itself:
30
+
31
+ ```python
32
+ import google.generativeai as genai
33
+ genai.configure()
34
+ model = genai.GenerativeModel("gemini-1.5-pro") # <- pass this to generate()
35
+ ```
36
+
37
+ ## Groq quirk to know
38
+
39
+ Groq's client is OpenAI-compatible (`.chat.completions.create()`), but the
40
+ `model=` string must match a currently-hosted Groq model ID that supports
41
+ JSON mode — check https://console.groq.com/docs/models since the lineup
42
+ changes over time.
@@ -0,0 +1,63 @@
1
+ """
2
+ StructGuard + Anthropic
3
+ =========================
4
+ Install:
5
+ pip install structguard[anthropic] python-dotenv
6
+
7
+ Setup:
8
+ Put ANTHROPIC_API_KEY and ANTHROPIC_MODEL in a `.env` file next to this
9
+ script (see the provided dummy .env for the expected format).
10
+
11
+ Run:
12
+ python anthropic_example.py
13
+ """
14
+ import os
15
+ from dotenv import load_dotenv
16
+ from pydantic import BaseModel
17
+ from anthropic import Anthropic
18
+
19
+ from structguard import generate, RetryLimitExceeded
20
+
21
+ load_dotenv()
22
+
23
+ MODEL_NAME = os.getenv("ANTHROPIC_MODEL", "claude-sonnet-4-6")
24
+
25
+
26
+ class Incident(BaseModel):
27
+ summary: str
28
+ priority: str
29
+ confidence: float
30
+
31
+
32
+ def main():
33
+ client = Anthropic() # reads ANTHROPIC_API_KEY from env (loaded via load_dotenv above)
34
+
35
+ prompt = (
36
+ "Summarize this incident: Database connection pool exhausted, "
37
+ "causing intermittent 500 errors on the checkout service since 14:02 UTC."
38
+ )
39
+
40
+ try:
41
+ result = generate(
42
+ llm=client,
43
+ prompt=prompt,
44
+ schema=Incident,
45
+ model=MODEL_NAME,
46
+ max_retries=2,
47
+ return_report=True,
48
+ )
49
+ except RetryLimitExceeded as e:
50
+ print(f"Gave up after {e.attempts} attempts: {e.last_error}")
51
+ return
52
+
53
+ incident = result.data
54
+ print("Model used:", MODEL_NAME)
55
+ print("Summary: ", incident.summary)
56
+ print("Priority: ", incident.priority)
57
+ print("Confidence:", incident.confidence)
58
+ print()
59
+ print("Report:", result.report)
60
+
61
+
62
+ if __name__ == "__main__":
63
+ main()
@@ -0,0 +1,54 @@
1
+ """
2
+ StructGuard with a stdlib dataclass schema (works with any provider — Groq shown here).
3
+
4
+ Install:
5
+ pip install structguard[groq] python-dotenv
6
+
7
+ Setup:
8
+ Put GROQ_API_KEY and GROQ_MODEL in a `.env` file next to this script.
9
+
10
+ Run:
11
+ python dataclass_example.py
12
+ """
13
+ import os
14
+ from dataclasses import dataclass
15
+ from dotenv import load_dotenv
16
+ from groq import Groq
17
+
18
+ from structguard import generate
19
+
20
+ load_dotenv()
21
+
22
+ MODEL_NAME = os.getenv("GROQ_MODEL", "llama-3.3-70b-versatile")
23
+
24
+
25
+ @dataclass
26
+ class TicketSummary:
27
+ title: str
28
+ category: str
29
+ urgent: bool
30
+
31
+
32
+ def main():
33
+ client = Groq(api_key=os.getenv("GROQ_API_KEY"))
34
+
35
+ ticket_text = (
36
+ "User reports they cannot check out — payment page hangs indefinitely "
37
+ "after clicking 'Pay Now'. Happening for all users since this morning."
38
+ )
39
+
40
+ result = generate(
41
+ llm=client,
42
+ prompt=f"Classify this support ticket:\n\n{ticket_text}",
43
+ schema=TicketSummary,
44
+ model=MODEL_NAME,
45
+ )
46
+
47
+ print("Model used:", MODEL_NAME)
48
+ print(f"Title: {result.title}")
49
+ print(f"Category: {result.category}")
50
+ print(f"Urgent: {result.urgent}")
51
+
52
+
53
+ if __name__ == "__main__":
54
+ main()
@@ -0,0 +1,80 @@
1
+ """
2
+ StructGuard — error handling, retries, and debug logging.
3
+
4
+ Install:
5
+ pip install structguard[anthropic] python-dotenv
6
+
7
+ Setup:
8
+ Put ANTHROPIC_API_KEY and ANTHROPIC_MODEL in a `.env` file next to this
9
+ script.
10
+
11
+ Run:
12
+ python error_handling_example.py
13
+ """
14
+ import logging
15
+ import os
16
+
17
+ from dotenv import load_dotenv
18
+ from pydantic import BaseModel
19
+ from anthropic import Anthropic
20
+
21
+ from structguard import (
22
+ generate,
23
+ RetryLimitExceeded,
24
+ SchemaValidationError,
25
+ JsonRepairError,
26
+ UnsupportedProviderError,
27
+ )
28
+
29
+ load_dotenv()
30
+
31
+ MODEL_NAME = os.getenv("ANTHROPIC_MODEL", "claude-sonnet-4-6")
32
+
33
+
34
+ class Incident(BaseModel):
35
+ summary: str
36
+ priority: str
37
+ confidence: float
38
+
39
+
40
+ def main():
41
+ # Turn on debug logging to see: raw LLM output, whether repair was applied,
42
+ # validation errors per attempt, and retry counts.
43
+ logging.basicConfig(level=logging.DEBUG)
44
+
45
+ client = Anthropic()
46
+
47
+ try:
48
+ result = generate(
49
+ llm=client,
50
+ prompt="Summarize this incident: API gateway returning 502s intermittently.",
51
+ schema=Incident,
52
+ model=MODEL_NAME,
53
+ max_retries=2, # 3 total attempts
54
+ debug=True,
55
+ return_report=True,
56
+ )
57
+ print("Model used:", MODEL_NAME)
58
+ print("Success:", result.data)
59
+ print("Retries needed:", result.report.retries)
60
+
61
+ except RetryLimitExceeded as e:
62
+ # All attempts exhausted — inspect e.attempts and e.last_error
63
+ print(f"Gave up after {e.attempts} attempts.")
64
+ print("Last underlying error:", e.last_error)
65
+
66
+ except SchemaValidationError as e:
67
+ # Only reachable if you call validate()/generate() in a way that
68
+ # surfaces a single validation failure directly (e.g. max_retries=0)
69
+ for err in e.errors:
70
+ print(f" {err['field']}: {err['issue']}")
71
+
72
+ except JsonRepairError as e:
73
+ print("Could not parse the model's output as JSON at all:", e.raw_output[:200])
74
+
75
+ except UnsupportedProviderError:
76
+ print("The `llm=` client isn't a recognized OpenAI/Anthropic/Gemini/Groq/Ollama client.")
77
+
78
+
79
+ if __name__ == "__main__":
80
+ main()
@@ -0,0 +1,78 @@
1
+ """
2
+ StructGuard + Google Gemini
3
+ ==============================
4
+ Install:
5
+ pip install structguard[gemini] python-dotenv
6
+
7
+ Setup:
8
+ Put GOOGLE_API_KEY and GEMINI_MODEL in a `.env` file next to this script
9
+ (see the provided dummy .env for the expected format).
10
+
11
+ Run:
12
+ python gemini_example.py
13
+
14
+ IMPORTANT — Gemini client shape is different from OpenAI/Anthropic:
15
+ Those SDKs give you one client object you call `.chat.completions.create()`
16
+ or `.messages.create()` on. Gemini instead wants you to construct a
17
+ `GenerativeModel` instance *per model name* first, then call
18
+ `.generate_content()` on THAT object.
19
+
20
+ So for StructGuard, the `llm=` argument must be the `GenerativeModel`
21
+ instance (not the top-level `google.generativeai` module, and not the
22
+ result of `genai.configure(...)`, which returns None). That's why we
23
+ build the model using MODEL_NAME from .env below, then pass the model
24
+ object itself into generate().
25
+ """
26
+ import os
27
+ from dotenv import load_dotenv
28
+ from pydantic import BaseModel
29
+ import google.generativeai as genai
30
+
31
+ from structguard import generate, RetryLimitExceeded
32
+
33
+ load_dotenv()
34
+
35
+ MODEL_NAME = os.getenv("GEMINI_MODEL", "gemini-1.5-pro")
36
+
37
+
38
+ class Incident(BaseModel):
39
+ summary: str
40
+ priority: str
41
+ confidence: float
42
+
43
+
44
+ def main():
45
+ genai.configure(api_key=os.getenv("GOOGLE_API_KEY"))
46
+
47
+ # Build the model instance yourself, using the model name from .env —
48
+ # this IS the object you pass as llm=.
49
+ model = genai.GenerativeModel(MODEL_NAME)
50
+
51
+ prompt = (
52
+ "Summarize this incident: Database connection pool exhausted, "
53
+ "causing intermittent 500 errors on the checkout service since 14:02 UTC."
54
+ )
55
+
56
+ try:
57
+ result = generate(
58
+ llm=model, # <-- the GenerativeModel instance, not the genai module
59
+ prompt=prompt,
60
+ schema=Incident,
61
+ max_retries=2,
62
+ return_report=True,
63
+ )
64
+ except RetryLimitExceeded as e:
65
+ print(f"Gave up after {e.attempts} attempts: {e.last_error}")
66
+ return
67
+
68
+ incident = result.data
69
+ print("Model used:", MODEL_NAME)
70
+ print("Summary: ", incident.summary)
71
+ print("Priority: ", incident.priority)
72
+ print("Confidence:", incident.confidence)
73
+ print()
74
+ print("Report:", result.report)
75
+
76
+
77
+ if __name__ == "__main__":
78
+ main()
@@ -0,0 +1,77 @@
1
+ """
2
+ StructGuard + Groq
3
+ =====================
4
+ Install:
5
+ pip install structguard[groq] python-dotenv
6
+
7
+ Setup:
8
+ Put GROQ_API_KEY and GROQ_MODEL in a `.env` file next to this script
9
+ (see the provided dummy .env for the expected format).
10
+
11
+ Run:
12
+ python groq_example.py
13
+
14
+ NOTE on models: Groq hosts several open-weight models (Llama, Mixtral, etc.)
15
+ behind an OpenAI-compatible chat API, so the client shape is identical to
16
+ OpenAI's — `.chat.completions.create()`. The main thing to get right is the
17
+ GROQ_MODEL value in your .env, since it must match one of Groq's currently
18
+ hosted model IDs (these change over time — check
19
+ https://console.groq.com/docs/models for the current list). Not every
20
+ hosted model supports JSON mode; StructGuard requests
21
+ `response_format={"type": "json_object"}` automatically, so pick a model
22
+ that's documented as JSON-mode compatible (most current Llama 3.x models
23
+ on Groq are).
24
+ """
25
+ import os
26
+ from dotenv import load_dotenv
27
+ from pydantic import BaseModel
28
+ from groq import Groq
29
+
30
+ from structguard import generate, RetryLimitExceeded
31
+
32
+ load_dotenv()
33
+
34
+ MODEL_NAME = os.getenv("GROQ_MODEL", "llama-3.3-70b-versatile")
35
+
36
+
37
+ class Incident(BaseModel):
38
+ summary: str
39
+ priority: str
40
+ confidence: float
41
+
42
+
43
+ def main():
44
+ client = Groq(api_key=os.getenv("GROQ_API_KEY")) # explicit, but Groq() also auto-reads GROQ_API_KEY
45
+
46
+ prompt = (
47
+ "Summarize this incident: Database connection pool exhausted, "
48
+ "causing intermittent 500 errors on the checkout service since 14:02 UTC."
49
+ )
50
+
51
+ try:
52
+ result = generate(
53
+ llm=client,
54
+ prompt=prompt,
55
+ schema=Incident,
56
+ model=MODEL_NAME, # <-- pulled from GROQ_MODEL in .env
57
+ max_retries=2,
58
+ return_report=True,
59
+ )
60
+ except RetryLimitExceeded as e:
61
+ print(f"Gave up after {e.attempts} attempts: {e.last_error}")
62
+ return
63
+
64
+ incident = result.data
65
+ print("Model used:", MODEL_NAME)
66
+ print("Summary: ", incident.summary)
67
+ print("Priority: ", incident.priority)
68
+ print("Confidence:", incident.confidence)
69
+ print()
70
+ print("Report:", result.report)
71
+ print()
72
+ print(f"Tokens in/out: {result.report.tokens_input}/{result.report.tokens_output}"
73
+ " (Groq's inference speed makes this a good fit for high-retry-tolerance pipelines)")
74
+
75
+
76
+ if __name__ == "__main__":
77
+ main()