Making UI changes
This commit is contained in:
110
DEV-README.md
Normal file
110
DEV-README.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# Development Environment Setup
|
||||
|
||||
This guide explains how to run the application in development mode with hot reload enabled.
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Development Mode (Hot Reload)
|
||||
|
||||
```bash
|
||||
# Start all services in development mode
|
||||
docker-compose -f docker-compose.dev.yml up --build
|
||||
|
||||
# Or run in detached mode
|
||||
docker-compose -f docker-compose.dev.yml up -d --build
|
||||
```
|
||||
|
||||
### Production Mode
|
||||
|
||||
```bash
|
||||
# Start production services
|
||||
docker-compose up --build
|
||||
```
|
||||
|
||||
## What's Different in Dev Mode?
|
||||
|
||||
### Backend (Quart/Flask)
|
||||
- **Hot Reload**: Python code changes are automatically detected and the server restarts
|
||||
- **Source Mounted**: Your local `services/raggr` directory is mounted as a volume
|
||||
- **Debug Mode**: Flask runs with `debug=True` for better error messages
|
||||
- **Environment**: `FLASK_ENV=development` and `PYTHONUNBUFFERED=1` for immediate log output
|
||||
|
||||
### Frontend (React + rsbuild)
|
||||
- **Auto Rebuild**: Frontend automatically rebuilds when files change
|
||||
- **Watch Mode**: rsbuild runs in watch mode, rebuilding to `dist/` on save
|
||||
- **Source Mounted**: Your local `services/raggr/raggr-frontend` directory is mounted as a volume
|
||||
- **Served by Backend**: Built files are served by the backend, no separate dev server
|
||||
|
||||
## Ports
|
||||
|
||||
- **Application**: 8080 (accessible at `http://localhost:8080` or `http://YOUR_IP:8080`)
|
||||
|
||||
The backend serves both the API and the auto-rebuilt frontend, making it accessible from other machines on your network.
|
||||
|
||||
## Useful Commands
|
||||
|
||||
```bash
|
||||
# View logs
|
||||
docker-compose -f docker-compose.dev.yml logs -f
|
||||
|
||||
# View logs for specific service
|
||||
docker-compose -f docker-compose.dev.yml logs -f raggr-backend
|
||||
docker-compose -f docker-compose.dev.yml logs -f raggr-frontend
|
||||
|
||||
# Rebuild after dependency changes
|
||||
docker-compose -f docker-compose.dev.yml up --build
|
||||
|
||||
# Stop all services
|
||||
docker-compose -f docker-compose.dev.yml down
|
||||
|
||||
# Stop and remove volumes (fresh start)
|
||||
docker-compose -f docker-compose.dev.yml down -v
|
||||
```
|
||||
|
||||
## Making Changes
|
||||
|
||||
### Backend Changes
|
||||
1. Edit any Python file in `services/raggr/`
|
||||
2. Save the file
|
||||
3. The Quart server will automatically restart
|
||||
4. Check logs to confirm reload
|
||||
|
||||
### Frontend Changes
|
||||
1. Edit any file in `services/raggr/raggr-frontend/src/`
|
||||
2. Save the file
|
||||
3. The browser will automatically refresh (Hot Module Replacement)
|
||||
4. No need to rebuild
|
||||
|
||||
### Dependency Changes
|
||||
|
||||
**Backend** (pyproject.toml):
|
||||
```bash
|
||||
# Rebuild the backend service
|
||||
docker-compose -f docker-compose.dev.yml up --build raggr-backend
|
||||
```
|
||||
|
||||
**Frontend** (package.json):
|
||||
```bash
|
||||
# Rebuild the frontend service
|
||||
docker-compose -f docker-compose.dev.yml up --build raggr-frontend
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Port Already in Use
|
||||
If you see port binding errors, make sure no other services are running on ports 8080 or 3000.
|
||||
|
||||
### Changes Not Reflected
|
||||
1. Check if the file is properly mounted (check docker-compose.dev.yml volumes)
|
||||
2. Verify the file isn't in an excluded directory (node_modules, __pycache__)
|
||||
3. Check container logs for errors
|
||||
|
||||
### Frontend Not Connecting to Backend
|
||||
Make sure your frontend API calls point to the correct backend URL. If accessing from the same machine, use `http://localhost:8080`. If accessing from another device on the network, use `http://YOUR_IP:8080`.
|
||||
|
||||
## Notes
|
||||
|
||||
- Both services bind to `0.0.0.0` and expose ports, making them accessible on your network
|
||||
- Node modules and Python cache are excluded from volume mounts to use container versions
|
||||
- Database and ChromaDB data persist in Docker volumes across restarts
|
||||
- Access the app from any device on your network using your host machine's IP address
|
||||
45
docker-compose.dev.yml
Normal file
45
docker-compose.dev.yml
Normal file
@@ -0,0 +1,45 @@
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
raggr-backend:
|
||||
build:
|
||||
context: ./services/raggr
|
||||
dockerfile: Dockerfile.dev
|
||||
image: torrtle/simbarag:dev
|
||||
ports:
|
||||
- "8080:8080"
|
||||
environment:
|
||||
- PAPERLESS_TOKEN=${PAPERLESS_TOKEN}
|
||||
- BASE_URL=${BASE_URL}
|
||||
- OLLAMA_URL=${OLLAMA_URL:-http://localhost:11434}
|
||||
- CHROMADB_PATH=/app/chromadb
|
||||
- OPENAI_API_KEY=${OPENAI_API_KEY}
|
||||
- FLASK_ENV=development
|
||||
- PYTHONUNBUFFERED=1
|
||||
volumes:
|
||||
# Mount source code for hot reload
|
||||
- ./services/raggr:/app
|
||||
# Exclude node_modules and Python cache
|
||||
- /app/raggr-frontend/node_modules
|
||||
- /app/__pycache__
|
||||
# Persist data
|
||||
- chromadb_data:/app/chromadb
|
||||
- database_data:/app/database
|
||||
command: sh -c "chmod +x /app/startup-dev.sh && /app/startup-dev.sh"
|
||||
|
||||
raggr-frontend:
|
||||
build:
|
||||
context: ./services/raggr/raggr-frontend
|
||||
dockerfile: Dockerfile.dev
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
volumes:
|
||||
# Mount source code for hot reload
|
||||
- ./services/raggr/raggr-frontend:/app
|
||||
# Exclude node_modules to use container's version
|
||||
- /app/node_modules
|
||||
command: sh -c "yarn build && yarn watch:build"
|
||||
|
||||
volumes:
|
||||
chromadb_data:
|
||||
database_data:
|
||||
33
services/raggr/Dockerfile.dev
Normal file
33
services/raggr/Dockerfile.dev
Normal file
@@ -0,0 +1,33 @@
|
||||
FROM python:3.13-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install system dependencies and uv
|
||||
RUN apt-get update && apt-get install -y \
|
||||
build-essential \
|
||||
curl \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
|
||||
# Add uv to PATH
|
||||
ENV PATH="/root/.local/bin:$PATH"
|
||||
|
||||
# Copy dependency files
|
||||
COPY pyproject.toml ./
|
||||
|
||||
# Install Python dependencies using uv
|
||||
RUN uv pip install --system -e .
|
||||
|
||||
# Create ChromaDB and database directories
|
||||
RUN mkdir -p /app/chromadb /app/database
|
||||
|
||||
# Expose port
|
||||
EXPOSE 8080
|
||||
|
||||
# Set environment variables
|
||||
ENV PYTHONPATH=/app
|
||||
ENV CHROMADB_PATH=/app/chromadb
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
# The actual source code will be mounted as a volume
|
||||
# No CMD here - will be specified in docker-compose
|
||||
9
services/raggr/raggr-frontend/.dockerignore
Normal file
9
services/raggr/raggr-frontend/.dockerignore
Normal file
@@ -0,0 +1,9 @@
|
||||
.git
|
||||
.gitignore
|
||||
README.md
|
||||
.DS_Store
|
||||
node_modules
|
||||
dist
|
||||
.cache
|
||||
coverage
|
||||
*.log
|
||||
1
services/raggr/raggr-frontend/.gitignore
vendored
1
services/raggr/raggr-frontend/.gitignore
vendored
@@ -6,6 +6,7 @@
|
||||
# Dist
|
||||
node_modules
|
||||
dist/
|
||||
.yarn
|
||||
|
||||
# Profile
|
||||
.rspack-profile-*/
|
||||
|
||||
1
services/raggr/raggr-frontend/.yarnrc.yml
Normal file
1
services/raggr/raggr-frontend/.yarnrc.yml
Normal file
@@ -0,0 +1 @@
|
||||
nodeLinker: node-modules
|
||||
15
services/raggr/raggr-frontend/Dockerfile.dev
Normal file
15
services/raggr/raggr-frontend/Dockerfile.dev
Normal file
@@ -0,0 +1,15 @@
|
||||
FROM node:20-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files
|
||||
COPY package.json yarn.lock* ./
|
||||
|
||||
# Install dependencies
|
||||
RUN yarn install
|
||||
|
||||
# Expose rsbuild dev server port (default 3000)
|
||||
EXPOSE 3000
|
||||
|
||||
# The actual source code will be mounted as a volume
|
||||
# CMD will be specified in docker-compose
|
||||
@@ -20,6 +20,7 @@
|
||||
"watch": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.3.10",
|
||||
"@rsbuild/core": "^1.5.6",
|
||||
"@rsbuild/plugin-react": "^1.4.0",
|
||||
"@tailwindcss/postcss": "^4.0.0",
|
||||
|
||||
@@ -3,4 +3,5 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
|
||||
background-color: #F9F5EB;
|
||||
}
|
||||
|
||||
BIN
services/raggr/raggr-frontend/src/assets/cat.png
Normal file
BIN
services/raggr/raggr-frontend/src/assets/cat.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.8 KiB |
@@ -7,7 +7,7 @@ type AnswerBubbleProps = {
|
||||
|
||||
export const AnswerBubble = ({ text, loading }: AnswerBubbleProps) => {
|
||||
return (
|
||||
<div className="rounded-md bg-orange-100 p-3 sm:p-4">
|
||||
<div className="rounded-md bg-orange-100 p-3 sm:p-4 w-2/3">
|
||||
{loading ? (
|
||||
<div className="flex flex-col w-full animate-pulse gap-2">
|
||||
<div className="flex flex-row gap-2 w-full">
|
||||
@@ -20,8 +20,8 @@ export const AnswerBubble = ({ text, loading }: AnswerBubbleProps) => {
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col break-words overflow-wrap-anywhere">
|
||||
<ReactMarkdown className="text-sm sm:text-base [&>*]:break-words">
|
||||
<div className=" flex flex-col break-words overflow-wrap-anywhere text-sm sm:text-base [&>*]:break-words">
|
||||
<ReactMarkdown>
|
||||
{"🐈: " + text}
|
||||
</ReactMarkdown>
|
||||
</div>
|
||||
|
||||
@@ -2,8 +2,9 @@ import { useEffect, useState, useRef } from "react";
|
||||
import { conversationService } from "../api/conversationService";
|
||||
import { QuestionBubble } from "./QuestionBubble";
|
||||
import { AnswerBubble } from "./AnswerBubble";
|
||||
import { MessageInput } from "./MessageInput";
|
||||
import { ConversationList } from "./ConversationList";
|
||||
import { parse } from "node:path/win32";
|
||||
import catIcon from "../assets/cat.png";
|
||||
|
||||
type Message = {
|
||||
text: string;
|
||||
@@ -38,6 +39,7 @@ export const ChatScreen = ({ setAuthenticated }: ChatScreenProps) => {
|
||||
const [showConversations, setShowConversations] = useState<boolean>(false);
|
||||
const [selectedConversation, setSelectedConversation] =
|
||||
useState<Conversation | null>(null);
|
||||
const [sidebarCollapsed, setSidebarCollapsed] = useState<boolean>(false);
|
||||
|
||||
const messagesEndRef = useRef<HTMLDivElement>(null);
|
||||
const simbaAnswers = ["meow.", "hiss...", "purrrrrr", "yowOWROWWowowr"];
|
||||
@@ -176,37 +178,81 @@ export const ChatScreen = ({ setAuthenticated }: ChatScreenProps) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="h-screen bg-opacity-20">
|
||||
<div className="bg-white/85 h-screen">
|
||||
<div className="flex flex-row justify-center py-4">
|
||||
<div className="flex flex-col gap-4 w-full px-4 sm:w-11/12 sm:max-w-2xl lg:max-w-4xl sm:px-0">
|
||||
<div className="flex flex-col sm:flex-row gap-3 sm:gap-0 sm:justify-between">
|
||||
<header className="flex flex-row justify-center gap-2 sticky top-0 z-10 bg-white">
|
||||
<h1 className="text-2xl sm:text-3xl">ask simba!</h1>
|
||||
</header>
|
||||
<div className="flex flex-row gap-2 justify-center sm:justify-end">
|
||||
<button
|
||||
className="p-2 h-11 border border-green-400 bg-green-200 hover:bg-green-400 cursor-pointer rounded-md text-sm sm:text-base"
|
||||
onClick={() => setShowConversations(!showConversations)}
|
||||
>
|
||||
{showConversations
|
||||
? "hide conversations"
|
||||
: "show conversations"}
|
||||
</button>
|
||||
<button
|
||||
className="p-2 h-11 border border-red-400 bg-red-200 hover:bg-red-400 cursor-pointer rounded-md text-sm sm:text-base"
|
||||
onClick={() => setAuthenticated(false)}
|
||||
>
|
||||
logout
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{showConversations && (
|
||||
<ConversationList
|
||||
conversations={conversations}
|
||||
onCreateNewConversation={handleCreateNewConversation}
|
||||
onSelectConversation={handleSelectConversation}
|
||||
<div className="h-screen flex flex-row bg-[#F9F5EB]">
|
||||
{/* Sidebar - Expanded */}
|
||||
<aside className={`hidden md:flex md:flex-col bg-white border-r border-gray-200 p-4 overflow-y-auto transition-all duration-300 ${sidebarCollapsed ? 'w-20' : 'w-64'}`}>
|
||||
{!sidebarCollapsed ? (
|
||||
<>
|
||||
<div className="flex flex-row items-center gap-2 mb-6">
|
||||
<img
|
||||
src={catIcon}
|
||||
alt="Simba"
|
||||
className="cursor-pointer hover:opacity-80"
|
||||
onClick={() => setSidebarCollapsed(true)}
|
||||
/>
|
||||
<h2 className="text-3xl font-semibold">asksimba!</h2>
|
||||
</div>
|
||||
<ConversationList
|
||||
conversations={conversations}
|
||||
onCreateNewConversation={handleCreateNewConversation}
|
||||
onSelectConversation={handleSelectConversation}
|
||||
/>
|
||||
<div className="mt-auto pt-4">
|
||||
<button
|
||||
className="w-full p-2 border border-red-400 bg-red-200 hover:bg-red-400 cursor-pointer rounded-md text-sm"
|
||||
onClick={() => setAuthenticated(false)}
|
||||
>
|
||||
logout
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div className="flex flex-col items-center gap-4">
|
||||
<img
|
||||
src={catIcon}
|
||||
alt="Simba"
|
||||
className="cursor-pointer hover:opacity-80"
|
||||
onClick={() => setSidebarCollapsed(false)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</aside>
|
||||
|
||||
{/* Main chat area */}
|
||||
<div className="flex-1 flex flex-col h-screen overflow-hidden">
|
||||
{/* Mobile header */}
|
||||
<header className="md:hidden flex flex-row justify-between items-center gap-3 p-4 border-b border-gray-200 bg-white">
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<img src={catIcon} alt="Simba" className="w-10 h-10" />
|
||||
<h1 className="text-xl">asksimba!</h1>
|
||||
</div>
|
||||
<div className="flex flex-row gap-2">
|
||||
<button
|
||||
className="p-2 border border-green-400 bg-green-200 hover:bg-green-400 cursor-pointer rounded-md text-sm"
|
||||
onClick={() => setShowConversations(!showConversations)}
|
||||
>
|
||||
{showConversations ? "hide" : "show"}
|
||||
</button>
|
||||
<button
|
||||
className="p-2 border border-red-400 bg-red-200 hover:bg-red-400 cursor-pointer rounded-md text-sm"
|
||||
onClick={() => setAuthenticated(false)}
|
||||
>
|
||||
logout
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Messages area */}
|
||||
<div className="flex-1 overflow-y-auto px-4 py-4">
|
||||
<div className="max-w-2xl mx-auto flex flex-col gap-4">
|
||||
{showConversations && (
|
||||
<div className="md:hidden">
|
||||
<ConversationList
|
||||
conversations={conversations}
|
||||
onCreateNewConversation={handleCreateNewConversation}
|
||||
onSelectConversation={handleSelectConversation}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{messages.map((msg, index) => {
|
||||
if (msg.speaker === "simba") {
|
||||
@@ -215,37 +261,21 @@ export const ChatScreen = ({ setAuthenticated }: ChatScreenProps) => {
|
||||
return <QuestionBubble key={index} text={msg.text} />;
|
||||
})}
|
||||
<div ref={messagesEndRef} />
|
||||
<footer className="flex flex-col gap-2 sticky bottom-0">
|
||||
<div className="flex flex-row justify-between gap-2 grow">
|
||||
<textarea
|
||||
className="p-3 sm:p-4 border border-blue-200 rounded-md grow bg-white min-h-[44px] resize-y"
|
||||
onChange={handleQueryChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
value={query}
|
||||
rows={2}
|
||||
placeholder="Type your message... (Press Enter to send, Shift+Enter for new line)"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-row justify-between gap-2 grow">
|
||||
<button
|
||||
className="p-3 sm:p-4 min-h-[44px] border border-blue-400 bg-blue-200 hover:bg-blue-400 cursor-pointer rounded-md flex-grow text-sm sm:text-base"
|
||||
onClick={() => handleQuestionSubmit()}
|
||||
type="submit"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex flex-row justify-center gap-2 grow items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
onChange={(event) => setSimbaMode(event.target.checked)}
|
||||
className="w-5 h-5 cursor-pointer"
|
||||
/>
|
||||
<p className="text-sm sm:text-base">simba mode?</p>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Input area */}
|
||||
<footer className="p-4 bg-[#F9F5EB]">
|
||||
<div className="max-w-2xl mx-auto">
|
||||
<MessageInput
|
||||
query={query}
|
||||
handleQueryChange={handleQueryChange}
|
||||
handleKeyDown={handleKeyDown}
|
||||
handleQuestionSubmit={handleQuestionSubmit}
|
||||
setSimbaMode={setSimbaMode}
|
||||
/>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -52,7 +52,7 @@ export const ConversationList = ({
|
||||
className="border-blue-400 bg-indigo-300 hover:bg-indigo-200 cursor-pointer rounded-md p-3 min-h-[44px] flex items-center"
|
||||
onClick={() => onSelectConversation(conversation)}
|
||||
>
|
||||
<p className="text-sm sm:text-base break-words">
|
||||
<p className="text-sm sm:text-base truncate w-full">
|
||||
{conversation.title}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { useEffect, useState, useRef } from "react";
|
||||
|
||||
type MessageInputProps = {
|
||||
handleQueryChange: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;
|
||||
handleKeyDown: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;
|
||||
handleQuestionSubmit: () => void;
|
||||
setSimbaMode: (sdf: boolean) => void;
|
||||
query: string;
|
||||
}
|
||||
|
||||
export const MessageInput = ({query, handleKeyDown, handleQueryChange, handleQuestionSubmit, setSimbaMode}: MessageInputProps) => {
|
||||
return (
|
||||
<div className="flex flex-col gap-4 sticky bottom-0 bg-[#3D763A] p-6 rounded-xl">
|
||||
<div className="flex flex-row justify-between grow">
|
||||
<textarea
|
||||
className="p-3 sm:p-4 border border-blue-200 rounded-md grow bg-[#F9F5EB] min-h-[44px] resize-y"
|
||||
onChange={handleQueryChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
value={query}
|
||||
rows={2}
|
||||
placeholder="Type your message... (Press Enter to send, Shift+Enter for new line)"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-row justify-between gap-2 grow">
|
||||
<button
|
||||
className="p-3 sm:p-4 min-h-[44px] border border-blue-400 bg-[#EDA541] hover:bg-blue-400 cursor-pointer rounded-md flex-grow text-sm sm:text-base"
|
||||
onClick={() => handleQuestionSubmit()}
|
||||
type="submit"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex flex-row justify-center gap-2 grow items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
onChange={(event) => setSimbaMode(event.target.checked)}
|
||||
className="w-5 h-5 cursor-pointer"
|
||||
/>
|
||||
<p className="text-sm sm:text-base">simba mode?</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -4,7 +4,7 @@ type QuestionBubbleProps = {
|
||||
|
||||
export const QuestionBubble = ({ text }: QuestionBubbleProps) => {
|
||||
return (
|
||||
<div className="rounded-md bg-stone-200 p-3 sm:p-4 break-words overflow-wrap-anywhere text-sm sm:text-base">
|
||||
<div className="w-2/3 rounded-md bg-stone-200 p-3 sm:p-4 break-words overflow-wrap-anywhere text-sm sm:text-base ml-auto">
|
||||
🤦: {text}
|
||||
</div>
|
||||
);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
31
services/raggr/startup-dev.sh
Executable file
31
services/raggr/startup-dev.sh
Executable file
@@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "Initializing database directories..."
|
||||
mkdir -p /app/chromadb /app/database
|
||||
|
||||
echo "Waiting for frontend to build..."
|
||||
while [ ! -f /app/raggr-frontend/dist/index.html ]; do
|
||||
sleep 1
|
||||
done
|
||||
echo "Frontend built successfully!"
|
||||
|
||||
echo "Running database migrations..."
|
||||
aerich upgrade
|
||||
|
||||
echo "Initializing visited.db with indexed_documents table..."
|
||||
python3 -c "
|
||||
import sqlite3
|
||||
conn = sqlite3.connect('database/visited.db')
|
||||
c = conn.cursor()
|
||||
c.execute('CREATE TABLE IF NOT EXISTS indexed_documents (id INTEGER PRIMARY KEY AUTOINCREMENT, paperless_id INTEGER)')
|
||||
conn.commit()
|
||||
conn.close()
|
||||
print('Database initialized successfully')
|
||||
"
|
||||
|
||||
echo "Starting reindex process..."
|
||||
python main.py "" --reindex || echo "Reindex failed, continuing anyway..."
|
||||
|
||||
echo "Starting Flask application in debug mode..."
|
||||
python app.py
|
||||
Reference in New Issue
Block a user