fix question generation
Browse files
backend/QWEN.md
CHANGED
|
@@ -10,6 +10,7 @@ The application follows a clean architecture with proper separation of concerns:
|
|
| 10 |
- **Database Layer**: Manages database connections and sessions
|
| 11 |
- **Model Layer**: Defines database models using SQLAlchemy
|
| 12 |
- **Schema Layer**: Defines Pydantic schemas for request/response validation
|
|
|
|
| 13 |
|
| 14 |
## Technologies Used
|
| 15 |
|
|
@@ -20,6 +21,9 @@ The application follows a clean architecture with proper separation of concerns:
|
|
| 20 |
- **Alembic**: Database migration tool
|
| 21 |
- **Pydantic**: Data validation and settings management
|
| 22 |
- **UUID**: For generating unique identifiers
|
|
|
|
|
|
|
|
|
|
| 23 |
|
| 24 |
## Architecture Components
|
| 25 |
|
|
@@ -34,6 +38,8 @@ backend/
|
|
| 34 |
│ └── routes.py # Root and health check endpoints
|
| 35 |
├── database/ # Database connection utilities
|
| 36 |
│ └── database.py # Database engine and session management
|
|
|
|
|
|
|
| 37 |
├── models/ # SQLAlchemy models
|
| 38 |
│ ├── user.py # User model
|
| 39 |
│ ├── job.py # Job model
|
|
@@ -45,13 +51,17 @@ backend/
|
|
| 45 |
│ ├── job.py # Job schemas
|
| 46 |
│ ├── assessment.py # Assessment schemas
|
| 47 |
│ ├── application.py # Application schemas
|
|
|
|
| 48 |
│ └── base.py # Base schema class
|
| 49 |
├── services/ # Business logic layer
|
| 50 |
│ ├── user_service.py # User-related services
|
| 51 |
│ ├── job_service.py # Job-related services
|
| 52 |
│ ├── assessment_service.py # Assessment-related services
|
| 53 |
│ ├── application_service.py # Application-related services
|
|
|
|
| 54 |
│ └── base_service.py # Generic service functions
|
|
|
|
|
|
|
| 55 |
├── alembic/ # Database migration files
|
| 56 |
├── config.py # Application configuration
|
| 57 |
├── logging_config.py # Logging configuration
|
|
@@ -63,21 +73,31 @@ backend/
|
|
| 63 |
### Key Features
|
| 64 |
|
| 65 |
1. **User Management**:
|
| 66 |
-
- Registration and authentication
|
| 67 |
-
-
|
|
|
|
| 68 |
|
| 69 |
2. **Job Management**:
|
| 70 |
- Create, update, delete job postings
|
| 71 |
- Manage job details and requirements
|
|
|
|
| 72 |
|
| 73 |
-
3. **Assessment Management**:
|
| 74 |
-
- Create assessments
|
| 75 |
-
- Define
|
| 76 |
-
- Regenerate assessments with new questions
|
|
|
|
|
|
|
| 77 |
|
| 78 |
4. **Application Management**:
|
| 79 |
- Submit applications with answers
|
|
|
|
| 80 |
- Track application results and scores
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
|
| 82 |
### API Endpoints
|
| 83 |
|
|
@@ -99,14 +119,20 @@ backend/
|
|
| 99 |
#### Assessments
|
| 100 |
- `GET /assessments/jobs/{jid}` - List assessments for a job
|
| 101 |
- `GET /assessments/jobs/{jid}/{aid}` - Get assessment details
|
| 102 |
-
- `POST /assessments/jobs/{id}` - Create assessment
|
| 103 |
-
- `PATCH /assessments/jobs/{jid}/{aid}/regenerate` - Regenerate assessment
|
| 104 |
- `PATCH /assessments/jobs/{jid}/{aid}` - Update assessment
|
| 105 |
- `DELETE /assessments/jobs/{jid}/{aid}` - Delete assessment
|
| 106 |
|
| 107 |
#### Applications
|
| 108 |
-
- `GET /applications/jobs/{jid}/assessments/{aid}` - List applications
|
|
|
|
| 109 |
- `POST /applications/jobs/{jid}/assessments/{aid}` - Create application
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
|
| 111 |
#### Health Check
|
| 112 |
- `GET /` - Root endpoint
|
|
@@ -130,11 +156,14 @@ LOG_LEVEL=INFO
|
|
| 130 |
LOG_FILE=app.log
|
| 131 |
LOG_FORMAT=%(asctime)s - %(name)s - %(levelname)s - %(message)s
|
| 132 |
|
| 133 |
-
# JWT Configuration
|
| 134 |
SECRET_KEY=your-secret-key-here
|
| 135 |
ALGORITHM=HS256
|
| 136 |
ACCESS_TOKEN_EXPIRE_MINUTES=30
|
| 137 |
|
|
|
|
|
|
|
|
|
|
| 138 |
# Application Configuration
|
| 139 |
APP_NAME=AI-Powered Hiring Assessment Platform
|
| 140 |
APP_VERSION=0.1.0
|
|
@@ -146,6 +175,7 @@ APP_DESCRIPTION=MVP for managing hiring assessments using AI
|
|
| 146 |
### Prerequisites
|
| 147 |
- Python 3.11+
|
| 148 |
- pip package manager
|
|
|
|
| 149 |
|
| 150 |
### Setup Instructions
|
| 151 |
|
|
@@ -153,7 +183,7 @@ APP_DESCRIPTION=MVP for managing hiring assessments using AI
|
|
| 153 |
```bash
|
| 154 |
pip install -r requirements.txt
|
| 155 |
```
|
| 156 |
-
|
| 157 |
2. **Set Up Environment Variables**:
|
| 158 |
Copy the `.env.example` file to `.env` and adjust the values as needed.
|
| 159 |
|
|
@@ -166,7 +196,7 @@ APP_DESCRIPTION=MVP for managing hiring assessments using AI
|
|
| 166 |
```bash
|
| 167 |
python main.py
|
| 168 |
```
|
| 169 |
-
|
| 170 |
Or using uvicorn directly:
|
| 171 |
```bash
|
| 172 |
uvicorn main:app --host 0.0.0.0 --port 8000 --reload
|
|
@@ -180,9 +210,9 @@ uvicorn main:app --reload --host 0.0.0.0 --port 8000
|
|
| 180 |
|
| 181 |
## Testing
|
| 182 |
|
| 183 |
-
To run tests
|
| 184 |
```bash
|
| 185 |
-
pytest
|
| 186 |
```
|
| 187 |
|
| 188 |
## Logging
|
|
@@ -213,28 +243,56 @@ The application uses Alembic for database migrations:
|
|
| 213 |
- Log errors appropriately
|
| 214 |
|
| 215 |
3. **Security**:
|
| 216 |
-
- Passwords
|
| 217 |
- Input validation through Pydantic schemas
|
| 218 |
- SQL injection prevention through SQLAlchemy ORM
|
|
|
|
| 219 |
|
| 220 |
4. **Architecture**:
|
| 221 |
- Keep business logic in service layer
|
| 222 |
- Use dependency injection for database sessions
|
| 223 |
- Separate API routes by domain/model
|
| 224 |
- Maintain clear separation between layers
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 225 |
|
| 226 |
## Future Enhancements
|
| 227 |
|
| 228 |
-
-
|
| 229 |
-
-
|
| 230 |
-
-
|
| 231 |
-
-
|
| 232 |
-
-
|
| 233 |
-
- Unit and integration tests
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
-
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 240 |
|
|
|
|
| 10 |
- **Database Layer**: Manages database connections and sessions
|
| 11 |
- **Model Layer**: Defines database models using SQLAlchemy
|
| 12 |
- **Schema Layer**: Defines Pydantic schemas for request/response validation
|
| 13 |
+
- **Integration Layer**: Handles external services like AI providers
|
| 14 |
|
| 15 |
## Technologies Used
|
| 16 |
|
|
|
|
| 21 |
- **Alembic**: Database migration tool
|
| 22 |
- **Pydantic**: Data validation and settings management
|
| 23 |
- **UUID**: For generating unique identifiers
|
| 24 |
+
- **Mistral AI**: AI provider for generating questions and scoring answers
|
| 25 |
+
- **JWT**: For authentication and authorization
|
| 26 |
+
- **bcrypt**: For password hashing
|
| 27 |
|
| 28 |
## Architecture Components
|
| 29 |
|
|
|
|
| 38 |
│ └── routes.py # Root and health check endpoints
|
| 39 |
├── database/ # Database connection utilities
|
| 40 |
│ └── database.py # Database engine and session management
|
| 41 |
+
├── integrations/ # External service integrations
|
| 42 |
+
│ └── ai_integration/ # AI provider implementations
|
| 43 |
├── models/ # SQLAlchemy models
|
| 44 |
│ ├── user.py # User model
|
| 45 |
│ ├── job.py # Job model
|
|
|
|
| 51 |
│ ├── job.py # Job schemas
|
| 52 |
│ ├── assessment.py # Assessment schemas
|
| 53 |
│ ├── application.py # Application schemas
|
| 54 |
+
│ ├── enums.py # Enum definitions
|
| 55 |
│ └── base.py # Base schema class
|
| 56 |
├── services/ # Business logic layer
|
| 57 |
│ ├── user_service.py # User-related services
|
| 58 |
│ ├── job_service.py # Job-related services
|
| 59 |
│ ├── assessment_service.py # Assessment-related services
|
| 60 |
│ ├── application_service.py # Application-related services
|
| 61 |
+
│ ├── ai_service.py # AI-related services
|
| 62 |
│ └── base_service.py # Generic service functions
|
| 63 |
+
├── utils/ # Utility functions
|
| 64 |
+
│ └── dependencies.py # Dependency injection functions
|
| 65 |
├── alembic/ # Database migration files
|
| 66 |
├── config.py # Application configuration
|
| 67 |
├── logging_config.py # Logging configuration
|
|
|
|
| 73 |
### Key Features
|
| 74 |
|
| 75 |
1. **User Management**:
|
| 76 |
+
- Registration and authentication with role-based access (HR vs Applicant)
|
| 77 |
+
- JWT-based secure session management
|
| 78 |
+
- Password hashing using bcrypt
|
| 79 |
|
| 80 |
2. **Job Management**:
|
| 81 |
- Create, update, delete job postings
|
| 82 |
- Manage job details and requirements
|
| 83 |
+
- Track applicant counts
|
| 84 |
|
| 85 |
+
3. **AI-Powered Assessment Management**:
|
| 86 |
+
- Create assessments with AI-generated questions based on job requirements
|
| 87 |
+
- Define question types (multiple choice single answer, multiple choice multiple answers, text-based)
|
| 88 |
+
- Regenerate assessments with new AI-generated questions
|
| 89 |
+
- Automatic duration estimation based on content using AI
|
| 90 |
+
- Passing score configuration (range 20-80)
|
| 91 |
|
| 92 |
4. **Application Management**:
|
| 93 |
- Submit applications with answers
|
| 94 |
+
- AI-powered scoring of text-based answers with rationales
|
| 95 |
- Track application results and scores
|
| 96 |
+
- Detailed feedback with AI-generated rationales
|
| 97 |
+
|
| 98 |
+
5. **Dashboard Features**:
|
| 99 |
+
- View application scores with sorting options
|
| 100 |
+
- Monitor assessment performance
|
| 101 |
|
| 102 |
### API Endpoints
|
| 103 |
|
|
|
|
| 119 |
#### Assessments
|
| 120 |
- `GET /assessments/jobs/{jid}` - List assessments for a job
|
| 121 |
- `GET /assessments/jobs/{jid}/{aid}` - Get assessment details
|
| 122 |
+
- `POST /assessments/jobs/{id}` - Create assessment with AI-generated questions
|
| 123 |
+
- `PATCH /assessments/jobs/{jid}/{aid}/regenerate` - Regenerate assessment with new AI-generated questions
|
| 124 |
- `PATCH /assessments/jobs/{jid}/{aid}` - Update assessment
|
| 125 |
- `DELETE /assessments/jobs/{jid}/{aid}` - Delete assessment
|
| 126 |
|
| 127 |
#### Applications
|
| 128 |
+
- `GET /applications/jobs/{jid}/assessments/{aid}` - List applications for an assessment
|
| 129 |
+
- `GET /applications/jobs/{jid}/assessment_id/{aid}/applications/{id}` - Get detailed application
|
| 130 |
- `POST /applications/jobs/{jid}/assessments/{aid}` - Create application
|
| 131 |
+
- `GET /applications/my-applications` - Get current user's applications
|
| 132 |
+
- `GET /applications/my-applications/{id}` - Get specific application for current user
|
| 133 |
+
|
| 134 |
+
#### Dashboard
|
| 135 |
+
- `GET /dashboard/applications/scores` - Get application scores with sorting options
|
| 136 |
|
| 137 |
#### Health Check
|
| 138 |
- `GET /` - Root endpoint
|
|
|
|
| 156 |
LOG_FILE=app.log
|
| 157 |
LOG_FORMAT=%(asctime)s - %(name)s - %(levelname)s - %(message)s
|
| 158 |
|
| 159 |
+
# JWT Configuration
|
| 160 |
SECRET_KEY=your-secret-key-here
|
| 161 |
ALGORITHM=HS256
|
| 162 |
ACCESS_TOKEN_EXPIRE_MINUTES=30
|
| 163 |
|
| 164 |
+
# AI Provider Configuration
|
| 165 |
+
MISTRAL_API_KEY=your-mistral-api-key-here
|
| 166 |
+
|
| 167 |
# Application Configuration
|
| 168 |
APP_NAME=AI-Powered Hiring Assessment Platform
|
| 169 |
APP_VERSION=0.1.0
|
|
|
|
| 175 |
### Prerequisites
|
| 176 |
- Python 3.11+
|
| 177 |
- pip package manager
|
| 178 |
+
- Mistral AI API key (optional, for AI features)
|
| 179 |
|
| 180 |
### Setup Instructions
|
| 181 |
|
|
|
|
| 183 |
```bash
|
| 184 |
pip install -r requirements.txt
|
| 185 |
```
|
| 186 |
+
|
| 187 |
2. **Set Up Environment Variables**:
|
| 188 |
Copy the `.env.example` file to `.env` and adjust the values as needed.
|
| 189 |
|
|
|
|
| 196 |
```bash
|
| 197 |
python main.py
|
| 198 |
```
|
| 199 |
+
|
| 200 |
Or using uvicorn directly:
|
| 201 |
```bash
|
| 202 |
uvicorn main:app --host 0.0.0.0 --port 8000 --reload
|
|
|
|
| 210 |
|
| 211 |
## Testing
|
| 212 |
|
| 213 |
+
To run tests:
|
| 214 |
```bash
|
| 215 |
+
python -m pytest
|
| 216 |
```
|
| 217 |
|
| 218 |
## Logging
|
|
|
|
| 243 |
- Log errors appropriately
|
| 244 |
|
| 245 |
3. **Security**:
|
| 246 |
+
- Passwords are hashed using bcrypt
|
| 247 |
- Input validation through Pydantic schemas
|
| 248 |
- SQL injection prevention through SQLAlchemy ORM
|
| 249 |
+
- JWT-based authentication and authorization
|
| 250 |
|
| 251 |
4. **Architecture**:
|
| 252 |
- Keep business logic in service layer
|
| 253 |
- Use dependency injection for database sessions
|
| 254 |
- Separate API routes by domain/model
|
| 255 |
- Maintain clear separation between layers
|
| 256 |
+
- Use enums for fixed values to ensure consistency
|
| 257 |
+
|
| 258 |
+
5. **AI Integration**:
|
| 259 |
+
- Abstract AI provider implementations behind interfaces
|
| 260 |
+
- Use factory pattern for AI provider selection
|
| 261 |
+
- Implement fallback mechanisms for AI services
|
| 262 |
+
|
| 263 |
+
## Implemented Features
|
| 264 |
+
|
| 265 |
+
- ✅ JWT token-based authentication
|
| 266 |
+
- ✅ Password hashing implementation using bcrypt
|
| 267 |
+
- ✅ AI-powered question generation based on job requirements
|
| 268 |
+
- ✅ AI-powered scoring of text-based answers with rationales
|
| 269 |
+
- ✅ Assessment duration estimation using AI
|
| 270 |
+
- ✅ Comprehensive API input/output validation with Pydantic schemas
|
| 271 |
+
- ✅ Proper enum definitions for consistent API contracts
|
| 272 |
+
- ✅ Role-based access control (HR vs Applicant)
|
| 273 |
+
- ✅ Detailed application feedback with AI-generated rationales
|
| 274 |
+
- ✅ My Applications endpoint for candidates to track their submissions
|
| 275 |
+
- ✅ Dashboard endpoints for viewing application scores
|
| 276 |
+
- ✅ Assessment regeneration functionality
|
| 277 |
+
- ✅ Proper handling of answers as JSON data within applications
|
| 278 |
+
- ✅ Comprehensive logging throughout the application
|
| 279 |
|
| 280 |
## Future Enhancements
|
| 281 |
|
| 282 |
+
- Enhanced AI scoring with more sophisticated models
|
| 283 |
+
- Advanced analytics and reporting features
|
| 284 |
+
- More sophisticated assessment types
|
| 285 |
+
- Integration with additional AI providers
|
| 286 |
+
- Performance optimizations for large datasets
|
| 287 |
+
- Unit and integration tests coverage
|
| 288 |
+
- Enhanced error handling and retry mechanisms
|
| 289 |
+
- Rate limiting for API endpoints
|
| 290 |
+
- Audit logging for compliance requirements
|
| 291 |
+
|
| 292 |
+
## Completed TODO Items
|
| 293 |
+
|
| 294 |
+
- ✅ When creating an assessment, questions are now generated using AI based on job requirements and specified question types
|
| 295 |
+
- ✅ All APIs now have clear input/output schemas with enums properly defined and visible in Swagger documentation
|
| 296 |
+
- ✅ Input validation is now done at both the Pydantic schema level and model level
|
| 297 |
+
- ✅ Answers are properly handled as part of the application model rather than as a separate model
|
| 298 |
|
backend/integrations/ai_integration/mistral_generator.py
CHANGED
|
@@ -193,18 +193,42 @@ Job Information:
|
|
| 193 |
if additional_note:
|
| 194 |
job_details += f"- Additional Note: {additional_note}\n"
|
| 195 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 196 |
prompt = f"""
|
| 197 |
You are an assessment generator.
|
| 198 |
|
| 199 |
-
Generate
|
| 200 |
|
| 201 |
{job_details}
|
| 202 |
|
| 203 |
MANDATORY RULES:
|
| 204 |
-
1. Output MUST be a JSON ARRAY with
|
| 205 |
-
2.
|
| 206 |
-
-
|
| 207 |
-
-
|
| 208 |
3. Do NOT include explanations or markdown.
|
| 209 |
4. Follow the schema EXACTLY.
|
| 210 |
|
|
@@ -223,6 +247,12 @@ Rules per type:
|
|
| 223 |
- MCQ → 4 choices + correct_answer as the text of the correct choice
|
| 224 |
- TEXT → correct_answer = null
|
| 225 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 226 |
Return ONLY the JSON array.
|
| 227 |
"""
|
| 228 |
|
|
@@ -240,8 +270,9 @@ Return ONLY the JSON array.
|
|
| 240 |
|
| 241 |
# Determine the question type based on the response
|
| 242 |
if q_data.get("type") == "MCQ":
|
| 243 |
-
# For multiple choice questions
|
| 244 |
-
|
|
|
|
| 245 |
|
| 246 |
# Create options
|
| 247 |
options = []
|
|
@@ -249,7 +280,7 @@ Return ONLY the JSON array.
|
|
| 249 |
option = AssessmentQuestionOption(text=choice, value=choice)
|
| 250 |
options.append(option)
|
| 251 |
|
| 252 |
-
# Find the correct option
|
| 253 |
correct_options = []
|
| 254 |
correct_answer = q_data.get("correct_answer")
|
| 255 |
if correct_answer:
|
|
|
|
| 193 |
if additional_note:
|
| 194 |
job_details += f"- Additional Note: {additional_note}\n"
|
| 195 |
|
| 196 |
+
# Determine the recommended number of questions based on job complexity
|
| 197 |
+
if job_info:
|
| 198 |
+
# Adjust the number of questions based on job seniority and skills
|
| 199 |
+
seniority = job_info.get('seniority', '').lower()
|
| 200 |
+
skill_count = len(job_info.get('skill_categories', []))
|
| 201 |
+
|
| 202 |
+
# Base number of questions based on complexity
|
| 203 |
+
if seniority in ['senior', 'lead']:
|
| 204 |
+
base_questions = 15 # More questions for senior roles
|
| 205 |
+
elif seniority in ['mid', 'intermediate']:
|
| 206 |
+
base_questions = 12
|
| 207 |
+
else: # intern, junior
|
| 208 |
+
base_questions = 10
|
| 209 |
+
|
| 210 |
+
# Adjust based on number of skills to cover
|
| 211 |
+
adjusted_questions = base_questions + (skill_count // 2)
|
| 212 |
+
|
| 213 |
+
# Ensure we have at least one of each requested type if specified
|
| 214 |
+
min_questions = len(questions_types) # At least one per type requested
|
| 215 |
+
total_questions = max(adjusted_questions, min_questions)
|
| 216 |
+
else:
|
| 217 |
+
# Default if no job info is provided
|
| 218 |
+
total_questions = max(10, len(questions_types)) # At least 10 or requested types count
|
| 219 |
+
|
| 220 |
prompt = f"""
|
| 221 |
You are an assessment generator.
|
| 222 |
|
| 223 |
+
Generate approximately {total_questions} questions for the following job. The number of questions should be appropriate for the job complexity and seniority level.
|
| 224 |
|
| 225 |
{job_details}
|
| 226 |
|
| 227 |
MANDATORY RULES:
|
| 228 |
+
1. Output MUST be a JSON ARRAY with approximately {total_questions} objects.
|
| 229 |
+
2. Distribute the questions among the requested types proportionally:
|
| 230 |
+
- Include MCQ questions (multiple choice) - both single and multiple answer types
|
| 231 |
+
- Include TEXT questions (text-based)
|
| 232 |
3. Do NOT include explanations or markdown.
|
| 233 |
4. Follow the schema EXACTLY.
|
| 234 |
|
|
|
|
| 247 |
- MCQ → 4 choices + correct_answer as the text of the correct choice
|
| 248 |
- TEXT → correct_answer = null
|
| 249 |
|
| 250 |
+
Consider the following when generating questions:
|
| 251 |
+
- For senior positions, include more complex and scenario-based questions
|
| 252 |
+
- For junior positions, focus on fundamental concepts
|
| 253 |
+
- Ensure questions cover the skill categories mentioned in the job description
|
| 254 |
+
- Mix difficulty levels appropriately for the role
|
| 255 |
+
|
| 256 |
Return ONLY the JSON array.
|
| 257 |
"""
|
| 258 |
|
|
|
|
| 270 |
|
| 271 |
# Determine the question type based on the response
|
| 272 |
if q_data.get("type") == "MCQ":
|
| 273 |
+
# For multiple choice questions, determine if it's single or multiple choice
|
| 274 |
+
# For now, default to choose_one, but we could enhance this logic later
|
| 275 |
+
question_type = QuestionType.choose_one
|
| 276 |
|
| 277 |
# Create options
|
| 278 |
options = []
|
|
|
|
| 280 |
option = AssessmentQuestionOption(text=choice, value=choice)
|
| 281 |
options.append(option)
|
| 282 |
|
| 283 |
+
# Find the correct option(s)
|
| 284 |
correct_options = []
|
| 285 |
correct_answer = q_data.get("correct_answer")
|
| 286 |
if correct_answer:
|
backend/integrations/ai_integration/mock_ai_generator.py
CHANGED
|
@@ -13,39 +13,65 @@ class MockAIGenerator(AIGeneratorInterface):
|
|
| 13 |
"""
|
| 14 |
|
| 15 |
def generate_questions(
|
| 16 |
-
self,
|
| 17 |
-
title: str,
|
| 18 |
-
questions_types: List[str],
|
| 19 |
-
additional_note: str = None,
|
| 20 |
job_info: Dict[str, Any] = None
|
| 21 |
) -> List[AssessmentQuestion]:
|
| 22 |
"""
|
| 23 |
Generate questions using mock AI logic based on job information.
|
| 24 |
"""
|
| 25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
generated_questions = []
|
| 27 |
-
|
| 28 |
-
for i
|
|
|
|
|
|
|
|
|
|
| 29 |
# Create a question ID
|
| 30 |
question_id = str(uuid.uuid4())
|
| 31 |
-
|
| 32 |
# Generate question text based on the assessment title, job info and question type
|
| 33 |
question_text = self._generate_question_text(title, q_type, i+1, additional_note, job_info)
|
| 34 |
-
|
| 35 |
# Determine weight (random between 1-5)
|
| 36 |
weight = random.randint(1, 5)
|
| 37 |
-
|
| 38 |
# Generate skill categories based on the assessment title and job info
|
| 39 |
skill_categories = self._generate_skill_categories(title, job_info)
|
| 40 |
-
|
| 41 |
# Generate options and correct options based on the question type
|
| 42 |
options = []
|
| 43 |
correct_options = []
|
| 44 |
-
|
| 45 |
if q_type in [QuestionType.choose_one.value, QuestionType.choose_many.value]:
|
| 46 |
options = self._generate_multiple_choice_options(q_type, question_text)
|
| 47 |
correct_options = self._select_correct_options(options, q_type)
|
| 48 |
-
|
| 49 |
# Create the AssessmentQuestion object
|
| 50 |
question = AssessmentQuestion(
|
| 51 |
id=question_id,
|
|
@@ -56,9 +82,9 @@ class MockAIGenerator(AIGeneratorInterface):
|
|
| 56 |
options=options,
|
| 57 |
correct_options=correct_options
|
| 58 |
)
|
| 59 |
-
|
| 60 |
generated_questions.append(question)
|
| 61 |
-
|
| 62 |
return generated_questions
|
| 63 |
|
| 64 |
def _generate_question_text(self, title: str, q_type: str, question_number: int, additional_note: str = None, job_info: Dict[str, Any] = None) -> str:
|
|
|
|
| 13 |
"""
|
| 14 |
|
| 15 |
def generate_questions(
|
| 16 |
+
self,
|
| 17 |
+
title: str,
|
| 18 |
+
questions_types: List[str],
|
| 19 |
+
additional_note: str = None,
|
| 20 |
job_info: Dict[str, Any] = None
|
| 21 |
) -> List[AssessmentQuestion]:
|
| 22 |
"""
|
| 23 |
Generate questions using mock AI logic based on job information.
|
| 24 |
"""
|
| 25 |
+
# Determine the recommended number of questions based on job complexity
|
| 26 |
+
if job_info:
|
| 27 |
+
# Adjust the number of questions based on job seniority and skills
|
| 28 |
+
seniority = job_info.get('seniority', '').lower()
|
| 29 |
+
skill_count = len(job_info.get('skill_categories', []))
|
| 30 |
+
|
| 31 |
+
# Base number of questions based on complexity
|
| 32 |
+
if seniority in ['senior', 'lead']:
|
| 33 |
+
base_questions = 15 # More questions for senior roles
|
| 34 |
+
elif seniority in ['mid', 'intermediate']:
|
| 35 |
+
base_questions = 12
|
| 36 |
+
else: # intern, junior
|
| 37 |
+
base_questions = 10
|
| 38 |
+
|
| 39 |
+
# Adjust based on number of skills to cover
|
| 40 |
+
adjusted_questions = base_questions + (skill_count // 2)
|
| 41 |
+
|
| 42 |
+
# Ensure we have at least one of each requested type if specified
|
| 43 |
+
min_questions = len(questions_types) # At least one per type requested
|
| 44 |
+
total_questions = max(adjusted_questions, min_questions)
|
| 45 |
+
else:
|
| 46 |
+
# Default if no job info is provided
|
| 47 |
+
total_questions = max(10, len(questions_types)) # At least 10 or requested types count
|
| 48 |
+
|
| 49 |
generated_questions = []
|
| 50 |
+
|
| 51 |
+
for i in range(total_questions):
|
| 52 |
+
# Cycle through the requested question types to ensure variety
|
| 53 |
+
q_type = questions_types[i % len(questions_types)]
|
| 54 |
+
|
| 55 |
# Create a question ID
|
| 56 |
question_id = str(uuid.uuid4())
|
| 57 |
+
|
| 58 |
# Generate question text based on the assessment title, job info and question type
|
| 59 |
question_text = self._generate_question_text(title, q_type, i+1, additional_note, job_info)
|
| 60 |
+
|
| 61 |
# Determine weight (random between 1-5)
|
| 62 |
weight = random.randint(1, 5)
|
| 63 |
+
|
| 64 |
# Generate skill categories based on the assessment title and job info
|
| 65 |
skill_categories = self._generate_skill_categories(title, job_info)
|
| 66 |
+
|
| 67 |
# Generate options and correct options based on the question type
|
| 68 |
options = []
|
| 69 |
correct_options = []
|
| 70 |
+
|
| 71 |
if q_type in [QuestionType.choose_one.value, QuestionType.choose_many.value]:
|
| 72 |
options = self._generate_multiple_choice_options(q_type, question_text)
|
| 73 |
correct_options = self._select_correct_options(options, q_type)
|
| 74 |
+
|
| 75 |
# Create the AssessmentQuestion object
|
| 76 |
question = AssessmentQuestion(
|
| 77 |
id=question_id,
|
|
|
|
| 82 |
options=options,
|
| 83 |
correct_options=correct_options
|
| 84 |
)
|
| 85 |
+
|
| 86 |
generated_questions.append(question)
|
| 87 |
+
|
| 88 |
return generated_questions
|
| 89 |
|
| 90 |
def _generate_question_text(self, title: str, q_type: str, question_number: int, additional_note: str = None, job_info: Dict[str, Any] = None) -> str:
|