janus-llm 3.4.2__tar.gz → 3.5.0__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {janus_llm-3.4.2 → janus_llm-3.5.0}/PKG-INFO +1 -1
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/__init__.py +1 -1
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/cli.py +123 -1
- janus_llm-3.5.0/janus/converter/aggregator.py +52 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/converter/converter.py +19 -9
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/converter/diagram.py +5 -5
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/llm/models_info.py +3 -1
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/parsers/_tests/test_code_parser.py +3 -2
- janus_llm-3.5.0/janus/parsers/code_parser.py +27 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/parsers/doc_parser.py +22 -17
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/parsers/eval_parser.py +11 -8
- janus_llm-3.5.0/janus/parsers/parser.py +51 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/parsers/refiner_parser.py +5 -10
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/parsers/reqs_parser.py +11 -12
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/parsers/uml.py +3 -2
- {janus_llm-3.4.2 → janus_llm-3.5.0}/pyproject.toml +1 -1
- janus_llm-3.4.2/janus/parsers/code_parser.py +0 -59
- {janus_llm-3.4.2 → janus_llm-3.5.0}/LICENSE +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/README.md +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/__main__.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/_tests/__init__.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/_tests/conftest.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/_tests/test_cli.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/converter/__init__.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/converter/_tests/__init__.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/converter/_tests/test_translate.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/converter/document.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/converter/evaluate.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/converter/requirements.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/converter/translate.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/embedding/__init__.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/embedding/_tests/__init__.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/embedding/_tests/test_collections.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/embedding/_tests/test_database.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/embedding/_tests/test_vectorize.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/embedding/collections.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/embedding/database.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/embedding/embedding_models_info.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/embedding/vectorize.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/__init__.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/_tests/__init__.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/_tests/test_combine.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/_tests/test_splitter.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/alc/__init__.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/alc/_tests/__init__.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/alc/_tests/test_alc.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/alc/alc.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/binary/__init__.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/binary/_tests/__init__.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/binary/_tests/test_binary.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/binary/binary.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/binary/reveng/decompile_script.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/block.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/combine.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/file.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/mumps/__init__.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/mumps/_tests/__init__.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/mumps/_tests/test_mumps.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/mumps/mumps.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/mumps/patterns.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/naive/__init__.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/naive/basic_splitter.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/naive/chunk_splitter.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/naive/registry.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/naive/simple_ast.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/naive/tag_splitter.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/node.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/splitter.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/treesitter/__init__.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/treesitter/_tests/__init__.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/treesitter/_tests/test_treesitter.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/language/treesitter/treesitter.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/llm/__init__.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/llm/model_callbacks.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/metrics/__init__.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/metrics/_tests/__init__.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/metrics/_tests/reference.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/metrics/_tests/target.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/metrics/_tests/test_bleu.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/metrics/_tests/test_chrf.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/metrics/_tests/test_file_pairing.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/metrics/_tests/test_llm.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/metrics/_tests/test_reading.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/metrics/_tests/test_rouge_score.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/metrics/_tests/test_similarity_score.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/metrics/_tests/test_treesitter_metrics.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/metrics/bleu.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/metrics/chrf.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/metrics/cli.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/metrics/complexity_metrics.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/metrics/file_pairing.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/metrics/llm_metrics.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/metrics/metric.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/metrics/reading.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/metrics/rouge_score.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/metrics/similarity.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/metrics/splitting.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/parsers/__init__.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/parsers/_tests/__init__.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/prompts/__init__.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/prompts/prompt.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/refiners/refiner.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/utils/__init__.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/utils/_tests/__init__.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/utils/_tests/test_logger.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/utils/_tests/test_progress.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/utils/enums.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/utils/logger.py +0 -0
- {janus_llm-3.4.2 → janus_llm-3.5.0}/janus/utils/progress.py +0 -0
@@ -5,7 +5,7 @@ from langchain_core._api.deprecation import LangChainDeprecationWarning
|
|
5
5
|
from janus.converter.translate import Translator
|
6
6
|
from janus.metrics import * # noqa: F403
|
7
7
|
|
8
|
-
__version__ = "3.
|
8
|
+
__version__ = "3.5.0"
|
9
9
|
|
10
10
|
# Ignoring a deprecation warning from langchain_core that I can't seem to hunt down
|
11
11
|
warnings.filterwarnings("ignore", category=LangChainDeprecationWarning)
|
@@ -2,7 +2,7 @@ import json
|
|
2
2
|
import logging
|
3
3
|
import os
|
4
4
|
from pathlib import Path
|
5
|
-
from typing import Optional
|
5
|
+
from typing import List, Optional
|
6
6
|
|
7
7
|
import click
|
8
8
|
import typer
|
@@ -12,6 +12,8 @@ from rich.console import Console
|
|
12
12
|
from rich.prompt import Confirm
|
13
13
|
from typing_extensions import Annotated
|
14
14
|
|
15
|
+
from janus.converter.aggregator import Aggregator
|
16
|
+
from janus.converter.converter import Converter
|
15
17
|
from janus.converter.diagram import DiagramGenerator
|
16
18
|
from janus.converter.document import Documenter, MadLibsDocumenter, MultiDocumenter
|
17
19
|
from janus.converter.requirements import RequirementsDocumenter
|
@@ -439,6 +441,126 @@ def document(
|
|
439
441
|
documenter.translate(input_dir, output_dir, overwrite, collection)
|
440
442
|
|
441
443
|
|
444
|
+
def get_subclasses(cls):
|
445
|
+
return set(cls.__subclasses__()).union(
|
446
|
+
set(s for c in cls.__subclasses__() for s in get_subclasses(c))
|
447
|
+
)
|
448
|
+
|
449
|
+
|
450
|
+
@app.command()
|
451
|
+
def aggregate(
|
452
|
+
input_dir: Annotated[
|
453
|
+
Path,
|
454
|
+
typer.Option(
|
455
|
+
"--input",
|
456
|
+
"-i",
|
457
|
+
help="The directory containing the source code to be translated. "
|
458
|
+
"The files should all be in one flat directory.",
|
459
|
+
),
|
460
|
+
],
|
461
|
+
language: Annotated[
|
462
|
+
str,
|
463
|
+
typer.Option(
|
464
|
+
"--language",
|
465
|
+
"-l",
|
466
|
+
help="The language of the source code.",
|
467
|
+
click_type=click.Choice(sorted(LANGUAGES)),
|
468
|
+
),
|
469
|
+
],
|
470
|
+
output_dir: Annotated[
|
471
|
+
Path,
|
472
|
+
typer.Option(
|
473
|
+
"--output-dir", "-o", help="The directory to store the translated code in."
|
474
|
+
),
|
475
|
+
],
|
476
|
+
llm_name: Annotated[
|
477
|
+
str,
|
478
|
+
typer.Option(
|
479
|
+
"--llm",
|
480
|
+
"-L",
|
481
|
+
help="The custom name of the model set with 'janus llm add'.",
|
482
|
+
),
|
483
|
+
] = "gpt-4o",
|
484
|
+
max_prompts: Annotated[
|
485
|
+
int,
|
486
|
+
typer.Option(
|
487
|
+
"--max-prompts",
|
488
|
+
"-m",
|
489
|
+
help="The maximum number of times to prompt a model on one functional block "
|
490
|
+
"before exiting the application. This is to prevent wasting too much money.",
|
491
|
+
),
|
492
|
+
] = 10,
|
493
|
+
overwrite: Annotated[
|
494
|
+
bool,
|
495
|
+
typer.Option(
|
496
|
+
"--overwrite/--preserve",
|
497
|
+
help="Whether to overwrite existing files in the output directory",
|
498
|
+
),
|
499
|
+
] = False,
|
500
|
+
temperature: Annotated[
|
501
|
+
float,
|
502
|
+
typer.Option("--temperature", "-t", help="Sampling temperature.", min=0, max=2),
|
503
|
+
] = 0.7,
|
504
|
+
collection: Annotated[
|
505
|
+
str,
|
506
|
+
typer.Option(
|
507
|
+
"--collection",
|
508
|
+
"-c",
|
509
|
+
help="If set, will put the translated result into a Chroma DB "
|
510
|
+
"collection with the name provided.",
|
511
|
+
),
|
512
|
+
] = None,
|
513
|
+
splitter_type: Annotated[
|
514
|
+
str,
|
515
|
+
typer.Option(
|
516
|
+
"-S",
|
517
|
+
"--splitter",
|
518
|
+
help="Name of custom splitter to use",
|
519
|
+
click_type=click.Choice(list(CUSTOM_SPLITTERS.keys())),
|
520
|
+
),
|
521
|
+
] = "file",
|
522
|
+
intermediate_converters: Annotated[
|
523
|
+
List[str],
|
524
|
+
typer.Option(
|
525
|
+
"-C",
|
526
|
+
"--converter",
|
527
|
+
help="Name of an intermediate converter to use",
|
528
|
+
click_type=click.Choice([c.__name__ for c in get_subclasses(Converter)]),
|
529
|
+
),
|
530
|
+
] = ["Documenter"],
|
531
|
+
):
|
532
|
+
converter_subclasses = get_subclasses(Converter)
|
533
|
+
converter_subclasses_map = {c.__name__: c for c in converter_subclasses}
|
534
|
+
model_arguments = dict(temperature=temperature)
|
535
|
+
collections_config = get_collections_config()
|
536
|
+
converters = []
|
537
|
+
for ic in intermediate_converters:
|
538
|
+
converters.append(
|
539
|
+
converter_subclasses_map[ic](
|
540
|
+
model=llm_name,
|
541
|
+
model_arguments=model_arguments,
|
542
|
+
source_language=language,
|
543
|
+
max_prompts=max_prompts,
|
544
|
+
db_path=db_loc,
|
545
|
+
db_config=collections_config,
|
546
|
+
splitter_type=splitter_type,
|
547
|
+
)
|
548
|
+
)
|
549
|
+
|
550
|
+
aggregator = Aggregator(
|
551
|
+
intermediate_converters=converters,
|
552
|
+
model=llm_name,
|
553
|
+
model_arguments=model_arguments,
|
554
|
+
source_language=language,
|
555
|
+
max_prompts=max_prompts,
|
556
|
+
db_path=db_loc,
|
557
|
+
db_config=collections_config,
|
558
|
+
splitter_type=splitter_type,
|
559
|
+
prompt_template="basic_aggregation",
|
560
|
+
)
|
561
|
+
aggregator.translate(input_dir, output_dir, overwrite, collection)
|
562
|
+
|
563
|
+
|
442
564
|
@app.command(
|
443
565
|
help="Diagram input code using an LLM.",
|
444
566
|
no_args_is_help=True,
|
@@ -0,0 +1,52 @@
|
|
1
|
+
from copy import deepcopy
|
2
|
+
from typing import List
|
3
|
+
|
4
|
+
from janus.converter.converter import Converter
|
5
|
+
from janus.language.block import CodeBlock, TranslatedCodeBlock
|
6
|
+
|
7
|
+
|
8
|
+
class Aggregator(Converter):
|
9
|
+
def __init__(
|
10
|
+
self,
|
11
|
+
intermediate_converters: List[Converter],
|
12
|
+
separator: str = "\n==============\n",
|
13
|
+
**kwargs,
|
14
|
+
):
|
15
|
+
"""
|
16
|
+
Initialization Method
|
17
|
+
Arguments:
|
18
|
+
intermediate_converters - list of converters to use
|
19
|
+
separator: separator string to partition different outputs before combination
|
20
|
+
"""
|
21
|
+
self._intermediate_converters = intermediate_converters
|
22
|
+
self._separator = separator
|
23
|
+
super().__init__(**kwargs)
|
24
|
+
self._load_parameters()
|
25
|
+
|
26
|
+
def _iterative_translate(self, root: CodeBlock) -> TranslatedCodeBlock:
|
27
|
+
res = TranslatedCodeBlock(root, language=self._target_language)
|
28
|
+
return self._recursive_translate(res)
|
29
|
+
|
30
|
+
def _recursive_translate(self, root: TranslatedCodeBlock) -> None:
|
31
|
+
"""
|
32
|
+
Recursively translates code blocks from a bottom up approach
|
33
|
+
"""
|
34
|
+
original_text = root.original.text
|
35
|
+
if len(root.children) > 0:
|
36
|
+
for c in root.children:
|
37
|
+
self._recursive_translate(c)
|
38
|
+
root.original.text = self._combine_blocks(root.children, self._separator)
|
39
|
+
else:
|
40
|
+
int_reps = [deepcopy(root) for ic in self._intermediate_converters]
|
41
|
+
for ic, r in zip(self._intermediate_converters, int_reps):
|
42
|
+
ic._add_translation(r)
|
43
|
+
root.original.text = self._combine_blocks(int_reps, self._separator)
|
44
|
+
self._add_translation(root)
|
45
|
+
root.original.text = original_text
|
46
|
+
return root
|
47
|
+
|
48
|
+
def _combine_blocks(self, blocks: List[TranslatedCodeBlock], separator: str) -> str:
|
49
|
+
"""
|
50
|
+
Combines code blocks into a single piece of text
|
51
|
+
"""
|
52
|
+
return separator.join([block.text for block in blocks])
|
@@ -7,7 +7,6 @@ from typing import Any, List, Optional, Tuple
|
|
7
7
|
from langchain.output_parsers import RetryWithErrorOutputParser
|
8
8
|
from langchain_core.exceptions import OutputParserException
|
9
9
|
from langchain_core.language_models import BaseLanguageModel
|
10
|
-
from langchain_core.output_parsers import BaseOutputParser
|
11
10
|
from langchain_core.prompts import ChatPromptTemplate, SystemMessagePromptTemplate
|
12
11
|
from langchain_core.runnables import RunnableLambda, RunnableParallel
|
13
12
|
from openai import BadRequestError, RateLimitError
|
@@ -26,7 +25,7 @@ from janus.language.splitter import (
|
|
26
25
|
from janus.llm import load_model
|
27
26
|
from janus.llm.model_callbacks import get_model_callback
|
28
27
|
from janus.llm.models_info import MODEL_PROMPT_ENGINES
|
29
|
-
from janus.parsers.
|
28
|
+
from janus.parsers.parser import GenericParser, JanusParser
|
30
29
|
from janus.parsers.refiner_parser import RefinerParser
|
31
30
|
from janus.refiners.refiner import BasicRefiner, Refiner
|
32
31
|
from janus.utils.enums import LANGUAGES
|
@@ -129,7 +128,7 @@ class Converter:
|
|
129
128
|
self._llm: BaseLanguageModel
|
130
129
|
self._prompt: ChatPromptTemplate
|
131
130
|
|
132
|
-
self._parser:
|
131
|
+
self._parser: JanusParser = GenericParser()
|
133
132
|
self._combiner: Combiner = Combiner()
|
134
133
|
|
135
134
|
self._refiner_type: str
|
@@ -328,6 +327,7 @@ class Converter:
|
|
328
327
|
"_prompt_template_name",
|
329
328
|
"_source_language",
|
330
329
|
"_model_name",
|
330
|
+
"_parser",
|
331
331
|
)
|
332
332
|
def _load_prompt(self) -> None:
|
333
333
|
"""Load the prompt according to this instance's attributes.
|
@@ -340,6 +340,9 @@ class Converter:
|
|
340
340
|
prompt_template=self._prompt_template_name,
|
341
341
|
)
|
342
342
|
self._prompt = prompt_engine.prompt
|
343
|
+
self._prompt = self._prompt.partial(
|
344
|
+
format_instructions=self._parser.get_format_instructions()
|
345
|
+
)
|
343
346
|
|
344
347
|
@run_if_changed("_db_path", "_db_config")
|
345
348
|
def _load_vectorizer(self) -> None:
|
@@ -445,6 +448,15 @@ class Converter:
|
|
445
448
|
except FileSizeError:
|
446
449
|
log.warning("Current tile is too large for basic splitter, skipping")
|
447
450
|
continue
|
451
|
+
except ValueError as e:
|
452
|
+
if str(e).startswith(
|
453
|
+
"Error raised by bedrock service"
|
454
|
+
) and "maximum context length" in str(e):
|
455
|
+
log.warning(
|
456
|
+
"Input is too large for this model's context length, skipping"
|
457
|
+
)
|
458
|
+
continue
|
459
|
+
raise e
|
448
460
|
|
449
461
|
# Don't attempt to write files for which translation failed
|
450
462
|
if not out_block.translated:
|
@@ -599,7 +611,7 @@ class Converter:
|
|
599
611
|
to the cube root of self.max_retries, so the total calls to the
|
600
612
|
LLM will be roughly as expected (up to sqrt(self.max_retries) over)
|
601
613
|
"""
|
602
|
-
self._parser.
|
614
|
+
input = self._parser.parse_input(block.original)
|
603
615
|
|
604
616
|
# Retries with just the output and the error
|
605
617
|
n1 = round(self.max_prompts ** (1 / 2))
|
@@ -607,15 +619,12 @@ class Converter:
|
|
607
619
|
# Retries with the input, output, and error
|
608
620
|
n2 = round(self.max_prompts // n1)
|
609
621
|
|
610
|
-
# Retries with just the input
|
611
622
|
if not self.skip_context:
|
612
623
|
self._make_prompt_additions(block)
|
613
624
|
if not self.skip_refiner: # Make replacements in the prompt
|
614
625
|
refine_output = RefinerParser(
|
615
626
|
parser=self._parser,
|
616
|
-
initial_prompt=self._prompt.format(
|
617
|
-
**{"SOURCE_CODE": block.original.text}
|
618
|
-
),
|
627
|
+
initial_prompt=self._prompt.format(**{"SOURCE_CODE": input}),
|
619
628
|
refiner=self._refiner,
|
620
629
|
max_retries=n1,
|
621
630
|
llm=self._llm,
|
@@ -626,13 +635,14 @@ class Converter:
|
|
626
635
|
parser=self._parser,
|
627
636
|
max_retries=n1,
|
628
637
|
)
|
638
|
+
|
629
639
|
completion_chain = self._prompt | self._llm
|
630
640
|
chain = RunnableParallel(
|
631
641
|
completion=completion_chain, prompt_value=self._prompt
|
632
642
|
) | RunnableLambda(lambda x: refine_output.parse_with_prompt(**x))
|
633
643
|
for _ in range(n2):
|
634
644
|
try:
|
635
|
-
return chain.invoke({"SOURCE_CODE":
|
645
|
+
return chain.invoke({"SOURCE_CODE": input})
|
636
646
|
except OutputParserException:
|
637
647
|
pass
|
638
648
|
|
@@ -52,7 +52,7 @@ class DiagramGenerator(Documenter):
|
|
52
52
|
self._load_diagram_prompt_engine()
|
53
53
|
|
54
54
|
def _run_chain(self, block: TranslatedCodeBlock) -> str:
|
55
|
-
self._parser.
|
55
|
+
input = self._parser.parse_input(block.original)
|
56
56
|
n1 = round(self.max_prompts ** (1 / 3))
|
57
57
|
|
58
58
|
# Retries with the input, output, and error
|
@@ -67,7 +67,7 @@ class DiagramGenerator(Documenter):
|
|
67
67
|
parser=self._diagram_parser,
|
68
68
|
initial_prompt=self._diagram_prompt.format(
|
69
69
|
**{
|
70
|
-
"SOURCE_CODE":
|
70
|
+
"SOURCE_CODE": input,
|
71
71
|
"DOCUMENTATION": documentation_text,
|
72
72
|
"DIAGRAM_TYPE": self._diagram_type,
|
73
73
|
}
|
@@ -81,7 +81,7 @@ class DiagramGenerator(Documenter):
|
|
81
81
|
parser=self._diagram_parser,
|
82
82
|
initial_prompt=self._diagram_prompt.format(
|
83
83
|
**{
|
84
|
-
"SOURCE_CODE":
|
84
|
+
"SOURCE_CODE": input,
|
85
85
|
"DIAGRAM_TYPE": self._diagram_type,
|
86
86
|
}
|
87
87
|
),
|
@@ -103,7 +103,7 @@ class DiagramGenerator(Documenter):
|
|
103
103
|
if self._add_documentation:
|
104
104
|
return chain.invoke(
|
105
105
|
{
|
106
|
-
"SOURCE_CODE":
|
106
|
+
"SOURCE_CODE": input,
|
107
107
|
"DOCUMENTATION": documentation_text,
|
108
108
|
"DIAGRAM_TYPE": self._diagram_type,
|
109
109
|
}
|
@@ -111,7 +111,7 @@ class DiagramGenerator(Documenter):
|
|
111
111
|
else:
|
112
112
|
return chain.invoke(
|
113
113
|
{
|
114
|
-
"SOURCE_CODE":
|
114
|
+
"SOURCE_CODE": input,
|
115
115
|
"DIAGRAM_TYPE": self._diagram_type,
|
116
116
|
}
|
117
117
|
)
|
@@ -210,7 +210,9 @@ def get_available_model_names() -> list[str]:
|
|
210
210
|
return avaialable_models
|
211
211
|
|
212
212
|
|
213
|
-
def load_model(
|
213
|
+
def load_model(
|
214
|
+
user_model_name: str,
|
215
|
+
) -> tuple[BaseLanguageModel, str, int, dict[str, float]]:
|
214
216
|
if not MODEL_CONFIG_DIR.exists():
|
215
217
|
MODEL_CONFIG_DIR.mkdir(parents=True)
|
216
218
|
model_config_file = MODEL_CONFIG_DIR / f"{user_model_name}.json"
|
@@ -1,11 +1,12 @@
|
|
1
1
|
import unittest
|
2
2
|
|
3
|
-
from janus.parsers.code_parser import CodeParser
|
3
|
+
from janus.parsers.code_parser import CodeParser
|
4
|
+
from janus.parsers.parser import GenericParser
|
4
5
|
|
5
6
|
|
6
7
|
class TestJanusParser(unittest.TestCase):
|
7
8
|
def setUp(self):
|
8
|
-
self.parser =
|
9
|
+
self.parser = GenericParser()
|
9
10
|
|
10
11
|
def test_parse_combined_output(self):
|
11
12
|
text = "test text"
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import re
|
2
|
+
|
3
|
+
from langchain_core.exceptions import OutputParserException
|
4
|
+
from langchain_core.messages import BaseMessage
|
5
|
+
|
6
|
+
from janus.parsers.parser import JanusParser
|
7
|
+
from janus.utils.logger import create_logger
|
8
|
+
|
9
|
+
log = create_logger(__name__)
|
10
|
+
|
11
|
+
|
12
|
+
class CodeParser(JanusParser):
|
13
|
+
language: str
|
14
|
+
|
15
|
+
def parse(self, text: str | BaseMessage) -> str:
|
16
|
+
if isinstance(text, BaseMessage):
|
17
|
+
text = str(text.content)
|
18
|
+
pattern = rf"```[^\S\r\n]*(?:{self.language}[^\S\r\n]*)?\n?(.*?)\n*```"
|
19
|
+
code = re.search(pattern, text, re.DOTALL)
|
20
|
+
if code is None:
|
21
|
+
raise OutputParserException(
|
22
|
+
"Code not find code between triple square brackets"
|
23
|
+
)
|
24
|
+
return str(code.group(1))
|
25
|
+
|
26
|
+
def get_format_instructions(self) -> str:
|
27
|
+
return "Output must contain text contained within triple square brackets (```)"
|
@@ -3,13 +3,12 @@ import re
|
|
3
3
|
|
4
4
|
from langchain.output_parsers import PydanticOutputParser
|
5
5
|
from langchain.output_parsers.json import parse_json_markdown
|
6
|
-
from langchain.schema.output_parser import BaseOutputParser
|
7
6
|
from langchain_core.exceptions import OutputParserException
|
8
|
-
from langchain_core.messages import
|
7
|
+
from langchain_core.messages import BaseMessage
|
9
8
|
from langchain_core.pydantic_v1 import BaseModel, Field
|
10
9
|
|
11
10
|
from janus.language.block import CodeBlock
|
12
|
-
from janus.parsers.
|
11
|
+
from janus.parsers.parser import JanusParser
|
13
12
|
from janus.utils.logger import create_logger
|
14
13
|
|
15
14
|
log = create_logger(__name__)
|
@@ -32,18 +31,21 @@ class MultiDoc(BaseModel):
|
|
32
31
|
)
|
33
32
|
|
34
33
|
|
35
|
-
class MultiDocumentationParser(
|
34
|
+
class MultiDocumentationParser(JanusParser, PydanticOutputParser):
|
36
35
|
block_name: str = ""
|
37
36
|
|
38
37
|
def __init__(self):
|
39
38
|
PydanticOutputParser.__init__(self, pydantic_object=MultiDoc)
|
40
39
|
|
41
|
-
def
|
42
|
-
|
40
|
+
def parse_input(self, block: CodeBlock) -> str:
|
41
|
+
text = super().parse_input(block)
|
42
|
+
self.block_name = str(block.name)
|
43
|
+
return text
|
44
|
+
|
45
|
+
def parse(self, text: str | BaseMessage) -> str:
|
46
|
+
if isinstance(text, BaseMessage):
|
47
|
+
text = str(text.content)
|
43
48
|
|
44
|
-
def parse(self, text: str) -> str:
|
45
|
-
if isinstance(text, AIMessage):
|
46
|
-
text = text.content
|
47
49
|
try:
|
48
50
|
docs = json.loads(super().parse(text).json())
|
49
51
|
except (OutputParserException, json.JSONDecodeError):
|
@@ -81,22 +83,25 @@ class MultiDocumentationParser(PydanticOutputParser, JanusParser):
|
|
81
83
|
|
82
84
|
@property
|
83
85
|
def _type(self) -> str:
|
84
|
-
return self.__class__.name
|
86
|
+
return str(self.__class__.name)
|
85
87
|
|
86
88
|
|
87
|
-
class MadlibsDocumentationParser(
|
89
|
+
class MadlibsDocumentationParser(JanusParser):
|
88
90
|
expected_keys: set[str]
|
89
91
|
|
90
92
|
def __init__(self):
|
91
93
|
super().__init__(expected_keys=[])
|
92
94
|
|
93
|
-
def
|
94
|
-
|
95
|
+
def parse_input(self, block: CodeBlock):
|
96
|
+
# TODO: Perform comment stripping/placeholding here rather than in script
|
97
|
+
text = super().parse_input(block)
|
98
|
+
comment_ids = re.findall(r"<(?:BLOCK|INLINE)_COMMENT (\w{8})>", text)
|
95
99
|
self.expected_keys = set(comment_ids)
|
96
100
|
|
97
|
-
def parse(self, text: str) -> str:
|
98
|
-
if isinstance(text,
|
99
|
-
text = text.content
|
101
|
+
def parse(self, text: str | BaseMessage) -> str:
|
102
|
+
if isinstance(text, BaseMessage):
|
103
|
+
text = str(text.content)
|
104
|
+
|
100
105
|
try:
|
101
106
|
obj = parse_json_markdown(text)
|
102
107
|
except json.JSONDecodeError as e:
|
@@ -166,4 +171,4 @@ class MadlibsDocumentationParser(BaseOutputParser[str], JanusParser):
|
|
166
171
|
|
167
172
|
@property
|
168
173
|
def _type(self) -> str:
|
169
|
-
return self.__class__.name
|
174
|
+
return str(self.__class__.name)
|
@@ -1,9 +1,10 @@
|
|
1
1
|
import json
|
2
2
|
|
3
3
|
from langchain.output_parsers import PydanticOutputParser
|
4
|
+
from langchain_core.messages import BaseMessage
|
4
5
|
from langchain_core.pydantic_v1 import BaseModel, Field, validator
|
5
6
|
|
6
|
-
from janus.parsers.
|
7
|
+
from janus.parsers.parser import JanusParser
|
7
8
|
from janus.utils.logger import create_logger
|
8
9
|
|
9
10
|
log = create_logger(__name__)
|
@@ -28,7 +29,7 @@ class Eval(BaseModel):
|
|
28
29
|
|
29
30
|
return v
|
30
31
|
|
31
|
-
def __add__(self, other):
|
32
|
+
def __add__(self, other: "Eval"):
|
32
33
|
if isinstance(other, int) and other == 0:
|
33
34
|
return self.copy()
|
34
35
|
return Eval.construct(
|
@@ -38,10 +39,10 @@ class Eval(BaseModel):
|
|
38
39
|
completeness=self.completeness + other.completeness,
|
39
40
|
)
|
40
41
|
|
41
|
-
def __radd__(self, other):
|
42
|
+
def __radd__(self, other) -> "Eval":
|
42
43
|
return self.__add__(other)
|
43
44
|
|
44
|
-
def __truediv__(self, other):
|
45
|
+
def __truediv__(self, other) -> "Eval":
|
45
46
|
if isinstance(other, int):
|
46
47
|
return Eval.construct(
|
47
48
|
syntax=self.syntax / other,
|
@@ -57,11 +58,13 @@ class Eval(BaseModel):
|
|
57
58
|
)
|
58
59
|
|
59
60
|
|
60
|
-
class EvaluationParser(
|
61
|
+
class EvaluationParser(JanusParser, PydanticOutputParser):
|
61
62
|
def __init__(self):
|
62
63
|
PydanticOutputParser.__init__(self, pydantic_object=Eval)
|
63
64
|
|
64
|
-
def parse(self, text: str) -> str:
|
65
|
+
def parse(self, text: str | BaseMessage) -> str:
|
66
|
+
if isinstance(text, BaseMessage):
|
67
|
+
text = str(text.content)
|
65
68
|
eval = super().parse(text)
|
66
69
|
return json.dumps(eval.json())
|
67
70
|
|
@@ -75,6 +78,6 @@ class EvaluationParser(PydanticOutputParser, JanusParser):
|
|
75
78
|
Returns:
|
76
79
|
A parsed version of the text.
|
77
80
|
"""
|
78
|
-
objs = [super().parse(line.strip()) for line in text.split("\n")]
|
79
|
-
avg_obj = sum(objs) / len(objs)
|
81
|
+
objs: list[Eval] = [super().parse(line.strip()) for line in text.split("\n")]
|
82
|
+
avg_obj: Eval = sum(objs) / len(objs)
|
80
83
|
return json.dumps(avg_obj.json())
|
@@ -0,0 +1,51 @@
|
|
1
|
+
from langchain.schema.output_parser import BaseOutputParser
|
2
|
+
from langchain_core.messages import BaseMessage
|
3
|
+
from langchain_core.output_parsers import StrOutputParser
|
4
|
+
|
5
|
+
from janus.language.block import CodeBlock
|
6
|
+
from janus.language.splitter import EmptyTreeError
|
7
|
+
from janus.utils.logger import create_logger
|
8
|
+
|
9
|
+
log = create_logger(__name__)
|
10
|
+
|
11
|
+
|
12
|
+
class JanusParser(BaseOutputParser[str]):
|
13
|
+
def parse_input(self, block: CodeBlock) -> str:
|
14
|
+
"""Parse the input block into raw string input ready to be passed to
|
15
|
+
an LLM. Also perform any processing or saving of metadata.
|
16
|
+
|
17
|
+
Arguments:
|
18
|
+
block: The CodeBlock to be processed
|
19
|
+
|
20
|
+
Returns:
|
21
|
+
A parsed version of the input text
|
22
|
+
"""
|
23
|
+
if block.text is None:
|
24
|
+
raise EmptyTreeError("No text in input CodeBlock!")
|
25
|
+
return block.text
|
26
|
+
|
27
|
+
def parse_combined_output(self, text: str) -> str:
|
28
|
+
"""Parse the output text from the LLM when multiple inputs are combined
|
29
|
+
|
30
|
+
Arguments:
|
31
|
+
text: The output text from the LLM
|
32
|
+
|
33
|
+
Returns:
|
34
|
+
A parsed version of the text
|
35
|
+
"""
|
36
|
+
return text
|
37
|
+
|
38
|
+
def parse_into_block(self, text: str | BaseMessage, block: CodeBlock):
|
39
|
+
if isinstance(text, BaseMessage):
|
40
|
+
text = str(text.content)
|
41
|
+
block.text = text
|
42
|
+
|
43
|
+
|
44
|
+
class GenericParser(JanusParser, StrOutputParser):
|
45
|
+
def parse(self, text: str | BaseMessage) -> str:
|
46
|
+
if isinstance(text, BaseMessage):
|
47
|
+
text = str(text.content)
|
48
|
+
return text
|
49
|
+
|
50
|
+
def get_format_instructions(self) -> str:
|
51
|
+
return "Output should be a string"
|
@@ -1,11 +1,13 @@
|
|
1
1
|
from langchain_core.exceptions import OutputParserException
|
2
2
|
from langchain_core.language_models import BaseLanguageModel
|
3
|
+
from langchain_core.messages import BaseMessage
|
3
4
|
from langchain_core.output_parsers import BaseOutputParser
|
4
5
|
|
6
|
+
from janus.parsers.parser import JanusParser
|
5
7
|
from janus.refiners.refiner import Refiner
|
6
8
|
|
7
9
|
|
8
|
-
class RefinerParser(
|
10
|
+
class RefinerParser(JanusParser):
|
9
11
|
"""Parser for performing refinement with a refiner
|
10
12
|
|
11
13
|
Properties:
|
@@ -25,15 +27,7 @@ class RefinerParser(BaseOutputParser):
|
|
25
27
|
refiner: Refiner
|
26
28
|
max_retries: int
|
27
29
|
|
28
|
-
def parse(self, text: str) -> str:
|
29
|
-
"""Parses the text using the refiner
|
30
|
-
|
31
|
-
Arguments:
|
32
|
-
text: text to parse
|
33
|
-
|
34
|
-
Returns:
|
35
|
-
Parsed text
|
36
|
-
"""
|
30
|
+
def parse(self, text: str | BaseMessage) -> str:
|
37
31
|
last_prompt = self.initial_prompt
|
38
32
|
for _ in range(self.max_retries):
|
39
33
|
try:
|
@@ -46,6 +40,7 @@ class RefinerParser(BaseOutputParser):
|
|
46
40
|
new_chain = new_prompt | self.llm
|
47
41
|
text = new_chain.invoke(prompt_arguments)
|
48
42
|
last_prompt = new_prompt.format(**prompt_arguments)
|
43
|
+
|
49
44
|
raise OutputParserException(
|
50
45
|
f"Error: unable to correct output after {self.max_retries} attempts"
|
51
46
|
)
|
@@ -2,29 +2,28 @@ import json
|
|
2
2
|
import re
|
3
3
|
|
4
4
|
from langchain.output_parsers.json import parse_json_markdown
|
5
|
-
from langchain.schema.output_parser import BaseOutputParser
|
6
5
|
from langchain_core.exceptions import OutputParserException
|
7
|
-
from langchain_core.messages import
|
6
|
+
from langchain_core.messages import BaseMessage
|
8
7
|
|
9
|
-
from janus.
|
10
|
-
from janus.parsers.code_parser import JanusParser
|
8
|
+
from janus.parsers.parser import JanusParser
|
11
9
|
from janus.utils.logger import create_logger
|
12
10
|
|
13
11
|
log = create_logger(__name__)
|
14
12
|
|
15
13
|
|
16
|
-
class RequirementsParser(
|
17
|
-
|
14
|
+
class RequirementsParser(JanusParser):
|
15
|
+
expected_keys: set[str]
|
18
16
|
|
19
17
|
def __init__(self):
|
20
18
|
super().__init__(expected_keys=[])
|
21
19
|
|
22
|
-
def
|
23
|
-
|
20
|
+
def parse(self, text: str | BaseMessage) -> str:
|
21
|
+
if isinstance(text, BaseMessage):
|
22
|
+
text = str(text.content)
|
24
23
|
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
# TODO: This is an incorrect implementation (lstrip and rstrip take character
|
25
|
+
# lists and strip any instances of those characters, not the full str)
|
26
|
+
# Should be replaced with a regex search, see CodeParser
|
28
27
|
text = text.lstrip("```json")
|
29
28
|
text = text.rstrip("```")
|
30
29
|
try:
|
@@ -70,4 +69,4 @@ class RequirementsParser(BaseOutputParser[str], JanusParser):
|
|
70
69
|
|
71
70
|
@property
|
72
71
|
def _type(self) -> str:
|
73
|
-
return self.__class__.name
|
72
|
+
return str(self.__class__.name)
|
@@ -4,6 +4,7 @@ from pathlib import Path
|
|
4
4
|
from typing import List, Tuple
|
5
5
|
|
6
6
|
from langchain_core.exceptions import OutputParserException
|
7
|
+
from langchain_core.messages import BaseMessage
|
7
8
|
|
8
9
|
from janus.parsers.code_parser import CodeParser
|
9
10
|
from janus.utils.logger import create_logger
|
@@ -12,7 +13,7 @@ log = create_logger(__name__)
|
|
12
13
|
|
13
14
|
|
14
15
|
class UMLSyntaxParser(CodeParser):
|
15
|
-
def _get_uml_output(self, file:
|
16
|
+
def _get_uml_output(self, file: Path) -> Tuple[str, str]:
|
16
17
|
# NOTE: running subprocess with shell=False, added nosec to label that we know
|
17
18
|
# risk exists
|
18
19
|
try:
|
@@ -33,7 +34,7 @@ class UMLSyntaxParser(CodeParser):
|
|
33
34
|
def _get_errs(self, s: str) -> List[str]:
|
34
35
|
return [x.group() for x in re.finditer(r"Error (.*)\n", s)]
|
35
36
|
|
36
|
-
def parse(self, text: str) -> str:
|
37
|
+
def parse(self, text: str | BaseMessage) -> str:
|
37
38
|
text = super().parse(text)
|
38
39
|
janus_path = Path.home().expanduser() / Path(".janus")
|
39
40
|
if not janus_path.exists():
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "janus-llm"
|
3
|
-
version = "3.
|
3
|
+
version = "3.5.0"
|
4
4
|
description = "A transcoding library using LLMs."
|
5
5
|
authors = ["Michael Doyle <mdoyle@mitre.org>", "Chris Glasz <cglasz@mitre.org>",
|
6
6
|
"Chris Tohline <ctohline@mitre.org>", "William Macke <wmacke@mitre.org>",
|
@@ -1,59 +0,0 @@
|
|
1
|
-
import re
|
2
|
-
|
3
|
-
from langchain.schema.output_parser import BaseOutputParser
|
4
|
-
from langchain_core.exceptions import OutputParserException
|
5
|
-
from langchain_core.messages import BaseMessage
|
6
|
-
from langchain_core.output_parsers import StrOutputParser
|
7
|
-
|
8
|
-
from janus.language.block import CodeBlock
|
9
|
-
from janus.utils.logger import create_logger
|
10
|
-
|
11
|
-
log = create_logger(__name__)
|
12
|
-
|
13
|
-
|
14
|
-
class JanusParser:
|
15
|
-
def parse_combined_output(self, text: str) -> str:
|
16
|
-
"""Parse the output text from the LLM when multiple inputs are combined
|
17
|
-
|
18
|
-
Arguments:
|
19
|
-
text: The output text from the LLM
|
20
|
-
|
21
|
-
Returns:
|
22
|
-
A parsed version of the text
|
23
|
-
"""
|
24
|
-
if isinstance(text, BaseMessage):
|
25
|
-
text = text.content
|
26
|
-
return text
|
27
|
-
|
28
|
-
def parse_into_block(self, text: str, block: CodeBlock):
|
29
|
-
if isinstance(text, BaseMessage):
|
30
|
-
text = text.content
|
31
|
-
block.text = text
|
32
|
-
|
33
|
-
def set_reference(self, block: CodeBlock):
|
34
|
-
pass
|
35
|
-
|
36
|
-
|
37
|
-
class GenericParser(StrOutputParser, JanusParser):
|
38
|
-
def parse(self, text: str) -> str:
|
39
|
-
if isinstance(text, BaseMessage):
|
40
|
-
return text.content
|
41
|
-
return text
|
42
|
-
|
43
|
-
|
44
|
-
class CodeParser(BaseOutputParser[str], JanusParser):
|
45
|
-
language: str
|
46
|
-
|
47
|
-
def parse(self, text: str) -> str:
|
48
|
-
if isinstance(text, BaseMessage):
|
49
|
-
text = text.content
|
50
|
-
pattern = rf"```[^\S\r\n]*(?:{self.language}[^\S\r\n]*)?\n?(.*?)\n*```"
|
51
|
-
code = re.search(pattern, text, re.DOTALL)
|
52
|
-
if code is None:
|
53
|
-
raise OutputParserException(
|
54
|
-
"Code not find code between triple square brackets"
|
55
|
-
)
|
56
|
-
return str(code.group(1))
|
57
|
-
|
58
|
-
def get_format_instructions(self) -> str:
|
59
|
-
return "Output must contain text contained within triple square brackets (```)"
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|