janus-llm 4.2.0__py3-none-any.whl → 4.3.5__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. janus/__init__.py +1 -1
  2. janus/__main__.py +1 -1
  3. janus/_tests/evaluator_tests/EvalReadMe.md +85 -0
  4. janus/_tests/evaluator_tests/incose_tests/incose_large_test.json +39 -0
  5. janus/_tests/evaluator_tests/incose_tests/incose_small_test.json +17 -0
  6. janus/_tests/evaluator_tests/inline_comment_tests/mumps_inline_comment_test.m +71 -0
  7. janus/_tests/test_cli.py +3 -2
  8. janus/cli/aggregate.py +135 -0
  9. janus/cli/cli.py +111 -0
  10. janus/cli/constants.py +43 -0
  11. janus/cli/database.py +289 -0
  12. janus/cli/diagram.py +178 -0
  13. janus/cli/document.py +174 -0
  14. janus/cli/embedding.py +122 -0
  15. janus/cli/llm.py +187 -0
  16. janus/cli/partition.py +125 -0
  17. janus/cli/self_eval.py +149 -0
  18. janus/cli/translate.py +183 -0
  19. janus/converter/__init__.py +1 -1
  20. janus/converter/_tests/test_translate.py +2 -0
  21. janus/converter/converter.py +129 -92
  22. janus/converter/document.py +21 -14
  23. janus/converter/evaluate.py +237 -4
  24. janus/converter/translate.py +3 -3
  25. janus/embedding/collections.py +1 -1
  26. janus/language/alc/_tests/alc.asm +3779 -0
  27. janus/language/alc/_tests/test_alc.py +1 -1
  28. janus/language/alc/alc.py +9 -4
  29. janus/language/binary/_tests/hello.bin +0 -0
  30. janus/language/block.py +47 -12
  31. janus/language/file.py +1 -1
  32. janus/language/mumps/_tests/mumps.m +235 -0
  33. janus/language/splitter.py +31 -23
  34. janus/language/treesitter/_tests/languages/fortran.f90 +416 -0
  35. janus/language/treesitter/_tests/languages/ibmhlasm.asm +16 -0
  36. janus/language/treesitter/_tests/languages/matlab.m +225 -0
  37. janus/language/treesitter/treesitter.py +9 -1
  38. janus/llm/models_info.py +26 -13
  39. janus/metrics/_tests/asm_test_file.asm +10 -0
  40. janus/metrics/_tests/mumps_test_file.m +6 -0
  41. janus/metrics/_tests/test_treesitter_metrics.py +1 -1
  42. janus/metrics/prompts/clarity.txt +8 -0
  43. janus/metrics/prompts/completeness.txt +16 -0
  44. janus/metrics/prompts/faithfulness.txt +10 -0
  45. janus/metrics/prompts/hallucination.txt +16 -0
  46. janus/metrics/prompts/quality.txt +8 -0
  47. janus/metrics/prompts/readability.txt +16 -0
  48. janus/metrics/prompts/usefulness.txt +16 -0
  49. janus/parsers/code_parser.py +4 -4
  50. janus/parsers/doc_parser.py +12 -9
  51. janus/parsers/eval_parsers/incose_parser.py +134 -0
  52. janus/parsers/eval_parsers/inline_comment_parser.py +112 -0
  53. janus/parsers/parser.py +7 -0
  54. janus/parsers/partition_parser.py +47 -13
  55. janus/parsers/reqs_parser.py +8 -5
  56. janus/parsers/uml.py +5 -4
  57. janus/prompts/prompt.py +2 -2
  58. janus/prompts/templates/README.md +30 -0
  59. janus/prompts/templates/basic_aggregation/human.txt +6 -0
  60. janus/prompts/templates/basic_aggregation/system.txt +1 -0
  61. janus/prompts/templates/basic_refinement/human.txt +14 -0
  62. janus/prompts/templates/basic_refinement/system.txt +1 -0
  63. janus/prompts/templates/diagram/human.txt +9 -0
  64. janus/prompts/templates/diagram/system.txt +1 -0
  65. janus/prompts/templates/diagram_with_documentation/human.txt +15 -0
  66. janus/prompts/templates/diagram_with_documentation/system.txt +1 -0
  67. janus/prompts/templates/document/human.txt +10 -0
  68. janus/prompts/templates/document/system.txt +1 -0
  69. janus/prompts/templates/document_cloze/human.txt +11 -0
  70. janus/prompts/templates/document_cloze/system.txt +1 -0
  71. janus/prompts/templates/document_cloze/variables.json +4 -0
  72. janus/prompts/templates/document_cloze/variables_asm.json +4 -0
  73. janus/prompts/templates/document_inline/human.txt +13 -0
  74. janus/prompts/templates/eval_prompts/incose/human.txt +32 -0
  75. janus/prompts/templates/eval_prompts/incose/system.txt +1 -0
  76. janus/prompts/templates/eval_prompts/incose/variables.json +3 -0
  77. janus/prompts/templates/eval_prompts/inline_comments/human.txt +49 -0
  78. janus/prompts/templates/eval_prompts/inline_comments/system.txt +1 -0
  79. janus/prompts/templates/eval_prompts/inline_comments/variables.json +3 -0
  80. janus/prompts/templates/micromanaged_mumps_v1.0/human.txt +23 -0
  81. janus/prompts/templates/micromanaged_mumps_v1.0/system.txt +3 -0
  82. janus/prompts/templates/micromanaged_mumps_v2.0/human.txt +28 -0
  83. janus/prompts/templates/micromanaged_mumps_v2.0/system.txt +3 -0
  84. janus/prompts/templates/micromanaged_mumps_v2.1/human.txt +29 -0
  85. janus/prompts/templates/micromanaged_mumps_v2.1/system.txt +3 -0
  86. janus/prompts/templates/multidocument/human.txt +15 -0
  87. janus/prompts/templates/multidocument/system.txt +1 -0
  88. janus/prompts/templates/partition/human.txt +22 -0
  89. janus/prompts/templates/partition/system.txt +1 -0
  90. janus/prompts/templates/partition/variables.json +4 -0
  91. janus/prompts/templates/pseudocode/human.txt +7 -0
  92. janus/prompts/templates/pseudocode/system.txt +7 -0
  93. janus/prompts/templates/refinement/fix_exceptions/human.txt +19 -0
  94. janus/prompts/templates/refinement/fix_exceptions/system.txt +1 -0
  95. janus/prompts/templates/refinement/format/code_format/human.txt +12 -0
  96. janus/prompts/templates/refinement/format/code_format/system.txt +1 -0
  97. janus/prompts/templates/refinement/format/requirements_format/human.txt +14 -0
  98. janus/prompts/templates/refinement/format/requirements_format/system.txt +1 -0
  99. janus/prompts/templates/refinement/hallucination/human.txt +13 -0
  100. janus/prompts/templates/refinement/hallucination/system.txt +1 -0
  101. janus/prompts/templates/refinement/reflection/human.txt +15 -0
  102. janus/prompts/templates/refinement/reflection/incose/human.txt +26 -0
  103. janus/prompts/templates/refinement/reflection/incose/system.txt +1 -0
  104. janus/prompts/templates/refinement/reflection/incose_deduplicate/human.txt +16 -0
  105. janus/prompts/templates/refinement/reflection/incose_deduplicate/system.txt +1 -0
  106. janus/prompts/templates/refinement/reflection/system.txt +1 -0
  107. janus/prompts/templates/refinement/revision/human.txt +16 -0
  108. janus/prompts/templates/refinement/revision/incose/human.txt +16 -0
  109. janus/prompts/templates/refinement/revision/incose/system.txt +1 -0
  110. janus/prompts/templates/refinement/revision/incose_deduplicate/human.txt +17 -0
  111. janus/prompts/templates/refinement/revision/incose_deduplicate/system.txt +1 -0
  112. janus/prompts/templates/refinement/revision/system.txt +1 -0
  113. janus/prompts/templates/refinement/uml/alc_fix_variables/human.txt +15 -0
  114. janus/prompts/templates/refinement/uml/alc_fix_variables/system.txt +2 -0
  115. janus/prompts/templates/refinement/uml/fix_connections/human.txt +15 -0
  116. janus/prompts/templates/refinement/uml/fix_connections/system.txt +2 -0
  117. janus/prompts/templates/requirements/human.txt +13 -0
  118. janus/prompts/templates/requirements/system.txt +2 -0
  119. janus/prompts/templates/retrieval/language_docs/human.txt +10 -0
  120. janus/prompts/templates/retrieval/language_docs/system.txt +1 -0
  121. janus/prompts/templates/simple/human.txt +16 -0
  122. janus/prompts/templates/simple/system.txt +3 -0
  123. janus/refiners/format.py +49 -0
  124. janus/refiners/refiner.py +143 -4
  125. janus/utils/enums.py +140 -111
  126. janus/utils/logger.py +2 -0
  127. {janus_llm-4.2.0.dist-info → janus_llm-4.3.5.dist-info}/METADATA +7 -7
  128. janus_llm-4.3.5.dist-info/RECORD +210 -0
  129. {janus_llm-4.2.0.dist-info → janus_llm-4.3.5.dist-info}/WHEEL +1 -1
  130. janus_llm-4.3.5.dist-info/entry_points.txt +3 -0
  131. janus/cli.py +0 -1343
  132. janus_llm-4.2.0.dist-info/RECORD +0 -113
  133. janus_llm-4.2.0.dist-info/entry_points.txt +0 -3
  134. {janus_llm-4.2.0.dist-info → janus_llm-4.3.5.dist-info}/LICENSE +0 -0
