KayO Codex commited on
Commit
8a6fd8e
·
0 Parent(s):

chore: configure legislation explainer project

Browse files
Files changed (6) hide show
  1. .gitignore +13 -0
  2. .python-version +1 -0
  3. config.py +138 -0
  4. pyproject.toml +26 -0
  5. requirements.txt +18 -0
  6. uv.lock +0 -0
.gitignore ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ # env vars
13
+ .env
.python-version ADDED
@@ -0,0 +1 @@
 
 
1
+ 3.12
config.py ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Configuration constants for the NITA bill Gradio app."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ import warnings
7
+ from dataclasses import dataclass
8
+ from pathlib import Path
9
+ from typing import Literal, Optional
10
+
11
+ from dotenv import load_dotenv
12
+
13
+ _PROJECT_ROOT = Path(__file__).resolve().parent
14
+ while _PROJECT_ROOT.name and _PROJECT_ROOT.name not in {"", "."}:
15
+ if (_PROJECT_ROOT / "pyproject.toml").exists():
16
+ break
17
+ if _PROJECT_ROOT.parent == _PROJECT_ROOT:
18
+ break
19
+ _PROJECT_ROOT = _PROJECT_ROOT.parent
20
+
21
+ load_dotenv(dotenv_path=_PROJECT_ROOT / ".env", override=False)
22
+
23
+ # Hugging Face tokenizers can emit fork/parallelism warnings in Gradio dev
24
+ # servers. Default this off unless the environment explicitly overrides it.
25
+ os.environ.setdefault("TOKENIZERS_PARALLELISM", "false")
26
+
27
+ # Suppress a known huggingface_hub deprecation warning emitted during first-time
28
+ # model/tokenizer downloads. It is noisy but not actionable for app users.
29
+ warnings.filterwarnings(
30
+ "ignore",
31
+ message=r"`resume_download` is deprecated and will be removed in version 1\.0\.0\.",
32
+ category=FutureWarning,
33
+ )
34
+
35
+ SUPPORTED_PROVIDERS = ["qwen", "openai", "anthropic", "gemini", "cohere"]
36
+ DEFAULT_PROVIDER: str = "qwen"
37
+ DEFAULT_QWEN_MODEL = "Qwen/Qwen3-32B:cheapest"
38
+ DEFAULT_EMBEDDING_MODEL = "sentence-transformers/all-MiniLM-L6-v2"
39
+ OPENAI_REASONING_EFFORT = "medium"
40
+ ANTHROPIC_THINKING_BUDGET = 2048
41
+ DEFAULT_CHUNK_SIZE = 350
42
+ DEFAULT_CHUNK_OVERLAP = 60
43
+ SCAN_CHUNK_SIZE = 1200
44
+ SCAN_CHUNK_OVERLAP = 150
45
+ SCAN_MAX_WINDOWS = 40
46
+ SCAN_TOP_K = 5
47
+ SCAN_BATCH_SIZE = 6
48
+ TOP_K_RETRIEVAL = 5
49
+ MAX_UPLOAD_SIZE_MB = 25
50
+ TIMEOUT_SECONDS = 30
51
+
52
+ ProviderLiteral = Literal["qwen", "openai", "anthropic", "gemini", "cohere"]
53
+
54
+ # Conservative full-document QA input budgets derived from provider/model
55
+ # context-window docs, with headroom reserved for prompts and outputs.
56
+ PROVIDER_FULL_DOCUMENT_QA_TOKEN_BUDGETS: dict[ProviderLiteral, int] = {
57
+ "qwen": 24_000,
58
+ "openai": 900_000,
59
+ "anthropic": 900_000,
60
+ "gemini": 900_000,
61
+ "cohere": 220_000,
62
+ }
63
+
64
+
65
+ @dataclass(frozen=True)
66
+ class ProviderConfig:
67
+ name: ProviderLiteral
68
+ key_prefix: Optional[str]
69
+ display_name: str
70
+ instructions: str
71
+
72
+
73
+ def _read_env_key(var_name: str) -> Optional[str]:
74
+ value = os.getenv(var_name)
75
+ if value is None:
76
+ return None
77
+ sanitized = value.strip().strip('"').strip("'")
78
+ return sanitized or None
79
+
80
+
81
+ OPENAI_API_KEY: Optional[str] = _read_env_key("OPENAI_API_KEY")
82
+ ANTHROPIC_API_KEY: Optional[str] = _read_env_key("ANTHROPIC_API_KEY")
83
+ GEMINI_API_KEY: Optional[str] = _read_env_key("GEMINI_API_KEY")
84
+ COHERE_API_KEY: Optional[str] = _read_env_key("COHERE_API_KEY")
85
+ DEFAULT_COHERE_KEY: Optional[str] = _read_env_key("DEFAULT_COHERE_KEY")
86
+ HF_TOKEN: Optional[str] = _read_env_key("HF_TOKEN")
87
+
88
+
89
+ PROVIDER_METADATA: list[ProviderConfig] = [
90
+ ProviderConfig(
91
+ name="qwen",
92
+ key_prefix=None,
93
+ display_name="Qwen3 32B",
94
+ instructions=(
95
+ "Use your Hugging Face token for the router-backed Qwen model. Leave blank to use HF_TOKEN from .env if configured."
96
+ ),
97
+ ),
98
+ ProviderConfig(
99
+ name="openai",
100
+ key_prefix="sk-",
101
+ display_name="OpenAI GPT-5.5",
102
+ instructions=(
103
+ "Enter your OpenAI API key. Leave blank to use OPENAI_API_KEY from .env if configured."
104
+ ),
105
+ ),
106
+ ProviderConfig(
107
+ name="anthropic",
108
+ key_prefix="sk-ant-",
109
+ display_name="Anthropic Claude Sonnet 4.6",
110
+ instructions=(
111
+ "Provide your Anthropic API key. Leave blank to use ANTHROPIC_API_KEY from .env if configured."
112
+ ),
113
+ ),
114
+ ProviderConfig(
115
+ name="gemini",
116
+ key_prefix=None,
117
+ display_name="Google Gemini 2.5 Flash",
118
+ instructions=(
119
+ "Use your Gemini API key. Leave blank to use the built-in GEMINI_API_KEY if configured."
120
+ ),
121
+ ),
122
+ ProviderConfig(
123
+ name="cohere",
124
+ key_prefix=None,
125
+ display_name="Cohere Command A Reasoning",
126
+ instructions=(
127
+ "Use your Cohere API key with Command R access. Leave blank to use COHERE_API_KEY or "
128
+ "DEFAULT_COHERE_KEY if configured."
129
+ ),
130
+ ),
131
+ ]
132
+
133
+
134
+ APP_TITLE = "Legislation Explainer"
135
+ APP_DESCRIPTION = (
136
+ "A Gradio policy assistant for Ghana's NITA bill and similar public-interest legislation. "
137
+ "Upload or link to a bill, generate a structured review, and ask grounded follow-up questions."
138
+ )
pyproject.toml ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [project]
2
+ name = "legislation-explainer"
3
+ version = "0.1.0"
4
+ description = "A Gradio tool for reviewing Ghana's NITA bill and related policy documents with small models."
5
+ readme = "README.md"
6
+ requires-python = ">=3.12, <3.13"
7
+ dependencies = [
8
+ "gradio==4.44.1",
9
+ "langchain==0.1.17",
10
+ "langchain-community==0.0.36",
11
+ "faiss-cpu==1.8.0",
12
+ "sentence-transformers==2.7.0",
13
+ "pydantic==2.6.4",
14
+ "requests==2.31.0",
15
+ "readability-lxml==0.8.1",
16
+ "lxml_html_clean>=0.4.3",
17
+ "python-docx==1.1.0",
18
+ "pypdf==4.2.0",
19
+ "anthropic==0.23.1",
20
+ "openai==1.25.0",
21
+ "httpx==0.27.2",
22
+ "google-generativeai==0.7.2",
23
+ "python-dotenv==1.0.1",
24
+ "cohere==5.5.5",
25
+ "pytest>=9.0.3",
26
+ ]
requirements.txt ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ gradio==4.44.1
2
+ langchain==0.1.17
3
+ langchain-community==0.0.36
4
+ faiss-cpu==1.8.0
5
+ sentence-transformers==2.7.0
6
+ pydantic==2.6.4
7
+ requests==2.31.0
8
+ readability-lxml==0.8.1
9
+ lxml_html_clean>=0.4.3
10
+ python-docx==1.1.0
11
+ pypdf==4.2.0
12
+ anthropic==0.23.1
13
+ openai==1.25.0
14
+ httpx==0.27.2
15
+ google-generativeai==0.7.2
16
+ python-dotenv==1.0.1
17
+ cohere==5.5.5
18
+ pytest==8.2.0
uv.lock ADDED
The diff for this file is too large to render. See raw diff