버그수정
This commit is contained in:
Binary file not shown.
@@ -151,6 +151,47 @@ class ResetProjectRequest(BaseModel):
|
||||
project_name: str | None = None
|
||||
|
||||
|
||||
def source_model_to_config(source: models.Source) -> SourceConfig:
|
||||
return SourceConfig(
|
||||
name=source.name,
|
||||
type=source.type,
|
||||
trust_level=source.trust_level,
|
||||
base_url=source.base_url,
|
||||
rate_limit_per_minute=source.rate_limit_per_minute,
|
||||
respect_robots_txt=source.respect_robots_txt,
|
||||
)
|
||||
|
||||
|
||||
def project_config_from_project_row(session, project: models.Project) -> ProjectConfig:
|
||||
config_dict = dict(project.config or {})
|
||||
if not config_dict:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"Project '{project.name}' has no stored config",
|
||||
)
|
||||
config = project_config_from_dict(config_dict)
|
||||
config.sources = [
|
||||
source_model_to_config(source)
|
||||
for source in session.scalars(
|
||||
select(models.Source).where(models.Source.project_id == project.id)
|
||||
).all()
|
||||
]
|
||||
return config
|
||||
|
||||
|
||||
def project_config_to_dict(config: ProjectConfig) -> dict[str, Any]:
|
||||
return {
|
||||
"project_name": config.project_name,
|
||||
"domain": config.domain,
|
||||
"target_entities": list(config.target_entities),
|
||||
"fields": list(config.fields),
|
||||
"sources": [asdict(source) for source in config.sources],
|
||||
"ontology": dict(config.ontology),
|
||||
"recommendation": dict(config.recommendation),
|
||||
"update_policy": dict(config.update_policy),
|
||||
}
|
||||
|
||||
|
||||
class CreateEntityRequest(BaseModel):
|
||||
entity_type: str
|
||||
name: str
|
||||
@@ -494,7 +535,7 @@ def register_routes(app, database_url: str) -> None:
|
||||
"id": project.id,
|
||||
"name": project.name,
|
||||
"domain": project.domain,
|
||||
"config": project.config,
|
||||
"config": project_config_to_dict(project_config_from_project_row(session, project)),
|
||||
"sources": [
|
||||
{
|
||||
"id": source.id,
|
||||
@@ -712,15 +753,10 @@ def register_routes(app, database_url: str) -> None:
|
||||
with session_scope(database_url) as session:
|
||||
repo = KnowledgeRepository(session)
|
||||
project = repo.get_project(request.project_name)
|
||||
config_dict = project.config or {}
|
||||
if not config_dict:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"Project '{request.project_name}' has no stored config",
|
||||
)
|
||||
config = project_config_from_dict(config_dict)
|
||||
config = project_config_from_project_row(session, project)
|
||||
try:
|
||||
source = repo.get_source(project.id, request.source_name)
|
||||
config.source_by_name(request.source_name)
|
||||
except KeyError as exc:
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
@@ -751,7 +787,10 @@ def register_routes(app, database_url: str) -> None:
|
||||
session.flush()
|
||||
response = crawl_job_response(job)
|
||||
|
||||
task_payload = {**inner_request.model_dump(), "__config_dict": config_dict}
|
||||
task_payload = {
|
||||
**inner_request.model_dump(),
|
||||
"__config_dict": project_config_to_dict(config),
|
||||
}
|
||||
background_tasks.add_task(
|
||||
run_site_crawl_job, database_url, response["job_id"], task_payload
|
||||
)
|
||||
@@ -850,13 +889,7 @@ def register_routes(app, database_url: str) -> None:
|
||||
with session_scope(database_url) as session:
|
||||
repo = KnowledgeRepository(session)
|
||||
project = repo.get_project(request.project_name)
|
||||
config_dict = project.config or {}
|
||||
if not config_dict:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"Project '{request.project_name}' has no stored config",
|
||||
)
|
||||
config = project_config_from_dict(config_dict)
|
||||
config = project_config_from_project_row(session, project)
|
||||
try:
|
||||
source_config = config.source_by_name(request.source_name)
|
||||
except KeyError as exc:
|
||||
|
||||
2641
crawler_platform/app/web/frontend/package-lock.json
generated
2641
crawler_platform/app/web/frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -34,7 +34,7 @@
|
||||
"react-dom": "^18.2.0",
|
||||
"react-hook-form": "^7.48.0",
|
||||
"react-i18next": "^13.4.0",
|
||||
"react-redux": "^1.13.0",
|
||||
"react-redux": "^8.1.3",
|
||||
"react-router-dom": "^6.20.0",
|
||||
"reactflow": "^11.10.1",
|
||||
"sonner": "^1.2.3",
|
||||
|
||||
@@ -1,14 +1,32 @@
|
||||
import { NavLink, Outlet } from "react-router-dom";
|
||||
import { useEffect } from "react";
|
||||
import {
|
||||
matchPath,
|
||||
NavLink,
|
||||
Outlet,
|
||||
useLocation,
|
||||
useNavigate,
|
||||
} from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import { LayoutDashboard, UploadCloud, Settings2, Activity, Brain, Network, ListChecks, Menu } from "lucide-react";
|
||||
import {
|
||||
LayoutDashboard,
|
||||
UploadCloud,
|
||||
Settings2,
|
||||
Activity,
|
||||
Brain,
|
||||
Network,
|
||||
ListChecks,
|
||||
Menu,
|
||||
} from "lucide-react";
|
||||
import { RootState } from "@/stores";
|
||||
import { toggleSidebar } from "@/stores/slices/uiSlice";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useProjects } from "@/hooks/useProjects";
|
||||
|
||||
interface NavItem {
|
||||
to: string;
|
||||
to?: string;
|
||||
projectPath?: string;
|
||||
labelKey: string;
|
||||
icon: React.ComponentType<{ className?: string }>;
|
||||
}
|
||||
@@ -16,17 +34,71 @@ interface NavItem {
|
||||
const navItems: NavItem[] = [
|
||||
{ to: "/", labelKey: "nav.dashboard", icon: LayoutDashboard },
|
||||
{ to: "/onboard", labelKey: "nav.onboard", icon: UploadCloud },
|
||||
{ to: "/sources/demo-project", labelKey: "nav.sources", icon: Settings2 },
|
||||
{ to: "/crawl/demo-project", labelKey: "nav.crawl", icon: Activity },
|
||||
{ to: "/research/demo-project", labelKey: "nav.research", icon: Brain },
|
||||
{ to: "/editor/demo-project", labelKey: "nav.editor", icon: Network },
|
||||
{ to: "/review/demo-project", labelKey: "nav.review", icon: ListChecks },
|
||||
{ projectPath: "sources", labelKey: "nav.sources", icon: Settings2 },
|
||||
{ projectPath: "crawl", labelKey: "nav.crawl", icon: Activity },
|
||||
{ projectPath: "research", labelKey: "nav.research", icon: Brain },
|
||||
{ projectPath: "editor", labelKey: "nav.editor", icon: Network },
|
||||
{ projectPath: "review", labelKey: "nav.review", icon: ListChecks },
|
||||
];
|
||||
|
||||
const projectRoutePatterns = [
|
||||
"/sources/:projectId",
|
||||
"/crawl/:projectId",
|
||||
"/research/:projectId",
|
||||
"/editor/:projectId",
|
||||
"/review/:projectId",
|
||||
];
|
||||
|
||||
function projectIdFromPathname(pathname: string): string | undefined {
|
||||
for (const pattern of projectRoutePatterns) {
|
||||
const match = matchPath({ path: pattern, end: false }, pathname);
|
||||
if (match?.params.projectId) return match.params.projectId;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function workspaceSectionFromPathname(pathname: string): string | undefined {
|
||||
for (const pattern of projectRoutePatterns) {
|
||||
const match = matchPath({ path: pattern, end: false }, pathname);
|
||||
if (match?.params.projectId) return pattern.split("/")[1];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export default function AppShell() {
|
||||
const { t } = useTranslation();
|
||||
const sidebarOpen = useSelector((s: RootState) => s.ui.sidebarOpen);
|
||||
const dispatch = useDispatch();
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const routeProjectId = projectIdFromPathname(location.pathname);
|
||||
const workspaceSection = workspaceSectionFromPathname(location.pathname);
|
||||
const { data: projects } = useProjects();
|
||||
const fallbackProjectId = projects?.[0]?.name;
|
||||
const routeProjectExists =
|
||||
!routeProjectId ||
|
||||
!projects ||
|
||||
projects.some((project) => project.name === routeProjectId);
|
||||
const currentProjectId = routeProjectExists
|
||||
? routeProjectId ?? fallbackProjectId
|
||||
: fallbackProjectId;
|
||||
|
||||
useEffect(() => {
|
||||
if (routeProjectId && projects && !routeProjectExists) {
|
||||
const nextPath =
|
||||
workspaceSection && fallbackProjectId
|
||||
? `/${workspaceSection}/${encodeURIComponent(fallbackProjectId)}`
|
||||
: "/";
|
||||
navigate(nextPath, { replace: true });
|
||||
}
|
||||
}, [
|
||||
fallbackProjectId,
|
||||
navigate,
|
||||
projects,
|
||||
routeProjectExists,
|
||||
routeProjectId,
|
||||
workspaceSection,
|
||||
]);
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen bg-background text-foreground">
|
||||
@@ -51,25 +123,62 @@ export default function AppShell() {
|
||||
<Menu className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{sidebarOpen && (
|
||||
<div className="border-b px-4 py-3">
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{t("nav.currentProject", "Current project")}
|
||||
</p>
|
||||
<p className="mt-1 truncate text-sm font-medium">
|
||||
{currentProjectId ??
|
||||
t("nav.noProjectSelected", "Select a project")}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<nav className="flex flex-col gap-1 p-2">
|
||||
{navItems.map(({ to, labelKey, icon: Icon }) => (
|
||||
<NavLink
|
||||
key={to}
|
||||
to={to}
|
||||
end={to === "/"}
|
||||
className={({ isActive }) =>
|
||||
cn(
|
||||
"flex items-center gap-3 rounded-md px-3 py-2 text-sm transition-colors",
|
||||
isActive
|
||||
? "bg-accent text-accent-foreground"
|
||||
: "text-muted-foreground hover:bg-accent/50 hover:text-foreground",
|
||||
)
|
||||
}
|
||||
>
|
||||
<Icon className="h-4 w-4 flex-shrink-0" />
|
||||
{sidebarOpen && <span>{t(labelKey)}</span>}
|
||||
</NavLink>
|
||||
))}
|
||||
{navItems.map(({ to, projectPath, labelKey, icon: Icon }) => {
|
||||
const href =
|
||||
to ??
|
||||
(currentProjectId
|
||||
? `/${projectPath}/${encodeURIComponent(currentProjectId)}`
|
||||
: undefined);
|
||||
|
||||
if (!href) {
|
||||
return (
|
||||
<div
|
||||
key={labelKey}
|
||||
className="flex cursor-not-allowed items-center gap-3 rounded-md px-3 py-2 text-sm text-muted-foreground/50"
|
||||
title={t(
|
||||
"nav.selectProjectFirst",
|
||||
"Select a project from the dashboard first",
|
||||
)}
|
||||
>
|
||||
<Icon className="h-4 w-4 flex-shrink-0" />
|
||||
{sidebarOpen && <span>{t(labelKey)}</span>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<NavLink
|
||||
key={labelKey}
|
||||
to={href}
|
||||
end={href === "/"}
|
||||
className={({ isActive }) =>
|
||||
cn(
|
||||
"flex items-center gap-3 rounded-md px-3 py-2 text-sm transition-colors",
|
||||
isActive
|
||||
? "bg-accent text-accent-foreground"
|
||||
: "text-muted-foreground hover:bg-accent/50 hover:text-foreground",
|
||||
)
|
||||
}
|
||||
>
|
||||
<Icon className="h-4 w-4 flex-shrink-0" />
|
||||
{sidebarOpen && <span>{t(labelKey)}</span>}
|
||||
</NavLink>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ export const projectSourceSchema = z.object({
|
||||
id: z.union([z.string(), z.number()]).transform(String),
|
||||
name: z.string(),
|
||||
type: z.string(),
|
||||
base_url: z.string().nullable().optional(),
|
||||
trust_level: z.union([z.string(), z.number()]).nullable().optional(),
|
||||
respect_robots_txt: z.boolean().nullable().optional(),
|
||||
rate_limit_per_minute: z.number().nullable().optional(),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { defineConfig } from "vite";
|
||||
import react from "@vitejs/plugin-react";
|
||||
import path from "node:path";
|
||||
|
||||
const BACKEND = "http://127.0.0.1:8000";
|
||||
const PROXY_PREFIXES = [
|
||||
@@ -24,6 +25,11 @@ export default defineConfig({
|
||||
plugins: [react()],
|
||||
root: ".",
|
||||
base: "/static/",
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(process.cwd(), "src"),
|
||||
},
|
||||
},
|
||||
build: {
|
||||
outDir: "../static",
|
||||
emptyOutDir: true,
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
11
crawler_platform/app/web/static/assets/index-DTEQpvfm.js
Normal file
11
crawler_platform/app/web/static/assets/index-DTEQpvfm.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -3,11 +3,12 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Ontology Crawler Platform</title>
|
||||
<script type="module" crossorigin src="/static/assets/index-BsoXaTIL.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/static/assets/index-BkBg_FAU.css">
|
||||
<meta name="description" content="Ontology Construction Platform with Phase 5 GraphRAG and Phase 7 LLM" />
|
||||
<title>Ontology Builder - AI-Powered Ontology Construction</title>
|
||||
<script type="module" crossorigin src="/static/assets/index-DTEQpvfm.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/static/assets/index-uHGS9kYH.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<div id="root"></div>
|
||||
|
||||
</body>
|
||||
|
||||
172
crawler_platform/app/web/static/locales/en/common.json
Normal file
172
crawler_platform/app/web/static/locales/en/common.json
Normal file
@@ -0,0 +1,172 @@
|
||||
{
|
||||
"app": {
|
||||
"title": "Ontology Builder",
|
||||
"subtitle": "AI-powered ontology construction"
|
||||
},
|
||||
"nav": {
|
||||
"dashboard": "Dashboard",
|
||||
"onboard": "New Project",
|
||||
"sources": "Sources",
|
||||
"crawl": "Crawl",
|
||||
"research": "Research",
|
||||
"editor": "Editor",
|
||||
"review": "Review",
|
||||
"toggleSidebar": "Toggle sidebar"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Ontology Builder",
|
||||
"subtitle": "Build and manage domain ontologies with AI-powered extraction",
|
||||
"newProject": "New Project",
|
||||
"projects": "Projects",
|
||||
"projectCount": "{{count}} total",
|
||||
"loadFailed": "Failed to load projects",
|
||||
"empty": {
|
||||
"title": "No projects yet",
|
||||
"hint": "Create your first project to start building an ontology"
|
||||
}
|
||||
},
|
||||
"onboarding": {
|
||||
"title": "Create New Project",
|
||||
"formTitle": "Choose Ontology Domain",
|
||||
"formDesc": "Pick the domain of ontology you want to build and give your project a name.",
|
||||
"projectName": "Project Name",
|
||||
"projectNameHint": "Letters, digits, _ and - only (2~64 chars)",
|
||||
"domain": "Domain",
|
||||
"domainSummary": "{{entities}} entity types · {{predicates}} predicates",
|
||||
"submit": "Create Project",
|
||||
"created": "Project created: {{name}}",
|
||||
"createFailed": "Create failed: {{msg}}"
|
||||
},
|
||||
"sources": {
|
||||
"title": "Configure Sources",
|
||||
"next": "Proceed to Crawl",
|
||||
"listTitle": "Registered Sources",
|
||||
"listDesc": "Reference sites used for ontology construction",
|
||||
"empty": "No sources yet. Add one using the form on the right.",
|
||||
"addTitle": "Add Source",
|
||||
"addDesc": "Enter information about the reference site",
|
||||
"name": "Name",
|
||||
"type": "Type",
|
||||
"baseUrl": "Base URL",
|
||||
"trust": "Trust",
|
||||
"rateLimit": "rate/min",
|
||||
"respectRobots": "Respect robots.txt",
|
||||
"add": "Add Source",
|
||||
"delete": "Delete",
|
||||
"confirmDelete": "Delete source '{{name}}'?",
|
||||
"added": "Source added: {{name}}",
|
||||
"addFailed": "Add failed: {{msg}}",
|
||||
"deleted": "Source deleted: {{name}}",
|
||||
"deleteFailed": "Delete failed: {{msg}}"
|
||||
},
|
||||
"research": {
|
||||
"title": "Autonomous Research",
|
||||
"formTitle": "Research Settings",
|
||||
"formDesc": "AI follows links from a seed to autonomously expand the ontology",
|
||||
"source": "Source",
|
||||
"pickSource": "Pick a source...",
|
||||
"goal": "Goal",
|
||||
"goalPlaceholder": "e.g. Collect note compositions and seasonal recommendations of popular perfume brands",
|
||||
"seedUrl": "Seed URL",
|
||||
"optional": "optional",
|
||||
"maxSteps": "Max Steps",
|
||||
"maxBranch": "Branch Width",
|
||||
"maxDepth": "Max Depth",
|
||||
"minRelevance": "Min Relevance",
|
||||
"sameDomainOnly": "Same domain only",
|
||||
"start": "Start Research",
|
||||
"runningHint": "This may take a while. Don't close the page until it finishes.",
|
||||
"runningTitle": "AI is researching...",
|
||||
"completed": "Research completed",
|
||||
"failed": "Failed: {{msg}}",
|
||||
"doneHint": "Done",
|
||||
"idleHint": "Start research on the left to see results here",
|
||||
"resultTitle": "Latest Result",
|
||||
"resultDesc": "Outcome of the research run in this session",
|
||||
"stepsTaken": "Steps",
|
||||
"pagesVisited": "Pages",
|
||||
"entitiesFound": "Entities",
|
||||
"claimsAdded": "Claims",
|
||||
"rawResult": "Raw JSON",
|
||||
"historyTitle": "Session History",
|
||||
"historyDesc": "Past research sessions for this project",
|
||||
"historyEmpty": "No sessions yet",
|
||||
"pages": "pages"
|
||||
},
|
||||
"editor": {
|
||||
"title": "Ontology Editor",
|
||||
"entitiesTab": "Entities",
|
||||
"claimsTab": "Claims",
|
||||
"bulkTab": "JSON Bulk",
|
||||
"addEntity": "Add Entity",
|
||||
"addEntityDesc": "Pick from the domain's entity_types",
|
||||
"entityType": "Type",
|
||||
"pickType": "Pick type...",
|
||||
"entityName": "Name",
|
||||
"add": "Add",
|
||||
"entitiesList": "Entities",
|
||||
"entityCount": "{{count}} total",
|
||||
"entitiesEmpty": "No entities yet",
|
||||
"entityAdded": "Entity added: {{name}}",
|
||||
"entityAddFailed": "Add failed: {{msg}}",
|
||||
"confirmDeleteEntity": "Delete entity '{{name}}'?",
|
||||
"addClaim": "Add Claim",
|
||||
"addClaimDesc": "Subject-Predicate-Object form",
|
||||
"source": "Source",
|
||||
"pickSource": "Pick source...",
|
||||
"subject": "Subject",
|
||||
"pickSubject": "Pick entity...",
|
||||
"predicate": "Predicate",
|
||||
"pickPredicate": "Pick predicate...",
|
||||
"objectKind": "Object kind",
|
||||
"objectEntity": "Other entity",
|
||||
"objectValue": "Literal value",
|
||||
"pickObject": "Pick entity...",
|
||||
"confidence": "Confidence",
|
||||
"claimsList": "Claims",
|
||||
"claimCount": "{{count}} total",
|
||||
"claimsEmpty": "No claims yet",
|
||||
"claimAdded": "Claim added",
|
||||
"claimAddFailed": "Add failed: {{msg}}",
|
||||
"confirmDeleteClaim": "Delete this claim?",
|
||||
"bulkTitle": "JSON Bulk Input",
|
||||
"bulkDesc": "JSON of shape { entities: [{ entity_type, name, metadata? }] }",
|
||||
"bulkSubmit": "Bulk Add",
|
||||
"bulkAdded": "{{count}} entities added"
|
||||
},
|
||||
"crawl": {
|
||||
"title": "Seed Crawl",
|
||||
"formTitle": "Crawl Settings",
|
||||
"formDesc": "Start from a seed URL and follow links to extract information",
|
||||
"source": "Source",
|
||||
"pickSource": "Pick a source...",
|
||||
"noSources": "No sources registered. Add a reference source first.",
|
||||
"addSource": "Add Source",
|
||||
"seedUrl": "Seed URL",
|
||||
"maxDepth": "Max Depth",
|
||||
"maxPages": "Max Pages",
|
||||
"sameDomainOnly": "Same domain only",
|
||||
"start": "Start Crawl",
|
||||
"started": "Crawl started (job #{{id}})",
|
||||
"startFailed": "Start failed: {{msg}}",
|
||||
"cancel": "Cancel",
|
||||
"cancelRequested": "Cancel requested",
|
||||
"cancelFailed": "Cancel failed: {{msg}}",
|
||||
"progressTitle": "Progress",
|
||||
"idleHint": "Enter a seed URL and start the crawl",
|
||||
"visited": "Visited",
|
||||
"queued": "Queued",
|
||||
"analyzed": "Analyzed",
|
||||
"latestPage": "Latest Page",
|
||||
"errorsCount": "{{count}} errors",
|
||||
"doneHint": "Crawl complete. Go review the results.",
|
||||
"review": "Review"
|
||||
},
|
||||
"common": {
|
||||
"retry": "Retry",
|
||||
"cancel": "Cancel",
|
||||
"next": "Next",
|
||||
"back": "Back",
|
||||
"complete": "Complete"
|
||||
}
|
||||
}
|
||||
172
crawler_platform/app/web/static/locales/ko/common.json
Normal file
172
crawler_platform/app/web/static/locales/ko/common.json
Normal file
@@ -0,0 +1,172 @@
|
||||
{
|
||||
"app": {
|
||||
"title": "온톨로지 빌더",
|
||||
"subtitle": "AI 기반 온톨로지 구축 플랫폼"
|
||||
},
|
||||
"nav": {
|
||||
"dashboard": "대시보드",
|
||||
"onboard": "프로젝트 생성",
|
||||
"sources": "참고 소스",
|
||||
"crawl": "크롤 진행",
|
||||
"research": "자율 연구",
|
||||
"editor": "온톨로지 편집",
|
||||
"review": "결과 검토",
|
||||
"toggleSidebar": "사이드바 토글"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "온톨로지 빌더",
|
||||
"subtitle": "도메인 온톨로지를 AI 추출로 구축하고 관리합니다",
|
||||
"newProject": "새 프로젝트",
|
||||
"projects": "프로젝트 목록",
|
||||
"projectCount": "{{count}}개",
|
||||
"loadFailed": "프로젝트를 불러오지 못했습니다",
|
||||
"empty": {
|
||||
"title": "아직 프로젝트가 없습니다",
|
||||
"hint": "첫 프로젝트를 만들어 온톨로지 구축을 시작하세요"
|
||||
}
|
||||
},
|
||||
"onboarding": {
|
||||
"title": "새 프로젝트 만들기",
|
||||
"formTitle": "온톨로지 도메인 선택",
|
||||
"formDesc": "어떤 종류의 온톨로지를 구축할지 도메인을 선택하고 프로젝트 이름을 정해주세요.",
|
||||
"projectName": "프로젝트 이름",
|
||||
"projectNameHint": "영문, 숫자, _ , - 만 사용 (2~64자)",
|
||||
"domain": "도메인",
|
||||
"domainSummary": "엔티티 {{entities}}종 · 관계 {{predicates}}개",
|
||||
"submit": "프로젝트 만들기",
|
||||
"created": "프로젝트가 생성되었습니다: {{name}}",
|
||||
"createFailed": "생성 실패: {{msg}}"
|
||||
},
|
||||
"sources": {
|
||||
"title": "참고 소스 설정",
|
||||
"next": "크롤 진행",
|
||||
"listTitle": "등록된 소스",
|
||||
"listDesc": "프로젝트 온톨로지 구축에 사용할 참고 사이트 목록",
|
||||
"empty": "아직 등록된 소스가 없습니다. 오른쪽 폼에서 추가하세요.",
|
||||
"addTitle": "소스 추가",
|
||||
"addDesc": "참고할 사이트 정보를 입력하세요",
|
||||
"name": "이름",
|
||||
"type": "타입",
|
||||
"baseUrl": "Base URL",
|
||||
"trust": "신뢰도",
|
||||
"rateLimit": "rate/분",
|
||||
"respectRobots": "robots.txt 준수",
|
||||
"add": "소스 추가",
|
||||
"delete": "삭제",
|
||||
"confirmDelete": "정말 '{{name}}' 소스를 삭제하시겠습니까?",
|
||||
"added": "소스가 추가되었습니다: {{name}}",
|
||||
"addFailed": "추가 실패: {{msg}}",
|
||||
"deleted": "소스가 삭제되었습니다: {{name}}",
|
||||
"deleteFailed": "삭제 실패: {{msg}}"
|
||||
},
|
||||
"research": {
|
||||
"title": "자율 연구",
|
||||
"formTitle": "자율 연구 설정",
|
||||
"formDesc": "AI가 시드에서 시작해 스스로 링크를 따라가며 온톨로지를 확장합니다",
|
||||
"source": "참고 소스",
|
||||
"pickSource": "소스를 선택하세요...",
|
||||
"goal": "목표",
|
||||
"goalPlaceholder": "예: 인기 브랜드 향수의 노트 구성과 시즌 추천 정보 수집",
|
||||
"seedUrl": "시드 URL",
|
||||
"optional": "선택",
|
||||
"maxSteps": "최대 단계",
|
||||
"maxBranch": "분기 폭",
|
||||
"maxDepth": "최대 깊이",
|
||||
"minRelevance": "최소 관련도",
|
||||
"sameDomainOnly": "동일 도메인만 탐색",
|
||||
"start": "자율 연구 시작",
|
||||
"runningHint": "장시간 걸릴 수 있습니다. 완료될 때까지 페이지를 닫지 마세요.",
|
||||
"runningTitle": "AI가 연구 중입니다...",
|
||||
"completed": "자율 연구가 완료되었습니다",
|
||||
"failed": "실패: {{msg}}",
|
||||
"doneHint": "완료",
|
||||
"idleHint": "왼쪽에서 자율 연구를 시작하면 결과가 여기에 표시됩니다",
|
||||
"resultTitle": "최근 결과",
|
||||
"resultDesc": "이번 세션에서 실행된 연구의 결과",
|
||||
"stepsTaken": "단계",
|
||||
"pagesVisited": "페이지",
|
||||
"entitiesFound": "엔티티",
|
||||
"claimsAdded": "클레임",
|
||||
"rawResult": "원시 응답 JSON",
|
||||
"historyTitle": "세션 이력",
|
||||
"historyDesc": "이 프로젝트의 자율 연구 세션 기록",
|
||||
"historyEmpty": "아직 실행된 세션이 없습니다",
|
||||
"pages": "페이지"
|
||||
},
|
||||
"editor": {
|
||||
"title": "온톨로지 직접 편집",
|
||||
"entitiesTab": "엔티티",
|
||||
"claimsTab": "클레임",
|
||||
"bulkTab": "JSON 일괄 입력",
|
||||
"addEntity": "엔티티 추가",
|
||||
"addEntityDesc": "온톨로지 도메인의 entity_types 중에서 선택",
|
||||
"entityType": "타입",
|
||||
"pickType": "타입 선택...",
|
||||
"entityName": "이름",
|
||||
"add": "추가",
|
||||
"entitiesList": "엔티티 목록",
|
||||
"entityCount": "{{count}}개",
|
||||
"entitiesEmpty": "아직 등록된 엔티티가 없습니다",
|
||||
"entityAdded": "엔티티가 추가되었습니다: {{name}}",
|
||||
"entityAddFailed": "추가 실패: {{msg}}",
|
||||
"confirmDeleteEntity": "엔티티 '{{name}}'을 삭제하시겠습니까?",
|
||||
"addClaim": "클레임 추가",
|
||||
"addClaimDesc": "주어-술어-목적어 형태로 직접 입력",
|
||||
"source": "소스",
|
||||
"pickSource": "소스 선택...",
|
||||
"subject": "주어 (Subject)",
|
||||
"pickSubject": "엔티티 선택...",
|
||||
"predicate": "술어 (Predicate)",
|
||||
"pickPredicate": "술어 선택...",
|
||||
"objectKind": "목적어 유형",
|
||||
"objectEntity": "다른 엔티티",
|
||||
"objectValue": "리터럴 값",
|
||||
"pickObject": "엔티티 선택...",
|
||||
"confidence": "신뢰도",
|
||||
"claimsList": "클레임 목록",
|
||||
"claimCount": "{{count}}개",
|
||||
"claimsEmpty": "아직 등록된 클레임이 없습니다",
|
||||
"claimAdded": "클레임이 추가되었습니다",
|
||||
"claimAddFailed": "추가 실패: {{msg}}",
|
||||
"confirmDeleteClaim": "클레임을 삭제하시겠습니까?",
|
||||
"bulkTitle": "JSON 일괄 입력",
|
||||
"bulkDesc": "{ entities: [{ entity_type, name, metadata? }] } 형태의 JSON",
|
||||
"bulkSubmit": "일괄 추가",
|
||||
"bulkAdded": "{{count}}개 엔티티가 추가되었습니다"
|
||||
},
|
||||
"crawl": {
|
||||
"title": "시드 크롤",
|
||||
"formTitle": "크롤 설정",
|
||||
"formDesc": "시드 URL에서 시작해 링크를 따라가며 정보를 추출합니다",
|
||||
"source": "참고 소스",
|
||||
"pickSource": "소스를 선택하세요...",
|
||||
"noSources": "등록된 소스가 없습니다. 먼저 참고 소스를 추가하세요.",
|
||||
"addSource": "소스 추가",
|
||||
"seedUrl": "시드 URL",
|
||||
"maxDepth": "최대 깊이",
|
||||
"maxPages": "최대 페이지",
|
||||
"sameDomainOnly": "동일 도메인만 따라가기",
|
||||
"start": "크롤 시작",
|
||||
"started": "크롤이 시작되었습니다 (job #{{id}})",
|
||||
"startFailed": "시작 실패: {{msg}}",
|
||||
"cancel": "취소",
|
||||
"cancelRequested": "취소 요청됨",
|
||||
"cancelFailed": "취소 실패: {{msg}}",
|
||||
"progressTitle": "진행 상태",
|
||||
"idleHint": "왼쪽에서 시드 URL을 입력하고 시작하세요",
|
||||
"visited": "방문",
|
||||
"queued": "대기",
|
||||
"analyzed": "분석",
|
||||
"latestPage": "최근 페이지",
|
||||
"errorsCount": "에러 {{count}}건",
|
||||
"doneHint": "크롤 완료. 결과 검토로 이동하세요.",
|
||||
"review": "결과 검토"
|
||||
},
|
||||
"common": {
|
||||
"retry": "다시 시도",
|
||||
"cancel": "취소",
|
||||
"next": "다음",
|
||||
"back": "이전",
|
||||
"complete": "완료"
|
||||
}
|
||||
}
|
||||
873
온톨로지플랫폼_통합설계서.md
873
온톨로지플랫폼_통합설계서.md
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user