# Project export: AI Docs

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: Cal Hacks 12.0
- Tagline: Making Google Docs (file storage, text editor) better with AI
- Devpost: https://devpost.com/software/ai-docs
- GitHub: https://github.com/joonyoo181/dropbox-ai
- Demo: https://dropbox-ai-deploy.vercel.app/
- Video: https://www.youtube.com/embed/vyKOyChcsCw?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Result: winner (Y Combinator: Build an Iconic YC Company - 2nd Place)
- Team: 3 GitHub contributor(s) — Junseo Yoo (26 commits), Sarvagya Somvanshi (10 commits), Melody Cui (1 commits)

## Devpost submission (written by the team)

### Inspiration

As people who use Google Docs for almost everything from writing college essays to class notes to spontaneous poetry, we’ve found it restrictive in its ability to enhance a user’s experience. We've decided to reimagine popular word processors and integrate them with AI beyond just grammar checks and sentence suggestions.

### What it does

AI Docs is an all-in-one file system that allows you to organize your files and edit them. Its high-level features include an AI-powered search bar for easy access to files and a background AI agent that reads your files to generate workflows and to-do actions for you immediately. For the actual word processor, we're reimagining what it means to write and create. Instead of having a single document and a sidebar for static comments, we extended it to a single document for writing the raw notes, and a dynamic sidebar that allows you to organize your comments/content and prompt AI (and see its responses), having all your notes in one place. This reimagines word processors and sees how AI can truly supplement all forms of writing and creation.

### How we built it

On the frontend, we used React 18, React Router for navigation, React Quill for rich text editing, Axios for API calls, and Vite for build tooling. On the backend, we used Express.js, OpenAI API for intelligent search and document analysis, CORS enabled, and databases.

### Challenges we ran into

Some challenges we ran into were finding cohesion in our vision. Our general topic is broad: word processor, and we had to work together to narrow it down into what we wanted our product to do and how we wanted to utilize AI in the background to have it be effective but also efficient.

### Accomplishments we're proud of

We're proud of having a working MVP (haha!) but also when our team came together with a vision, it was scattered, and we all had a lot of inputs/ideas that we wanted to implement. We're just super proud that we were able to implement the core features we were looking for and supplement it with a lot of details that enhance the user experience. We are also proud of how this solution solves the problem we've been facing with existing word processors!

### What we learned

We learned a lot: coding in a fast paced environment with a narrow deadline, collaboration, and coming up with an idea and building it end to end with no other guidance than our minds and a collective vision that we share.

### What's next

Next for AI Docs is to include more workflows that integrate across different writing formats such as creative writing and essay writing to allow it to cater to anyone who uses the platform.

## README (from the GitHub repository)

# Dropbox AI (a.k.a. PickupAI)

"We pick up where Dropbox dropped off"

## Inspiration
As people who use Google Docs/Dropbox Paper for almost everything from writing college essays to class notes to spontaneous poetry, we’ve found it restrictive in its ability to enhance a user’s experience. We've decided to reimagine popular word processors and integrate them with AI beyond just grammar checks and sentence suggestions.

## What it does
AI Docs is an all-in-one file system that allows you to organize your files and edit them. Its high-level features include an AI-powered search bar for easy access to files and a background AI agent that reads your files to generate workflows and to-do actions for you immediately. For the actual word processor, we're reimagining what it means to write and create. Instead of having a single document and a sidebar for static comments, we extended it to a single document for writing the raw notes, and a dynamic sidebar that allows you to organize your comments/content and prompt AI (and see its responses), having all your notes in one place. This reimagines word processors and sees how AI can truly supplement all forms of writing and creation.


## Detected evidence (automated analysis)

Indexed codebase: 20 recognized source files, 202 KB.
- CSS (language) — detected in the code
- Express (technology) — detected in the code
- Google Gemini (technology) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- OpenAI (technology) — detected in the code
- React (technology) — detected in the code

## Codebase structure (from repository index)

### Files (24 of 24)

```
.gitignore
backend/aiService.js
backend/config.js
backend/package.json
backend/server.js
frontend/index.html
frontend/package.json
frontend/src/App.jsx
frontend/src/components/ActionItems.css
frontend/src/components/ActionItems.jsx
frontend/src/components/ActionItemsPage.css
frontend/src/components/ActionItemsPage.jsx
frontend/src/components/DocumentEditor.css
frontend/src/components/DocumentEditor.jsx
frontend/src/components/DocumentList.css
frontend/src/components/DocumentList.jsx
frontend/src/components/Sidebar.css
frontend/src/components/Sidebar.jsx
frontend/src/config.js
frontend/src/index.css
frontend/src/main.jsx
frontend/vite.config.js
package.json
README.md
```

### Dependencies

