├── CONTRIBUTING.md ├── frontend ├── Dockerfile.dev ├── netlify.toml ├── public │ └── images │ │ ├── favicon.ico │ │ ├── sqlite-icon.png │ │ ├── favicon_light.ico │ │ ├── postgres-icon.png │ │ └── xlsx-csv-icon.png ├── cz.yaml ├── src │ ├── lib │ │ └── utils.ts │ ├── routes │ │ ├── (errors) │ │ │ ├── 403.tsx │ │ │ ├── 500.tsx │ │ │ ├── 404.tsx │ │ │ ├── 401.tsx │ │ │ └── 503.tsx │ │ ├── _authenticated │ │ │ ├── index.tsx │ │ │ ├── table │ │ │ │ └── $tableName.tsx │ │ │ ├── report │ │ │ │ └── $reportId.tsx │ │ │ └── route.tsx │ │ └── __root.tsx │ ├── vite-env.d.ts │ ├── components │ │ ├── ui │ │ │ ├── skeleton.tsx │ │ │ ├── shadcn-io │ │ │ │ └── spinner │ │ │ │ │ └── Bars.tsx │ │ │ ├── label.tsx │ │ │ ├── sonner.tsx │ │ │ ├── separator.tsx │ │ │ ├── textarea.tsx │ │ │ ├── progress.tsx │ │ │ ├── collapsible.tsx │ │ │ ├── input.tsx │ │ │ ├── switch.tsx │ │ │ ├── avatar.tsx │ │ │ ├── checkbox.tsx │ │ │ ├── radio-group.tsx │ │ │ ├── popover.tsx │ │ │ ├── badge.tsx │ │ │ ├── alert.tsx │ │ │ ├── tooltip.tsx │ │ │ ├── scroll-area.tsx │ │ │ ├── tabs.tsx │ │ │ ├── card.tsx │ │ │ ├── button.tsx │ │ │ ├── input-otp.tsx │ │ │ ├── table.tsx │ │ │ ├── calendar.tsx │ │ │ ├── kibo-ui │ │ │ │ └── image-zoom.tsx │ │ │ ├── dialog.tsx │ │ │ ├── form.tsx │ │ │ ├── alert-dialog.tsx │ │ │ ├── sheet.tsx │ │ │ ├── reactbits │ │ │ │ └── split-text.tsx │ │ │ └── command.tsx │ │ ├── skip-to-main.tsx │ │ ├── coming-soon.tsx │ │ ├── layout │ │ │ ├── main.tsx │ │ │ ├── types.ts │ │ │ ├── new-analysis-btn.tsx │ │ │ ├── authenticated-layout.tsx │ │ │ ├── header.tsx │ │ │ ├── top-nav.tsx │ │ │ └── app-sidebar.tsx │ │ ├── navigation-progress.tsx │ │ ├── search.tsx │ │ ├── learn-more.tsx │ │ ├── select-dropdown.tsx │ │ ├── confirm-dialog.tsx │ │ ├── theme-switch.tsx │ │ ├── long-text.tsx │ │ ├── setting.tsx │ │ └── command-menu.tsx │ ├── utils │ │ ├── show-submitted-data.tsx │ │ └── handle-server-error.ts │ ├── hooks │ │ ├── use-dialog-state.tsx │ │ ├── use-mobile.tsx │ │ ├── use-table-list.tsx │ │ ├── use-sidebar-data.tsx │ │ ├── use-global-file-drop.ts │ │ ├── use-table-data.tsx │ │ └── use-analysis.tsx │ ├── features │ │ ├── errors │ │ │ ├── maintenance-error.tsx │ │ │ ├── forbidden.tsx │ │ │ ├── unauthorized-error.tsx │ │ │ ├── not-found-error.tsx │ │ │ └── general-error.tsx │ │ ├── table-preview │ │ │ └── components │ │ │ │ ├── editable-table-name.tsx │ │ │ │ ├── rename-table-form.tsx │ │ │ │ └── table-columns.tsx │ │ └── analysis-report │ │ │ └── components │ │ │ └── followup-input.tsx │ ├── config │ │ └── fonts.ts │ ├── context │ │ ├── search-context.tsx │ │ ├── font-context.tsx │ │ ├── settings-context.tsx │ │ ├── theme-context.tsx │ │ └── analysis-history-context.tsx │ ├── assets │ │ └── vite.svg │ ├── stores │ │ └── authStore.ts │ └── main.tsx ├── knip.config.ts ├── tsconfig.json ├── .prettierignore ├── components.json ├── tsconfig.node.json ├── vite.config.ts ├── tsconfig.app.json ├── Dockerfile ├── index.html ├── .prettierrc ├── eslint.config.js └── package.json ├── .assets └── preview.gif ├── app ├── src │ ├── routers │ │ ├── health.py │ │ ├── __init__.py │ │ ├── model_list.py │ │ └── new_analysis.py │ ├── models │ │ ├── requests.py │ │ ├── __init__.py │ │ └── responses.py │ ├── utils │ │ ├── __init__.py │ │ ├── prompts.py │ │ ├── reports.py │ │ └── llm_models.py │ ├── main.py │ ├── database.py │ ├── prompts │ │ ├── prompt-v3.txt │ │ └── prompt-v3+.txt │ ├── db_to_schema.py │ └── code_service.py ├── requirements.txt └── Dockerfile ├── sandbox ├── Dockerfile └── requirements.txt ├── .dbsetting ├── db └── init.sql ├── .gitignore ├── docker-compose.yml ├── docker-compose.dev.yml └── README.md /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | We are working on this, please wait for update 2 | -------------------------------------------------------------------------------- /frontend/Dockerfile.dev: -------------------------------------------------------------------------------- 1 | FROM node:22-alpine 2 | 3 | WORKDIR /app 4 | -------------------------------------------------------------------------------- /.assets/preview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quelmap-inc/quelmap/HEAD/.assets/preview.gif -------------------------------------------------------------------------------- /frontend/netlify.toml: -------------------------------------------------------------------------------- 1 | [[redirects]] 2 | from = "/*" 3 | to = "/index.html" 4 | status = 200 -------------------------------------------------------------------------------- /frontend/public/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quelmap-inc/quelmap/HEAD/frontend/public/images/favicon.ico -------------------------------------------------------------------------------- /frontend/public/images/sqlite-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quelmap-inc/quelmap/HEAD/frontend/public/images/sqlite-icon.png -------------------------------------------------------------------------------- /frontend/public/images/favicon_light.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quelmap-inc/quelmap/HEAD/frontend/public/images/favicon_light.ico -------------------------------------------------------------------------------- /frontend/public/images/postgres-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quelmap-inc/quelmap/HEAD/frontend/public/images/postgres-icon.png -------------------------------------------------------------------------------- /frontend/public/images/xlsx-csv-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quelmap-inc/quelmap/HEAD/frontend/public/images/xlsx-csv-icon.png -------------------------------------------------------------------------------- /frontend/cz.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | commitizen: 3 | name: cz_conventional_commits 4 | tag_format: v$version 5 | update_changelog_on_bump: true 6 | version_provider: npm 7 | version_scheme: semver 8 | -------------------------------------------------------------------------------- /app/src/routers/health.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | 3 | router = APIRouter() 4 | 5 | @router.get("/health") 6 | async def health_check(): 7 | """ヘルスチェックエンドポイント""" 8 | return {"status": "healthy"} 9 | -------------------------------------------------------------------------------- /frontend/src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from 'clsx' 2 | import { twMerge } from 'tailwind-merge' 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /frontend/knip.config.ts: -------------------------------------------------------------------------------- 1 | import type { KnipConfig } from 'knip'; 2 | 3 | const config: KnipConfig = { 4 | ignore: ['src/components/ui/**', 'src/routeTree.gen.ts'], 5 | ignoreDependencies: ["tailwindcss", "tw-animate-css"] 6 | }; 7 | 8 | export default config; -------------------------------------------------------------------------------- /frontend/src/routes/(errors)/403.tsx: -------------------------------------------------------------------------------- 1 | import { createFileRoute } from '@tanstack/react-router' 2 | import ForbiddenError from '@/features/errors/forbidden' 3 | 4 | export const Route = createFileRoute('/(errors)/403')({ 5 | component: ForbiddenError, 6 | }) 7 | -------------------------------------------------------------------------------- /frontend/src/routes/(errors)/500.tsx: -------------------------------------------------------------------------------- 1 | import { createFileRoute } from '@tanstack/react-router' 2 | import GeneralError from '@/features/errors/general-error' 3 | 4 | export const Route = createFileRoute('/(errors)/500')({ 5 | component: GeneralError, 6 | }) 7 | -------------------------------------------------------------------------------- /frontend/src/routes/(errors)/404.tsx: -------------------------------------------------------------------------------- 1 | import { createFileRoute } from '@tanstack/react-router' 2 | import NotFoundError from '@/features/errors/not-found-error' 3 | 4 | export const Route = createFileRoute('/(errors)/404')({ 5 | component: NotFoundError, 6 | }) 7 | -------------------------------------------------------------------------------- /frontend/src/routes/_authenticated/index.tsx: -------------------------------------------------------------------------------- 1 | import { createFileRoute } from '@tanstack/react-router' 2 | import NewAnalysis from '@/features/new-analysis' 3 | 4 | export const Route = createFileRoute('/_authenticated/')({ 5 | component: NewAnalysis, 6 | }) 7 | -------------------------------------------------------------------------------- /frontend/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | interface ImportMetaEnv { 3 | readonly VITE_SERVER_URL: string 4 | readonly USER_DATABASE_URL: string 5 | } 6 | 7 | interface ImportMeta { 8 | readonly env: ImportMetaEnv 9 | } 10 | -------------------------------------------------------------------------------- /sandbox/Dockerfile: -------------------------------------------------------------------------------- 1 | # ベースイメージ 2 | FROM python:3.11-slim 3 | 4 | # 作業ディレクトリ設定 5 | WORKDIR /usr/src/app 6 | 7 | # 依存関係をコピーしてインストール 8 | COPY requirements.txt ./ 9 | RUN pip install --no-cache-dir -r requirements.txt 10 | 11 | # アプリケーションコードをコピー 12 | COPY main.py . -------------------------------------------------------------------------------- /frontend/src/routes/(errors)/401.tsx: -------------------------------------------------------------------------------- 1 | import { createFileRoute } from '@tanstack/react-router' 2 | import UnauthorisedError from '@/features/errors/unauthorized-error' 3 | 4 | export const Route = createFileRoute('/(errors)/401')({ 5 | component: UnauthorisedError, 6 | }) 7 | -------------------------------------------------------------------------------- /frontend/src/routes/(errors)/503.tsx: -------------------------------------------------------------------------------- 1 | import { createFileRoute } from '@tanstack/react-router' 2 | import MaintenanceError from '@/features/errors/maintenance-error' 3 | 4 | export const Route = createFileRoute('/(errors)/503')({ 5 | component: MaintenanceError, 6 | }) 7 | -------------------------------------------------------------------------------- /frontend/src/routes/_authenticated/table/$tableName.tsx: -------------------------------------------------------------------------------- 1 | import { createFileRoute } from '@tanstack/react-router' 2 | import TablePreview from '@/features/table-preview' 3 | 4 | export const Route = createFileRoute('/_authenticated/table/$tableName')({ 5 | component: TablePreview, 6 | }) 7 | -------------------------------------------------------------------------------- /frontend/src/routes/_authenticated/report/$reportId.tsx: -------------------------------------------------------------------------------- 1 | import { createFileRoute } from '@tanstack/react-router' 2 | import AnalysisEReport from '@/features/analysis-report' 3 | 4 | export const Route = createFileRoute('/_authenticated/report/$reportId')({ 5 | component: AnalysisEReport, 6 | }) 7 | -------------------------------------------------------------------------------- /frontend/src/routes/_authenticated/route.tsx: -------------------------------------------------------------------------------- 1 | import { createFileRoute } from '@tanstack/react-router' 2 | import { AuthenticatedLayout } from '@/components/layout/authenticated-layout' 3 | 4 | export const Route = createFileRoute('/_authenticated')({ 5 | component: AuthenticatedLayout, 6 | }) 7 | -------------------------------------------------------------------------------- /frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.app.json" }, 5 | { "path": "./tsconfig.node.json" } 6 | ], 7 | "compilerOptions": { 8 | "baseUrl": ".", 9 | "paths": { 10 | "@/*": ["./src/*"] 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /sandbox/requirements.txt: -------------------------------------------------------------------------------- 1 | fastapi 2 | uvicorn[standard] 3 | pandas 4 | sqlalchemy 5 | psycopg2-binary # PostgreSQL用ドライバ 6 | pydantic 7 | numpy 8 | scikit-learn 9 | markdown 10 | tabulate 11 | matplotlib 12 | japanize-matplotlib 13 | seaborn 14 | scipy 15 | sympy 16 | statsmodels 17 | umap-learn -------------------------------------------------------------------------------- /app/requirements.txt: -------------------------------------------------------------------------------- 1 | fastapi 2 | uvicorn[standard] 3 | requests # code_runnerにHTTPリクエストを送るため 4 | pydantic 5 | jinja2 6 | python-multipart 7 | markdown 8 | 9 | tabulate 10 | sqlalchemy 11 | psycopg2-binary 12 | pandas 13 | 14 | 15 | openai==1.74.0 16 | 17 | numpy 18 | torch 19 | torchvision 20 | openpyxl 21 | -------------------------------------------------------------------------------- /.dbsetting: -------------------------------------------------------------------------------- 1 | POSTGRES_USER=admin 2 | POSTGRES_PASSWORD=quelmap_admin_pass_hewifoe35c5hdKocuiwec7672DaJ0918y 3 | POSTGRES_DB=main_db 4 | 5 | # Readonly user for Code Sandbox 6 | DB_READER_PASSWORD=quelmap_reader_pass_j30hcnidm3cbirubco3JKN # Please match with db/init.sql 7 | DB_READER_USER=reader # Please match with db/init.sql -------------------------------------------------------------------------------- /app/src/routers/__init__.py: -------------------------------------------------------------------------------- 1 | from .data import router as data_router 2 | from .health import router as health_router 3 | from .new_analysis import router as new_analysis_router 4 | from .model_list import router as model_list_router 5 | 6 | __all__ = [ 7 | "data_router", 8 | "health_router", 9 | "new_analysis_router", 10 | "model_list_router" 11 | ] 12 | -------------------------------------------------------------------------------- /frontend/src/components/ui/skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@/lib/utils' 2 | 3 | function Skeleton({ className, ...props }: React.ComponentProps<'div'>) { 4 | return ( 5 |
10 | ) 11 | } 12 | 13 | export { Skeleton } 14 | -------------------------------------------------------------------------------- /app/src/models/requests.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | from typing import List 3 | 4 | class VariableRetrievalResponse(BaseModel): 5 | id: str 6 | name: str 7 | 8 | class StartAnalysisRequest(BaseModel): 9 | space_id: str 10 | query: str 11 | tables: List[str] = [] 12 | mode: str = "standard" 13 | model: str = "" 14 | index: int = -1 15 | -------------------------------------------------------------------------------- /frontend/.prettierignore: -------------------------------------------------------------------------------- 1 | # Ignore everything 2 | /* 3 | 4 | # Except these files & folders 5 | !/src 6 | !index.html 7 | !package.json 8 | !tailwind.config.js 9 | !tsconfig.json 10 | !tsconfig.node.json 11 | !vite.config.ts 12 | !.prettierrc 13 | !README.md 14 | !eslint.config.js 15 | !postcss.config.js 16 | 17 | # Ignore auto generated routeTree.gen.ts 18 | /src/routeTree.gen.ts -------------------------------------------------------------------------------- /frontend/src/components/ui/shadcn-io/spinner/Bars.tsx: -------------------------------------------------------------------------------- 1 | import { Spinner } from '.' 2 | 3 | interface BarsProps { 4 | size?: 'sm' | 'md' | 'lg' 5 | className?: string 6 | } 7 | 8 | const Bars: React.FC = ({ size = 'md', className }) => { 9 | return ( 10 | 11 | ) 12 | } 13 | 14 | export default Bars -------------------------------------------------------------------------------- /app/Dockerfile: -------------------------------------------------------------------------------- 1 | # ベースイメージ 2 | FROM python:3.10-slim 3 | 4 | # 作業ディレクトリ設定 5 | WORKDIR /usr/src/app 6 | 7 | # 依存関係をコピーしてインストール 8 | COPY requirements.txt ./ 9 | RUN pip install --no-cache-dir -r requirements.txt 10 | 11 | # アプリケーションコードと関連ディレクトリをコピー 12 | COPY src /usr/src/app/ 13 | 14 | # EXPOSE 8000 (ドキュメント用、オプション) 15 | CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"] 16 | -------------------------------------------------------------------------------- /app/src/utils/__init__.py: -------------------------------------------------------------------------------- 1 | from .prompts import get_db_embedded_prompt, set_db_schema, is_database_registered 2 | from .reports import save_report 3 | from .llm_models import get_model_list, get_openai_client,get_model_by_id 4 | 5 | __all__ = [ 6 | "get_db_embedded_prompt", 7 | "set_db_schema", 8 | "is_database_registered", 9 | "save_report", 10 | "get_model_list", 11 | "get_openai_client", 12 | "get_model_by_id", 13 | ] 14 | -------------------------------------------------------------------------------- /frontend/src/components/skip-to-main.tsx: -------------------------------------------------------------------------------- 1 | const SkipToMain = () => { 2 | return ( 3 | 7 | Skip to Main 8 | 9 | ) 10 | } 11 | 12 | export default SkipToMain 13 | -------------------------------------------------------------------------------- /frontend/src/utils/show-submitted-data.tsx: -------------------------------------------------------------------------------- 1 | import { toast } from 'sonner' 2 | 3 | export function showSubmittedData( 4 | data: unknown, 5 | title: string = 'You submitted the following values:' 6 | ) { 7 | toast.message(title, { 8 | description: ( 9 | // w-[340px] 10 |
11 |         {JSON.stringify(data, null, 2)}
12 |       
13 | ), 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /db/init.sql: -------------------------------------------------------------------------------- 1 | -- db_init/init.sql 2 | 3 | CREATE USER reader WITH PASSWORD 'quelmap_reader_pass_j30hcnidm3cbirubco3JKN'; 4 | 5 | -- DBへの接続権限を付与 6 | GRANT CONNECT ON DATABASE main_db TO reader; 7 | 8 | -- publicスキーマの使用権限を付与 9 | GRANT USAGE ON SCHEMA public TO reader; 10 | 11 | -- publicスキーマ内の全ての既存テーブルに対するSELECT権限を付与 12 | GRANT SELECT ON ALL TABLES IN SCHEMA public TO reader; 13 | 14 | -- 今後作成されるテーブルに対しても自動でSELECT権限を付与する設定 15 | ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO reader; -------------------------------------------------------------------------------- /app/src/models/__init__.py: -------------------------------------------------------------------------------- 1 | from .requests import VariableRetrievalResponse, StartAnalysisRequest 2 | from .responses import ConnectionResponse, ErrorResponse, StartAnalysisResponse, GetReportResponse,GetSpaceResponse,CreateSpaceResponse 3 | 4 | __all__ = [ 5 | "VariableRetrievalResponse", 6 | "StartAnalysisRequest", 7 | "ConnectionResponse", 8 | "ErrorResponse", 9 | "StartAnalysisResponse", 10 | "GetReportResponse", 11 | "GetSpaceResponse", 12 | "CreateSpaceResponse" 13 | ] 14 | -------------------------------------------------------------------------------- /frontend/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": false, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "", 8 | "css": "src/index.css", 9 | "baseColor": "slate", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils", 16 | "ui": "@/components/ui", 17 | "lib": "@/lib", 18 | "hooks": "@/hooks" 19 | }, 20 | "iconLibrary": "lucide" 21 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | __pycache__/ 3 | 4 | app/src/exports 5 | 6 | # Logs 7 | frontend/logs 8 | frontend/*.log 9 | frontend/npm-debug.log* 10 | frontend/yarn-debug.log* 11 | frontend/yarn-error.log* 12 | frontend/pnpm-debug.log* 13 | frontend/lerna-debug.log* 14 | frontend/.tanstack 15 | frontend/node_modules 16 | frontend/dist 17 | frontend/dist-ssr 18 | frontend/*.local 19 | 20 | .env 21 | 22 | # Editor directories and files 23 | .vscode/* 24 | !.vscode/extensions.json 25 | .idea 26 | .DS_Store 27 | *.suo 28 | *.ntvs* 29 | *.njsproj 30 | *.sln 31 | *.sw? 32 | log -------------------------------------------------------------------------------- /frontend/src/components/coming-soon.tsx: -------------------------------------------------------------------------------- 1 | import { IconPlanet } from '@tabler/icons-react' 2 | 3 | export default function ComingSoon() { 4 | return ( 5 |
6 |
7 | 8 |

