- Reorganize project into monorepo structure - backend/app/ - New FastAPI backend (modular with src/) - backend/legacy/ - Legacy database modules (relational & vector) - frontend/ - React text editor application - Add launcher.py for easy full-stack startup - Complete documentation in README.md - Quick start guide - API endpoints reference - Development setup - Troubleshooting - Refactor main.py to 35 lines (app configuration only) - Update .gitignore for full-stack project - Add CHANGELOG.md with version history (v0.1.0-v0.1.1) Structure is now clean and ready for team collaboration.
102 lines
2.8 KiB
Python
102 lines
2.8 KiB
Python
import sqlite3
|
|
import json
|
|
import os
|
|
from fastapi import FastAPI, Body, HTTPException
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
import uvicorn
|
|
|
|
app = FastAPI()
|
|
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=["*"],
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
DB_FILE = os.path.join(BASE_DIR, "archivium.db")
|
|
|
|
|
|
def get_db_connection():
|
|
conn = sqlite3.connect(DB_FILE)
|
|
conn.execute("PRAGMA journal_mode=WAL;")
|
|
conn.row_factory = sqlite3.Row
|
|
return conn
|
|
|
|
|
|
def init_db():
|
|
with get_db_connection() as conn:
|
|
conn.execute("""
|
|
CREATE TABLE IF NOT EXISTS archive
|
|
(
|
|
id
|
|
INTEGER
|
|
PRIMARY
|
|
KEY
|
|
AUTOINCREMENT,
|
|
filename
|
|
TEXT
|
|
UNIQUE,
|
|
ocr_text
|
|
TEXT,
|
|
metadata
|
|
TEXT,
|
|
created_at
|
|
TIMESTAMP
|
|
DEFAULT
|
|
CURRENT_TIMESTAMP
|
|
)
|
|
""")
|
|
conn.commit()
|
|
|
|
|
|
init_db()
|
|
|
|
|
|
@app.post("/save-document")
|
|
async def save_document(data: dict = Body(...)):
|
|
title = data.get("title")
|
|
content = data.get("content")
|
|
|
|
if not title or content is None:
|
|
raise HTTPException(status_code=400, detail="Missing title or content")
|
|
|
|
content_str = json.dumps(content)
|
|
|
|
try:
|
|
with get_db_connection() as conn:
|
|
conn.execute("""
|
|
INSERT INTO archive (filename, ocr_text)
|
|
VALUES (?, ?) ON CONFLICT(filename) DO
|
|
UPDATE SET
|
|
ocr_text=excluded.ocr_text
|
|
""", (title, content_str))
|
|
conn.commit()
|
|
return {"status": "success"}
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
|
@app.get("/load-document")
|
|
async def load_document(title: str = None):
|
|
with get_db_connection() as conn:
|
|
if title:
|
|
row = conn.execute("SELECT filename, ocr_text FROM archive WHERE filename = ?", (title,)).fetchone()
|
|
else:
|
|
row = conn.execute("SELECT filename, ocr_text FROM archive ORDER BY id DESC LIMIT 1").fetchone()
|
|
|
|
if row:
|
|
try:
|
|
content_val = json.loads(row['ocr_text'])
|
|
except:
|
|
content_val = row['ocr_text']
|
|
|
|
return {"title": row['filename'], "content": content_val}
|
|
|
|
raise HTTPException(status_code=404, detail="Document not found")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
uvicorn.run(app, host="127.0.0.1", port=8000)
|