feat: Enhance AI suggestion functionality in ImportClient and improve compactLine handling
Build and Push Reader Image / docker (push) Successful in 42s
Build and Push Reader Image / docker (push) Successful in 42s
This commit is contained in:
@@ -56,6 +56,7 @@ export function ImportClient() {
|
|||||||
const [parseError, setParseError] = useState("")
|
const [parseError, setParseError] = useState("")
|
||||||
|
|
||||||
const [aiLoading, setAiLoading] = useState(false)
|
const [aiLoading, setAiLoading] = useState(false)
|
||||||
|
const [aiModel, setAiModel] = useState("")
|
||||||
const [importing, setImporting] = useState(false)
|
const [importing, setImporting] = useState(false)
|
||||||
const [result, setResult] = useState<Record<string, unknown> | null>(null)
|
const [result, setResult] = useState<Record<string, unknown> | null>(null)
|
||||||
|
|
||||||
@@ -237,16 +238,19 @@ export function ImportClient() {
|
|||||||
form.append("preview", "true")
|
form.append("preview", "true")
|
||||||
form.append("splitMode", splitMode)
|
form.append("splitMode", splitMode)
|
||||||
if (splitMode === "regex") form.append("chapterRegex", chapterStartPattern)
|
if (splitMode === "regex") form.append("chapterRegex", chapterStartPattern)
|
||||||
const res = await fetch("/api/mod/epub", { method: "POST", credentials: "include", body: form })
|
form.append("title", title)
|
||||||
|
form.append("authorName", author)
|
||||||
|
const res = await fetch("/api/mod/epub/ai-suggest", { method: "POST", credentials: "include", body: form })
|
||||||
const data = await res.json()
|
const data = await res.json()
|
||||||
if (!res.ok) throw new Error(data?.detail || "AI suggest failed")
|
if (!res.ok) throw new Error(data?.detail || "AI suggest failed")
|
||||||
const suggestedGenres: string[] = (data?.novel?.detectedGenres || []).slice(0, 6)
|
const suggestedGenres: string[] = (data?.suggestedGenres || []).slice(0, 6)
|
||||||
|
setAiModel(String(data?.model || data?.source || ""))
|
||||||
setGenreQuery("")
|
setGenreQuery("")
|
||||||
if (suggestedGenres.length > 0) {
|
if (suggestedGenres.length > 0) {
|
||||||
const ensuredIds = await ensureGenreIdsByNames(suggestedGenres)
|
const ensuredIds = await ensureGenreIdsByNames(suggestedGenres)
|
||||||
setSelectedGenreIds(ensuredIds)
|
setSelectedGenreIds(ensuredIds)
|
||||||
}
|
}
|
||||||
if (!shortDescription) setShortDescription(data?.novel?.description || "")
|
setShortDescription(data?.shortDescription || "")
|
||||||
toast.success("Đã áp dụng gợi ý AI")
|
toast.success("Đã áp dụng gợi ý AI")
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast.error(error instanceof Error ? error.message : "AI suggest lỗi")
|
toast.error(error instanceof Error ? error.message : "AI suggest lỗi")
|
||||||
@@ -480,6 +484,7 @@ export function ImportClient() {
|
|||||||
<Button variant="outline" onClick={onAiSuggest} disabled={aiLoading}>{aiLoading ? <Loader2 className="h-4 w-4 animate-spin" /> : <Sparkles className="h-4 w-4" />} AI gợi ý</Button>
|
<Button variant="outline" onClick={onAiSuggest} disabled={aiLoading}>{aiLoading ? <Loader2 className="h-4 w-4 animate-spin" /> : <Sparkles className="h-4 w-4" />} AI gợi ý</Button>
|
||||||
<Button onClick={onSaveReview}>Lưu & sang bước 3</Button>
|
<Button onClick={onSaveReview}>Lưu & sang bước 3</Button>
|
||||||
</div>
|
</div>
|
||||||
|
{aiModel && <p className="text-xs text-muted-foreground">AI model: {aiModel}</p>}
|
||||||
</section>
|
</section>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ function sourceClass(source: HotCarouselItem["hotSource"]) {
|
|||||||
return "border-primary/30 bg-primary/20 text-primary"
|
return "border-primary/30 bg-primary/20 text-primary"
|
||||||
}
|
}
|
||||||
|
|
||||||
function compactLine(text: string, max = 180) {
|
function compactLine(text: string | null | undefined, max = 180) {
|
||||||
const normalized = text.replace(/\s+/g, " ").trim()
|
const normalized = String(text || "").replace(/\s+/g, " ").trim()
|
||||||
if (normalized.length <= max) return normalized
|
if (normalized.length <= max) return normalized
|
||||||
return `${normalized.slice(0, max).trim()}...`
|
return `${normalized.slice(0, max).trim()}...`
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user