English | 한국어

LinkLog

Flutter + Supabase 기반 사용자 정의 RAG 빌더
나만의 지식 베이스를 구축하고, AI에게 질문하세요.

Screenshots

Flutter Supabase OpenAI


아키텍처

LinkLog는 레이어 분리 및 유지보수성을 극대화한 Flutter 안티 그래비티 아키텍처를 기반으로 설계되었습니다.

┌─────────────────────────────────────────────────────────────┐
│                       Presentation Layer                    │
│            (Riverpod ViewModels & Screen Widgets)           │
└──────────────────────────────┬──────────────────────────────┘
                               ▼
┌─────────────────────────────────────────────────────────────┐
│                         Domain Layer                        │
│            (Pure Dart Entities & Usecase Logic)             │
└──────────────────────────────┬──────────────────────────────┘
                               ▼
┌─────────────────────────────────────────────────────────────┐
│                           Data Layer                        │
│            (Supabase DTOs & Repository Implementations)      │
└──────────────────────────────┴─────────────────────────────┘

주요 기능

기능설명
API 설정Supabase URL/Key, OpenAI Key를 flutter_secure_storage로 안전하게 저장
문서 업로드텍스트 입력 → text-embedding-3-small 벡터화 → Supabase 저장
RAG 채팅질문 벡터화 → cosine similarity 검색 → GPT-4o-mini 답변 생성
문서 관리등록된 문서 목록 조회 및 삭제

시작하기

1. Supabase 설정

Supabase 프로젝트를 생성한 뒤, SQL Editor에서 아래 스크립트를 실행하세요:

-- pgvector 확장 활성화
create extension if not exists vector with schema extensions;

-- documents 테이블 생성
create table if not exists public.documents (
  id bigserial primary key,
  content text not null,
  metadata text,
  embedding vector(1536),
  created_at timestamptz default now()
);

-- 검색 성능 인덱스
create index if not exists documents_embedding_idx
  on public.documents
  using ivfflat (embedding vector_cosine_ops)
  with (lists = 100);

-- 유사도 검색 함수
create or replace function public.match_documents(
  query_embedding vector(1536),
  match_count int default 5,
  match_threshold float default 0.7
)
returns table (
  id bigint,
  content text,
  metadata text,
  similarity float
)
language plpgsql
as $$
begin
  return query
  select
    d.id, d.content, d.metadata,
    1 - (d.embedding <=> query_embedding) as similarity
  from public.documents d
  where 1 - (d.embedding <=> query_embedding) > match_threshold
  order by d.embedding <=> query_embedding
  limit match_count;
end;
$$;

-- RLS 정책
alter table public.documents enable row level security;
create policy "Allow public read" on public.documents for select using (true);
create policy "Allow public insert" on public.documents for insert with check (true);
create policy "Allow public delete" on public.documents for delete using (true);

전체 SQL 파일: supabase_setup.sql

2. 앱 실행

git clone https://github.com/kimdzhekhon/Link_log.git
cd Link_log
flutter pub get
flutter run

3. 앱 설정

  1. 설정 탭에서 Supabase URL, Anon Key, OpenAI API Key 입력
  2. 문서 탭에서 지식 베이스용 텍스트 추가
  3. 채팅 탭에서 질문 입력 → AI 답변 확인

기술 스택

구분기술
FrontendFlutter, Material 3
상태 관리flutter_riverpod
보안 저장소flutter_secure_storage
DatabaseSupabase (PostgreSQL + pgvector)
AIOpenAI text-embedding-3-small, GPT-4o-mini
통신http (REST API)

프로젝트 구조

lib/
├── main.dart                    # 앱 진입점, 네비게이션
├── providers/
│   └── providers.dart           # Riverpod 상태 관리
├── services/
│   ├── secure_storage_service.dart  # API 키 암호화 저장
│   ├── supabase_service.dart        # Supabase CRUD & RPC
│   └── openai_service.dart          # 임베딩 & Chat Completion
└── views/
    ├── settings_view.dart       # API 설정 UI
    ├── document_view.dart       # 문서 업로드/관리 UI
    └── chat_view.dart           # RAG 채팅 UI

라이선스

MIT License