├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── index.html ├── requirements.txt ├── src ├── __init__.py ├── create │ ├── __init__.py │ ├── csn.py │ ├── swebench.py │ └── utils.py ├── evaluations │ ├── __init__.py │ ├── eval_coir.py │ ├── eval_csn.py │ ├── eval_localization.py │ ├── eval_swebench.py │ └── utils.py ├── get_repo_structure │ ├── __init__.py │ ├── get_patch_info.py │ └── get_repo_structure.py ├── rerank.py └── run_pipeline.sh └── static ├── .DS_Store ├── css ├── bulma-carousel.min.css ├── bulma-slider.min.css ├── bulma.css.map.txt ├── bulma.min.css ├── fontawesome.all.min.css └── index.css ├── images ├── .DS_Store ├── coderankllm.png ├── codesearchnet.png ├── coir.png ├── cornstack.png ├── favicon.svg ├── file_level.png └── function_level.png └── js ├── bulma-carousel.js ├── bulma-carousel.min.js ├── bulma-slider.js ├── bulma-slider.min.js ├── fontawesome.all.min.js └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | data/ 2 | **/ids_to_keep_*.json 3 | *counts.json* 4 | medi*.json 5 | nq* 6 | shards 7 | filtered 8 | *.onnx 9 | **triton_models** 10 | *.arrow 11 | **results** 12 | results.md 13 | mteb_metadata.md 14 | rank_*_processed.json 15 | ckpts 16 | wandb 17 | **metadata/ 18 | scripts/text/embedding_training_data/dotted/* 19 | scripts/video/preproc/ 20 | *.csv 21 | scripts/reddit/downloaded/* 22 | *.jsonl 23 | *.gz 24 | *.parquet 25 | 26 | # Dataset directories 27 | datasets/ 28 | code_datasets/ 29 | 30 | # Output directories 31 | outputs/ 32 | results/ 33 | 34 | # Evaluation results 35 | evaluations/ 36 | eval_results/ 37 | 38 | # Byte-compiled / optimized / DLL files 39 | __pycache__/ 40 | *.py[cod] 41 | *$py.class 42 | slurm-* 43 | # C extensions 44 | *.so 45 | 46 | # Distribution / packaging 47 | .Python 48 | build/ 49 | develop-eggs/ 50 | dist/ 51 | downloads/ 52 | eggs/ 53 | .eggs/ 54 | lib/ 55 | lib64/ 56 | parts/ 57 | sdist/ 58 | var/ 59 | wheels/ 60 | share/python-wheels/ 61 | *.egg-info/ 62 | .installed.cfg 63 | *.egg 64 | MANIFEST 65 | 66 | # PyInstaller 67 | # Usually these files are written by a python script from a template 68 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 69 | *.manifest 70 | *.spec 71 | 72 | # Installer logs 73 | pip-log.txt 74 | pip-delete-this-directory.txt 75 | 76 | # Unit test / coverage reports 77 | htmlcov/ 78 | .tox/ 79 | .nox/ 80 | .coverage 81 | .coverage.* 82 | .cache 83 | nosetests.xml 84 | coverage.xml 85 | *.cover 86 | *.py,cover 87 | .hypothesis/ 88 | .pytest_cache/ 89 | cover/ 90 | 91 | # Translations 92 | *.mo 93 | *.pot 94 | 95 | # Django stuff: 96 | *.log 97 | local_settings.py 98 | db.sqlite3 99 | db.sqlite3-journal 100 | 101 | # Flask stuff: 102 | instance/ 103 | .webassets-cache 104 | 105 | # Scrapy stuff: 106 | .scrapy 107 | 108 | # Sphinx documentation 109 | docs/_build/ 110 | 111 | # PyBuilder 112 | .pybuilder/ 113 | target/ 114 | 115 | # Jupyter Notebook 116 | .ipynb_checkpoints 117 | 118 | # IPython 119 | profile_default/ 120 | ipython_config.py 121 | 122 | # pyenv 123 | # For a library or package, you might want to ignore these files since the code is 124 | # intended to run in multiple environments; otherwise, check them in: 125 | # .python-version 126 | 127 | # pipenv 128 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 129 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 130 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 131 | # install all needed dependencies. 132 | #Pipfile.lock 133 | 134 | # poetry 135 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 136 | # This is especially recommended for binary packages to ensure reproducibility, and is more 137 | # commonly ignored for libraries. 138 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 139 | #poetry.lock 140 | 141 | # pdm 142 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 143 | #pdm.lock 144 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 145 | # in version control. 146 | # https://pdm.fming.dev/#use-with-ide 147 | .pdm.toml 148 | 149 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 150 | __pypackages__/ 151 | 152 | # Celery stuff 153 | celerybeat-schedule 154 | celerybeat.pid 155 | 156 | # SageMath parsed files 157 | *.sage.py 158 | 159 | # Environments 160 | .env 161 | .venv 162 | env/ 163 | venv/ 164 | ENV/ 165 | env.bak/ 166 | venv.bak/ 167 | 168 | # Spyder project settings 169 | .spyderproject 170 | .spyproject 171 | 172 | # Rope project settings 173 | .ropeproject 174 | 175 | # mkdocs documentation 176 | /site 177 | 178 | # mypy 179 | .mypy_cache/ 180 | .dmypy.json 181 | dmypy.json 182 | 183 | # Pyre type checker 184 | .pyre/ 185 | 186 | # pytype static type analyzer 187 | .pytype/ 188 | 189 | # Cython debug symbols 190 | cython_debug/ 191 | 192 | # PyCharm 193 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 194 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 195 | # and can be added to the global gitignore or merged into this file. For a more nuclear 196 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 197 | #.idea/ 198 | 199 | # Virtual Environment 200 | venv/ 201 | env/ 202 | ENV/ 203 | 204 | # IDE 205 | .idea/ 206 | .vscode/ 207 | *.swp 208 | *.swo 209 | 210 | # OS 211 | .DS_Store 212 | .DS_Store? 213 | ._* 214 | .Spotlight-V100 215 | .Trashes 216 | ehthumbs.db 217 | Thumbs.db -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "llm-reranker"] 2 | path = llm-reranker 3 | url = https://github.com/gangiswag/llm-reranker.git 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🌽 CoRNStack: A High-Quality Contrastive Dataset for Better Code Ranking. 2 | 3 |

4 | ℹ️ About 5 | | 📖 More About CORNSTACK 6 | | 🚀 Quick Start 7 | | 👀 Running Evaluation 8 | | 🔄 Running Reranker 9 |

10 | 11 | 12 | 13 | ## ℹ️ About 14 | * 🌽 **CoRNStack** is a large-scale high-quality (text, code) pairs dataset for training and fine-tuning embedding models and re-rankers for code retrieval via contrastive learning. 15 | * We train **CodeRankEmbed**, a 137M bi-encoder, on 🌽 **CoRNStack** and demonstrate considerably higher performance on a variety of code retrieval benchmarks, with substantial gains over current state-of-the-art code embedding models. 16 | * By leveraging 🌽 **CoRNStack**, we are the first to finetune LLMs as code rerankers. **CodeRankLLM**, our 7B code reranker, considerably improves performance over the retriever. 17 | 18 | 19 | ## 📖 More About CORNSTACK 20 | 21 | The performance of code embedding models is highly contingent on the quality of the large-scale data used for contrastive training. Effective contrastive training hinges on satisfying two primary conditions: 22 | 1) The positives are highly relevant to the query and not noisy 23 | 2) The negatives are semantically similar to the positives but do not directly address the query, a.k.a hard negatives. 24 | 25 | Existing approaches heuristically source contrastive examples from large-scale open-source code data with limited filtering and mining, retaining irrelevant or incorrectly labeled pairs, which impair the models’ ability to learn robust and accurate representations. To address these challenges, we introduce curriculum-based hard negative mining and consistency filtering techniques and apply these techniques on the de-duplicated version of The Stack v2. More details on these specific curation techniques and how we use them to train embedding models and re-rankers in our paper coming soon! 26 | 27 | ## 🚀 Quick Start 28 | 29 | Install the required dependencies: 30 | ```bash 31 | pip install -r requirements.txt 32 | ``` 33 | 34 | 35 | ## 👀 Running Evaluation 36 | 37 | To reproduce the performance of **CodeRankEmbed** on popular code retrieval benchmarks, run the following commands: 38 | 39 | ### COIR Evaluation 40 | ``` 41 | cd src/ 42 | python evaluation/eval_coir.py 43 | ``` 44 | 45 | ### CSN Evaluation 46 | 47 | ``` 48 | cd src/ 49 | python create/csn.py 50 | python evaluation/eval_csn.py 51 | ``` 52 | Ignore any errors when running `python create/csn.py`. 53 | 54 | ### SWE-Bench-Lite Evaluation 55 | 56 | ``` 57 | cd src/ 58 | python create/swebench.py 59 | python evaluation/eval_swebench.py 60 | python evaluation/eval_localization.py --level file #print out file localization top-k results 61 | python evaluation/eval_localization.py --level function #print out function localization top-k results 62 | ``` 63 | 64 | ## 🔄 Running Reranker 65 | 66 | Initialize and update the submodules: 67 | ```bash 68 | # Initialize submodules 69 | git submodule init 70 | git submodule update 71 | ``` 72 | **Note:** You need to install the vLLM library (instructions [here](https://docs.vllm.ai/en/latest/getting_started/installation.html)) which provides optimization for LLM inference. 73 | 74 | To run the complete pipeline including retrieval and reranking: 75 | 76 | ```bash 77 | cd src/ 78 | ./run_pipeline.sh 79 | ``` 80 | 81 | The pipeline script supports several options: 82 | - `--dataset_dir`: Directory for datasets (default: ./datasets) 83 | - `--output_dir`: Directory for outputs (default: ./outputs) 84 | - `--eval_dir`: Directory for evaluation results (default: ./evaluations) 85 | - `--top_k`: Number of candidates to rerank (default: 100) 86 | - `--window_size`: Window size for reranking (default: 10) 87 | - `--step_size`: Step size for reranking (default: 5) 88 | - `--skip_retriever`: Skip retrieval step if you already have retrieval results (default: 1) 89 | 90 | The pipeline will: 91 | 1. Run the retriever to generate initial rankings (if --skip_retriever=0) 92 | 2. Convert the retrieval results to the required format 93 | 3. Run the CodeRankLLM reranker on the top retrieved results 94 | 4. Evaluate and save the reranking results 95 | 96 | Results will be saved in: 97 | - Reranking outputs: `{output_dir}/code_datasets/{dataset_name}/` 98 | - Evaluation results: `{eval_dir}/eval_results/{dataset_name}_eval.json` 99 | 100 | We plan to release the full training and dataset curation code soon! 101 | 102 | 103 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | We introduce CoRNStack, a large-scale, high-quality contrastive training dataset for code that spans multiple programming languages. We demonstrate that contrastive training of embedding models using CoRNStack leads to state-of-the-art performance across a variety of code retrieval tasks. 10 | 11 | 13 | 14 | 15 | 16 | 17 | 18 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 43 | 44 | 59 | 60 | 61 | 62 | 63 |
64 |
65 |
66 |
67 |
68 |

69 | 70 | CoRNStack: High-Quality Contrastive Data for Better Code Ranking

71 |
72 | 73 | Tarun Suresh*1,3, 74 | 75 | Revanth Gangi Reddy*1, 76 | 77 | Yifei Xu1,2, 78 | 79 | Zach Nussbaum3,
80 | 81 | Andriy Mulyar3, 82 | 83 | Brandon Duderstadt3, 84 | 85 | Heng Ji1 86 | 87 |
88 | 89 |
90 | 1University of Illinois Urbana-Champaign,     2Lapis Labs,     3Nomic AI 91 |
92 | 161 |
162 |
163 |
164 |
165 |
166 | 167 | 168 | 178 | 179 | 180 | 181 |
182 |
183 | 184 |
185 |
186 |

Abstract

187 |
188 |

189 | Problem: Effective code retrieval is essential for improving code generation, bug fixing, and software maintenance, especially as software complexity grows. Although current code embedding models work well for smaller tasks, they often struggle with real-world challenges like finding bugs in GitHub repositories. This may be due to the noisy, inconsistent data used in their training, which limits their ability to generalize. 190 |
191 |
192 | Contribution: To tackle this, we introduce CoRNStack, a large-scale, high-quality training dataset designed specifically for code retrieval across multiple programming languages. CoRNStack is curated to remove noisy data and includes challenging examples that improve learning. The dataset, which comprises instances of the form of <query, positive, negatives>, supports training code retrieval and reranking models. 193 |
194 |
195 | Results: With contrastive training on CoRNStack, our code retriever model (CodeRankEmbed) achieves state-of-the-art results across diverse code retrieval tasks. Our fine-tuned reranking model (CodeRankLLM) further enhances the quality of retrieved results, and when combined with our code retriever, it significantly improves the accuracy of finding relevant functions in GitHub issues—a key need in real-world software development. 196 |

197 |
198 |
199 | CoRNStack curation overview. 200 |
201 | Figure 1: Figure demonstrating CoRNStack curation methodology, with consistency filtering to remove noisy positives and a curriculum-based hard negative mining strategy. 202 |
203 |
204 |
205 |
206 | 207 |
208 |
209 | 210 |
211 |
212 |
213 |
214 |

CoRNStack Curation

215 | 216 |

217 | The effectiveness of code embedding models depends heavily on the quality of their training data, which comes in the form of triples: a query, a relevant (positive) example, and unrelated (negative) examples. Training with high quality positives with hard negatives, examples that are similar to the positives but don't answer the query correctly, results in high performing code embedding models. Directly using open-source code data like The Stack v2 for this purpose can introduce mismatched or mislabeled pairs, which weakens model performance. To address this, we propose a two-step filtering method that selects the most relevant positives based on similarity scores and adds a diverse range of hard negatives. We call this curated dataset as CoRNStack, short for Consistency filtering and Robust Negatives for enriching The Stackv2. 218 |

219 |
220 |

221 | Data Selection: We built our dataset from the de-duplicated Stackv2, a rich collection of source code in over 600 programming and markup languages. To create text-code pairs, we took function docstrings as text and paired them with their respective functions as code. We applied filters to exclude pairs where the text was non-English, too short, or contained URLs, HTML tags, or invalid characters. Unlike past approaches, we kept pairs with text lengths of 256 tokens or more to help the model handle long query sequences often seen in detailed code retrieval tasks, like those found in GitHub issues. 222 |

223 |
224 |

225 | Dual Consistency Filtering: To create a high-quality dataset of (text, code) pairs, we use an embedding model (Jina-Code-v2) to get text and code embeddings, then calculate similarity scores between all pairs. We keep a pair if it ranks in the top-two most similar matches and surpasses a set similarity threshold. To evaluate this filtered dataset, we ran automated comparisons with other code datasets like CosQA and CodeSearchNet. Using the Qwen2.5-Coder model, we checked if each code snippet fully addresses its corresponding text query across thousands of samples. Our results show CoRNStack has considerably higher <query, positive> correctness than the other datasets. 226 |

227 |
228 |

229 | Curriculum-Based Hard Negative Mining: We improve model training by carefully selecting challenging negatives to learn from. For each (text, code) pair, we start by filtering out false negatives based on a similarity score threshold to ensure only truly "negative" examples remain. From these, we sample a set of negatives using a probability method that emphasizes more challenging cases, with a temperature parameter that adjusts over time to gradually sharpen the selection. This setup, akin to a curriculum, helps the model learn from progressively harder examples, which enhances diversity and prevents overfitting. Importantly, this strategy is efficient, as it relies on a precomputed similarity matrix, making it both scalable and practical. 230 |

231 |
232 | 233 |
234 |
235 | 236 |
237 |
238 |
239 |
240 |

CodeRankEmbed Retriever

241 |
242 |

243 | Model: We use a bi-encoder architecture for our retriever, with weights shared between the text and code encoder. The retriever is trained using a contrastive learning objective based on the InfoNCE loss. The encoder is initialized with Arctic-Embed-M-Long, a text encoder supporting an extended context length of 8,192 tokens and pretrained on large-scale web query-document pairs, along with public text retrieval datasets. We release our trained code retriever as CodeRankEmbed. 244 |

245 |

246 | Evaluation Datasets: We evaluate CodeRankEmbed on a variety of code retrieval tasks under zero-shot settings. We use CodeSearchNet as the benchmark for function-level text-to-code retrieval, a semantic search task where natural language queries are used to retrieve relevant code snippets. Additionally, to evaluate performance across diverse code retrieval tasks, we use the CoIR benchmark, which includes text-to-code, code-to-text, code-to-code, and hybrid code retrieval tasks (retrieving a hybrid of code and textual documents given a hybrid query). 247 |

248 |

249 | Baselines: We compare our finetuned code retriever against state-of-the-art code embedding models of various sizes, both open-source and proprietary. The open-source code embedding models include CodeSage, CodeT5+ and Jina-Code-v2, which are 250 | currently leading text-to-code retrieval benchmarks. We also compare with the proprietary Voyage-Code-002. 251 |

252 |

253 | Results: Our code retriever, despite being smaller than the majority of the baselines, significantly outperforms all open-source and proprietary code embedding models, establishing a new state-of-the-art for code embedding tasks. This demonstrates the robustness of our contrastive training data, with the trained model exhibiting superior cross-task generalization on COIR despite being trained exclusively for only text-to-code retrieval. 254 |

255 | 258 |
259 | CoIR Results 260 |
261 |
262 | CodeSearchNet Results 263 |
264 |
265 |
266 |
267 | 268 |
269 |
270 |
271 |
272 |

CodeRankLLM Reranker

273 |
274 |

275 | Model: Our code reranker is based on LLM-based listwise reranking, which has gained prominence for the ability to score multiple passages simultaneously. Training data for listwise reranking was generated by selecting 50,000 <query, positive, negatives> tuples from CoRNStack, filtered to ensure higher similarity scores and better ranks for the positives. Since CoRNStack doesn't contain the ranked ordering data required for training listwise rerankers, we leverage Qwen-2.5-32B-Instruct LLM provided ranked orderings for each example to serve as ranking supervision. We train the reranker using a language modeling objective that minimizes the prediction error of the next token in the sequence. We release our trained code reranker as CodeRankLLM. 276 |

277 |
278 |

279 | Baselines and Evaluation: We compare reranking performance with that of the zero-shot Qwen-2.5-Coder-7B-Instruct model, our base model for our finetuning. Since text-based LLMs are typically trained on both text and code data, we include a listwise text reranker as a baseline. Specifically, we fine-tune the Qwen-2.5-7B-Instruct LLM on 40k GPT-4-labeled listwise reranking instances derived from MS MARCO. We evaluate our models using the CodeSearchNet and AdvTest text-to-code retrieval benchmarks. During inference, we rerank the top 100 results from our code retriever, employing a window size of 10 and a step size of 5 for the listwise LLM rerankers. 280 |

281 |
282 |

283 | Results: The text reranker Qwen-2.5-Text, although finetuned with listwise text data, performs strongly across programming languages, likely due to code examples in its pretraining data enhancing code comprehension. In contrast, the code model Qwen-2.5-Code underperforms in zero-shot listwise reranking but improves markedly after finetuning with code-specific listwise data created using CoRNStack. 284 |

285 |
286 | CodeRankLLM Results 287 |
288 | Table 1: Ranking performance (MRR@100 in %) for different models from reranking top-100 retrieval results on function-level text-to-code retrieval datasets. 289 |
290 |
291 | 292 |
293 |
294 |
295 | 296 |
297 |
298 |
299 |
300 |

Function-Localization for Real-World Software Development

301 |
302 |

303 | Having previously evaluated our CodeRankEmbed and CodeRankLLM models on academic benchmarks, we now demonstrate their utility in assisting software development in real-world settings. Specifically, we focus on the task of function localization, which involves accurately identifying the specific functions that need to be modified in response to a GitHub issue. 304 |

305 |

306 | Datasets: We evaluate our code retriever+reranker framework based on SWE-Bench, a widely used repository-level benchmark that focuses on resolving real-world GitHub issues with code patches passing associated test cases. Specifically, employ SWE-Bench-Lite, a subset of SWE-Bench, which we reformulated for function localization, where the patched functions are treated as the localization targets. We retained 274 of 300 examples where patches modify existing functions or classes, with the excluded examples introducing code corresponding to new functions or import statements. The GitHub issue serves as the text query, and all functions in the repository are candidates for retrieval. 307 |

308 |

309 | Baselines and Metrics: Our main baseline, Agentless, is an automated tool for tackling software development issues and is a top open-source performer on SWE-Bench-Lite. It operates in two phases: localization and repair. In localization, Agentless first identifies relevant files, then narrows down to specific classes, functions, and edit locations. Given the size of codebases, it uses file location information and GitHub issues to rank files that may need updates, then pinpoints functions needing changes within these files. Since Agentless selects up to three files for edits and localizes functions within them, we evaluate file localization at top 1–3 and function localization at top 5-10. We also compare against code retrieval baselines, excluding proprietary ones due to API costs. 310 |

311 |

312 | Results: Our code retriever significantly outperforms Agentless and other retrieval baselines in function localization accuracy. Applying our code reranker over the retriever results yields consistent improvements in both file and function localization. While SWE-Bench-Lite is constructed from popular open-source Python repositories, we hypothesize that our retrieval-based approach could achieve greater improvements on private repositories, which are typically not included in LLM pretraining data, and we leave this investigation for future work. 313 |

314 |
315 | SWE-Bench File-Level Results 316 |
317 | Figure 2: File localization performance (%) on SWE-Bench-Lite. 318 |
319 |
320 |
321 | SWE-Bench Function-Level Results 322 |
323 | Figure 3: Function localization performance (%) on SWE-Bench-Lite. 324 |
325 |
326 |
327 | 328 |
329 |
330 | 331 | 338 | 339 | 340 | 356 | 357 | 358 | 359 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | coir-eval 2 | beir 3 | einops 4 | fire 5 | openai 6 | pre-commit 7 | datasets 8 | tiktoken 9 | libcst 10 | llama-index 11 | jsonlines 12 | swebench @ git+https://github.com/princeton-nlp/SWE-bench 13 | # Dependencies for reranker 14 | torch>=2.0.0 15 | transformers>=4.31.0 16 | sentence-transformers>=2.2.2 17 | accelerate>=0.21.0 18 | bitsandbytes>=0.41.1 19 | scipy>=1.11.2 20 | numpy>=1.24.3 21 | tqdm>=4.65.0 -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gangiswag/cornstack/6432dfde69400892000bb2dabdb90fbc3b239f20/src/__init__.py -------------------------------------------------------------------------------- /src/create/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gangiswag/cornstack/6432dfde69400892000bb2dabdb90fbc3b239f20/src/create/__init__.py -------------------------------------------------------------------------------- /src/create/csn.py: -------------------------------------------------------------------------------- 1 | import json 2 | import argparse 3 | import pandas as pd 4 | from pathlib import Path 5 | from utils import save_tsv_dict, save_file_jsonl, NL2CodeDataset 6 | import os 7 | import subprocess 8 | 9 | def main(): 10 | parser = argparse.ArgumentParser() 11 | parser.add_argument("--dataset_dir", type=str, default="datasets") 12 | 13 | args = parser.parse_args() 14 | 15 | # Create code_datasets directory 16 | code_datasets_dir = os.path.join(args.dataset_dir, "code_datasets") 17 | os.makedirs(code_datasets_dir, exist_ok=True) 18 | 19 | # Change to dataset directory for download 20 | orig_dir = os.getcwd() 21 | os.chdir(code_datasets_dir) 22 | 23 | # Download and extract dataset 24 | commands = [ 25 | "wget https://github.com/microsoft/CodeBERT/raw/master/GraphCodeBERT/codesearch/dataset.zip", 26 | "unzip dataset.zip", 27 | "rm -r dataset.zip", 28 | "mv dataset CSN", 29 | "cd CSN && bash run.sh", 30 | "cd .." 31 | ] 32 | 33 | print("Downloading and preparing CSN dataset...") 34 | for command in commands: 35 | try: 36 | subprocess.run(command, shell=True, check=True) 37 | except subprocess.CalledProcessError as e: 38 | print(f"Error executing command '{command}': {e}") 39 | os.chdir(orig_dir) 40 | return 41 | 42 | for lang in ['python', 'java', 'ruby', 'php', 'javascript', 'go']: 43 | print(f"Processing {lang}...") 44 | path = Path(os.path.join(code_datasets_dir, f'csn_{lang}')) 45 | path.mkdir(parents=True, exist_ok=True) 46 | qrels_path = Path(os.path.join(path, 'qrels')) 47 | qrels_path.mkdir(parents=True, exist_ok=True) 48 | 49 | query_dataset = NL2CodeDataset(f'CSN/{lang}/test.jsonl', None) 50 | code_dataset = NL2CodeDataset(f'CSN/{lang}/codebase.jsonl', prefix=None) 51 | 52 | queries, docs, qrels = [], [], [] 53 | url2id = {} 54 | i = 0 55 | for url, example in code_dataset.url2example.items(): 56 | url2id[url] = i 57 | docs.append({'_id': f'{url2id[url]}_code', 'text': example['code'], 'title': example['title'], 'metadata': {}}) 58 | i += 1 59 | 60 | for url, example in query_dataset.url2example.items(): 61 | queries.append({'_id': f'{url2id[url]}_query', 'text': example['nl'], 'metadata': {}}) 62 | qrels.append({"query-id": f'{url2id[url]}_query', "corpus-id": f'{url2id[url]}_code', "score": 1}) 63 | 64 | save_file_jsonl(queries, os.path.join(path, "queries.jsonl")) 65 | save_file_jsonl(docs, os.path.join(path, "corpus.jsonl")) 66 | qrels_path = os.path.join(path, "qrels", "test.tsv") 67 | save_tsv_dict(qrels, qrels_path, ["query-id", "corpus-id", "score"]) 68 | 69 | # Cleanup 70 | subprocess.run('rm -r CSN', shell=True, check=True) 71 | subprocess.run('rm -r _MACOSX', shell=True, check=True) 72 | 73 | os.chdir(orig_dir) 74 | 75 | if __name__ == "__main__": 76 | main() -------------------------------------------------------------------------------- /src/create/swebench.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import chardet 4 | import unidiff 5 | import shutil 6 | import argparse 7 | import datasets 8 | import traceback 9 | import subprocess 10 | from git import Repo 11 | from tqdm import tqdm 12 | from pathlib import Path 13 | from tempfile import TemporaryDirectory 14 | from utils import save_tsv_dict, save_file_jsonl 15 | from get_repo_structure.get_repo_structure import get_project_structure_from_scratch 16 | from get_repo_structure.get_patch_info import * 17 | 18 | # %% Get oracle file contents 19 | 20 | # get oracle file contents from the repo 21 | class ContextManager: 22 | def __init__(self, repo_path, base_commit, verbose=False): 23 | self.repo_path = Path(repo_path).resolve().as_posix() 24 | self.old_dir = os.getcwd() 25 | self.base_commit = base_commit 26 | self.verbose = verbose 27 | 28 | def __enter__(self): 29 | os.chdir(self.repo_path) 30 | cmd = f"git reset --hard {self.base_commit} && git clean -fdxq" 31 | if self.verbose: 32 | subprocess.run(cmd, shell=True, check=True) 33 | else: 34 | subprocess.run( 35 | cmd, 36 | shell=True, 37 | check=True, 38 | stdout=subprocess.DEVNULL, 39 | stderr=subprocess.DEVNULL, 40 | ) 41 | return self 42 | 43 | def get_environment(self): 44 | raise NotImplementedError() # TODO: activate conda environment and return the environment file 45 | 46 | def get_readme_files(self): 47 | files = os.listdir(self.repo_path) 48 | files = list(filter(lambda x: os.path.isfile(x), files)) 49 | files = list(filter(lambda x: x.lower().startswith("readme"), files)) 50 | return files 51 | 52 | def __exit__(self, exc_type, exc_val, exc_tb): 53 | os.chdir(self.old_dir) 54 | 55 | 56 | class AutoContextManager(ContextManager): 57 | """Automatically clones the repo if it doesn't exist""" 58 | 59 | def __init__(self, instance, root_dir=None, verbose=False, token=None): 60 | if token is None: 61 | token = os.environ.get("GITHUB_TOKEN", "git") 62 | self.tempdir = None 63 | if root_dir is None: 64 | self.tempdir = TemporaryDirectory() 65 | root_dir = self.tempdir.name 66 | self.root_dir = root_dir 67 | repo_dir = os.path.join(self.root_dir, instance["repo"].replace("/", "__")) 68 | if not os.path.exists(repo_dir): 69 | repo_url = ( 70 | f"https://{token}@github.com/swe-bench/" 71 | + instance["repo"].replace("/", "__") 72 | + ".git" 73 | ) 74 | if verbose: 75 | print(f"Cloning {instance['repo']} to {root_dir}") 76 | Repo.clone_from(repo_url, repo_dir) 77 | super().__init__(repo_dir, instance["base_commit"], verbose=verbose) 78 | self.instance = instance 79 | 80 | def __exit__(self, exc_type, exc_val, exc_tb): 81 | if self.tempdir is not None: 82 | self.tempdir.cleanup() 83 | return super().__exit__(exc_type, exc_val, exc_tb) 84 | 85 | 86 | def ingest_files(filenames): 87 | files_dict = dict() 88 | for filename in filenames: 89 | with open(filename) as f: 90 | content = f.read() 91 | files_dict[filename] = content 92 | return files_dict 93 | 94 | def get_oracle_filenames(instance): 95 | """ 96 | Returns the filenames that are changed in the patch 97 | """ 98 | source_files = { 99 | patch_file.source_file.split("a/", 1)[-1] 100 | for patch_file in unidiff.PatchSet(instance["patch"]) 101 | } 102 | gold_docs = set() 103 | for source_file in source_files: 104 | gold_docs.add(source_file) 105 | return gold_docs 106 | 107 | 108 | # get all file contents from the repo 109 | def is_test(name, test_phrases=None): 110 | if test_phrases is None: 111 | test_phrases = ["test", "tests", "testing"] 112 | words = set(re.split(r" |_|\/|\.", name.lower())) 113 | return any(word in words for word in test_phrases) 114 | 115 | def list_files(root_dir, include_tests=False): 116 | files = [] 117 | for filename in Path(root_dir).rglob("*.py"): 118 | if not include_tests and is_test(filename.as_posix()): 119 | continue 120 | files.append(filename.relative_to(root_dir).as_posix()) 121 | return files 122 | 123 | def detect_encoding(filename): 124 | """ 125 | Detect the encoding of a file 126 | """ 127 | with open(filename, "rb") as file: 128 | rawdata = file.read() 129 | return chardet.detect(rawdata)["encoding"] 130 | 131 | def ingest_directory_contents(root_dir, include_tests=False): 132 | files_content = {} 133 | for relative_path in list_files(root_dir, include_tests=include_tests): 134 | filename = os.path.join(root_dir, relative_path) 135 | encoding = detect_encoding(filename) 136 | if encoding is None: 137 | content = "[BINARY DATA FILE]" 138 | else: 139 | try: 140 | with open(filename, encoding=encoding) as file: 141 | content = file.read() 142 | except (UnicodeDecodeError, LookupError): 143 | content = "[BINARY DATA FILE]" 144 | files_content[relative_path] = content 145 | return files_content 146 | 147 | def get_file_contents(input_instances, verbose: bool = False, tmp_dir: str = "/scratch"): 148 | orig_dir = os.getcwd() 149 | with TemporaryDirectory(dir=tmp_dir if os.path.exists(tmp_dir) else "/tmp") as root_dir: 150 | for instance_id, instance in tqdm( 151 | input_instances.items(), 152 | total=len(input_instances), 153 | desc="Getting file contents", 154 | ): 155 | try: 156 | with AutoContextManager(instance, root_dir, verbose=verbose) as cm: 157 | readmes = cm.get_readme_files() 158 | instance["readmes"] = ingest_files(readmes) 159 | instance["oracle_file_contents"] = ingest_files(get_oracle_filenames(instance)) 160 | instance["file_contents"] = ingest_directory_contents(cm.repo_path) 161 | assert all([ 162 | okey in instance["file_contents"] 163 | for okey in instance["oracle_file_contents"].keys() 164 | ]) 165 | except Exception as e: 166 | print(f"Failed on instance {instance_id}", e) 167 | traceback.print_exc() 168 | finally: 169 | # if AutoContextManager fails to exit properly future exits will return the wrong directory 170 | os.chdir(orig_dir) 171 | os.chdir(orig_dir) 172 | 173 | def file(dataset, name): 174 | for item in dataset: 175 | queries = [{ 176 | "_id": item["instance_id"], 177 | "text": item["problem_statement"], 178 | "metadata": {} 179 | }] 180 | item_dict = {item["instance_id"]: item} 181 | get_file_contents(item_dict, tmp_dir=args.tmp_dir) 182 | docs = [] 183 | for instance_id, instance in item_dict.items(): 184 | print(f"Instance #{instance_id}: {len(instance['oracle_file_contents'])} oracle / {len(instance['file_contents'])} files") 185 | for filename, content in instance["file_contents"].items(): 186 | docs.append({ 187 | "_id": f"{instance_id}_{filename}", 188 | "title": filename, 189 | "text": content, 190 | "metadata": {}, 191 | }) 192 | 193 | qrels = [] 194 | for instance_id, instance in item_dict.items(): 195 | for filename, content in instance["oracle_file_contents"].items(): 196 | qrels.append({ 197 | "query-id": instance_id, 198 | "corpus-id": f"{instance_id}_{filename}", 199 | "score": 1 200 | }) 201 | 202 | path = os.path.join(args.dataset_dir, f"{name}_{instance_id}") 203 | os.makedirs(path, exist_ok=True) 204 | os.makedirs(os.path.join(path, "qrels"), exist_ok=True) 205 | 206 | save_file_jsonl(queries, os.path.join(path, "queries.jsonl")) 207 | save_file_jsonl(docs, os.path.join(path, "corpus.jsonl")) 208 | qrels_path = os.path.join(path, "qrels", "test.tsv") 209 | save_tsv_dict(qrels, qrels_path, ["query-id", "corpus-id", "score"]) 210 | 211 | def function(dataset, name): 212 | #TODO: validate this extensively on each instance 213 | for i, item in tqdm(enumerate(dataset), total = len(dataset), colour= 'blue'): 214 | if os.path.exists(f"datasets/{name}_{item['instance_id']}"): 215 | continue 216 | 217 | queries = [{ 218 | "_id": item["instance_id"], 219 | "text": item["problem_statement"], 220 | "metadata": {} 221 | }] 222 | 223 | try: 224 | structure = get_project_structure_from_scratch(item['repo'], item['base_commit'], 225 | item['instance_id'], 'playground') 226 | data = find_py_or_non_dict_with_path(structure['structure'], cond = item["instance_id"].startswith('pytest-dev__')) 227 | patch_info = parse_patch_full(item['patch'], structure) 228 | except: 229 | import pdb;pdb.set_trace() 230 | changed_funcs = set() 231 | for fle, hunks in patch_info.items(): 232 | for hunk in hunks: 233 | if hunk['function_changed'] and hunk['newly_added'] is False: 234 | if hunk['class_changed']: 235 | changed_funcs.add(f'{fle}/{hunk["class_changed"]}/{hunk["function_changed"]}') 236 | else: 237 | changed_funcs.add(f'{fle}/{hunk["function_changed"]}') 238 | 239 | if not changed_funcs: 240 | #import pdb;pdb.set_trace() 241 | continue 242 | 243 | docs = [] 244 | for func, content in data.items(): 245 | docs.append({ 246 | "_id": func, 247 | "title": '', 248 | "text": content, 249 | "metadata": {}, 250 | }) 251 | qrels = [] 252 | for func in changed_funcs: 253 | try: 254 | assert func in data 255 | except: 256 | import pdb;pdb.set_trace() 257 | qrels.append({ 258 | "query-id": item["instance_id"], 259 | "corpus-id": func, 260 | "score": 1 261 | }) 262 | 263 | path = os.path.join(args.dataset_dir, f"{name}_{item['instance_id']}") 264 | os.makedirs(path, exist_ok=True) 265 | os.makedirs(os.path.join(path, "qrels"), exist_ok=True) 266 | 267 | save_file_jsonl(queries, os.path.join(path, "queries.jsonl")) 268 | save_file_jsonl(docs, os.path.join(path, "corpus.jsonl")) 269 | qrels_path = os.path.join(path, "qrels", "test.tsv") 270 | save_tsv_dict(qrels, qrels_path, ["query-id", "corpus-id", "score"]) 271 | 272 | def main(): 273 | dataset = datasets.load_dataset(args.dataset_name, cache_dir=args.cache_dir)[args.split] 274 | if args.num_examples is not None: 275 | import random 276 | indices = random.sample([i for i in range(len(dataset))], args.num_examples) 277 | dataset = dataset.select(indices) 278 | print(dataset) 279 | 280 | name = "swe-bench" 281 | if "lite" in args.dataset_name.lower(): 282 | name += "-lite" 283 | elif 'verified' in args.dataset_name.lower(): 284 | name += "-verified" 285 | if args.split != 'test': 286 | name += f"-{args.split}" 287 | if args.level != 'file': 288 | name += f"-{args.level}" 289 | 290 | if not args.reuse_cached: 291 | [shutil.rmtree(f'{args.dataset_dir}/{instance}') for instance in os.listdir(f'{args.dataset_dir}') if instance.startswith(f'{name}_') or instance.startswith(f'csn_{args.level}_')] 292 | eval(args.level)(dataset, name) 293 | 294 | 295 | 296 | if __name__ == "__main__": 297 | parser = argparse.ArgumentParser() 298 | parser.add_argument("--dataset_name", type=str, default="princeton-nlp/SWE-bench_Lite", 299 | choices=["princeton-nlp/SWE-bench", "princeton-nlp/SWE-bench_Lite", "princeton-nlp/SWE-bench_Verified"]) 300 | parser.add_argument("--split", type=str, default="test") 301 | parser.add_argument("--level", type=str, default="function") 302 | parser.add_argument("--cache_dir", type=str, default="cache/") 303 | parser.add_argument("--tmp_dir", type=str, default="tmp/") 304 | parser.add_argument("--dataset_dir", type=str, default="datasets") 305 | parser.add_argument("--num_examples", type=int, default=None) 306 | parser.add_argument("--reuse_cached", type=bool, default=True) 307 | args = parser.parse_args() 308 | 309 | main() 310 | -------------------------------------------------------------------------------- /src/create/utils.py: -------------------------------------------------------------------------------- 1 | import jsonlines 2 | import csv 3 | import os 4 | from tqdm import tqdm 5 | import json 6 | def load_jsonlines(file): 7 | with jsonlines.open(file, 'r') as jsonl_f: 8 | lst = [obj for obj in jsonl_f] 9 | return lst 10 | 11 | def save_file_jsonl(data, fp): 12 | with jsonlines.open(fp, mode='w') as writer: 13 | writer.write_all(data) 14 | 15 | def save_tsv_dict(data, fp, fields): 16 | # build dir 17 | dir_path = os.path.dirname(fp) 18 | os.makedirs(dir_path, exist_ok=True) 19 | 20 | # writing to csv file 21 | with open(fp, 'w') as csvfile: 22 | writer = csv.DictWriter(csvfile, fieldnames=fields, delimiter='\t',) 23 | writer.writeheader() 24 | writer.writerows(data) 25 | 26 | def cost_esitmate(path): 27 | corpus = load_jsonlines(os.path.join(path, "corpus.jsonl")) 28 | queries = load_jsonlines(os.path.join(path, "queries.jsonl")) 29 | num_corpus_words = 0 30 | num_queries_words = 0 31 | for item in tqdm(corpus): 32 | num_corpus_words += len(item["text"].split(" ")) 33 | for item in tqdm(queries): 34 | num_queries_words += len(item["text"].split(" ")) 35 | print(len(corpus)) 36 | print(len(queries)) 37 | print(num_corpus_words) 38 | print(num_queries_words) 39 | 40 | 41 | def convert_nl2code_examples_to_features(js, prefix = None): 42 | #TODO: use actual code and not code tokens 43 | """convert examples to token ids""" 44 | code = ' '.join(js['code_tokens']) if type(js['code_tokens']) is list else ' '.join(js['code_tokens'].split()) 45 | code = f'{prefix}: {code}' if prefix is not None else code 46 | 47 | nl = ' '.join(js['docstring_tokens']) if type(js['docstring_tokens']) is list else ' '.join(js['doc'].split()) 48 | nl = f'{prefix}: {nl}' if prefix is not None else nl 49 | 50 | return code, nl, (js['url'] if "url" in js else js["retrieval_idx"]) 51 | 52 | class NL2CodeDataset: 53 | def __init__(self, file_path=None, prefix = None): 54 | data = [] 55 | self.url2example = {} 56 | with open(file_path) as f: 57 | if "jsonl" in file_path: 58 | for line in f: 59 | line = line.strip() 60 | try: 61 | js = json.loads(line) 62 | except: 63 | continue 64 | if 'function_tokens' in js: 65 | js['code_tokens'] = js['function_tokens'] 66 | data.append(js) 67 | elif "codebase" in file_path or "code_idx_map" in file_path: 68 | js = json.load(f) 69 | for key in js: 70 | temp = {} 71 | temp['code_tokens'] = key.split() 72 | temp["retrieval_idx"] = js[key] 73 | temp['doc'] = "" 74 | temp['docstring_tokens'] = "" 75 | data.append(temp) 76 | elif "json" in file_path: 77 | for js in json.load(f): 78 | data.append(js) 79 | for js in data: 80 | code, nl, url = convert_nl2code_examples_to_features(js, prefix) 81 | self.url2example[url] = {'code': code, 'nl': nl, 'title': js.get('func_name', '')} 82 | 83 | def __len__(self): 84 | return len(self.urls) -------------------------------------------------------------------------------- /src/evaluations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gangiswag/cornstack/6432dfde69400892000bb2dabdb90fbc3b239f20/src/evaluations/__init__.py -------------------------------------------------------------------------------- /src/evaluations/eval_coir.py: -------------------------------------------------------------------------------- 1 | import coir 2 | from coir.evaluation import COIR 3 | from sentence_transformers import SentenceTransformer 4 | from beir.retrieval import models 5 | import fire 6 | import numpy as np 7 | import torch 8 | from utils import Retriever 9 | 10 | #ran with 512 seq length for fair comparison against baselines following CoIR paper although higher seq length may yield better pfm 11 | def main(tasks = 'all', output_dir = 'results', batch_size = 256, max_seq_length = 512): 12 | st = SentenceTransformer("cornstack/CodeRankEmbed", trust_remote_code= True).to(torch.bfloat16) 13 | st.max_seq_length = max_seq_length 14 | contrast_encoder = Retriever(st, add_prefix= True) 15 | 16 | if tasks == 'all': 17 | tasks = ["codetrans-dl","stackoverflow-qa","apps","codefeedback-mt", 18 | "codefeedback-st","codetrans-contest","synthetic-text2sql", 19 | "cosqa","codesearchnet","codesearchnet-ccr"] 20 | else: 21 | tasks = tasks.split() 22 | 23 | for task in tasks: 24 | if task in ['apps', 'cosqa', "synthetic-text2sql"]: 25 | contrast_encoder.add_prefix = True 26 | else: 27 | contrast_encoder.add_prefix = False 28 | 29 | # Initialize evaluation 30 | evaluation = COIR(tasks= coir.get_tasks(tasks= [task]),batch_size=batch_size) 31 | 32 | # Run evaluation 33 | results = evaluation.run(contrast_encoder, output_folder=f"{output_dir}/coir") 34 | print(results) 35 | 36 | if __name__ == "__main__": 37 | fire.Fire(main) -------------------------------------------------------------------------------- /src/evaluations/eval_csn.py: -------------------------------------------------------------------------------- 1 | import os 2 | import torch 3 | import random 4 | import logging 5 | import argparse 6 | from pathlib import Path 7 | import json 8 | import numpy as np 9 | from sentence_transformers import SentenceTransformer 10 | from beir.datasets.data_loader import GenericDataLoader 11 | import fire 12 | 13 | logger = logging.getLogger(__name__) 14 | 15 | 16 | def set_seed(seed=42): 17 | random.seed(seed) 18 | os.environ['PYHTONHASHSEED'] = str(seed) 19 | np.random.seed(seed) 20 | torch.manual_seed(seed) 21 | torch.cuda.manual_seed(seed) 22 | torch.backends.cudnn.deterministic = True 23 | 24 | 25 | 26 | 27 | def evaluate(device, lang, batch_size, dataset_dir, output_dir): 28 | model = SentenceTransformer( "cornstack/CodeRankEmbed", trust_remote_code= True).to(device).to(torch.bfloat16) 29 | 30 | corpus, queries, qrels = GenericDataLoader( 31 | data_folder=os.path.join(dataset_dir, "code_datasets", f'csn_{lang}') 32 | ).load(split="test") 33 | 34 | 35 | query_examples = [(k, f'Represent this query for searching relevant code: {v}') for k, v in queries.items()] 36 | code_examples = [(k, v['text']) for k, v in corpus.items()] 37 | 38 | qs = [ex[1] for ex in query_examples] 39 | cs = [ex[1] for ex in code_examples] 40 | 41 | nl_vecs = model.encode(qs, show_progress_bar= True, batch_size= batch_size) 42 | code_vecs = model.encode(cs, show_progress_bar= True, batch_size= batch_size) 43 | 44 | 45 | scores = np.matmul(nl_vecs, code_vecs.T) 46 | sort_ids = np.argsort(scores, axis=-1, kind='quicksort', order=None)[:, ::-1] 47 | print(f"nl_vecs_shape: {nl_vecs.shape} " 48 | f"\t code_vecs_shape: {code_vecs.shape} " 49 | f"\t score_matrix_shape: {scores.shape}") 50 | 51 | nl_ids = [ex[0] for ex in query_examples] 52 | code_ids = [ex[0] for ex in code_examples] 53 | 54 | # Save retrieval results in rank format 55 | rank_file = os.path.join(output_dir, f'csn_{lang}', 'rank.tsv') 56 | os.makedirs(os.path.dirname(rank_file), exist_ok=True) 57 | 58 | with open(rank_file, 'w') as f: 59 | for query_idx, (query_id, sort_id) in enumerate(zip(nl_ids, sort_ids)): 60 | for rank, doc_idx in enumerate(sort_id[:1000]): # Save top 1000 results 61 | doc_id = code_ids[doc_idx] 62 | score = float(scores[query_idx][doc_idx]) 63 | f.write(f"{query_id}\t{doc_id}\t{score}\n") 64 | 65 | ranks = [] 66 | for url, sort_id in zip(nl_ids, sort_ids): 67 | rank = 0 68 | find = False 69 | for i, idx in enumerate(sort_id[:1000]): 70 | if find is False: 71 | rank += 1 72 | if code_ids[idx] == list(qrels[url].keys())[0]: 73 | find = True 74 | if find: 75 | ranks.append(1 / rank) 76 | else: 77 | ranks.append(0) 78 | 79 | mrr = float(np.mean(ranks)) 80 | return mrr 81 | 82 | 83 | def main(device = 'cuda', output_dir = 'results', dataset_dir = 'datasets', batch_size = 64): 84 | set_seed(42) 85 | Path(f'{output_dir}/csn').mkdir(parents=True, exist_ok=True) 86 | 87 | for lang in ['python', 'java', 'ruby', 'php', 'javascript', 'go']: 88 | mrr = evaluate(device, lang, batch_size, dataset_dir, output_dir) 89 | print(f'{lang} MRR', mrr) 90 | 91 | result_data = { 92 | "language": lang, 93 | } 94 | 95 | with open(f"{output_dir}/csn/overall_results.jsonl", 'a') as f: 96 | f.write(json.dumps({**result_data, **{'mrr': mrr}}) + "\n") 97 | 98 | if __name__ == "__main__": 99 | fire.Fire(main) 100 | -------------------------------------------------------------------------------- /src/evaluations/eval_localization.py: -------------------------------------------------------------------------------- 1 | from swebench.harness.run_evaluation import get_gold_predictions 2 | import numpy as np 3 | import json 4 | from tabulate import tabulate 5 | from fire import Fire 6 | from pathlib import Path 7 | import unidiff 8 | import os 9 | import csv 10 | from beir.datasets.data_loader import GenericDataLoader 11 | from get_repo_structure.get_patch_info import * 12 | 13 | SWE_BENCH_MAP = {'swe-bench-lite': 'princeton-nlp/SWE-bench_Lite', 14 | 'swe-bench-verified': 'princeton-nlp/SWE-bench_Verified', 15 | 'swe-bench': 'princeton-nlp/SWE-bench'} 16 | 17 | #ids where there exists at least one original function in the repo edited for swe-bench-lite test split 18 | CHANGED_IDS = set(['sympy__sympy-15011', 'mwaskom__seaborn-3190', 'django__django-15498', 'sympy__sympy-13043', 'django__django-16229', 'sympy__sympy-24066', 'django__django-13315', 'astropy__astropy-14995', 'django__django-13158', 'sympy__sympy-20442', 'matplotlib__matplotlib-23314', 'psf__requests-2674', 'django__django-14608', 'django__django-15061', 'astropy__astropy-12907', 'pytest-dev__pytest-5413', 'django__django-15814', 'pylint-dev__pylint-7993', 'django__django-13265', 'matplotlib__matplotlib-25442', 'django__django-14787', 'django__django-15252', 'scikit-learn__scikit-learn-11281', 'django__django-13590', 'sphinx-doc__sphinx-8506', 'sympy__sympy-13773', 'pytest-dev__pytest-7490', 'django__django-12113', 'sympy__sympy-14774', 'sympy__sympy-18835', 'sympy__sympy-24213', 'pydata__xarray-4248', 'django__django-16820', 'sphinx-doc__sphinx-8595', 'django__django-15388', 'scikit-learn__scikit-learn-10508', 'django__django-16379', 'matplotlib__matplotlib-23964', 'pydata__xarray-5131', 'pytest-dev__pytest-7168', 'scikit-learn__scikit-learn-14894', 'matplotlib__matplotlib-23563', 'sphinx-doc__sphinx-10451', 'django__django-13925', 'sympy__sympy-14817', 'scikit-learn__scikit-learn-25500', 'django__django-11620', 'pallets__flask-4992', 'sympy__sympy-13437', 'sympy__sympy-20154', 'scikit-learn__scikit-learn-11040', 'sympy__sympy-15609', 'psf__requests-3362', 'psf__requests-2148', 'sympy__sympy-13647', 'pytest-dev__pytest-5103', 'sympy__sympy-23117', 'django__django-11999', 'django__django-12497', 'django__django-16816', 'django__django-11422', 'sympy__sympy-22840', 'pytest-dev__pytest-11148', 'sympy__sympy-16988', 'matplotlib__matplotlib-23562', 'pytest-dev__pytest-5495', 'sympy__sympy-14308', 'django__django-13660', 'django__django-16910', 'pylint-dev__pylint-6506', 'scikit-learn__scikit-learn-10949', 'django__django-11133', 'sympy__sympy-21379', 'sphinx-doc__sphinx-7686', 'sympy__sympy-16792', 'sympy__sympy-20322', 'pytest-dev__pytest-7432', 'django__django-16139', 'matplotlib__matplotlib-22711', 'astropy__astropy-7746', 'sympy__sympy-15678', 'scikit-learn__scikit-learn-13241', 'pydata__xarray-4094', 'django__django-15202', 'django__django-12453', 'django__django-11001', 'astropy__astropy-14365', 'django__django-13321', 'sympy__sympy-12454', 'scikit-learn__scikit-learn-12471', 'sympy__sympy-18057', 'sympy__sympy-12419', 'sympy__sympy-16503', 'sympy__sympy-13031', 'django__django-12708', 'sympy__sympy-22714', 'pallets__flask-4045', 'django__django-10924', 'sphinx-doc__sphinx-10325', 'scikit-learn__scikit-learn-14983', 'scikit-learn__scikit-learn-13584', 'matplotlib__matplotlib-23299', 'django__django-11039', 'django__django-12908', 'scikit-learn__scikit-learn-13496', 'django__django-15819', 'django__django-14016', 'django__django-15738', 'django__django-11905', 'django__django-11019', 'sphinx-doc__sphinx-7738', 'sphinx-doc__sphinx-11445', 'django__django-14534', 'scikit-learn__scikit-learn-25747', 'sympy__sympy-18698', 'sympy__sympy-13471', 'django__django-12308', 'django__django-14997', 'sympy__sympy-21171', 'django__django-13710', 'django__django-11848', 'matplotlib__matplotlib-25079', 'matplotlib__matplotlib-24334', 'sympy__sympy-13146', 'django__django-16527', 'django__django-14730', 'sympy__sympy-18532', 'django__django-15789', 'django__django-14238', 'pylint-dev__pylint-7114', 'django__django-16595', 'mwaskom__seaborn-2848', 'scikit-learn__scikit-learn-13142', 'django__django-12589', 'sphinx-doc__sphinx-8721', 'scikit-learn__scikit-learn-25570', 'django__django-14752', 'django__django-12700', 'pylint-dev__pylint-7080', 'scikit-learn__scikit-learn-25638', 'pallets__flask-5063', 'django__django-11179', 'django__django-12983', 'django__django-15347', 'scikit-learn__scikit-learn-13497', 'sympy__sympy-21614', 'sympy__sympy-20212', 'sphinx-doc__sphinx-8435', 'django__django-15851', 'django__django-11583', 'sympy__sympy-12236', 'django__django-11910', 'matplotlib__matplotlib-23913', 'sympy__sympy-15345', 'scikit-learn__scikit-learn-15512', 'django__django-13964', 'sympy__sympy-11897', 'sympy__sympy-18189', 'sympy__sympy-19007', 'sympy__sympy-18087', 'sympy__sympy-13177', 'django__django-12125', 'matplotlib__matplotlib-26011', 'django__django-16046', 'django__django-11815', 'django__django-12747', 'django__django-16400', 'django__django-15695', 'pytest-dev__pytest-8906', 'django__django-15996', 'sphinx-doc__sphinx-8273', 'sympy__sympy-22005', 'django__django-17051', 'django__django-16873', 'sphinx-doc__sphinx-8474', 'django__django-12470', 'django__django-12284', 'pytest-dev__pytest-5221', 'django__django-11630', 'pytest-dev__pytest-5692', 'matplotlib__matplotlib-24265', 'pytest-dev__pytest-11143', 'matplotlib__matplotlib-26020', 'django__django-11797', 'django__django-17087', 'django__django-12856', 'django__django-13033', 'django__django-13658', 'django__django-12184', 'django__django-16408', 'django__django-14382', 'django__django-11742', 'mwaskom__seaborn-3407', 'sympy__sympy-14396', 'scikit-learn__scikit-learn-13779', 'pydata__xarray-3364', 'matplotlib__matplotlib-24149', 'django__django-13448', 'sympy__sympy-14317', 'sympy__sympy-12481', 'scikit-learn__scikit-learn-14087', 'sympy__sympy-24152', 'django__django-14667', 'matplotlib__matplotlib-25498', 'django__django-13757', 'psf__requests-1963', 'django__django-13028', 'pytest-dev__pytest-6116', 'sympy__sympy-19254', 'sympy__sympy-13971', 'scikit-learn__scikit-learn-15535', 'sympy__sympy-21627', 'sympy__sympy-21612', 'sympy__sympy-17139', 'matplotlib__matplotlib-24970', 'scikit-learn__scikit-learn-10297', 'django__django-15320', 'django__django-15781', 'django__django-16041', 'pylint-dev__pylint-7228', 'django__django-13447', 'django__django-13933', 'sympy__sympy-15346', 'sympy__sympy-24909', 'matplotlib__matplotlib-23476', 'django__django-13401', 'sympy__sympy-18621', 'sympy__sympy-23191', 'sympy__sympy-20639', 'django__django-14017', 'pytest-dev__pytest-7373', 'sphinx-doc__sphinx-8282', 'pydata__xarray-4493', 'sympy__sympy-13915', 'matplotlib__matplotlib-18869', 'django__django-13551', 'matplotlib__matplotlib-22835', 'sympy__sympy-13480', 'django__django-14155', 'django__django-14672', 'pylint-dev__pylint-5859', 'matplotlib__matplotlib-23987', 'sympy__sympy-11870', 'django__django-15790', 'mwaskom__seaborn-3010', 'sympy__sympy-18199', 'django__django-11283', 'sphinx-doc__sphinx-8801', 'matplotlib__matplotlib-25433', 'pytest-dev__pytest-8365', 'pytest-dev__pytest-7220', 'django__django-14855', 'django__django-12286', 'sphinx-doc__sphinx-8713', 'psf__requests-2317', 'astropy__astropy-14182', 'django__django-13768', 'django__django-13230', 'sympy__sympy-24102', 'sympy__sympy-21847', 'sympy__sympy-14024', 'psf__requests-863', 'scikit-learn__scikit-learn-14092', 'django__django-14999', 'sympy__sympy-13895', 'astropy__astropy-6938', 'sphinx-doc__sphinx-7975', 'sympy__sympy-16281', 'django__django-16255', 'sympy__sympy-23262', 'sympy__sympy-20049', 'sphinx-doc__sphinx-8627', 'django__django-14580', 'matplotlib__matplotlib-25311']) 19 | 20 | 21 | def topk_accuracy(predictions_dict, label_dict, k = 5, level = 'file'): 22 | topk = np.zeros(k) 23 | tot = 0 24 | for key in label_dict.keys(): 25 | if key in predictions_dict and key in label_dict and key in CHANGED_IDS: 26 | predictions, label = predictions_dict[key], label_dict[key] 27 | for i in range(min(len(predictions), k)): 28 | if label.issubset(set(predictions[:i + 1])): 29 | topk[i:] += 1.0 30 | break 31 | 32 | tot += 1 33 | assert tot == 274 34 | topk = topk / tot * 100 35 | i_lst = [0, 1, 2] if level == 'file' else [4, 9] 36 | return tabulate([[f'top-{i + 1}', round(acc, 1)] for i, acc in enumerate(topk) if i in i_lst], 37 | headers=['top-k', 'accuracy (%)'], tablefmt="grid") 38 | 39 | 40 | 41 | 42 | def read_jsonl(filepath): 43 | data = [] 44 | with open(filepath, 'r') as file: 45 | for line in file: 46 | data.append(json.loads(line)) 47 | return data 48 | 49 | def convert_solutions_dict(dataset, key = 'model_patch'): 50 | return {elem['instance_id']: elem[key] for elem in dataset} 51 | 52 | def tabulate_dict(dict, headers = ['metric', 'value']): 53 | return tabulate([[k, v] for k, v in dict.items()], 54 | headers=headers, tablefmt="grid") 55 | 56 | 57 | def parse_agentless_funcs(agentless_results): 58 | parsed_res = {} 59 | for i in range(len(agentless_results)): 60 | data = agentless_results[i] 61 | file_res = [] 62 | for j in range(len(data['found_related_locs'])): 63 | file_name = data['found_files'][j] 64 | for retrieved in data['found_related_locs'][j]: 65 | for ret in retrieved.split('\n'): 66 | if ret.startswith('function: '): 67 | file_res.append(f"{file_name}/{ret.split('function: ')[-1].strip().replace('.', '/')}") 68 | parsed_res[data['instance_id']] = file_res 69 | return parsed_res 70 | 71 | def file_localization_results(agentless_path = None, 72 | crag_bench_path_results = None, ds_name = "swe-bench-lite", split = 'test', k = 5): 73 | solutions = convert_solutions_dict(get_gold_predictions(SWE_BENCH_MAP[ds_name], split)) 74 | 75 | gold_files_changed = {key: 76 | {patch_file.source_file.split("a/", 1)[-1] 77 | for patch_file in unidiff.PatchSet(v)} for key, v in solutions.items() 78 | } 79 | 80 | if agentless_path is not None: 81 | data = read_jsonl(agentless_path) 82 | localized_files = convert_solutions_dict(data, key = 'found_files') 83 | else: 84 | localized_files = crag_bench_path_results 85 | 86 | print(f'Top-{k} accuracy for File Localization: ') 87 | print(topk_accuracy(localized_files, gold_files_changed, k)) 88 | 89 | def parse_agentless_repair(data): 90 | localized_functions = {} 91 | for dat in data: 92 | patch_info = patch_to_dict(dat['model_patch']) 93 | changed_funcs = set() 94 | for fle, hunks in patch_info.items(): 95 | for hunk in hunks: 96 | if hunk['function_changed'] and hunk['newly_added'] is False: 97 | if hunk['class_changed']: 98 | changed_funcs.add(f'{fle}/{hunk["class_changed"]}/{hunk["function_changed"]}') 99 | else: 100 | changed_funcs.add(f'{fle}/{hunk["function_changed"]}') 101 | 102 | localized_functions[dat['instance_id']] = changed_funcs 103 | return localized_functions 104 | 105 | 106 | def function_localization_results(agentless_path = None, 107 | crag_bench_path_results = None, ds_name = "swe-bench-lite", split = 'test', k = 5, changed_functions = None, reranker_results = {}): 108 | if agentless_path is not None: 109 | data = read_jsonl(agentless_path) 110 | localized_functions = parse_agentless_funcs(data) 111 | elif reranker_results != {}: 112 | localized_functions = reranker_results 113 | else: 114 | localized_functions = convert_solutions_dict(read_jsonl(crag_bench_path_results), key = 'docs') 115 | 116 | print(f'Top-{k} accuracy for Function Localization: ') 117 | print(topk_accuracy(localized_functions, changed_functions, k, level = 'function')) 118 | 119 | 120 | 121 | def extract_file_path(changed_funcs): 122 | for k, v in changed_funcs.items(): 123 | changed_files = [] 124 | seen_files = set() 125 | for vv in v: 126 | match = re.match(r"(.+\.py)(/.*)?", vv) 127 | if match: 128 | if match.group(1) not in seen_files: 129 | changed_files.append(match.group(1)) 130 | seen_files.add(changed_files[-1]) 131 | else: 132 | import pdb;pdb.set_trace() 133 | changed_funcs[k] = changed_files 134 | 135 | return changed_funcs 136 | 137 | 138 | def load_beir_results_from_tsv(input_file): 139 | results = defaultdict(dict) 140 | with open(input_file, 'r', newline='') as tsvfile: 141 | tsvreader = csv.reader(tsvfile, delimiter='\t') 142 | next(tsvreader) 143 | 144 | for row in tsvreader: 145 | query_id, doc_id, score = row[0], row[1], float(row[2]) 146 | results[query_id][doc_id] = score 147 | 148 | return results 149 | 150 | def get_sorted_documents(results, sorted_documents_per_query): 151 | 152 | for query_id, doc_scores in results.items(): 153 | sorted_docs = sorted(doc_scores.items(), key=lambda x: x[1], reverse=True) 154 | sorted_doc_ids = [doc_id for doc_id, score in sorted_docs] 155 | 156 | res = [] 157 | seen = set() 158 | for doc_id in sorted_doc_ids: 159 | match = re.match(r"(.+\.py)(/.*)?", doc_id) 160 | if match.group(1) not in seen: 161 | res.append(match.group(1)) 162 | seen.add(match.group(1)) 163 | 164 | 165 | sorted_documents_per_query[query_id] = res 166 | 167 | return sorted_documents_per_query 168 | 169 | def get_sorted_documents_func(results, sorted_documents_per_query): 170 | 171 | for query_id, doc_scores in results.items(): 172 | sorted_docs = sorted(doc_scores.items(), key=lambda x: x[1], reverse=True) 173 | sorted_documents_per_query[query_id] = [doc_id for doc_id, score in sorted_docs] 174 | 175 | return sorted_documents_per_query 176 | 177 | 178 | def main(level = 'file', mode = 'agentless', model = 'CodeRankEmbed', ds_name = 'swe-bench-lite', split = 'test', k = 10, agentless_path = '', retriever_output_dir = 'results', dataset_output_dir = 'datasets'): 179 | if ds_name != 'swe-bench-lite' and split != 'test': 180 | raise NotImplementedError('only evaluation on the swe-bench-lite test split is supported now!!!') 181 | 182 | agentless_path = None 183 | crag_bench_path_results = None 184 | beir_res = None 185 | 186 | if not mode.startswith('agentless'): 187 | if level == 'file': 188 | level = 'function' 189 | actually_file = True 190 | else: 191 | actually_file = False 192 | 193 | if mode == 'agentless': 194 | agentless_path = Path(agentless_path) 195 | 196 | elif mode == 'code-retriever': 197 | prefx = f'{retriever_output_dir}/model={model}_dataset={ds_name}_split={split}_level={level}_evalmode=default' 198 | crag_bench_path_results = Path(f'{prefx}_results.json') 199 | try: 200 | beir_res = read_jsonl(f'{prefx}_output.json') 201 | except: 202 | beir_res = None 203 | 204 | if not ((mode.startswith('agentless') and level == 'file')) : 205 | if split == 'test': 206 | prefx = f"{ds_name}" 207 | else: 208 | prefx = f"{ds_name}-{split}" 209 | 210 | if level == 'file': 211 | prefx += '_' 212 | else: 213 | prefx += f'-{level}_' 214 | 215 | instance_list = [i for i in os.listdir(dataset_output_dir) if i.startswith(prefx)] 216 | 217 | reranker_results = {} 218 | if mode == 'reranker': 219 | raise NotImplementedError('Re-ranker localization evaluation to be added in') 220 | 221 | 222 | if (mode.startswith('agentless') and level == 'function') or not actually_file: 223 | qrels = [GenericDataLoader( 224 | data_folder=os.path.join(dataset_output_dir, ins_dir) 225 | ).load(split="test")[2] for ins_dir in instance_list] 226 | 227 | changed_functions = {list(qrel.keys())[0] : set(qrel[list(qrel.keys())[0]].keys()) for qrel in qrels} 228 | if beir_res is not None: 229 | print(beir_res) 230 | 231 | function_localization_results(agentless_path, crag_bench_path_results, 232 | ds_name= ds_name, split= split, k = k, changed_functions= changed_functions, reranker_results = reranker_results) 233 | 234 | elif mode == 'reranker': 235 | level = 'file' 236 | 237 | else: 238 | crag_bench_path_results = extract_file_path(convert_solutions_dict(read_jsonl(crag_bench_path_results), key = 'docs')) 239 | level = 'file' 240 | 241 | if level == 'file': 242 | if mode == 'reranker': 243 | raise NotImplementedError('Re-ranker localization evaluation to be added in') 244 | 245 | 246 | file_localization_results(agentless_path, crag_bench_path_results, 247 | ds_name= ds_name, split= split, k = k) 248 | 249 | 250 | 251 | if __name__ == "__main__": 252 | Fire(main) -------------------------------------------------------------------------------- /src/evaluations/eval_swebench.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import logging 4 | import argparse 5 | from time import time 6 | from datasets import load_dataset 7 | from beir import util, LoggingHandler 8 | from beir.retrieval import models 9 | from beir.datasets.data_loader import GenericDataLoader 10 | from beir.retrieval.evaluation import EvaluateRetrieval 11 | from beir.retrieval.search.dense import DenseRetrievalExactSearch as DRES 12 | from tqdm import tqdm 13 | from transformers import AutoTokenizer 14 | from copy import deepcopy 15 | import torch 16 | import csv 17 | from sentence_transformers import SentenceTransformer 18 | from collections import defaultdict 19 | 20 | #### Just some code to print debug information to stdout 21 | logging.basicConfig(format='%(asctime)s - %(message)s', 22 | datefmt='%Y-%m-%d %H:%M:%S', 23 | level=logging.INFO, 24 | handlers=[LoggingHandler()]) 25 | 26 | def get_top_docs(results: dict, corpus: dict, task_id: str, topk: int = 100) -> list[str]: 27 | if task_id not in results: return [] 28 | doc_scores = results[task_id] 29 | doc_scores_sorted = sorted(doc_scores.items(), key=lambda item: item[1], reverse=True) 30 | doc_scores_sorted = doc_scores_sorted[:topk] 31 | doc_code_snippets = [code_id for code_id, score in doc_scores_sorted] 32 | return doc_code_snippets 33 | 34 | def save_beir_results_to_tsv(results, output_file): 35 | # Create a defaultdict to store the results 36 | formatted_results = defaultdict(dict) 37 | 38 | # Process the results 39 | for query_id, doc_scores in results.items(): 40 | for doc_id, score in doc_scores.items(): 41 | formatted_results[query_id][doc_id] = score 42 | 43 | # Write to TSV 44 | with open(output_file, 'w', newline='') as tsvfile: 45 | tsvwriter = csv.writer(tsvfile, delimiter='\t') 46 | tsvwriter.writerow(['Query ID', 'Corpus ID', 'Relevance Score']) 47 | 48 | for query_id, doc_scores in formatted_results.items(): 49 | for doc_id, score in doc_scores.items(): 50 | tsvwriter.writerow([query_id, doc_id, score]) 51 | 52 | print(f"Results saved to {output_file}") 53 | 54 | def save_beir_results_to_tsv_list(all_results, output_file): 55 | results_dct = {} 56 | for result in all_results: 57 | for k, v in result.items(): 58 | if k in results_dct: 59 | import pdb;pdb.set_trace() 60 | results_dct[k] = v 61 | save_beir_results_to_tsv(results_dct, output_file) 62 | 63 | def main(): 64 | if os.path.exists(args.results_file): 65 | os.remove(args.results_file) 66 | 67 | contrast_encoder = models.SentenceBERT() 68 | contrast_encoder.q_model = SentenceTransformer(args.model, trust_remote_code= True).to(torch.bfloat16) 69 | contrast_encoder.doc_model = SentenceTransformer(args.model, trust_remote_code= True).to(torch.bfloat16) 70 | contrast_encoder.q_model.max_seq_length = args.sequence_length 71 | contrast_encoder.doc_model.max_seq_length = args.sequence_length 72 | 73 | model = DRES(contrast_encoder, batch_size=args.batch_size, corpus_chunk_size=512*9999) 74 | retriever = EvaluateRetrieval(model, score_function="dot") 75 | 76 | args.output_file = f"{args.output_dir}/model={args.model}_dataset={args.dataset}_split={args.split}_level={args.level}_eval_mode=default_output.json" 77 | args.results_file = f"{args.output_dir}/model={args.model}_dataset={args.dataset}_split={args.split}_level={args.level}_eval_mode=default_results.json" 78 | args.rerank_input_file = f"{args.output_dir}/model={args.model}_dataset={args.dataset}_split={args.split}_level={args.level}_eval_mode=default_rerank_input.tsv" 79 | 80 | if args.tok: 81 | tokenizer = AutoTokenizer.from_pretrained(args.tokenizer, trust_remote_code = True) 82 | query_tokens = [] 83 | corpus_tokens = [] 84 | 85 | 86 | if args.dataset.startswith("swe-bench"): 87 | all_eval_results = [] 88 | 89 | if args.dataset.startswith("swe-bench"): 90 | if 'lite' in args.dataset.lower(): 91 | swebench = load_dataset("princeton-nlp/SWE-bench_Lite")[args.split] 92 | elif 'verified' in args.dataset.lower(): 93 | swebench = load_dataset("princeton-nlp/SWE-bench_Verified")[args.split] 94 | else: 95 | swebench = load_dataset("princeton-nlp/SWE-bench")[args.split] 96 | all_top_docs = [[] for _ in swebench] 97 | if args.split == 'test': 98 | prefx = f"{args.dataset}" 99 | else: 100 | prefx = f"{args.dataset}-{args.split}" 101 | if args.level == 'file': 102 | prefx += '_' 103 | else: 104 | prefx += f'-{args.level}_' 105 | else: 106 | raise ValueError(f"`dataset` should starts with either 'swe-bench'.") 107 | 108 | instance_list = [i for i in os.listdir(args.dataset_dir) if i.startswith(prefx)] 109 | 110 | for ins_dir in tqdm(instance_list): 111 | logging.info("Instance Repo: {}".format(ins_dir)) 112 | # load data and perform retrieval 113 | corpus, queries, qrels = GenericDataLoader( 114 | data_folder=os.path.join(args.dataset_dir, ins_dir) 115 | ).load(split="test") 116 | if args.add_prefix and args.query_prefix != '': 117 | queries = {k : f'{args.query_prefix}: {v}' for k, v in queries.items()} 118 | 119 | logging.info(f"Instance #{ins_dir}: #{len(corpus)} corpus, #{len(queries)} queries") 120 | 121 | if args.tok: 122 | for v in queries.values(): 123 | query_tokens.append(tokenizer(v, padding=True, truncation=False, return_tensors="pt")['input_ids'].shape[1]) 124 | 125 | for v in corpus.values(): 126 | corpus_tokens.append(tokenizer(v['text'], padding=True, truncation=False, return_tensors="pt")['input_ids'].shape[1]) 127 | 128 | continue 129 | 130 | rerank_tsv_file = args.rerank_input_file.split('.') 131 | rerank_tsv_file = f'{rerank_tsv_file[0]}_{ins_dir[len(prefx):]}.tsv' 132 | 133 | 134 | start_time = time() 135 | if len(queries) == 1: 136 | queries.update({"dummy": "dummy"}) 137 | results = retriever.retrieve(corpus, queries) 138 | save_beir_results_to_tsv(results, rerank_tsv_file) 139 | if "dummy" in queries: 140 | queries.pop("dummy") 141 | results.pop("dummy") 142 | end_time = time() 143 | logging.info("Time taken to retrieve: {:.2f} seconds".format(end_time - start_time)) 144 | 145 | # get topk retrieved docs 146 | if args.dataset.startswith("swe-bench"): 147 | indices = [i for i,ex in enumerate(swebench) if ex["instance_id"] in queries] 148 | for index in indices: 149 | instance_id = swebench[index]["instance_id"] 150 | all_top_docs[index] = get_top_docs(results, corpus, instance_id) 151 | 152 | else: 153 | raise ValueError(f"`dataset` should starts with either 'swe-bench'.") 154 | 155 | # evaluate retrieval results 156 | if len(qrels) == 0: 157 | logging.info("No qrels found for this dataset.") 158 | return 159 | logging.info("Retriever evaluation for k in: {}".format(retriever.k_values)) 160 | ndcg, _map, recall, precision = retriever.evaluate(qrels, results, retriever.k_values) 161 | mrr = retriever.evaluate_custom(qrels, results, retriever.k_values, metric="mrr") 162 | eval_results = { 163 | "ndcg": ndcg, "mrr": mrr, 164 | "recall": recall, "precision": precision, 165 | "time": end_time - start_time 166 | } 167 | logging.info(f"Instance #{ins_dir}: {eval_results}") 168 | all_eval_results.append(eval_results) 169 | 170 | with open(args.output_file + "_all", "w") as f: 171 | json.dump(all_eval_results, f) 172 | 173 | if args.tok: 174 | import matplotlib.pyplot as plt 175 | import seaborn as sns 176 | import numpy as np 177 | # Create the plot 178 | plt.figure(figsize=(10, 6)) 179 | sns.histplot(query_tokens, bins=50, kde=True, stat='probability', label='queries distribution') 180 | 181 | # Set the axis labels 182 | plt.xlabel('tokens length') 183 | plt.ylabel('frequency') 184 | plt.legend() 185 | 186 | # Display the plot 187 | plt.savefig('queries_tok.png') 188 | plt.close() 189 | 190 | # Create the plot 191 | plt.figure(figsize=(10, 6)) 192 | sns.histplot(corpus_tokens, bins=50, kde=True, log_scale = (True, False), stat='probability', label='corpus distribution') 193 | 194 | # Set the axis labels 195 | plt.xlabel('tokens length') 196 | plt.ylabel('frequency') 197 | plt.legend() 198 | 199 | # Display the plot 200 | plt.savefig('corpus_tok.png') 201 | plt.close() 202 | 203 | print('queries mean tokens ', np.mean(query_tokens)) 204 | print('corpus mean tokens ', np.mean(corpus_tokens)) 205 | return 206 | 207 | if args.dataset.startswith("swe-bench"): 208 | swebench = swebench.add_column("docs", all_top_docs) 209 | swebench.to_json(args.results_file) 210 | 211 | avg_eval_results = {} 212 | for k,v_dict in all_eval_results[0].items(): 213 | if isinstance(v_dict, dict): 214 | avg_v_dict = {} 215 | for vk,vv in v_dict.items(): 216 | avg_vv = sum([e[k][vk] for e in all_eval_results])/len(all_eval_results) 217 | avg_v_dict[vk] = avg_vv 218 | avg_eval_results.update(avg_v_dict) 219 | elif isinstance(v_dict, float): 220 | avg_v = sum([e[k] for e in all_eval_results])/len(all_eval_results) 221 | avg_eval_results[k] = avg_v 222 | else: 223 | raise ValueError 224 | print("Average Eval Results: ", avg_eval_results) 225 | with open(args.output_file, "w") as f: 226 | json.dump(avg_eval_results, f) 227 | 228 | else: 229 | raise ValueError(f"`dataset` should starts with either 'swe-bench'.") 230 | 231 | if __name__ == "__main__": 232 | parser = argparse.ArgumentParser() 233 | parser.add_argument("--dataset", type=str, default="swe-bench-lite", 234 | help="Dataset to use for evaluation") 235 | parser.add_argument("--split", type=str, default="test", 236 | help="Dataset split to use for evaluation") 237 | parser.add_argument("--level", type=str, default="function", 238 | help="Localization level to use for evaluation") 239 | parser.add_argument("--model", type=str, default="cornstack/CodeRankEmbed", help="Sentence-BERT model to use") 240 | parser.add_argument("--tokenizer", type=str, default= "Snowflake/snowflake-arctic-embed-m-long", help="Sentence-BERT model to use") 241 | parser.add_argument("--batch_size", type=int, default=256, help="Batch size for retrieval") 242 | parser.add_argument("--sequence_length", type=int, default=1024, help="Sequence length for retrieval") 243 | parser.add_argument("--output_dir", type=str, default="results", 244 | help="Specify the filepath if you want to save the retrieval (evaluation) results.") 245 | parser.add_argument("--dataset_dir", type=str, default="datasets", 246 | help="Specify the filepath where the dataset is storied") 247 | parser.add_argument('--tok', default= False, type = bool) 248 | parser.add_argument('--add_prefix', default= True, type = bool) 249 | parser.add_argument('--query_prefix', default= 'Represent this query for searching relevant code', type = str) 250 | parser.add_argument('--document_prefix', default= '', type = str) 251 | args = parser.parse_args() 252 | 253 | main() -------------------------------------------------------------------------------- /src/evaluations/utils.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | class Retriever: 4 | def __init__( 5 | self, 6 | model, 7 | add_prefix=False, 8 | query_prefix="Represent this query for searching relevant code", 9 | document_prefix="", 10 | normalize=True, 11 | binarize=False, 12 | multiprocess = True 13 | ): 14 | self.model = model 15 | self.multiprocess = multiprocess 16 | if multiprocess: 17 | self.gpu_pool = self.model.start_multi_process_pool() 18 | self.add_prefix = add_prefix 19 | self.doc_as_query = False 20 | self.query_prefix = query_prefix 21 | self.docoment_prefix = document_prefix 22 | self.normalize = normalize 23 | self.binarize = binarize 24 | 25 | def set_normalize(self, normalize): 26 | self.normalize = normalize 27 | 28 | def encode(self, sentences, **kwargs): 29 | if self.add_prefix: 30 | print(f"Adding prefix: {self.query_prefix}") 31 | sentences = [f"{self.query_prefix}: {sent}" for sent in sentences] 32 | kwargs.pop('convert_to_tensor') 33 | kwargs["normalize_embeddings"] = self.normalize 34 | return self.model.encode_multi_process(sentences, self.gpu_pool, **kwargs) 35 | 36 | def encode_queries(self, queries, **kwargs) -> np.ndarray: 37 | if self.add_prefix and self.query_prefix != "": 38 | input_texts = [f'{self.query_prefix}: {q}' for q in queries] 39 | else: 40 | input_texts = queries 41 | 42 | kwargs.pop('convert_to_tensor') 43 | kwargs["normalize_embeddings"] = self.normalize 44 | if self.multiprocess: 45 | return self.model.encode_multi_process(input_texts, self.gpu_pool, **kwargs) 46 | return self.model.encode(input_texts, **kwargs) 47 | 48 | def encode_corpus(self, corpus, **kwargs) -> np.ndarray: 49 | if isinstance(corpus[0], dict): 50 | input_texts = ['{} {}'.format(doc.get('title', ''), doc['text']).strip() for doc in corpus] 51 | else: 52 | input_texts = corpus 53 | if self.add_prefix: 54 | if self.doc_as_query and self.query_prefix != "": 55 | input_texts = [f'{self.query_prefix}: {t}' for t in input_texts] 56 | elif self.docoment_prefix != "": 57 | input_texts = [f'{self.docoment_prefix}: {t}' for t in input_texts] 58 | 59 | kwargs.pop('convert_to_tensor') 60 | kwargs["normalize_embeddings"] = self.normalize 61 | if self.multiprocess: 62 | return self.model.encode_multi_process(input_texts, self.gpu_pool, **kwargs) 63 | return self.model.encode(input_texts, **kwargs) -------------------------------------------------------------------------------- /src/get_repo_structure/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gangiswag/cornstack/6432dfde69400892000bb2dabdb90fbc3b239f20/src/get_repo_structure/__init__.py -------------------------------------------------------------------------------- /src/get_repo_structure/get_patch_info.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import json 3 | import re 4 | from collections import defaultdict 5 | 6 | def split_github_patch(patch_string): 7 | # Regular expression to match the change indicator pattern 8 | pattern = r"@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@ " 9 | 10 | # Split the string using the pattern 11 | split_patches = re.split(pattern, patch_string) 12 | 13 | # Remove any empty strings from the result 14 | split_patches = [patch.strip() for patch in split_patches if patch.strip()] 15 | 16 | return split_patches 17 | 18 | def parse_patch(patch): 19 | """ 20 | Parse a git patch into a structured format. 21 | 22 | Parameters: 23 | patch (str): The git patch as a string. 24 | 25 | Returns: 26 | list: A list of dictionaries representing the file changes and hunks. 27 | """ 28 | file_changes = [] 29 | current_file = None 30 | current_hunk = None 31 | deleted_lines = 0 32 | 33 | patch_lines = patch.split("\n") 34 | for line in patch_lines: 35 | if line.startswith("diff --git"): 36 | # Reset for new files 37 | if current_file: 38 | file_changes.append(current_file) 39 | current_file = {"file": "", "hunks": []} 40 | elif line.startswith("--- a/"): 41 | pass 42 | elif line.startswith("+++ b/"): 43 | if current_file is not None: 44 | current_file["file"] = line[6:] 45 | elif line.startswith("@@ "): 46 | if current_file is not None: 47 | match = re.match(r"@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@", line) 48 | if match: 49 | current_hunk = {"start_line": int(match.group(2)), "changes": []} 50 | current_file["hunks"].append(current_hunk) 51 | deleted_lines = 0 52 | added_lines = 0 53 | elif line.startswith("+") or line.startswith("-"): 54 | if current_hunk is not None: 55 | change_type = "add" if line.startswith("+") else "delete" 56 | if change_type == "delete": 57 | deleted_lines += 1 58 | current_hunk["changes"].append( 59 | { 60 | "type": change_type, 61 | "content": line[1:].strip(), 62 | "line": current_hunk["start_line"] - added_lines, 63 | } 64 | ) 65 | current_hunk["start_line"] += 1 66 | else: 67 | added_lines += 1 68 | current_hunk["changes"].append( 69 | { 70 | "type": change_type, 71 | "content": line[1:].strip(), 72 | "line": current_hunk["start_line"] - deleted_lines, 73 | } 74 | ) 75 | current_hunk["start_line"] += 1 76 | else: 77 | if current_hunk is not None: 78 | current_hunk["start_line"] += 1 79 | 80 | if current_file: 81 | file_changes.append(current_file) 82 | 83 | return file_changes 84 | 85 | 86 | def patch_to_dict(patch_string): 87 | patch_lines = patch_string.splitlines() 88 | patch_dict = {} 89 | 90 | current_file = None 91 | current_content = [] 92 | 93 | for line in patch_lines: 94 | # Check if this line indicates the start of a new file 95 | if line.startswith('diff --git'): 96 | # If we were already processing a file, save its content 97 | if current_file: 98 | patch_dict[current_file] = process_hunks(current_content) 99 | # Reset for the new file 100 | current_file = None 101 | current_content = [] 102 | 103 | # Identify the file name from the '+++ b/' line 104 | elif line.startswith('+++ b/'): 105 | current_file = line[6:] # Extract file name from '+++ b/filename' 106 | 107 | # If we are processing a file, keep adding content 108 | elif current_file: 109 | current_content.append(line) 110 | 111 | # Don't forget to add the last file processed to the dictionary 112 | if current_file: 113 | patch_dict[current_file] = process_hunks(current_content) 114 | 115 | return patch_dict 116 | 117 | def process_hunks(file_content): 118 | """Process the content of a file into hunks keyed by the '@@' lines.""" 119 | hunk_dict = {} 120 | current_hunk_key = None 121 | current_hunk_content = [] 122 | 123 | for line in file_content: 124 | if line.startswith('@@'): 125 | # If there is an existing hunk, save it before processing the new one 126 | if current_hunk_key: 127 | hunk_dict[current_hunk_key] = "\n".join(current_hunk_content) 128 | # Set the new hunk key and reset the hunk content 129 | current_hunk_key = line 130 | current_hunk_content = [] 131 | 132 | # Keep adding lines to the current hunk content 133 | current_hunk_content.append(line) 134 | 135 | # Save the last hunk processed 136 | if current_hunk_key: 137 | hunk_dict[current_hunk_key] = "\n".join(current_hunk_content) 138 | 139 | return hunk_dict 140 | 141 | 142 | def get_last_function_or_method(structure): 143 | last_function = None 144 | last_method = None 145 | last_class_name = None 146 | 147 | # Check the last function in the functions list 148 | if structure['functions']: 149 | last_function = max(structure['functions'], key=lambda func: func['end_line']) 150 | 151 | # Check the last method in each class and store the class name 152 | for cls in structure['classes']: 153 | if cls['methods']: 154 | last_class_method = max(cls['methods'], key=lambda method: method['end_line']) 155 | if not last_method or last_class_method['end_line'] > last_method['end_line']: 156 | last_method = last_class_method 157 | last_class_name = cls['name'] 158 | 159 | # Compare the last function and last method 160 | if last_function and last_method: 161 | if last_function['end_line'] > last_method['end_line']: 162 | return {'function_name': last_function['name'], 'class_name': None} 163 | else: 164 | return {'function_name': last_method['name'], 'class_name': last_class_name} 165 | elif last_function: 166 | return {'function_name': last_function['name'], 'class_name': None} 167 | elif last_method: 168 | return {'function_name': last_method['name'], 'class_name': last_class_name} 169 | else: 170 | return None 171 | 172 | def find_class_only(line_num, structure): 173 | for cls in structure['classes']: 174 | if (cls['start_line'] <= line_num <= cls['end_line']): 175 | return cls 176 | return None 177 | def find_class_or_function(line_num, structure): 178 | for cls in structure['classes']: 179 | if (cls['start_line'] <= line_num <= cls['end_line']): 180 | for method in cls['methods']: 181 | if (method['start_line'] <= line_num <= method['end_line']): 182 | return cls, method 183 | return cls, None # No method, but inside the class 184 | for func in structure['functions']: 185 | if (func['start_line'] <= line_num <= func['end_line']): 186 | return None, func 187 | return None, None 188 | 189 | 190 | 191 | # Helper function to find the class or function for a line 192 | # def find_class_or_function(line_num, structure): 193 | # def find_precise_function(line_num, functions): 194 | # """Recursively find the most precise nested function at the given line number.""" 195 | # for func in functions: 196 | # if func['start_line'] <= line_num <= func['end_line']: 197 | # # Check if there are nested functions inside this function 198 | # precise_nested = find_precise_function(line_num, func.get('nested_functions', [])) 199 | # return func if precise_nested is None else precise_nested 200 | # return None 201 | 202 | # # Check if the line number falls within a class 203 | # for cls in structure['classes']: 204 | # if cls['start_line'] <= line_num <= cls['end_line']: 205 | # # Check if it falls within a method inside the class 206 | # for method in cls['methods']: 207 | # if method['start_line'] <= line_num <= method['end_line']: 208 | # # Check for the most precise nested function within this method 209 | # precise_function = find_precise_function(line_num, [method]) 210 | # return cls, precise_function 211 | # return cls, None # No method, but inside the class 212 | 213 | # # Check if the line number falls within a top-level function 214 | # for func in structure['functions']: 215 | # if func['start_line'] <= line_num <= func['end_line']: 216 | # # Check for the most precise nested function within this top-level function 217 | # precise_function = find_precise_function(line_num, [func]) 218 | # return None, precise_function 219 | 220 | # return None, None # Not inside any class or function 221 | 222 | def create_hunk_result(class_changed, function_changed, num_lines_changed, num_lines_added, 223 | num_lines_removed, newly_added): 224 | result = { 225 | 'class_changed': class_changed, 226 | 'function_changed': function_changed, 227 | 'num_lines_changed': num_lines_changed, 228 | 'num_lines_added': num_lines_added, 229 | 'num_lines_removed': num_lines_removed, 230 | 'newly_added': newly_added 231 | } 232 | return result 233 | 234 | 235 | 236 | def analyze_hunks(hunks, structure): 237 | results = [] 238 | # Iterate through each hunk and analyze changes 239 | for hunk_header, hunk_content in hunks.items(): 240 | # Parse hunk header to get line ranges (e.g., @@ -101,10 +101,11 @@) 241 | hunk_lines = hunk_content.splitlines() 242 | old_line_num, new_line_num = extract_line_numbers(hunk_header) 243 | 244 | class_changed = None 245 | function_changed = None 246 | 247 | current_old_line = old_line_num 248 | # Process each line in the hunk content 249 | i = 1 250 | while i < len(hunk_lines): 251 | if hunk_lines[i].startswith('+') and not hunk_lines[i].startswith('+++'): 252 | if 'def ' in hunk_lines[i]: 253 | while i < len(hunk_lines) and hunk_lines[i].startswith('+') and not hunk_lines[i].startswith('+++'): 254 | i += 1 255 | 256 | elif 'class ' in hunk_lines[i]: 257 | while i < len(hunk_lines) and hunk_lines[i].startswith('+') and not hunk_lines[i].startswith('+++'): 258 | if 'def ' in hunk_lines[i]: 259 | while i < len(hunk_lines) and hunk_lines[i].startswith('+') and not hunk_lines[i].startswith('+++'): 260 | i += 1 261 | else: 262 | i += 1 263 | 264 | else: 265 | # Find the associated class or function for the added line 266 | cls, func = find_class_or_function(current_old_line, structure) 267 | if cls: 268 | class_changed = cls['name'] 269 | if func: 270 | function_changed = func['name'] 271 | 272 | result = {'class_changed': class_changed, 'function_changed': function_changed, 'newly_added': True} 273 | class_changed = None 274 | function_changed = None 275 | 276 | results.append(result) 277 | i += 1 278 | 279 | elif hunk_lines[i].startswith('-') and not hunk_lines[i].startswith('---'): 280 | # This line was removed 281 | cls, func = find_class_or_function(current_old_line, structure) 282 | if cls: 283 | class_changed = cls['name'] 284 | if func: 285 | function_changed = func['name'] 286 | result = {'class_changed': class_changed, 'function_changed': function_changed, 'newly_added': False} 287 | class_changed = None 288 | function_changed = None 289 | results.append(result) 290 | current_old_line += 1 291 | i += 1 292 | else: 293 | current_old_line += 1 294 | i += 1 295 | 296 | 297 | # Create the result for this hunk 298 | class_changed = None 299 | function_changed = None 300 | 301 | return results 302 | 303 | def extract_line_numbers(hunk_header): 304 | # Example hunk header format: @@ -101,10 +101,11 @@ 305 | parts = hunk_header.split() 306 | old_range = parts[1][1:].split(',') # "-101,10" 307 | new_range = parts[2][1:].split(',') # "+101,11" 308 | 309 | old_line_num = int(old_range[0]) 310 | new_line_num = int(new_range[0]) 311 | 312 | return old_line_num, new_line_num 313 | 314 | 315 | def extract_structure(path_str, structure): 316 | # Split the path by '/' 317 | keys = path_str.split('/') 318 | 319 | # Initialize structure if it's not provided 320 | if structure is None: 321 | structure = {'structure': {}} 322 | 323 | # Start with the base dictionary (the 'structure' key) 324 | current_level = structure['structure'] 325 | 326 | # Iterate through each part of the path 327 | for key in keys: 328 | current_level = current_level[key] 329 | 330 | return current_level 331 | 332 | 333 | def parse_patch_full(patch, repo_structure): 334 | """ 335 | Parse a git patch into a structured format. 336 | 337 | Parameters: 338 | patch (str): The git patch as a string. 339 | 340 | Returns: 341 | list: A list of dictionaries representing the file changes and hunks. 342 | """ 343 | #TODO: get info about which functions/classes added, removed, renamed 344 | hunks_per_file_dct = patch_to_dict(patch) 345 | full_patch_info = {} 346 | for file, hunks in hunks_per_file_dct.items(): 347 | file_structure = extract_structure(file, repo_structure) 348 | full_patch_info[file] = analyze_hunks(hunks, file_structure) 349 | 350 | return full_patch_info 351 | 352 | def check(lines,i, indentation): 353 | if lines[i].startswith('- ') or lines[i].startswith('+ '): 354 | return indentation < len(lines[i].strip('+').strip('-')) - len(lines[i].strip('+').strip('-').lstrip()) 355 | elif lines[i].startswith('-') or lines[i].startswith('+'): 356 | return indentation <= len(lines[i].strip('+').strip('-')) - len(lines[i].strip('+').strip('-').lstrip()) 357 | 358 | return True 359 | 360 | def extract_changed_functions(patch_string, type = 'function'): 361 | # Regular expression to match function definitions 362 | if type == 'function': 363 | function_pattern = r'def\s+(\w+)\s*\(' 364 | else: 365 | class_pattern = r'class\s+(\w+)\s*\(' 366 | # Split the patch into lines 367 | lines = patch_string.split('\n') 368 | 369 | changed_functions = set() 370 | i = 0 371 | while i < len(lines): 372 | match = re.search(function_pattern, lines[i].strip('+').strip('-')) 373 | 374 | if match and lines[i].startswith('-'): 375 | changed_functions.add(match.group(1)) 376 | i += 1 377 | continue 378 | 379 | elif match and not lines[i].startswith('+'): 380 | indentation = len(lines[i]) - len(lines[i].lstrip()) 381 | i += 1 382 | while i < len(lines) and not re.search(function_pattern, lines[i].strip('+').strip('-')) and check(lines,i, indentation): 383 | if (lines[i].startswith('-') or lines[i].startswith('+')): 384 | changed_functions.add(match.group(1)) 385 | i += 1 386 | 387 | else: 388 | i += 1 389 | 390 | return changed_functions 391 | 392 | 393 | def find_py_or_non_dict_with_path(d, cond = False): 394 | results = {} 395 | stack = [(d, [])] 396 | 397 | while stack: 398 | current_dict, path = stack.pop() 399 | 400 | for key, value in current_dict.items(): 401 | current_path = path + [key] 402 | 403 | if key.endswith('.py'): 404 | if ('test' not in key.lower() and (('test' not in '/'.join(current_path).lower()) or cond)): 405 | file_path = '/'.join(current_path) 406 | 407 | for fun in value['functions']: 408 | func_path = f"{file_path}/{fun['name']}" 409 | results[func_path] = f'{func_path}\n' + '\n'.join(fun['text']) 410 | 411 | for clas in value['classes']: 412 | for fun in clas['methods']: 413 | func_path = f"{file_path}/{clas['name']}/{fun['name']}" 414 | results[func_path] = f'{func_path}\n' + f'class {clas["name"]}:' + '\n'.join(fun['text']) 415 | 416 | elif isinstance(value, dict): 417 | stack.append((value, current_path)) 418 | 419 | return results 420 | 421 | 422 | 423 | 424 | def search_errored_funcs(d, file_name, class_name, func_name, line_number): 425 | errored_function = func_name if func_name else None 426 | errored_class = class_name if class_name else None 427 | 428 | stack = [(d, [])] 429 | 430 | while stack and not (errored_function and errored_class): 431 | current_dict, path = stack.pop() 432 | 433 | for key, value in current_dict.items(): 434 | current_path = path + [key] 435 | 436 | 437 | if key.endswith('.py') and 'test' not in key.lower() and 'test' not in '/'.join(current_path).lower() and (key in file_name if file_name != '' else True): 438 | file_path = '/'.join(current_path) 439 | 440 | for fun in value['functions']: 441 | if line_number != '' and fun['start_line'] <= line_number <= fun['end_line']: 442 | errored_function = f"{file_path}/{fun['name']}" 443 | 444 | if errored_function: 445 | break 446 | 447 | 448 | 449 | for clas in value['classes']: 450 | if line_number != '' and fun['start_line'] <= line_number <= fun['end_line']: 451 | errored_class = f"{file_path}/{clas['name']}" 452 | 453 | for fun in clas['methods']: 454 | if line_number != '' and fun['start_line'] <= line_number <= fun['end_line']: 455 | errored_function = f"{file_path}/{clas['name']}/{fun['name']}" 456 | 457 | if errored_function: 458 | break 459 | 460 | if errored_class: 461 | break 462 | 463 | 464 | elif isinstance(value, dict): 465 | stack.append((value, current_path)) 466 | 467 | return errored_function, errored_class -------------------------------------------------------------------------------- /src/get_repo_structure/get_repo_structure.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import ast 3 | import json 4 | import os 5 | import subprocess 6 | import uuid 7 | 8 | import pandas as pd 9 | from tqdm import tqdm 10 | 11 | repo_to_top_folder = { 12 | "django/django": "django", 13 | "sphinx-doc/sphinx": "sphinx", 14 | "scikit-learn/scikit-learn": "scikit-learn", 15 | "sympy/sympy": "sympy", 16 | "pytest-dev/pytest": "pytest", 17 | "matplotlib/matplotlib": "matplotlib", 18 | "astropy/astropy": "astropy", 19 | "pydata/xarray": "xarray", 20 | "mwaskom/seaborn": "seaborn", 21 | "psf/requests": "requests", 22 | "pylint-dev/pylint": "pylint", 23 | "pallets/flask": "flask", 24 | "sqlfluff/sqlfluff": "sqlfluff", 25 | "marshmallow-code/marshmallow": "marshmallow", 26 | 'pvlib/pvlib-python': 'pvlib-python', 27 | 'pylint-dev/astroid': 'astroid', 28 | 'pyvista/pyvista': 'pyvista', 29 | 'pydicom/pydicom': 'pydicom' 30 | } 31 | 32 | 33 | def checkout_commit(repo_path, commit_id): 34 | """Checkout the specified commit in the given local git repository. 35 | :param repo_path: Path to the local git repository 36 | :param commit_id: Commit ID to checkout 37 | :return: None 38 | """ 39 | try: 40 | # Change directory to the provided repository path and checkout the specified commit 41 | print(f"Checking out commit {commit_id} in repository at {repo_path}...") 42 | subprocess.run(["git", "-C", repo_path, "checkout", commit_id], check=True) 43 | print("Commit checked out successfully.") 44 | except subprocess.CalledProcessError as e: 45 | print(f"An error occurred while running git command: {e}") 46 | except Exception as e: 47 | print(f"An unexpected error occurred: {e}") 48 | 49 | 50 | def clone_repo(repo_name, repo_playground): 51 | try: 52 | 53 | print( 54 | f"Cloning repository from https://github.com/{repo_name}.git to {repo_playground}/{repo_to_top_folder[repo_name]}..." 55 | ) 56 | subprocess.run( 57 | [ 58 | "git", 59 | "clone", 60 | f"https://github.com/{repo_name}.git", 61 | f"{repo_playground}/{repo_to_top_folder[repo_name]}", 62 | ], 63 | check=True, 64 | ) 65 | print("Repository cloned successfully.") 66 | except subprocess.CalledProcessError as e: 67 | print(f"An error occurred while running git command: {e}") 68 | except Exception as e: 69 | print(f"An unexpected error occurred: {e}") 70 | 71 | 72 | def get_project_structure_from_scratch( 73 | repo_name, commit_id, instance_id, repo_playground 74 | ): 75 | 76 | # Generate a temperary folder and add uuid to avoid collision 77 | repo_playground = os.path.join(repo_playground, str(uuid.uuid4())) 78 | 79 | # assert playground doesn't exist 80 | assert not os.path.exists(repo_playground), f"{repo_playground} already exists" 81 | 82 | # create playground 83 | os.makedirs(repo_playground) 84 | 85 | clone_repo(repo_name, repo_playground) 86 | checkout_commit(f"{repo_playground}/{repo_to_top_folder[repo_name]}", commit_id) 87 | structure = create_structure(f"{repo_playground}/{repo_to_top_folder[repo_name]}") 88 | # clean up 89 | subprocess.run( 90 | ["rm", "-rf", f"{repo_playground}/{repo_to_top_folder[repo_name]}"], check=True 91 | ) 92 | d = { 93 | "repo": repo_name, 94 | "base_commit": commit_id, 95 | "structure": structure, 96 | "instance_id": instance_id, 97 | } 98 | return d 99 | 100 | 101 | 102 | def parse_python_file(file_path, file_content=None): 103 | """Parse a Python file to extract class and function definitions with their line numbers. 104 | :param file_path: Path to the Python file. 105 | :return: Class names, function names, and file contents 106 | """ 107 | if file_content is None: 108 | try: 109 | with open(file_path, "r") as file: 110 | file_content = file.read() 111 | parsed_data = ast.parse(file_content) 112 | except Exception as e: # Catch all types of exceptions 113 | print(f"Error in file {file_path}: {e}") 114 | return [], [], "" 115 | else: 116 | try: 117 | parsed_data = ast.parse(file_content) 118 | except Exception as e: # Catch all types of exceptions 119 | print(f"Error in file {file_path}: {e}") 120 | return [], [], "" 121 | 122 | class_info = [] 123 | function_names = [] 124 | class_methods = set() 125 | 126 | for node in ast.walk(parsed_data): 127 | if isinstance(node, ast.ClassDef): 128 | methods = [] 129 | for n in node.body: 130 | if isinstance(n, ast.FunctionDef): 131 | methods.append( 132 | { 133 | "name": n.name, 134 | "start_line": n.lineno, 135 | "end_line": n.end_lineno, 136 | "text": file_content.splitlines()[ 137 | n.lineno - 1 : n.end_lineno 138 | ], 139 | } 140 | ) 141 | class_methods.add(n.name) 142 | class_info.append( 143 | { 144 | "name": node.name, 145 | "start_line": node.lineno, 146 | "end_line": node.end_lineno, 147 | "text": file_content.splitlines()[ 148 | node.lineno - 1 : node.end_lineno 149 | ], 150 | "methods": methods, 151 | } 152 | ) 153 | elif isinstance(node, ast.FunctionDef) and not isinstance( 154 | node, ast.AsyncFunctionDef 155 | ): 156 | if node.name not in class_methods: 157 | function_names.append( 158 | { 159 | "name": node.name, 160 | "start_line": node.lineno, 161 | "end_line": node.end_lineno, 162 | "text": file_content.splitlines()[ 163 | node.lineno - 1 : node.end_lineno 164 | ], 165 | } 166 | ) 167 | 168 | return class_info, function_names, file_content.splitlines() 169 | 170 | 171 | def create_structure(directory_path): 172 | """Create the structure of the repository directory by parsing Python files. 173 | :param directory_path: Path to the repository directory. 174 | :return: A dictionary representing the structure. 175 | """ 176 | structure = {} 177 | 178 | for root, _, files in os.walk(directory_path): 179 | repo_name = os.path.basename(directory_path) 180 | relative_root = os.path.relpath(root, directory_path) 181 | if relative_root == ".": 182 | relative_root = repo_name 183 | curr_struct = structure 184 | for part in relative_root.split(os.sep): 185 | if part not in curr_struct: 186 | curr_struct[part] = {} 187 | curr_struct = curr_struct[part] 188 | for file_name in files: 189 | if file_name.endswith(".py"): 190 | file_path = os.path.join(root, file_name) 191 | class_info, function_names, file_lines = parse_python_file(file_path) 192 | curr_struct[file_name] = { 193 | "classes": class_info, 194 | "functions": function_names, 195 | "text": file_lines, 196 | } 197 | else: 198 | curr_struct[file_name] = {} 199 | 200 | return structure 201 | -------------------------------------------------------------------------------- /src/rerank.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import argparse 4 | import subprocess 5 | from pathlib import Path 6 | 7 | def evaluate_results(eval_dir, dataset_name, qrels_path, results_path): 8 | """ 9 | Evaluate reranking results using MRR@k metrics 10 | """ 11 | # Load qrels 12 | with open(qrels_path) as f: 13 | qrels = {} 14 | for i, line in enumerate(f): 15 | if i == 0 and line.lower().startswith("query-id"): 16 | continue 17 | 18 | qid, docid, score = line.strip().split("\t") 19 | if qid not in qrels: 20 | qrels[qid] = {} 21 | qrels[qid][docid] = int(score) 22 | 23 | # Load results 24 | with open(results_path) as f: 25 | results = json.load(f) 26 | 27 | # Calculate MRR@k for different k values 28 | metrics = [1, 3, 5, 10, 20, 100] 29 | mrr_at_k = {} 30 | 31 | for k in metrics: 32 | mrr_sum = 0.0 33 | num_queries = 0 34 | 35 | for qid in qrels: 36 | if qid in results: 37 | sorted_docs = sorted(results[qid].items(), key=lambda x: x[1], reverse=True)[:k] 38 | 39 | for rank, (doc_id, _) in enumerate(sorted_docs, start=1): 40 | if doc_id in qrels[qid] and qrels[qid][doc_id] > 0: 41 | mrr_sum += 1.0 / rank 42 | break 43 | num_queries += 1 44 | 45 | mrr = mrr_sum / num_queries if num_queries > 0 else 0.0 46 | mrr_at_k[k] = mrr 47 | 48 | # Save evaluation results 49 | os.makedirs(os.path.join(eval_dir, "eval_results"), exist_ok=True) 50 | eval_path = os.path.join(eval_dir, "eval_results", f"{dataset_name}_eval.json") 51 | with open(eval_path, "w") as f: 52 | json.dump(mrr_at_k, f, indent=4) 53 | 54 | return mrr_at_k 55 | 56 | def run_convert_and_rerank(args): 57 | """ 58 | First convert results and then run the reranker on retriever outputs. 59 | The retriever stores datasets in BEIR format at: 60 | - CSN: {args.dataset_dir}/code_datasets/csn_{lang} 61 | - SWE-bench: {args.dataset_dir}/swe-bench-lite-function_{instance_id} 62 | """ 63 | reranker_path = os.path.join(os.path.dirname(__file__), "..", "llm-reranker") 64 | convert_script = os.path.join(reranker_path, "scripts", "convert_results.py") 65 | rerank_script = os.path.join(reranker_path, "scripts", "rerank_llm.py") 66 | 67 | os.makedirs(args.output_dir, exist_ok=True) 68 | os.makedirs(args.eval_dir, exist_ok=True) 69 | 70 | code_datasets_dir = os.path.join(args.dataset_dir, "code_datasets") 71 | if os.path.exists(code_datasets_dir): 72 | # datasets = os.listdir(code_datasets_dir) 73 | datasets = ["csn_ruby"] 74 | else: 75 | datasets = [] 76 | 77 | if os.path.exists(args.dataset_dir): 78 | datasets.extend([d for d in os.listdir(args.dataset_dir) if d.startswith("swe-bench-lite-function_")]) 79 | for dataset_name in datasets: 80 | # Determine dataset type and instance ID 81 | if dataset_name.startswith("csn_"): 82 | lang = dataset_name.split("_")[1] 83 | instance_id = None 84 | data_type = "codedataset" 85 | prompt_type = "docstring" 86 | dataset_path = os.path.join(code_datasets_dir, dataset_name) 87 | elif dataset_name.startswith("swe-bench-lite-function_"): 88 | instance_id = dataset_name.split("_")[-1] 89 | data_type = "codedataset" 90 | prompt_type = "github_issue" 91 | dataset_path = os.path.join(args.dataset_dir, dataset_name) 92 | else: 93 | continue 94 | 95 | if not os.path.isdir(dataset_path): 96 | continue 97 | 98 | # First convert results 99 | print(f"Converting results for {dataset_name}...") 100 | convert_cmd = [ 101 | "python", convert_script, 102 | "--dataset", dataset_name, 103 | "--output_dir", args.output_dir, 104 | "--data_type", data_type, 105 | "--data_dir", args.dataset_dir if dataset_name.startswith("swe-bench") else code_datasets_dir, 106 | "--top_k", str(args.top_k), 107 | "--rerank_type", "code" 108 | ] 109 | 110 | try: 111 | subprocess.run(convert_cmd, check=True) 112 | print(f"Successfully converted {dataset_name}") 113 | except subprocess.CalledProcessError as e: 114 | print(f"Failed to convert {dataset_name}: {e}") 115 | continue 116 | 117 | # Then run reranker 118 | print(f"Running reranker on {dataset_name}...") 119 | rerank_cmd = [ 120 | "python", rerank_script, 121 | "--model", "cornstack/CodeRankLLM", 122 | "--dataset", dataset_name, 123 | "--output_dir", args.output_dir, 124 | "--data_type", data_type, 125 | "--data_dir", args.dataset_dir if dataset_name.startswith("swe-bench") else code_datasets_dir, 126 | "--use_logits", "0", 127 | "--use_alpha", "0", 128 | "--llm_top_k", str(args.top_k), 129 | "--window_size", str(args.window_size), 130 | "--step_size", str(args.step_size), 131 | "--do_batched", "1", 132 | "--rerank_type", "code", 133 | "--code_prompt_type", prompt_type 134 | ] 135 | 136 | try: 137 | subprocess.run(rerank_cmd, check=True) 138 | print(f"Successfully reranked {dataset_name}") 139 | 140 | # Evaluate results 141 | print(f"Evaluating results for {dataset_name}...") 142 | qrels_path = os.path.join(dataset_path, "qrels", "test.tsv") 143 | results_path = os.path.join(args.output_dir, "code_datasets", dataset_name, f"rerank_{args.top_k}_llm_gen_num.json") 144 | 145 | mrr_at_k = evaluate_results(args.eval_dir, dataset_name, qrels_path, results_path) 146 | print(f"Evaluation results for {dataset_name}:") 147 | for k, mrr in mrr_at_k.items(): 148 | print(f"MRR@{k}: {mrr:.4f}") 149 | 150 | except subprocess.CalledProcessError as e: 151 | print(f"Failed to rerank {dataset_name}: {e}") 152 | continue 153 | 154 | def main(): 155 | parser = argparse.ArgumentParser() 156 | parser.add_argument("--dataset_dir", type=str, required=True, 157 | help="Directory containing retriever outputs in BEIR format") 158 | parser.add_argument("--output_dir", type=str, required=True, 159 | help="Directory to store reranker outputs") 160 | parser.add_argument("--eval_dir", type=str, required=True, 161 | help="Directory to store evaluation results") 162 | parser.add_argument("--top_k", type=int, default=100, 163 | help="Number of candidates to rerank") 164 | parser.add_argument("--window_size", type=int, default=10, 165 | help="Window size for reranking") 166 | parser.add_argument("--step_size", type=int, default=5, 167 | help="Step size for reranking") 168 | args = parser.parse_args() 169 | 170 | run_convert_and_rerank(args) 171 | 172 | if __name__ == "__main__": 173 | main() -------------------------------------------------------------------------------- /src/run_pipeline.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export REPO_DIR="$(pwd)" 4 | export DATASET_DIR="${REPO_DIR}/datasets" 5 | export OUTPUT_DIR="${REPO_DIR}/outputs" 6 | export EVAL_DIR="${REPO_DIR}/evaluations" 7 | 8 | # Default reranking parameters 9 | TOP_K=100 10 | WINDOW_SIZE=10 11 | STEP_SIZE=5 12 | SKIP_RETRIEVER=1 13 | 14 | while [[ $# -gt 0 ]]; do 15 | case $1 in 16 | --dataset_dir) 17 | DATASET_DIR="$2" 18 | shift 2 19 | ;; 20 | --output_dir) 21 | OUTPUT_DIR="$2" 22 | shift 2 23 | ;; 24 | --eval_dir) 25 | EVAL_DIR="$2" 26 | shift 2 27 | ;; 28 | --top_k) 29 | TOP_K="$2" 30 | shift 2 31 | ;; 32 | --window_size) 33 | WINDOW_SIZE="$2" 34 | shift 2 35 | ;; 36 | --step_size) 37 | STEP_SIZE="$2" 38 | shift 2 39 | ;; 40 | --skip_retriever) 41 | SKIP_RETRIEVER=1 42 | shift 43 | ;; 44 | *) 45 | echo "Unknown argument: $1" 46 | exit 1 47 | ;; 48 | esac 49 | done 50 | 51 | mkdir -p "${DATASET_DIR}" 52 | mkdir -p "${OUTPUT_DIR}" 53 | mkdir -p "${EVAL_DIR}" 54 | 55 | if [ "${SKIP_RETRIEVER}" -eq 0 ]; then 56 | echo "Running CSN retriever..." 57 | python create/csn.py \ 58 | --dataset_dir "${DATASET_DIR}" 59 | 60 | # Run retrieval evaluation to generate rank files 61 | echo "Running retrieval evaluation..." 62 | python evaluations/eval_csn.py \ 63 | --device "cuda" \ 64 | --dataset_dir "${DATASET_DIR}" \ 65 | --output_dir "${OUTPUT_DIR}" \ 66 | --batch_size 64 67 | 68 | # # Run SWE-bench retriever 69 | # echo "Running SWE-bench retriever..." 70 | # python src/create/swebench.py \ 71 | # --dataset_dir "${DATASET_DIR}" \ 72 | # --dataset_name "princeton-nlp/SWE-bench_Lite" \ 73 | # --split "test" \ 74 | # --level "function" 75 | else 76 | echo "Skipping retriever step..." 77 | if [ ! -d "${DATASET_DIR}" ]; then 78 | echo "Error: Dataset directory ${DATASET_DIR} does not exist!" 79 | echo "Please provide a valid dataset directory when skipping retriever step." 80 | exit 1 81 | fi 82 | fi 83 | 84 | # Run the reranker (includes conversion step) 85 | echo "Running reranker..." 86 | python rerank.py \ 87 | --dataset_dir "${DATASET_DIR}" \ 88 | --output_dir "${OUTPUT_DIR}" \ 89 | --eval_dir "${EVAL_DIR}" \ 90 | --top_k "${TOP_K}" \ 91 | --window_size "${WINDOW_SIZE}" \ 92 | --step_size "${STEP_SIZE}" 93 | 94 | echo "Pipeline completed! Results are in:" 95 | echo "- Datasets: ${DATASET_DIR}" 96 | echo "- Reranking outputs: ${OUTPUT_DIR}" 97 | echo "- Evaluation results: ${EVAL_DIR}" -------------------------------------------------------------------------------- /static/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gangiswag/cornstack/6432dfde69400892000bb2dabdb90fbc3b239f20/static/.DS_Store -------------------------------------------------------------------------------- /static/css/bulma-carousel.min.css: -------------------------------------------------------------------------------- 1 | @-webkit-keyframes spinAround{from{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes spinAround{from{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.slider{position:relative;width:100%}.slider-container{display:flex;flex-wrap:nowrap;flex-direction:row;overflow:hidden;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);min-height:100%}.slider-container.is-vertical{flex-direction:column}.slider-container .slider-item{flex:none}.slider-container .slider-item .image.is-covered img{-o-object-fit:cover;object-fit:cover;-o-object-position:center center;object-position:center center;height:100%;width:100%}.slider-container .slider-item .video-container{height:0;padding-bottom:0;padding-top:56.25%;margin:0;position:relative}.slider-container .slider-item .video-container.is-1by1,.slider-container .slider-item .video-container.is-square{padding-top:100%}.slider-container .slider-item .video-container.is-4by3{padding-top:75%}.slider-container .slider-item .video-container.is-21by9{padding-top:42.857143%}.slider-container .slider-item .video-container embed,.slider-container .slider-item .video-container iframe,.slider-container .slider-item .video-container object{position:absolute;top:0;left:0;width:100%!important;height:100%!important}.slider-navigation-next,.slider-navigation-previous{display:flex;justify-content:center;align-items:center;position:absolute;width:42px;height:42px;background:#fff center center no-repeat;background-size:20px 20px;border:1px solid #fff;border-radius:25091983px;box-shadow:0 2px 5px #3232321a;top:50%;margin-top:-20px;left:0;cursor:pointer;transition:opacity .3s,-webkit-transform .3s;transition:transform .3s,opacity .3s;transition:transform .3s,opacity .3s,-webkit-transform .3s}.slider-navigation-next:hover,.slider-navigation-previous:hover{-webkit-transform:scale(1.2);transform:scale(1.2)}.slider-navigation-next.is-hidden,.slider-navigation-previous.is-hidden{display:none;opacity:0}.slider-navigation-next svg,.slider-navigation-previous svg{width:25%}.slider-navigation-next{left:auto;right:0;background:#fff center center no-repeat;background-size:20px 20px}.slider-pagination{display:none;justify-content:center;align-items:center;position:absolute;bottom:0;left:0;right:0;padding:.5rem 1rem;text-align:center}.slider-pagination .slider-page{background:#fff;width:10px;height:10px;border-radius:25091983px;display:inline-block;margin:0 3px;box-shadow:0 2px 5px #3232321a;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;cursor:pointer}.slider-pagination .slider-page.is-active,.slider-pagination .slider-page:hover{-webkit-transform:scale(1.4);transform:scale(1.4)}@media screen and (min-width:800px){.slider-pagination{display:flex}}.hero.has-carousel{position:relative}.hero.has-carousel+.hero-body,.hero.has-carousel+.hero-footer,.hero.has-carousel+.hero-head{z-index:10;overflow:hidden}.hero.has-carousel .hero-carousel{position:absolute;top:0;left:0;bottom:0;right:0;height:auto;border:none;margin:auto;padding:0;z-index:0}.hero.has-carousel .hero-carousel .slider{width:100%;max-width:100%;overflow:hidden;height:100%!important;max-height:100%;z-index:0}.hero.has-carousel .hero-carousel .slider .has-background{max-height:100%}.hero.has-carousel .hero-carousel .slider .has-background .is-background{-o-object-fit:cover;object-fit:cover;-o-object-position:center center;object-position:center center;height:100%;width:100%}.hero.has-carousel .hero-body{margin:0 3rem;z-index:10} -------------------------------------------------------------------------------- /static/css/bulma-slider.min.css: -------------------------------------------------------------------------------- 1 | @-webkit-keyframes spinAround{from{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes spinAround{from{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}input[type=range].slider{-webkit-appearance:none;-moz-appearance:none;appearance:none;margin:1rem 0;background:0 0;touch-action:none}input[type=range].slider.is-fullwidth{display:block;width:100%}input[type=range].slider:focus{outline:0}input[type=range].slider:not([orient=vertical])::-webkit-slider-runnable-track{width:100%}input[type=range].slider:not([orient=vertical])::-moz-range-track{width:100%}input[type=range].slider:not([orient=vertical])::-ms-track{width:100%}input[type=range].slider:not([orient=vertical]).has-output+output,input[type=range].slider:not([orient=vertical]).has-output-tooltip+output{width:3rem;background:#4a4a4a;border-radius:4px;padding:.4rem .8rem;font-size:.75rem;line-height:.75rem;text-align:center;text-overflow:ellipsis;white-space:nowrap;color:#fff;overflow:hidden;pointer-events:none;z-index:200}input[type=range].slider:not([orient=vertical]).has-output-tooltip:disabled+output,input[type=range].slider:not([orient=vertical]).has-output:disabled+output{opacity:.5}input[type=range].slider:not([orient=vertical]).has-output{display:inline-block;vertical-align:middle;width:calc(100% - (4.2rem))}input[type=range].slider:not([orient=vertical]).has-output+output{display:inline-block;margin-left:.75rem;vertical-align:middle}input[type=range].slider:not([orient=vertical]).has-output-tooltip{display:block}input[type=range].slider:not([orient=vertical]).has-output-tooltip+output{position:absolute;left:0;top:-.1rem}input[type=range].slider[orient=vertical]{-webkit-appearance:slider-vertical;-moz-appearance:slider-vertical;appearance:slider-vertical;-webkit-writing-mode:bt-lr;-ms-writing-mode:bt-lr;writing-mode:bt-lr}input[type=range].slider[orient=vertical]::-webkit-slider-runnable-track{height:100%}input[type=range].slider[orient=vertical]::-moz-range-track{height:100%}input[type=range].slider[orient=vertical]::-ms-track{height:100%}input[type=range].slider::-webkit-slider-runnable-track{cursor:pointer;animate:.2s;box-shadow:0 0 0 #7a7a7a;background:#dbdbdb;border-radius:4px;border:0 solid #7a7a7a}input[type=range].slider::-moz-range-track{cursor:pointer;animate:.2s;box-shadow:0 0 0 #7a7a7a;background:#dbdbdb;border-radius:4px;border:0 solid #7a7a7a}input[type=range].slider::-ms-track{cursor:pointer;animate:.2s;box-shadow:0 0 0 #7a7a7a;background:#dbdbdb;border-radius:4px;border:0 solid #7a7a7a}input[type=range].slider::-ms-fill-lower{background:#dbdbdb;border-radius:4px}input[type=range].slider::-ms-fill-upper{background:#dbdbdb;border-radius:4px}input[type=range].slider::-webkit-slider-thumb{box-shadow:none;border:1px solid #b5b5b5;border-radius:4px;background:#fff;cursor:pointer}input[type=range].slider::-moz-range-thumb{box-shadow:none;border:1px solid #b5b5b5;border-radius:4px;background:#fff;cursor:pointer}input[type=range].slider::-ms-thumb{box-shadow:none;border:1px solid #b5b5b5;border-radius:4px;background:#fff;cursor:pointer}input[type=range].slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none}input[type=range].slider.is-circle::-webkit-slider-thumb{border-radius:290486px}input[type=range].slider.is-circle::-moz-range-thumb{border-radius:290486px}input[type=range].slider.is-circle::-ms-thumb{border-radius:290486px}input[type=range].slider:active::-webkit-slider-thumb{-webkit-transform:scale(1.25);transform:scale(1.25)}input[type=range].slider:active::-moz-range-thumb{transform:scale(1.25)}input[type=range].slider:active::-ms-thumb{transform:scale(1.25)}input[type=range].slider:disabled{opacity:.5;cursor:not-allowed}input[type=range].slider:disabled::-webkit-slider-thumb{cursor:not-allowed;-webkit-transform:scale(1);transform:scale(1)}input[type=range].slider:disabled::-moz-range-thumb{cursor:not-allowed;transform:scale(1)}input[type=range].slider:disabled::-ms-thumb{cursor:not-allowed;transform:scale(1)}input[type=range].slider:not([orient=vertical]){min-height:calc((1rem + 2px) * 1.25)}input[type=range].slider:not([orient=vertical])::-webkit-slider-runnable-track{height:.5rem}input[type=range].slider:not([orient=vertical])::-moz-range-track{height:.5rem}input[type=range].slider:not([orient=vertical])::-ms-track{height:.5rem}input[type=range].slider[orient=vertical]::-webkit-slider-runnable-track{width:.5rem}input[type=range].slider[orient=vertical]::-moz-range-track{width:.5rem}input[type=range].slider[orient=vertical]::-ms-track{width:.5rem}input[type=range].slider::-webkit-slider-thumb{height:1rem;width:1rem}input[type=range].slider::-moz-range-thumb{height:1rem;width:1rem}input[type=range].slider::-ms-thumb{height:1rem;width:1rem}input[type=range].slider::-ms-thumb{margin-top:0}input[type=range].slider::-webkit-slider-thumb{margin-top:-.25rem}input[type=range].slider[orient=vertical]::-webkit-slider-thumb{margin-top:auto;margin-left:-.25rem}input[type=range].slider.is-small:not([orient=vertical]){min-height:calc((.75rem + 2px) * 1.25)}input[type=range].slider.is-small:not([orient=vertical])::-webkit-slider-runnable-track{height:.375rem}input[type=range].slider.is-small:not([orient=vertical])::-moz-range-track{height:.375rem}input[type=range].slider.is-small:not([orient=vertical])::-ms-track{height:.375rem}input[type=range].slider.is-small[orient=vertical]::-webkit-slider-runnable-track{width:.375rem}input[type=range].slider.is-small[orient=vertical]::-moz-range-track{width:.375rem}input[type=range].slider.is-small[orient=vertical]::-ms-track{width:.375rem}input[type=range].slider.is-small::-webkit-slider-thumb{height:.75rem;width:.75rem}input[type=range].slider.is-small::-moz-range-thumb{height:.75rem;width:.75rem}input[type=range].slider.is-small::-ms-thumb{height:.75rem;width:.75rem}input[type=range].slider.is-small::-ms-thumb{margin-top:0}input[type=range].slider.is-small::-webkit-slider-thumb{margin-top:-.1875rem}input[type=range].slider.is-small[orient=vertical]::-webkit-slider-thumb{margin-top:auto;margin-left:-.1875rem}input[type=range].slider.is-medium:not([orient=vertical]){min-height:calc((1.25rem + 2px) * 1.25)}input[type=range].slider.is-medium:not([orient=vertical])::-webkit-slider-runnable-track{height:.625rem}input[type=range].slider.is-medium:not([orient=vertical])::-moz-range-track{height:.625rem}input[type=range].slider.is-medium:not([orient=vertical])::-ms-track{height:.625rem}input[type=range].slider.is-medium[orient=vertical]::-webkit-slider-runnable-track{width:.625rem}input[type=range].slider.is-medium[orient=vertical]::-moz-range-track{width:.625rem}input[type=range].slider.is-medium[orient=vertical]::-ms-track{width:.625rem}input[type=range].slider.is-medium::-webkit-slider-thumb{height:1.25rem;width:1.25rem}input[type=range].slider.is-medium::-moz-range-thumb{height:1.25rem;width:1.25rem}input[type=range].slider.is-medium::-ms-thumb{height:1.25rem;width:1.25rem}input[type=range].slider.is-medium::-ms-thumb{margin-top:0}input[type=range].slider.is-medium::-webkit-slider-thumb{margin-top:-.3125rem}input[type=range].slider.is-medium[orient=vertical]::-webkit-slider-thumb{margin-top:auto;margin-left:-.3125rem}input[type=range].slider.is-large:not([orient=vertical]){min-height:calc((1.5rem + 2px) * 1.25)}input[type=range].slider.is-large:not([orient=vertical])::-webkit-slider-runnable-track{height:.75rem}input[type=range].slider.is-large:not([orient=vertical])::-moz-range-track{height:.75rem}input[type=range].slider.is-large:not([orient=vertical])::-ms-track{height:.75rem}input[type=range].slider.is-large[orient=vertical]::-webkit-slider-runnable-track{width:.75rem}input[type=range].slider.is-large[orient=vertical]::-moz-range-track{width:.75rem}input[type=range].slider.is-large[orient=vertical]::-ms-track{width:.75rem}input[type=range].slider.is-large::-webkit-slider-thumb{height:1.5rem;width:1.5rem}input[type=range].slider.is-large::-moz-range-thumb{height:1.5rem;width:1.5rem}input[type=range].slider.is-large::-ms-thumb{height:1.5rem;width:1.5rem}input[type=range].slider.is-large::-ms-thumb{margin-top:0}input[type=range].slider.is-large::-webkit-slider-thumb{margin-top:-.375rem}input[type=range].slider.is-large[orient=vertical]::-webkit-slider-thumb{margin-top:auto;margin-left:-.375rem}input[type=range].slider.is-white::-moz-range-track{background:#fff!important}input[type=range].slider.is-white::-webkit-slider-runnable-track{background:#fff!important}input[type=range].slider.is-white::-ms-track{background:#fff!important}input[type=range].slider.is-white::-ms-fill-lower{background:#fff}input[type=range].slider.is-white::-ms-fill-upper{background:#fff}input[type=range].slider.is-white .has-output-tooltip+output,input[type=range].slider.is-white.has-output+output{background-color:#fff;color:#0a0a0a}input[type=range].slider.is-black::-moz-range-track{background:#0a0a0a!important}input[type=range].slider.is-black::-webkit-slider-runnable-track{background:#0a0a0a!important}input[type=range].slider.is-black::-ms-track{background:#0a0a0a!important}input[type=range].slider.is-black::-ms-fill-lower{background:#0a0a0a}input[type=range].slider.is-black::-ms-fill-upper{background:#0a0a0a}input[type=range].slider.is-black .has-output-tooltip+output,input[type=range].slider.is-black.has-output+output{background-color:#0a0a0a;color:#fff}input[type=range].slider.is-light::-moz-range-track{background:#f5f5f5!important}input[type=range].slider.is-light::-webkit-slider-runnable-track{background:#f5f5f5!important}input[type=range].slider.is-light::-ms-track{background:#f5f5f5!important}input[type=range].slider.is-light::-ms-fill-lower{background:#f5f5f5}input[type=range].slider.is-light::-ms-fill-upper{background:#f5f5f5}input[type=range].slider.is-light .has-output-tooltip+output,input[type=range].slider.is-light.has-output+output{background-color:#f5f5f5;color:#363636}input[type=range].slider.is-dark::-moz-range-track{background:#363636!important}input[type=range].slider.is-dark::-webkit-slider-runnable-track{background:#363636!important}input[type=range].slider.is-dark::-ms-track{background:#363636!important}input[type=range].slider.is-dark::-ms-fill-lower{background:#363636}input[type=range].slider.is-dark::-ms-fill-upper{background:#363636}input[type=range].slider.is-dark .has-output-tooltip+output,input[type=range].slider.is-dark.has-output+output{background-color:#363636;color:#f5f5f5}input[type=range].slider.is-primary::-moz-range-track{background:#00d1b2!important}input[type=range].slider.is-primary::-webkit-slider-runnable-track{background:#00d1b2!important}input[type=range].slider.is-primary::-ms-track{background:#00d1b2!important}input[type=range].slider.is-primary::-ms-fill-lower{background:#00d1b2}input[type=range].slider.is-primary::-ms-fill-upper{background:#00d1b2}input[type=range].slider.is-primary .has-output-tooltip+output,input[type=range].slider.is-primary.has-output+output{background-color:#00d1b2;color:#fff}input[type=range].slider.is-link::-moz-range-track{background:#3273dc!important}input[type=range].slider.is-link::-webkit-slider-runnable-track{background:#3273dc!important}input[type=range].slider.is-link::-ms-track{background:#3273dc!important}input[type=range].slider.is-link::-ms-fill-lower{background:#3273dc}input[type=range].slider.is-link::-ms-fill-upper{background:#3273dc}input[type=range].slider.is-link .has-output-tooltip+output,input[type=range].slider.is-link.has-output+output{background-color:#3273dc;color:#fff}input[type=range].slider.is-info::-moz-range-track{background:#209cee!important}input[type=range].slider.is-info::-webkit-slider-runnable-track{background:#209cee!important}input[type=range].slider.is-info::-ms-track{background:#209cee!important}input[type=range].slider.is-info::-ms-fill-lower{background:#209cee}input[type=range].slider.is-info::-ms-fill-upper{background:#209cee}input[type=range].slider.is-info .has-output-tooltip+output,input[type=range].slider.is-info.has-output+output{background-color:#209cee;color:#fff}input[type=range].slider.is-success::-moz-range-track{background:#23d160!important}input[type=range].slider.is-success::-webkit-slider-runnable-track{background:#23d160!important}input[type=range].slider.is-success::-ms-track{background:#23d160!important}input[type=range].slider.is-success::-ms-fill-lower{background:#23d160}input[type=range].slider.is-success::-ms-fill-upper{background:#23d160}input[type=range].slider.is-success .has-output-tooltip+output,input[type=range].slider.is-success.has-output+output{background-color:#23d160;color:#fff}input[type=range].slider.is-warning::-moz-range-track{background:#ffdd57!important}input[type=range].slider.is-warning::-webkit-slider-runnable-track{background:#ffdd57!important}input[type=range].slider.is-warning::-ms-track{background:#ffdd57!important}input[type=range].slider.is-warning::-ms-fill-lower{background:#ffdd57}input[type=range].slider.is-warning::-ms-fill-upper{background:#ffdd57}input[type=range].slider.is-warning .has-output-tooltip+output,input[type=range].slider.is-warning.has-output+output{background-color:#ffdd57;color:rgba(0,0,0,.7)}input[type=range].slider.is-danger::-moz-range-track{background:#ff3860!important}input[type=range].slider.is-danger::-webkit-slider-runnable-track{background:#ff3860!important}input[type=range].slider.is-danger::-ms-track{background:#ff3860!important}input[type=range].slider.is-danger::-ms-fill-lower{background:#ff3860}input[type=range].slider.is-danger::-ms-fill-upper{background:#ff3860}input[type=range].slider.is-danger .has-output-tooltip+output,input[type=range].slider.is-danger.has-output+output{background-color:#ff3860;color:#fff} -------------------------------------------------------------------------------- /static/css/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: 'Noto Sans', sans-serif; 3 | } 4 | 5 | 6 | .footer .icon-link { 7 | font-size: 25px; 8 | color: #000; 9 | } 10 | 11 | .link-block a { 12 | margin-top: 5px; 13 | margin-bottom: 5px; 14 | } 15 | 16 | .dnerf { 17 | font-variant: small-caps; 18 | } 19 | 20 | 21 | .teaser .hero-body { 22 | padding-top: 0; 23 | padding-bottom: 3rem; 24 | } 25 | 26 | .teaser { 27 | font-family: 'Google Sans', sans-serif; 28 | } 29 | 30 | 31 | .publication-title { 32 | } 33 | 34 | .publication-banner { 35 | max-height: parent; 36 | 37 | } 38 | 39 | .publication-banner video { 40 | position: relative; 41 | left: auto; 42 | top: auto; 43 | transform: none; 44 | object-fit: fit; 45 | } 46 | 47 | .publication-header .hero-body { 48 | } 49 | 50 | .publication-title { 51 | font-family: 'Google Sans', sans-serif; 52 | } 53 | 54 | .publication-authors { 55 | font-family: 'Google Sans', sans-serif; 56 | } 57 | 58 | .publication-venue { 59 | color: #555; 60 | width: fit-content; 61 | font-weight: bold; 62 | } 63 | 64 | .publication-awards { 65 | color: #ff3860; 66 | width: fit-content; 67 | font-weight: bolder; 68 | } 69 | 70 | .publication-authors { 71 | } 72 | 73 | .publication-authors a { 74 | color: hsl(204, 86%, 53%) !important; 75 | } 76 | 77 | .publication-authors a:hover { 78 | text-decoration: underline; 79 | } 80 | 81 | .author-block { 82 | display: inline-block; 83 | } 84 | 85 | .publication-banner img { 86 | } 87 | 88 | .publication-authors { 89 | /*color: #4286f4;*/ 90 | } 91 | 92 | .publication-video { 93 | position: relative; 94 | width: 100%; 95 | height: 0; 96 | padding-bottom: 56.25%; 97 | 98 | overflow: hidden; 99 | border-radius: 10px !important; 100 | } 101 | 102 | .publication-video iframe { 103 | position: absolute; 104 | top: 0; 105 | left: 0; 106 | width: 100%; 107 | height: 100%; 108 | } 109 | 110 | .publication-body img { 111 | } 112 | 113 | .results-carousel { 114 | overflow: hidden; 115 | } 116 | 117 | .results-carousel .item { 118 | margin: 5px; 119 | overflow: hidden; 120 | border: 1px solid #bbb; 121 | border-radius: 10px; 122 | padding: 0; 123 | font-size: 0; 124 | } 125 | 126 | .results-carousel video { 127 | margin: 0; 128 | } 129 | 130 | 131 | .interpolation-panel { 132 | background: #f5f5f5; 133 | border-radius: 10px; 134 | } 135 | 136 | .interpolation-panel .interpolation-image { 137 | width: 100%; 138 | border-radius: 5px; 139 | } 140 | 141 | .interpolation-video-column { 142 | } 143 | 144 | .interpolation-panel .slider { 145 | margin: 0 !important; 146 | } 147 | 148 | .interpolation-panel .slider { 149 | margin: 0 !important; 150 | } 151 | 152 | #interpolation-image-wrapper { 153 | width: 100%; 154 | } 155 | #interpolation-image-wrapper img { 156 | border-radius: 5px; 157 | } 158 | -------------------------------------------------------------------------------- /static/images/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gangiswag/cornstack/6432dfde69400892000bb2dabdb90fbc3b239f20/static/images/.DS_Store -------------------------------------------------------------------------------- /static/images/coderankllm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gangiswag/cornstack/6432dfde69400892000bb2dabdb90fbc3b239f20/static/images/coderankllm.png -------------------------------------------------------------------------------- /static/images/codesearchnet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gangiswag/cornstack/6432dfde69400892000bb2dabdb90fbc3b239f20/static/images/codesearchnet.png -------------------------------------------------------------------------------- /static/images/coir.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gangiswag/cornstack/6432dfde69400892000bb2dabdb90fbc3b239f20/static/images/coir.png -------------------------------------------------------------------------------- /static/images/cornstack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gangiswag/cornstack/6432dfde69400892000bb2dabdb90fbc3b239f20/static/images/cornstack.png -------------------------------------------------------------------------------- /static/images/favicon.svg: -------------------------------------------------------------------------------- 1 | 3 | 153 | 223 | 238 | 247 | 256 | 264 | 275 | 283 | 291 | 299 | 308 | 321 | 333 | 342 | 351 | 359 | 367 | 374 | 381 | 444 | 453 | 462 | 471 | 486 | 496 | 504 | 511 | 517 | 523 | 529 | 535 | 541 | 547 | 553 | 559 | 583 | 591 | 599 | -------------------------------------------------------------------------------- /static/images/file_level.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gangiswag/cornstack/6432dfde69400892000bb2dabdb90fbc3b239f20/static/images/file_level.png -------------------------------------------------------------------------------- /static/images/function_level.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gangiswag/cornstack/6432dfde69400892000bb2dabdb90fbc3b239f20/static/images/function_level.png -------------------------------------------------------------------------------- /static/js/bulma-slider.js: -------------------------------------------------------------------------------- 1 | (function webpackUniversalModuleDefinition(root, factory) { 2 | if(typeof exports === 'object' && typeof module === 'object') 3 | module.exports = factory(); 4 | else if(typeof define === 'function' && define.amd) 5 | define([], factory); 6 | else if(typeof exports === 'object') 7 | exports["bulmaSlider"] = factory(); 8 | else 9 | root["bulmaSlider"] = factory(); 10 | })(typeof self !== 'undefined' ? self : this, function() { 11 | return /******/ (function(modules) { // webpackBootstrap 12 | /******/ // The module cache 13 | /******/ var installedModules = {}; 14 | /******/ 15 | /******/ // The require function 16 | /******/ function __webpack_require__(moduleId) { 17 | /******/ 18 | /******/ // Check if module is in cache 19 | /******/ if(installedModules[moduleId]) { 20 | /******/ return installedModules[moduleId].exports; 21 | /******/ } 22 | /******/ // Create a new module (and put it into the cache) 23 | /******/ var module = installedModules[moduleId] = { 24 | /******/ i: moduleId, 25 | /******/ l: false, 26 | /******/ exports: {} 27 | /******/ }; 28 | /******/ 29 | /******/ // Execute the module function 30 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 31 | /******/ 32 | /******/ // Flag the module as loaded 33 | /******/ module.l = true; 34 | /******/ 35 | /******/ // Return the exports of the module 36 | /******/ return module.exports; 37 | /******/ } 38 | /******/ 39 | /******/ 40 | /******/ // expose the modules object (__webpack_modules__) 41 | /******/ __webpack_require__.m = modules; 42 | /******/ 43 | /******/ // expose the module cache 44 | /******/ __webpack_require__.c = installedModules; 45 | /******/ 46 | /******/ // define getter function for harmony exports 47 | /******/ __webpack_require__.d = function(exports, name, getter) { 48 | /******/ if(!__webpack_require__.o(exports, name)) { 49 | /******/ Object.defineProperty(exports, name, { 50 | /******/ configurable: false, 51 | /******/ enumerable: true, 52 | /******/ get: getter 53 | /******/ }); 54 | /******/ } 55 | /******/ }; 56 | /******/ 57 | /******/ // getDefaultExport function for compatibility with non-harmony modules 58 | /******/ __webpack_require__.n = function(module) { 59 | /******/ var getter = module && module.__esModule ? 60 | /******/ function getDefault() { return module['default']; } : 61 | /******/ function getModuleExports() { return module; }; 62 | /******/ __webpack_require__.d(getter, 'a', getter); 63 | /******/ return getter; 64 | /******/ }; 65 | /******/ 66 | /******/ // Object.prototype.hasOwnProperty.call 67 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 68 | /******/ 69 | /******/ // __webpack_public_path__ 70 | /******/ __webpack_require__.p = ""; 71 | /******/ 72 | /******/ // Load entry module and return exports 73 | /******/ return __webpack_require__(__webpack_require__.s = 0); 74 | /******/ }) 75 | /************************************************************************/ 76 | /******/ ([ 77 | /* 0 */ 78 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 79 | 80 | "use strict"; 81 | Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); 82 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isString", function() { return isString; }); 83 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__events__ = __webpack_require__(1); 84 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; 85 | 86 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 87 | 88 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; 89 | 90 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 91 | 92 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 93 | 94 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 95 | 96 | 97 | 98 | var isString = function isString(unknown) { 99 | return typeof unknown === 'string' || !!unknown && (typeof unknown === 'undefined' ? 'undefined' : _typeof(unknown)) === 'object' && Object.prototype.toString.call(unknown) === '[object String]'; 100 | }; 101 | 102 | var bulmaSlider = function (_EventEmitter) { 103 | _inherits(bulmaSlider, _EventEmitter); 104 | 105 | function bulmaSlider(selector) { 106 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 107 | 108 | _classCallCheck(this, bulmaSlider); 109 | 110 | var _this = _possibleConstructorReturn(this, (bulmaSlider.__proto__ || Object.getPrototypeOf(bulmaSlider)).call(this)); 111 | 112 | _this.element = typeof selector === 'string' ? document.querySelector(selector) : selector; 113 | // An invalid selector or non-DOM node has been provided. 114 | if (!_this.element) { 115 | throw new Error('An invalid selector or non-DOM node has been provided.'); 116 | } 117 | 118 | _this._clickEvents = ['click']; 119 | /// Set default options and merge with instance defined 120 | _this.options = _extends({}, options); 121 | 122 | _this.onSliderInput = _this.onSliderInput.bind(_this); 123 | 124 | _this.init(); 125 | return _this; 126 | } 127 | 128 | /** 129 | * Initiate all DOM element containing selector 130 | * @method 131 | * @return {Array} Array of all slider instances 132 | */ 133 | 134 | 135 | _createClass(bulmaSlider, [{ 136 | key: 'init', 137 | 138 | 139 | /** 140 | * Initiate plugin 141 | * @method init 142 | * @return {void} 143 | */ 144 | value: function init() { 145 | this._id = 'bulmaSlider' + new Date().getTime() + Math.floor(Math.random() * Math.floor(9999)); 146 | this.output = this._findOutputForSlider(); 147 | 148 | this._bindEvents(); 149 | 150 | if (this.output) { 151 | if (this.element.classList.contains('has-output-tooltip')) { 152 | // Get new output position 153 | var newPosition = this._getSliderOutputPosition(); 154 | 155 | // Set output position 156 | this.output.style['left'] = newPosition.position; 157 | } 158 | } 159 | 160 | this.emit('bulmaslider:ready', this.element.value); 161 | } 162 | }, { 163 | key: '_findOutputForSlider', 164 | value: function _findOutputForSlider() { 165 | var _this2 = this; 166 | 167 | var result = null; 168 | var outputs = document.getElementsByTagName('output') || []; 169 | 170 | Array.from(outputs).forEach(function (output) { 171 | if (output.htmlFor == _this2.element.getAttribute('id')) { 172 | result = output; 173 | return true; 174 | } 175 | }); 176 | return result; 177 | } 178 | }, { 179 | key: '_getSliderOutputPosition', 180 | value: function _getSliderOutputPosition() { 181 | // Update output position 182 | var newPlace, minValue; 183 | 184 | var style = window.getComputedStyle(this.element, null); 185 | // Measure width of range input 186 | var sliderWidth = parseInt(style.getPropertyValue('width'), 10); 187 | 188 | // Figure out placement percentage between left and right of input 189 | if (!this.element.getAttribute('min')) { 190 | minValue = 0; 191 | } else { 192 | minValue = this.element.getAttribute('min'); 193 | } 194 | var newPoint = (this.element.value - minValue) / (this.element.getAttribute('max') - minValue); 195 | 196 | // Prevent bubble from going beyond left or right (unsupported browsers) 197 | if (newPoint < 0) { 198 | newPlace = 0; 199 | } else if (newPoint > 1) { 200 | newPlace = sliderWidth; 201 | } else { 202 | newPlace = sliderWidth * newPoint; 203 | } 204 | 205 | return { 206 | 'position': newPlace + 'px' 207 | }; 208 | } 209 | 210 | /** 211 | * Bind all events 212 | * @method _bindEvents 213 | * @return {void} 214 | */ 215 | 216 | }, { 217 | key: '_bindEvents', 218 | value: function _bindEvents() { 219 | if (this.output) { 220 | // Add event listener to update output when slider value change 221 | this.element.addEventListener('input', this.onSliderInput, false); 222 | } 223 | } 224 | }, { 225 | key: 'onSliderInput', 226 | value: function onSliderInput(e) { 227 | e.preventDefault(); 228 | 229 | if (this.element.classList.contains('has-output-tooltip')) { 230 | // Get new output position 231 | var newPosition = this._getSliderOutputPosition(); 232 | 233 | // Set output position 234 | this.output.style['left'] = newPosition.position; 235 | } 236 | 237 | // Check for prefix and postfix 238 | var prefix = this.output.hasAttribute('data-prefix') ? this.output.getAttribute('data-prefix') : ''; 239 | var postfix = this.output.hasAttribute('data-postfix') ? this.output.getAttribute('data-postfix') : ''; 240 | 241 | // Update output with slider value 242 | this.output.value = prefix + this.element.value + postfix; 243 | 244 | this.emit('bulmaslider:ready', this.element.value); 245 | } 246 | }], [{ 247 | key: 'attach', 248 | value: function attach() { 249 | var _this3 = this; 250 | 251 | var selector = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'input[type="range"].slider'; 252 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 253 | 254 | var instances = new Array(); 255 | 256 | var elements = isString(selector) ? document.querySelectorAll(selector) : Array.isArray(selector) ? selector : [selector]; 257 | elements.forEach(function (element) { 258 | if (typeof element[_this3.constructor.name] === 'undefined') { 259 | var instance = new bulmaSlider(element, options); 260 | element[_this3.constructor.name] = instance; 261 | instances.push(instance); 262 | } else { 263 | instances.push(element[_this3.constructor.name]); 264 | } 265 | }); 266 | 267 | return instances; 268 | } 269 | }]); 270 | 271 | return bulmaSlider; 272 | }(__WEBPACK_IMPORTED_MODULE_0__events__["a" /* default */]); 273 | 274 | /* harmony default export */ __webpack_exports__["default"] = (bulmaSlider); 275 | 276 | /***/ }), 277 | /* 1 */ 278 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 279 | 280 | "use strict"; 281 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 282 | 283 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 284 | 285 | var EventEmitter = function () { 286 | function EventEmitter() { 287 | var listeners = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; 288 | 289 | _classCallCheck(this, EventEmitter); 290 | 291 | this._listeners = new Map(listeners); 292 | this._middlewares = new Map(); 293 | } 294 | 295 | _createClass(EventEmitter, [{ 296 | key: "listenerCount", 297 | value: function listenerCount(eventName) { 298 | if (!this._listeners.has(eventName)) { 299 | return 0; 300 | } 301 | 302 | var eventListeners = this._listeners.get(eventName); 303 | return eventListeners.length; 304 | } 305 | }, { 306 | key: "removeListeners", 307 | value: function removeListeners() { 308 | var _this = this; 309 | 310 | var eventName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; 311 | var middleware = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; 312 | 313 | if (eventName !== null) { 314 | if (Array.isArray(eventName)) { 315 | name.forEach(function (e) { 316 | return _this.removeListeners(e, middleware); 317 | }); 318 | } else { 319 | this._listeners.delete(eventName); 320 | 321 | if (middleware) { 322 | this.removeMiddleware(eventName); 323 | } 324 | } 325 | } else { 326 | this._listeners = new Map(); 327 | } 328 | } 329 | }, { 330 | key: "middleware", 331 | value: function middleware(eventName, fn) { 332 | var _this2 = this; 333 | 334 | if (Array.isArray(eventName)) { 335 | name.forEach(function (e) { 336 | return _this2.middleware(e, fn); 337 | }); 338 | } else { 339 | if (!Array.isArray(this._middlewares.get(eventName))) { 340 | this._middlewares.set(eventName, []); 341 | } 342 | 343 | this._middlewares.get(eventName).push(fn); 344 | } 345 | } 346 | }, { 347 | key: "removeMiddleware", 348 | value: function removeMiddleware() { 349 | var _this3 = this; 350 | 351 | var eventName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; 352 | 353 | if (eventName !== null) { 354 | if (Array.isArray(eventName)) { 355 | name.forEach(function (e) { 356 | return _this3.removeMiddleware(e); 357 | }); 358 | } else { 359 | this._middlewares.delete(eventName); 360 | } 361 | } else { 362 | this._middlewares = new Map(); 363 | } 364 | } 365 | }, { 366 | key: "on", 367 | value: function on(name, callback) { 368 | var _this4 = this; 369 | 370 | var once = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; 371 | 372 | if (Array.isArray(name)) { 373 | name.forEach(function (e) { 374 | return _this4.on(e, callback); 375 | }); 376 | } else { 377 | name = name.toString(); 378 | var split = name.split(/,|, | /); 379 | 380 | if (split.length > 1) { 381 | split.forEach(function (e) { 382 | return _this4.on(e, callback); 383 | }); 384 | } else { 385 | if (!Array.isArray(this._listeners.get(name))) { 386 | this._listeners.set(name, []); 387 | } 388 | 389 | this._listeners.get(name).push({ once: once, callback: callback }); 390 | } 391 | } 392 | } 393 | }, { 394 | key: "once", 395 | value: function once(name, callback) { 396 | this.on(name, callback, true); 397 | } 398 | }, { 399 | key: "emit", 400 | value: function emit(name, data) { 401 | var _this5 = this; 402 | 403 | var silent = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; 404 | 405 | name = name.toString(); 406 | var listeners = this._listeners.get(name); 407 | var middlewares = null; 408 | var doneCount = 0; 409 | var execute = silent; 410 | 411 | if (Array.isArray(listeners)) { 412 | listeners.forEach(function (listener, index) { 413 | // Start Middleware checks unless we're doing a silent emit 414 | if (!silent) { 415 | middlewares = _this5._middlewares.get(name); 416 | // Check and execute Middleware 417 | if (Array.isArray(middlewares)) { 418 | middlewares.forEach(function (middleware) { 419 | middleware(data, function () { 420 | var newData = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; 421 | 422 | if (newData !== null) { 423 | data = newData; 424 | } 425 | doneCount++; 426 | }, name); 427 | }); 428 | 429 | if (doneCount >= middlewares.length) { 430 | execute = true; 431 | } 432 | } else { 433 | execute = true; 434 | } 435 | } 436 | 437 | // If Middleware checks have been passed, execute 438 | if (execute) { 439 | if (listener.once) { 440 | listeners[index] = null; 441 | } 442 | listener.callback(data); 443 | } 444 | }); 445 | 446 | // Dirty way of removing used Events 447 | while (listeners.indexOf(null) !== -1) { 448 | listeners.splice(listeners.indexOf(null), 1); 449 | } 450 | } 451 | } 452 | }]); 453 | 454 | return EventEmitter; 455 | }(); 456 | 457 | /* harmony default export */ __webpack_exports__["a"] = (EventEmitter); 458 | 459 | /***/ }) 460 | /******/ ])["default"]; 461 | }); -------------------------------------------------------------------------------- /static/js/bulma-slider.min.js: -------------------------------------------------------------------------------- 1 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.bulmaSlider=e():t.bulmaSlider=e()}("undefined"!=typeof self?self:this,function(){return function(n){var r={};function i(t){if(r[t])return r[t].exports;var e=r[t]={i:t,l:!1,exports:{}};return n[t].call(e.exports,e,e.exports,i),e.l=!0,e.exports}return i.m=n,i.c=r,i.d=function(t,e,n){i.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:n})},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=0)}([function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),n.d(e,"isString",function(){return l});var r=n(1),i=Object.assign||function(t){for(var e=1;e=l.length&&(s=!0)):s=!0),s&&(t.once&&(u[e]=null),t.callback(r))});-1!==u.indexOf(null);)u.splice(u.indexOf(null),1)}}]),e}();e.a=i}]).default}); -------------------------------------------------------------------------------- /static/js/index.js: -------------------------------------------------------------------------------- 1 | window.HELP_IMPROVE_VIDEOJS = false; 2 | 3 | var INTERP_BASE = "./static/interpolation/stacked"; 4 | var NUM_INTERP_FRAMES = 240; 5 | 6 | var interp_images = []; 7 | function preloadInterpolationImages() { 8 | for (var i = 0; i < NUM_INTERP_FRAMES; i++) { 9 | var path = INTERP_BASE + '/' + String(i).padStart(6, '0') + '.jpg'; 10 | interp_images[i] = new Image(); 11 | interp_images[i].src = path; 12 | } 13 | } 14 | 15 | function setInterpolationImage(i) { 16 | var image = interp_images[i]; 17 | image.ondragstart = function() { return false; }; 18 | image.oncontextmenu = function() { return false; }; 19 | $('#interpolation-image-wrapper').empty().append(image); 20 | } 21 | 22 | 23 | $(document).ready(function() { 24 | // Check for click events on the navbar burger icon 25 | $(".navbar-burger").click(function() { 26 | // Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu" 27 | $(".navbar-burger").toggleClass("is-active"); 28 | $(".navbar-menu").toggleClass("is-active"); 29 | 30 | }); 31 | 32 | var options = { 33 | slidesToScroll: 1, 34 | slidesToShow: 3, 35 | loop: true, 36 | infinite: true, 37 | autoplay: false, 38 | autoplaySpeed: 3000, 39 | } 40 | 41 | // Initialize all div with carousel class 42 | var carousels = bulmaCarousel.attach('.carousel', options); 43 | 44 | // Loop on each carousel initialized 45 | for(var i = 0; i < carousels.length; i++) { 46 | // Add listener to event 47 | carousels[i].on('before:show', state => { 48 | console.log(state); 49 | }); 50 | } 51 | 52 | // Access to bulmaCarousel instance of an element 53 | var element = document.querySelector('#my-element'); 54 | if (element && element.bulmaCarousel) { 55 | // bulmaCarousel instance is available as element.bulmaCarousel 56 | element.bulmaCarousel.on('before-show', function(state) { 57 | console.log(state); 58 | }); 59 | } 60 | 61 | /*var player = document.getElementById('interpolation-video'); 62 | player.addEventListener('loadedmetadata', function() { 63 | $('#interpolation-slider').on('input', function(event) { 64 | console.log(this.value, player.duration); 65 | player.currentTime = player.duration / 100 * this.value; 66 | }) 67 | }, false);*/ 68 | preloadInterpolationImages(); 69 | 70 | $('#interpolation-slider').on('input', function(event) { 71 | setInterpolationImage(this.value); 72 | }); 73 | setInterpolationImage(0); 74 | $('#interpolation-slider').prop('max', NUM_INTERP_FRAMES - 1); 75 | 76 | bulmaSlider.attach(); 77 | 78 | }) 79 | 80 | --------------------------------------------------------------------------------