Coming Soon 👀

9 |

10 | This page has not been created yet.
11 | Stay tuned though! 12 |

13 |
14 |
15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /frontend/src/utils/handle-server-error.ts: -------------------------------------------------------------------------------- 1 | import { AxiosError } from 'axios' 2 | import { toast } from 'sonner' 3 | 4 | export function handleServerError(error: unknown) { 5 | // eslint-disable-next-line no-console 6 | console.log(error) 7 | 8 | let errMsg = 'Something went wrong!' 9 | 10 | if ( 11 | error && 12 | typeof error === 'object' && 13 | 'status' in error && 14 | Number(error.status) === 204 15 | ) { 16 | errMsg = 'Content not found.' 17 | } 18 | 19 | if (error instanceof AxiosError) { 20 | errMsg = error.response?.data.title 21 | } 22 | 23 | toast.error(errMsg) 24 | } 25 | -------------------------------------------------------------------------------- /frontend/src/components/layout/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { cn } from '@/lib/utils' 3 | 4 | interface MainProps extends React.HTMLAttributes { 5 | fixed?: boolean 6 | ref?: React.Ref 7 | } 8 | 9 | export const Main = ({ fixed, className, ...props }: MainProps) => { 10 | return ( 11 |
20 | ) 21 | } 22 | 23 | Main.displayName = 'Main' 24 | -------------------------------------------------------------------------------- /frontend/src/hooks/use-dialog-state.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | 3 | /** 4 | * Custom hook for confirm dialog 5 | * @param initialState string | null 6 | * @returns A stateful value, and a function to update it. 7 | * @example const [open, setOpen] = useDialogState<"approve" | "reject">() 8 | */ 9 | export default function useDialogState( 10 | initialState: T | null = null 11 | ) { 12 | const [open, _setOpen] = useState(initialState) 13 | 14 | const setOpen = (str: T | null) => 15 | _setOpen((prev) => (prev === str ? null : str)) 16 | 17 | return [open, setOpen] as const 18 | } 19 | -------------------------------------------------------------------------------- /app/src/routers/model_list.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | from ..models.responses import GetModelListResponse 3 | from ..models.responses import LLMMODEL 4 | from ..utils.llm_models import get_model_list as get_model_list_util 5 | 6 | 7 | router = APIRouter() 8 | 9 | @router.get("/get-model-list", response_model=GetModelListResponse) 10 | def get_model_list(base_url: str , api_key=""): 11 | models = get_model_list_util(base_url, api_key) 12 | return GetModelListResponse(models=[LLMMODEL(id=model["id"], name=model["display_name"] if model["display_name"] else model["model_name"], description=model["description"]) for model in models]) 13 | -------------------------------------------------------------------------------- /frontend/src/hooks/use-mobile.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | const MOBILE_BREAKPOINT = 768 4 | 5 | export function useIsMobile() { 6 | const [isMobile, setIsMobile] = React.useState(undefined) 7 | 8 | React.useEffect(() => { 9 | const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`) 10 | const onChange = () => { 11 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) 12 | } 13 | mql.addEventListener('change', onChange) 14 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) 15 | return () => mql.removeEventListener('change', onChange) 16 | }, []) 17 | 18 | return !!isMobile 19 | } 20 | -------------------------------------------------------------------------------- /frontend/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 4 | "target": "ES2022", 5 | "lib": ["ES2023"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "Bundler", 11 | "allowImportingTsExtensions": true, 12 | "isolatedModules": true, 13 | "moduleDetection": "force", 14 | "noEmit": true, 15 | 16 | /* Linting */ 17 | "strict": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noFallthroughCasesInSwitch": true, 21 | "noUncheckedSideEffectImports": true 22 | }, 23 | "include": ["vite.config.ts"] 24 | } 25 | -------------------------------------------------------------------------------- /frontend/src/components/navigation-progress.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef } from 'react' 2 | import { useRouterState } from '@tanstack/react-router' 3 | import LoadingBar, { LoadingBarRef } from 'react-top-loading-bar' 4 | 5 | export function NavigationProgress() { 6 | const ref = useRef(null) 7 | const state = useRouterState() 8 | 9 | useEffect(() => { 10 | if (state.status === 'pending') { 11 | ref.current?.continuousStart() 12 | } else { 13 | ref.current?.complete() 14 | } 15 | }, [state.status]) 16 | 17 | return ( 18 | 24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /frontend/src/components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import * as React from 'react' 4 | import * as LabelPrimitive from '@radix-ui/react-label' 5 | import { cn } from '@/lib/utils' 6 | 7 | function Label({ 8 | className, 9 | ...props 10 | }: React.ComponentProps) { 11 | return ( 12 | 20 | ) 21 | } 22 | 23 | export { Label } 24 | -------------------------------------------------------------------------------- /frontend/src/components/ui/sonner.tsx: -------------------------------------------------------------------------------- 1 | import { Toaster as Sonner, ToasterProps } from 'sonner' 2 | import { useTheme } from '@/context/theme-context' 3 | 4 | const Toaster = ({ ...props }: ToasterProps) => { 5 | const { theme = 'system' } = useTheme() 6 | 7 | return ( 8 | 21 | ) 22 | } 23 | 24 | export { Toaster } 25 | -------------------------------------------------------------------------------- /frontend/src/features/errors/maintenance-error.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from '@/components/ui/button' 2 | 3 | export default function MaintenanceError() { 4 | return ( 5 |
6 |
7 |

503

8 | Website is under maintenance! 9 |

10 | The site is not available at the moment.
11 | We'll be back online shortly. 12 |

13 |
14 | 15 |
16 |
17 |
18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | from fastapi.middleware.cors import CORSMiddleware 3 | import asyncio 4 | from .routers import data_router, health_router, new_analysis_router,model_list_router 5 | from .utils.prompts import set_db_schema 6 | 7 | app = FastAPI() 8 | 9 | app.add_middleware( 10 | CORSMiddleware, 11 | allow_origins=["*"], # ← ここの値を確認 12 | allow_credentials=True, 13 | allow_methods=["*"], # OPTIONSメソッドが許可されているか 14 | allow_headers=["*"], 15 | ) 16 | 17 | # ルーターを登録 18 | app.include_router(data_router) 19 | app.include_router(health_router) 20 | app.include_router(new_analysis_router) 21 | app.include_router(model_list_router) 22 | 23 | #アプリケーション起動時にデータベーススキーマを設定 24 | @app.on_event("startup") 25 | async def startup_event(): 26 | # データベーススキーマを設定 27 | set_db_schema() -------------------------------------------------------------------------------- /frontend/src/components/ui/separator.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import * as SeparatorPrimitive from '@radix-ui/react-separator' 3 | import { cn } from '@/lib/utils' 4 | 5 | function Separator({ 6 | className, 7 | orientation = 'horizontal', 8 | decorative = true, 9 | ...props 10 | }: React.ComponentProps) { 11 | return ( 12 | 22 | ) 23 | } 24 | 25 | export { Separator } 26 | -------------------------------------------------------------------------------- /frontend/src/components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { cn } from '@/lib/utils' 3 | 4 | function Textarea({ className, ...props }: React.ComponentProps<'textarea'>) { 5 | return ( 6 |