Skip to content

Commit 9fe9cef

Browse files
Add FAQ automation system with GitHub Actions integration (#14)
* Add FAQ automation system with GitHub Actions integration This commit introduces a comprehensive FAQ automation system that uses RAG and LLM-based triage to intelligently process new FAQ proposals. Features: - AI-powered FAQ proposal analysis (NEW/UPDATE/DUPLICATE decisions) - Automated PR creation for approved changes - GitHub issue template for structured FAQ proposals - Complete test suite with unit and integration tests - Comprehensive documentation (README, CONTRIBUTING) Components: - faq_automation/: Python module with core logic - core.py: FAQ processing utilities - rag_agent.py: LLM-based decision agent using OpenAI - actions.py: GitHub Actions integration helpers - cli.py: Command-line interface for workflow - .github/workflows/faq-automation.yml: GitHub Actions workflow - .github/ISSUE_TEMPLATE/faq-proposal.yml: Structured issue template - tests/: Comprehensive test coverage - CONTRIBUTING.md: Contributor guidelines - README.md: Updated with full documentation Dependencies added: - minsearch: Lightweight text search for FAQ retrieval - openai: LLM integration for decision making - pydantic: Structured output validation The system processes FAQ proposals through: 1. Issue submission via GitHub template 2. Retrieval of similar existing FAQs 3. LLM analysis and decision (NEW/UPDATE/DUPLICATE) 4. Automated PR creation or issue closure with feedback Supports: machine-learning-zoomcamp (initial course) Can be extended to support all courses in the future * Fix minsearch version requirement (0.0.7 instead of 0.4.1) * Configure setuptools to only package faq_automation * Change default model to gpt-5-nano for structured output support - Update CLI default model from gpt-4 to gpt-5-nano - Update RAG agent default model to gpt-5-nano - Update GitHub Actions workflow to use gpt-5-nano - Fix setuptools package configuration - Fix minsearch version requirement (0.0.7) * Remove test artifacts and add *.egg-info/ to gitignore * Add *.egg-info/ to gitignore * Add contribution banner to course pages Added a simple text banner with link to CONTRIBUTING.md at the top of each course page to encourage user contributions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * Increase contribution banner font size to match questions Set font size to 1.17em to match the question heading size for better visibility and consistency. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * Update issue template with dropdown for course selection - Change course field from input to dropdown menu - Add all 4 available courses as options: - machine-learning-zoomcamp - data-engineering-zoomcamp - llm-zoomcamp - mlops-zoomcamp - Update uv.lock to sync with FAQ automation dependencies 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * Add manual trigger for testing FAQ automation workflow - Add workflow_dispatch trigger with issue_number input - Support both automatic (issue opened) and manual execution - Fetch issue data when manually triggered - Update error handler to use correct issue number This allows testing the workflow on feature branches without merging. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * Fix issue number handling for manual workflow triggers * Fix: Create FAQ bot branches from main instead of current branch * docs: Update Development section with correct uv commands and API key setup * fix: Correct uv commands in Makefile and improve issue body parsing - Remove incorrect 'python -m' prefix from uv commands in Makefile - Update parse_issue_body to stop collecting content at any ### section - Ensures Checklist and other sections are excluded from parsed answer - All tests now passing * docs: Update README - remove Quick Start and correct LLM to GPT-5 - Remove Quick Start section (missing necessary environment setup) - Update all GPT-4 references to GPT-5 - Development section now contains all necessary setup instructions * docs: Update issue links to DataTalksClub/faq repository - Replace relative issue links with absolute URLs - Use direct link to FAQ proposal template - Simplify CONTRIBUTING instructions (remove redundant steps) - Point to https://github.com/DataTalksClub/faq/issues * docs: Remove GitHub Discussions reference from Support section * docs: Fix escaped backticks in CONTRIBUTING.md example code blocks * docs: Fix nested code blocks using 4 backticks for outer block * docs: Update testing documentation links for consistency * docs: Remove outer code block from example to render link correctly * docs: Add FAQ automation tests to tests/README.md - Document test_faq_automation.py (core functions) - Document test_cli_parsing.py (issue body parsing) - Document test_faq_actions.py (GitHub Actions integration) - Update test coverage section with test counts - Add example commands for running FAQ automation tests * refactor: Organize FAQ automation tests into classes - Reorganize test_faq_automation.py into classes (TestParseFrontmatter, TestWriteFrontmatter, TestGenerateDocumentId, TestKeepRelevant) - Reorganize test_cli_parsing.py into TestParseIssueBody class - Reorganize test_faq_actions.py into classes (TestGeneratePRBody, TestGenerateDuplicateComment) - Follow the established test structure pattern from test_sorting.py - All 102 unit tests passing * docs: Add FAQ automation examples to test method examples - Add example for running specific FAQ automation test method - Add example for running specific CLI parsing test method - Show proper class-based test structure in examples * docs: Update test commands to match Makefile and remove --extra dev - Use 'make test' commands as primary examples - Show 'uv run pytest' commands as alternatives - Remove '--extra dev' flag for consistency with Makefile - All test commands now consistent across documentation * Fix OpenAI API syntax to match notebook implementation Update faq_automation/rag_agent.py to use the correct OpenAI API syntax from the notebook prototype: - Changed beta.chat.completions.parse to responses.parse - Changed messages parameter to input - Changed response_format parameter to text_format - Updated response parsing to extract from response.output All 116 tests pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * Replace JS parsing logic with Python in FAQ automation workflow Eliminates code duplication between JavaScript and Python parsing by using a single Python implementation for all issue body parsing. Changes: - Add parse_full_issue_body() to extract course, question, and answer - Create scripts/extract_issue_fields.py for GitHub Actions integration - Simplify workflow to use Python parsing instead of JS - Add 6 comprehensive tests for parse_full_issue_body() - Update tests/README.md with new test documentation Benefits: - Single source of truth for parsing logic - All parsing code is testable - Easier maintenance (one language, one implementation) - No duplication between JS and Python Test results: All 122 tests pass (was 116, added 6 new tests) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * Replace bash scripting with Python for GitHub Actions outputs Creates a shared GitHub Actions helper module to eliminate bash scripting for writing to GITHUB_OUTPUT environment variable. Changes: - Create faq_automation/github_actions.py with write_github_output() - Supports both multiline (heredoc) and single-line formats - Handles local testing mode (prints to stdout) - Environment detection helpers (is_github_actions, get_github_output_path) - Update scripts/extract_issue_fields.py to use shared function - Import write_github_output from github_actions module - Remove duplicate implementation - Create scripts/write_faq_decision_output.py - Reads faq_decision.json - Writes to GITHUB_OUTPUT using Python - Replaces bash: echo "decision=$(jq -c .)" >> $GITHUB_OUTPUT - Update .github/workflows/faq-automation.yml - Replace bash output logic with Python script call - Cleaner, more maintainable workflow - Add comprehensive tests (10 new tests) - test_github_actions.py with 3 test classes - Multiline and single-line output formats - Local testing mode behavior - Environment detection - Update tests/README.md documentation Benefits: - All GitHub Actions integration uses Python - Single source of truth for output writing - Fully testable (no bash to test) - Consistent approach across all scripts - Better error handling and validation Test results: All 132 tests pass (was 122, added 10 new tests) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * Update workflow to use modern uv sync command Replace 'uv pip install --system -e .' with 'uv sync --no-dev' for: - Consistency with local development workflow - Modern uv best practices - Declarative dependency management - Faster installation (skips dev dependencies not needed in automation) Benefits: - Uses same uv sync approach as README recommends locally - Only installs production dependencies needed for FAQ automation - Automatic virtual environment management - Better reproducibility 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * Simplify FAQ automation workflow by removing --course argument Removes code duplication and simplifies workflow by having CLI parse course from issue body instead of extracting it separately. Changes: - Remove --course argument from CLI (faq_automation/cli.py) - Always use parse_full_issue_body() to extract course, question, answer - Update all references from args.course to parsed course variable - Simplify workflow (.github/workflows/faq-automation.yml) - Keep "Fetch issue body" step for clean separation - Remove "Extract issue fields with Python" step entirely (~26 lines removed) - Simplify "Process FAQ with AI" step (~14 lines removed) - Pass full issue body directly to CLI without reconstruction - Delete scripts/extract_issue_fields.py (no longer needed) - Update README.md example - Add course field to test_issue.txt example - Remove --course argument from CLI command Benefits: - Workflow reduced from 3 steps to 2 steps - Removed ~40 lines from workflow file - Deleted 1 script file (67 lines) - Simpler CLI interface (one less argument) - Single parsing path (no conditionals) - Easier to maintain and understand All 132 tests pass ✅ 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * Fix workflow to use uv run for Python commands After switching to 'uv sync --no-dev', Python commands need to run within the uv-managed virtual environment using 'uv run'. Changes: - Use 'uv run python -m faq_automation.cli' to run CLI module - Use 'uv run scripts/write_faq_decision_output.py' for script (leverages shebang line for cleaner syntax) This ensures Python commands execute with the correct dependencies installed by uv sync. Fixes: ModuleNotFoundError: No module named 'yaml' 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * Remove dead code: parse_issue_body() and its tests Removed parse_issue_body() function from CLI as it is no longer used in production. After removing the --course argument, the CLI always uses parse_full_issue_body() which extracts course, question, and answer from the full issue body. Changes: - Removed parse_issue_body() function from faq_automation/cli.py (58 lines) - Removed TestParseIssueBody class from tests/unit/test_cli_parsing.py (79 lines) - Updated import statement in test file - Updated tests/README.md to reflect new test count (132 → 127 tests) All 127 tests pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * Add answer content example to FAQ file format section 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * Add course field to FAQ example in contributing guide 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * Update test documentation to reflect full test suite scope - Updated description to clarify tests cover both site generator and FAQ automation - Added guidance for adding tests to FAQ automation system - Specified which test files to use for different FAQ automation components - Added notes about testing with real issue bodies and mocking external dependencies 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * Add comprehensive integration tests for FAQ automation workflow Added 26 integration tests covering the complete end-to-end FAQ automation workflow, bringing total test count from 143 to 153. Test coverage includes: - FAQ agent integration (5 tests): initialization, search, and proposal processing - File creation and updates (3 tests): creating new FAQs and updating existing ones - PR and comment generation (5 tests): generating outputs for all decision types - CLI integration (2 tests): parsing issue bodies and full CLI execution - Error handling and edge cases (4 tests): empty sections, non-existent docs, etc. - Site generator integration (3 tests): verifying created files work with generate_website.py - End-to-end workflows (3 tests): complete NEW/UPDATE/DUPLICATE flows All tests use mocked OpenAI API responses for consistency and speed, while performing real file I/O to verify format compatibility with the site generator. Updated tests/README.md with comprehensive documentation of the new test suite. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * Add auto-close for FAQ issues when PR is merged Modified FAQ automation workflow to include "Closes #<issue>" in PR body. This uses GitHub's native auto-close feature to automatically close the originating issue when the FAQ bot's PR is merged. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * docs: Document auto-close behavior for FAQ issues when PRs merge Updated README.md and CONTRIBUTING.md to clarify that issues with NEW or UPDATE actions are automatically closed when their associated PRs are merged, using GitHub's native "Closes #issue" feature. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * refactor: Remove manual workflow trigger to simplify FAQ automation Removed workflow_dispatch trigger and all related logic for manual workflow execution. The workflow now only triggers automatically on issue creation with the faq-proposal label, which simplifies the codebase and reduces maintenance burden. Changes: - Removed workflow_dispatch trigger and inputs section - Simplified job condition to only check for faq-proposal label - Removed fallback logic for manual issue number input - Streamlined issue body fetching (always uses context.payload.issue) - Cleaned up error handler to assume issue context 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> --------- Co-authored-by: Claude <[email protected]>
1 parent ec9d92d commit 9fe9cef

23 files changed

+3576
-25
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
name: FAQ Proposal
2+
description: Propose a new FAQ entry or update to existing FAQ
3+
title: "[FAQ] "
4+
labels: ["faq-proposal"]
5+
body:
6+
- type: markdown
7+
attributes:
8+
value: |
9+
## FAQ Proposal
10+
11+
Thank you for helping improve our FAQ! Please provide a clear question and answer below.
12+
13+
Our FAQ bot will automatically analyze your proposal and determine if it should:
14+
- Create a new FAQ entry
15+
- Update an existing FAQ entry
16+
- Mark as duplicate of an existing FAQ
17+
18+
- type: dropdown
19+
id: course
20+
attributes:
21+
label: Course
22+
description: Which course is this FAQ for?
23+
options:
24+
- machine-learning-zoomcamp
25+
- data-engineering-zoomcamp
26+
- llm-zoomcamp
27+
- mlops-zoomcamp
28+
validations:
29+
required: true
30+
31+
- type: textarea
32+
id: question
33+
attributes:
34+
label: Question
35+
description: What is the FAQ question?
36+
placeholder: "How do I install the required dependencies?"
37+
validations:
38+
required: true
39+
40+
- type: textarea
41+
id: answer
42+
attributes:
43+
label: Answer
44+
description: What is the answer to this question?
45+
placeholder: |
46+
To install the required dependencies, run:
47+
```bash
48+
uv pip install -r requirements.txt
49+
```
50+
validations:
51+
required: true
52+
53+
- type: checkboxes
54+
id: checklist
55+
attributes:
56+
label: Checklist
57+
description: Please confirm the following
58+
options:
59+
- label: I have searched existing FAQs and this question is not already answered
60+
required: true
61+
- label: The answer provides accurate, helpful information
62+
required: true
63+
- label: I have included any relevant code examples or links
64+
required: false
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
name: FAQ Automation
2+
3+
on:
4+
issues:
5+
types: [opened]
6+
7+
permissions:
8+
contents: write
9+
issues: write
10+
pull-requests: write
11+
12+
jobs:
13+
process-faq-proposal:
14+
if: contains(github.event.issue.labels.*.name, 'faq-proposal')
15+
runs-on: ubuntu-latest
16+
17+
steps:
18+
- name: Checkout repository
19+
uses: actions/checkout@v4
20+
21+
- name: Set up Python
22+
uses: actions/setup-python@v5
23+
with:
24+
python-version: '3.13'
25+
26+
- name: Install uv
27+
uses: astral-sh/setup-uv@v4
28+
29+
- name: Install dependencies
30+
run: |
31+
uv sync --no-dev
32+
33+
- name: Fetch issue body
34+
id: fetch_issue
35+
uses: actions/github-script@v7
36+
with:
37+
script: |
38+
const body = context.payload.issue.body || '';
39+
40+
// Save issue body to file for Python to parse
41+
const fs = require('fs');
42+
fs.writeFileSync('/tmp/issue_body.txt', body);
43+
44+
console.log('Fetched issue body, saved to /tmp/issue_body.txt');
45+
46+
- name: Process FAQ with AI
47+
id: process
48+
env:
49+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
50+
run: |
51+
# Run FAQ automation CLI with full issue body
52+
uv run python -m faq_automation.cli \
53+
--issue-body "$(cat /tmp/issue_body.txt)" \
54+
--issue-number ${{ github.event.issue.number }} \
55+
--model "gpt-5-nano" \
56+
--output-dir /tmp
57+
58+
# Write decision output to GitHub Actions
59+
uv run scripts/write_faq_decision_output.py
60+
61+
- name: Handle NEW or UPDATE action
62+
if: fromJson(steps.process.outputs.decision).action != 'DUPLICATE'
63+
uses: actions/github-script@v7
64+
with:
65+
script: |
66+
const decision = ${{ steps.process.outputs.decision }};
67+
const action = decision.action;
68+
const issueNumber = decision.issue_number;
69+
const prBody = decision.pr_body;
70+
const filePath = decision.file_path;
71+
72+
// Create branch name
73+
const branchName = `faq-bot/issue-${issueNumber}`;
74+
75+
// Configure git
76+
await exec.exec('git', ['config', 'user.name', 'FAQ Bot']);
77+
await exec.exec('git', ['config', 'user.email', '[email protected]']);
78+
79+
// Fetch and checkout main, then create new branch from it
80+
await exec.exec('git', ['fetch', 'origin', 'main']);
81+
await exec.exec('git', ['checkout', 'main']);
82+
await exec.exec('git', ['checkout', '-b', branchName]);
83+
84+
// Add modified files
85+
await exec.exec('git', ['add', filePath]);
86+
87+
// Commit changes
88+
const commitMsg = `${action}: ${decision.decision.question.substring(0, 72)}`;
89+
await exec.exec('git', ['commit', '-m', commitMsg]);
90+
91+
// Push branch
92+
await exec.exec('git', ['push', 'origin', branchName]);
93+
94+
// Create pull request
95+
const { data: pr } = await github.rest.pulls.create({
96+
owner: context.repo.owner,
97+
repo: context.repo.repo,
98+
title: `[FAQ Bot] ${action}: ${decision.decision.question.substring(0, 72)}`,
99+
head: branchName,
100+
base: 'main',
101+
body: `${prBody}\n\nCloses #${issueNumber}`
102+
});
103+
104+
// Comment on issue with PR link
105+
await github.rest.issues.createComment({
106+
owner: context.repo.owner,
107+
repo: context.repo.repo,
108+
issue_number: issueNumber,
109+
body: `✅ FAQ ${action} proposal created in PR #${pr.number}\n\nPlease review and approve the changes.`
110+
});
111+
112+
- name: Handle DUPLICATE action
113+
if: fromJson(steps.process.outputs.decision).action == 'DUPLICATE'
114+
uses: actions/github-script@v7
115+
with:
116+
script: |
117+
const decision = ${{ steps.process.outputs.decision }};
118+
const comment = decision.comment;
119+
const issueNumber = decision.issue_number;
120+
121+
// Post comment
122+
await github.rest.issues.createComment({
123+
owner: context.repo.owner,
124+
repo: context.repo.repo,
125+
issue_number: issueNumber,
126+
body: comment
127+
});
128+
129+
// Close issue
130+
await github.rest.issues.update({
131+
owner: context.repo.owner,
132+
repo: context.repo.repo,
133+
issue_number: issueNumber,
134+
state: 'closed',
135+
state_reason: 'completed'
136+
});
137+
138+
- name: Handle errors
139+
if: failure()
140+
uses: actions/github-script@v7
141+
with:
142+
script: |
143+
const issueNumber = context.payload.issue.number;
144+
await github.rest.issues.createComment({
145+
owner: context.repo.owner,
146+
repo: context.repo.repo,
147+
issue_number: issueNumber,
148+
body: `❌ FAQ Bot encountered an error processing this proposal.\n\nPlease check the [workflow run](${context.payload.repository.html_url}/actions/runs/${context.runId}) for details.\n\nA maintainer will review this manually.`
149+
});

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@
22
_site
33
__pycache__
44
.envrc
5-
.ipynb_checkpoints/
5+
.ipynb_checkpoints/
6+
CLAUDE.md
7+
*.egg-info/

CONTRIBUTING.md

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# Contributing to DataTalks.Club FAQ
2+
3+
Thank you for your interest in contributing to the DataTalks.Club FAQ! This guide will help you understand how to propose new FAQ entries or updates.
4+
5+
## Proposing a New FAQ Entry
6+
7+
We have an automated system that helps maintain the FAQ repository. Here's how to propose a new FAQ entry:
8+
9+
### 1. Create a New Issue
10+
11+
1. Go to the [FAQ Proposal form](https://github.com/DataTalksClub/faq/issues/new?template=faq-proposal.yml)
12+
2. Fill out the form:
13+
- **Course**: Which course this FAQ is for (e.g., `machine-learning-zoomcamp`)
14+
- **Question**: The FAQ question
15+
- **Answer**: A clear, helpful answer with examples if applicable
16+
- Check the validation boxes
17+
18+
### 2. Automated Processing
19+
20+
Once you submit your issue, our FAQ Bot will automatically:
21+
22+
1. **Analyze your proposal** using AI to compare it with existing FAQs
23+
2. **Make a decision**:
24+
- **NEW**: Create a new FAQ entry if the question isn't covered
25+
- **UPDATE**: Update an existing FAQ if your proposal adds valuable context
26+
- **DUPLICATE**: Mark as duplicate if the question is already fully answered
27+
28+
### 3. What Happens Next
29+
30+
#### For NEW or UPDATE Decisions
31+
32+
- A Pull Request will be automatically created with the proposed changes
33+
- The PR will include:
34+
- The new or modified FAQ file(s)
35+
- Explanation of why this action was chosen
36+
- Section placement and reasoning
37+
- A maintainer will review the PR
38+
- Once approved and merged, your FAQ contribution will be live!
39+
- The originating issue will be automatically closed when the PR is merged
40+
41+
#### For DUPLICATE Decisions
42+
43+
- The bot will comment on your issue with:
44+
- Explanation of why it's considered a duplicate
45+
- Link to the existing FAQ that covers your question
46+
- Link to the source file
47+
- The issue will be automatically closed
48+
- If you believe this is incorrect, you can reopen and mention a maintainer
49+
50+
## Writing Good FAQ Entries
51+
52+
### Question Guidelines
53+
54+
- Be specific and clear
55+
- Use the actual words students might search for
56+
- Start with question words (How, What, When, Why, etc.)
57+
- Examples:
58+
- ✅ "How do I install Python dependencies using uv?"
59+
- ❌ "Dependencies"
60+
61+
### Answer Guidelines
62+
63+
- Start with a direct answer
64+
- Include code examples when relevant
65+
- Add links to documentation or resources
66+
- Keep it concise but complete
67+
- Use markdown formatting for readability
68+
69+
**Example:**
70+
71+
### Course
72+
machine-learning-zoomcamp
73+
74+
### Question
75+
How do I run the tests for this project?
76+
77+
### Answer
78+
To run all tests, use:
79+
80+
```bash
81+
make test
82+
```
83+
84+
For unit tests only:
85+
86+
```bash
87+
make test-unit
88+
```
89+
90+
For integration tests only:
91+
92+
```bash
93+
make test-int
94+
```
95+
96+
See the [testing documentation](tests/README.md) for more details.
97+
98+
## Manual Contributions
99+
100+
If you prefer to contribute directly via Pull Request:
101+
102+
1. Fork the repository
103+
2. Create a new branch: `git checkout -b faq/your-topic`
104+
3. Add your FAQ file in the appropriate location:
105+
- `_questions/{course}/{section}/{NNN}_{id}_{slug}.md`
106+
4. Follow the frontmatter format:
107+
108+
```markdown
109+
---
110+
id: abc123
111+
question: 'Your question here?'
112+
sort_order: 10
113+
---
114+
115+
Your answer content here.
116+
```
117+
118+
5. Update `_questions/{course}/_metadata.yaml` if adding a new section
119+
6. Run tests: `make test`
120+
7. Create a Pull Request
121+
122+
## FAQ File Structure
123+
124+
FAQ files are organized as:
125+
126+
```
127+
_questions/
128+
├── machine-learning-zoomcamp/
129+
│ ├── _metadata.yaml # Course configuration
130+
│ ├── general/
131+
│ │ ├── 001_abc123_when-does-course-start.md
132+
│ │ └── 002_def456_what-are-prerequisites.md
133+
│ └── module-1/
134+
│ ├── 001_xyz789_install-docker.md
135+
│ └── 002_uvw456_docker-errors.md
136+
└── data-engineering-zoomcamp/
137+
└── ...
138+
```
139+
140+
### Frontmatter Fields
141+
142+
- **id** (required): Unique 10-character identifier
143+
- **question** (required): The FAQ question
144+
- **sort_order** (required): Integer for ordering within section
145+
- **images** (optional): Array of image objects for embedded images
146+
147+
### Markdown Content
148+
149+
- Write the answer in markdown
150+
- Use code blocks with language specifications
151+
- Include links where helpful
152+
- Keep formatting clean and readable
153+
154+
## Questions or Issues?
155+
156+
If you have questions about contributing or encounter issues with the FAQ Bot:
157+
158+
1. Check existing issues for similar questions
159+
2. Create a new issue with the "question" or "bug" label
160+
3. Tag a maintainer if urgent
161+
162+
Thank you for helping improve the DataTalks.Club FAQ! 🎉

0 commit comments

Comments
 (0)