wangdl d1b3ac160a fix(ios): QuizGenerateRequest Codable 替代 [String: Any]
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-30 09:06:36 +08:00

638 lines
14 KiB
Swift

//
// APIModels.swift - api-server
//
import Foundation
// MARK: - API Envelope (ResponseInterceptor wraps all responses)
struct APIEnvelope<T: Decodable>: Decodable {
let success: Bool
let data: T
let timestamp: String?
}
// MARK: - Pagination
struct PaginationMeta: Codable {
let page: Int
let limit: Int
let total: Int
}
struct PaginatedResponse<T: Decodable>: Decodable {
let data: [T]
let meta: PaginationMeta
}
// MARK: - Waitlist
struct WaitlistEntry: Codable, Identifiable {
let id: String
let nickname: String?
let email: String
let devices: [String]?
let interests: [String]?
let painpoint: String?
let willingBeta: Bool?
let createdAt: String?
}
struct WaitlistCreateRequest: Codable {
let email: String
let nickname: String?
let devices: [String]?
let interests: [String]?
let painpoint: String?
let willingBeta: Bool?
init(email: String, nickname: String? = nil, devices: [String]? = nil,
interests: [String]? = nil, painpoint: String? = nil, willingBeta: Bool = true) {
self.email = email
self.nickname = nickname
self.devices = devices
self.interests = interests
self.painpoint = painpoint
self.willingBeta = willingBeta
}
}
struct WaitlistResponse: Codable {
let success: Bool?
let message: String?
let data: WaitlistEntry?
}
struct WaitlistStats: Codable {
let total: Int?
let today: Int?
let deviceBreakdown: [String: Int]?
let interestBreakdown: [String: Int]?
}
// MARK: - Auth
struct AuthResponse: Codable {
let accessToken: String
let refreshToken: String?
let user: AuthUser?
}
struct AuthUser: Codable, Identifiable {
let id: String
let email: String?
let nickname: String?
let avatarUrl: String?
let role: String?
let status: String?
let onboardingCompleted: Bool?
}
struct AppleAuthRequest: Codable {
let identityToken: String
let authorizationCode: String?
let fullName: AppleFullName?
let nonce: String?
struct AppleFullName: Codable {
let givenName: String?
let familyName: String?
}
}
struct RefreshRequest: Codable {
let refreshToken: String
}
// MARK: - User Profile (matches GET /users/me with include: profile + preferences)
struct UserProfileResponse: Codable, Identifiable {
let id: String
let email: String?
let nickname: String?
let avatarUrl: String?
let role: String?
let status: String?
let onboardingCompleted: Bool?
let createdAt: String?
let profile: UserProfileData?
let preferences: UserPreferences?
}
struct UserProfileData: Codable {
let learningIdentity: String?
let learningDirection: String?
let bio: String?
let currentGoal: String?
}
struct UserPreferences: Codable, Equatable {
let preferredMethods: [String]?
let defaultFocusMinutes: Int?
let aiSuggestionLevel: String?
let language: String?
let appearance: String?
let notificationEnabled: Bool?
}
struct UpdateProfileRequest: Codable {
let nickname: String?
let avatarUrl: String?
}
struct UpdatePreferencesRequest: Codable {
let preferredMethods: [String]?
let defaultFocusMinutes: Int?
let aiSuggestionLevel: String?
let language: String?
let appearance: String?
let notificationEnabled: Bool?
}
struct UpdateProfileDataRequest: Codable {
let learningIdentity: String?
let learningDirection: String?
let bio: String?
let currentGoal: String?
}
// MARK: - Knowledge Base (matches Prisma KnowledgeBase model)
struct KnowledgeBase: Codable, Identifiable {
let id: String
let userId: String?
let title: String
let description: String?
let coverKey: String?
let coverUrl: String?
let coverType: String?
let visibility: String?
let isPinned: Bool?
let ownerType: String?
let isVerified: Bool?
let status: String?
let itemCount: Int?
let lastStudiedAt: String?
let createdAt: String?
let updatedAt: String?
}
struct CreateKnowledgeBaseRequest: Codable {
let title: String
let description: String?
var coverKey: String? = nil
}
struct KnowledgeBaseCoverUploadResult {
let fileId: String
let objectKey: String
}
// MARK: - Knowledge Items (matches Prisma KnowledgeItem model)
struct KnowledgeItem: Codable, Identifiable, Hashable {
let id: String
let userId: String?
let knowledgeBaseId: String?
let parentId: String?
let itemType: String?
let title: String
let content: String?
let summary: String?
let sourceType: String?
let sourceRef: String?
let orderIndex: Int?
let status: String?
let createdAt: String?
let updatedAt: String?
}
struct CreateKnowledgeItemRequest: Codable {
let knowledgeBaseId: String
let title: String
let content: String?
let itemType: String?
}
struct UpdateKnowledgeItemRequest: Codable {
let title: String?
let content: String?
let summary: String?
}
// MARK: - Active Recall (matches ActiveRecallQuestion / Answer models)
struct ActiveRecallQuestion: Codable, Identifiable {
let id: String
let userId: String?
let knowledgeItemId: String?
let questionText: String
let difficulty: String?
let createdBy: String?
let createdAt: String?
}
struct ActiveRecallAnswer: Codable, Identifiable {
let id: String
let userId: String?
let questionId: String?
let answerType: String?
let answerText: String?
let submittedAt: String?
}
struct SubmitAnswerRequest: Codable {
let answerText: String
}
// MARK: - AI Analysis (matches AiAnalysisResult model)
struct AIAnalysisRequest: Codable {
let questionText: String?
let knowledgeItemContent: String?
let userAnswer: String?
let text: String?
let type: String?
}
struct AIAnalysisResult: Codable, Identifiable {
let id: String
let userId: String?
let summary: String?
let masteryScore: Int?
let strengths: [String]?
let weaknesses: [String]?
let suggestions: [String]?
let nextActions: [String]?
let rawResult: AIAnalysisRawResult?
let createdAt: String?
}
struct AIAnalysisRawResult: Codable {
let score: Double?
let analysis: String?
let focusItems: [String]?
}
// MARK: - Learning Session (matches Prisma LearningSession model)
struct LearningSession: Codable, Identifiable {
let id: String
let userId: String?
let knowledgeBaseId: String?
let knowledgeItemId: String?
let mode: String?
let status: String?
let startedAt: String?
let endedAt: String?
let durationSeconds: Int?
let focusMinutes: Int?
let createdAt: String?
}
struct CreateLearningSessionRequest: Codable {
let knowledgeBaseId: String?
let knowledgeItemId: String?
let mode: String?
}
// MARK: - Review (matches ReviewCard / ReviewLog models)
struct ReviewCard: Codable, Identifiable {
let id: String
let userId: String?
let knowledgeItemId: String?
let frontText: String
let backText: String?
let difficulty: String?
let status: String?
let nextReviewAt: String?
let intervalDays: Int?
let easeFactor: Double?
let repetitionCount: Int?
let lapseCount: Int?
}
struct SubmitReviewRequest: Codable {
let rating: String
let responseText: String?
}
// MARK: - Focus Items (matches Prisma FocusItem model)
struct FocusItem: Codable, Identifiable {
let id: String
let userId: String?
let knowledgeBaseId: String?
let knowledgeItemId: String?
let title: String
let reason: String?
let suggestion: String?
let priority: String?
let status: String?
let masteryScore: Int?
let dueAt: String?
let completedAt: String?
let createdAt: String?
}
// MARK: - Activity (matches DailyLearningActivity + summary aggregation)
struct ActivitySummary: Codable {
let totalMinutes: Int?
let totalCardsReviewed: Int?
let activeDays: Int?
let dailyAverage: Int?
}
struct ActivityHeatmap: Codable {
// Dictionary of "YYYY-MM-DD" -> durationSeconds
}
// MARK: - Feedback
struct FeedbackCreateRequest: Codable {
let category: String
let content: String
let email: String?
init(category: String = "general", content: String, email: String? = nil) {
self.category = category
self.content = content
self.email = email
}
}
struct FeedbackData: Codable, Identifiable {
let id: String?
let category: String?
let content: String?
let status: String?
let createdAt: String?
}
// MARK: - Notifications (matches Prisma Notification model)
struct NotificationItem: Codable, Identifiable {
let id: String
let userId: String?
let type: String
let title: String
let content: String?
let data: [String: String]?
let readAt: String?
let createdAt: String?
}
// MARK: - Generic
struct GenericSuccessResponse: Codable {
let success: Bool?
let message: String?
}
struct BatchDeleteResponse: Codable {
let success: Bool?
let message: String?
let count: Int?
}
// MARK: - Quiz
struct Quiz: Codable, Identifiable {
let id: String
let knowledgeBaseId: String?
let title: String?
let description: String?
let questionCount: Int?
let sourceType: String?
let status: String?
let createdAt: String?
let questions: [QuizQuestion]?
}
struct QuizQuestion: Codable, Identifiable {
let id: String
let quizId: String?
let type: String?
let stem: String?
let options: [String]?
let answer: String?
let explanation: String?
let orderIndex: Int?
}
struct QuizAttempt: Codable, Identifiable {
let id: String
let quizId: String?
let totalQuestions: Int?
let correctCount: Int?
let score: Int?
let startedAt: String?
let finishedAt: String?
let answers: [QuizAnswer]?
let quiz: QuizInfo?
}
struct QuizInfo: Codable { let title: String? }
struct QuizAnswer: Codable, Identifiable {
let id: String
let attemptId: String?
let questionId: String?
let userAnswer: String?
let isCorrect: Bool?
let answeredAt: String?
let question: QuizQuestion?
}
struct QuizGenerateRequest: Codable {
let knowledgeBaseId: String
let questionCount: Int
}
struct QuizSubmitRequest: Codable {
let attemptId: String
let answers: [QuizAnswerItem]
}
struct QuizAnswerItem: Codable {
let questionId: String
let answer: String
}
struct QuizSubmitResponse: Codable {
let score: Int?
let correctCount: Int?
let totalQuestions: Int?
let finishedAt: String?
}
// MARK: - RAG Chat
struct ChatSession: Codable, Identifiable {
let id: String
let userId: String?
let knowledgeBaseId: String?
let title: String?
let createdAt: String?
let updatedAt: String?
}
struct ChatMessage: Codable, Identifiable {
let id: String
let sessionId: String?
let role: String
let content: String
let tokens: Int?
let createdAt: String?
let citations: [ChatCitation]?
}
struct ChatCitation: Codable, Identifiable {
let id: String
let chunkId: String?
let sourceTitle: String?
let excerptText: String?
let pageNumber: Int?
}
struct CreateSessionRequest: Codable {
let knowledgeBaseId: String
let title: String?
}
struct SendMessageRequest: Codable {
let content: String
}
struct SendMessageResponse: Codable {
let id: String?
let role: String?
let content: String?
let tokens: Int?
let blocked: Bool?
let message: String?
let citations: [ChatCitation]?
}
// MARK: - Document Import
struct CreateImportRequest: Codable {
let knowledgeBaseId: String
let fileName: String?
let sourceType: String?
let rawText: String?
}
struct ImportStatusResponse: Codable {
let id: String
let status: String?
let fileName: String?
let knowledgeBaseId: String?
let errorMessage: String?
let itemCount: Int?
}
// MARK: - Import Candidate
struct ImportCandidate: Codable, Identifiable {
let id: String
let sourceId: String?
let title: String?
let content: String?
let status: String?
let confidence: Double?
let createdAt: String?
}
struct BatchAcceptRequest: Codable {
let sourceId: String
}
// MARK: - Knowledge Source
struct KnowledgeSource: Codable, Identifiable {
let id: String
let knowledgeBaseId: String?
let title: String?
let originalFilename: String?
let type: String?
let mimeType: String?
let parseStatus: String?
let indexStatus: String?
let textLength: Int?
let createdAt: String?
}
struct AddSourceRequest: Codable {
let fileId: String?
let type: String?
let title: String?
}
// MARK: - Learning Activity
struct ActivityTrend: Codable {
let date: String?
let value: Double?
let label: String?
}
struct ActivityStreak: Codable {
let currentStreak: Int?
let longestStreak: Int?
let lastActiveDate: String?
}
struct ActivityRecommendation: Codable, Identifiable {
var id: String { title ?? UUID().uuidString }
let title: String?
let description: String?
let type: String?
let priority: String?
}
// MARK: - File Upload (COS presigned URL flow)
struct FileUploadUrlRequest: Codable {
let filename: String
let mimeType: String
let sizeBytes: Int
}
struct FileUploadUrlResponse: Codable {
let uploadUrl: String
let objectKey: String
let bucket: String
let region: String
let expiresIn: Int
}
struct FileConfirmUploadRequest: Codable {
let objectKey: String
let checksum: String?
}
struct FileConfirmUploadResponse: Codable {
let id: String
let filename: String
let objectKey: String
let sizeBytes: Int
}
struct FileDetailResponse: Codable {
let file: FileInfo
let downloadUrl: String
}
struct FileInfo: Codable {
let id: String
let filename: String
let mimeType: String?
let sizeBytes: Int
let objectKey: String?
let storagePath: String?
let createdAt: String?
}