- backend/package.json: @google/generative-ai@^0.24.1, body-parser@^1.20.2, cors@^2.8.5, dotenv@^16.4.1, express@^4.18.2, nodemon@^3.0.2, openai@^4.104.0
- frontend/package.json: @rollup/rollup-linux-x64-gnu@4.6.1, @types/react@^18.2.48, @types/react-dom@^18.2.18, @vitejs/plugin-react@^4.2.1, axios@^1.6.5, react@^18.2.0, react-dom@^18.2.0, react-quill@^2.0.0, react-router-dom@^6.21.1, vite@^5.0.11
- package.json: concurrently@^8.2.2

### Recent commits (newest first)

- Update README.md
- Update README.md
- repdeploy
- new pkg
- added vercel
- render auth
- pushing to add config
- e
- add vercel deployment information
- fix edit action item
- Merge pull request #4 from joonyoo181/auto-edit
- Merge branch 'main' into auto-edit
- done
- add support for command e and e/ as well
- make tool bar scrollable
- Add cmd + \ for unformatting
- Add edit command
- Minor fixes to the command palette's location when going off screen
- remove some bars from the commenting feature
- change the mail

## Key source files (fetched from GitHub, selected and truncated for size)

### package.json

```
{
  "name": "dropbox-ai",
  "version": "1.0.0",
  "description": "Document editing application similar to Dropbox Paper/Google Docs",
  "private": true,
  "workspaces": [
    "frontend",
    "backend"
  ],
  "scripts": {
    "dev": "concurrently \"npm run dev:backend\" \"npm run dev:frontend\"",
    "dev:backend": "cd backend && npm run dev",
    "dev:frontend": "cd frontend && npm run dev",
    "install:all": "npm install && cd backend && npm install && cd ../frontend && npm install",
    "build": "cd frontend && npm install && npm run build",
    "vercel-build": "cd frontend && npm install && npm run build"
  },
  "devDependencies": {
    "concurrently": "^8.2.2"
  }
}

```

### backend/package.json

```
{
  "name": "backend",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "dev": "nodemon server.js",
    "start": "node server.js"
  },
  "dependencies": {
    "@google/generative-ai": "^0.24.1",
    "body-parser": "^1.20.2",
    "cors": "^2.8.5",
    "dotenv": "^16.4.1",
    "express": "^4.18.2",
    "openai": "^4.104.0"
  },
  "devDependencies": {
    "nodemon": "^3.0.2"
  }
}

```

### frontend/package.json

```
{
  "name": "frontend",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.21.1",
    "react-quill": "^2.0.0",
    "axios": "^1.6.5"
  },
  "devDependencies": {
    "@types/react": "^18.2.48",
    "@types/react-dom": "^18.2.18",
    "@vitejs/plugin-react": "^4.2.1",
    "vite": "^5.0.11"
  },
  "optionalDependencies": {
    "@rollup/rollup-linux-x64-gnu": "4.6.1"
  }
}

```

### backend/server.js

