revit-api-docs 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.
Files changed (36) hide show
  1. revit_api_docs/__init__.py +18 -0
  2. revit_api_docs/__main__.py +8 -0
  3. revit_api_docs/config.py +115 -0
  4. revit_api_docs/data.py +320 -0
  5. revit_api_docs/default_config.yaml +85 -0
  6. revit_api_docs/embedder/__init__.py +1 -0
  7. revit_api_docs/embedder/providers/__init__.py +25 -0
  8. revit_api_docs/embedder/providers/base.py +28 -0
  9. revit_api_docs/embedder/providers/google.py +36 -0
  10. revit_api_docs/embedder/providers/openai.py +58 -0
  11. revit_api_docs/llm_client.py +288 -0
  12. revit_api_docs/prompts/__init__.py +5 -0
  13. revit_api_docs/prompts/loader.py +20 -0
  14. revit_api_docs/prompts/pipeline.api_quality_stage1_no_html.md +28 -0
  15. revit_api_docs/prompts/pipeline.api_quality_stage1_system.md +1 -0
  16. revit_api_docs/prompts/pipeline.api_quality_stage1_with_html.md +35 -0
  17. revit_api_docs/prompts/pipeline.api_quality_stage2.md +33 -0
  18. revit_api_docs/prompts/pipeline.api_quality_stage2_system.md +1 -0
  19. revit_api_docs/prompts/pipeline.rewrite_query.md +21 -0
  20. revit_api_docs/prompts/pipeline.rewrite_query_system.md +1 -0
  21. revit_api_docs/prompts/pipeline.sdk_extract_readme_system.md +1 -0
  22. revit_api_docs/prompts/pipeline.sdk_extract_readme_user.md +22 -0
  23. revit_api_docs/prompts/pipeline.sdk_golden_code.md +32 -0
  24. revit_api_docs/prompts/pipeline.sdk_golden_code_system.md +1 -0
  25. revit_api_docs/prompts/pipeline.sdk_quality_file_batch.md +17 -0
  26. revit_api_docs/prompts/pipeline.sdk_quality_file_system.md +1 -0
  27. revit_api_docs/prompts/pipeline.sdk_quality_project.md +20 -0
  28. revit_api_docs/prompts/pipeline.sdk_quality_project_system.md +1 -0
  29. revit_api_docs/reranker.py +177 -0
  30. revit_api_docs/retriever.py +901 -0
  31. revit_api_docs/server.py +244 -0
  32. revit_api_docs-0.1.0.dist-info/METADATA +139 -0
  33. revit_api_docs-0.1.0.dist-info/RECORD +36 -0
  34. revit_api_docs-0.1.0.dist-info/WHEEL +4 -0
  35. revit_api_docs-0.1.0.dist-info/entry_points.txt +2 -0
  36. revit_api_docs-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,58 @@
