{"id":40467018,"url":"https://github.com/kangwonlee/gemini-python-tutor","last_synced_at":"2026-01-20T18:12:34.616Z","repository":{"id":259739564,"uuid":"865825563","full_name":"kangwonlee/gemini-python-tutor","owner":"kangwonlee","description":"AI Tutor for Coding Assignments","archived":false,"fork":false,"pushed_at":"2026-01-02T13:29:01.000Z","size":237,"stargazers_count":0,"open_issues_count":11,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-08T18:46:13.203Z","etag":null,"topics":["pytest","pytest-json-report","python","rest-api"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kangwonlee.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-10-01T07:43:49.000Z","updated_at":"2026-01-02T13:29:05.000Z","dependencies_parsed_at":"2024-10-27T18:28:49.589Z","dependency_job_id":"0d286f2c-a302-44da-bf43-f258e86da925","html_url":"https://github.com/kangwonlee/gemini-python-tutor","commit_stats":null,"previous_names":["kangwonlee/gemini-python-tutor"],"tags_count":33,"template":false,"template_full_name":"cicirello/python-github-action-template","purl":"pkg:github/kangwonlee/gemini-python-tutor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kangwonlee%2Fgemini-python-tutor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kangwonlee%2Fgemini-python-tutor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kangwonlee%2Fgemini-python-tutor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kangwonlee%2Fgemini-python-tutor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kangwonlee","download_url":"https://codeload.github.com/kangwonlee/gemini-python-tutor/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kangwonlee%2Fgemini-python-tutor/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28608299,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T16:10:39.856Z","status":"ssl_error","status_checked_at":"2026-01-20T16:10:39.493Z","response_time":117,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["pytest","pytest-json-report","python","rest-api"],"created_at":"2026-01-20T18:12:33.875Z","updated_at":"2026-01-20T18:12:34.608Z","avatar_url":"https://github.com/kangwonlee.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://github.com/kangwonlee/gemini-python-tutor/workflows/build/badge.svg)](https://github.com/kangwonlee/gemini-python-tutor/actions)\n[![GitHub release](https://img.shields.io/github/release/kangwonlee/gemini-python-tutor.svg)](https://github.com/kangwonlee/gemini-python-tutor/releases)\n\n# AI Code Tutor\n\nThis 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 with enhanced security against prompt injection attacks.\n\nThe 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. New security features sanitize inputs and use random delimiters to prevent malicious prompt manipulation.\n\n## Key Features\n- AI-powered feedback for C/C++ and Python assignments.\n- Supports multiple JSON test reports from `pytest-json-report`.\n- Analyzes multiple student code files (`.c`, `.cpp`, `.py`).\n- Flexible LLM selection (Claude, Gemini, Grok, Nvidia NIM, Perplexity) with Gemini fallback.\n- Customizable feedback language (e.g., English, Korean).\n- Excludes common README content to optimize API usage.\n- **Security Enhancements**: Sanitizes student code and READMEs to remove malicious patterns and wraps content with random delimiters to prevent prompt injection attacks.\n\n## Prerequisites\n- **Python Dependencies**:\n  - Install required packages:\n    ```bash\n    pip install pytest pytest-json-report pytest-xdist requests\n    ```\n  - Generate JSON reports with:\n    ```bash\n    python -m pytest --json-report --json-report-indent=4 --json-report-file=report.json tests/test_file.py\n    ```\n  - See [pytest-json-report documentation](https://pypi.org/project/pytest-json-report/).\n- **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`).\n- **Docker**: For C/C++ testing, use a Docker image with `clang`, `cmake`, and `pytest`.\n\n## Usage\n1. Add a workflow file (e.g., `.github/workflows/classroom.yml`) to your repository.\n2. Configure it to run tests and invoke the AI tutor. Example for C/C++ assignments:\n\n```yaml\nname: Grade Assignment\non: [push, pull_request, workflow_dispatch]\njobs:\n  grade:\n    runs-on: ubuntu-latest\n    env:\n      CONTAINER_WORKSPACE: /app/workspace\n      CONTAINER_TESTS: /tests\n      CONTAINER_SRC: /app/workspace/src\n      C_FILENAME: main.c\n      WORKSPACE_OUTPUT: ${{ runner.temp }}/output\n      CONTAINER_OUTPUT: /output\n    steps:\n      - uses: actions/checkout@v5\n      - name: Set up environment\n        run: pip install pytest==8.3.5 pytest-json-report==1.5.0 pytest-xdist==3.6.1 requests==2.32.4\n      - name: Create output folder\n        run: mkdir -p ${{ env.WORKSPACE_OUTPUT }}\n      - name: Run C/C++ tests\n        run: |\n          docker run --rm \\\n            --volume ${{ github.workspace }}:${{ env.CONTAINER_WORKSPACE }}:ro \\\n            --volume ${{ env.WORKSPACE_OUTPUT }}:${{ env.CONTAINER_OUTPUT }}:rw \\\n            --workdir ${{ env.CONTAINER_TESTS }} \\\n            ghcr.io/kangwonlee/edu-base-cpp:4e0d6d8 \\\n            /bin/sh -c \"cmake . -DCMAKE_BUILD_TYPE=Debug -DSTUDENT_DIR=${{ env.CONTAINER_WORKSPACE }} \u0026\u0026 make \u0026\u0026 python3 -m pytest --json-report --json-report-indent=4 --json-report-file=${{ env.CONTAINER_OUTPUT }}/report.json test_dynamic.py\"\n      - name: AI Code Tutor\n        uses: kangwonlee/gemini-python-tutor@v0.3.12\n        if: always()\n        with:\n          report-files: ${{ env.WORKSPACE_OUTPUT }}/report.json\n          student-files: ${{ env.CONTAINER_SRC }}/${{ env.C_FILENAME }}\n          readme-path: ${{ env.CONTAINER_WORKSPACE }}/README.md\n          explanation-in: English\n          model: gemini-2.5-flash\n          INPUT_CLAUDE_API_KEY: ${{ secrets.INPUT_CLAUDE_API_KEY }}\n          INPUT_GOOGLE_API_KEY: ${{ secrets.INPUT_GOOGLE_API_KEY }}\n          INPUT_GROK_API_KEY: ${{ secrets.INPUT_GROK_API_KEY }}\n          INPUT_NVIDIA_API_KEY: ${{ secrets.INPUT_NVIDIA_API_KEY }}\n          INPUT_PERPLEXITY_API_KEY: ${{ secrets.INPUT_PERPLEXITY_API_KEY }}\n        timeout-minutes: 10\n```\n\n### Notes\n- **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.\n- **Model Selection**: Set `model` to prefer an LLM (e.g., `gemini-2.5-flash`). If its key is unavailable, the action falls back to Gemini if `INPUT_GOOGLE_API_KEY` is set, or uses any available key.\n- **Secrets**: Store API keys as repository secrets with `INPUT_` prefix (e.g., `INPUT_GOOGLE_API_KEY`) in Settings \u003e Secrets and variables \u003e Actions.\n- **README Optimization**: Exclude common README content with:\n  - Start: ``From here is common to all assignments.``\n  - End: ``Until here is common to all assignments.``\n  - Use double backticks (``).\n- **Security**: Student code and READMEs are sanitized to remove malicious patterns (e.g., \"ignore previous instructions\") and wrapped with random delimiters to prevent prompt injection.\n\n### Optimizing pytest for AI Feedback\n- Use descriptive test names (e.g., `test_sum_range_for__valid_input`).\n- Include clear assertion messages (e.g., `assert result == 10, f\"Expected 10, got {result}\"`).\n- Keep tests focused for accurate AI interpretation.\n\n## Inputs\n| Input                   | Description                                      | Required | Default         |\n|-------------------------|--------------------------------------------------|----------|-----------------|\n| `report-files`          | Comma-separated JSON report files                | Yes      | None            |\n| `student-files`         | Comma-separated student code files (`.c`, `.cpp`, `.py`) | Yes | None            |\n| `readme-path`           | Path to assignment instructions (README.md)      | Yes      | None            |\n| `explanation-in`        | Feedback language (e.g., English, Korean)        | No       | `English`       |\n| `model`                 | Preferred LLM (e.g., `gemini-2.5-flash`, `claude-sonnet-4-20250514`) | No | `gemini-2.5-flash` |\n| `INPUT_CLAUDE_API_KEY`  | Claude API key                                  | No*      | None            |\n| `INPUT_GOOGLE_API_KEY`  | Google Gemini API key                           | No*      | None            |\n| `INPUT_GROK_API_KEY`    | Grok API key                                    | No*      | None            |\n| `INPUT_NVIDIA_API_KEY`  | Nvidia NIM API key                              | No*      | None            |\n| `INPUT_PERPLEXITY_API_KEY` | Perplexity API key                          | No*      | None            |\n\n*At least one API key is required.\n\n### Example with Multiple Files\n```yaml\nwith:\n  report-files: 'report1.json,report2.json,reports/*.json'\n  student-files: 'src/main.c,src/utils.c'\n  readme-path: README.md\n  explanation-in: English\n  model: gemini-2.5-flash\n  INPUT_GOOGLE_API_KEY: ${{ secrets.INPUT_GOOGLE_API_KEY }}\n  INPUT_CLAUDE_API_KEY: ${{ secrets.INPUT_CLAUDE_API_KEY }}\n```\n\n## Outputs\n- **Feedback**: Markdown written to `$GITHUB_STEP_SUMMARY`, visible in the GitHub Job Summary, and saved as `feedback.md` in artifacts.\n\n## Limitations\n- Primarily supports C/C++ and Python assignments via `pytest-json-report`.\n- Requires at least one valid API key.\n- C/C++ feedback relies on `pytest` tests wrapping compiled code.\n- Prompt injection mitigated but not eliminated; use in controlled environments.\n\n## Future Enhancements\n- Auto-detect feedback language.\n- Support additional programming languages.\n- Add verbose mode for detailed feedback.\n- Enhance prompt injection defenses with advanced parsing.\n\n## Troubleshooting\nCheck GitHub Actions logs for details.\n\n### Common Errors\n- **API Key Issues**: \"No API keys provided\" – Ensure at least one API key is set in secrets.\n- **Report File Issues**: \"Report file not found\" – Verify JSON report exists.\n- **Student File Issues**: \"Student file not found\" – Check file paths and extensions.\n- **Prompt Injection**: Malicious inputs are sanitized and wrapped with random delimiters, but monitor outputs for anomalies.\n\n### Debugging Tips\n- View logs in the \"AI Code Tutor\" job.\n- Test locally with [act](https://github.com/nektos/act).\n- Use `INPUT_FAIL-EXPECTED=true` for debugging expected test failures.\n\n## Contact\nQuestions? Contact [https://github.com/kangwonlee](https://github.com/kangwonlee).\n\n## License\nBSD 3-Clause License + Do Not Harm.\nCopyright (c) 2024 Kangwon Lee\n\n## Acknowledgements\n- Built using [python-github-action-template](https://github.com/cicirello/python-github-action-template) by Vincent A. Cicirello (MIT License).\n- Gemini 2.5 Flash and Grok assisted with code and documentation.\n- Registered as #C-2024-034203, #C-2024-035473, #C-2025-016393, and #C-2025-027967 with the Korea Copyright Commission.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkangwonlee%2Fgemini-python-tutor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkangwonlee%2Fgemini-python-tutor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkangwonlee%2Fgemini-python-tutor/lists"}