@@ -1,15 +1,248 @@
1
+ import json
2
+ import re
3
+ from copy import deepcopy
4
+
5
+ from langchain_core.runnables import Runnable, RunnableLambda, RunnableParallel
6
+
1
7
  from janus.converter.converter import Converter
8
+ from janus.language.block import TranslatedCodeBlock
2
9
  from janus.language.combine import JsonCombiner
3
- from janus.parsers.eval_parser import EvaluationParser
10
+ from janus.parsers.eval_parsers.incose_parser import IncoseParser
11
+ from janus.parsers.eval_parsers.inline_comment_parser import InlineCommentParser
12
+ from janus.parsers.parser import JanusParserException
4
13
  from janus.utils.logger import create_logger
5
14
 
6
15
  log = create_logger(__name__)
7
16
 
8
17
 
9
18
  class Evaluator(Converter):
10
- def __init__(self, **kwargs):
19
+ """Evaluator
20
+
21
+ A class that performs an LLM self evaluation"
22
+ "on an input target, with an associated prompt.
23
+
24
+ Current valid evaluation types:
25
+ ['incose', 'comments']
26
+
27
+ """
28
+
29
+ def __init__(self, **kwargs) -> None:
30
+ """Initialize the Evaluator class
31
+
32
+ Arguments:
33
+ model: The LLM to use for translation. If an OpenAI model, the
34
+ `OPENAI_API_KEY` environment variable must be set.
35
+ model_arguments: Additional arguments to pass to the LLM constructor.
36
+ max_prompts: The maximum number of prompts to try before giving up.
37
+ """
11
38
  super().__init__(**kwargs)
