Spaces:
Build error
Build error
Commit ·
7844eee
1
Parent(s): 517964f
demo 效果展示,方便 hf 部署浏览
Browse files- src/app/api/documents/[id]/route.ts +5 -3
- src/app/api/documents/route.ts +5 -3
- src/app/api/history/sessions/route.ts +3 -2
- src/app/knowledge/page.tsx +24 -7
- src/hooks/useChatHistory.ts +2 -1
- 备注.md +0 -9
src/app/api/documents/[id]/route.ts
CHANGED
|
@@ -1,17 +1,19 @@
|
|
| 1 |
-
import { NextResponse } from 'next/server';
|
| 2 |
import db from '@/lib/db';
|
| 3 |
|
| 4 |
export async function GET(
|
| 5 |
-
request:
|
| 6 |
{ params }: { params: Promise<{ id: string }> }
|
| 7 |
) {
|
| 8 |
try {
|
| 9 |
const resolvedParams = await params;
|
| 10 |
const { id } = resolvedParams;
|
|
|
|
| 11 |
|
| 12 |
// DEMO DATA HANDLER
|
| 13 |
-
if (id.startsWith('demo/')) {
|
| 14 |
// Return static content for demo docs
|
|
|
|
| 15 |
const demoDocs: Record<string, any> = {
|
| 16 |
'demo/kb1/doc1': {
|
| 17 |
id: 'demo/kb1/doc1',
|
|
|
|
| 1 |
+
import { NextRequest, NextResponse } from 'next/server';
|
| 2 |
import db from '@/lib/db';
|
| 3 |
|
| 4 |
export async function GET(
|
| 5 |
+
request: NextRequest,
|
| 6 |
{ params }: { params: Promise<{ id: string }> }
|
| 7 |
) {
|
| 8 |
try {
|
| 9 |
const resolvedParams = await params;
|
| 10 |
const { id } = resolvedParams;
|
| 11 |
+
const isDemoMode = request.nextUrl.searchParams.get('mode') === 'demo';
|
| 12 |
|
| 13 |
// DEMO DATA HANDLER
|
| 14 |
+
if (isDemoMode || id.startsWith('demo/')) {
|
| 15 |
// Return static content for demo docs
|
| 16 |
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
| 17 |
const demoDocs: Record<string, any> = {
|
| 18 |
'demo/kb1/doc1': {
|
| 19 |
id: 'demo/kb1/doc1',
|
src/app/api/documents/route.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
| 1 |
|
| 2 |
-
import { NextResponse } from 'next/server';
|
| 3 |
import db from '@/lib/db';
|
| 4 |
import { startYuqueSync, getSyncStatus } from '@/lib/yuque-service';
|
| 5 |
|
| 6 |
-
export async function GET() {
|
| 7 |
try {
|
|
|
|
|
|
|
| 8 |
// Select all columns EXCEPT content_preview to reduce payload size, but include length for stats
|
| 9 |
// Use word_count if available (more accurate), otherwise fallback to 0 (will be updated on next sync)
|
| 10 |
const docs = db.prepare(`
|
|
@@ -21,7 +23,7 @@ export async function GET() {
|
|
| 21 |
|
| 22 |
// DEMO DATA FALLBACK
|
| 23 |
// If database is empty or connection fails, return static demo data for HuggingFace/Demo purposes
|
| 24 |
-
if (docs.length === 0 && kbs.length === 0) {
|
| 25 |
return NextResponse.json({
|
| 26 |
documents: [
|
| 27 |
{
|
|
|
|
| 1 |
|
| 2 |
+
import { NextRequest, NextResponse } from 'next/server';
|
| 3 |
import db from '@/lib/db';
|
| 4 |
import { startYuqueSync, getSyncStatus } from '@/lib/yuque-service';
|
| 5 |
|
| 6 |
+
export async function GET(req: NextRequest) {
|
| 7 |
try {
|
| 8 |
+
const isDemoMode = req.nextUrl.searchParams.get('mode') === 'demo';
|
| 9 |
+
|
| 10 |
// Select all columns EXCEPT content_preview to reduce payload size, but include length for stats
|
| 11 |
// Use word_count if available (more accurate), otherwise fallback to 0 (will be updated on next sync)
|
| 12 |
const docs = db.prepare(`
|
|
|
|
| 23 |
|
| 24 |
// DEMO DATA FALLBACK
|
| 25 |
// If database is empty or connection fails, return static demo data for HuggingFace/Demo purposes
|
| 26 |
+
if (isDemoMode || (docs.length === 0 && kbs.length === 0)) {
|
| 27 |
return NextResponse.json({
|
| 28 |
documents: [
|
| 29 |
{
|
src/app/api/history/sessions/route.ts
CHANGED
|
@@ -2,12 +2,13 @@ import { NextRequest, NextResponse } from 'next/server';
|
|
| 2 |
import db from '@/lib/db';
|
| 3 |
|
| 4 |
// GET: List all sessions
|
| 5 |
-
export async function GET() {
|
| 6 |
try {
|
|
|
|
| 7 |
const sessions = db.prepare('SELECT * FROM sessions ORDER BY created_at DESC').all();
|
| 8 |
|
| 9 |
// DEMO DATA FALLBACK
|
| 10 |
-
if (sessions.length === 0) {
|
| 11 |
return NextResponse.json([
|
| 12 |
{
|
| 13 |
id: 'demo-session-1',
|
|
|
|
| 2 |
import db from '@/lib/db';
|
| 3 |
|
| 4 |
// GET: List all sessions
|
| 5 |
+
export async function GET(req: NextRequest) {
|
| 6 |
try {
|
| 7 |
+
const isDemoMode = req.nextUrl.searchParams.get('mode') === 'demo';
|
| 8 |
const sessions = db.prepare('SELECT * FROM sessions ORDER BY created_at DESC').all();
|
| 9 |
|
| 10 |
// DEMO DATA FALLBACK
|
| 11 |
+
if (isDemoMode || sessions.length === 0) {
|
| 12 |
return NextResponse.json([
|
| 13 |
{
|
| 14 |
id: 'demo-session-1',
|
src/app/knowledge/page.tsx
CHANGED
|
@@ -325,19 +325,27 @@ function KnowledgePageContent() {
|
|
| 325 |
|
| 326 |
const fetchDocuments = async () => {
|
| 327 |
try {
|
| 328 |
-
const
|
|
|
|
|
|
|
|
|
|
|
|
|
| 329 |
const data = await res.json();
|
| 330 |
setDocuments(data.documents || []);
|
| 331 |
setKnowledgeBases(data.knowledgeBases || []);
|
| 332 |
setSyncStatus(data.status);
|
| 333 |
|
| 334 |
-
// Initial KB selection logic
|
| 335 |
-
if (
|
| 336 |
// Check URL first
|
| 337 |
const kbParam = searchParams.get('kb');
|
| 338 |
-
if
|
| 339 |
-
|
|
|
|
|
|
|
|
|
|
| 340 |
} else {
|
|
|
|
| 341 |
setCurrentKbNamespace(data.knowledgeBases[0].namespace);
|
| 342 |
}
|
| 343 |
}
|
|
@@ -430,7 +438,11 @@ function KnowledgePageContent() {
|
|
| 430 |
if (selectedNode && !selectedNode.doc.content_preview && selectedNode.doc.id) {
|
| 431 |
setIsLoadingContent(true);
|
| 432 |
try {
|
| 433 |
-
const
|
|
|
|
|
|
|
|
|
|
|
|
|
| 434 |
if (res.ok) {
|
| 435 |
const data = await res.json();
|
| 436 |
if (data.content_preview) {
|
|
@@ -461,7 +473,7 @@ function KnowledgePageContent() {
|
|
| 461 |
}, 2000);
|
| 462 |
|
| 463 |
return () => clearInterval(interval);
|
| 464 |
-
}, [syncStatus.status]);
|
| 465 |
|
| 466 |
const handleSync = async () => {
|
| 467 |
try {
|
|
@@ -494,6 +506,11 @@ function KnowledgePageContent() {
|
|
| 494 |
</div>
|
| 495 |
|
| 496 |
<div className="flex items-center gap-4">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 497 |
<button
|
| 498 |
onClick={handleSync}
|
| 499 |
disabled={syncStatus.status === 'running'}
|
|
|
|
| 325 |
|
| 326 |
const fetchDocuments = async () => {
|
| 327 |
try {
|
| 328 |
+
const isDemoEnv = process.env.NEXT_PUBLIC_DEMO_MODE === 'true';
|
| 329 |
+
const isDemoParam = searchParams.get('demo') === 'true';
|
| 330 |
+
const isDemo = isDemoEnv || isDemoParam;
|
| 331 |
+
|
| 332 |
+
const res = await fetch(`/api/documents${isDemo ? '?mode=demo' : ''}`);
|
| 333 |
const data = await res.json();
|
| 334 |
setDocuments(data.documents || []);
|
| 335 |
setKnowledgeBases(data.knowledgeBases || []);
|
| 336 |
setSyncStatus(data.status);
|
| 337 |
|
| 338 |
+
// Initial KB selection logic
|
| 339 |
+
if (data.knowledgeBases && data.knowledgeBases.length > 0) {
|
| 340 |
// Check URL first
|
| 341 |
const kbParam = searchParams.get('kb');
|
| 342 |
+
// Verify if the kbParam actually exists in the fetched knowledge bases
|
| 343 |
+
const kbExists = kbParam && data.knowledgeBases.some((k: KnowledgeBase) => k.namespace === kbParam);
|
| 344 |
+
|
| 345 |
+
if (kbExists) {
|
| 346 |
+
if (!currentKbNamespace) setCurrentKbNamespace(kbParam);
|
| 347 |
} else {
|
| 348 |
+
// If no KB selected, or selected KB doesn't exist (e.g. switching modes), select the first one
|
| 349 |
setCurrentKbNamespace(data.knowledgeBases[0].namespace);
|
| 350 |
}
|
| 351 |
}
|
|
|
|
| 438 |
if (selectedNode && !selectedNode.doc.content_preview && selectedNode.doc.id) {
|
| 439 |
setIsLoadingContent(true);
|
| 440 |
try {
|
| 441 |
+
const isDemoEnv = process.env.NEXT_PUBLIC_DEMO_MODE === 'true';
|
| 442 |
+
const isDemoParam = searchParams.get('demo') === 'true';
|
| 443 |
+
const isDemo = isDemoEnv || isDemoParam;
|
| 444 |
+
|
| 445 |
+
const res = await fetch(`/api/documents/${encodeURIComponent(selectedNode.doc.id)}${isDemo ? '?mode=demo' : ''}`);
|
| 446 |
if (res.ok) {
|
| 447 |
const data = await res.json();
|
| 448 |
if (data.content_preview) {
|
|
|
|
| 473 |
}, 2000);
|
| 474 |
|
| 475 |
return () => clearInterval(interval);
|
| 476 |
+
}, [syncStatus.status, searchParams.get('demo')]);
|
| 477 |
|
| 478 |
const handleSync = async () => {
|
| 479 |
try {
|
|
|
|
| 506 |
</div>
|
| 507 |
|
| 508 |
<div className="flex items-center gap-4">
|
| 509 |
+
{(process.env.NEXT_PUBLIC_DEMO_MODE === 'true' || searchParams.get('demo') === 'true') && (
|
| 510 |
+
<div className="px-2 py-1 bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-300 text-xs font-medium rounded border border-amber-200 dark:border-amber-800">
|
| 511 |
+
Demo Mode
|
| 512 |
+
</div>
|
| 513 |
+
)}
|
| 514 |
<button
|
| 515 |
onClick={handleSync}
|
| 516 |
disabled={syncStatus.status === 'running'}
|
src/hooks/useChatHistory.ts
CHANGED
|
@@ -110,7 +110,8 @@ export function useChatHistory() {
|
|
| 110 |
useEffect(() => {
|
| 111 |
async function fetchSessions() {
|
| 112 |
try {
|
| 113 |
-
const
|
|
|
|
| 114 |
if (!res.ok) throw new Error('Failed to fetch sessions');
|
| 115 |
const data = await res.json();
|
| 116 |
setSessions(data);
|
|
|
|
| 110 |
useEffect(() => {
|
| 111 |
async function fetchSessions() {
|
| 112 |
try {
|
| 113 |
+
const isDemo = process.env.NEXT_PUBLIC_DEMO_MODE === 'true';
|
| 114 |
+
const res = await fetch(`/api/history/sessions${isDemo ? '?mode=demo' : ''}`);
|
| 115 |
if (!res.ok) throw new Error('Failed to fetch sessions');
|
| 116 |
const data = await res.json();
|
| 117 |
setSessions(data);
|
备注.md
CHANGED
|
@@ -1,9 +0,0 @@
|
|
| 1 |
-
|
| 2 |
-
你实现的demo 功能,上传之后没有啊,能不能在本地看一下,或者用什么方式检查一下,确定可以再上传。或者是你确保代码没问题,也可以直接更新,告诉,我再上传试一下
|
| 3 |
-
- 知识库管理页面 :
|
| 4 |
-
- 将显示 2 个演示知识库:“产品手册”和“技术文档”。
|
| 5 |
-
- 包含 3 篇演示文档:“RAG 系统介绍”、“快速开始指南”和“API 接口文档”。
|
| 6 |
-
- 文档列表会显示字数、同步时间等模拟数据。
|
| 7 |
-
- 历史对话记录 :
|
| 8 |
-
- 侧边栏会显示 2 个历史会话:“什么是 RAG 架构?”和“DeepSeek V3 性能评估”。
|
| 9 |
-
- 点击这些会话,可以查看预设的对话内容(问答详情)。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|