- ✨AI Generated
+ {quizState.current.from === 'generated'
+ ? '⚡新しい問題'
+ : quizState.current.from === 'missed'
+ ? '📝再チャレンジ'
+ : '😒低正答率'}
diff --git a/src/islands/ai-quiz/index.qwik.tsx b/src/islands/ai-quiz/index.qwik.tsx
index 3011d9d7..1f5f4338 100644
--- a/src/islands/ai-quiz/index.qwik.tsx
+++ b/src/islands/ai-quiz/index.qwik.tsx
@@ -23,11 +23,14 @@ export default component$<{
noteLoadType: props.noteLoadType,
rangeNotes: new Set(),
+
+ lastMissedQuizIds: [],
})
useContextProvider(SCREEN_STATE_CTX, screenState)
const settings = useStore({
- quizzes: 5,
+ quizzesByRound: 5,
+ lowRateQuizzesInRound: 1,
})
useContextProvider(SETTINGS_CTX, settings)
diff --git a/src/islands/ai-quiz/storage.ts b/src/islands/ai-quiz/storage.ts
new file mode 100644
index 00000000..fc86bc7f
--- /dev/null
+++ b/src/islands/ai-quiz/storage.ts
@@ -0,0 +1,45 @@
+import Dexie from 'dexie'
+import type { QuizContent } from './constants'
+
+type SerializedQuiz = {
+ type: 'select'
+} & QuizContent
+
+export interface QuizzesByNote {
+ id?: number
+
+ targetNotebook: string
+
+ quiz: SerializedQuiz
+
+ rateSource: {
+ /**
+ * 正答数
+ */
+ correct: number
+ /**
+ * 出題数
+ */
+ total: number
+ }
+
+ rate: number
+
+ noteId: string
+
+ noteTimestamp: number
+}
+
+export class QuizDB extends Dexie {
+ quizzesByNote: Dexie.Table
+ constructor() {
+ super('quizzesByNote')
+
+ this.version(1).stores({
+ quizzesByNote:
+ 'id++, targetNotebook, noteId, quiz, rateSource, rate, noteTimestamp',
+ })
+
+ this.quizzesByNote = this.table('quizzesByNote')
+ }
+}
diff --git a/src/islands/ai-quiz/store.ts b/src/islands/ai-quiz/store.ts
index 755fd66d..342efdb4 100644
--- a/src/islands/ai-quiz/store.ts
+++ b/src/islands/ai-quiz/store.ts
@@ -10,6 +10,8 @@ export interface Quiz {
content: QuizContent
source: TextNoteData
+
+ id: number
}
export interface ScreenState {
@@ -32,31 +34,39 @@ export interface ScreenState {
* 出題範囲
*/
rangeNotes: Set
+
+ lastMissedQuizIds: number[]
}
-export interface QuizState {
+export type QuizFrom = 'generated' | 'missed' | 'lowRate'
+export type QuizState = {
correctQuizzes: Quiz[]
incorrectQuizzes: Quiz[]
generatedQuizzes: number
- quizzes: Quiz[]
+ quizzes: {
+ quiz: Quiz
+ from: QuizFrom
+ }[]
current: {
index: number
quiz: Quiz
choices: string[]
+ from: QuizFrom
} | null
- goalQuestions: number
-
isFinished: boolean
finishedQuizIndexes: Set
+
+ lastMissedQuizzes: number
}
export interface Settings {
- quizzes: number
+ quizzesByRound: number
+ lowRateQuizzesInRound: number
}
export const SCREEN_STATE_CTX = createContextId('screenState')
diff --git a/src/islands/app/CreateNote.qwik.tsx b/src/islands/app/CreateNote.qwik.tsx
index 2f18a8a8..79a84aef 100644
--- a/src/islands/app/CreateNote.qwik.tsx
+++ b/src/islands/app/CreateNote.qwik.tsx
@@ -48,6 +48,7 @@ export const CreateNote = component$(() => {
canToJsonData: {
html: 'これは新しいノートである',
},
+ timestamp: Date.now(),
},
]))
diff --git a/src/islands/note/App.tsx b/src/islands/note/App.tsx
index 95a2ffdc..0f7870ab 100644
--- a/src/islands/note/App.tsx
+++ b/src/islands/note/App.tsx
@@ -42,6 +42,7 @@ export default (props: Props) => {
},
type: 'text',
id: crypto.randomUUID(),
+ timestamp: Date.now(),
}) as Note,
...notes.notes(),
])
diff --git a/src/islands/note/components/notes-utils.ts b/src/islands/note/components/notes-utils.ts
index a193c0be..9181f07d 100644
--- a/src/islands/note/components/notes-utils.ts
+++ b/src/islands/note/components/notes-utils.ts
@@ -24,6 +24,10 @@ export interface NoteData {
* ID
*/
id: string
+ /**
+ * 更新日
+ */
+ timestamp: number
}
export interface NoteComponentProps {
diff --git a/src/islands/note/components/notes/ImageNote/create.ts b/src/islands/note/components/notes/ImageNote/create.ts
index 3e0ced6d..d5910b8c 100644
--- a/src/islands/note/components/notes/ImageNote/create.ts
+++ b/src/islands/note/components/notes/ImageNote/create.ts
@@ -18,6 +18,7 @@ export const createImageNote = (initNoteData?: ImageNoteData) => {
},
type: 'image',
id: crypto.randomUUID(),
+ timestamp: Date.now(),
},
)
const addNote: Note = {
diff --git a/src/islands/note/components/notes/TextNote/TextNote.tsx b/src/islands/note/components/notes/TextNote/TextNote.tsx
index 38f014cc..1d13013f 100644
--- a/src/islands/note/components/notes/TextNote/TextNote.tsx
+++ b/src/islands/note/components/notes/TextNote/TextNote.tsx
@@ -98,6 +98,7 @@ export const TextNote = ((props) => {
}
})
const saveContent = () => {
+ props.setNoteData('timestamp', Date.now())
props.setNoteData('canToJsonData', 'html', getEditor()?.getHTML() || '')
props.updated()
}
@@ -193,7 +194,6 @@ export const TextNote = ((props) => {
}
const paragraphId = Math.random().toString()
editor.commands.setNode('llmpreview', { id: paragraphId })
- console.log(editor, paragraphId)
const pre = editor.$node('llmpreview', { id: paragraphId })!
pre.content = '生成中...'
let rawText = ''
diff --git a/src/islands/note/components/notes/TextNote/create.ts b/src/islands/note/components/notes/TextNote/create.ts
index d137f76f..7dcef263 100644
--- a/src/islands/note/components/notes/TextNote/create.ts
+++ b/src/islands/note/components/notes/TextNote/create.ts
@@ -18,6 +18,7 @@ export const createTextNote = (initNoteData?: TextNoteData) => {
},
type: 'text',
id: crypto.randomUUID(),
+ timestamp: Date.now(),
},
)
const addNote: Note = {
diff --git a/src/islands/note/utils/file-format/index.ts b/src/islands/note/utils/file-format/index.ts
index 7f4d22bf..d970ee9c 100644
--- a/src/islands/note/utils/file-format/index.ts
+++ b/src/islands/note/utils/file-format/index.ts
@@ -55,6 +55,8 @@ export const saveNoteDatas = async (noteDatas: NoteData[]): Promise => {
blobMimetypes,
noteData: thisNoteData.canToJsonData,
+
+ timestamp: thisNoteData.timestamp,
}
})()
fileTree[`${baseNoteDir}/note.json`] = textEncoder.encode(
@@ -185,6 +187,7 @@ export const load = async (data: Blob): Promise => {
blobs,
type: noteDefineJsonData.type,
id: id,
+ timestamp: noteDefineJsonData.timestamp,
} as MargedNoteData)
}
return {
diff --git a/src/islands/note/utils/file-format/manifest-schema.ts b/src/islands/note/utils/file-format/manifest-schema.ts
index 7c29187f..a4135edb 100644
--- a/src/islands/note/utils/file-format/manifest-schema.ts
+++ b/src/islands/note/utils/file-format/manifest-schema.ts
@@ -9,6 +9,9 @@ import {
record,
unknown,
pipe,
+ number,
+ optional,
+ type InferOutput,
} from 'valibot'
/**
@@ -36,5 +39,8 @@ export const note0 = object({
blobMimetypes: record(string(), string()),
noteData: unknown(),
+
+ // If undefined, fallback 0
+ timestamp: optional(number(), 0),
})
-export type Note0 = InferInput
+export type Note0 = InferOutput
diff --git a/src/utils/hash.ts b/src/utils/hash.ts
new file mode 100644
index 00000000..deea19d5
--- /dev/null
+++ b/src/utils/hash.ts
@@ -0,0 +1,9 @@
+const encoder = new TextEncoder()
+export const sha256 = async (data: Uint8Array | string): Promise => {
+ const hashBuffer = await crypto.subtle.digest(
+ 'SHA-256',
+ typeof data === 'string' ? encoder.encode(data) : data,
+ )
+ const hashArray = Array.from(new Uint8Array(hashBuffer))
+ return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('')
+}