Skip to content

Commit 7304298

Browse files
committed
Merge branch 'jobs-if'
2 parents acfa103 + a12946d commit 7304298

File tree

4 files changed

+292
-157
lines changed

4 files changed

+292
-157
lines changed

CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616

1717
### Fixed
1818

19+
## [v0.3.7] - 2025-08-01
20+
21+
### Added
22+
- **Flexible LLM Selection**: Added support for Claude, Grok, Nvidia NIM, and Perplexity alongside Gemini, with automatic fallback to Gemini or a single available API key if the specified model’s key is unavailable (`entrypoint.py`).
23+
- **C/C++ Support**: Extended feedback capabilities to C/C++ assignments, using `pytest` and `pytest-json-report` to analyze compiled code (e.g., via `ctypes`) in a Docker environment (`README.md`).
24+
- **Comprehensive Testing**: Added new test cases in `test_entrypoint.py` to cover single-key scenarios, Gemini fallback, empty key handling, and invalid model cases.
25+
26+
### Changed
27+
- **Updated README**: Renamed to "AI Code Tutor" to reflect C/C++ and Python support. Clarified dependencies (`pytest==8.3.5`, `pytest-json-report==1.5.0`, `pytest-xdist==3.6.1`, `requests==2.32.4`) and API key setup with `INPUT_` prefix (e.g., `INPUT_GOOGLE_API_KEY`). Improved YAML example for GitHub Classroom with Docker-based C/C++ testing.
28+
- **Enhanced Model Selection Logic**: Refactored `get_model_key_from_env` in `entrypoint.py` to handle missing `INPUT_MODEL`, prioritize specified model, and fall back to Gemini or single available key. Improved error messages for clarity.
29+
- **Improved Error Handling**: Added `try-except` for writing to `GITHUB_STEP_SUMMARY` in `entrypoint.py` to handle permission issues in GitHub Actions.
30+
- **Test Refinements**: Removed `mock_env_api_keys` fixture in `test_entrypoint.py` for better isolation, using `monkeypatch` directly. Updated tests to align with new model selection logic and `ValueError` exceptions.
31+
- **Code Cleanup**: Streamlined `entrypoint.py` by removing redundant comments, improving type hints (e.g., `key: str` in `get_startwith`), and organizing `get_config_class` logic with a separate `get_config_class_dict`.
32+
33+
### Fixed
34+
- **API Key Handling**: Fixed potential `KeyError` in `entrypoint.py` by using `os.getenv` with defaults, ensuring robust environment variable access.
35+
- **Test Accuracy**: Corrected `test_get_model_key_from_env__invalid_model_no_gemini` to expect valid fallback to a single available key (e.g., Claude) instead of an error.
36+
37+
### Removed
38+
- **Docker Badges**: Temporarily removed Docker Hub badges from `README.md` to align with updated deployment instructions (pending re-addition with verified image updates).
39+
1940
## [v0.3.6] - 2025-07-20
2041

2142

README.md