12
- self.set_prompt("evaluate")
13
39
  self._combiner = JsonCombiner()
14
- self._parser = EvaluationParser()
15
40
  self._load_parameters()
41
+
42
+
43
+ class RequirementEvaluator(Evaluator):
44
+ """INCOSE Requirement Evaluator
45
+
46
+ A class that performs an LLM self evaluation on an input target,
47
+ with an associated prompt.
48
+
49
+ The evaluation prompts are for Incose Evaluations
50
+
51
+ """
52
+
53
+ def __init__(self, eval_items_per_request: int | None = None, **kwargs) -> None:
54
+ """Initialize the Evaluator class
55
+
56
+ Arguments:
57
+ model: The LLM to use for translation. If an OpenAI model, the
58
+ `OPENAI_API_KEY` environment variable must be set.
59
+ model_arguments: Additional arguments to pass to the LLM constructor.
60
+ max_prompts: The maximum number of prompts to try before giving up.
61
+ """
62
+ super().__init__(**kwargs)
63
+ self.eval_items_per_request = eval_items_per_request
64
+ self._parser = IncoseParser()
65
+ self.set_prompt("eval_prompts/incose")
66
+
67
+ def _input_runnable(self) -> Runnable:
68
+ def _get_code(json_text: str) -> str:
69
+ return json.loads(json_text)["code"]
70
+
71
+ def _get_reqs(json_text: str) -> str:
72
+ return json.dumps(json.loads(json_text)["requirements"])
73
+
74
+ return RunnableLambda(self._parser.parse_input) | RunnableParallel(
75
+ SOURCE_CODE=_get_code,
76
+ REQUIREMENTS=_get_reqs,
77
+ context=self._retriever,
78
+ )
79
+
80
+ def _add_translation(self, block: TranslatedCodeBlock):
81
+ if block.translated:
82
+ return
83
+
84
+ if block.original.text is None:
85
+ block.translated = True
86
+ return
87
+
88
+ if self.eval_items_per_request is None:
89
+ return super()._add_translation(block)
90
+
91
+ input_obj = json.loads(block.original.text)
92
+ requirements = input_obj.get("requirements", [])
93
+
94
+ if not requirements:
95
+ log.debug(f"[{block.name}] Skipping empty block")
96
+ block.translated = True
97
+ block.text = None
98
+ block.complete = True
99
+ return
100
+
101
+ # For some reason requirements objects are in nested lists?
102
+ while isinstance(requirements[0], list):
103
+ requirements = [r for lst in requirements for r in lst]
104
+
105
+ if len(requirements) <= self.eval_items_per_request:
106
+ input_obj["requirements"] = requirements
107
+ block.original.text = json.dumps(input_obj)
108
+ return super()._add_translation(block)
109
+
110
+ block.processing_time = 0
111
+ block.cost = 0
112
+ obj = {}
113
+ for i in range(0, len(requirements), self.eval_items_per_request):
114
+ # Build a new TranslatedBlock using the new working text
115
+ working_requirements = requirements[i : i + self.eval_items_per_request]
116
+ working_copy = deepcopy(block.original)
117
+ working_obj = json.loads(working_copy.text) # type: ignore
118
+ working_obj["requirements"] = working_requirements
119
+ working_copy.text = json.dumps(working_obj)
120
+ working_block = TranslatedCodeBlock(working_copy, self._target_language)
121
+
122
+ # Run the LLM on the working text
123
+ try:
124
+ super()._add_translation(working_block)
125
+ except JanusParserException as e:
126
+ block.text += "\n==============\n" + working_block.text
127
+ block.tokens = self._llm.get_num_tokens(block.text)
128
+ raise e
129
+ finally:
130
+ # Update metadata to include for all runs
131
+ block.num_requests += working_block.num_requests
132
+ block.cost += working_block.cost
133
+ block.processing_time += working_block.processing_time
134
+ block.request_input_tokens += working_block.request_input_tokens
135
+ block.request_output_tokens += working_block.request_output_tokens
136
+
137
+ # Update the output text to merge this section's output in
138
+ obj.update(json.loads(working_block.text))
139
+ # intermediate result of block,
140
+ # will be overwritten if file completes successfully
141
+ block.text = json.dumps(obj)
142
+
143
+ block.text = json.dumps(obj)
144
+ block.tokens = self._llm.get_num_tokens(block.text)
145
+ block.translated = True
146
+
147
+ log.debug(
148
+ f"[{block.name}] Output code:\n{json.dumps(json.loads(block.text), indent=2)}"
149
+ )
150
+
151
+
152
+ class InlineCommentEvaluator(Evaluator):
153
+ """Inline Comment Evaluator
154
+
155
+ A class that performs an LLM self evaluation on inline comments,
156
+ with an associated prompt.
157
+ """
158
+
159
+ def __init__(self, eval_items_per_request: int | None = None, **kwargs) -> None:
160
+ """Initialize the Evaluator class
161
+
162
+ Arguments:
163
+ model: The LLM to use for translation. If an OpenAI model, the
164
+ `OPENAI_API_KEY` environment variable must be set.
165
+ model_arguments: Additional arguments to pass to the LLM constructor.
166
+ max_prompts: The maximum number of prompts to try before giving up.
167
+ """
168
+ super().__init__(**kwargs)
169
+ self._combiner = JsonCombiner()
170
+ self._load_parameters()
171
+ self._parser = InlineCommentParser()
172
+ self.set_prompt("eval_prompts/inline_comments")
173
+ self.eval_items_per_request = eval_items_per_request
174
+
175
+ def _add_translation(self, block: TranslatedCodeBlock):
176
+ if block.translated:
177
+ return
178
+
179
+ if block.original.text is None:
180
+ block.translated = True
181
+ return
182
+
183
+ if self.eval_items_per_request is None:
184
+ return super()._add_translation(block)
185
+
186
+ comment_pattern = r"<(?:INLINE|BLOCK)_COMMENT \w{8}>.*$"
187
+ comments = list(
188
+ re.finditer(comment_pattern, block.original.text, flags=re.MULTILINE)
189
+ )
190
+
191
+ if not comments:
192
+ log.info(f"[{block.name}] Skipping commentless block")
193
+ block.translated = True
194
+ block.text = None
195
+ block.complete = True
196
+ return
197
+
198
+ if len(comments) <= self.eval_items_per_request:
199
+ return super()._add_translation(block)
200
+
201
+ comment_group_indices = list(range(0, len(comments), self.eval_items_per_request))
202
+ log.debug(
203
+ f"[{block.name}] Block contains more than {self.eval_items_per_request}"
204
+ f" comments, splitting {len(comments)} comments into"
205
+ f" {len(comment_group_indices)} groups"
206
+ )
207
+
208
+ block.processing_time = 0
209
+ block.cost = 0
210
+ block.retries = 0
211
+ obj = {}
212
+ for i in range(0, len(comments), self.eval_items_per_request):
213
+ # Split the text into the section containing comments of interest,
214
+ # all the text prior to those comments, and all the text after them
215
+ working_comments = comments[i : i + self.eval_items_per_request]
216
+ start_idx = working_comments[0].start()
217
+ end_idx = working_comments[-1].end()
218
+ prefix = block.original.text[:start_idx]
219
+ keeper = block.original.text[start_idx:end_idx]
220
+ suffix = block.original.text[end_idx:]
221
+
222
+ # Strip all comment placeholders outside of the section of interest
223
+ prefix = re.sub(comment_pattern, "", prefix, flags=re.MULTILINE)
224
+ suffix = re.sub(comment_pattern, "", suffix, flags=re.MULTILINE)
225
+
226
+ # Build a new TranslatedBlock using the new working text
227
+ working_copy = deepcopy(block.original)
228
+ working_copy.text = prefix + keeper + suffix
229
+ working_block = TranslatedCodeBlock(working_copy, self._target_language)
230
+
231
+ # Run the LLM on the working text
232
+ super()._add_translation(working_block)
233
+
234
+ # Update metadata to include for all runs
235
+ block.retries += working_block.retries
236
+ block.cost += working_block.cost
237
+ block.processing_time += working_block.processing_time
238
+
239
+ # Update the output text to merge this section's output in
240
+ obj.update(json.loads(working_block.text))
241
+
242
+ block.text = json.dumps(obj)
243
+ block.tokens = self._llm.get_num_tokens(block.text)
244
+ block.translated = True
245
+
246
+ log.debug(
247
+ f"[{block.name}] Output code:\n{json.dumps(json.loads(block.text), indent=2)}"
248
+ )
@@ -21,8 +21,7 @@ class Translator(Converter):
21
21
 
