feat: add report preview

This commit is contained in:
qixinbo
2026-03-19 17:48:52 +08:00
parent 7c9abcadfe
commit 2c9ae92668
3 changed files with 37 additions and 1 deletions
+7
View File
@@ -4,9 +4,11 @@ from fastapi import FastAPI, HTTPException
from fastapi.encoders import jsonable_encoder from fastapi.encoders import jsonable_encoder
from fastapi.responses import StreamingResponse from fastapi.responses import StreamingResponse
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel from pydantic import BaseModel
import json import json
import re import re
import os
from datetime import datetime from datetime import datetime
from app.api import upload, llm, skills, users, datasources, projects, semantic from app.api import upload, llm, skills, users, datasources, projects, semantic
@@ -34,6 +36,11 @@ app.add_middleware(
# Initialize database tables # Initialize database tables
Base.metadata.create_all(bind=engine) Base.metadata.create_all(bind=engine)
# Mount static directory for reports
data_dir = os.path.join(os.path.dirname(__file__), "data", "data")
os.makedirs(data_dir, exist_ok=True)
app.mount("/reports", StaticFiles(directory=data_dir), name="reports")
app.include_router(upload.router, prefix="/api/v1") app.include_router(upload.router, prefix="/api/v1")
app.include_router(llm.router, prefix="/api/v1") app.include_router(llm.router, prefix="/api/v1")
app.include_router(skills.router, prefix="/api/v1") app.include_router(skills.router, prefix="/api/v1")
+26 -1
View File
@@ -2,7 +2,7 @@ import { useState, useRef, useEffect } from "react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { ScrollArea } from "@/components/ui/scroll-area"; import { ScrollArea } from "@/components/ui/scroll-area";
import { User, Loader2, Sparkles, ArrowUp, ChevronDown, Paperclip, Check, X, Square, Plus, Database, Wand2, Search, Zap, LayoutGrid, CheckCircle2, Table, XCircle, Settings } from "lucide-react"; import { User, Loader2, Sparkles, ArrowUp, ChevronDown, Paperclip, Check, X, Square, Plus, Database, Wand2, Search, Zap, LayoutGrid, CheckCircle2, Table, XCircle, Settings, ExternalLink } from "lucide-react";
import { api } from "@/lib/api"; import { api } from "@/lib/api";
import { type ChartSpec } from "@/store/visualizationStore"; import { type ChartSpec } from "@/store/visualizationStore";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
@@ -50,6 +50,17 @@ const splitReportHtml = (content: string): { markdown: string; reportHtml: strin
return { markdown, reportHtml: reportHtml || null }; return { markdown, reportHtml: reportHtml || null };
}; };
const HTML_FILE_REGEX = /data[\\\/]data[\\\/]([a-zA-Z0-9_\-]+\.html?)/i;
const extractExternalReport = (content: string): string | null => {
if (!content) return null;
const match = content.match(HTML_FILE_REGEX);
if (match && match[1]) {
return `/reports/${match[1]}`;
}
return null;
};
interface ModelConfig { interface ModelConfig {
id: string; id: string;
name?: string; name?: string;
@@ -926,6 +937,7 @@ export function ChatInterface() {
<div className="max-w-3xl mx-auto px-4 py-8 space-y-8"> <div className="max-w-3xl mx-auto px-4 py-8 space-y-8">
{messages.map((msg) => { {messages.map((msg) => {
const { markdown, reportHtml } = splitReportHtml(msg.content); const { markdown, reportHtml } = splitReportHtml(msg.content);
const externalReportUrl = extractExternalReport(msg.content);
return ( return (
<div <div
key={msg.id} key={msg.id}
@@ -993,6 +1005,19 @@ export function ChatInterface() {
/> />
</div> </div>
) : null} ) : null}
{externalReportUrl ? (
<div className="mt-4 flex">
<a
href={externalReportUrl}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-2 px-4 py-2 bg-blue-50 text-blue-600 hover:bg-blue-100 hover:text-blue-700 rounded-lg text-sm font-medium transition-colors"
>
<ExternalLink className="h-4 w-4" />
</a>
</div>
) : null}
{msg.viz ? ( {msg.viz ? (
<div className="mt-3 pt-3 border-t border-zinc-100"> <div className="mt-3 pt-3 border-t border-zinc-100">
<InlineVisualizationCard viz={msg.viz} /> <InlineVisualizationCard viz={msg.viz} />
+4
View File
@@ -20,6 +20,10 @@ export default defineConfig({
target: 'http://localhost:8000', target: 'http://localhost:8000',
changeOrigin: true, changeOrigin: true,
}, },
'/reports': {
target: 'http://localhost:8000',
changeOrigin: true,
},
}, },
}, },
}) })