1
+ """OpenAI-compatible embedding provider (OpenAI, OpenRouter or any compatible base_url)."""
2
+ from .base import BaseEmbedding
3
+ from ...config import get_api_key, get_proxy_url
4
+
5
+
6
+ class OpenAIEmbedding(BaseEmbedding):
7
+
8
+ def __init__(self, model: str = "openai/text-embedding-3-large", dimension: int = 3072,
9
+ api_key_env: str = "OPENROUTER_API_KEY", base_url: str = "https://openrouter.ai/api/v1",
10
+ timeout: float = 30.0):
11
+ from openai import OpenAI
12
+ import httpx
13
+
14
+ self._model = model
15
+ self._dimension = dimension
16
+
17
+ proxy = get_proxy_url()
18
+ self._http_client = httpx.Client(proxy=proxy) if proxy else None
19
+
20
+ # One retry and a short timeout: a bad key or a down endpoint must not
21
+ # stall a query for long; the retriever falls back to keyword search.
22
+ self._client = OpenAI(
23
+ api_key=get_api_key(api_key_env),
24
+ base_url=base_url,
25
+ http_client=self._http_client,
26
+ max_retries=1,
27
+ timeout=timeout,
28
+ )
29
+
30
+ def close(self) -> None:
31
+ """Close the underlying httpx.Client, if any."""
32
+ if self._http_client is not None:
33
+ try:
34
+ self._http_client.close()
35
+ except Exception:
36
+ pass
37
+
38
+ def __enter__(self) -> "OpenAIEmbedding":
39
+ return self
40
+
41
+ def __exit__(self, exc_type, exc_val, exc_tb) -> None:
42
+ self.close()
43
+
44
+ @property
45
+ def model_name(self) -> str:
46
+ return self._model
47
+
48
+ @property
49
+ def dimension(self) -> int:
50
+ return self._dimension
51
+
52
+ def embed_texts(self, texts: list[str]) -> list[list[float]]:
53
+ response = self._client.embeddings.create(model=self._model, input=texts)
54
+ return [item.embedding for item in response.data]
55
+
56
+ def embed_query(self, query: str) -> list[float]:
57
+ response = self._client.embeddings.create(model=self._model, input=[query])
58
+ return response.data[0].embedding
@@ -0,0 +1,288 @@
1
+ """Minimal chat-completions client (OpenAI-compatible, used through OpenRouter).
2
+
3
+ Used by the offline pipeline tools (SDK summarisation, quality agents) and by
4
+ the optional query rewriting in the retriever. Configuration comes from the
5
+ `llm` section of the config; the key from the environment variable named in
6
+ `api_key_env`. The MCP server never needs it.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import json
11
+ import os
12
+ import sys
13
+ from typing import Any, Generator
14
+
15
+ import time
16
+
17
+ import httpx
18
+
19
+ # SDK summarisation calls run long; use a generous timeout.
20
+ _DEFAULT_TIMEOUT = 120.0
21
+
22
+ # Transient statuses (OpenRouter / upstream hiccups) that are retried.
23
+ # 403 has been observed as a transient refusal from Anthropic via OpenRouter.
24
+ _RETRYABLE_STATUS = frozenset({403, 408, 409, 429, 500, 502, 503, 504, 529})
25
+ _MAX_RETRIES = 4 # total attempts = 1 + retries
26
+ _BACKOFF_BASE = 1.5 # backoff base in seconds: 1.5, 3.0, 4.5 ...
27
+ _MAX_403_RETRIES = 1 # 403 is usually permissions/quota: retry once, then give up
28
+
29
+
30
+ class LLMClient:
31
+ def __init__(
32
+ self,
33
+ base_url: str,
34
+ api_key: str,
35
+ model: str,
36
+ temperature: float = 0.3,
37
+ max_tokens: int = 4096,
38
+ timeout: float = _DEFAULT_TIMEOUT,
39
+ proxy: str | None = None,
40
+ ):
41
+ self.base_url = base_url.rstrip("/")
42
+ self.api_key = api_key
43
+ self.model = model
44
+ self.temperature = temperature
45
+ self.max_tokens = max_tokens
46
+
47
+ # Configure HTTP proxy if provided (helps with Gemini routing in restricted networks)
48
+ if proxy:
49
+ self._client = httpx.Client(
50
+ timeout=timeout,
51
+ proxy=proxy,
52
+ )
53
+ else:
54
+ self._client = httpx.Client(timeout=timeout)
55
+
56
+ def close(self) -> None:
57
+ """Close the underlying httpx.Client and its connection pool."""
58
+ try:
59
+ self._client.close()
60
+ except Exception:
61
+ pass
62
+
63
+ def __enter__(self) -> "LLMClient":
64
+ return self
65
+
66
+ def __exit__(self, exc_type, exc_val, exc_tb) -> None:
67
+ self.close()
68
+
69
+ def _build_request(
70
+ self,
71
+ prompt: str,
72
+ system_prompt: str | None = None,
73
+ stream: bool = False,
74
+ messages: list[dict] | None = None,
75
+ ) -> tuple[str, dict, dict]:
76
+ """Build request URL, headers, and payload.
77
+
78
+ If `messages` is provided it is used verbatim as the chat messages array
79
+ (structured multi-turn: system + per-role turns). Otherwise a simple
80
+ [system, user] pair is built from `system_prompt` / `prompt`.
81
+ """
82
+ url = f"{self.base_url}/chat/completions"
83
+ headers = {
84
+ "Authorization": f"Bearer {self.api_key}",
85
+ "Content-Type": "application/json",
86
+ "X-Title": "revit-api-docs",
87
+ }
88
+
89
+ if messages is not None:
90
+ msgs = messages
91
+ else:
92
+ _system = system_prompt or (
93
+ "You are an expert assistant for summarizing Revit SDK C# sample code. "
94
+ "Always respond in English."
95
+ )
96
+ msgs = [
97
+ {"role": "system", "content": _system},
98
+ {"role": "user", "content": prompt},
99
+ ]
100
+
101
+ payload: dict[str, Any] = {
102
+ "model": self.model,
103
+ "messages": msgs,
104
+ "temperature": self.temperature,
105
+ "max_tokens": self.max_tokens,
106
+ "stream": stream,
107
+ }
108
+ return url, headers, payload
109
+
110
+ def generate_text(self, prompt: str, system_prompt: str | None = None) -> str:
111
+ """Chat-completions call; returns the first message's content.
112
+
113
+ Retries transient statuses with a short backoff (see _RETRYABLE_STATUS).
114
+ """
115
+ url, headers, payload = self._build_request(prompt, system_prompt, stream=False)
116
+
117
+ import logging
118
+ _llm_log = logging.getLogger("revit_api_docs.llm_client")
119
+
120
+ resp = None
121
+ last_err: Exception | None = None
122
+ consecutive_403 = 0
123
+ for attempt in range(1, _MAX_RETRIES + 1):
124
+ try:
125
+ resp = self._client.post(url, headers=headers, json=payload)
126
+ if resp.status_code in _RETRYABLE_STATUS and attempt < _MAX_RETRIES:
127
+ # 403 circuit breaker: stop after _MAX_403_RETRIES so a lasting
128
+ # permission/quota error is not retried as if transient.
129
+ if resp.status_code == 403:
130
+ consecutive_403 += 1
131
+ if consecutive_403 > _MAX_403_RETRIES:
132
+ _llm_log.warning(
133
+ f"[generate_text] {self.model} HTTP 403 x{consecutive_403} "
134
+ "— circuit break, no more retries."
135
+ )
136
+ resp.raise_for_status()
137
+ else:
138
+ consecutive_403 = 0
139
+ body = resp.text[:300].replace("\n", " ")
140
+ wait = _BACKOFF_BASE * attempt
141
+ _llm_log.warning(
142
+ f"[generate_text] {self.model} HTTP {resp.status_code} "
143
+ f"(attempt {attempt}/{_MAX_RETRIES}) — retrying in {wait:.1f}s. Body: {body}"
144
+ )
145
+ time.sleep(wait)
146
+ continue
147
+ resp.raise_for_status()
148
+ break
149
+ except (httpx.TransportError, httpx.TimeoutException) as e:
150
+ # transport-level hiccup: retry as well
151
+ last_err = e
152
+ if attempt < _MAX_RETRIES:
153
+ wait = _BACKOFF_BASE * attempt
154
+ _llm_log.warning(
155
+ f"[generate_text] {self.model} transport error "
156
+ f"(attempt {attempt}/{_MAX_RETRIES}): {e} — retrying in {wait:.1f}s"
157
+ )
158
+ time.sleep(wait)
159
+ continue
160
+ raise
161
+ except httpx.HTTPStatusError as e:
162
+ # non-retryable status or retries exhausted: raise with the body for diagnosis
163
+ body = e.response.text[:500] if e.response is not None else ""
164
+ raise httpx.HTTPStatusError(
165
+ f"{e} | OpenRouter response: {body}",
166
+ request=e.request, response=e.response,
167
+ ) from None
168
+
169
+ if resp is None: # unreachable in practice
170
+ raise last_err or RuntimeError("generate_text: no response")
171
+
172
+ data = resp.json()
173
+
174
+ choices = data.get("choices") or []
175
+ if not choices:
176
+ return ""
177
+
178
+ choice = choices[0]
179
+ finish_reason = choice.get("finish_reason", "unknown")
180
+ message = choice.get("message") or {}
181
+ content = message.get("content") or ""
182
+
183
+ _llm_log.info(
184
+ f"[generate_text] finish_reason={finish_reason} "
185
+ f"content_len={len(content)} max_tokens={self.max_tokens}"
186
+ )
187
+ if finish_reason == "length":
188
+ _llm_log.warning(
189
+ f"[generate_text] RESPONSE TRUNCATED — hit max_tokens={self.max_tokens}. "
190
+ f"Increase max_tokens in config."
191
+ )
192
+
193
+ return str(content)
194
+
195
+ def generate_stream(
196
+ self, prompt: str, system_prompt: str | None = None,
197
+ messages: list[dict] | None = None,
198
+ ) -> Generator[str, None, None]:
199
+ """Stream tokens over SSE. `messages` may carry a structured multi-turn
200
+ conversation (system + per-role entries) instead of `prompt`."""
201
+ url, headers, payload = self._build_request(
202
+ prompt, system_prompt, stream=True, messages=messages,
203
+ )
204
+
205
+ with self._client.stream("POST", url, headers=headers, json=payload) as resp:
206
+ resp.raise_for_status()
207
+ for line in resp.iter_lines():
208
+ if not line or not line.startswith("data: "):
209
+ continue
210
+ data_str = line[6:] # strip "data: "
211
+ if data_str.strip() == "[DONE]":
212
+ break
213
+ try:
214
+ chunk = json.loads(data_str)
215
+ delta = chunk.get("choices", [{}])[0].get("delta", {})
216
+ token = delta.get("content", "")
217
+ if token:
218
+ yield token
219
+ except (json.JSONDecodeError, IndexError):
220
+ continue
221
+
222
+ def stream_print(
223
+ self, prompt: str, system_prompt: str | None = None
224
+ ) -> str:
225
+ """Stream to stdout as tokens arrive; return the full text."""
226
+ full_text = []
227
+ for token in self.generate_stream(prompt, system_prompt):
228
+ print(token, end="", flush=True)
229
+ full_text.append(token)
230
+ print() # final newline
231
+ return "".join(full_text)
232
+
233
+
234
+ def create_llm_client(config: dict[str, Any], provider_override: str | None = None) -> LLMClient:
235
+ """Build an LLMClient from config["llm"].
236
+
237
+ Args:
238
+ config: the loaded config dict
239
+ provider_override: use this llm.models entry instead of llm.provider
240
+ """
241
+ llm_cfg = config.get("llm", {})
242
+ provider = provider_override or llm_cfg.get("provider", "claude")
243
+ models_cfg = llm_cfg.get("models", {})
244
+ model_cfg = models_cfg.get(provider, {})
245
+
246
+ if not model_cfg:
247
+ available = list(models_cfg.keys())
248
+ raise RuntimeError(
249
+ f"no llm.models entry for provider={provider!r} in the config; "
250
+ f"available: {available}"
251
+ )
252
+
253
+ model = model_cfg.get("model")
254
+ base_url = model_cfg.get("base_url") or config.get("openrouter", {}).get("base_url")
255
+ api_key_env = (
256
+ model_cfg.get("api_key_env")
257
+ or config.get("openrouter", {}).get("api_key_env", "OPENROUTER_API_KEY")
258
+ )
259
+ api_key = os.getenv(api_key_env, "")
260
+
261
+ if not model:
262
+ raise RuntimeError(f"llm.models.{provider}.model is not set in the config")
263
+ if not base_url:
264
+ raise RuntimeError(f"llm.models.{provider}.base_url is not set in the config")
265
+ if not api_key:
266
+ raise RuntimeError(
267
+ f"environment variable {api_key_env} is not set; it must hold the API key "
268
+ f"for the {provider} model"
269
+ )
270
+
271
+ temperature = llm_cfg.get("temperature", 0.3)
272
+ max_tokens = llm_cfg.get("max_tokens", 4096)
273
+
274
+ # Proxy: model-level override > global proxy config
275
+ proxy_cfg = config.get("proxy", {})
276
+ proxy_url: str | None = None
277
+ if proxy_cfg.get("enabled", False):
278
+ proxy_url = proxy_cfg.get("https") or proxy_cfg.get("http")
279
+
280
+ return LLMClient(
281
+ base_url=base_url,
282
+ api_key=api_key,
283
+ model=model,
284
+ temperature=temperature,
285
+ max_tokens=max_tokens,
286
+ proxy=proxy_url,
287
+ )
288
+
@@ -0,0 +1,5 @@
1
+ """Prompt templates used by the retriever (query rewriting) and the pipeline tools."""
2
+
3
+ from .loader import load_prompt
4
+
5
+ __all__ = ["load_prompt"]
@@ -0,0 +1,20 @@
1
+ """Prompt template loader.
2
+
3
+ Prompt text lives in this package so prompts can be reviewed and tuned without
4
+ digging through runtime code.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ from functools import lru_cache
9
+ from pathlib import Path
10
+
11
+ _PROMPT_DIR = Path(__file__).resolve().parent
12
+
13
+
14
+ @lru_cache(maxsize=None)
15
+ def load_prompt(name: str) -> str:
16
+ """Load a prompt template by filename from the prompts directory."""
17
+ if "/" in name or "\\" in name or name.startswith("."):
18
+ raise ValueError(f"Invalid prompt name: {name!r}")
19
+ path = _PROMPT_DIR / name
20
+ return path.read_text(encoding="utf-8")
@@ -0,0 +1,28 @@
1
+ Audit the following parsed Revit API record for data quality.
2
+
3
+ No raw HTML is available. Be conservative: without HTML you cannot know if missing fields are parser failures or absent source documentation. Only deduct for clearly detectable issues.
4
+
5
+ ## Score Criteria
6
+ - -0.5 name/full_id indicates a constructor (`#ctor` or `Constructor`) -> noise.
7
+ - -0.3 summary or info is clearly generic boilerplate.
8
+ - -0.25 parameters field is empty but syntax shows the method takes arguments with actual parameter names.
9
+ - -0.1 any field contains raw HTML tags, garbled text, or excessive whitespace.
10
+
11
+ Do not deduct for empty summary/info, missing syntax, or missing parameters when source absence is plausible.
12
+
13
+ Parsed record:
14
+ name : {name}
15
+ full_id : {full_id}
16
+ syntax : {syntax}
17
+ summary : {summary}
18
+ info : {info}
19
+ parameters : {parameters}
20
+
21
+ Return ONLY a JSON object:
22
+ {{
23
+ "quality_score": 0.8,
24
+ "issues": [],
25
+ "needs_rewrite": false
26
+ }}
27
+
28
+ Use threshold {threshold}. JSON only. No markdown. No explanation.
@@ -0,0 +1 @@
1
+ You are a data-quality auditor for Revit API documentation records. You measure parse quality: how well the parser captured information that exists in the HTML. Always reply with a single valid JSON object and nothing else.
@@ -0,0 +1,35 @@
1
+ Audit the following parsed Revit API record by comparing it against the raw HTML source.
2
+
3
+ ## Principle
4
+ Measure parse quality, not documentation completeness. Only deduct points when the HTML source contains information that the parsed record is missing or captured incorrectly. If the HTML lacks a field, an empty parsed field is correct.
5
+
6
+ ## Score Criteria
7
+ Cumulative deductions from 1.0, only when HTML evidence exists:
8
+ - -0.5 name/full_id indicates a constructor (`#ctor` or `Constructor`) -> noise record.
9
+ - -0.4 summary and info are both empty but HTML contains a real description.
10
+ - -0.3 summary/info is generic boilerplate while HTML has a real description.
11
+ - -0.25 parameters field is empty but HTML shows method parameters with descriptions.
12
+ - -0.2 syntax/C# signature is missing but HTML contains a public C# signature.
13
+ - -0.2 important HTML content such as description or return value is absent from parsed fields.
14
+ - -0.15 all parameter types are `Unknown Type` but HTML has actual type information.
15
+ - -0.1 any field contains raw HTML tags, garbled unicode, or excessive whitespace.
16
+
17
+ Parsed record:
18
+ name : {name}
19
+ full_id : {full_id}
20
+ syntax : {syntax}
21
+ summary : {summary}
22
+ info : {info}
23
+ parameters : {parameters}
24
+
25
+ Raw HTML excerpt:
26
+ {html_excerpt}
27
+
28
+ Return ONLY a JSON object:
29
+ {{
30
+ "quality_score": 0.0,
31
+ "issues": ["short English issue strings"],
32
+ "needs_rewrite": true
33
+ }}
34
+
35
+ Use threshold {threshold}. JSON only. No markdown. No explanation.
@@ -0,0 +1,33 @@
1
+ The following Revit API record has quality issues. Use the raw HTML as ground truth to produce corrected fields.
2
+
3
+ Identified issues:
4
+ {issues}
5
+
6
+ Original parsed record:
7
+ name : {name}
8
+ full_id : {full_id}
9
+ syntax : {syntax}
10
+ summary : {summary}
11
+ info : {info}
12
+ parameters : {parameters}
13
+ remark : {remark}
14
+
15
+ Raw HTML excerpt:
16
+ {html_excerpt}
17
+
18
+ ## Rules
19
+ - Only include fields where you can make a genuine improvement based on HTML evidence.
20
+ - If the original field already matches the HTML, do not include it.
21
+ - If a field is empty in both the record and the HTML, omit it.
22
+ - Do not fabricate content.
23
+ - Keep output concise.
24
+
25
+ Return ONLY a JSON object with improved fields:
26
+ {{
27
+ "summary": "clear one-sentence English description",
28
+ "parameters": "one parameter per line, or empty string if none",
29
+ "syntax": "correct C# public signature from HTML",
30
+ "info": "concise description if summary is missing"
31
+ }}
32
+
33
+ Omit unchanged fields. JSON only. No markdown. No explanation.
@@ -0,0 +1 @@
1
+ You are an expert Revit API documentation writer. Repair and improve incomplete or garbled API records using raw HTML as the authoritative reference. Always reply with a single valid JSON object and nothing else.
@@ -0,0 +1,21 @@
1
+ You are a Revit API expert. Given a user query, possibly in Chinese, extract all relevant Revit API class names, method names, properties, enums, and English technical keywords.
2
+
3
+ ## Rules
4
+ 1. Translate non-English domain terms to exact Revit API equivalents.
5
+ 2. Entity nouns are primary search targets. Action verbs are secondary qualifiers.
6
+ 3. Strip natural-language filler words and focus on API entities.
7
+ 4. Be exhaustive: include parent classes, related interfaces, relevant enum types, BuiltInParameter, and BuiltInCategory names.
8
+ 5. Include full namespace paths when useful, for example `Autodesk.Revit.DB.Wall`.
9
+ 6. Include method signatures, property names, and likely overload terms.
10
+ 7. Think about what a developer would search for when implementing this feature.
11
+ 8. Output ONLY a JSON object.
12
+
13
+ ## Examples
14
+ - "结构柱" -> {{"keywords": "structural column FamilyInstance BuiltInCategory.OST_StructuralColumns NewFamilyInstance StructuralType", "api_terms": ["FamilyInstance", "FamilySymbol", "NewFamilyInstance", "StructuralType", "BuiltInCategory.OST_StructuralColumns", "Level", "XYZ"]}}
15
+ - "创建墙体" -> {{"keywords": "create wall Wall.Create WallType Level Line CurveLoop", "api_terms": ["Wall", "Wall.Create", "WallType", "WallUtils", "CurtainGrid", "Line.CreateBound", "Level"]}}
16
+ - "i want get wall created api" -> {{"keywords": "Wall Wall.Create WallType Level Line", "api_terms": ["Wall", "Wall.Create", "WallType", "WallUtils", "Line.CreateBound", "Level", "FilteredElementCollector"]}}
17
+ - "获取房间面积" -> {{"keywords": "room area Room get_Area SpatialElement BoundarySegment", "api_terms": ["Room", "SpatialElement", "Area", "Room.Area", "Room.get_BoundarySegments", "SpatialElementBoundaryOptions"]}}
18
+ - "修改墙类型" -> {{"keywords": "change wall type WallType ChangeTypeId Element.ChangeTypeId GetTypeId", "api_terms": ["Element.ChangeTypeId", "Element.GetTypeId", "WallType", "FilteredElementCollector", "Wall"]}}
19
+ - "Part" -> {{"keywords": "Part PartUtils PartMaker CreateParts DivideParts PartType", "api_terms": ["Part", "PartUtils", "PartMaker", "PartUtils.CreateParts", "PartUtils.AreElementsValidForCreateParts"]}}
20
+
21
+ User query: {query}
@@ -0,0 +1 @@
1
+ You are a Revit API keyword extractor. Output JSON only.
@@ -0,0 +1 @@
1
+ You are an AI assistant specializing in codebase analysis and extracting structured data from technical documentation.
@@ -0,0 +1,22 @@
1
+ # Role
2
+ You are an AI assistant specializing in codebase analysis and extracting structured data from technical documentation.
3
+
4
+ # Goal
5
+ Parse the provided ReadMe text to extract key identifiers for code. Output will be used programmatically by an automated code retrieval system.
6
+
7
+ # Instructions
8
+ 1. Carefully analyze the text provided.
9
+ 2. Extract:
10
+ - `target_files`: all project source filenames explicitly mentioned.
11
+ - `key_classes_and_methods`: custom class or method names responsible for core functionality.
12
+ - `mentioned_apis`: key API classes from external frameworks such as `Autodesk.Revit.DB.View`.
13
+ 3. Return a single strict JSON object.
14
+ 4. If no information is found for a field, use an empty list `[]`.
15
+ 5. Output only raw JSON. No markdown. No explanation.
16
+
17
+ # Example
18
+ Input: "This tool is in `Processor.cs`. Core logic is in `DataParser` using `Autodesk.Revit.DB.Transaction`."
19
+ Output: {{"target_files": ["Processor.cs"], "key_classes_and_methods": ["DataParser"], "mentioned_apis": ["Autodesk.Revit.DB.Transaction"]}}
20
+
21
+ # README Content
22
+ {readme_text}
@@ -0,0 +1,32 @@
1
+ # Role
2
+ You are an expert C# software architect and technical writer specializing in the Autodesk Revit API.
3
+
4
+ # Goal
5
+ Analyze the ReadMe context and raw C# code details. Identify the single most relevant code block representing the core functionality described in the ReadMe, then synthesize it into a clean, reusable, documented Golden Code Snippet for a RAG knowledge base.
6
+
7
+ # Context
8
+ <ReadMeContext>
9
+ {readme_summary}
10
+ </ReadMeContext>
11
+
12
+ <RawCodeDetails>
13
+ {detail_code_analysis}
14
+ </RawCodeDetails>
15
+
16
+ # Instructions
17
+ 1. Read `<ReadMeContext>` to understand the project's main purpose and key APIs.
18
+ 2. Examine `<RawCodeDetails>` and select the one method or block that most directly implements the core functionality.
19
+ 3. Remove UI interaction code, logging/debugging, generic file I/O unless core, and `IExternalCommand.Execute` boilerplate.
20
+ 4. Refactor for reuse with a clear method signature, typed parameters, and hardcoded values converted to parameters.
21
+ 5. Keep Transaction handling appropriate for standalone SDK examples.
22
+ 6. Generate XML documentation comments.
23
+ 7. Output one complete syntactically correct C# method block.
24
+
25
+ # Output
26
+ Return ONLY a JSON object:
27
+ {{
28
+ "summary": "One sentence English description of what this code demonstrates and which Revit APIs it uses.",
29
+ "content": "The complete clean C# method with XML documentation comments."
30
+ }}
31
+
32
+ JSON only. No markdown. No explanation outside JSON.
@@ -0,0 +1 @@
1
+ You are an expert C# software architect and technical writer specializing in the Autodesk Revit API. You identify core logic and refactor it into clear, concise, educational code examples. Always reply with a single valid JSON object and nothing else.
@@ -0,0 +1,17 @@
1
+ Analyze these C# files from the Revit SDK project "{project_name}".
2
+
3
+ Project context: {project_summary}
4
+
5
+ {file_sections}
6
+
7
+ Return a JSON array with one object per file in the same order:
8
+ [
9
+ {{
10
+ "filename": "exact filename",
11
+ "file_purpose": "1-sentence English description of what this file does",
12
+ "key_classes": ["ClassName1", "ClassName2"],
13
+ "key_methods": ["MethodName1 - brief description", "MethodName2 - brief description"]
14
+ }}
15
+ ]
16
+
17
+ JSON array only. No markdown. No explanation.
@@ -0,0 +1 @@
1
+ You are a Revit SDK code analyst. Analyze C# source files and extract metadata. Always reply with a single valid JSON array and nothing else.
@@ -0,0 +1,20 @@
1
+ Analyze this Revit SDK sample project.
2
+
3
+ Project name: {project_name}
4
+ Number of C# files: {file_count}
5
+
6
+ README content:
7
+ {readme}
8
+
9
+ File listing with code previews:
10
+ {file_previews}
11
+
12
+ Return a JSON object with:
13
+ {{
14
+ "project_summary": "2-3 sentence English description of what this project demonstrates",
15
+ "api_classes_used": ["main Revit API classes/types used"],
16
+ "key_patterns": ["design patterns demonstrated"],
17
+ "use_case_category": "geometry|family|view|structure|mep|annotation|export|utility|ui|analysis|database|other"
18
+ }}
19
+
20
+ JSON only. No markdown. No explanation.
@@ -0,0 +1 @@
1
+ You are a Revit SDK code analyst. Analyze C# sample projects that demonstrate Revit API usage patterns. Always reply with a single valid JSON object and nothing else.