22
22
  Arguments:
23
23
  model: The LLM to use for translation. If an OpenAI model, the
24
- `OPENAI_API_KEY` environment variable must be set and the
25
- `OPENAI_ORG_ID` environment variable should be set if needed.
24
+ `OPENAI_API_KEY` environment variable must be set.
26
25
  model_arguments: Additional arguments to pass to the LLM constructor.
27
26
  source_language: The source programming language.
28
27
  target_language: The target programming language.
@@ -67,7 +66,8 @@ class Translator(Converter):
67
66
  )
68
67
  self._target_language = target_language
69
68
  self._target_version = target_version
70
- self._target_suffix = f".{LANGUAGES[target_language]['suffix']}"
69
+ # Taking the first suffix as the default for output files
70
+ self._target_suffix = f".{LANGUAGES[target_language]['suffixes'][0]}"
71
71
 
72
72
  @run_if_changed(
73
73
  "_prompt_template_name",
@@ -87,7 +87,7 @@ class Collections:
87
87
  """Get the Chroma collections.
88
88
 
89
89
  Returns:
90
- The Chroma collections. Raises ValueError if not found.
90
+ The Chroma collections. Raises InvalidCollectionException if not found.
91
91
  """
92
92
  if isinstance(name, str):
93
93
  return [self._client.get_collection(name)]