```javascript
// IMPORTANT: Load config first to clear global env vars and load local .env
import './config.js';

import express from 'express';
import cors from 'cors';
import bodyParser from 'body-parser';
import { interpretSearchQuery, analyzeDocumentContent, rankDocuments, suggestTextImprovement, extractActionItems, areTasksSimilar, draftEmailFromTask, createCalendarEventFromTask, processAICommand, generateWordEdit, processEditCommand } from './aiService.js';

const app = express();
const PORT = process.env.PORT || 3001;

// Middleware
app.use(cors());
app.use(bodyParser.json());

// In-memory storage for documents (replace with database in production)
let documents = [
  {
    id: '1',
    title: 'Welcome Document',
    content: '<h1>Welcome to DocEditor</h1><p>This is your first document. Start editing!</p>',
    createdAt: new Date('2025-01-15').toISOString(),
    updatedAt: new Date('2025-01-15').toISOString(),
    comments: [],
    tabs: {
      summary: [],
      definitions: [],
      questions: [],
      notes: [],
      edits: [],
      versions: []
    },
    customTabs: [],
    metadata: {
      topics: ['introduction', 'getting started'],
      documentType: 'document',
      summary: 'A welcome document for new users'
    }
  },
  {
    id: '2',
    title: 'Meeting Notes',
    content: '<h2>Team Meeting - Q1 2024</h2><ul><li>Discuss project goals</li><li>Review timeline</li></ul>',
    createdAt: new Date('2024-12-02').toISOString(),
    updatedAt: new Date('2024-12-02').toISOString(),
    comments: [],
    tabs: {
      summary: [],
      definitions: [],
      questions: [],
      notes: [],
      edits: [],
      versions: []
    },
    customTabs: [],
    metadata: {
      topics: ['meeting', 'planning', 'Q1'],
      documentType: 'meeting_notes',
      summary: 'Team meeting notes for Q1 planning'
    }
  },
  {
    id: '3',
    title: 'Public Health Essay Draft',
    content: '<h1>The Impact of Vaccination Programs on Public Health</h1><p>In this essay, I will examine the profound effects of vaccination programs on public health outcomes...</p><h2>Introduction</h2><p>Vaccination programs have been instrumental in reducing infectious diseases worldwide.</p>',
    createdAt: new Date('2024-11-20').toISOString(),
    updatedAt: new Date('2024-12-01').toISOString(),
    comments: [],
    tabs: {
      summary: [],
      definitions: [],
      questions: [],
      notes: [],
      edits: [],
      versions: []
    },
    customTabs: [],
    metadata: {
      topics: ['public health', 'vaccination', 'healthcare'],
      documentType: 'essay',
      summary: 'An essay about vaccination programs and public health'
    }
  },
  {
    id: '4',
    title: 'response to sylvia plath',
    content: `When I read The Bell Jar by Sylvia Plath, one quote — the quote that has stuck with me and probably everybody else who read it goes as follows:

  <br>“I saw my life branching out before me like the green fig tree in the story. From the tip of every branch, like a fat purple fig, a wonderful future beckoned and winked. One fig was a husband and a happy home and children, and another fig was a famous poet and another fig was a brilliant professor, and another fig was Ee Gee, the amazing editor, and another fig was Europe and Africa and South America, and another fig was Constantin and Socrates and Attila and a pack of other lovers with queer names and offbeat professions, and another fig was an Olympic lady crew champion, and beyond and above these figs were many more figs I couldn't quite make out. I saw myself sitting in the crotch of this fig tree, starving to death, just because I couldn't make up my mind which of the figs I would choose. I wanted each and every one of them, but choosing one meant losing all the rest, and, as I sat there, unable to decide, the figs began to wrinkle and go black, and, one by one, they plopped to the ground at my feet.”

  <br>My figs are not the same as hers, but they constantly grow outwards. A part of me wants to become a writer and finally finish writing that sci-fi book and spend the rest of my life writing poetry on the value & meaning & fragility of life; a part of me wants to go into the start-up world and make something of value that will change things in the world and if not the world then maybe for just one person; a part of me wants to become a quizzer and kill it on Jeopardy since Who Wants to be a Millionaire now only features … millionaires; a part of me wants to go into politics and make it on the Hill where I can claim to be a “just politician” and truly be one. But each one of these dreams are so big and require so much time and effort that doing each one of them is unfeasible.`,
    createdAt: new Date('2025-01-25').toISOString(),
    updatedAt: new Date('2025-01-25').toISOString(),
    comments: [],
    tabs: {
      summary: [],
      definitions: [],
      questions: [],
      notes: [],
      edits: [],
      versions: []
    },
    customTabs: [],
    metadata: {
      topics: ['slyvia path', 'substack', 'post'],
      documentType: 'blog',
      summary: 'A response to quote from slyvia path'
    }
  }
];

// In-memory storage for action items
let actionItems = [];

// Get all documents
app.get('/api/documents', (req, res) => {
  res.json(documents.map(doc => ({
    id: doc.id,
    title: doc.title,
    createdAt: doc.createdAt,
    updatedAt: doc.updatedAt,
    metadata: doc.metadata
  })));
});

// Get a single document
app.get('/api/documents/:id', (req, res) => {
  const doc = documents.find(d => d.id === req.params.id);
  if (!doc) {
    return res.status(404).json({ error: 'Document not found' });
  }
  res.json(doc);
});

// Create a new document
app.post('/api/documents', async (req, res) => {
  const newDoc = {
    id: Date.now().toString(),
    title: req.body.title || 'Untitled Document',
    content: req.body.content || '',
    comments: [],
    tabs: {
      summary: [],
      definitions: [],
      questions: [],
      notes
[truncated — 11044 more characters]
```

### frontend/src/main.jsx

```javascript
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './index.css';

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

```

### frontend/src/App.jsx

```javascript
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import DocumentList from './components/DocumentList';
import DocumentEditor from './components/DocumentEditor';

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<DocumentList />} />
        <Route path="/document/:id" element={<DocumentEditor />} />
      </Routes>
    </Router>
  );
}

export default App;

```

### frontend/vite.config.js

```javascript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  server: {
    port: 3000,
    proxy: {
      '/api': {
        target: 'http://localhost:3001',
        changeOrigin: true,
      },
    },
  },
});

```

### frontend/index.html

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>DocEditor</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.jsx"></script>
  </body>
</html>

```

### backend/config.js

```javascript
import dotenv from 'dotenv';
import path from 'path';
import { fileURLToPath } from 'url';

// Get the directory name in ES modules
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// Load .env file from backend directory
dotenv.config({ path: path.join(__dirname, '.env') });

// Export a flag to confirm config was loaded
export const configLoaded = true;

```

### frontend/src/config.js

```javascript
// API Configuration
export const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3001';


```

[11 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]