Python SDK
Official Python SDK for Kai the AI
Overview
The official Python SDK for Kai the AI provides a modern, type-safe interface for integrating intelligent teaching assistance into your Python applications. Built with Python 3.8+ features, the SDK supports both synchronous and asynchronous operations, comprehensive error handling, and follows PEP 8 style guidelines.
Installation
Install the SDK using pip:
pip install kai-sdkFor development installations with optional dependencies:
pip install kai-sdk[dev] # Includes testing and development tools
pip install kai-sdk[async] # Includes async HTTP client dependenciesRequirements
- Python 3.8 or higher
- Active Kai the AI API key
- Internet connection for API requests
Quick Start
Here’s a minimal example to get you started:
from kai_sdk import KaiClient
# Initialize the client
client = KaiClient(api_key="your_api_key_here")
# Grade a student submission
result = client.assignments.grade(
assignment_id="CS101-HW1",
student_submission="The sorting algorithm works by...",
grading_style="detailed"
)
print(f"Score: {result.score}/100")
print(f"Feedback: {result.feedback}")Authentication
API Key Setup
The SDK requires an API key for authentication. You can provide the key in several ways:
export KAI_API_KEY="your_api_key_here"from kai_sdk import KaiClient
# Automatically reads from KAI_API_KEY environment variable
client = KaiClient()from kai_sdk import KaiClient
client = KaiClient(api_key="your_api_key_here")from kai_sdk import KaiClient
import os
# Load from configuration file
with open("config/kai_config.txt") as f:
api_key = f.read().strip()
client = KaiClient(api_key=api_key)Never hardcode API keys in your source code or commit them to version control. Use environment variables or secure configuration management.
Core Classes
KaiClient
The main client class for interacting with Kai’s API.
class KaiClient:
"""
Main client for Kai the AI API.
Args:
api_key: Your API key (defaults to KAI_API_KEY env variable)
base_url: API base URL (default: https://chi2api.com/v1)
timeout: Request timeout in seconds (default: 30)
max_retries: Maximum number of retry attempts (default: 3)
"""
def __init__(
self,
api_key: str | None = None,
base_url: str = "https://chi2api.com/v1",
timeout: int = 30,
max_retries: int = 3
) -> None:
...Attributes:
assignments: Assignment grading operationscontent: Content generation operationsanalytics: Student analytics and performance metricsquizzes: Quiz generation and management
Assignment
Handle assignment grading and feedback operations.
class Assignment:
"""Assignment grading operations."""
def grade(
self,
assignment_id: str,
student_submission: str,
rubric_id: str | None = None,
grading_style: str = "detailed"
) -> GradeResult:
"""
Grade a student submission.
Args:
assignment_id: Unique identifier for the assignment
student_submission: Student's submitted work
rubric_id: Optional rubric to apply
grading_style: "detailed", "concise", or "points_only"
Returns:
GradeResult object containing score and feedback
Raises:
ValidationError: Invalid parameters
RateLimitError: Rate limit exceeded
APIError: API request failed
"""
...
def get_grade(self, grade_id: str) -> GradeResult:
"""Retrieve a previously generated grade."""
...
def batch_grade(
self,
submissions: list[dict]
) -> list[GradeResult]:
"""Grade multiple submissions in a single request."""
...Quiz
Generate and manage quiz content.
class Quiz:
"""Quiz generation and management operations."""
def generate(
self,
topic: str,
difficulty: str = "medium",
question_count: int = 10,
question_types: list[str] | None = None
) -> QuizResult:
"""
Generate quiz questions on a topic.
Args:
topic: Subject matter for quiz questions
difficulty: "easy", "medium", or "hard"
question_count: Number of questions (1-50)
question_types: List of question types to include
Returns:
QuizResult with generated questions
"""
...Analytics
Access student performance data and analytics.
class Analytics:
"""Student analytics and performance metrics."""
def get_student_performance(
self,
student_id: str,
start_date: str | None = None,
end_date: str | None = None,
course_id: str | None = None
) -> PerformanceData:
"""
Retrieve student performance metrics.
Args:
student_id: Student identifier
start_date: ISO 8601 date string (optional)
end_date: ISO 8601 date string (optional)
course_id: Filter by specific course (optional)
Returns:
PerformanceData with metrics and trends
"""
...
def get_class_analytics(
self,
course_id: str,
metric_types: list[str] | None = None
) -> ClassAnalytics:
"""Retrieve aggregate class-level analytics."""
...Response Models
GradeResult
from dataclasses import dataclass
from datetime import datetime
@dataclass
class GradeResult:
"""Result from grading operation."""
grade_id: str
score: int # 0-100
feedback: str
suggestions: list[str]
timestamp: datetime
rubric_breakdown: dict[str, int] | None = None
@property
def passed(self) -> bool:
"""Check if grade meets passing threshold (>= 70)."""
return self.score >= 70QuizResult
@dataclass
class QuizQuestion:
"""Individual quiz question."""
question_id: str
question_text: str
question_type: str
options: list[str] | None = None
correct_answer: str | None = None
explanation: str | None = None
@dataclass
class QuizResult:
"""Result from quiz generation."""
quiz_id: str
topic: str
difficulty: str
questions: list[QuizQuestion]
estimated_time_minutes: intPerformanceData
@dataclass
class PerformanceData:
"""Student performance metrics."""
student_id: str
average_score: float
assignments_completed: int
assignments_total: int
strength_areas: list[str]
improvement_areas: list[str]
trend: str # "improving", "stable", "declining"
last_updated: datetimeComplete API Methods
Assignment Grading
from kai_sdk import KaiClient
from kai_sdk.exceptions import ValidationError, RateLimitError
client = KaiClient(api_key="your_api_key")
try:
# Grade a single submission
result = client.assignments.grade(
assignment_id="CS101-HW1",
student_submission="My algorithm implementation...",
rubric_id="standard_coding_rubric",
grading_style="detailed"
)
print(f"Grade ID: {result.grade_id}")
print(f"Score: {result.score}/100")
print(f"Feedback: {result.feedback}")
if result.rubric_breakdown:
print("\nRubric Breakdown:")
for criterion, points in result.rubric_breakdown.items():
print(f" {criterion}: {points}")
print("\nSuggestions:")
for suggestion in result.suggestions:
print(f" - {suggestion}")
except ValidationError as e:
print(f"Invalid parameters: {e}")
except RateLimitError as e:
print(f"Rate limit exceeded: {e}")import asyncio
from kai_sdk import AsyncKaiClient
async def grade_submission():
async with AsyncKaiClient(api_key="your_api_key") as client:
result = await client.assignments.grade(
assignment_id="CS101-HW1",
student_submission="My algorithm implementation...",
grading_style="detailed"
)
print(f"Score: {result.score}/100")
return result
# Run async function
result = asyncio.run(grade_submission())Batch Grading
Grade multiple submissions efficiently:
from kai_sdk import KaiClient
client = KaiClient()
submissions = [
{
"assignment_id": "CS101-HW1",
"student_id": "student_001",
"student_submission": "First student's work..."
},
{
"assignment_id": "CS101-HW1",
"student_id": "student_002",
"student_submission": "Second student's work..."
},
# ... more submissions
]
results = client.assignments.batch_grade(submissions)
for result in results:
print(f"Student {result.student_id}: {result.score}/100")Quiz Generation
from kai_sdk import KaiClient
client = KaiClient()
quiz = client.quizzes.generate(
topic="Python Data Structures",
difficulty="medium",
question_count=10,
question_types=["multiple_choice", "true_false"]
)
print(f"Quiz ID: {quiz.quiz_id}")
print(f"Estimated time: {quiz.estimated_time_minutes} minutes")
print(f"Questions: {len(quiz.questions)}")
for i, question in enumerate(quiz.questions, 1):
print(f"\nQuestion {i}: {question.question_text}")
if question.options:
for opt in question.options:
print(f" {opt}")import asyncio
from kai_sdk import AsyncKaiClient
async def generate_multiple_quizzes():
async with AsyncKaiClient() as client:
# Generate multiple quizzes concurrently
topics = [
"Python Basics",
"Object-Oriented Programming",
"Data Structures"
]
tasks = [
client.quizzes.generate(
topic=topic,
difficulty="medium",
question_count=5
)
for topic in topics
]
quizzes = await asyncio.gather(*tasks)
return quizzes
quizzes = asyncio.run(generate_multiple_quizzes())
print(f"Generated {len(quizzes)} quizzes")Student Analytics
from kai_sdk import KaiClient
from datetime import datetime, timedelta
client = KaiClient()
# Get performance for the last 30 days
end_date = datetime.now()
start_date = end_date - timedelta(days=30)
performance = client.analytics.get_student_performance(
student_id="student_12345",
start_date=start_date.isoformat(),
end_date=end_date.isoformat(),
course_id="CS101"
)
print(f"Average Score: {performance.average_score:.1f}")
print(f"Completion Rate: {performance.assignments_completed}/{performance.assignments_total}")
print(f"Trend: {performance.trend}")
print("\nStrengths:")
for area in performance.strength_areas:
print(f" ✓ {area}")
print("\nAreas for Improvement:")
for area in performance.improvement_areas:
print(f" ! {area}")Error Handling
The SDK provides specific exception types for different error scenarios:
from kai_sdk import KaiClient
from kai_sdk.exceptions import (
KaiSDKError, # Base exception
ValidationError, # Invalid parameters
AuthenticationError, # Invalid API key
RateLimitError, # Rate limit exceeded
APIError, # General API error
TimeoutError, # Request timeout
)
client = KaiClient()
try:
result = client.assignments.grade(
assignment_id="CS101-HW1",
student_submission="Student work...",
grading_style="detailed"
)
except ValidationError as e:
# Handle invalid parameters
print(f"Invalid input: {e}")
print(f"Details: {e.details}")
except AuthenticationError as e:
# Handle authentication failures
print(f"Authentication failed: {e}")
print("Please check your API key")
except RateLimitError as e:
# Handle rate limiting
print(f"Rate limit exceeded: {e}")
print(f"Retry after: {e.retry_after} seconds")
except TimeoutError as e:
# Handle timeouts
print(f"Request timed out: {e}")
print("Try increasing the timeout parameter")
except APIError as e:
# Handle general API errors
print(f"API error: {e}")
print(f"Status code: {e.status_code}")
print(f"Error code: {e.error_code}")
except KaiSDKError as e:
# Catch-all for SDK errors
print(f"SDK error: {e}")Implement exponential backoff for rate limit errors:
import time
from kai_sdk.exceptions import RateLimitError
max_retries = 3
retry_delay = 1
for attempt in range(max_retries):
try:
result = client.assignments.grade(...)
break
except RateLimitError as e:
if attempt < max_retries - 1:
wait_time = retry_delay * (2 ** attempt)
print(f"Rate limited, waiting {wait_time}s...")
time.sleep(wait_time)
else:
raiseAsync/Await Support
The SDK provides full async support through the AsyncKaiClient:
import asyncio
from kai_sdk import AsyncKaiClient
async def main():
async with AsyncKaiClient(api_key="your_api_key") as client:
# All methods are awaitable
result = await client.assignments.grade(
assignment_id="CS101-HW1",
student_submission="Student work..."
)
print(f"Score: {result.score}")
asyncio.run(main())import asyncio
from kai_sdk import AsyncKaiClient
async def process_multiple_submissions():
async with AsyncKaiClient() as client:
# Grade multiple submissions concurrently
submissions = [
("assignment_1", "submission text 1"),
("assignment_2", "submission text 2"),
("assignment_3", "submission text 3"),
]
tasks = [
client.assignments.grade(
assignment_id=aid,
student_submission=text
)
for aid, text in submissions
]
# Execute all grading requests concurrently
results = await asyncio.gather(*tasks)
for i, result in enumerate(results, 1):
print(f"Submission {i}: {result.score}/100")
asyncio.run(process_multiple_submissions())import asyncio
from kai_sdk import AsyncKaiClient
from kai_sdk.exceptions import RateLimitError, APIError
async def safe_grade(client, assignment_id, submission):
try:
result = await client.assignments.grade(
assignment_id=assignment_id,
student_submission=submission
)
return result
except RateLimitError:
# Wait and retry
await asyncio.sleep(5)
return await safe_grade(client, assignment_id, submission)
except APIError as e:
print(f"Failed to grade: {e}")
return None
async def main():
async with AsyncKaiClient() as client:
result = await safe_grade(
client,
"CS101-HW1",
"Student work..."
)
if result:
print(f"Score: {result.score}")
asyncio.run(main())Rate Limiting and Best Practices
Understanding Rate Limits
Kai enforces the following rate limits based on your plan:
| Plan | Requests/Minute | Requests/Day |
|---|---|---|
| Free | 10 | 1,000 |
| Educator | 60 | 10,000 |
| Institution | 300 | 100,000 |
Handling Rate Limits
The SDK automatically handles rate limiting with exponential backoff:
from kai_sdk import KaiClient
# Configure retry behavior
client = KaiClient(
api_key="your_api_key",
max_retries=5, # Retry up to 5 times
timeout=60 # 60 second timeout
)
# The client will automatically retry on rate limit errors
result = client.assignments.grade(...)Best Practices
Use Batch Operations: Grade multiple submissions in one request
results = client.assignments.batch_grade(submissions)Enable Async for Concurrent Operations: Use
AsyncKaiClientfor parallel requestsasync with AsyncKaiClient() as client: results = await asyncio.gather(*tasks)Implement Caching: Cache frequently accessed data like rubrics
from functools import lru_cache @lru_cache(maxsize=100) def get_rubric(rubric_id): return client.rubrics.get(rubric_id)Monitor Rate Limits: Check response headers for rate limit status
result = client.assignments.grade(...) remaining = client.last_response.headers.get('X-RateLimit-Remaining') print(f"Requests remaining: {remaining}")Use Webhooks for Long Operations: For batch processing, use webhooks instead of polling
Configuration Options
Client Configuration
from kai_sdk import KaiClient
from kai_sdk.config import Config
# Method 1: Direct configuration
client = KaiClient(
api_key="your_api_key",
base_url="https://chi2api.com/v1",
timeout=30,
max_retries=3,
verify_ssl=True,
user_agent="MyApp/1.0"
)
# Method 2: Using Config object
config = Config(
api_key="your_api_key",
timeout=60,
max_retries=5
)
client = KaiClient(config=config)
# Method 3: Environment-based configuration
# Reads from KAI_API_KEY, KAI_BASE_URL, etc.
client = KaiClient.from_env()Logging Configuration
import logging
from kai_sdk import KaiClient
# Enable debug logging
logging.basicConfig(level=logging.DEBUG)
kai_logger = logging.getLogger('kai_sdk')
kai_logger.setLevel(logging.DEBUG)
client = KaiClient()
# Now all SDK operations will log debug information
result = client.assignments.grade(...)Custom HTTP Session
from kai_sdk import KaiClient
import requests
# Create custom session with specific settings
session = requests.Session()
session.headers.update({'X-Custom-Header': 'value'})
session.proxies = {'https': 'http://proxy.example.com:8080'}
client = KaiClient(
api_key="your_api_key",
session=session
)Complete Working Examples
Example 1: Automated Grading Pipeline
#!/usr/bin/env python3
"""
Automated grading pipeline for processing student submissions.
"""
from pathlib import Path
from typing import List
from kai_sdk import KaiClient
from kai_sdk.exceptions import KaiSDKError
import csv
def load_submissions(csv_path: Path) -> List[dict]:
"""Load student submissions from CSV file."""
submissions = []
with open(csv_path) as f:
reader = csv.DictReader(f)
for row in reader:
submissions.append({
'student_id': row['student_id'],
'assignment_id': row['assignment_id'],
'submission_text': row['submission_text']
})
return submissions
def grade_submissions(client: KaiClient, submissions: List[dict]) -> List[dict]:
"""Grade all submissions and return results."""
results = []
for submission in submissions:
try:
result = client.assignments.grade(
assignment_id=submission['assignment_id'],
student_submission=submission['submission_text'],
grading_style='detailed'
)
results.append({
'student_id': submission['student_id'],
'score': result.score,
'feedback': result.feedback,
'suggestions': ', '.join(result.suggestions)
})
print(f"✓ Graded {submission['student_id']}: {result.score}/100")
except KaiSDKError as e:
print(f"✗ Failed to grade {submission['student_id']}: {e}")
results.append({
'student_id': submission['student_id'],
'score': None,
'feedback': f"Error: {e}",
'suggestions': ''
})
return results
def save_results(results: List[dict], output_path: Path):
"""Save grading results to CSV."""
with open(output_path, 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=['student_id', 'score', 'feedback', 'suggestions'])
writer.writeheader()
writer.writerows(results)
print(f"\n✓ Results saved to {output_path}")
def main():
# Initialize client
client = KaiClient()
# Load submissions
submissions = load_submissions(Path('submissions.csv'))
print(f"Loaded {len(submissions)} submissions")
# Grade all submissions
results = grade_submissions(client, submissions)
# Save results
save_results(results, Path('grading_results.csv'))
# Print summary
successful = sum(1 for r in results if r['score'] is not None)
avg_score = sum(r['score'] for r in results if r['score']) / successful
print(f"\n=== Summary ===")
print(f"Total submissions: {len(submissions)}")
print(f"Successfully graded: {successful}")
print(f"Average score: {avg_score:.1f}/100")
if __name__ == '__main__':
main()Example 2: Quiz Generator with Export
#!/usr/bin/env python3
"""
Generate quizzes for multiple topics and export to various formats.
"""
from kai_sdk import KaiClient
from typing import List
import json
def generate_quiz(
client: KaiClient,
topic: str,
difficulty: str = "medium",
count: int = 10
):
"""Generate a quiz for a specific topic."""
quiz = client.quizzes.generate(
topic=topic,
difficulty=difficulty,
question_count=count,
question_types=["multiple_choice", "true_false", "short_answer"]
)
print(f"\n✓ Generated quiz: {topic}")
print(f" ID: {quiz.quiz_id}")
print(f" Questions: {len(quiz.questions)}")
print(f" Time: ~{quiz.estimated_time_minutes} minutes")
return quiz
def export_quiz_to_json(quiz, filename: str):
"""Export quiz to JSON format."""
quiz_data = {
'quiz_id': quiz.quiz_id,
'topic': quiz.topic,
'difficulty': quiz.difficulty,
'estimated_time_minutes': quiz.estimated_time_minutes,
'questions': [
{
'id': q.question_id,
'text': q.question_text,
'type': q.question_type,
'options': q.options,
'correct_answer': q.correct_answer,
'explanation': q.explanation
}
for q in quiz.questions
]
}
with open(filename, 'w') as f:
json.dump(quiz_data, f, indent=2)
print(f"✓ Exported to {filename}")
def export_quiz_to_markdown(quiz, filename: str):
"""Export quiz to Markdown format."""
with open(filename, 'w') as f:
f.write(f"# {quiz.topic} Quiz\n\n")
f.write(f"**Difficulty:** {quiz.difficulty}\n")
f.write(f"**Estimated Time:** {quiz.estimated_time_minutes} minutes\n\n")
f.write("---\n\n")
for i, q in enumerate(quiz.questions, 1):
f.write(f"## Question {i}\n\n")
f.write(f"{q.question_text}\n\n")
if q.options:
for opt in q.options:
f.write(f"- {opt}\n")
f.write("\n")
if q.explanation:
f.write(f"**Explanation:** {q.explanation}\n\n")
f.write("---\n\n")
print(f"✓ Exported to {filename}")
def main():
client = KaiClient()
# Topics to generate quizzes for
topics = [
("Python Fundamentals", "easy", 15),
("Data Structures", "medium", 20),
("Algorithm Design", "hard", 10)
]
for topic, difficulty, count in topics:
# Generate quiz
quiz = generate_quiz(client, topic, difficulty, count)
# Export to different formats
base_name = topic.lower().replace(' ', '_')
export_quiz_to_json(quiz, f"{base_name}_quiz.json")
export_quiz_to_markdown(quiz, f"{base_name}_quiz.md")
print("\n✓ All quizzes generated and exported successfully!")
if __name__ == '__main__':
main()Example 3: Student Analytics Dashboard
#!/usr/bin/env python3
"""
Generate comprehensive student analytics reports.
"""
from kai_sdk import KaiClient
from datetime import datetime, timedelta
from typing import List
import matplotlib.pyplot as plt
from pathlib import Path
def get_class_roster(csv_path: Path) -> List[str]:
"""Load student IDs from roster."""
import csv
with open(csv_path) as f:
reader = csv.DictReader(f)
return [row['student_id'] for row in reader]
def analyze_student(client: KaiClient, student_id: str, course_id: str):
"""Get comprehensive analytics for a student."""
end_date = datetime.now()
start_date = end_date - timedelta(days=90) # Last 90 days
performance = client.analytics.get_student_performance(
student_id=student_id,
start_date=start_date.isoformat(),
end_date=end_date.isoformat(),
course_id=course_id
)
return {
'student_id': student_id,
'average_score': performance.average_score,
'completion_rate': performance.assignments_completed / performance.assignments_total,
'trend': performance.trend,
'strengths': performance.strength_areas,
'improvements': performance.improvement_areas
}
def generate_class_report(analytics_data: List[dict], output_dir: Path):
"""Generate visual report for the class."""
output_dir.mkdir(exist_ok=True)
# Extract data for visualization
scores = [data['average_score'] for data in analytics_data]
completion_rates = [data['completion_rate'] * 100 for data in analytics_data]
# Create visualizations
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
# Score distribution
ax1.hist(scores, bins=10, edgecolor='black')
ax1.set_xlabel('Average Score')
ax1.set_ylabel('Number of Students')
ax1.set_title('Score Distribution')
ax1.axvline(sum(scores)/len(scores), color='red', linestyle='--', label='Class Average')
ax1.legend()
# Completion rate distribution
ax2.hist(completion_rates, bins=10, edgecolor='black')
ax2.set_xlabel('Completion Rate (%)')
ax2.set_ylabel('Number of Students')
ax2.set_title('Assignment Completion Distribution')
plt.tight_layout()
plt.savefig(output_dir / 'class_analytics.png', dpi=300, bbox_inches='tight')
print(f"✓ Saved visualization to {output_dir / 'class_analytics.png'}")
# Generate text report
with open(output_dir / 'class_report.txt', 'w') as f:
f.write("CLASS ANALYTICS REPORT\n")
f.write("=" * 50 + "\n\n")
f.write(f"Total Students: {len(analytics_data)}\n")
f.write(f"Class Average: {sum(scores)/len(scores):.1f}\n")
f.write(f"Average Completion Rate: {sum(completion_rates)/len(completion_rates):.1f}%\n\n")
# Students by trend
improving = sum(1 for d in analytics_data if d['trend'] == 'improving')
stable = sum(1 for d in analytics_data if d['trend'] == 'stable')
declining = sum(1 for d in analytics_data if d['trend'] == 'declining')
f.write("Student Trends:\n")
f.write(f" Improving: {improving} ({improving/len(analytics_data)*100:.1f}%)\n")
f.write(f" Stable: {stable} ({stable/len(analytics_data)*100:.1f}%)\n")
f.write(f" Declining: {declining} ({declining/len(analytics_data)*100:.1f}%)\n\n")
# Students needing attention
f.write("Students Needing Attention:\n")
for data in analytics_data:
if data['average_score'] < 70 or data['trend'] == 'declining':
f.write(f" - {data['student_id']}: Score {data['average_score']:.1f}, {data['trend']}\n")
print(f"✓ Saved report to {output_dir / 'class_report.txt'}")
def main():
client = KaiClient()
course_id = "CS101"
# Load student roster
student_ids = get_class_roster(Path('roster.csv'))
print(f"Analyzing {len(student_ids)} students...")
# Gather analytics for all students
analytics_data = []
for student_id in student_ids:
try:
data = analyze_student(client, student_id, course_id)
analytics_data.append(data)
print(f"✓ Analyzed {student_id}")
except Exception as e:
print(f"✗ Failed to analyze {student_id}: {e}")
# Generate comprehensive report
output_dir = Path('analytics_report')
generate_class_report(analytics_data, output_dir)
print(f"\n✓ Analytics complete! Check {output_dir} for results")
if __name__ == '__main__':
main()Type Hints and Modern Python
The SDK leverages modern Python features for better type safety:
from typing import Optional, Union, List, Dict, Any
from kai_sdk import KaiClient
from kai_sdk.models import GradeResult
def process_grade(
client: KaiClient,
assignment_id: str,
submission: str,
rubric_id: Optional[str] = None
) -> Union[GradeResult, None]:
"""
Type-safe grading function with proper annotations.
Args:
client: Initialized KaiClient instance
assignment_id: Assignment identifier
submission: Student submission text
rubric_id: Optional rubric identifier
Returns:
GradeResult if successful, None if failed
"""
try:
result = client.assignments.grade(
assignment_id=assignment_id,
student_submission=submission,
rubric_id=rubric_id
)
return result
except Exception as e:
print(f"Grading failed: {e}")
return None
# Type checkers (mypy, pyright) will validate all types
result: Optional[GradeResult] = process_grade(
client=client,
assignment_id="CS101-HW1",
submission="Student work..."
)
if result is not None:
score: int = result.score
print(f"Score: {score}")Links and Resources
SDK Resources
- GitHub Repository - Source code and issues
- PyPI Package - Package distribution
- Changelog - Version history
- Examples - More code examples
Support
- API Status: status.kaitheai.com
- Developer Forum: forum.kaitheai.com
- Email: developers@chi2labs.com
Star the GitHub repository to receive notifications about new releases and features.