osa_tool 0.2.1__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {osa_tool-0.2.1 → osa_tool-0.2.2}/PKG-INFO +47 -43
- {osa_tool-0.2.1 → osa_tool-0.2.2}/README.md +44 -41
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/aboutgen/about_generator.py +9 -5
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/analytics/metadata.py +3 -2
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/analytics/prompt_builder.py +5 -5
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/analytics/report_maker.py +2 -2
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/analytics/run_report_gen.py +2 -2
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/arguments_parser.py +35 -21
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/config/settings/arguments.yaml +8 -47
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/config/settings/config.toml +24 -26
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/config/settings.py +3 -5
- osa_tool-0.2.2/osa_tool/docs/templates/ci_config.toml +45 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/git_agent/git_agent.py +1 -1
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/models/models.py +5 -4
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/osatreesitter/docgen.py +396 -162
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/readmegen/context/dependencies.py +12 -9
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/readmegen/models/llm_service.py +14 -17
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/run.py +67 -14
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/scheduler/README.md +60 -58
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/utils.py +7 -2
- {osa_tool-0.2.1 → osa_tool-0.2.2}/pyproject.toml +4 -3
- {osa_tool-0.2.1 → osa_tool-0.2.2}/LICENSE +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/__init__.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/aboutgen/__init__.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/aboutgen/prompts_about_config.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/analytics/__init__.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/analytics/report_generator.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/analytics/sourcerank.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/config/__init__.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/config/settings/prompt_for_analysis.toml +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/config/settings/prompt_for_scheduler.toml +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/config/settings/prompts.toml +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/config/settings/prompts_about_section.toml +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/config/settings/prompts_article.toml +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/config/templates/template.toml +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/convertion/__init__.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/convertion/notebook_converter.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/docs/images/osa_logo.PNG +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/docs/images/osa_logo_transparent.PNG +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/docs/templates/community.toml +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/docs/templates/contributing.toml +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/docs/templates/licenses.toml +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/docs/templates/mkdocs.yml +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/docs_generator/__init__.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/docs_generator/community.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/docs_generator/contributing.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/docs_generator/docs_run.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/docs_generator/license.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/git_agent/__init__.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/github_workflow/README.md +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/github_workflow/__init__.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/github_workflow/generator.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/github_workflow/providers/black.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/github_workflow/providers/unit_test.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/models/__init__.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/organization/repo_organizer.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/osatreesitter/__init__.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/osatreesitter/osa_treesitter.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/readmegen/__init__.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/readmegen/context/__init__.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/readmegen/context/article_content.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/readmegen/context/article_path.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/readmegen/context/files_contents.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/readmegen/context/pypi_status_checker.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/readmegen/generator/__init__.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/readmegen/generator/base_builder.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/readmegen/generator/builder.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/readmegen/generator/builder_article.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/readmegen/generator/header.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/readmegen/generator/icons/shieldsio_icons.json +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/readmegen/generator/installation.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/readmegen/models/__init__.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/readmegen/postprocessor/__init__.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/readmegen/postprocessor/readme_refiner.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/readmegen/postprocessor/response_cleaner.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/readmegen/prompts/__init__.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/readmegen/prompts/prompts_builder.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/readmegen/readme_core.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/readmegen/utils.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/scheduler/__init__.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/scheduler/prompts.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/scheduler/scheduler.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/scheduler/workflow_manager.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/translation/__init__.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/translation/dir_translator.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/ui/__init__.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/ui/plan_editor.py +0 -0
- {osa_tool-0.2.1 → osa_tool-0.2.2}/osa_tool/ui/web_plan_editor.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: osa_tool
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Tool that just makes your open source project better!
|
|
5
5
|
License: BSD-3-Clause
|
|
6
6
|
Author: ITMO-NSS-team
|
|
@@ -12,7 +12,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.11
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.12
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
-
Requires-Dist: ProtoLLM (>=0.1.
|
|
15
|
+
Requires-Dist: ProtoLLM (>=0.1.5)
|
|
16
16
|
Requires-Dist: PyYAML (==6.0.2)
|
|
17
17
|
Requires-Dist: Pygments (==2.19.1)
|
|
18
18
|
Requires-Dist: aiofiles (>=24.1.0,<25.0.0)
|
|
@@ -60,6 +60,7 @@ Requires-Dist: pydantic (>=2.9.0,<2.11.0)
|
|
|
60
60
|
Requires-Dist: pydantic-extra-types (==2.9.0)
|
|
61
61
|
Requires-Dist: pydantic_core (>=2.23.4,<2.24.0)
|
|
62
62
|
Requires-Dist: pytest (==8.3.4)
|
|
63
|
+
Requires-Dist: pytest-asyncio (==1.1.0)
|
|
63
64
|
Requires-Dist: pytest-mock (==3.14.0)
|
|
64
65
|
Requires-Dist: python-dotenv (==1.0.1)
|
|
65
66
|
Requires-Dist: qrcode (==8.0)
|
|
@@ -121,13 +122,15 @@ It also generates advices and recommendations for the repository.
|
|
|
121
122
|
|
|
122
123
|
OSA is currently under development, so not all features are implemented.
|
|
123
124
|
|
|
125
|
+
|
|
126
|
+
|
|
124
127
|
---
|
|
125
128
|
|
|
126
129
|
## How it works?
|
|
127
130
|
|
|
128
|
-
Here is a short
|
|
131
|
+
Here is a short video:
|
|
129
132
|
|
|
130
|
-
](https://www.youtube.com/watch?v=LDSb7JJgKoY)
|
|
131
134
|
|
|
132
135
|
---
|
|
133
136
|
|
|
@@ -220,23 +223,29 @@ docker build --build-arg GIT_USER_NAME="your-user-name" --build-arg GIT_USER_EMA
|
|
|
220
223
|
|
|
221
224
|
OSA requires Python 3.10 or higher.
|
|
222
225
|
|
|
223
|
-
File `.env` is required to specify GitHub/GitLab/Gitverse token (GIT_TOKEN) and LLM API key (OPENAI_API_KEY or
|
|
226
|
+
File `.env` is required to specify GitHub/GitLab/Gitverse token (GIT_TOKEN) and LLM API key (OPENAI_API_KEY or
|
|
227
|
+
AUTHORIZATION_KEY)
|
|
224
228
|
|
|
225
229
|
When running `osa-tool` from CLI, you need to set the GIT_TOKEN and API key first:
|
|
226
230
|
|
|
227
|
-
```
|
|
231
|
+
```sh
|
|
232
|
+
# Linux / macOS (bash/zsh)
|
|
228
233
|
export OPENAI_API_KEY=<your_api_key>
|
|
229
234
|
export GIT_TOKEN=<your_git_token>
|
|
235
|
+
|
|
236
|
+
# Windows (PowerShell)
|
|
237
|
+
setx OPENAI_API_KEY "<your_api_key>"
|
|
238
|
+
setx GIT_TOKEN "<your_git_token>"
|
|
230
239
|
```
|
|
231
240
|
|
|
232
241
|
### Tokens
|
|
233
242
|
|
|
234
|
-
| Token name
|
|
235
|
-
|
|
236
|
-
| `GIT_TOKEN`
|
|
237
|
-
| `OPENAI_API_KEY`
|
|
238
|
-
| `
|
|
239
|
-
| `X-API-Key`
|
|
243
|
+
| Token name | Description | Mandatory |
|
|
244
|
+
|---------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|
|
|
245
|
+
| `GIT_TOKEN` | Personal GitHub/GitLab/Gitverse token used to clone private repositories, access metadata, and interact with its API. | Yes |
|
|
246
|
+
| `OPENAI_API_KEY` | API key for accessing [OpenAI](https://platform.openai.com/docs/api-reference/introduction), [vsegpt](https://vsegpt.ru/Docs/API) and [openrouter](https://openrouter.ai/) providers | No |
|
|
247
|
+
| `AUTHORIZATION_KEY` | API key for [gigachat](https://developers.sber.ru/portal/products/gigachat-api) provider | No |
|
|
248
|
+
| `X-API-Key` | API key for the [pepy.tech](https://pepy.tech/pepy-api) REST API, used to fetch Python package download statistics | No |
|
|
240
249
|
|
|
241
250
|
### Usage
|
|
242
251
|
|
|
@@ -274,15 +283,14 @@ documentation, see the [GitHub Action Workflow Generator README](./osa_tool/gith
|
|
|
274
283
|
| `--api` | LLM API service provider | `itmo` |
|
|
275
284
|
| `--base-url` | URL of the provider compatible with API OpenAI | `https://api.openai.com/v1` |
|
|
276
285
|
| `--model` | Specific LLM model to use | `gpt-3.5-turbo` |
|
|
286
|
+
| `--top_p` | Nucleus sampling probability | `None` |
|
|
287
|
+
| `--temperature` | Sampling temperature to use for the LLM output (0 = deterministic, 1 = creative). | `None` |
|
|
288
|
+
| `--max_tokens` | Maximum number of tokens the model can generate in a single response | `None` |
|
|
277
289
|
| `--article` | Link to the pdf file of the article | `None` |
|
|
278
|
-
| `--translate-dirs` | Enable automatic translation of the directory name into English | `disabled` |
|
|
279
290
|
| `-m`, `--mode` | Operation mode for repository processing: `basic`, `auto` (default), or `advanced`. | `auto` |
|
|
280
291
|
| `--delete-dir` | Enable deleting the downloaded repository after processing | `disabled` |
|
|
281
292
|
| `--no-fork` | Avoid create fork for target repository | `False` |
|
|
282
293
|
| `--no-pull-request` | Avoid create pull request for target repository | `False` |
|
|
283
|
-
| `--top_p` | Nucleus sampling probability | `null` |
|
|
284
|
-
| `--temperature` | Sampling temperature to use for the LLM output (0 = deterministic, 1 = creative). | `null` |
|
|
285
|
-
| `--max_tokens` | Maximum number of tokens the model can generate in a single response | `null` |
|
|
286
294
|
|
|
287
295
|
To learn how to work with the interactive CLI and view descriptions of all available keys, visit
|
|
288
296
|
the [CLI usage guide](./osa_tool/scheduler/README.md).
|
|
@@ -293,19 +301,17 @@ the [CLI usage guide](./osa_tool/scheduler/README.md).
|
|
|
293
301
|
|
|
294
302
|
Examples of generated README files are available in [examples](https://github.com/aimclub/OSA/tree/main/examples).
|
|
295
303
|
|
|
296
|
-
URL of the GitHub/GitLab/Gitverse repository, LLM API service provider (*optional*) and Specific LLM model to use
|
|
297
|
-
required to use the generator.
|
|
304
|
+
URL of the GitHub/GitLab/Gitverse repository, LLM API service provider (*optional*) and Specific LLM model to use
|
|
305
|
+
(*optional*) are required to use the generator.
|
|
298
306
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
2. [OpenAI](https://platform.openai.com/docs/models)
|
|
303
|
-
3. [Ollama](https://ollama.com/library)
|
|
307
|
+
Supported LLM providers are available as part of the [ProtoLLM](https://github.com/aimclub/ProtoLLM/)
|
|
308
|
+
ecosystem. See the [connectors directory](https://github.com/aimclub/ProtoLLM/tree/main/protollm/connectors) for the
|
|
309
|
+
full list.
|
|
304
310
|
|
|
305
311
|
Local ITMO model:
|
|
306
312
|
|
|
307
313
|
```sh
|
|
308
|
-
python -m osa_tool.run -r https://github.com/aimclub/OSA --
|
|
314
|
+
python -m osa_tool.run -r https://github.com/aimclub/OSA --base-url [ITMO_MODEL_URL]
|
|
309
315
|
```
|
|
310
316
|
|
|
311
317
|
For this API provider itmo model url must be specified in dotenv (ITMO_MODEL_URL=) or in the --base-url argument.
|
|
@@ -322,6 +328,12 @@ VseGPT:
|
|
|
322
328
|
python -m osa_tool.run -r https://github.com/aimclub/OSA --api openai --base-url https://api.vsegpt.ru/v1 --model openai/gpt-3.5-turbo
|
|
323
329
|
```
|
|
324
330
|
|
|
331
|
+
Openrouter:
|
|
332
|
+
|
|
333
|
+
```sh
|
|
334
|
+
python -m osa_tool.run -r https://github.com/aimclub/OSA --api openai --base-url https://openrouter.ai/api/v1 --model qwen/qwen3-30b-a3b-instruct-2507
|
|
335
|
+
```
|
|
336
|
+
|
|
325
337
|
Ollama:
|
|
326
338
|
|
|
327
339
|
```sh
|
|
@@ -338,7 +350,8 @@ Detailed description of OSA API is available [here](https://aimclub.github.io/OS
|
|
|
338
350
|
|
|
339
351
|
## Chat with developers: OSA_helpdesk
|
|
340
352
|
|
|
341
|
-
In our Telegram chat [OSA_helpdesk](t.me/osa_helpdesk) you can ask questions about working with OSA and find the latest
|
|
353
|
+
In our Telegram chat [OSA_helpdesk](t.me/osa_helpdesk) you can ask questions about working with OSA and find the latest
|
|
354
|
+
news about the project.
|
|
342
355
|
|
|
343
356
|
---
|
|
344
357
|
|
|
@@ -385,29 +398,20 @@ for their code that we used as a foundation for our own version of README genera
|
|
|
385
398
|
|
|
386
399
|
If you use this software, please cite it as below.
|
|
387
400
|
|
|
388
|
-
###
|
|
401
|
+
### Simple format
|
|
389
402
|
|
|
390
|
-
|
|
403
|
+
Nikitin N. et al. An LLM-Powered Tool for Enhancing Scientific Open-Source Repositories // Championing Open-source DEvelopment in ML Workshop@ ICML25.
|
|
391
404
|
|
|
392
405
|
### BibTeX format
|
|
393
406
|
|
|
394
|
-
@
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
year = {2025},
|
|
401
|
-
|
|
402
|
-
publisher = {github.com},
|
|
403
|
-
|
|
404
|
-
journal = {github.com repository},
|
|
405
|
-
|
|
406
|
-
howpublished = {\url{https://github.com/aimclub/OSA.git}},
|
|
407
|
-
|
|
408
|
-
url = {https://github.com/aimclub/OSA.git}
|
|
407
|
+
@inproceedings{nikitinllm,
|
|
408
|
+
title={An LLM-Powered Tool for Enhancing Scientific Open-Source Repositories},
|
|
409
|
+
author={Nikitin, Nikolay and Getmanov, Andrey and Popov, Zakhar and
|
|
410
|
+
Ulyanova Ekaterina and Aksenkin, Yaroslav and
|
|
411
|
+
Sokolov, Ilya and Boukhanovsky, Alexander},
|
|
412
|
+
booktitle={Championing Open-source DEvelopment in ML Workshop@ ICML25}
|
|
409
413
|
|
|
410
|
-
|
|
414
|
+
}
|
|
411
415
|
|
|
412
416
|
---
|
|
413
417
|
|
|
@@ -36,13 +36,15 @@ It also generates advices and recommendations for the repository.
|
|
|
36
36
|
|
|
37
37
|
OSA is currently under development, so not all features are implemented.
|
|
38
38
|
|
|
39
|
+
|
|
40
|
+
|
|
39
41
|
---
|
|
40
42
|
|
|
41
43
|
## How it works?
|
|
42
44
|
|
|
43
|
-
Here is a short
|
|
45
|
+
Here is a short video:
|
|
44
46
|
|
|
45
|
-
](https://www.youtube.com/watch?v=LDSb7JJgKoY)
|
|
46
48
|
|
|
47
49
|
---
|
|
48
50
|
|
|
@@ -135,23 +137,29 @@ docker build --build-arg GIT_USER_NAME="your-user-name" --build-arg GIT_USER_EMA
|
|
|
135
137
|
|
|
136
138
|
OSA requires Python 3.10 or higher.
|
|
137
139
|
|
|
138
|
-
File `.env` is required to specify GitHub/GitLab/Gitverse token (GIT_TOKEN) and LLM API key (OPENAI_API_KEY or
|
|
140
|
+
File `.env` is required to specify GitHub/GitLab/Gitverse token (GIT_TOKEN) and LLM API key (OPENAI_API_KEY or
|
|
141
|
+
AUTHORIZATION_KEY)
|
|
139
142
|
|
|
140
143
|
When running `osa-tool` from CLI, you need to set the GIT_TOKEN and API key first:
|
|
141
144
|
|
|
142
|
-
```
|
|
145
|
+
```sh
|
|
146
|
+
# Linux / macOS (bash/zsh)
|
|
143
147
|
export OPENAI_API_KEY=<your_api_key>
|
|
144
148
|
export GIT_TOKEN=<your_git_token>
|
|
149
|
+
|
|
150
|
+
# Windows (PowerShell)
|
|
151
|
+
setx OPENAI_API_KEY "<your_api_key>"
|
|
152
|
+
setx GIT_TOKEN "<your_git_token>"
|
|
145
153
|
```
|
|
146
154
|
|
|
147
155
|
### Tokens
|
|
148
156
|
|
|
149
|
-
| Token name
|
|
150
|
-
|
|
151
|
-
| `GIT_TOKEN`
|
|
152
|
-
| `OPENAI_API_KEY`
|
|
153
|
-
| `
|
|
154
|
-
| `X-API-Key`
|
|
157
|
+
| Token name | Description | Mandatory |
|
|
158
|
+
|---------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|
|
|
159
|
+
| `GIT_TOKEN` | Personal GitHub/GitLab/Gitverse token used to clone private repositories, access metadata, and interact with its API. | Yes |
|
|
160
|
+
| `OPENAI_API_KEY` | API key for accessing [OpenAI](https://platform.openai.com/docs/api-reference/introduction), [vsegpt](https://vsegpt.ru/Docs/API) and [openrouter](https://openrouter.ai/) providers | No |
|
|
161
|
+
| `AUTHORIZATION_KEY` | API key for [gigachat](https://developers.sber.ru/portal/products/gigachat-api) provider | No |
|
|
162
|
+
| `X-API-Key` | API key for the [pepy.tech](https://pepy.tech/pepy-api) REST API, used to fetch Python package download statistics | No |
|
|
155
163
|
|
|
156
164
|
### Usage
|
|
157
165
|
|
|
@@ -189,15 +197,14 @@ documentation, see the [GitHub Action Workflow Generator README](./osa_tool/gith
|
|
|
189
197
|
| `--api` | LLM API service provider | `itmo` |
|
|
190
198
|
| `--base-url` | URL of the provider compatible with API OpenAI | `https://api.openai.com/v1` |
|
|
191
199
|
| `--model` | Specific LLM model to use | `gpt-3.5-turbo` |
|
|
200
|
+
| `--top_p` | Nucleus sampling probability | `None` |
|
|
201
|
+
| `--temperature` | Sampling temperature to use for the LLM output (0 = deterministic, 1 = creative). | `None` |
|
|
202
|
+
| `--max_tokens` | Maximum number of tokens the model can generate in a single response | `None` |
|
|
192
203
|
| `--article` | Link to the pdf file of the article | `None` |
|
|
193
|
-
| `--translate-dirs` | Enable automatic translation of the directory name into English | `disabled` |
|
|
194
204
|
| `-m`, `--mode` | Operation mode for repository processing: `basic`, `auto` (default), or `advanced`. | `auto` |
|
|
195
205
|
| `--delete-dir` | Enable deleting the downloaded repository after processing | `disabled` |
|
|
196
206
|
| `--no-fork` | Avoid create fork for target repository | `False` |
|
|
197
207
|
| `--no-pull-request` | Avoid create pull request for target repository | `False` |
|
|
198
|
-
| `--top_p` | Nucleus sampling probability | `null` |
|
|
199
|
-
| `--temperature` | Sampling temperature to use for the LLM output (0 = deterministic, 1 = creative). | `null` |
|
|
200
|
-
| `--max_tokens` | Maximum number of tokens the model can generate in a single response | `null` |
|
|
201
208
|
|
|
202
209
|
To learn how to work with the interactive CLI and view descriptions of all available keys, visit
|
|
203
210
|
the [CLI usage guide](./osa_tool/scheduler/README.md).
|
|
@@ -208,19 +215,17 @@ the [CLI usage guide](./osa_tool/scheduler/README.md).
|
|
|
208
215
|
|
|
209
216
|
Examples of generated README files are available in [examples](https://github.com/aimclub/OSA/tree/main/examples).
|
|
210
217
|
|
|
211
|
-
URL of the GitHub/GitLab/Gitverse repository, LLM API service provider (*optional*) and Specific LLM model to use
|
|
212
|
-
required to use the generator.
|
|
218
|
+
URL of the GitHub/GitLab/Gitverse repository, LLM API service provider (*optional*) and Specific LLM model to use
|
|
219
|
+
(*optional*) are required to use the generator.
|
|
213
220
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
2. [OpenAI](https://platform.openai.com/docs/models)
|
|
218
|
-
3. [Ollama](https://ollama.com/library)
|
|
221
|
+
Supported LLM providers are available as part of the [ProtoLLM](https://github.com/aimclub/ProtoLLM/)
|
|
222
|
+
ecosystem. See the [connectors directory](https://github.com/aimclub/ProtoLLM/tree/main/protollm/connectors) for the
|
|
223
|
+
full list.
|
|
219
224
|
|
|
220
225
|
Local ITMO model:
|
|
221
226
|
|
|
222
227
|
```sh
|
|
223
|
-
python -m osa_tool.run -r https://github.com/aimclub/OSA --
|
|
228
|
+
python -m osa_tool.run -r https://github.com/aimclub/OSA --base-url [ITMO_MODEL_URL]
|
|
224
229
|
```
|
|
225
230
|
|
|
226
231
|
For this API provider itmo model url must be specified in dotenv (ITMO_MODEL_URL=) or in the --base-url argument.
|
|
@@ -237,6 +242,12 @@ VseGPT:
|
|
|
237
242
|
python -m osa_tool.run -r https://github.com/aimclub/OSA --api openai --base-url https://api.vsegpt.ru/v1 --model openai/gpt-3.5-turbo
|
|
238
243
|
```
|
|
239
244
|
|
|
245
|
+
Openrouter:
|
|
246
|
+
|
|
247
|
+
```sh
|
|
248
|
+
python -m osa_tool.run -r https://github.com/aimclub/OSA --api openai --base-url https://openrouter.ai/api/v1 --model qwen/qwen3-30b-a3b-instruct-2507
|
|
249
|
+
```
|
|
250
|
+
|
|
240
251
|
Ollama:
|
|
241
252
|
|
|
242
253
|
```sh
|
|
@@ -253,7 +264,8 @@ Detailed description of OSA API is available [here](https://aimclub.github.io/OS
|
|
|
253
264
|
|
|
254
265
|
## Chat with developers: OSA_helpdesk
|
|
255
266
|
|
|
256
|
-
In our Telegram chat [OSA_helpdesk](t.me/osa_helpdesk) you can ask questions about working with OSA and find the latest
|
|
267
|
+
In our Telegram chat [OSA_helpdesk](t.me/osa_helpdesk) you can ask questions about working with OSA and find the latest
|
|
268
|
+
news about the project.
|
|
257
269
|
|
|
258
270
|
---
|
|
259
271
|
|
|
@@ -300,28 +312,19 @@ for their code that we used as a foundation for our own version of README genera
|
|
|
300
312
|
|
|
301
313
|
If you use this software, please cite it as below.
|
|
302
314
|
|
|
303
|
-
###
|
|
315
|
+
### Simple format
|
|
304
316
|
|
|
305
|
-
|
|
317
|
+
Nikitin N. et al. An LLM-Powered Tool for Enhancing Scientific Open-Source Repositories // Championing Open-source DEvelopment in ML Workshop@ ICML25.
|
|
306
318
|
|
|
307
319
|
### BibTeX format
|
|
308
320
|
|
|
309
|
-
@
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
year = {2025},
|
|
316
|
-
|
|
317
|
-
publisher = {github.com},
|
|
318
|
-
|
|
319
|
-
journal = {github.com repository},
|
|
320
|
-
|
|
321
|
-
howpublished = {\url{https://github.com/aimclub/OSA.git}},
|
|
322
|
-
|
|
323
|
-
url = {https://github.com/aimclub/OSA.git}
|
|
321
|
+
@inproceedings{nikitinllm,
|
|
322
|
+
title={An LLM-Powered Tool for Enhancing Scientific Open-Source Repositories},
|
|
323
|
+
author={Nikitin, Nikolay and Getmanov, Andrey and Popov, Zakhar and
|
|
324
|
+
Ulyanova Ekaterina and Aksenkin, Yaroslav and
|
|
325
|
+
Sokolov, Ilya and Boukhanovsky, Alexander},
|
|
326
|
+
booktitle={Championing Open-source DEvelopment in ML Workshop@ ICML25}
|
|
324
327
|
|
|
325
|
-
|
|
328
|
+
}
|
|
326
329
|
|
|
327
330
|
---
|
|
@@ -137,7 +137,7 @@ class AboutGenerator:
|
|
|
137
137
|
topics = [topic.strip().lower().replace(" ", "-") for topic in response.split(",") if topic.strip()]
|
|
138
138
|
logger.debug(f"Generated topics from LLM: {topics}")
|
|
139
139
|
validated_topics = self._validate_topics(topics)
|
|
140
|
-
return list(
|
|
140
|
+
return list({*existing_topics, *validated_topics})
|
|
141
141
|
except Exception as e:
|
|
142
142
|
logger.error(f"Error generating topics: {e}")
|
|
143
143
|
return []
|
|
@@ -161,7 +161,8 @@ class AboutGenerator:
|
|
|
161
161
|
logger.warning(f"Topic validation not implemented for platform: {self.platform}")
|
|
162
162
|
return topics
|
|
163
163
|
|
|
164
|
-
|
|
164
|
+
@staticmethod
|
|
165
|
+
def _validate_github_topics(topics: List[str]) -> List[str]:
|
|
165
166
|
"""Validates topics against GitHub Topics API.
|
|
166
167
|
|
|
167
168
|
Args:
|
|
@@ -205,7 +206,8 @@ class AboutGenerator:
|
|
|
205
206
|
logger.info(f"Validated {len(validated_topics)} topics out of {len(topics)}.")
|
|
206
207
|
return validated_topics
|
|
207
208
|
|
|
208
|
-
|
|
209
|
+
@staticmethod
|
|
210
|
+
def _validate_gitlab_topics(topics: List[str]) -> List[str]:
|
|
209
211
|
"""Validates topics against GitLab Topics API.
|
|
210
212
|
|
|
211
213
|
Args:
|
|
@@ -243,7 +245,8 @@ class AboutGenerator:
|
|
|
243
245
|
logger.info(f"Validated {len(validated_topics)} topics out of {len(topics)}.")
|
|
244
246
|
return validated_topics
|
|
245
247
|
|
|
246
|
-
|
|
248
|
+
@staticmethod
|
|
249
|
+
def _validate_gitverse_topics(topics: List[str]) -> List[str]:
|
|
247
250
|
"""Validates topics for Gitverse platform.
|
|
248
251
|
|
|
249
252
|
Args:
|
|
@@ -285,7 +288,8 @@ class AboutGenerator:
|
|
|
285
288
|
|
|
286
289
|
return candidates[0] if candidates else ""
|
|
287
290
|
|
|
288
|
-
|
|
291
|
+
@staticmethod
|
|
292
|
+
def _extract_readme_urls(readme_content: str) -> List[str]:
|
|
289
293
|
"""Extract all absolute URLs from README content"""
|
|
290
294
|
logger.info("Extracting URLs from README.")
|
|
291
295
|
url_pattern = r"(?:http|ftp|https):\/\/(?:[\w_-]+(?:(?:\.[\w_-]+)+))(?:[\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])"
|
|
@@ -171,6 +171,7 @@ def _parse_repository_metadata_gitlab(repo_data: dict) -> RepositoryMetadata:
|
|
|
171
171
|
def _parse_repository_metadata_gitverse(repo_data: dict) -> RepositoryMetadata:
|
|
172
172
|
"""Parse Gitverse API response into RepositoryMetadata."""
|
|
173
173
|
owner_info = repo_data.get("owner", {}) or {}
|
|
174
|
+
license_info = repo_data.get("license") or {}
|
|
174
175
|
|
|
175
176
|
return RepositoryMetadata(
|
|
176
177
|
name=repo_data.get("name", ""),
|
|
@@ -200,8 +201,8 @@ def _parse_repository_metadata_gitverse(repo_data: dict) -> RepositoryMetadata:
|
|
|
200
201
|
has_projects=repo_data.get("has_projects", False),
|
|
201
202
|
is_private=repo_data.get("private", False),
|
|
202
203
|
homepage_url=repo_data.get("homepage", ""),
|
|
203
|
-
license_name=
|
|
204
|
-
license_url=
|
|
204
|
+
license_name=license_info.get("name", ""),
|
|
205
|
+
license_url=license_info.get("url", ""),
|
|
205
206
|
platform="gitverse",
|
|
206
207
|
)
|
|
207
208
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
from pydantic import BaseModel, Field
|
|
2
|
-
from typing import List
|
|
3
1
|
from enum import Enum
|
|
4
2
|
|
|
3
|
+
from pydantic import BaseModel, Field
|
|
4
|
+
|
|
5
5
|
|
|
6
6
|
class YesNoPartial(str, Enum):
|
|
7
7
|
YES = "Yes"
|
|
@@ -12,7 +12,7 @@ class YesNoPartial(str, Enum):
|
|
|
12
12
|
|
|
13
13
|
class RepositoryStructure(BaseModel):
|
|
14
14
|
compliance: str = Field("Unknown", description="Compliance with standard structure")
|
|
15
|
-
missing_files:
|
|
15
|
+
missing_files: list[str] = Field(
|
|
16
16
|
default_factory=list,
|
|
17
17
|
description="List of missing critical files that impact project usability and clarity",
|
|
18
18
|
)
|
|
@@ -45,11 +45,11 @@ class CodeDocumentation(BaseModel):
|
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
class OverallAssessment(BaseModel):
|
|
48
|
-
key_shortcomings:
|
|
48
|
+
key_shortcomings: list[str] = Field(
|
|
49
49
|
default_factory=lambda: ["There are no critical issues"],
|
|
50
50
|
description="List of the most significant and critical issues that need to be addressed",
|
|
51
51
|
)
|
|
52
|
-
recommendations:
|
|
52
|
+
recommendations: list[str] = Field(
|
|
53
53
|
default_factory=lambda: ["No recommendations"],
|
|
54
54
|
description="Specific improvements to address issues or optimize the process",
|
|
55
55
|
)
|
|
@@ -14,6 +14,7 @@ from reportlab.platypus import (
|
|
|
14
14
|
Spacer,
|
|
15
15
|
Table,
|
|
16
16
|
TableStyle,
|
|
17
|
+
Flowable,
|
|
17
18
|
)
|
|
18
19
|
|
|
19
20
|
from osa_tool.analytics.metadata import load_data_metadata
|
|
@@ -247,7 +248,7 @@ class ReportGenerator:
|
|
|
247
248
|
)
|
|
248
249
|
return bullet_list
|
|
249
250
|
|
|
250
|
-
def body_second_part(self) -> list:
|
|
251
|
+
def body_second_part(self) -> list[Flowable]:
|
|
251
252
|
"""
|
|
252
253
|
Generates the second part of the report, which contains the analysis of the repository.
|
|
253
254
|
|
|
@@ -353,7 +354,6 @@ class ReportGenerator:
|
|
|
353
354
|
pagesize=A4,
|
|
354
355
|
topMargin=50,
|
|
355
356
|
bottomMargin=40,
|
|
356
|
-
leftMaring=10,
|
|
357
357
|
)
|
|
358
358
|
doc.build(
|
|
359
359
|
[
|
|
@@ -6,7 +6,7 @@ import pandas as pd
|
|
|
6
6
|
|
|
7
7
|
from osa_tool.analytics.report_maker import ReportGenerator
|
|
8
8
|
from osa_tool.analytics.sourcerank import SourceRank
|
|
9
|
-
from osa_tool.
|
|
9
|
+
from osa_tool.git_agent.git_agent import GitAgent
|
|
10
10
|
from osa_tool.readmegen.context.pypi_status_checker import PyPiPackageInspector
|
|
11
11
|
from osa_tool.run import load_configuration
|
|
12
12
|
from osa_tool.utils import logger, rich_section, delete_repository
|
|
@@ -78,7 +78,7 @@ def main():
|
|
|
78
78
|
)
|
|
79
79
|
|
|
80
80
|
# Clone the repository
|
|
81
|
-
github_agent =
|
|
81
|
+
github_agent = GitAgent(repo_url)
|
|
82
82
|
github_agent.clone_repository()
|
|
83
83
|
|
|
84
84
|
# Initialize analytics and generate report
|
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import argparse
|
|
2
|
+
from typing import Any
|
|
2
3
|
|
|
4
|
+
import tomli
|
|
3
5
|
import yaml
|
|
4
6
|
|
|
7
|
+
from osa_tool.utils import build_arguments_path, build_config_path
|
|
5
8
|
|
|
6
|
-
|
|
9
|
+
|
|
10
|
+
def build_parser_from_yaml() -> argparse.ArgumentParser:
|
|
7
11
|
"""
|
|
8
12
|
Build an ArgumentParser based on a YAML configuration file.
|
|
9
13
|
|
|
10
|
-
Args:
|
|
11
|
-
yaml_path: Path to the YAML file defining CLI arguments.
|
|
12
|
-
|
|
13
14
|
Returns:
|
|
14
15
|
argparse.ArgumentParser: Configured argument parser.
|
|
15
16
|
"""
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
config_yaml = read_arguments_file(build_arguments_path())
|
|
19
|
+
config_toml = read_config_file(build_config_path())
|
|
18
20
|
|
|
19
21
|
parser = argparse.ArgumentParser(
|
|
20
22
|
description="Generated CLI parser from YAML configuration",
|
|
@@ -26,39 +28,34 @@ def build_parser_from_yaml(yaml_path: str) -> argparse.ArgumentParser:
|
|
|
26
28
|
aliases = options.get("aliases", [])
|
|
27
29
|
arg_type = options.get("type", "str")
|
|
28
30
|
description = options.get("description", "")
|
|
29
|
-
default = options.get("default")
|
|
30
31
|
choices = options.get("choices")
|
|
31
|
-
|
|
32
|
+
default = get_default_from_config(config_toml, key)
|
|
32
33
|
kwargs = {"help": description}
|
|
33
34
|
|
|
34
35
|
if arg_type == "flag":
|
|
35
36
|
kwargs["action"] = "store_true"
|
|
36
|
-
|
|
37
|
-
kwargs["default"] = default
|
|
37
|
+
kwargs["default"] = default
|
|
38
38
|
elif arg_type == "str":
|
|
39
39
|
kwargs["type"] = str
|
|
40
|
-
|
|
41
|
-
kwargs["default"] = default
|
|
40
|
+
kwargs["default"] = default
|
|
42
41
|
if choices:
|
|
43
42
|
kwargs["choices"] = choices
|
|
44
43
|
elif arg_type == "int":
|
|
45
44
|
kwargs["type"] = int
|
|
46
|
-
|
|
47
|
-
kwargs["default"] = default
|
|
45
|
+
kwargs["default"] = default
|
|
48
46
|
elif arg_type == "list":
|
|
49
47
|
kwargs["nargs"] = "+"
|
|
50
48
|
kwargs["type"] = str
|
|
51
|
-
|
|
52
|
-
kwargs["default"] = default
|
|
49
|
+
kwargs["default"] = default
|
|
53
50
|
else:
|
|
54
51
|
raise ValueError(f"Unsupported type '{arg_type}' for argument '{key}'")
|
|
55
52
|
|
|
56
53
|
group.add_argument(*aliases, **kwargs)
|
|
57
54
|
|
|
58
|
-
core_args = {k: v for k, v in
|
|
55
|
+
core_args = {k: v for k, v in config_yaml.items() if not isinstance(v, dict) or "type" in v}
|
|
59
56
|
add_arguments(parser, core_args)
|
|
60
57
|
|
|
61
|
-
for group_name, group_args in
|
|
58
|
+
for group_name, group_args in config_yaml.items():
|
|
62
59
|
if isinstance(group_args, dict) and "type" not in group_args:
|
|
63
60
|
arg_group = parser.add_argument_group(f"{group_name} arguments")
|
|
64
61
|
add_arguments(arg_group, group_args)
|
|
@@ -66,8 +63,8 @@ def build_parser_from_yaml(yaml_path: str) -> argparse.ArgumentParser:
|
|
|
66
63
|
return parser
|
|
67
64
|
|
|
68
65
|
|
|
69
|
-
def get_keys_from_group_in_yaml(
|
|
70
|
-
data = read_arguments_file(
|
|
66
|
+
def get_keys_from_group_in_yaml(group_name: str) -> list:
|
|
67
|
+
data = read_arguments_file(build_arguments_path())
|
|
71
68
|
keys = []
|
|
72
69
|
for key, params in data.items():
|
|
73
70
|
if key == group_name:
|
|
@@ -75,7 +72,7 @@ def get_keys_from_group_in_yaml(yaml_path, group_name) -> list:
|
|
|
75
72
|
return keys
|
|
76
73
|
|
|
77
74
|
|
|
78
|
-
def read_arguments_file_flat(yaml_path) -> dict:
|
|
75
|
+
def read_arguments_file_flat(yaml_path: str) -> dict:
|
|
79
76
|
"""
|
|
80
77
|
Read YAML arguments file and flatten nested groups into a single dict.
|
|
81
78
|
"""
|
|
@@ -92,7 +89,24 @@ def read_arguments_file_flat(yaml_path) -> dict:
|
|
|
92
89
|
return flat_data
|
|
93
90
|
|
|
94
91
|
|
|
95
|
-
def
|
|
92
|
+
def get_default_from_config(config: dict, key: str) -> Any:
|
|
93
|
+
"""
|
|
94
|
+
Find default value for a key in config dict by searching all top-level sections.
|
|
95
|
+
"""
|
|
96
|
+
for section, values in config.items():
|
|
97
|
+
if isinstance(values, dict) and key in values:
|
|
98
|
+
return values[key]
|
|
99
|
+
return None
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def read_arguments_file(yaml_path: str) -> dict:
|
|
96
103
|
with open(yaml_path, "r", encoding="utf-8") as f:
|
|
97
104
|
data = yaml.safe_load(f)
|
|
98
105
|
return data
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def read_config_file(toml_path: str) -> dict[str, Any]:
|
|
109
|
+
"""Load TOML config as a nested dict."""
|
|
110
|
+
with open(toml_path, "rb") as f:
|
|
111
|
+
data = tomli.load(f)
|
|
112
|
+
return {k.lower(): v for k, v in data.items()}
|