Lines changed: 97 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,148 +1,158 @@
11
[![Build Status](https://github.com/kangwonlee/gemini-python-tutor/workflows/build/badge.svg)](https://github.com/kangwonlee/gemini-python-tutor/actions)
22
[![GitHub release](https://img.shields.io/github/release/kangwonlee/gemini-python-tutor.svg)](https://github.com/kangwonlee/gemini-python-tutor/releases)
3-
[![Docker Image Version (latest by date)](https://img.shields.io/docker/v/beachgoer/gemini-python-tutor?label=Docker%20Hub&logo=docker)](https://hub.docker.com/r/beachgoer/gemini-python-tutor)
4-
[![Docker Image Size (latest by date)](https://img.shields.io/docker/image-size/beachgoer/gemini-python-tutor?logo=docker)](https://hub.docker.com/r/beachgoer/gemini-python-tutor)
53

6-
# AI Python Code Tutor
4+
# AI Code Tutor
75

8-
This GitHub Action leverages AI to analyze test results and Python code, delivering personalized feedback for student assignments. It identifies errors, suggests improvements, and explains concepts clearly.
6+
This GitHub Action uses AI to provide personalized feedback for student assignments in C/C++ and Python. It analyzes test results and code, identifying errors, suggesting optimizations, and explaining concepts clearly. Ideal for GitHub Classroom, it saves instructors time and ensures consistent, on-demand feedback.
97

10-
The AI tutor detects logic errors, recommends efficient algorithms, simplifies complex topics, and links to relevant documentation. It saves instructors time, ensures consistent feedback, and empowers students to learn anytime, anywhere.
8+
The AI tutor processes JSON test reports from `pytest-json-report`, generated by `pytest` tests wrapping C/C++ or Python code. It detects logic errors, recommends efficient algorithms, and links to relevant documentation.
119

1210
## Key Features
13-
14-
- AI-powered feedback for Python code assignments.
15-
- Supports multiple JSON test report files from `pytest-json-report`.
16-
- Analyzes multiple student code files.
17-
- Customizable explanation language (e.g., English, Korean).
11+
- AI-powered feedback for C/C++ and Python assignments.
12+
- Supports multiple JSON test reports from `pytest-json-report`.
13+
- Analyzes multiple student code files (`.c`, `.cpp`, `.py`).
14+
- Flexible LLM selection (Claude, Gemini, Grok, Nvidia NIM, Perplexity) with Gemini fallback.
15+
- Customizable feedback language (e.g., English, Korean).
1816
- Excludes common README content to optimize API usage.
1917

2018
## Prerequisites
21-
22-
To use this action, you’ll need:
23-
24-
- **pytest-json-report plugin**: Generates JSON test reports for analysis.
25-
- Install it with:
19+
- **Python Dependencies**:
20+
- Install required packages:
2621
```bash
27-
pip install pytest-json-report
22+
pip install pytest pytest-json-report pytest-xdist requests
2823
```
29-
- Generate a JSON report with:
24+
- Generate JSON reports with:
3025
```bash
31-
python -m pytest --json-report --json-indent=4 --json-report-file=report.json tests/test_my_test_file.py
26+
python -m pytest --json-report --json-report-indent=4 --json-report-file=report.json tests/test_file.py
3227
```
3328
- See [pytest-json-report documentation](https://pypi.org/project/pytest-json-report/).
34-
35-
- **Google API Key**: Set as `GOOGLE_API_KEY` in your repository secrets.
29+
- **API Key**: At least one API key for supported LLMs (Claude, Gemini, Grok, Nvidia NIM, Perplexity), set as repository secrets (e.g., `INPUT_CLAUDE_API_KEY`, `INPUT_GOOGLE_API_KEY`).
30+
- **Docker**: For C/C++ testing, use a Docker image with `clang`, `cmake`, and `pytest`.
3631

3732
## Usage
38-
3933
1. Add a workflow file (e.g., `.github/workflows/classroom.yml`) to your repository.
40-
2. Configure it as follows:
41-
42-
``` yaml
43-
on: [push]
34+
2. Configure it to run tests and invoke the AI tutor. Example for C/C++ assignments:
4435

36+
```yaml
37+
name: Grade Assignment
38+
on: [push, pull_request, workflow_dispatch]
4539
jobs:
4640
grade:
4741
runs-on: ubuntu-latest
42+
env:
43+
CONTAINER_WORKSPACE: /app/workspace
44+
CONTAINER_TESTS: /tests
45+
CONTAINER_SRC: /app/workspace/src
46+
C_FILENAME: main.c
47+
WORKSPACE_OUTPUT: ${{ runner.temp }}/output
48+
CONTAINER_OUTPUT: /output
4849
steps:
4950
- uses: actions/checkout@v4
50-
- name: Install dependencies
51-
run: pip install pytest pytest-json-report
52-
- name: Run tests
51+
- name: Set up environment
52+
run: pip install pytest==8.3.5 pytest-json-report==1.5.0 pytest-xdist==3.6.1 requests==2.32.4
53+
- name: Create output folder
54+
run: mkdir -p ${{ env.WORKSPACE_OUTPUT }}
55+
- name: Run C/C++ tests
5356
run: |
54-
python -m pytest --json-report --json-report-file=report.json tests/test_my_test_file.py
55-
- name: AI Python Tutor
56-
uses: kangwonlee/gemini-python-tutor@v0.2.1
57-
if: always() # Runs even if, or especially when, tests fail
57+
docker run --rm \
58+
--volume ${{ github.workspace }}:${{ env.CONTAINER_WORKSPACE }}:ro \
59+
--volume ${{ env.WORKSPACE_OUTPUT }}:${{ env.CONTAINER_OUTPUT }}:rw \
60+
--workdir ${{ env.CONTAINER_TESTS }} \
61+
ghcr.io/kangwonlee/edu-base-cpp:4e0d6d8 \
62+
/bin/sh -c "cmake . -DCMAKE_BUILD_TYPE=Debug -DSTUDENT_DIR=${{ env.CONTAINER_WORKSPACE }} && make && python3 -m pytest --json-report --json-report-indent=4 --json-report-file=${{ env.CONTAINER_OUTPUT }}/report.json test_dynamic.py"
63+
- name: AI Code Tutor
64+
uses: kangwonlee/gemini-python-tutor@v0.3.7
65+
if: always()
5866
with:
59-
report-files: report.json
60-
api-key: ${{ secrets.GOOGLE_API_KEY }}
61-
student-files: exercise.py
62-
readme-path: README.md
67+
report-files: ${{ env.WORKSPACE_OUTPUT }}/report.json
68+
student-files: ${{ env.CONTAINER_SRC }}/${{ env.C_FILENAME }}
69+
readme-path: ${{ env.CONTAINER_WORKSPACE }}/README.md
6370
explanation-in: English
64-
timeout-minutes: 5
71+
model: gemini
72+
INPUT_CLAUDE_API_KEY: ${{ secrets.INPUT_CLAUDE_API_KEY }}
73+
INPUT_GOOGLE_API_KEY: ${{ secrets.INPUT_GOOGLE_API_KEY }}
74+
INPUT_GROK_API_KEY: ${{ secrets.INPUT_GROK_API_KEY }}
75+
INPUT_NVIDIA_API_KEY: ${{ secrets.INPUT_NVIDIA_API_KEY }}
76+
INPUT_PERPLEXITY_API_KEY: ${{ secrets.INPUT_PERPLEXITY_API_KEY }}
77+
timeout-minutes: 10
6578
```
6679

6780
### Notes
68-
- The action processes JSON output from `pytest-json-report` to evaluate test results and provide feedback.
69-
- To save API usage, exclude common README content by marking it with:
81+
- **C/C++ Testing**: Tests can run in a Docker container with `pytest` wrapping C/C++ code (e.g., via `ctypes` for shared libraries, as in `test_dynamic.py`). Ensure JSON reports are generated.
82+
- **Model Selection**: Set `model` to prefer an LLM (e.g., `gemini`). If its key is unavailable, the action falls back to Gemini if `INPUT_GOOGLE_API_KEY` is set, or uses any one of available key.
83+
- **Secrets**: Store API keys as repository secrets with `INPUT_` prefix (e.g., `INPUT_GOOGLE_API_KEY`) in Settings > Secrets and variables > Actions.
84+
- **README Optimization**: Exclude common README content with:
7085
- Start: ``From here is common to all assignments.``
7186
- End: ``Until here is common to all assignments.``
72-
- Use double backticks (``) around these markers.
87+
- Use double backticks (``).
7388

74-
### Optimizing pytest for LLMs
75-
- Use descriptive test names (e.g., `test_calculate_sum_correctly`).
76-
- Add clear assertion messages (e.g., `assert x == 5, "Expected 5, got {x}"`).
77-
- Keep tests simple and focused for better AI interpretation.
89+
### Optimizing pytest for AI Feedback
90+
- Use descriptive test names (e.g., `test_sum_range_for__valid_input`).
91+
- Include clear assertion messages (e.g., `assert result == 10, f"Expected 10, got {result}"`).
92+
- Keep tests focused for accurate AI interpretation.
7893

7994
## Inputs
80-
81-
| Input | Description | Required | Default |
82-
|-------------------|--------------------------------------------------|----------|-----------------|
83-
| `report-files` | Comma-separated list of JSON report files | Yes | `report.json` |
84-
| `api-key` | Google API key for Gemini | Yes | N/A |
85-
| `student-files` | Comma-separated list of student Python files | Yes | `exercise.py` |
86-
| `readme-path` | Path to assignment instructions (README.md) | No | `README.md` |
87-
| `explanation-in` | Language for feedback (e.g., English, Korean) | No | `English` |
88-
| `model` | Gemini model (e.g., `gemini-2.0-flash`) | No | `gemini-2.0-flash` |
89-
95+
| Input | Description | Required | Default |
96+
|-------------------------|--------------------------------------------------|----------|-----------------|
97+
| `report-files` | Comma-separated JSON report files | Yes | `report.json` |
98+
| `student-files` | Comma-separated student code files (`.c`, `.cpp`, `.py`) | Yes | `exercise.py` |
99+
| `readme-path` | Path to assignment instructions (README.md) | No | `README.md` |
100+
| `explanation-in` | Feedback language (e.g., English, Korean) | No | `English` |
101+
| `model` | Preferred LLM (e.g., `gemini`, `claude`) | No | None |
102+
| `INPUT_CLAUDE_API_KEY` | Claude API key | No* | None |
103+
| `INPUT_GOOGLE_API_KEY` | Google Gemini API key | No* | None |
104+
| `INPUT_GROK_API_KEY` | Grok API key | No* | None |
105+
| `INPUT_NVIDIA_API_KEY` | Nvidia NIM API key | No* | None |
106+
| `INPUT_PERPLEXITY_API_KEY` | Perplexity API key | No* | None |
107+
108+
*At least one API key is required.
90109

91110
### Example with Multiple Files
92-
93-
``` yaml
111+
```yaml
94112
with:
95-
report-files: 'report1.json, report2.json, reports/*.json'
96-
api-key: ${{ secrets.GOOGLE_API_KEY }}
97-
student-files: 'exercise1.py, exercise2.py'
113+
report-files: 'report1.json,report2.json,reports/*.json'
114+
student-files: 'src/main.c,src/utils.c'
98115
readme-path: README.md
99116
explanation-in: English
117+
model: gemini
118+
INPUT_GOOGLE_API_KEY: ${{ secrets.INPUT_GOOGLE_API_KEY }}
119+
INPUT_CLAUDE_API_KEY: ${{ secrets.INPUT_CLAUDE_API_KEY }}
100120
```
101121

102122
## Outputs
103-
104-
- **Feedback**: Written to `$GITHUB_STEP_SUMMARY` (if set) in Markdown format, visible in the GitHub Job Summary.
123+
- **Feedback**: Markdown written to `$GITHUB_STEP_SUMMARY`, visible in the GitHub Job Summary, and saved as `feedback.md` in artifacts.
105124

106125
## Limitations
107-
108-
- Developed primarily to support Python code assignments.
109-
- Requires `pytest-json-report` for test reports.
126+
- Primarily supports C/C++ and Python assignments via `pytest-json-report`.
127+
- Requires at least one valid API key.
128+
- C/C++ feedback relies on `pytest` tests wrapping compiled code.
110129

111130
## Future Enhancements
112-
113-
- Expand natural language support with auto-detection.
114-
- Add options for AI models (e.g., Gemini Advanced, Grok, Perplexity).
115-
- Facilitate supporting more programming languages.
116-
- Include a `verbose` mode for detailed feedback.
131+
- Auto-detect feedback language.
132+
- Support additional programming languages.
133+
- Add verbose mode for detailed feedback.
117134

118135
## Troubleshooting
119-
120-
Check the action logs in the GitHub Actions tab for details.
136+
Check GitHub Actions logs for details.
121137

122138
### Common Errors
123-
- **API Key Issues**:
124-
- "Invalid API key": Verify `GOOGLE_API_KEY` in secrets.
125-
- **Report File Issues**:
126-
- "Report file not found": Ensure JSON report exists.
127-
- **Student File Issues**:
128-
- "Student file not found": Check file paths and `.py` extensions.
139+
- **API Key Issues**: "No API keys provided" – Ensure at least one API key is set in secrets.
140+
- **Report File Issues**: "Report file not found" – Verify JSON report exists.
141+
- **Student File Issues**: "Student file not found" – Check file paths and extensions.
129142

130143
### Debugging Tips
131-
- View logs in the "AI Python Tutor" job.
144+
- View logs in the "AI Code Tutor" job.
132145
- Test locally with [act](https://github.com/nektos/act).
133-
- Environment variable `INPUT_FAIL-EXPECTED` available for testing and debugging
146+
- Use `INPUT_FAIL-EXPECTED=true` for debugging expected test failures.
134147

135148
## Contact
136-
137-
Questions? Please contact [https://github.com/kangwonlee](https://github.com/kangwonlee).
149+
Questions? Contact [https://github.com/kangwonlee](https://github.com/kangwonlee).
138150

139151
## License
140-
141-
BSD 3-Clause License + Do Not Harm.
152+
BSD 3-Clause License + Do Not Harm.
142153
Copyright (c) 2024 Kangwon Lee
143154

144155
## Acknowledgements
145-
146-
* Built using [python-github-action-template](https://github.com/cicirello/python-github-action-template) by Vincent A. Cicirello (MIT License).
147-
* Gemini 2.0 Flash and Grok 3 helped with the code and documentation.
148-
* Registered as #C-2024-034203, #C-2024-035473, #C-2025-016393, and #C-2025-027967 with the Korea Copyright Commission.
156+
- Built using [python-github-action-template](https://github.com/cicirello/python-github-action-template) by Vincent A. Cicirello (MIT License).
157+
- Gemini 2.0 Flash and Grok 3 assisted with code and documentation.
158+
- Registered as #C-2024-034203, #C-2024-035473, #C-2025-016393, and #C-2025-027967 with the Korea Copyright Commission.

0 commit comments

Comments
 (0)