├── public ├── test │ └── data │ │ └── 05-versions-space.pdf ├── ab.png ├── eb.png ├── ib.png ├── kb.png ├── sb.png ├── abb.png ├── ebb.png ├── ibb.png ├── kbb.png ├── logo.ico ├── ollama.png ├── ollama-bg.png ├── easter-egg1.jpg ├── easter-egg2.jpg └── logo.svg ├── app ├── favicon.ico ├── favicon.png ├── fonts │ ├── GeistVF.woff │ └── GeistMonoVF.woff ├── logout.tsx ├── utils │ └── feedback.ts ├── types │ └── feedback.ts ├── auth │ └── callback │ │ └── route.ts ├── sitemap.ts ├── api │ ├── feedback │ │ └── route.ts │ ├── parse-pdf │ │ └── route.tsx │ └── chat │ │ └── route.ts ├── ChatContext.tsx ├── layout.tsx ├── globals.css ├── page.tsx ├── opengraph-image.tsx └── about │ └── page.tsx ├── utils └── common.ts ├── postcss.config.mjs ├── tools ├── sejmstats-utils.ts ├── wikipedia-search.ts ├── sejmstats-server.ts ├── enhancedTool.ts ├── wikipedia.ts └── sejmstats.ts ├── lib ├── easter-eggs.ts ├── plugins.ts ├── get-patronite-users.tsx ├── types.ts ├── utils.ts ├── prompts.ts ├── llms │ ├── LLM.ts │ ├── TogetherLLm.ts │ └── OpenAILLm.ts ├── prompt-tracking.tsx └── store.ts ├── components ├── ui │ ├── skeleton.tsx │ ├── label.tsx │ ├── textarea.tsx │ ├── separator.tsx │ ├── input.tsx │ ├── toaster.tsx │ ├── slider.tsx │ ├── tooltip.tsx │ ├── switch.tsx │ ├── badge.tsx │ ├── popover.tsx │ ├── avatar.tsx │ ├── alert.tsx │ ├── scroll-area.tsx │ ├── resizable.tsx │ ├── button.tsx │ ├── tabs.tsx │ ├── card.tsx │ ├── dialog.tsx │ ├── sheet.tsx │ └── toast.tsx ├── theme-provider.tsx ├── markdownResponse.tsx ├── loadingDots.tsx ├── summary.tsx ├── landing-page │ ├── featureCard.tsx │ ├── capbility-card.tsx │ ├── image-slider.tsx │ ├── login.tsx │ ├── footer.tsx │ ├── diagram.tsx │ ├── comparsion-section.tsx │ └── about.tsx ├── feedback-dialog.tsx ├── landing-page.tsx ├── navbar.tsx ├── feedback-history.tsx └── initial-page.tsx ├── components.json ├── hooks ├── use-media-query.tsx ├── use-mobile.tsx ├── useFileHandling.ts ├── feedback.ts ├── streamProcessor.ts └── use-toast.ts ├── .gitignore ├── middleware.ts ├── tsconfig.json ├── next.config.mjs ├── README.md ├── package.json ├── tailwind.config.ts ├── .github └── workflows │ └── nextjs.yml └── yt ├── devlog2.md └── devlog1.md /public/test/data/05-versions-space.pdf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/ab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miskibin/asystent-rp/HEAD/public/ab.png -------------------------------------------------------------------------------- /public/eb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miskibin/asystent-rp/HEAD/public/eb.png -------------------------------------------------------------------------------- /public/ib.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miskibin/asystent-rp/HEAD/public/ib.png -------------------------------------------------------------------------------- /public/kb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miskibin/asystent-rp/HEAD/public/kb.png -------------------------------------------------------------------------------- /public/sb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miskibin/asystent-rp/HEAD/public/sb.png -------------------------------------------------------------------------------- /app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miskibin/asystent-rp/HEAD/app/favicon.ico -------------------------------------------------------------------------------- /app/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miskibin/asystent-rp/HEAD/app/favicon.png -------------------------------------------------------------------------------- /public/abb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miskibin/asystent-rp/HEAD/public/abb.png -------------------------------------------------------------------------------- /public/ebb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miskibin/asystent-rp/HEAD/public/ebb.png -------------------------------------------------------------------------------- /public/ibb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miskibin/asystent-rp/HEAD/public/ibb.png -------------------------------------------------------------------------------- /public/kbb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miskibin/asystent-rp/HEAD/public/kbb.png -------------------------------------------------------------------------------- /public/logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miskibin/asystent-rp/HEAD/public/logo.ico -------------------------------------------------------------------------------- /public/ollama.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miskibin/asystent-rp/HEAD/public/ollama.png -------------------------------------------------------------------------------- /public/ollama-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miskibin/asystent-rp/HEAD/public/ollama-bg.png -------------------------------------------------------------------------------- /app/fonts/GeistVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miskibin/asystent-rp/HEAD/app/fonts/GeistVF.woff -------------------------------------------------------------------------------- /public/easter-egg1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miskibin/asystent-rp/HEAD/public/easter-egg1.jpg -------------------------------------------------------------------------------- /public/easter-egg2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miskibin/asystent-rp/HEAD/public/easter-egg2.jpg -------------------------------------------------------------------------------- /app/fonts/GeistMonoVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miskibin/asystent-rp/HEAD/app/fonts/GeistMonoVF.woff -------------------------------------------------------------------------------- /app/logout.tsx: -------------------------------------------------------------------------------- 1 | export default function Logout() { 2 | return Logout; 3 | } 4 | -------------------------------------------------------------------------------- /utils/common.ts: -------------------------------------------------------------------------------- 1 | export const generateUniqueId = () => { 2 | return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; 3 | }; 4 | -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /tools/sejmstats-utils.ts: -------------------------------------------------------------------------------- 1 | export function getActName(title: string): string { 2 | let trimmed = title.split("jednolitego tekstu ustawy")[1].trim(); 3 | if (trimmed.startsWith("o ")) return "Ustawa " + trimmed; 4 | return trimmed; 5 | } 6 | -------------------------------------------------------------------------------- /lib/easter-eggs.ts: -------------------------------------------------------------------------------- 1 | export const easterEggMapping = [ 2 | { regex: /f[üu]r\s+deutschland/i, photo: "easter-egg1.jpg" }, 3 | { 4 | regex: /miska\s+ry[żz]u|miski\s+ry[żz]u|miske\s+ry[żz]u|miskę\s+ry[żz]u/i, 5 | photo: "easter-egg2.jpg", 6 | }, 7 | ]; 8 | -------------------------------------------------------------------------------- /components/ui/skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib/utils" 2 | 3 | function Skeleton({ 4 | className, 5 | ...props 6 | }: React.HTMLAttributes) { 7 | return ( 8 |
12 | ) 13 | } 14 | 15 | export { Skeleton } 16 | -------------------------------------------------------------------------------- /components/theme-provider.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import { ThemeProvider as NextThemesProvider } from "next-themes" 5 | import { type ThemeProviderProps } from "next-themes/dist/types" 6 | 7 | export function ThemeProvider({ children, ...props }: ThemeProviderProps) { 8 | return {children} 9 | } 10 | -------------------------------------------------------------------------------- /lib/plugins.ts: -------------------------------------------------------------------------------- 1 | import { ChatPlugin } from "./types"; 2 | 3 | export enum PluginNames { 4 | SejmStats = "sejm-stats.pl", 5 | Wikipedia = "wikipedia", 6 | } 7 | 8 | export const plugins: ChatPlugin[] = [ 9 | { 10 | name: PluginNames.SejmStats, 11 | enabled: true, 12 | }, 13 | // { 14 | // name: PluginNames.Wikipedia, 15 | // enabled: false, 16 | // }, 17 | ]; 18 | -------------------------------------------------------------------------------- /components/markdownResponse.tsx: -------------------------------------------------------------------------------- 1 | // components/MarkdownResponse.tsx 2 | import React from "react"; 3 | import ReactMarkdown from "react-markdown"; 4 | 5 | interface MarkdownResponseProps { 6 | content: string; 7 | } 8 | 9 | const MarkdownResponse: React.FC = ({ content }) => { 10 | return {content}; 11 | }; 12 | 13 | export default MarkdownResponse; 14 | -------------------------------------------------------------------------------- /app/utils/feedback.ts: -------------------------------------------------------------------------------- 1 | import { Message } from "@/lib/types"; 2 | 3 | export function trimMessage(message: Message): Message { 4 | return { 5 | id: message.id, 6 | role: message.role, 7 | content: message.content?.slice(0, 300) ?? "", 8 | artifacts: 9 | message.artifacts?.map((artifact) => ({ 10 | type: artifact.type, 11 | question: artifact.question, 12 | searchQuery: artifact.searchQuery, 13 | data: artifact.data, 14 | })) ?? [], 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "app/globals.css", 9 | "baseColor": "neutral", 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 | } -------------------------------------------------------------------------------- /hooks/use-media-query.tsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | 3 | export function useMediaQuery(query: string): boolean { 4 | const [matches, setMatches] = useState(false); 5 | 6 | useEffect(() => { 7 | const media = window.matchMedia(query); 8 | if (media.matches !== matches) { 9 | setMatches(media.matches); 10 | } 11 | const listener = () => setMatches(media.matches); 12 | media.addListener(listener); 13 | return () => media.removeListener(listener); 14 | }, [matches, query]); 15 | 16 | return matches; 17 | } 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | *.log 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | 38 | .vercel 39 | -------------------------------------------------------------------------------- /app/types/feedback.ts: -------------------------------------------------------------------------------- 1 | import { Message } from "@/lib/types"; 2 | 3 | export interface FeedbackPayload { 4 | messageId: string; 5 | user: string; 6 | reason?: string; 7 | context: Message[]; 8 | } 9 | 10 | export interface UseFeedbackLogicProps { 11 | messages: Message[]; 12 | } 13 | 14 | export interface UseFeedbackLogicReturn { 15 | isDialogOpen: boolean; 16 | setIsDialogOpen: (open: boolean) => void; 17 | feedbackSent: boolean; 18 | isSubmitting: boolean; 19 | reason: string; 20 | setReason: (reason: string) => void; 21 | handleFeedback: () => Promise; 22 | } 23 | -------------------------------------------------------------------------------- /middleware.ts: -------------------------------------------------------------------------------- 1 | // middleware.ts 2 | import { createMiddlewareClient } from "@supabase/auth-helpers-nextjs"; 3 | import { NextResponse } from "next/server"; 4 | import type { NextRequest } from "next/server"; 5 | 6 | export async function middleware(req: NextRequest) { 7 | const res = NextResponse.next(); 8 | const supabase = createMiddlewareClient({ req, res }); 9 | 10 | const { 11 | data: { session }, 12 | } = await supabase.auth.getSession(); 13 | 14 | return res; 15 | } 16 | 17 | export const config = { 18 | matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"], 19 | }; 20 | -------------------------------------------------------------------------------- /app/auth/callback/route.ts: -------------------------------------------------------------------------------- 1 | import { createRouteHandlerClient } from "@supabase/auth-helpers-nextjs"; 2 | import { cookies } from "next/headers"; 3 | import { NextResponse } from "next/server"; 4 | 5 | export async function GET(request: Request) { 6 | const requestUrl = new URL(request.url); 7 | const code = requestUrl.searchParams.get("code"); 8 | 9 | if (code) { 10 | const supabase = createRouteHandlerClient({ cookies }); 11 | await supabase.auth.exchangeCodeForSession(code); 12 | } 13 | 14 | // URL to redirect to after sign in process completes 15 | return NextResponse.redirect(requestUrl.origin); 16 | } 17 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": true, 7 | "noEmit": true, 8 | "esModuleInterop": true, 9 | "module": "esnext", 10 | "moduleResolution": "bundler", 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "jsx": "preserve", 14 | "incremental": true, 15 | "plugins": [ 16 | { 17 | "name": "next" 18 | } 19 | ], 20 | "paths": { 21 | "@/*": ["./*"] 22 | } 23 | }, 24 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 25 | "exclude": ["node_modules"] 26 | } 27 | -------------------------------------------------------------------------------- /components/loadingDots.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { motion } from 'framer-motion'; 3 | 4 | const LoadingDots = () => { 5 | return ( 6 |
7 | {[0, 1, 2].map((index) => ( 8 | 21 | ))} 22 |
23 | ); 24 | }; 25 | 26 | export default LoadingDots; -------------------------------------------------------------------------------- /tools/wikipedia-search.ts: -------------------------------------------------------------------------------- 1 | "use server"; 2 | import { WikipediaQueryRun } from "@langchain/community/tools/wikipedia_query_run"; 3 | 4 | const wikipediaTool = new WikipediaQueryRun({ 5 | topKResults: 1, 6 | maxDocContentLength: 2000, 7 | }); 8 | 9 | async function searchWikipedia(question: string): Promise { 10 | try { 11 | console.log("Searching Wikipedia for:", question); 12 | const result = await wikipediaTool.invoke(question); 13 | console.log("Wikipedia search result:", result); 14 | return result; 15 | } catch (error) { 16 | console.error("Error searching Wikipedia:", error); 17 | return "An error occurred while searching Wikipedia."; 18 | } 19 | } 20 | 21 | export { searchWikipedia }; 22 | -------------------------------------------------------------------------------- /app/sitemap.ts: -------------------------------------------------------------------------------- 1 | import type { MetadataRoute } from "next"; 2 | 3 | export default function sitemap(): MetadataRoute.Sitemap { 4 | return [ 5 | { 6 | url: "https://chat.sejm-stats.pl", 7 | lastModified: new Date(), 8 | changeFrequency: "weekly", 9 | priority: 1, 10 | }, 11 | { 12 | url: "https://chat.sejm-stats.pl/about", 13 | lastModified: new Date(), 14 | changeFrequency: "monthly", 15 | priority: 0.8, 16 | }, 17 | { 18 | url: "https://chat.sejm-stats.pl/privacy", 19 | lastModified: new Date(), 20 | changeFrequency: "yearly", 21 | priority: 0.2, 22 | }, 23 | { 24 | url: "https://chat.sejm-stats.pl/terms-of-service", 25 | lastModified: new Date(), 26 | changeFrequency: "yearly", 27 | priority: 0.2, 28 | }, 29 | ]; 30 | } 31 | -------------------------------------------------------------------------------- /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 { cva, type VariantProps } from "class-variance-authority" 6 | 7 | import { cn } from "@/lib/utils" 8 | 9 | const labelVariants = cva( 10 | "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" 11 | ) 12 | 13 | const Label = React.forwardRef< 14 | React.ElementRef, 15 | React.ComponentPropsWithoutRef & 16 | VariantProps 17 | >(({ className, ...props }, ref) => ( 18 | 23 | )) 24 | Label.displayName = LabelPrimitive.Root.displayName 25 | 26 | export { Label } 27 | -------------------------------------------------------------------------------- /components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | export interface TextareaProps 6 | extends React.TextareaHTMLAttributes {} 7 | 8 | const Textarea = React.forwardRef( 9 | ({ className, ...props }, ref) => { 10 | return ( 11 |