# Project export: Chimera

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: TreeHacks 2024
- Tagline: Have you ever "lost" a file in your messy file manager? Chimera, your semantic file searcher, will easily understand anything you're looking for and ensure any code, paper, or document will appear!
- Devpost: https://devpost.com/software/semantic-file-searcher
- GitHub: https://github.com/couplefire/chimera
- Team: 4 GitHub contributor(s) — Nathan Wang (25 commits), Locke Cai (15 commits), Jeff (7 commits), Michael Huang (5 commits)

## Devpost submission (written by the team)

### Inspiration

Examining our difficulties in our daily workflow, we realized that we often could not find files that we knew we had written before. Lots of us had saved countless papers and books, only to be unsure of where we saved them. Not knowing where our old code was led us to rewrite old libraries and codebases. Thus, we all wished for a better file searcher. One which, instead of solely relying on filenames or exact string matching in the file content, also took into account how

### What it does

Chimera will first ask you to describe the file you are looking for. Then it will go through all the files in your directory and rank them according to which fit the prompt the best.

### How we built it

We used the Tauri framework to build the app and wrote it in Rust. The app first embedded the prompts and the files into a vector space (using OpenAI's embedding models), then compared the similarity between the prompts and each file, then outputted them in order of likelihood.

### Challenges we ran into

Building it in Rust was quite difficult, as some of us didn't know Rust and had to learn it on the fly, and there were a lot of issues working with some Rust libraries.

### Accomplishments we're proud of

The end product, being built with Rust, is highly performant. Our embeddings framework is also easily parallelizable, so it can easily be extended to index every file in a user's computer relatively quickly.

### What we learned

We learned how to work with Rust (especially the Tauri framework and Apache Arrow's data format that LanceDB uses) and how to use a vector DB.

### What's next

While this hackathon used OpenAI's embeddings API, the end goal would be to ship a local embeddings model to the user's computer so their files won't have to leave their personal laptop. In addition, we hope to fine-tune the embeddings model to perform better at the specific task of searching for files.

## README (from the GitHub repository)

# Chimera

## Inspiration

Examining our difficulties in our daily workflow, we realized that we often could not find files that we knew we had written before. Lots of us had saved countless papers and books, only to be unsure of where we saved them. Not knowing where our old code was led us to rewrite old libraries and codebases. Thus, we all wished for a better file searcher. One which, instead of solely relying on filenames or exact string matching in the file content, also took into account how 

## What it does

Chimera will first ask you to describe the file you are looking for. Then it will go through all the files in your directory and rank them according to which fit the prompt the best.

## How we built it

We used the Tauri framework to build the app and wrote it in Rust. The app first embedded the prompts and the files into a vector space (using OpenAI's embedding models), then compared the similarity between the prompts and each file, then outputted them in order of likelihood. 

## Challenges we ran into

Building it in Rust was quite difficult, as some of us didn't know Rust and had to learn it on the fly, and there were a lot of issues working with some Rust libraries. 

## Accomplishments that we're proud of

The end product, being built with Rust, is highly performant. Our embeddings framework is also easily parallelizable, so it can easily be extended to index every file in a user's computer relatively quickly.

## What we learned

We learned how to work with Rust (especially the Tauri framework and Apache Arrow's data format that LanceDB uses) and how to use a vector DB.

## What's next for Chimera

While this hackathon used OpenAI's embeddings API, the end goal would be to ship a local embeddings model to the user's computer so their files won't have to leave their personal laptop. In addition, we hope to fine-tune the embeddings model to perform better at the specific task of searching for files.

## Detected evidence (automated analysis)

Indexed codebase: 36 recognized source files, 117 KB.
- CSS (language) — detected in the code
- HTML (language) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- Rust (language) — detected in the code
- TypeScript (language) — detected in the code

## Codebase structure (from repository index)

### Files (90 of 90)

```
.DS_Store
.gitignore
.vscode/extensions.json
.vscode/settings.json
data/my_table.lance/_latest.manifest
data/my_table.lance/_transactions/0-d7b4903c-e874-488f-b235-8d35d0190fbf.txn
data/my_table.lance/_transactions/1-53371309-3f9a-48f8-81ef-5285513f72a9.txn
data/my_table.lance/_versions/1.manifest
data/my_table.lance/_versions/2.manifest
data/my_table.lance/data/b370ad91-6389-49d0-8353-5062a5da98a8.lance
files-to-index/6110-sp24-main/.gitignore
files-to-index/6110-sp24-main/.gitmodules
files-to-index/6110-sp24-main/.pre-commit-config.yaml
files-to-index/6110-sp24-main/build.sh
files-to-index/6110-sp24-main/Cargo.lock
files-to-index/6110-sp24-main/Cargo.toml
files-to-index/6110-sp24-main/README.md
files-to-index/6110-sp24-main/run.sh
files-to-index/6110-sp24-main/src/main.rs
files-to-index/6110-sp24-main/src/parser.rs
files-to-index/6110-sp24-main/src/snapshots/decaf_rust__tokenizer__tests__tokenizer@aGVsbG8gd29ybGQ=.snap
files-to-index/6110-sp24-main/src/snapshots/decaf_rust__tokenizer__tests__tokenizer@IT0gLS0gKysgLSAhID0gPiA+PSA8IDw9ICogLyAlICsgLSA7IFsgXSB7IH0gKCAp.snap
files-to-index/6110-sp24-main/src/snapshots/decaf_rust__tokenizer__tests__tokenizer@J1xcJw==.snap
files-to-index/6110-sp24-main/src/snapshots/decaf_rust__tokenizer__tests__tokenizer@J1xuJw==.snap
files-to-index/6110-sp24-main/src/snapshots/decaf_rust__tokenizer__tests__tokenizer@J211bHQn.snap
files-to-index/6110-sp24-main/src/snapshots/decaf_rust__tokenizer__tests__tokenizer@J2En.snap
files-to-index/6110-sp24-main/src/snapshots/decaf_rust__tokenizer__tests__tokenizer@Ly8gdGhpcyBpcyBhIGNvbW1lbnQKaW50IG1haW4=.snap
files-to-index/6110-sp24-main/src/snapshots/decaf_rust__tokenizer__tests__tokenizer@MHgxMjNoZWxsbw==.snap
files-to-index/6110-sp24-main/src/tokenizer.rs
files-to-index/6110-sp24-main/src/utils/cli.rs
files-to-index/6110-sp24-main/src/utils/mod.rs
files-to-index/6110-sp24-main/test.dcf
files-to-index/6110-sp24-main/test.sh
files-to-index/lecture notes/l-bft.txt
files-to-index/lecture notes/l-bitcoin.txt
files-to-index/lecture notes/l-ethereum.txt
files-to-index/lecture notes/l-farm.txt
files-to-index/lecture notes/l-gfs.txt
files-to-index/lecture notes/l-grove.txt
files-to-index/lecture notes/l-linearizability.txt
files-to-index/lecture notes/l-memcached.txt
files-to-index/lecture notes/l-raft-QA.txt
files-to-index/lecture notes/l-raft.txt
files-to-index/lecture notes/l-raft2.txt
files-to-index/lecture notes/l-rpc.txt
files-to-index/lecture notes/l-spanner.txt
files-to-index/lecture notes/l-sundr.txt
files-to-index/lecture notes/l-zookeeper.txt
README.md
tauri/.gitignore
tauri/files-to-index/a.txt
tauri/files-to-index/test_create_table.py
tauri/files-to-index/test_data/my_table.lance/_latest.manifest
tauri/files-to-index/test_data/my_table.lance/_transactions/0-2bba53c4-3f2b-4fe2-b8b3-706cc5b85cd7.txn
tauri/files-to-index/test_data/my_table.lance/_transactions/1-2d4f8c33-7fff-423c-a3db-8c00d67e9c27.txn
tauri/files-to-index/test_data/my_table.lance/_versions/1.manifest
tauri/files-to-index/test_data/my_table.lance/_versions/2.manifest
tauri/files-to-index/test_data/my_table.lance/data/0ac366be-01cd-4b36-bfb6-5828927324d2.lance
tauri/index.html
tauri/package.json
tauri/README.md
tauri/src-tauri/.gitignore
tauri/src-tauri/build.rs
tauri/src-tauri/Cargo.lock
tauri/src-tauri/Cargo.toml
tauri/src-tauri/icons/icon.icns
tauri/src-tauri/src/db.rs
tauri/src-tauri/src/embeddings/file_embedding.rs
tauri/src-tauri/src/embeddings/mod.rs
tauri/src-tauri/src/embeddings/prompt_embedding.rs
tauri/src-tauri/src/indexer.rs
tauri/src-tauri/src/main.rs
tauri/src-tauri/src/parser.rs
tauri/src-tauri/src/similarity_search.rs
tauri/src-tauri/tauri.conf.json
tauri/src/App.css
tauri/src/App.tsx
tauri/src/components/resultbox.tsx
tauri/src/components/searchbox.tsx
tauri/src/main.tsx
tauri/src/styles.css
tauri/src/styles/resultbox.module.css
tauri/src/styles/searchbox.module.css
tauri/src/types/types.ts
tauri/src/utils/ext_to_icon.ts
tauri/src/utils/logoutils.ts
tauri/src/vite-env.d.ts
tauri/tsconfig.json
tauri/tsconfig.node.json
tauri/vite.config.ts
```

### Dependencies

- files-to-index/6110-sp24-main/Cargo.toml: base64@0.21.7, clap@4.4.18, insta@1.34.0, rstest@0.18.2, serde@1.0.196
- tauri/package.json: @tauri-apps/api@^1.5.2, @tauri-apps/cli@^1.5.9, @types/lodash@^4.14.202, @types/react@^18.2.15, @types/react-dom@^18.2.7, @vitejs/plugin-react@^4.2.1, lodash@^4.17.21, react@^18.2.0, react-dom@^18.2.0, typescript@^5.0.2, vite@^5.0.0
- tauri/src-tauri/Cargo.toml: anyhow@1.0.79, arrow-array@50.0.0, arrow-schema@50.0.0, async-openai@0.18.3, futures@0.3.30, lopdf@0.32.0, open@5.0.1, pdf-extract@0.7.4, serde@1.0, serde_json@1.0, tauri@1.5, tauri-build@1.5, tokio@1.36.0, vectordb@0.4.10, walkdir@2.4.0

### Recent commits (newest first)

- updated readme
- changed name
- polishes
- better icons
- better icons
- better icons
- normalize
- fix conflict
- open files (rust)
- add more files; update parser
- add more files; rearrange into folders
- added highlight
- merge
- concate name and file content
- Batch indexing
- integrated w backend
- migrate to async openai
- add random files
- better front end
- working ish

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

### tauri/package.json

```
{
  "name": "semantic-files",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview",
    "tauri": "tauri"
  },
  "dependencies": {
    "@tauri-apps/api": "^1.5.2",
    "lodash": "^4.17.21",
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "@tauri-apps/cli": "^1.5.9",
    "@types/lodash": "^4.14.202",
    "@types/react": "^18.2.15",
    "@types/react-dom": "^18.2.7",
    "@vitejs/plugin-react": "^4.2.1",
    "typescript": "^5.0.2",
    "vite": "^5.0.0"
  }
}

```

### files-to-index/6110-sp24-main/Cargo.toml

```
[package]
name = "decaf-rust"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
clap = { version = "4.4.18", features = ["derive"] }
serde = { version = "1.0.196", features = ["derive"] }

[dev-dependencies]
base64 = "0.21.7"
insta = { version = "1.34.0", features = ["yaml"] }
rstest = "0.18.2"

[profile.dev.package]
insta.opt-level = 3

```

### tauri/src-tauri/Cargo.toml

```
[package]
name = "semantic-files"
version = "0.0.0"
description = "A Tauri App"
authors = ["you"]
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[build-dependencies]
tauri-build = { version = "1.5", features = [] }

[dependencies]
tauri = { version = "1.5", features = [ "window-hide", "global-shortcut-all", "macos-private-api", "shell-open"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
vectordb = "0.4.10"
walkdir = "2.4.0"
anyhow = "1.0.79"
pdf-extract = "0.7.4"
tokio = "1.36.0"
futures = "0.3.30"
arrow-schema = "50.0.0"
arrow-array = "50.0.0"
lopdf = "0.32.0"
async-openai = "0.18.3"
open = "5.0.1"

[features]
# this feature is used for production builds or when `devPath` points to the filesystem
# DO NOT REMOVE!!
custom-protocol = ["tauri/custom-protocol"]

```

### tauri/src/main.tsx

```typescript
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import "./styles.css";

ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
);
```

### tauri/src/App.tsx

```typescript
import { useEffect, useState } from "react";
import { invoke } from "@tauri-apps/api/tauri";
import { appWindow } from "@tauri-apps/api/window";
import SearchBox from "./components/searchbox";
import ResultBox from "./components/resultbox";
import { SearchResult } from "./types/types";
import { debounce } from 'lodash'
import "./App.css";

function App() {
  const [searchResults, setSearchResults] = useState<SearchResult[]>([]);

  useEffect(() => {
    window.addEventListener('click', (e: MouseEvent) => {
      if (!document.getElementById('app')?.contains(e.target as Node)) {
        appWindow.hide();
      }
    });

    return () => {
      window.removeEventListener('click', () => {
        appWindow.hide();
      });
    }
  }, [])

  const handleSearchChange = async (text: string) => {
    const res = await invoke("search", { searchText: text});
    if (res) {
      const searchResults = res as SearchResult[];
      setSearchResults(searchResults);
    };
  };

  const debouncedSearch = debounce(handleSearchChange, 100, { trailing: true, leading: true })

  return (
    <div id="app">
      <SearchBox onSearchChange={debouncedSearch} />
      <div className="results">
        {searchResults.map((result, index) => (
          <ResultBox key={index} result={result} />
        ))}
      </div>
    </div>
  );
}

export default App;

```

### files-to-index/6110-sp24-main/src/main.rs

```rust
use std::{error, process::exit};

mod parser;
mod tokenizer;
mod utils;

fn get_writer(output: &Option<std::path::PathBuf>) -> Box<dyn std::io::Write> {
    match output {
        Some(path) => Box::new(std::fs::File::create(path.as_path()).unwrap()),
        None => Box::new(std::io::stdout()),
    }
}

fn execute(
    input: &str,
    writer: &mut Box<dyn std::io::Write>,
    target: utils::cli::CompilerAction,
) -> Result<(), Box<dyn error::Error>> {
    match target {
        utils::cli::CompilerAction::Default => {
            panic!("Invalid target");
        }
        utils::cli::CompilerAction::Scan => {
            let tokens = tokenizer::tokenize(input.to_string())?;
            for token in tokens {
                writeln!(writer, "{token}").unwrap();
            }
        }
        utils::cli::CompilerAction::Parse => {
            let tokens = tokenizer::tokenize(input.to_string())?;
            let program = parser::parse_program(tokens)?;
            writeln!(writer, "{:?}", program).unwrap();
        }
        utils::cli::CompilerAction::Inter => {
            todo!("inter");
        }
        utils::cli::CompilerAction::Assembly => {
            todo!("assembly");
        }
    }
    Ok(())
}

fn main() {
    let args = utils::cli::parse();
    let input = std::fs::read_to_string(&args.input).expect("Filename is incorrect.");

    if args.debug {
        eprintln!(
            "Filename: {:?}\nDebug: {:?}\nOptimizations: {:?}\nOutput File: {:?}\nTarget: {:?}",
            args.input, args.debug, args.opt, args.output, args.target
        );
    }

    // Use writeln!(writer, "template string") to write to stdout ot file.
    let mut writer = get_writer(&args.output);
    match execute(&input, &mut writer, args.target) {
        Ok(()) => {}
        Err(e) => {
            eprintln!("{e}");
            exit(1);
        }
    }
}

```

### tauri/src-tauri/src/main.rs

```rust
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

use std::sync::Arc;
use serde::Serialize;
use tauri::Manager;
use tauri::GlobalShortcutManager;

use db::{DbConnection, init_db};
use indexer::start_indexing;

mod indexer;
mod db;
mod similarity_search;
mod embeddings;
mod parser;

pub const EMBEDDING_DIM: u32 = 128;

#[derive(Serialize)]
struct SearchResult {
    fileName: String,
    directory: String,
    fileSize: u64, 
    numPages: Option<u64>,
}

#[tauri::command]
async fn search(search_text: &str, state: tauri::State<'_, DbConnection>) -> Result<Vec<SearchResult>, ()> {
    if search_text.is_empty() {
        return Ok(Vec::new());
    }

    let prompt_embed = embeddings::create_embedding_prompt(search_text).await.unwrap();
    let result = similarity_search::search(state.inner().clone(), prompt_embed).await.unwrap();

    Ok(result)
}

#[tauri::command]
async fn open(path: &str, _state: tauri::State<'_, DbConnection>) -> Result<(), ()> {
    open::that(path).unwrap();
    Ok(())
}

fn main() {
    tauri::Builder::default()
        .setup(|app| { 
            let initialize_db = true;

            let handle = tauri::async_runtime::spawn(async move { 
                let db = init_db(initialize_db).await;
                db
            });
            let db = tauri::async_runtime::block_on(handle).unwrap();
            app.manage(db.clone());

            if initialize_db {
                tauri::async_runtime::spawn(async move {
                    println!("Starting indexing process...");
                    match start_indexing(db).await {
                        Ok(_) => println!("Indexing process finished successfully!"),
                        Err(e) => println!("Error while indexing: {}", e),
                    }
                });
            }

            let window = app.get_window("main").unwrap();
            window.hide().unwrap();
            let window_rc1 = Arc::new(window);
            let window_rc2 = Arc::clone(&window_rc1);

            {
                let _toggle = app.app_handle().global_shortcut_manager().register("Cmd+]", move || {
                    if window_rc1.is_visible().unwrap() {
                        window_rc1.hide().unwrap();
                    } else {
                        window_rc1.show().unwrap();
                    }
                });
            }

            {
                let _hide_esc = app.app_handle().global_shortcut_manager().register("esc", move || {
                    window_rc2.hide().unwrap();
                });
            }

            Ok(()) 
        }) 
        .invoke_handler(tauri::generate_handler![search, open])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

```

### files-to-index/6110-sp24-main/src/utils/cli.rs

```rust
/**
 * A generic command-line interface for 6.035 compilers.  This class
 * provides command-line parsing for student projects.  It recognizes
 * the required <tt>-target</tt>, <tt>-debug</tt>, <tt>-opt</tt>, and
 * <tt>-o</tt> switches, and generates a name for input and output
 * files.
 *
 * @author 6.1100 Staff, last updated January 2024
 */
use clap::Parser;

#[derive(Clone, clap::ValueEnum, Debug)]
pub enum CompilerAction {
    Default,
    Scan,
    Parse,
    Inter,
    Assembly,
}

#[derive(Clone, clap::ValueEnum, Debug, PartialEq, Eq, Hash)]
pub enum Optimization {}

#[derive(Parser, Debug)]
pub struct Args {
    /// compile to the given stage
    #[clap(short, long, value_enum, default_value_t=CompilerAction::Default, value_name = "stage")]
    pub target: CompilerAction,

    /// write output to
    #[clap(short, long, value_name = "outname")]
    pub output: Option<std::path::PathBuf>,

    /// Perform the listed optimizations
    #[clap(
        short = 'O',
        long,
        value_delimiter = ',',
        value_enum,
        value_name = "optimization,.."
    )]
    pub opt: Vec<Optimization>,

    /// Print debugging information
    #[arg(short, long, default_value_t = false)]
    pub debug: bool,

    /// Decaf file
    pub input: std::path::PathBuf,
}

pub fn parse() -> Args {
    Args::parse()
}

```

### tauri/index.html

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Tauri + React + TS</title>
  </head>

  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

```

### tauri/vite.config.ts

```typescript
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

// https://vitejs.dev/config/
export default defineConfig(async () => ({
  plugins: [react()],

  // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
  //
  // 1. prevent vite from obscuring rust errors
  clearScreen: false,
  // 2. tauri expects a fixed port, fail if that port is not available
  server: {
    port: 1420,
    strictPort: true,
    watch: {
      // 3. tell vite to ignore watching `src-tauri`
      ignored: ["**/src-tauri/**"],
    },
  },
}));

```

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