Compare commits
75 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c7e510723d | |||
| 42093de872 | |||
| aa48a5d764 | |||
| 1dedca45ac | |||
| 3552de1b45 | |||
| 2b94e36df6 | |||
| d1e1de4a8d | |||
| 23587e17ad | |||
| 213f452f0b | |||
| 27a488539d | |||
| 283da50d33 | |||
| a809085715 | |||
| 67321f1cba | |||
| 7683186470 | |||
| fded43b77e | |||
| 22ff7da4e0 | |||
| 844561b6cc | |||
| 52bc1d8387 | |||
| 8a3ac0c338 | |||
| bb125d7d4f | |||
| a405716847 | |||
| bad6e03095 | |||
| 2330fddfbb | |||
| 61dfd74134 | |||
| 029ff83979 | |||
| dbbc4cb2e1 | |||
| 1cce21cdc2 | |||
| 8b786a51b3 | |||
| ad7537dd84 | |||
| 3bab23172a | |||
| 18c132d494 | |||
| d072353e08 | |||
| c8bbc101cc | |||
| b93f748998 | |||
| ecb100448a | |||
| c749c856b5 | |||
| 0baf278972 | |||
| ae7780266a | |||
| 587960aebe | |||
| 4e1b6784f7 | |||
| 8b381f2640 | |||
| 0dc7fa6c34 | |||
| 2a2bf682bf | |||
| 87526129fb | |||
| 8ed1b7aa46 | |||
| 4084bd0ecc | |||
| d11eaceaf1 | |||
| 1e6986fbc5 | |||
| 11a19bdec7 | |||
| 51064f1b90 | |||
| 3385cd19e8 | |||
| 852f8517df | |||
| bb917f9818 | |||
| 10248fb29f | |||
| 446dc85bdd | |||
| 4aa2c226a9 | |||
| bf9ba8313a | |||
| 444b59c557 | |||
| b2e1df94db | |||
| b4963cabc8 | |||
| 2851024340 | |||
| 7f25a25729 | |||
| acfe23265a | |||
| 2c6fbbd7dd | |||
| 3e8c923641 | |||
| df5cbe30a6 | |||
| 9e1a536778 | |||
| a1db8833ef | |||
| 95dd0e0158 | |||
| 19f3c857d5 | |||
| 7f3da73aa4 | |||
| c384c2b610 | |||
| dcf358f27d | |||
| 40afc8c0e2 | |||
| b22bc8a799 |
@@ -1,7 +1,6 @@
|
||||
name: Bugfix
|
||||
title: "Sweep: "
|
||||
title: ""
|
||||
description: Write something like "We notice ... behavior when ... happens instead of ...""
|
||||
labels: sweep
|
||||
body:
|
||||
- type: textarea
|
||||
id: description
|
||||
@@ -1,11 +1,10 @@
|
||||
name: Feature Request
|
||||
title: "Sweep: "
|
||||
description: Write something like "Write an api endpoint that does "..." in the "..." file"
|
||||
labels: sweep
|
||||
title: ""
|
||||
description: Write something like "Write an api endpoint that does "..." in the "..." file". If you would like to use sweep.dev prefix with "Sweep:"
|
||||
body:
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Details
|
||||
description: More details for Sweep
|
||||
description: More details
|
||||
placeholder: The new endpoint should use the ... class from ... file because it contains ... logic
|
||||
@@ -1,11 +1,10 @@
|
||||
name: Refactor
|
||||
title: "Sweep: "
|
||||
description: Write something like "Modify the ... api endpoint to use ... version and ... framework"
|
||||
labels: sweep
|
||||
title: ""
|
||||
description: Write something like "Modify the ... api endpoint to use ... version and ... framework" If you would like to use sweep.dev prefix with "Sweep:"
|
||||
body:
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Details
|
||||
description: More details for Sweep
|
||||
description: More details
|
||||
placeholder: We are migrating this function to ... version because ...
|
||||
@@ -12,14 +12,14 @@ jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install pnpm
|
||||
run: npm install -g pnpm
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v2
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: "pnpm"
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Run lint
|
||||
run: pnpm run lint
|
||||
|
||||
@@ -7,18 +7,14 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v2
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v2
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "18"
|
||||
|
||||
node-version-file: '.nvmrc'
|
||||
cache: "pnpm"
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
npm i -g pnpm
|
||||
pnpm install
|
||||
|
||||
run: pnpm install
|
||||
- name: Run tests
|
||||
run: pnpm run test
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"[xml]": {
|
||||
"editor.defaultFormatter": "redhat.vscode-xml"
|
||||
}
|
||||
}
|
||||
},
|
||||
"jest.rootPath": "./packages/core"
|
||||
}
|
||||
@@ -8,38 +8,38 @@ We include several end-to-end examples using LlamaIndex.TS in the repository
|
||||
|
||||
Check out the examples below or try them out and complete them in minutes with interactive Github Codespace tutorials provided by Dev-Docs [here](https://codespaces.new/team-dev-docs/lits-dev-docs-playground?devcontainer_path=.devcontainer%2Fjavascript_ltsquickstart%2Fdevcontainer.json):
|
||||
|
||||
## [Chat Engine](https://github.com/run-llama/LlamaIndexTS/blob/main/apps/simple/chatEngine.ts)
|
||||
## [Chat Engine](https://github.com/run-llama/LlamaIndexTS/blob/main/examples/chatEngine.ts)
|
||||
|
||||
Read a file and chat about it with the LLM.
|
||||
|
||||
## [Vector Index](https://github.com/run-llama/LlamaIndexTS/blob/main/apps/simple/vectorIndex.ts)
|
||||
## [Vector Index](https://github.com/run-llama/LlamaIndexTS/blob/main/examples/vectorIndex.ts)
|
||||
|
||||
Create a vector index and query it. The vector index will use embeddings to fetch the top k most relevant nodes. By default, the top k is 2.
|
||||
|
||||
## [Summary Index](https://github.com/run-llama/LlamaIndexTS/blob/main/apps/simple/summaryIndex.ts)
|
||||
## [Summary Index](https://github.com/run-llama/LlamaIndexTS/blob/main/examples/summaryIndex.ts)
|
||||
|
||||
Create a list index and query it. This example also use the `LLMRetriever`, which will use the LLM to select the best nodes to use when generating answer.
|
||||
|
||||
## [Save / Load an Index](https://github.com/run-llama/LlamaIndexTS/blob/main/apps/simple/storageContext.ts)
|
||||
## [Save / Load an Index](https://github.com/run-llama/LlamaIndexTS/blob/main/examples/storageContext.ts)
|
||||
|
||||
Create and load a vector index. Persistance to disk in LlamaIndex.TS happens automatically once a storage context object is created.
|
||||
|
||||
## [Customized Vector Index](https://github.com/run-llama/LlamaIndexTS/blob/main/apps/simple/vectorIndexCustomize.ts)
|
||||
## [Customized Vector Index](https://github.com/run-llama/LlamaIndexTS/blob/main/examples/vectorIndexCustomize.ts)
|
||||
|
||||
Create a vector index and query it, while also configuring the the `LLM`, the `ServiceContext`, and the `similarity_top_k`.
|
||||
|
||||
## [OpenAI LLM](https://github.com/run-llama/LlamaIndexTS/blob/main/apps/simple/openai.ts)
|
||||
## [OpenAI LLM](https://github.com/run-llama/LlamaIndexTS/blob/main/examples/openai.ts)
|
||||
|
||||
Create an OpenAI LLM and directly use it for chat.
|
||||
|
||||
## [Llama2 DeuceLLM](https://github.com/run-llama/LlamaIndexTS/blob/main/apps/simple/llamadeuce.ts)
|
||||
## [Llama2 DeuceLLM](https://github.com/run-llama/LlamaIndexTS/blob/main/examples/llamadeuce.ts)
|
||||
|
||||
Create a Llama-2 LLM and directly use it for chat.
|
||||
|
||||
## [SubQuestionQueryEngine](https://github.com/run-llama/LlamaIndexTS/blob/main/apps/simple/subquestion.ts)
|
||||
## [SubQuestionQueryEngine](https://github.com/run-llama/LlamaIndexTS/blob/main/examples/subquestion.ts)
|
||||
|
||||
Uses the `SubQuestionQueryEngine`, which breaks complex queries into multiple questions, and then aggreates a response across the answers to all sub-questions.
|
||||
|
||||
## [Low Level Modules](https://github.com/run-llama/LlamaIndexTS/blob/main/apps/simple/lowlevel.ts)
|
||||
## [Low Level Modules](https://github.com/run-llama/LlamaIndexTS/blob/main/examples/lowlevel.ts)
|
||||
|
||||
This example uses several low-level components, which removes the need for an actual query engine. These components can be used anywhere, in any application, or customized and sub-classed to meet your own needs.
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
# Installation and Setup
|
||||
|
||||
## Installation from NPM
|
||||
|
||||
Make sure you have NodeJS v18 or higher.
|
||||
|
||||
```bash npm2yarn
|
||||
npm install llamaindex
|
||||
```
|
||||
|
||||
## Environment variables
|
||||
|
||||
Our examples use OpenAI by default. You'll need to set up your Open AI key like so:
|
||||
|
||||
```bash
|
||||
export OPENAI_API_KEY="sk-......" # Replace with your key from https://platform.openai.com/account/api-keys
|
||||
```
|
||||
|
||||
If you want to have it automatically loaded every time, add it to your .zshrc/.bashrc.
|
||||
|
||||
WARNING: do not check in your OpenAI key into version control.
|
||||
@@ -0,0 +1,63 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
# Installation and Setup
|
||||
|
||||
Make sure you have NodeJS v18 or higher.
|
||||
|
||||
## Using create-llama
|
||||
|
||||
The easiest way to get started with LlamaIndex is by using `create-llama`. This CLI tool enables you to quickly start building a new LlamaIndex application, with everything set up for you.
|
||||
|
||||
Just run
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="1" label="npm" default>
|
||||
|
||||
```bash
|
||||
npx create-llama@latest
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="2" label="Yarn">
|
||||
|
||||
```bash
|
||||
yarn create llama
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="3" label="pnpm">
|
||||
|
||||
```bash
|
||||
pnpm create llama@latest
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
to get started. Once your app is generated, run
|
||||
|
||||
```bash npm2yarn
|
||||
npm run dev
|
||||
```
|
||||
|
||||
to start the development server. You can then visit [http://localhost:3000](http://localhost:3000) to see your app
|
||||
|
||||
## Installation from NPM
|
||||
|
||||
```bash npm2yarn
|
||||
npm install llamaindex
|
||||
```
|
||||
|
||||
### Environment variables
|
||||
|
||||
Our examples use OpenAI by default. You'll need to set up your Open AI key like so:
|
||||
|
||||
```bash
|
||||
export OPENAI_API_KEY="sk-......" # Replace with your key from https://platform.openai.com/account/api-keys
|
||||
```
|
||||
|
||||
If you want to have it automatically loaded every time, add it to your .zshrc/.bashrc.
|
||||
|
||||
WARNING: do not check in your OpenAI key into version control.
|
||||
@@ -5,7 +5,7 @@ slug: /
|
||||
|
||||
# What is LlamaIndex.TS?
|
||||
|
||||
LlamaIndex.TS is a data framework for LLM applications to ingest, structure, and access private or domain-specific data. While a python package is also available (see [here](https://gpt-index.readthedocs.io/en/latest/)), LlamaIndex.TS offers core features in a simple package, optimized for usage with TypeScript.
|
||||
LlamaIndex.TS is a data framework for LLM applications to ingest, structure, and access private or domain-specific data. While a python package is also available (see [here](https://docs.llamaindex.ai/en/stable/)), LlamaIndex.TS offers core features in a simple package, optimized for usage with TypeScript.
|
||||
|
||||
## 🚀 Why LlamaIndex.TS?
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ The basic concept of the Sub Question Query Engine is that it splits a single qu
|
||||
|
||||
### Getting Started
|
||||
|
||||
The easiest way to start trying the Sub Question Query Engine is running the subquestion.ts file in [apps/simple](https://github.com/run-llama/LlamaIndexTS/blob/main/apps/simple/subquestion.ts).
|
||||
The easiest way to start trying the Sub Question Query Engine is running the subquestion.ts file in [examples](https://github.com/run-llama/LlamaIndexTS/blob/main/examples/subquestion.ts).
|
||||
|
||||
```bash
|
||||
npx ts-node subquestion.ts
|
||||
|
||||
@@ -4,7 +4,7 @@ sidebar_position: 2
|
||||
|
||||
# Starter Tutorial
|
||||
|
||||
Once you have [installed LlamaIndex.TS using NPM](installation.md) and set up your OpenAI key, you're ready to start your first app:
|
||||
Once you have [installed LlamaIndex.TS using NPM](installation) and set up your OpenAI key, you're ready to start your first app:
|
||||
|
||||
In a new folder:
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/* eslint-disable turbo/no-undeclared-env-vars */
|
||||
import * as dotenv from "dotenv";
|
||||
import * as fs from "fs";
|
||||
import { MongoClient } from "mongodb";
|
||||
|
||||
// Load environment variables from local .env file
|
||||
dotenv.config();
|
||||
|
||||
const jsonFile = "tinytweets.json";
|
||||
const mongoUri = process.env.MONGODB_URI!;
|
||||
const databaseName = process.env.MONGODB_DATABASE!;
|
||||
const collectionName = process.env.MONGODB_COLLECTION!;
|
||||
|
||||
async function importJsonToMongo() {
|
||||
// Load the tweets from a local file
|
||||
const tweets = JSON.parse(fs.readFileSync(jsonFile, "utf-8"));
|
||||
|
||||
// Create a new client and connect to the server
|
||||
const client = new MongoClient(mongoUri);
|
||||
|
||||
const db = client.db(databaseName);
|
||||
const collection = db.collection(collectionName);
|
||||
|
||||
// Insert the tweets into mongo
|
||||
await collection.insertMany(tweets);
|
||||
|
||||
console.log(
|
||||
`Data imported successfully to the MongoDB collection ${collectionName}.`,
|
||||
);
|
||||
await client.close();
|
||||
}
|
||||
|
||||
// Run the import function
|
||||
importJsonToMongo();
|
||||
@@ -0,0 +1,50 @@
|
||||
/* eslint-disable turbo/no-undeclared-env-vars */
|
||||
import * as dotenv from "dotenv";
|
||||
import {
|
||||
MongoDBAtlasVectorSearch,
|
||||
SimpleMongoReader,
|
||||
storageContextFromDefaults,
|
||||
VectorStoreIndex,
|
||||
} from "llamaindex";
|
||||
import { MongoClient } from "mongodb";
|
||||
|
||||
// Load environment variables from local .env file
|
||||
dotenv.config();
|
||||
|
||||
const mongoUri = process.env.MONGODB_URI!;
|
||||
const databaseName = process.env.MONGODB_DATABASE!;
|
||||
const collectionName = process.env.MONGODB_COLLECTION!;
|
||||
const vectorCollectionName = process.env.MONGODB_VECTORS!;
|
||||
const indexName = process.env.MONGODB_VECTOR_INDEX!;
|
||||
|
||||
async function loadAndIndex() {
|
||||
// Create a new client and connect to the server
|
||||
const client = new MongoClient(mongoUri);
|
||||
// load objects from mongo and convert them into LlamaIndex Document objects
|
||||
// llamaindex has a special class that does this for you
|
||||
// it pulls every object in a given collection
|
||||
const reader = new SimpleMongoReader(client);
|
||||
const documents = await reader.loadData(databaseName, collectionName, [
|
||||
"full_text",
|
||||
]);
|
||||
|
||||
// create Atlas as a vector store
|
||||
const vectorStore = new MongoDBAtlasVectorSearch({
|
||||
mongodbClient: client,
|
||||
dbName: databaseName,
|
||||
collectionName: vectorCollectionName, // this is where your embeddings will be stored
|
||||
indexName: indexName, // this is the name of the index you will need to create
|
||||
});
|
||||
|
||||
// now create an index from all the Documents and store them in Atlas
|
||||
const storageContext = await storageContextFromDefaults({ vectorStore });
|
||||
await VectorStoreIndex.fromDocuments(documents, { storageContext });
|
||||
console.log(
|
||||
`Successfully created embeddings in the MongoDB collection ${vectorCollectionName}.`,
|
||||
);
|
||||
await client.close();
|
||||
}
|
||||
|
||||
loadAndIndex();
|
||||
|
||||
// you can't query your index yet because you need to create a vector search index in mongodb's UI now
|
||||
@@ -0,0 +1,34 @@
|
||||
/* eslint-disable turbo/no-undeclared-env-vars */
|
||||
import * as dotenv from "dotenv";
|
||||
import {
|
||||
MongoDBAtlasVectorSearch,
|
||||
serviceContextFromDefaults,
|
||||
VectorStoreIndex,
|
||||
} from "llamaindex";
|
||||
import { MongoClient } from "mongodb";
|
||||
|
||||
// Load environment variables from local .env file
|
||||
dotenv.config();
|
||||
|
||||
async function query() {
|
||||
const client = new MongoClient(process.env.MONGODB_URI!);
|
||||
const serviceContext = serviceContextFromDefaults();
|
||||
const store = new MongoDBAtlasVectorSearch({
|
||||
mongodbClient: client,
|
||||
dbName: process.env.MONGODB_DATABASE!,
|
||||
collectionName: process.env.MONGODB_VECTORS!,
|
||||
indexName: process.env.MONGODB_VECTOR_INDEX!,
|
||||
});
|
||||
|
||||
const index = await VectorStoreIndex.fromVectorStore(store, serviceContext);
|
||||
|
||||
const retriever = index.asRetriever({ similarityTopK: 20 });
|
||||
const queryEngine = index.asQueryEngine({ retriever });
|
||||
const result = await queryEngine.query(
|
||||
"What does the author think of web frameworks?",
|
||||
);
|
||||
console.log(result.response);
|
||||
await client.close();
|
||||
}
|
||||
|
||||
query();
|
||||
@@ -0,0 +1,20 @@
|
||||
# mongodb-llamaindexts
|
||||
|
||||
## 0.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [3bab231]
|
||||
- llamaindex@0.0.37
|
||||
|
||||
## 0.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- Updated dependencies
|
||||
- Updated dependencies
|
||||
- Updated dependencies
|
||||
- Updated dependencies
|
||||
- Updated dependencies
|
||||
- llamaindex@0.0.36
|
||||
@@ -0,0 +1,127 @@
|
||||
# LlamaIndexTS retrieval augmented generation with MongoDB
|
||||
|
||||
### Prepare Environment
|
||||
|
||||
Make sure to run `pnpm install` and set your OpenAI environment variable before running these examples.
|
||||
|
||||
```
|
||||
pnpm install
|
||||
export OPENAI_API_KEY="sk-..."
|
||||
```
|
||||
|
||||
### Sign up for MongoDB Atlas
|
||||
|
||||
We'll be using MongoDB's hosted database service, [MongoDB Atlas](https://www.mongodb.com/cloud/atlas/register). You can sign up for free and get a small hosted cluster for free:
|
||||
|
||||

|
||||
|
||||
The signup process will walk you through the process of creating your cluster and ensuring it's configured for you to access. Once the cluster is created, choose "Connect" and then "Connect to your application". Choose Python, and you'll be presented with a connection string that looks like this:
|
||||
|
||||

|
||||
|
||||
### Set up environment variables
|
||||
|
||||
Copy the connection string (make sure you include your password) and put it into a file called `.env` in the root of this repo. It should look like this:
|
||||
|
||||
```
|
||||
MONGODB_URI=mongodb+srv://seldo:xxxxxxxxxxx@llamaindexdemocluster.xfrdhpz.mongodb.net/?retryWrites=true&w=majority
|
||||
```
|
||||
|
||||
You will also need to choose a name for your database, and the collection where we will store the tweets, and also include them in .env. They can be any string, but this is what we used:
|
||||
|
||||
```
|
||||
MONGODB_DATABASE=tiny_tweets_db
|
||||
MONGODB_COLLECTION=tiny_tweets_collection
|
||||
```
|
||||
|
||||
### Import tweets into MongoDB
|
||||
|
||||
You are now ready to import our ready-made data set into Mongo. This is the file `tinytweets.json`, a selection of approximately 1000 tweets from @seldo on Twitter in mid-2019. With your environment set up you can do this by running
|
||||
|
||||
```
|
||||
pnpm ts-node 1_import.ts
|
||||
```
|
||||
|
||||
If you don't want to use tweets, you can replace `json_file` with any other array of JSON objects, but you will need to modify some code later to make sure the correct field gets indexed. There is no LlamaIndex-specific code here; you can load your data into Mongo any way you want to.
|
||||
|
||||
### Load and index your data
|
||||
|
||||
Now we're ready to index our data. To do this, LlamaIndex will pull your text out of Mongo, split it into chunks, and then send those chunks to OpenAI to be turned into [vector embeddings](https://docs.llamaindex.ai/en/stable/understanding/indexing/indexing.html#what-is-an-embedding). The embeddings will then be stored in a new collection in Mongo. This will take a while depending how much text you have, but the good news is that once it's done you will be able to query quickly without needing to re-index.
|
||||
|
||||
We'll be using OpenAI to do the embedding, so now is when you need to [generate an OpenAI API key](https://platform.openai.com/account/api-keys) if you haven't already and add it to your `.env` file like this:
|
||||
|
||||
```
|
||||
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
```
|
||||
|
||||
You'll also need to pick a name for the new collection where the embeddings will be stored, and add it to `.env`, along with the name of a vector search index (we'll be creating this in the next step, after you've indexed your data):
|
||||
|
||||
```
|
||||
MONGODB_VECTORS=tiny_tweets_vectors
|
||||
MONGODB_VECTOR_INDEX=tiny_tweets_vector_index
|
||||
```
|
||||
|
||||
If the data you're indexing is the tweets we gave you, you're ready to go:
|
||||
|
||||
```bash
|
||||
pnpm ts-node 2_load_and_index.ts
|
||||
```
|
||||
|
||||
> Note: this script is running a couple of minutes and currently doesn't show any progress.
|
||||
|
||||
What you're doing here is creating a Reader which loads the data out of Mongo in the collection and database specified. It looks for text in a set of specific keys in each object. In this case we've given it just one key, "full_text".
|
||||
|
||||
Now you're creating a vector search client for Mongo. In addition to a MongoDB client object, you again tell it what database everything is in. This time you give it the name of the collection where you'll store the vector embeddings, and the name of the vector search index you'll create in the next step.
|
||||
|
||||
### Create a vector search index
|
||||
|
||||
Now if all has gone well you should be able to log in to the Mongo Atlas UI and see two collections in your database: the original data in `tiny_tweets_collection`, and the vector embeddings in `tiny_tweets_vectors`.
|
||||
|
||||

|
||||
|
||||
Now it's time to create the vector search index so that you can query the data.
|
||||
It's not yet possible to programmatically create a vector search index using the [`createIndex`](https://www.mongodb.com/docs/manual/reference/method/db.collection.createIndex/) function, therefore we have to create one manually in the UI.
|
||||
To do so, first, click the Search tab, and then click "Create Search Index":
|
||||
|
||||

|
||||
|
||||
We have to use the JSON editor, as the Visual Editor does not yet support to create a vector search index:
|
||||
|
||||

|
||||
|
||||
Now under "database and collection" select `tiny_tweets_db` and within that select `tiny_tweets_vectors`. Then under "Index name" enter `tiny_tweets_vector_index` (or whatever value you put for MONGODB_VECTOR_INDEX in `.env`). Under that, you'll want to enter this JSON object:
|
||||
|
||||
```json
|
||||
{
|
||||
"mappings": {
|
||||
"dynamic": true,
|
||||
"fields": {
|
||||
"embedding": {
|
||||
"dimensions": 1536,
|
||||
"similarity": "cosine",
|
||||
"type": "knnVector"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This tells Mongo that the `embedding` field in each document (in the `tiny_tweets_vectors` collection) is a vector of 1536 dimensions (this is the size of embeddings used by OpenAI), and that we want to use cosine similarity to compare vectors. You don't need to worry too much about these values unless you want to use a different LLM to OpenAI entirely.
|
||||
|
||||
The UI will ask you to review and confirm your choices, then you need to wait a minute or two while it generates the index. If all goes well, you should see something like this screen:
|
||||
|
||||

|
||||
|
||||
Now you're ready to query your data!
|
||||
|
||||
### Run a test query
|
||||
|
||||
You can do this by running
|
||||
|
||||
```bash
|
||||
pnpm ts-node 3_query.ts
|
||||
```
|
||||
|
||||
This sets up a connection to Atlas just like `2_load_and_index.ts` did, then it creates a [query engine](https://docs.llamaindex.ai/en/stable/understanding/querying/querying.html#getting-started) and runs a query against it.
|
||||
|
||||
If all is well, you should get a nuanced opinion about web frameworks.
|
||||
|
After Width: | Height: | Size: 141 KiB |
|
After Width: | Height: | Size: 107 KiB |
|
After Width: | Height: | Size: 360 KiB |
|
After Width: | Height: | Size: 230 KiB |
|
After Width: | Height: | Size: 278 KiB |
|
After Width: | Height: | Size: 211 KiB |
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"version": "0.0.3",
|
||||
"private": true,
|
||||
"name": "mongodb-llamaindexts",
|
||||
"dependencies": {
|
||||
"llamaindex": "workspace:*",
|
||||
"dotenv": "^16.3.1",
|
||||
"mongodb": "^6.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.18.6",
|
||||
"ts-node": "^10.9.1"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint ."
|
||||
}
|
||||
}
|
||||
@@ -1,271 +0,0 @@
|
||||
# simple
|
||||
|
||||
## 0.0.33
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [63f2108]
|
||||
- llamaindex@0.0.35
|
||||
|
||||
## 0.0.32
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2a27e21]
|
||||
- llamaindex@0.0.34
|
||||
|
||||
## 0.0.31
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [5e2e92c]
|
||||
- llamaindex@0.0.33
|
||||
|
||||
## 0.0.30
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [90c0b83]
|
||||
- Updated dependencies [dfd22aa]
|
||||
- llamaindex@0.0.32
|
||||
|
||||
## 0.0.29
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [6c55b2d]
|
||||
- Updated dependencies [8aa8c65]
|
||||
- Updated dependencies [6c55b2d]
|
||||
- llamaindex@0.0.31
|
||||
|
||||
## 0.0.28
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [139abad]
|
||||
- Updated dependencies [139abad]
|
||||
- Updated dependencies [eb0e994]
|
||||
- Updated dependencies [eb0e994]
|
||||
- Updated dependencies [139abad]
|
||||
- llamaindex@0.0.30
|
||||
|
||||
## 0.0.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [a52143b]
|
||||
- Updated dependencies [1b7fd95]
|
||||
- Updated dependencies [0db3f41]
|
||||
- llamaindex@0.0.29
|
||||
|
||||
## 0.0.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [96bb657]
|
||||
- Updated dependencies [96bb657]
|
||||
- Updated dependencies [837854d]
|
||||
- llamaindex@0.0.28
|
||||
|
||||
## 0.0.25
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [4a5591b]
|
||||
- Updated dependencies [4a5591b]
|
||||
- Updated dependencies [4a5591b]
|
||||
- llamaindex@0.0.27
|
||||
|
||||
## 0.0.24
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [5bb55bc]
|
||||
- llamaindex@0.0.26
|
||||
|
||||
## 0.0.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [e21eca2]
|
||||
- Updated dependencies [40a8f07]
|
||||
- Updated dependencies [40a8f07]
|
||||
- llamaindex@0.0.25
|
||||
|
||||
## 0.0.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [e4af7b3]
|
||||
- Updated dependencies [259fe63]
|
||||
- llamaindex@0.0.24
|
||||
|
||||
## 0.0.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- Updated dependencies [9d6b2ed]
|
||||
- llamaindex@0.0.23
|
||||
|
||||
## 0.0.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [454f3f8]
|
||||
- Updated dependencies [454f3f8]
|
||||
- Updated dependencies [454f3f8]
|
||||
- Updated dependencies [454f3f8]
|
||||
- Updated dependencies [99df58f]
|
||||
- llamaindex@0.0.22
|
||||
|
||||
## 0.0.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [f7a57ca]
|
||||
- Updated dependencies [0a09de2]
|
||||
- Updated dependencies [f7a57ca]
|
||||
- llamaindex@0.0.21
|
||||
|
||||
## 0.0.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b526a2d]
|
||||
- Updated dependencies [b526a2d]
|
||||
- Updated dependencies [b526a2d]
|
||||
- llamaindex@0.0.20
|
||||
|
||||
## 0.0.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [a747f28]
|
||||
- Updated dependencies [355910b]
|
||||
- Updated dependencies [355910b]
|
||||
- llamaindex@0.0.19
|
||||
|
||||
## 0.0.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [824c13c]
|
||||
- Updated dependencies [18b8915]
|
||||
- Updated dependencies [ade9d8f]
|
||||
- Updated dependencies [824c13c]
|
||||
- llamaindex@0.0.18
|
||||
|
||||
## 0.0.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [f80b062]
|
||||
- Updated dependencies [b3fec86]
|
||||
- Updated dependencies [b3fec86]
|
||||
- llamaindex@0.0.17
|
||||
|
||||
## 0.0.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [ec12633]
|
||||
- Updated dependencies [9214b06]
|
||||
- Updated dependencies [3316c6b]
|
||||
- Updated dependencies [3316c6b]
|
||||
- llamaindex@0.0.16
|
||||
|
||||
## 0.0.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b501eb5]
|
||||
- Updated dependencies [f9d1a6e]
|
||||
- llamaindex@0.0.15
|
||||
|
||||
## 0.0.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [4ef334a]
|
||||
- Updated dependencies [0af7773]
|
||||
- Updated dependencies [bea4af9]
|
||||
- Updated dependencies [4ef334a]
|
||||
- llamaindex@0.0.14
|
||||
|
||||
## 0.0.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [4f6f245]
|
||||
- llamaindex@0.0.13
|
||||
|
||||
## 0.0.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [68bdaaa]
|
||||
- llamaindex@0.0.12
|
||||
|
||||
## 0.0.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [fb7fb76]
|
||||
- llamaindex@0.0.11
|
||||
|
||||
## 0.0.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [6f2cb31]
|
||||
- llamaindex@0.0.10
|
||||
|
||||
## 0.0.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [02d9bb0]
|
||||
- llamaindex@0.0.9
|
||||
|
||||
## 0.0.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [ea5038e]
|
||||
- llamaindex@0.0.8
|
||||
|
||||
## 0.0.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [9fa6d4a]
|
||||
- llamaindex@0.0.7
|
||||
|
||||
## 0.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- llamaindex@0.0.6
|
||||
|
||||
## 0.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [5a765aa]
|
||||
- llamaindex@0.0.5
|
||||
|
||||
## 0.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [c65d671]
|
||||
- llamaindex@0.0.4
|
||||
|
||||
## 0.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [ca9410f]
|
||||
- llamaindex@0.0.3
|
||||
@@ -1,10 +0,0 @@
|
||||
# Simple Examples
|
||||
|
||||
Due to packaging, you will need to run these commands to get started.
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
pnpm --filter llamaindex build
|
||||
```
|
||||
|
||||
Then run the examples with `ts-node`, for example `npx ts-node vectorIndex.ts`
|
||||
@@ -1,16 +0,0 @@
|
||||
import { Anthropic } from "llamaindex";
|
||||
|
||||
(async () => {
|
||||
const anthropic = new Anthropic();
|
||||
const result = await anthropic.chat([
|
||||
{ content: "You want to talk in rhymes.", role: "system" },
|
||||
{ content: "Hello, world!", role: "user" },
|
||||
{ content: "Hello!", role: "assistant" },
|
||||
{
|
||||
content:
|
||||
"How much wood would a woodchuck chuck if a woodchuck could chuck wood?",
|
||||
role: "user",
|
||||
},
|
||||
]);
|
||||
console.log(result);
|
||||
})();
|
||||
@@ -1,33 +0,0 @@
|
||||
import { stdin as input, stdout as output } from "node:process";
|
||||
// readline/promises is still experimental so not in @types/node yet
|
||||
// @ts-ignore
|
||||
import readline from "node:readline/promises";
|
||||
|
||||
import {
|
||||
ContextChatEngine,
|
||||
Document,
|
||||
serviceContextFromDefaults,
|
||||
VectorStoreIndex,
|
||||
} from "llamaindex";
|
||||
|
||||
import essay from "./essay";
|
||||
|
||||
async function main() {
|
||||
const document = new Document({ text: essay });
|
||||
const serviceContext = serviceContextFromDefaults({ chunkSize: 512 });
|
||||
const index = await VectorStoreIndex.fromDocuments([document], {
|
||||
serviceContext,
|
||||
});
|
||||
const retriever = index.asRetriever();
|
||||
retriever.similarityTopK = 5;
|
||||
const chatEngine = new ContextChatEngine({ retriever });
|
||||
const rl = readline.createInterface({ input, output });
|
||||
|
||||
while (true) {
|
||||
const query = await rl.question("Query: ");
|
||||
const response = await chatEngine.chat(query);
|
||||
console.log(response.toString());
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -1,49 +0,0 @@
|
||||
import {
|
||||
CompactAndRefine,
|
||||
OpenAI,
|
||||
PapaCSVReader,
|
||||
ResponseSynthesizer,
|
||||
serviceContextFromDefaults,
|
||||
VectorStoreIndex,
|
||||
} from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
// Load CSV
|
||||
const reader = new PapaCSVReader();
|
||||
const path = "data/titanic_train.csv";
|
||||
const documents = await reader.loadData(path);
|
||||
|
||||
const serviceContext = serviceContextFromDefaults({
|
||||
llm: new OpenAI({ model: "gpt-4" }),
|
||||
});
|
||||
|
||||
// Split text and create embeddings. Store them in a VectorStoreIndex
|
||||
const index = await VectorStoreIndex.fromDocuments(documents, {
|
||||
serviceContext,
|
||||
});
|
||||
|
||||
const csvPrompt = ({ context = "", query = "" }) => {
|
||||
return `The following CSV file is loaded from ${path}
|
||||
\`\`\`csv
|
||||
${context}
|
||||
\`\`\`
|
||||
Given the CSV file, generate me Typescript code to answer the question: ${query}. You can use built in NodeJS functions but avoid using third party libraries.
|
||||
`;
|
||||
};
|
||||
|
||||
const responseSynthesizer = new ResponseSynthesizer({
|
||||
responseBuilder: new CompactAndRefine(serviceContext, csvPrompt),
|
||||
});
|
||||
|
||||
const queryEngine = index.asQueryEngine({ responseSynthesizer });
|
||||
|
||||
// Query the index
|
||||
const response = await queryEngine.query(
|
||||
"What is the correlation between survival and age?",
|
||||
);
|
||||
|
||||
// Output response
|
||||
console.log(response.toString());
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -1,715 +0,0 @@
|
||||
survived,pclass,name,sex,age,sibsp,parch,ticket,fare,cabin,embarked
|
||||
0,3,Braund,male,22,1,0,A/5 21171,7.25,,S
|
||||
1,1,Cumings,female,38,1,0,PC 17599,71.2833,C85,C
|
||||
1,3,Heikkinen,female,26,0,0,STON/O2. 3101282,7.925,,S
|
||||
1,1,Futrelle,female,35,1,0,113803,53.1,C123,S
|
||||
0,3,Allen,male,35,0,0,373450,8.05,,S
|
||||
0,1,McCarthy,male,54,0,0,17463,51.8625,E46,S
|
||||
0,3,Palsson,male,2,3,1,349909,21.075,,S
|
||||
1,3,Johnson,female,27,0,2,347742,11.1333,,S
|
||||
1,2,Nasser,female,14,1,0,237736,30.0708,,C
|
||||
1,3,Sandstrom,female,4,1,1,PP 9549,16.7,G6,S
|
||||
1,1,Bonnell,female,58,0,0,113783,26.55,C103,S
|
||||
0,3,Saundercock,male,20,0,0,A/5. 2151,8.05,,S
|
||||
0,3,Andersson,male,39,1,5,347082,31.275,,S
|
||||
0,3,Vestrom,female,14,0,0,350406,7.8542,,S
|
||||
1,2,Hewlett,female,55,0,0,248706,16,,S
|
||||
0,3,Rice,male,2,4,1,382652,29.125,,Q
|
||||
0,3,Vander,female,31,1,0,345763,18,,S
|
||||
0,2,Fynney,male,35,0,0,239865,26,,S
|
||||
1,2,Beesley,male,34,0,0,248698,13,D56,S
|
||||
1,3,McGowan,female,15,0,0,330923,8.0292,,Q
|
||||
1,1,Sloper,male,28,0,0,113788,35.5,A6,S
|
||||
0,3,Palsson,female,8,3,1,349909,21.075,,S
|
||||
1,3,Asplund,female,38,1,5,347077,31.3875,,S
|
||||
0,1,Fortune,male,19,3,2,19950,263,C23 C25 C27,S
|
||||
0,1,Uruchurtu,male,40,0,0,PC 17601,27.7208,,C
|
||||
0,2,Wheadon,male,66,0,0,C.A. 24579,10.5,,S
|
||||
0,1,Meyer,male,28,1,0,PC 17604,82.1708,,C
|
||||
0,1,Holverson,male,42,1,0,113789,52,,S
|
||||
0,3,Cann,male,21,0,0,A./5. 2152,8.05,,S
|
||||
0,3,Vander,female,18,2,0,345764,18,,S
|
||||
1,3,Nicola-Yarred,female,14,1,0,2651,11.2417,,C
|
||||
0,3,Ahlin,female,40,1,0,7546,9.475,,S
|
||||
0,2,Turpin,female,27,1,0,11668,21,,S
|
||||
1,2,Laroche,female,3,1,2,SC/Paris 2123,41.5792,,C
|
||||
1,3,Devaney,female,19,0,0,330958,7.8792,,Q
|
||||
0,3,Arnold-Franchi,female,18,1,0,349237,17.8,,S
|
||||
0,3,Panula,male,7,4,1,3101295,39.6875,,S
|
||||
0,3,Nosworthy,male,21,0,0,A/4. 39886,7.8,,S
|
||||
1,1,Harper,female,49,1,0,PC 17572,76.7292,D33,C
|
||||
1,2,Faunthorpe,female,29,1,0,2926,26,,S
|
||||
0,1,Ostby,male,65,0,1,113509,61.9792,B30,C
|
||||
1,2,Rugg,female,21,0,0,C.A. 31026,10.5,,S
|
||||
0,3,Novel,male,28.5,0,0,2697,7.2292,,C
|
||||
1,2,West,female,5,1,2,C.A. 34651,27.75,,S
|
||||
0,3,Goodwin,male,11,5,2,CA 2144,46.9,,S
|
||||
0,3,Sirayanian,male,22,0,0,2669,7.2292,,C
|
||||
1,1,Icard,female,38,0,0,113572,80,B28,
|
||||
0,1,Harris,male,45,1,0,36973,83.475,C83,S
|
||||
0,3,Skoog,male,4,3,2,347088,27.9,,S
|
||||
1,2,Nye,female,29,0,0,C.A. 29395,10.5,F33,S
|
||||
0,3,Crease,male,19,0,0,S.P. 3464,8.1583,,S
|
||||
1,3,Andersson,female,17,4,2,3101281,7.925,,S
|
||||
0,3,Kink,male,26,2,0,315151,8.6625,,S
|
||||
0,2,Jenkin,male,32,0,0,C.A. 33111,10.5,,S
|
||||
0,3,Goodwin,female,16,5,2,CA 2144,46.9,,S
|
||||
0,2,Hood,male,21,0,0,S.O.C. 14879,73.5,,S
|
||||
0,3,Chronopoulos,male,26,1,0,2680,14.4542,,C
|
||||
1,3,Bing,male,32,0,0,1601,56.4958,,S
|
||||
0,3,Moen,male,25,0,0,348123,7.65,F G73,S
|
||||
1,2,Caldwell,male,0.83,0,2,248738,29,,S
|
||||
1,3,Dowdell,female,30,0,0,364516,12.475,,S
|
||||
0,3,Waelens,male,22,0,0,345767,9,,S
|
||||
1,3,Sheerlinck,male,29,0,0,345779,9.5,,S
|
||||
0,1,Carrau,male,28,0,0,113059,47.1,,S
|
||||
1,2,Ilett,female,17,0,0,SO/C 14885,10.5,,S
|
||||
1,3,Backstrom,female,33,3,0,3101278,15.85,,S
|
||||
0,3,Ford,male,16,1,3,W./C. 6608,34.375,,S
|
||||
1,1,Fortune,female,23,3,2,19950,263,C23 C25 C27,S
|
||||
0,3,Celotti,male,24,0,0,343275,8.05,,S
|
||||
0,3,Christmann,male,29,0,0,343276,8.05,,S
|
||||
0,3,Andreasson,male,20,0,0,347466,7.8542,,S
|
||||
0,1,Chaffee,male,46,1,0,W.E.P. 5734,61.175,E31,S
|
||||
0,3,Dean,male,26,1,2,C.A. 2315,20.575,,S
|
||||
0,3,Coxon,male,59,0,0,364500,7.25,,S
|
||||
0,1,Goldschmidt,male,71,0,0,PC 17754,34.6542,A5,C
|
||||
1,1,Greenfield,male,23,0,1,PC 17759,63.3583,D10 D12,C
|
||||
1,2,Doling,female,34,0,1,231919,23,,S
|
||||
0,2,Kantor,male,34,1,0,244367,26,,S
|
||||
0,3,Petranec,female,28,0,0,349245,7.8958,,S
|
||||
0,1,White,male,21,0,1,35281,77.2875,D26,S
|
||||
0,3,Johansson,male,33,0,0,7540,8.6542,,S
|
||||
0,3,Gustafsson,male,37,2,0,3101276,7.925,,S
|
||||
0,3,Mionoff,male,28,0,0,349207,7.8958,,S
|
||||
1,3,Salkjelsvik,female,21,0,0,343120,7.65,,S
|
||||
0,3,Rekic,male,38,0,0,349249,7.8958,,S
|
||||
0,1,Porter,male,47,0,0,110465,52,C110,S
|
||||
0,3,Zabour,female,14.5,1,0,2665,14.4542,,C
|
||||
0,3,Barton,male,22,0,0,324669,8.05,,S
|
||||
0,3,Jussila,female,20,1,0,4136,9.825,,S
|
||||
0,3,Attalah,female,17,0,0,2627,14.4583,,C
|
||||
0,3,Pekoniemi,male,21,0,0,STON/O 2. 3101294,7.925,,S
|
||||
0,3,Connors,male,70.5,0,0,370369,7.75,,Q
|
||||
0,2,Turpin,male,29,1,0,11668,21,,S
|
||||
0,1,Baxter,male,24,0,1,PC 17558,247.5208,B58 B60,C
|
||||
0,3,Andersson,female,2,4,2,347082,31.275,,S
|
||||
0,2,Hickman,male,21,2,0,S.O.C. 14879,73.5,,S
|
||||
0,2,Nasser,male,32.5,1,0,237736,30.0708,,C
|
||||
1,2,Webber,female,32.5,0,0,27267,13,E101,S
|
||||
0,1,White,male,54,0,1,35281,77.2875,D26,S
|
||||
1,3,Nicola-Yarred,male,12,1,0,2651,11.2417,,C
|
||||
1,3,Madsen,male,24,0,0,C 17369,7.1417,,S
|
||||
0,3,Ekstrom,male,45,0,0,347061,6.975,,S
|
||||
0,3,Drazenoic,male,33,0,0,349241,7.8958,,C
|
||||
0,3,Coelho,male,20,0,0,SOTON/O.Q. 3101307,7.05,,S
|
||||
0,3,Robins,female,47,1,0,A/5. 3337,14.5,,S
|
||||
1,2,Weisz,female,29,1,0,228414,26,,S
|
||||
0,2,Sobey,male,25,0,0,C.A. 29178,13,,S
|
||||
0,2,Richard,male,23,0,0,SC/PARIS 2133,15.0458,,C
|
||||
1,1,Newsom,female,19,0,2,11752,26.2833,D47,S
|
||||
0,1,Futrelle,male,37,1,0,113803,53.1,C123,S
|
||||
0,3,Osen,male,16,0,0,7534,9.2167,,S
|
||||
0,1,Giglio,male,24,0,0,PC 17593,79.2,B86,C
|
||||
1,3,Nysten,female,22,0,0,347081,7.75,,S
|
||||
1,3,Hakkarainen,female,24,1,0,STON/O2. 3101279,15.85,,S
|
||||
0,3,Burke,male,19,0,0,365222,6.75,,Q
|
||||
0,2,Andrew,male,18,0,0,231945,11.5,,S
|
||||
0,2,Nicholls,male,19,1,1,C.A. 33112,36.75,,S
|
||||
1,3,Andersson,male,27,0,0,350043,7.7958,,S
|
||||
0,3,Ford,female,9,2,2,W./C. 6608,34.375,,S
|
||||
0,2,Navratil,male,36.5,0,2,230080,26,F2,S
|
||||
0,2,Byles,male,42,0,0,244310,13,,S
|
||||
0,2,Bateman,male,51,0,0,S.O.P. 1166,12.525,,S
|
||||
1,1,Pears,female,22,1,0,113776,66.6,C2,S
|
||||
0,3,Meo,male,55.5,0,0,A.5. 11206,8.05,,S
|
||||
0,3,van,male,40.5,0,2,A/5. 851,14.5,,S
|
||||
0,1,Williams,male,51,0,1,PC 17597,61.3792,,C
|
||||
1,3,Gilnagh,female,16,0,0,35851,7.7333,,Q
|
||||
0,3,Corn,male,30,0,0,SOTON/OQ 392090,8.05,,S
|
||||
0,3,Cribb,male,44,0,1,371362,16.1,,S
|
||||
1,2,Watt,female,40,0,0,C.A. 33595,15.75,,S
|
||||
0,3,Bengtsson,male,26,0,0,347068,7.775,,S
|
||||
0,3,Calic,male,17,0,0,315093,8.6625,,S
|
||||
0,3,Panula,male,1,4,1,3101295,39.6875,,S
|
||||
1,3,Goldsmith,male,9,0,2,363291,20.525,,S
|
||||
0,3,Skoog,female,45,1,4,347088,27.9,,S
|
||||
0,3,Ling,male,28,0,0,1601,56.4958,,S
|
||||
0,1,Van,male,61,0,0,111240,33.5,B19,S
|
||||
0,3,Rice,male,4,4,1,382652,29.125,,Q
|
||||
1,3,Johnson,female,1,1,1,347742,11.1333,,S
|
||||
0,3,Sivola,male,21,0,0,STON/O 2. 3101280,7.925,,S
|
||||
0,1,Smith,male,56,0,0,17764,30.6958,A7,C
|
||||
0,3,Klasen,male,18,1,1,350404,7.8542,,S
|
||||
0,1,Isham,female,50,0,0,PC 17595,28.7125,C49,C
|
||||
0,2,Hale,male,30,0,0,250653,13,,S
|
||||
0,3,Leonard,male,36,0,0,LINE,0,,S
|
||||
0,3,Asplund,male,9,4,2,347077,31.3875,,S
|
||||
1,2,Becker,male,1,2,1,230136,39,F4,S
|
||||
1,3,Kink-Heilmann,female,4,0,2,315153,22.025,,S
|
||||
1,1,Romaine,male,45,0,0,111428,26.55,,S
|
||||
0,3,Bourke,male,40,1,1,364849,15.5,,Q
|
||||
0,3,Turcin,male,36,0,0,349247,7.8958,,S
|
||||
1,2,Pinsky,female,32,0,0,234604,13,,S
|
||||
0,2,Carbines,male,19,0,0,28424,13,,S
|
||||
1,3,Andersen-Jensen,female,19,1,0,350046,7.8542,,S
|
||||
1,2,Navratil,male,3,1,1,230080,26,F2,S
|
||||
1,1,Brown,female,44,0,0,PC 17610,27.7208,B4,C
|
||||
1,1,Lurette,female,58,0,0,PC 17569,146.5208,B80,C
|
||||
0,3,Olsen,male,42,0,1,4579,8.4042,,S
|
||||
0,2,Yrois,female,24,0,0,248747,13,,S
|
||||
0,3,Vande,male,28,0,0,345770,9.5,,S
|
||||
0,3,Johanson,male,34,0,0,3101264,6.4958,,S
|
||||
0,3,Youseff,male,45.5,0,0,2628,7.225,,C
|
||||
1,3,Cohen,male,18,0,0,A/5 3540,8.05,,S
|
||||
0,3,Strom,female,2,0,1,347054,10.4625,G6,S
|
||||
0,3,Backstrom,male,32,1,0,3101278,15.85,,S
|
||||
1,3,Albimona,male,26,0,0,2699,18.7875,,C
|
||||
1,3,Carr,female,16,0,0,367231,7.75,,Q
|
||||
1,1,Blank,male,40,0,0,112277,31,A31,C
|
||||
0,3,Ali,male,24,0,0,SOTON/O.Q. 3101311,7.05,,S
|
||||
1,2,Cameron,female,35,0,0,F.C.C. 13528,21,,S
|
||||
0,3,Perkin,male,22,0,0,A/5 21174,7.25,,S
|
||||
0,2,Givard,male,30,0,0,250646,13,,S
|
||||
1,1,Newell,female,31,1,0,35273,113.275,D36,C
|
||||
1,3,Honkanen,female,27,0,0,STON/O2. 3101283,7.925,,S
|
||||
0,2,Jacobsohn,male,42,1,0,243847,27,,S
|
||||
1,1,Bazzani,female,32,0,0,11813,76.2917,D15,C
|
||||
0,2,Harris,male,30,0,0,W/C 14208,10.5,,S
|
||||
1,3,Sunderland,male,16,0,0,SOTON/OQ 392089,8.05,,S
|
||||
0,2,Bracken,male,27,0,0,220367,13,,S
|
||||
0,3,Green,male,51,0,0,21440,8.05,,S
|
||||
1,1,Hoyt,male,38,1,0,19943,90,C93,S
|
||||
0,3,Berglund,male,22,0,0,PP 4348,9.35,,S
|
||||
1,2,Mellors,male,19,0,0,SW/PP 751,10.5,,S
|
||||
0,3,Lovell,male,20.5,0,0,A/5 21173,7.25,,S
|
||||
0,2,Fahlstrom,male,18,0,0,236171,13,,S
|
||||
1,1,Harris,female,35,1,0,36973,83.475,C83,S
|
||||
0,3,Larsson,male,29,0,0,347067,7.775,,S
|
||||
0,2,Sjostedt,male,59,0,0,237442,13.5,,S
|
||||
1,3,Asplund,female,5,4,2,347077,31.3875,,S
|
||||
0,2,Leyson,male,24,0,0,C.A. 29566,10.5,,S
|
||||
0,2,Hold,male,44,1,0,26707,26,,S
|
||||
1,2,Collyer,female,8,0,2,C.A. 31921,26.25,,S
|
||||
0,2,Pengelly,male,19,0,0,28665,10.5,,S
|
||||
0,2,Hunt,male,33,0,0,SCO/W 1585,12.275,,S
|
||||
0,2,Coleridge,male,29,0,0,W./C. 14263,10.5,,S
|
||||
0,3,Maenpaa,male,22,0,0,STON/O 2. 3101275,7.125,,S
|
||||
0,3,Attalah,male,30,0,0,2694,7.225,,C
|
||||
0,1,Minahan,male,44,2,0,19928,90,C78,Q
|
||||
0,3,Lindahl,female,25,0,0,347071,7.775,,S
|
||||
1,2,Hamalainen,female,24,0,2,250649,14.5,,S
|
||||
1,1,Beckwith,male,37,1,1,11751,52.5542,D35,S
|
||||
0,2,Carter,male,54,1,0,244252,26,,S
|
||||
0,3,Strom,female,29,1,1,347054,10.4625,G6,S
|
||||
0,1,Stead,male,62,0,0,113514,26.55,C87,S
|
||||
0,3,Lobb,male,30,1,0,A/5. 3336,16.1,,S
|
||||
0,3,Rosblom,female,41,0,2,370129,20.2125,,S
|
||||
1,3,Touma,female,29,0,2,2650,15.2458,,C
|
||||
1,1,Cherry,female,30,0,0,110152,86.5,B77,S
|
||||
1,1,Ward,female,35,0,0,PC 17755,512.3292,,C
|
||||
1,2,Parrish,female,50,0,1,230433,26,,S
|
||||
1,3,Asplund,male,3,4,2,347077,31.3875,,S
|
||||
0,1,Taussig,male,52,1,1,110413,79.65,E67,S
|
||||
0,1,Harrison,male,40,0,0,112059,0,B94,S
|
||||
0,2,Reeves,male,36,0,0,C.A. 17248,10.5,,S
|
||||
0,3,Panula,male,16,4,1,3101295,39.6875,,S
|
||||
1,3,Persson,male,25,1,0,347083,7.775,,S
|
||||
1,1,Graham,female,58,0,1,PC 17582,153.4625,C125,S
|
||||
1,1,Bissette,female,35,0,0,PC 17760,135.6333,C99,S
|
||||
1,3,Tornquist,male,25,0,0,LINE,0,,S
|
||||
1,2,Mellinger,female,41,0,1,250644,19.5,,S
|
||||
0,1,Natsch,male,37,0,1,PC 17596,29.7,C118,C
|
||||
1,1,Andrews,female,63,1,0,13502,77.9583,D7,S
|
||||
0,3,Lindblom,female,45,0,0,347073,7.75,,S
|
||||
0,3,Rice,male,7,4,1,382652,29.125,,Q
|
||||
1,3,Abbott,female,35,1,1,C.A. 2673,20.25,,S
|
||||
0,3,Duane,male,65,0,0,336439,7.75,,Q
|
||||
0,3,Olsson,male,28,0,0,347464,7.8542,,S
|
||||
0,3,de,male,16,0,0,345778,9.5,,S
|
||||
1,3,Dorking,male,19,0,0,A/5. 10482,8.05,,S
|
||||
0,3,Stankovic,male,33,0,0,349239,8.6625,,C
|
||||
1,3,de,male,30,0,0,345774,9.5,,S
|
||||
0,3,Naidenoff,male,22,0,0,349206,7.8958,,S
|
||||
1,2,Hosono,male,42,0,0,237798,13,,S
|
||||
1,3,Connolly,female,22,0,0,370373,7.75,,Q
|
||||
1,1,Barber,female,26,0,0,19877,78.85,,S
|
||||
1,1,Bishop,female,19,1,0,11967,91.0792,B49,C
|
||||
0,2,Levy,male,36,0,0,SC/Paris 2163,12.875,D,C
|
||||
0,3,Haas,female,24,0,0,349236,8.85,,S
|
||||
0,3,Mineff,male,24,0,0,349233,7.8958,,S
|
||||
0,3,Hanna,male,23.5,0,0,2693,7.2292,,C
|
||||
0,1,Allison,female,2,1,2,113781,151.55,C22 C26,S
|
||||
1,1,Baxter,female,50,0,1,PC 17558,247.5208,B58 B60,C
|
||||
0,3,Johnson,male,19,0,0,LINE,0,,S
|
||||
1,1,Allison,male,0.92,1,2,113781,151.55,C22 C26,S
|
||||
1,1,Penasco,female,17,1,0,PC 17758,108.9,C65,C
|
||||
0,2,Abelson,male,30,1,0,P/PP 3381,24,,C
|
||||
1,1,Francatelli,female,30,0,0,PC 17485,56.9292,E36,C
|
||||
1,1,Hays,female,24,0,0,11767,83.1583,C54,C
|
||||
1,1,Ryerson,female,18,2,2,PC 17608,262.375,B57 B59 B63 B66,C
|
||||
0,2,Lahtinen,female,26,1,1,250651,26,,S
|
||||
0,3,Hendekovic,male,28,0,0,349243,7.8958,,S
|
||||
0,2,Hart,male,43,1,1,F.C.C. 13529,26.25,,S
|
||||
1,3,Nilsson,female,26,0,0,347470,7.8542,,S
|
||||
1,2,Kantor,female,24,1,0,244367,26,,S
|
||||
0,2,Moraweck,male,54,0,0,29011,14,,S
|
||||
1,1,Wick,female,31,0,2,36928,164.8667,C7,S
|
||||
1,1,Spedden,female,40,1,1,16966,134.5,E34,C
|
||||
0,3,Dennis,male,22,0,0,A/5 21172,7.25,,S
|
||||
0,3,Danoff,male,27,0,0,349219,7.8958,,S
|
||||
1,2,Slayter,female,30,0,0,234818,12.35,,Q
|
||||
1,2,Caldwell,female,22,1,1,248738,29,,S
|
||||
1,1,Young,female,36,0,0,PC 17760,135.6333,C32,C
|
||||
0,3,Nysveen,male,61,0,0,345364,6.2375,,S
|
||||
1,2,Ball,female,36,0,0,28551,13,D,S
|
||||
1,3,Goldsmith,female,31,1,1,363291,20.525,,S
|
||||
1,1,Hippach,female,16,0,1,111361,57.9792,B18,C
|
||||
0,1,Partner,male,45.5,0,0,113043,28.5,C124,S
|
||||
0,1,Graham,male,38,0,1,PC 17582,153.4625,C91,S
|
||||
0,3,Vander,male,16,2,0,345764,18,,S
|
||||
0,1,Pears,male,29,1,0,113776,66.6,C2,S
|
||||
1,1,Burns,female,41,0,0,16966,134.5,E40,C
|
||||
1,3,Dahl,male,45,0,0,7598,8.05,,S
|
||||
0,1,Blackwell,male,45,0,0,113784,35.5,T,S
|
||||
1,2,Navratil,male,2,1,1,230080,26,F2,S
|
||||
1,1,Fortune,female,24,3,2,19950,263,C23 C25 C27,S
|
||||
0,2,Collander,male,28,0,0,248740,13,,S
|
||||
0,2,Sedgwick,male,25,0,0,244361,13,,S
|
||||
0,2,Fox,male,36,0,0,229236,13,,S
|
||||
1,2,Brown,female,24,0,0,248733,13,F33,S
|
||||
1,2,Smith,female,40,0,0,31418,13,,S
|
||||
1,3,Coutts,male,3,1,1,C.A. 37671,15.9,,S
|
||||
0,3,Dimic,male,42,0,0,315088,8.6625,,S
|
||||
0,3,Odahl,male,23,0,0,7267,9.225,,S
|
||||
0,3,Elias,male,15,1,1,2695,7.2292,,C
|
||||
0,3,Arnold-Franchi,male,25,1,0,349237,17.8,,S
|
||||
0,3,Vanden,male,28,0,0,345783,9.5,,S
|
||||
1,1,Bowerman,female,22,0,1,113505,55,E33,S
|
||||
0,2,Funk,female,38,0,0,237671,13,,S
|
||||
0,3,Skoog,male,40,1,4,347088,27.9,,S
|
||||
0,2,del,male,29,1,0,SC/PARIS 2167,27.7208,,C
|
||||
0,3,Barbara,female,45,0,1,2691,14.4542,,C
|
||||
0,3,Asim,male,35,0,0,SOTON/O.Q. 3101310,7.05,,S
|
||||
0,3,Adahl,male,30,0,0,C 7076,7.25,,S
|
||||
1,1,Warren,female,60,1,0,110813,75.25,D37,C
|
||||
1,1,Aubart,female,24,0,0,PC 17477,69.3,B35,C
|
||||
1,1,Harder,male,25,1,0,11765,55.4417,E50,C
|
||||
0,3,Wiklund,male,18,1,0,3101267,6.4958,,S
|
||||
0,3,Beavan,male,19,0,0,323951,8.05,,S
|
||||
0,1,Ringhini,male,22,0,0,PC 17760,135.6333,,C
|
||||
0,3,Palsson,female,3,3,1,349909,21.075,,S
|
||||
1,3,Landergren,female,22,0,0,C 7077,7.25,,S
|
||||
0,1,Widener,male,27,0,2,113503,211.5,C82,C
|
||||
0,3,Betros,male,20,0,0,2648,4.0125,,C
|
||||
0,3,Gustafsson,male,19,0,0,347069,7.775,,S
|
||||
1,1,Bidois,female,42,0,0,PC 17757,227.525,,C
|
||||
1,3,Nakid,female,1,0,2,2653,15.7417,,C
|
||||
0,3,Tikkanen,male,32,0,0,STON/O 2. 3101293,7.925,,S
|
||||
1,1,Holverson,female,35,1,0,113789,52,,S
|
||||
0,2,Davies,male,18,0,0,S.O.C. 14879,73.5,,S
|
||||
0,3,Goodwin,male,1,5,2,CA 2144,46.9,,S
|
||||
1,2,Buss,female,36,0,0,27849,13,,S
|
||||
1,2,Lehmann,female,17,0,0,SC 1748,12,,C
|
||||
1,1,Carter,male,36,1,2,113760,120,B96 B98,S
|
||||
1,3,Jansson,male,21,0,0,350034,7.7958,,S
|
||||
0,3,Gustafsson,male,28,2,0,3101277,7.925,,S
|
||||
1,1,Newell,female,23,1,0,35273,113.275,D36,C
|
||||
1,3,Sandstrom,female,24,0,2,PP 9549,16.7,G6,S
|
||||
0,3,Johansson,male,22,0,0,350052,7.7958,,S
|
||||
0,3,Olsson,female,31,0,0,350407,7.8542,,S
|
||||
0,2,McKane,male,46,0,0,28403,26,,S
|
||||
0,2,Pain,male,23,0,0,244278,10.5,,S
|
||||
1,2,Trout,female,28,0,0,240929,12.65,,S
|
||||
1,3,Niskanen,male,39,0,0,STON/O 2. 3101289,7.925,,S
|
||||
0,3,Adams,male,26,0,0,341826,8.05,,S
|
||||
0,3,Jussila,female,21,1,0,4137,9.825,,S
|
||||
0,3,Hakkarainen,male,28,1,0,STON/O2. 3101279,15.85,,S
|
||||
0,3,Oreskovic,female,20,0,0,315096,8.6625,,S
|
||||
0,2,Gale,male,34,1,0,28664,21,,S
|
||||
0,3,Widegren,male,51,0,0,347064,7.75,,S
|
||||
1,2,Richards,male,3,1,1,29106,18.75,,S
|
||||
0,3,Birkeland,male,21,0,0,312992,7.775,,S
|
||||
1,1,Minahan,female,33,1,0,19928,90,C78,Q
|
||||
1,3,Sundman,male,44,0,0,STON/O 2. 3101269,7.925,,S
|
||||
1,2,Drew,female,34,1,1,28220,32.5,,S
|
||||
1,2,Silven,female,18,0,2,250652,13,,S
|
||||
0,2,Matthews,male,30,0,0,28228,13,,S
|
||||
0,3,Van,female,10,0,2,345773,24.15,,S
|
||||
0,3,Charters,male,21,0,0,A/5. 13032,7.7333,,Q
|
||||
0,3,Zimmerman,male,29,0,0,315082,7.875,,S
|
||||
0,3,Danbom,female,28,1,1,347080,14.4,,S
|
||||
0,3,Rosblom,male,18,1,1,370129,20.2125,,S
|
||||
1,2,Clarke,female,28,1,0,2003,26,,S
|
||||
1,2,Phillips,female,19,0,0,250655,26,,S
|
||||
1,3,Pickard,male,32,0,0,SOTON/O.Q. 392078,8.05,E10,S
|
||||
1,1,Bjornstrom-Steffansson,male,28,0,0,110564,26.55,C52,S
|
||||
1,2,Louch,female,42,1,0,SC/AH 3085,26,,S
|
||||
0,3,Kallio,male,17,0,0,STON/O 2. 3101274,7.125,,S
|
||||
0,1,Silvey,male,50,1,0,13507,55.9,E44,S
|
||||
1,1,Carter,female,14,1,2,113760,120,B96 B98,S
|
||||
0,3,Ford,female,21,2,2,W./C. 6608,34.375,,S
|
||||
1,2,Richards,female,24,2,3,29106,18.75,,S
|
||||
0,1,Fortune,male,64,1,4,19950,263,C23 C25 C27,S
|
||||
0,2,Kvillner,male,31,0,0,C.A. 18723,10.5,,S
|
||||
1,2,Hart,female,45,1,1,F.C.C. 13529,26.25,,S
|
||||
0,3,Hampe,male,20,0,0,345769,9.5,,S
|
||||
0,3,Petterson,male,25,1,0,347076,7.775,,S
|
||||
1,2,Reynaldo,female,28,0,0,230434,13,,S
|
||||
1,1,Dodge,male,4,0,2,33638,81.8583,A34,S
|
||||
1,2,Mellinger,female,13,0,1,250644,19.5,,S
|
||||
1,1,Seward,male,34,0,0,113794,26.55,,S
|
||||
1,3,Baclini,female,5,2,1,2666,19.2583,,C
|
||||
1,1,Peuchen,male,52,0,0,113786,30.5,C104,S
|
||||
0,2,West,male,36,1,2,C.A. 34651,27.75,,S
|
||||
0,1,Foreman,male,30,0,0,113051,27.75,C111,C
|
||||
1,1,Goldenberg,male,49,1,0,17453,89.1042,C92,C
|
||||
1,3,Jalsevac,male,29,0,0,349240,7.8958,,C
|
||||
0,1,Millet,male,65,0,0,13509,26.55,E38,S
|
||||
1,2,Toomey,female,50,0,0,F.C.C. 13531,10.5,,S
|
||||
1,1,Anderson,male,48,0,0,19952,26.55,E12,S
|
||||
0,3,Morley,male,34,0,0,364506,8.05,,S
|
||||
0,1,Gee,male,47,0,0,111320,38.5,E63,S
|
||||
0,2,Milling,male,48,0,0,234360,13,,S
|
||||
0,3,Goncalves,male,38,0,0,SOTON/O.Q. 3101306,7.05,,S
|
||||
0,1,Smart,male,56,0,0,113792,26.55,,S
|
||||
1,3,Baclini,female,0.75,2,1,2666,19.2583,,C
|
||||
0,3,Cacic,male,38,0,0,315089,8.6625,,S
|
||||
1,2,West,female,33,1,2,C.A. 34651,27.75,,S
|
||||
1,2,Jerwan,female,23,0,0,SC/AH Basle 541,13.7917,D,C
|
||||
0,3,Strandberg,female,22,0,0,7553,9.8375,,S
|
||||
0,2,Renouf,male,34,1,0,31027,21,,S
|
||||
0,3,Braund,male,29,1,0,3460,7.0458,,S
|
||||
0,3,Karlsson,male,22,0,0,350060,7.5208,,S
|
||||
1,3,Hirvonen,female,2,0,1,3101298,12.2875,,S
|
||||
0,3,Goodwin,male,9,5,2,CA 2144,46.9,,S
|
||||
0,3,Rouse,male,50,0,0,A/5 3594,8.05,,S
|
||||
1,3,Turkula,female,63,0,0,4134,9.5875,,S
|
||||
1,1,Bishop,male,25,1,0,11967,91.0792,B49,C
|
||||
1,1,Hoyt,female,35,1,0,19943,90,C93,S
|
||||
0,1,Kent,male,58,0,0,11771,29.7,B37,C
|
||||
0,3,Somerton,male,30,0,0,A.5. 18509,8.05,,S
|
||||
1,3,Coutts,male,9,1,1,C.A. 37671,15.9,,S
|
||||
0,3,Windelov,male,21,0,0,SOTON/OQ 3101317,7.25,,S
|
||||
0,1,Molson,male,55,0,0,113787,30.5,C30,S
|
||||
0,1,Artagaveytia,male,71,0,0,PC 17609,49.5042,,C
|
||||
0,3,Stanley,male,21,0,0,A/4 45380,8.05,,S
|
||||
1,1,Eustis,female,54,1,0,36947,78.2667,D20,C
|
||||
0,1,Allison,female,25,1,2,113781,151.55,C22 C26,S
|
||||
0,3,Svensson,male,24,0,0,350035,7.7958,,S
|
||||
0,3,Calic,male,17,0,0,315086,8.6625,,S
|
||||
0,3,Canavan,female,21,0,0,364846,7.75,,Q
|
||||
0,3,Laitinen,female,37,0,0,4135,9.5875,,S
|
||||
1,1,Maioni,female,16,0,0,110152,86.5,B79,S
|
||||
0,1,Penasco,male,18,1,0,PC 17758,108.9,C65,C
|
||||
1,2,Quick,female,33,0,2,26360,26,,S
|
||||
0,3,Olsen,male,28,0,0,C 4001,22.525,,S
|
||||
1,3,Lang,male,26,0,0,1601,56.4958,,S
|
||||
1,3,Daly,male,29,0,0,382651,7.75,,Q
|
||||
1,1,McGough,male,36,0,0,PC 17473,26.2875,E25,S
|
||||
1,1,Rothschild,female,54,1,0,PC 17603,59.4,,C
|
||||
0,3,Coleff,male,24,0,0,349209,7.4958,,S
|
||||
0,1,Walker,male,47,0,0,36967,34.0208,D46,S
|
||||
1,2,Lemore,female,34,0,0,C.A. 34260,10.5,F33,S
|
||||
1,2,Angle,female,36,1,0,226875,26,,S
|
||||
0,3,Pavlovic,male,32,0,0,349242,7.8958,,S
|
||||
1,1,Perreault,female,30,0,0,12749,93.5,B73,S
|
||||
0,3,Vovk,male,22,0,0,349252,7.8958,,S
|
||||
1,1,Hippach,female,44,0,1,111361,57.9792,B18,C
|
||||
0,3,Farrell,male,40.5,0,0,367232,7.75,,Q
|
||||
1,2,Ridsdale,female,50,0,0,W./C. 14258,10.5,,S
|
||||
0,3,Salonen,male,39,0,0,3101296,7.925,,S
|
||||
0,2,Hocking,male,23,2,1,29104,11.5,,S
|
||||
1,2,Quick,female,2,1,1,26360,26,,S
|
||||
0,3,Elias,male,17,1,1,2690,7.2292,,C
|
||||
0,3,Cacic,female,30,0,0,315084,8.6625,,S
|
||||
1,2,Hart,female,7,0,2,F.C.C. 13529,26.25,,S
|
||||
0,1,Butt,male,45,0,0,113050,26.55,B38,S
|
||||
1,1,LeRoy,female,30,0,0,PC 17761,106.425,,C
|
||||
1,1,Frolicher,female,22,0,2,13568,49.5,B39,C
|
||||
1,1,Crosby,female,36,0,2,WE/P 5735,71,B22,S
|
||||
0,3,Andersson,female,9,4,2,347082,31.275,,S
|
||||
0,3,Andersson,female,11,4,2,347082,31.275,,S
|
||||
1,2,Beane,male,32,1,0,2908,26,,S
|
||||
0,1,Douglas,male,50,1,0,PC 17761,106.425,C86,C
|
||||
0,1,Nicholson,male,64,0,0,693,26,,S
|
||||
1,2,Beane,female,19,1,0,2908,26,,S
|
||||
0,3,Goldsmith,male,33,1,1,363291,20.525,,S
|
||||
1,2,Davies,male,8,1,1,C.A. 33112,36.75,,S
|
||||
1,1,Thayer,male,17,0,2,17421,110.8833,C70,C
|
||||
0,2,Sharp,male,27,0,0,244358,26,,S
|
||||
1,3,Leeni,male,22,0,0,2620,7.225,,C
|
||||
1,3,Ohman,female,22,0,0,347085,7.775,,S
|
||||
0,1,Wright,male,62,0,0,113807,26.55,,S
|
||||
1,1,Duff,female,48,1,0,11755,39.6,A16,C
|
||||
1,1,Taussig,female,39,1,1,110413,79.65,E67,S
|
||||
1,3,de,female,36,1,0,345572,17.4,,S
|
||||
0,3,Sivic,male,40,0,0,349251,7.8958,,S
|
||||
0,2,Norman,male,28,0,0,218629,13.5,,S
|
||||
0,3,Davies,male,24,2,0,A/4 48871,24.15,,S
|
||||
0,3,Stoytcheff,male,19,0,0,349205,7.8958,,S
|
||||
0,3,Palsson,female,29,0,4,349909,21.075,,S
|
||||
1,3,Jonsson,male,32,0,0,350417,7.8542,,S
|
||||
1,2,Harris,male,62,0,0,S.W./PP 752,10.5,,S
|
||||
1,1,Appleton,female,53,2,0,11769,51.4792,C101,S
|
||||
1,1,Flynn,male,36,0,0,PC 17474,26.3875,E25,S
|
||||
0,3,Rush,male,16,0,0,A/4. 20589,8.05,,S
|
||||
0,3,Patchett,male,19,0,0,358585,14.5,,S
|
||||
1,2,Garside,female,34,0,0,243880,13,,S
|
||||
1,1,Silvey,female,39,1,0,13507,55.9,E44,S
|
||||
1,3,Jussila,male,32,0,0,STON/O 2. 3101286,7.925,,S
|
||||
1,2,Christy,female,25,1,1,237789,30,,S
|
||||
1,1,Thayer,female,39,1,1,17421,110.8833,C68,C
|
||||
0,2,Downton,male,54,0,0,28403,26,,S
|
||||
0,1,Ross,male,36,0,0,13049,40.125,A10,C
|
||||
1,1,Taussig,female,18,0,2,110413,79.65,E68,S
|
||||
0,2,Jarvis,male,47,0,0,237565,15,,S
|
||||
1,1,Frolicher-Stehli,male,60,1,1,13567,79.2,B41,C
|
||||
0,3,Gilinski,male,22,0,0,14973,8.05,,S
|
||||
0,3,Rintamaki,male,35,0,0,STON/O 2. 3101273,7.125,,S
|
||||
1,1,Stephenson,female,52,1,0,36947,78.2667,D20,C
|
||||
0,3,Elsbury,male,47,0,0,A/5 3902,7.25,,S
|
||||
0,2,Chapman,male,37,1,0,SC/AH 29037,26,,S
|
||||
0,3,Van,male,36,1,1,345773,24.15,,S
|
||||
0,3,Johnson,male,49,0,0,LINE,0,,S
|
||||
1,1,Duff,male,49,1,0,PC 17485,56.9292,A20,C
|
||||
1,2,Jacobsohn,female,24,2,1,243847,27,,S
|
||||
0,3,Torber,male,44,0,0,364511,8.05,,S
|
||||
1,1,Homer,male,35,0,0,111426,26.55,,C
|
||||
0,3,Lindell,male,36,1,0,349910,15.55,,S
|
||||
0,3,Karaic,male,30,0,0,349246,7.8958,,S
|
||||
1,1,Daniel,male,27,0,0,113804,30.5,,S
|
||||
1,2,Laroche,female,22,1,2,SC/Paris 2123,41.5792,,C
|
||||
1,1,Shutes,female,40,0,0,PC 17582,153.4625,C125,S
|
||||
0,3,Andersson,female,39,1,5,347082,31.275,,S
|
||||
0,3,Brocklebank,male,35,0,0,364512,8.05,,S
|
||||
1,2,Herman,female,24,1,2,220845,65,,S
|
||||
0,3,Danbom,male,34,1,1,347080,14.4,,S
|
||||
0,3,Lobb,female,26,1,0,A/5. 3336,16.1,,S
|
||||
1,2,Becker,female,4,2,1,230136,39,F4,S
|
||||
0,2,Gavey,male,26,0,0,31028,10.5,,S
|
||||
0,3,Yasbeck,male,27,1,0,2659,14.4542,,C
|
||||
1,1,Kimball,male,42,1,0,11753,52.5542,D19,S
|
||||
1,3,Nakid,male,20,1,1,2653,15.7417,,C
|
||||
0,3,Hansen,male,21,0,0,350029,7.8542,,S
|
||||
0,3,Bowen,male,21,0,0,54636,16.1,,S
|
||||
0,1,Sutton,male,61,0,0,36963,32.3208,D50,S
|
||||
0,2,Kirkland,male,57,0,0,219533,12.35,,Q
|
||||
1,1,Longley,female,21,0,0,13502,77.9583,D9,S
|
||||
0,3,Bostandyeff,male,26,0,0,349224,7.8958,,S
|
||||
1,1,Barkworth,male,80,0,0,27042,30,A23,S
|
||||
0,3,Lundahl,male,51,0,0,347743,7.0542,,S
|
||||
1,1,Stahelin-Maeglin,male,32,0,0,13214,30.5,B50,C
|
||||
0,3,Skoog,female,9,3,2,347088,27.9,,S
|
||||
1,2,Davis,female,28,0,0,237668,13,,S
|
||||
0,3,Leinonen,male,32,0,0,STON/O 2. 3101292,7.925,,S
|
||||
0,2,Collyer,male,31,1,1,C.A. 31921,26.25,,S
|
||||
0,3,Panula,female,41,0,5,3101295,39.6875,,S
|
||||
0,3,Jensen,male,20,0,0,350050,7.8542,,S
|
||||
1,1,Sagesser,female,24,0,0,PC 17477,69.3,B35,C
|
||||
0,3,Skoog,female,2,3,2,347088,27.9,,S
|
||||
1,3,Baclini,female,0.75,2,1,2666,19.2583,,C
|
||||
1,1,Harper,male,48,1,0,PC 17572,76.7292,D33,C
|
||||
0,3,Cor,male,19,0,0,349231,7.8958,,S
|
||||
1,1,Simonius-Blumer,male,56,0,0,13213,35.5,A26,C
|
||||
1,3,Stanley,female,23,0,0,CA. 2314,7.55,,S
|
||||
1,2,Doling,female,18,0,1,231919,23,,S
|
||||
0,3,Kalvik,male,21,0,0,8475,8.4333,,S
|
||||
0,3,Hegarty,female,18,0,0,365226,6.75,,Q
|
||||
0,2,Hickman,male,24,2,0,S.O.C. 14879,73.5,,S
|
||||
0,3,Bourke,female,32,1,1,364849,15.5,,Q
|
||||
0,2,Eitemiller,male,23,0,0,29751,13,,S
|
||||
0,1,Newell,male,58,0,2,35273,113.275,D48,C
|
||||
1,1,Frauenthal,male,50,2,0,PC 17611,133.65,,S
|
||||
0,3,Badt,male,40,0,0,2623,7.225,,C
|
||||
0,1,Colley,male,47,0,0,5727,25.5875,E58,S
|
||||
0,3,Coleff,male,36,0,0,349210,7.4958,,S
|
||||
1,3,Lindqvist,male,20,1,0,STON/O 2. 3101285,7.925,,S
|
||||
0,2,Hickman,male,32,2,0,S.O.C. 14879,73.5,,S
|
||||
0,2,Butler,male,25,0,0,234686,13,,S
|
||||
0,3,Cook,male,43,0,0,A/5 3536,8.05,,S
|
||||
1,2,Brown,female,40,1,1,29750,39,,S
|
||||
0,1,Davidson,male,31,1,0,F.C. 12750,52,B71,S
|
||||
0,2,Mitchell,male,70,0,0,C.A. 24580,10.5,,S
|
||||
1,2,Wilhelms,male,31,0,0,244270,13,,S
|
||||
0,3,Edvardsson,male,18,0,0,349912,7.775,,S
|
||||
0,3,Sawyer,male,24.5,0,0,342826,8.05,,S
|
||||
1,3,Turja,female,18,0,0,4138,9.8417,,S
|
||||
0,3,Goodwin,female,43,1,6,CA 2144,46.9,,S
|
||||
1,1,Cardeza,male,36,0,1,PC 17755,512.3292,B51 B53 B55,C
|
||||
1,1,Hassab,male,27,0,0,PC 17572,76.7292,D49,C
|
||||
0,3,Olsvigen,male,20,0,0,6563,9.225,,S
|
||||
0,3,Goodwin,male,14,5,2,CA 2144,46.9,,S
|
||||
0,2,Brown,male,60,1,1,29750,39,,S
|
||||
0,2,Laroche,male,25,1,2,SC/Paris 2123,41.5792,,C
|
||||
0,3,Panula,male,14,4,1,3101295,39.6875,,S
|
||||
0,3,Dakic,male,19,0,0,349228,10.1708,,S
|
||||
0,3,Fischer,male,18,0,0,350036,7.7958,,S
|
||||
1,1,Madill,female,15,0,1,24160,211.3375,B5,S
|
||||
1,1,Dick,male,31,1,0,17474,57,B20,S
|
||||
1,3,Karun,female,4,0,1,349256,13.4167,,C
|
||||
0,3,Saad,male,25,0,0,2672,7.225,,C
|
||||
0,1,Weir,male,60,0,0,113800,26.55,,S
|
||||
0,2,Chapman,male,52,0,0,248731,13.5,,S
|
||||
0,3,Kelly,male,44,0,0,363592,8.05,,S
|
||||
0,1,Thayer,male,49,1,1,17421,110.8833,C68,C
|
||||
0,3,Humblen,male,42,0,0,348121,7.65,F G63,S
|
||||
1,1,Astor,female,18,1,0,PC 17757,227.525,C62 C64,C
|
||||
1,1,Silverthorne,male,35,0,0,PC 17475,26.2875,E24,S
|
||||
0,3,Barbara,female,18,0,1,2691,14.4542,,C
|
||||
0,3,Gallagher,male,25,0,0,36864,7.7417,,Q
|
||||
0,3,Hansen,male,26,1,0,350025,7.8542,,S
|
||||
0,2,Morley,male,39,0,0,250655,26,,S
|
||||
1,2,Kelly,female,45,0,0,223596,13.5,,S
|
||||
1,1,Calderhead,male,42,0,0,PC 17476,26.2875,E24,S
|
||||
1,1,Cleaver,female,22,0,0,113781,151.55,,S
|
||||
1,1,Mayne,female,24,0,0,PC 17482,49.5042,C90,C
|
||||
1,1,Taylor,male,48,1,0,19996,52,C126,S
|
||||
0,3,Larsson,male,29,0,0,7545,9.4833,,S
|
||||
0,2,Greenberg,male,52,0,0,250647,13,,S
|
||||
0,3,Soholt,male,19,0,0,348124,7.65,F G73,S
|
||||
1,1,Endres,female,38,0,0,PC 17757,227.525,C45,C
|
||||
1,2,Troutt,female,27,0,0,34218,10.5,E101,S
|
||||
0,3,Johnson,male,33,0,0,347062,7.775,,S
|
||||
1,2,Harper,female,6,0,1,248727,33,,S
|
||||
0,3,Jensen,male,17,1,0,350048,7.0542,,S
|
||||
0,2,Gillespie,male,34,0,0,12233,13,,S
|
||||
0,2,Hodges,male,50,0,0,250643,13,,S
|
||||
1,1,Chambers,male,27,1,0,113806,53.1,E8,S
|
||||
0,3,Oreskovic,male,20,0,0,315094,8.6625,,S
|
||||
1,2,Renouf,female,30,3,0,31027,21,,S
|
||||
0,2,Bryhl,male,25,1,0,236853,26,,S
|
||||
0,3,Ilmakangas,female,25,1,0,STON/O2. 3101271,7.925,,S
|
||||
1,1,Allen,female,29,0,0,24160,211.3375,B5,S
|
||||
0,3,Hassan,male,11,0,0,2699,18.7875,,C
|
||||
0,2,Berriman,male,23,0,0,28425,13,,S
|
||||
0,2,Troupiansky,male,23,0,0,233639,13,,S
|
||||
0,3,Williams,male,28.5,0,0,54636,16.1,,S
|
||||
0,3,Ford,female,48,1,3,W./C. 6608,34.375,,S
|
||||
1,1,Lesurer,male,35,0,0,PC 17755,512.3292,B101,C
|
||||
0,1,Cavendish,male,36,1,0,19877,78.85,C46,S
|
||||
1,1,Ryerson,female,21,2,2,PC 17608,262.375,B57 B59 B63 B66,C
|
||||
0,3,McNamee,male,24,1,0,376566,16.1,,S
|
||||
1,3,Stranden,male,31,0,0,STON/O 2. 3101288,7.925,,S
|
||||
0,1,Crosby,male,70,1,1,WE/P 5735,71,B22,S
|
||||
0,3,Abbott,male,16,1,1,C.A. 2673,20.25,,S
|
||||
1,2,Sinkkonen,female,30,0,0,250648,13,,S
|
||||
0,1,Marvin,male,19,1,0,113773,53.1,D30,S
|
||||
0,3,Connaghton,male,31,0,0,335097,7.75,,Q
|
||||
1,2,Wells,female,4,1,1,29103,23,,S
|
||||
1,3,Moor,male,6,0,1,392096,12.475,E121,S
|
||||
0,3,Vande,male,33,0,0,345780,9.5,,S
|
||||
0,3,Jonkoff,male,23,0,0,349204,7.8958,,S
|
||||
1,2,Herman,female,48,1,2,220845,65,,S
|
||||
1,2,Hamalainen,male,0.67,1,1,250649,14.5,,S
|
||||
0,3,Carlsson,male,28,0,0,350042,7.7958,,S
|
||||
0,2,Bailey,male,18,0,0,29108,11.5,,S
|
||||
0,3,Theobald,male,34,0,0,363294,8.05,,S
|
||||
1,1,Rothes,female,33,0,0,110152,86.5,B77,S
|
||||
0,3,Nirva,male,41,0,0,SOTON/O2 3101272,7.125,,S
|
||||
1,3,Barah,male,20,0,0,2663,7.2292,,C
|
||||
1,1,Carter,female,36,1,2,113760,120,B96 B98,S
|
||||
0,3,Eklund,male,16,0,0,347074,7.775,,S
|
||||
1,1,Hogeboom,female,51,1,0,13502,77.9583,D11,S
|
||||
0,3,Mangan,female,30.5,0,0,364850,7.75,,Q
|
||||
0,3,Gronnestad,male,32,0,0,8471,8.3625,,S
|
||||
0,3,Lievens,male,24,0,0,345781,9.5,,S
|
||||
0,3,Jensen,male,48,0,0,350047,7.8542,,S
|
||||
0,2,Mack,female,57,0,0,S.O./P.P. 3,10.5,E77,S
|
||||
1,2,Hocking,female,54,1,3,29105,23,,S
|
||||
0,3,Myhrman,male,18,0,0,347078,7.75,,S
|
||||
1,3,Emanuel,female,5,0,0,364516,12.475,,S
|
||||
1,1,Robert,female,43,0,1,24160,211.3375,B3,S
|
||||
1,3,Ayoub,female,13,0,0,2687,7.2292,,C
|
||||
1,1,Dick,female,17,1,0,17474,57,B20,S
|
||||
0,1,Long,male,29,0,0,113501,30,D6,S
|
||||
0,3,Ali,male,25,0,0,SOTON/O.Q. 3101312,7.05,,S
|
||||
0,3,Harmer,male,25,0,0,374887,7.25,,S
|
||||
1,3,Sjoblom,female,18,0,0,3101265,7.4958,,S
|
||||
0,3,Rice,male,8,4,1,382652,29.125,,Q
|
||||
1,3,Dean,male,1,1,2,C.A. 2315,20.575,,S
|
||||
0,1,Guggenheim,male,46,0,0,PC 17593,79.2,B82 B84,C
|
||||
0,2,Gaskell,male,16,0,0,239865,26,,S
|
||||
0,3,Dantcheff,male,25,0,0,349203,7.8958,,S
|
||||
0,2,Otter,male,39,0,0,28213,13,,S
|
||||
1,1,Leader,female,49,0,0,17465,25.9292,D17,S
|
||||
1,3,Osman,female,31,0,0,349244,8.6833,,S
|
||||
0,3,Ibrahim,male,30,0,0,2685,7.2292,,C
|
||||
0,3,Van,female,30,1,1,345773,24.15,,S
|
||||
0,2,Ponesell,male,34,0,0,250647,13,,S
|
||||
1,2,Collyer,female,31,1,1,C.A. 31921,26.25,,S
|
||||
1,1,Carter,male,11,1,2,113760,120,B96 B98,S
|
||||
1,3,Thomas,male,0.42,0,1,2625,8.5167,,C
|
||||
1,3,Hedman,male,27,0,0,347089,6.975,,S
|
||||
0,3,Johansson,male,31,0,0,347063,7.775,,S
|
||||
0,1,Andrews,male,39,0,0,112050,0,A36,S
|
||||
0,3,Pettersson,female,18,0,0,347087,7.775,,S
|
||||
0,2,Meyer,male,39,0,0,248723,13,,S
|
||||
1,1,Chambers,female,33,1,0,113806,53.1,E8,S
|
||||
0,3,Alexander,male,26,0,0,3474,7.8875,,S
|
||||
0,3,Lester,male,39,0,0,A/4 48871,24.15,,S
|
||||
0,2,Slemen,male,35,0,0,28206,10.5,,S
|
||||
0,3,Andersson,female,6,4,2,347082,31.275,,S
|
||||
0,3,Tomlin,male,30.5,0,0,364499,8.05,,S
|
||||
0,3,Heininen,female,23,0,0,STON/O2. 3101290,7.925,,S
|
||||
0,2,Mallet,male,31,1,1,S.C./PARIS 2079,37.0042,,C
|
||||
0,3,Holm,male,43,0,0,C 7075,6.45,,S
|
||||
0,3,Skoog,male,10,3,2,347088,27.9,,S
|
||||
1,1,Hays,female,52,1,1,12749,93.5,B69,S
|
||||
1,3,Lulic,male,27,0,0,315098,8.6625,,S
|
||||
0,1,Reuchlin,male,38,0,0,19972,0,,S
|
||||
1,3,Moor,female,27,0,1,392096,12.475,E121,S
|
||||
0,3,Panula,male,2,4,1,3101295,39.6875,,S
|
||||
1,2,Mallet,male,1,0,2,S.C./PARIS 2079,37.0042,,C
|
||||
1,1,Stone,female,62,0,0,113572,80,B28,
|
||||
1,3,Yasbeck,female,15,1,0,2659,14.4542,,C
|
||||
1,2,Richards,male,0.83,1,1,29106,18.75,,S
|
||||
0,3,Augustsson,male,23,0,0,347468,7.8542,,S
|
||||
0,3,Allum,male,18,0,0,2223,8.3,,S
|
||||
1,1,Compton,female,39,1,1,PC 17756,83.1583,E49,C
|
||||
0,3,Pasic,male,21,0,0,315097,8.6625,,S
|
||||
1,3,Chip,male,32,0,0,1601,56.4958,,S
|
||||
0,3,Alhomaki,male,20,0,0,SOTON/O2 3101287,7.925,,S
|
||||
0,2,Mudd,male,16,0,0,S.O./P.P. 3,10.5,,S
|
||||
1,1,Serepeca,female,30,0,0,113798,31,,C
|
||||
0,3,Lemberopolous,male,34.5,0,0,2683,6.4375,,C
|
||||
0,3,Culumovic,male,17,0,0,315090,8.6625,,S
|
||||
0,3,Abbing,male,42,0,0,C.A. 5547,7.55,,S
|
||||
0,3,Markoff,male,35,0,0,349213,7.8958,,C
|
||||
0,2,Harper,male,28,0,1,248727,33,,S
|
||||
0,3,Andersson,male,4,4,2,347082,31.275,,S
|
||||
0,3,Svensson,male,74,0,0,347060,7.775,,S
|
||||
0,3,Boulos,female,9,1,1,2678,15.2458,,C
|
||||
1,1,Lines,female,16,0,1,PC 17592,39.4,D28,S
|
||||
0,2,Carter,female,44,1,0,244252,26,,S
|
||||
1,3,Aks,female,18,0,1,392091,9.35,,S
|
||||
1,1,Wick,female,45,1,1,36928,164.8667,,S
|
||||
1,1,Daly,male,51,0,0,113055,26.55,E17,S
|
||||
1,3,Baclini,female,24,0,3,2666,19.2583,,C
|
||||
0,3,Hansen,male,41,2,0,350026,14.1083,,S
|
||||
0,2,Giles,male,21,1,0,28134,11.5,,S
|
||||
1,1,Swift,female,48,0,0,17466,25.9292,D17,S
|
||||
0,2,Gill,male,24,0,0,233866,13,,S
|
||||
1,2,Bystrom,female,42,0,0,236852,13,,S
|
||||
1,2,Duran,female,27,1,0,SC/PARIS 2149,13.8583,,C
|
||||
0,1,Roebling,male,31,0,0,PC 17590,50.4958,A24,S
|
||||
1,3,Johnson,male,4,1,1,347742,11.1333,,S
|
||||
0,3,Balkic,male,26,0,0,349248,7.8958,,S
|
||||
1,1,Beckwith,female,47,1,1,11751,52.5542,D35,S
|
||||
0,1,Carlsson,male,33,0,0,695,5,B51 B53 B55,S
|
||||
0,3,Vander,male,47,0,0,345765,9,,S
|
||||
1,2,Abelson,female,28,1,0,P/PP 3381,24,,C
|
||||
1,3,Najib,female,15,0,0,2667,7.225,,C
|
||||
0,3,Gustafsson,male,20,0,0,7534,9.8458,,S
|
||||
0,3,Petroff,male,19,0,0,349212,7.8958,,S
|
||||
1,1,Potter,female,56,0,1,11767,83.1583,C50,C
|
||||
1,2,Shelley,female,25,0,1,230433,26,,S
|
||||
0,3,Markun,male,33,0,0,349257,7.8958,,S
|
||||
0,3,Dahlberg,female,22,0,0,7552,10.5167,,S
|
||||
0,2,Banfield,male,28,0,0,C.A./SOTON 34068,10.5,,S
|
||||
0,3,Sutehall,male,25,0,0,SOTON/OQ 392076,7.05,,S
|
||||
0,3,Rice,female,39,0,5,382652,29.125,,Q
|
||||
0,2,Montvila,male,27,0,0,211536,13,,S
|
||||
1,1,Graham,female,19,0,0,112053,30,B42,S
|
||||
1,1,Behr,male,26,0,0,111369,30,C148,C
|
||||
0,3,Dooley,male,32,0,0,370376,7.75,,Q
|
||||
|
@@ -1,24 +0,0 @@
|
||||
import { SimpleDirectoryReader } from "llamaindex";
|
||||
|
||||
function callback(
|
||||
category: string,
|
||||
name: string,
|
||||
status: any,
|
||||
message?: string,
|
||||
): boolean {
|
||||
console.log(category, name, status, message);
|
||||
if (name.endsWith(".pdf")) {
|
||||
console.log("I DON'T WANT PDF FILES!");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
// Load page
|
||||
const reader = new SimpleDirectoryReader(callback);
|
||||
const params = { directoryPath: "./data" };
|
||||
await reader.loadData(params);
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -1,353 +0,0 @@
|
||||
const essay = `What I Worked On
|
||||
|
||||
February 2021
|
||||
|
||||
Before college the two main things I worked on, outside of school, were writing and programming. I didn't write essays. I wrote what beginning writers were supposed to write then, and probably still are: short stories. My stories were awful. They had hardly any plot, just characters with strong feelings, which I imagined made them deep.
|
||||
|
||||
The first programs I tried writing were on the IBM 1401 that our school district used for what was then called "data processing." This was in 9th grade, so I was 13 or 14. The school district's 1401 happened to be in the basement of our junior high school, and my friend Rich Draves and I got permission to use it. It was like a mini Bond villain's lair down there, with all these alien-looking machines — CPU, disk drives, printer, card reader — sitting up on a raised floor under bright fluorescent lights.
|
||||
|
||||
The language we used was an early version of Fortran. You had to type programs on punch cards, then stack them in the card reader and press a button to load the program into memory and run it. The result would ordinarily be to print something on the spectacularly loud printer.
|
||||
|
||||
I was puzzled by the 1401. I couldn't figure out what to do with it. And in retrospect there's not much I could have done with it. The only form of input to programs was data stored on punched cards, and I didn't have any data stored on punched cards. The only other option was to do things that didn't rely on any input, like calculate approximations of pi, but I didn't know enough math to do anything interesting of that type. So I'm not surprised I can't remember any programs I wrote, because they can't have done much. My clearest memory is of the moment I learned it was possible for programs not to terminate, when one of mine didn't. On a machine without time-sharing, this was a social as well as a technical error, as the data center manager's expression made clear.
|
||||
|
||||
With microcomputers, everything changed. Now you could have a computer sitting right in front of you, on a desk, that could respond to your keystrokes as it was running instead of just churning through a stack of punch cards and then stopping. [1]
|
||||
|
||||
The first of my friends to get a microcomputer built it himself. It was sold as a kit by Heathkit. I remember vividly how impressed and envious I felt watching him sitting in front of it, typing programs right into the computer.
|
||||
|
||||
Computers were expensive in those days and it took me years of nagging before I convinced my father to buy one, a TRS-80, in about 1980. The gold standard then was the Apple II, but a TRS-80 was good enough. This was when I really started programming. I wrote simple games, a program to predict how high my model rockets would fly, and a word processor that my father used to write at least one book. There was only room in memory for about 2 pages of text, so he'd write 2 pages at a time and then print them out, but it was a lot better than a typewriter.
|
||||
|
||||
Though I liked programming, I didn't plan to study it in college. In college I was going to study philosophy, which sounded much more powerful. It seemed, to my naive high school self, to be the study of the ultimate truths, compared to which the things studied in other fields would be mere domain knowledge. What I discovered when I got to college was that the other fields took up so much of the space of ideas that there wasn't much left for these supposed ultimate truths. All that seemed left for philosophy were edge cases that people in other fields felt could safely be ignored.
|
||||
|
||||
I couldn't have put this into words when I was 18. All I knew at the time was that I kept taking philosophy courses and they kept being boring. So I decided to switch to AI.
|
||||
|
||||
AI was in the air in the mid 1980s, but there were two things especially that made me want to work on it: a novel by Heinlein called The Moon is a Harsh Mistress, which featured an intelligent computer called Mike, and a PBS documentary that showed Terry Winograd using SHRDLU. I haven't tried rereading The Moon is a Harsh Mistress, so I don't know how well it has aged, but when I read it I was drawn entirely into its world. It seemed only a matter of time before we'd have Mike, and when I saw Winograd using SHRDLU, it seemed like that time would be a few years at most. All you had to do was teach SHRDLU more words.
|
||||
|
||||
There weren't any classes in AI at Cornell then, not even graduate classes, so I started trying to teach myself. Which meant learning Lisp, since in those days Lisp was regarded as the language of AI. The commonly used programming languages then were pretty primitive, and programmers' ideas correspondingly so. The default language at Cornell was a Pascal-like language called PL/I, and the situation was similar elsewhere. Learning Lisp expanded my concept of a program so fast that it was years before I started to have a sense of where the new limits were. This was more like it; this was what I had expected college to do. It wasn't happening in a class, like it was supposed to, but that was ok. For the next couple years I was on a roll. I knew what I was going to do.
|
||||
|
||||
For my undergraduate thesis, I reverse-engineered SHRDLU. My God did I love working on that program. It was a pleasing bit of code, but what made it even more exciting was my belief — hard to imagine now, but not unique in 1985 — that it was already climbing the lower slopes of intelligence.
|
||||
|
||||
I had gotten into a program at Cornell that didn't make you choose a major. You could take whatever classes you liked, and choose whatever you liked to put on your degree. I of course chose "Artificial Intelligence." When I got the actual physical diploma, I was dismayed to find that the quotes had been included, which made them read as scare-quotes. At the time this bothered me, but now it seems amusingly accurate, for reasons I was about to discover.
|
||||
|
||||
I applied to 3 grad schools: MIT and Yale, which were renowned for AI at the time, and Harvard, which I'd visited because Rich Draves went there, and was also home to Bill Woods, who'd invented the type of parser I used in my SHRDLU clone. Only Harvard accepted me, so that was where I went.
|
||||
|
||||
I don't remember the moment it happened, or if there even was a specific moment, but during the first year of grad school I realized that AI, as practiced at the time, was a hoax. By which I mean the sort of AI in which a program that's told "the dog is sitting on the chair" translates this into some formal representation and adds it to the list of things it knows.
|
||||
|
||||
What these programs really showed was that there's a subset of natural language that's a formal language. But a very proper subset. It was clear that there was an unbridgeable gap between what they could do and actually understanding natural language. It was not, in fact, simply a matter of teaching SHRDLU more words. That whole way of doing AI, with explicit data structures representing concepts, was not going to work. Its brokenness did, as so often happens, generate a lot of opportunities to write papers about various band-aids that could be applied to it, but it was never going to get us Mike.
|
||||
|
||||
So I looked around to see what I could salvage from the wreckage of my plans, and there was Lisp. I knew from experience that Lisp was interesting for its own sake and not just for its association with AI, even though that was the main reason people cared about it at the time. So I decided to focus on Lisp. In fact, I decided to write a book about Lisp hacking. It's scary to think how little I knew about Lisp hacking when I started writing that book. But there's nothing like writing a book about something to help you learn it. The book, On Lisp, wasn't published till 1993, but I wrote much of it in grad school.
|
||||
|
||||
Computer Science is an uneasy alliance between two halves, theory and systems. The theory people prove things, and the systems people build things. I wanted to build things. I had plenty of respect for theory — indeed, a sneaking suspicion that it was the more admirable of the two halves — but building things seemed so much more exciting.
|
||||
|
||||
The problem with systems work, though, was that it didn't last. Any program you wrote today, no matter how good, would be obsolete in a couple decades at best. People might mention your software in footnotes, but no one would actually use it. And indeed, it would seem very feeble work. Only people with a sense of the history of the field would even realize that, in its time, it had been good.
|
||||
|
||||
There were some surplus Xerox Dandelions floating around the computer lab at one point. Anyone who wanted one to play around with could have one. I was briefly tempted, but they were so slow by present standards; what was the point? No one else wanted one either, so off they went. That was what happened to systems work.
|
||||
|
||||
I wanted not just to build things, but to build things that would last.
|
||||
|
||||
In this dissatisfied state I went in 1988 to visit Rich Draves at CMU, where he was in grad school. One day I went to visit the Carnegie Institute, where I'd spent a lot of time as a kid. While looking at a painting there I realized something that might seem obvious, but was a big surprise to me. There, right on the wall, was something you could make that would last. Paintings didn't become obsolete. Some of the best ones were hundreds of years old.
|
||||
|
||||
And moreover this was something you could make a living doing. Not as easily as you could by writing software, of course, but I thought if you were really industrious and lived really cheaply, it had to be possible to make enough to survive. And as an artist you could be truly independent. You wouldn't have a boss, or even need to get research funding.
|
||||
|
||||
I had always liked looking at paintings. Could I make them? I had no idea. I'd never imagined it was even possible. I knew intellectually that people made art — that it didn't just appear spontaneously — but it was as if the people who made it were a different species. They either lived long ago or were mysterious geniuses doing strange things in profiles in Life magazine. The idea of actually being able to make art, to put that verb before that noun, seemed almost miraculous.
|
||||
|
||||
That fall I started taking art classes at Harvard. Grad students could take classes in any department, and my advisor, Tom Cheatham, was very easy going. If he even knew about the strange classes I was taking, he never said anything.
|
||||
|
||||
So now I was in a PhD program in computer science, yet planning to be an artist, yet also genuinely in love with Lisp hacking and working away at On Lisp. In other words, like many a grad student, I was working energetically on multiple projects that were not my thesis.
|
||||
|
||||
I didn't see a way out of this situation. I didn't want to drop out of grad school, but how else was I going to get out? I remember when my friend Robert Morris got kicked out of Cornell for writing the internet worm of 1988, I was envious that he'd found such a spectacular way to get out of grad school.
|
||||
|
||||
Then one day in April 1990 a crack appeared in the wall. I ran into professor Cheatham and he asked if I was far enough along to graduate that June. I didn't have a word of my dissertation written, but in what must have been the quickest bit of thinking in my life, I decided to take a shot at writing one in the 5 weeks or so that remained before the deadline, reusing parts of On Lisp where I could, and I was able to respond, with no perceptible delay "Yes, I think so. I'll give you something to read in a few days."
|
||||
|
||||
I picked applications of continuations as the topic. In retrospect I should have written about macros and embedded languages. There's a whole world there that's barely been explored. But all I wanted was to get out of grad school, and my rapidly written dissertation sufficed, just barely.
|
||||
|
||||
Meanwhile I was applying to art schools. I applied to two: RISD in the US, and the Accademia di Belli Arti in Florence, which, because it was the oldest art school, I imagined would be good. RISD accepted me, and I never heard back from the Accademia, so off to Providence I went.
|
||||
|
||||
I'd applied for the BFA program at RISD, which meant in effect that I had to go to college again. This was not as strange as it sounds, because I was only 25, and art schools are full of people of different ages. RISD counted me as a transfer sophomore and said I had to do the foundation that summer. The foundation means the classes that everyone has to take in fundamental subjects like drawing, color, and design.
|
||||
|
||||
Toward the end of the summer I got a big surprise: a letter from the Accademia, which had been delayed because they'd sent it to Cambridge England instead of Cambridge Massachusetts, inviting me to take the entrance exam in Florence that fall. This was now only weeks away. My nice landlady let me leave my stuff in her attic. I had some money saved from consulting work I'd done in grad school; there was probably enough to last a year if I lived cheaply. Now all I had to do was learn Italian.
|
||||
|
||||
Only stranieri (foreigners) had to take this entrance exam. In retrospect it may well have been a way of excluding them, because there were so many stranieri attracted by the idea of studying art in Florence that the Italian students would otherwise have been outnumbered. I was in decent shape at painting and drawing from the RISD foundation that summer, but I still don't know how I managed to pass the written exam. I remember that I answered the essay question by writing about Cezanne, and that I cranked up the intellectual level as high as I could to make the most of my limited vocabulary. [2]
|
||||
|
||||
I'm only up to age 25 and already there are such conspicuous patterns. Here I was, yet again about to attend some august institution in the hopes of learning about some prestigious subject, and yet again about to be disappointed. The students and faculty in the painting department at the Accademia were the nicest people you could imagine, but they had long since arrived at an arrangement whereby the students wouldn't require the faculty to teach anything, and in return the faculty wouldn't require the students to learn anything. And at the same time all involved would adhere outwardly to the conventions of a 19th century atelier. We actually had one of those little stoves, fed with kindling, that you see in 19th century studio paintings, and a nude model sitting as close to it as possible without getting burned. Except hardly anyone else painted her besides me. The rest of the students spent their time chatting or occasionally trying to imitate things they'd seen in American art magazines.
|
||||
|
||||
Our model turned out to live just down the street from me. She made a living from a combination of modelling and making fakes for a local antique dealer. She'd copy an obscure old painting out of a book, and then he'd take the copy and maltreat it to make it look old. [3]
|
||||
|
||||
While I was a student at the Accademia I started painting still lives in my bedroom at night. These paintings were tiny, because the room was, and because I painted them on leftover scraps of canvas, which was all I could afford at the time. Painting still lives is different from painting people, because the subject, as its name suggests, can't move. People can't sit for more than about 15 minutes at a time, and when they do they don't sit very still. So the traditional m.o. for painting people is to know how to paint a generic person, which you then modify to match the specific person you're painting. Whereas a still life you can, if you want, copy pixel by pixel from what you're seeing. You don't want to stop there, of course, or you get merely photographic accuracy, and what makes a still life interesting is that it's been through a head. You want to emphasize the visual cues that tell you, for example, that the reason the color changes suddenly at a certain point is that it's the edge of an object. By subtly emphasizing such things you can make paintings that are more realistic than photographs not just in some metaphorical sense, but in the strict information-theoretic sense. [4]
|
||||
|
||||
I liked painting still lives because I was curious about what I was seeing. In everyday life, we aren't consciously aware of much we're seeing. Most visual perception is handled by low-level processes that merely tell your brain "that's a water droplet" without telling you details like where the lightest and darkest points are, or "that's a bush" without telling you the shape and position of every leaf. This is a feature of brains, not a bug. In everyday life it would be distracting to notice every leaf on every bush. But when you have to paint something, you have to look more closely, and when you do there's a lot to see. You can still be noticing new things after days of trying to paint something people usually take for granted, just as you can after days of trying to write an essay about something people usually take for granted.
|
||||
|
||||
This is not the only way to paint. I'm not 100% sure it's even a good way to paint. But it seemed a good enough bet to be worth trying.
|
||||
|
||||
Our teacher, professor Ulivi, was a nice guy. He could see I worked hard, and gave me a good grade, which he wrote down in a sort of passport each student had. But the Accademia wasn't teaching me anything except Italian, and my money was running out, so at the end of the first year I went back to the US.
|
||||
|
||||
I wanted to go back to RISD, but I was now broke and RISD was very expensive, so I decided to get a job for a year and then return to RISD the next fall. I got one at a company called Interleaf, which made software for creating documents. You mean like Microsoft Word? Exactly. That was how I learned that low end software tends to eat high end software. But Interleaf still had a few years to live yet. [5]
|
||||
|
||||
Interleaf had done something pretty bold. Inspired by Emacs, they'd added a scripting language, and even made the scripting language a dialect of Lisp. Now they wanted a Lisp hacker to write things in it. This was the closest thing I've had to a normal job, and I hereby apologize to my boss and coworkers, because I was a bad employee. Their Lisp was the thinnest icing on a giant C cake, and since I didn't know C and didn't want to learn it, I never understood most of the software. Plus I was terribly irresponsible. This was back when a programming job meant showing up every day during certain working hours. That seemed unnatural to me, and on this point the rest of the world is coming around to my way of thinking, but at the time it caused a lot of friction. Toward the end of the year I spent much of my time surreptitiously working on On Lisp, which I had by this time gotten a contract to publish.
|
||||
|
||||
The good part was that I got paid huge amounts of money, especially by art student standards. In Florence, after paying my part of the rent, my budget for everything else had been $7 a day. Now I was getting paid more than 4 times that every hour, even when I was just sitting in a meeting. By living cheaply I not only managed to save enough to go back to RISD, but also paid off my college loans.
|
||||
|
||||
I learned some useful things at Interleaf, though they were mostly about what not to do. I learned that it's better for technology companies to be run by product people than sales people (though sales is a real skill and people who are good at it are really good at it), that it leads to bugs when code is edited by too many people, that cheap office space is no bargain if it's depressing, that planned meetings are inferior to corridor conversations, that big, bureaucratic customers are a dangerous source of money, and that there's not much overlap between conventional office hours and the optimal time for hacking, or conventional offices and the optimal place for it.
|
||||
|
||||
But the most important thing I learned, and which I used in both Viaweb and Y Combinator, is that the low end eats the high end: that it's good to be the "entry level" option, even though that will be less prestigious, because if you're not, someone else will be, and will squash you against the ceiling. Which in turn means that prestige is a danger sign.
|
||||
|
||||
When I left to go back to RISD the next fall, I arranged to do freelance work for the group that did projects for customers, and this was how I survived for the next several years. When I came back to visit for a project later on, someone told me about a new thing called HTML, which was, as he described it, a derivative of SGML. Markup language enthusiasts were an occupational hazard at Interleaf and I ignored him, but this HTML thing later became a big part of my life.
|
||||
|
||||
In the fall of 1992 I moved back to Providence to continue at RISD. The foundation had merely been intro stuff, and the Accademia had been a (very civilized) joke. Now I was going to see what real art school was like. But alas it was more like the Accademia than not. Better organized, certainly, and a lot more expensive, but it was now becoming clear that art school did not bear the same relationship to art that medical school bore to medicine. At least not the painting department. The textile department, which my next door neighbor belonged to, seemed to be pretty rigorous. No doubt illustration and architecture were too. But painting was post-rigorous. Painting students were supposed to express themselves, which to the more worldly ones meant to try to cook up some sort of distinctive signature style.
|
||||
|
||||
A signature style is the visual equivalent of what in show business is known as a "schtick": something that immediately identifies the work as yours and no one else's. For example, when you see a painting that looks like a certain kind of cartoon, you know it's by Roy Lichtenstein. So if you see a big painting of this type hanging in the apartment of a hedge fund manager, you know he paid millions of dollars for it. That's not always why artists have a signature style, but it's usually why buyers pay a lot for such work. [6]
|
||||
|
||||
There were plenty of earnest students too: kids who "could draw" in high school, and now had come to what was supposed to be the best art school in the country, to learn to draw even better. They tended to be confused and demoralized by what they found at RISD, but they kept going, because painting was what they did. I was not one of the kids who could draw in high school, but at RISD I was definitely closer to their tribe than the tribe of signature style seekers.
|
||||
|
||||
I learned a lot in the color class I took at RISD, but otherwise I was basically teaching myself to paint, and I could do that for free. So in 1993 I dropped out. I hung around Providence for a bit, and then my college friend Nancy Parmet did me a big favor. A rent-controlled apartment in a building her mother owned in New York was becoming vacant. Did I want it? It wasn't much more than my current place, and New York was supposed to be where the artists were. So yes, I wanted it! [7]
|
||||
|
||||
Asterix comics begin by zooming in on a tiny corner of Roman Gaul that turns out not to be controlled by the Romans. You can do something similar on a map of New York City: if you zoom in on the Upper East Side, there's a tiny corner that's not rich, or at least wasn't in 1993. It's called Yorkville, and that was my new home. Now I was a New York artist — in the strictly technical sense of making paintings and living in New York.
|
||||
|
||||
I was nervous about money, because I could sense that Interleaf was on the way down. Freelance Lisp hacking work was very rare, and I didn't want to have to program in another language, which in those days would have meant C++ if I was lucky. So with my unerring nose for financial opportunity, I decided to write another book on Lisp. This would be a popular book, the sort of book that could be used as a textbook. I imagined myself living frugally off the royalties and spending all my time painting. (The painting on the cover of this book, ANSI Common Lisp, is one that I painted around this time.)
|
||||
|
||||
The best thing about New York for me was the presence of Idelle and Julian Weber. Idelle Weber was a painter, one of the early photorealists, and I'd taken her painting class at Harvard. I've never known a teacher more beloved by her students. Large numbers of former students kept in touch with her, including me. After I moved to New York I became her de facto studio assistant.
|
||||
|
||||
She liked to paint on big, square canvases, 4 to 5 feet on a side. One day in late 1994 as I was stretching one of these monsters there was something on the radio about a famous fund manager. He wasn't that much older than me, and was super rich. The thought suddenly occurred to me: why don't I become rich? Then I'll be able to work on whatever I want.
|
||||
|
||||
Meanwhile I'd been hearing more and more about this new thing called the World Wide Web. Robert Morris showed it to me when I visited him in Cambridge, where he was now in grad school at Harvard. It seemed to me that the web would be a big deal. I'd seen what graphical user interfaces had done for the popularity of microcomputers. It seemed like the web would do the same for the internet.
|
||||
|
||||
If I wanted to get rich, here was the next train leaving the station. I was right about that part. What I got wrong was the idea. I decided we should start a company to put art galleries online. I can't honestly say, after reading so many Y Combinator applications, that this was the worst startup idea ever, but it was up there. Art galleries didn't want to be online, and still don't, not the fancy ones. That's not how they sell. I wrote some software to generate web sites for galleries, and Robert wrote some to resize images and set up an http server to serve the pages. Then we tried to sign up galleries. To call this a difficult sale would be an understatement. It was difficult to give away. A few galleries let us make sites for them for free, but none paid us.
|
||||
|
||||
Then some online stores started to appear, and I realized that except for the order buttons they were identical to the sites we'd been generating for galleries. This impressive-sounding thing called an "internet storefront" was something we already knew how to build.
|
||||
|
||||
So in the summer of 1995, after I submitted the camera-ready copy of ANSI Common Lisp to the publishers, we started trying to write software to build online stores. At first this was going to be normal desktop software, which in those days meant Windows software. That was an alarming prospect, because neither of us knew how to write Windows software or wanted to learn. We lived in the Unix world. But we decided we'd at least try writing a prototype store builder on Unix. Robert wrote a shopping cart, and I wrote a new site generator for stores — in Lisp, of course.
|
||||
|
||||
We were working out of Robert's apartment in Cambridge. His roommate was away for big chunks of time, during which I got to sleep in his room. For some reason there was no bed frame or sheets, just a mattress on the floor. One morning as I was lying on this mattress I had an idea that made me sit up like a capital L. What if we ran the software on the server, and let users control it by clicking on links? Then we'd never have to write anything to run on users' computers. We could generate the sites on the same server we'd serve them from. Users wouldn't need anything more than a browser.
|
||||
|
||||
This kind of software, known as a web app, is common now, but at the time it wasn't clear that it was even possible. To find out, we decided to try making a version of our store builder that you could control through the browser. A couple days later, on August 12, we had one that worked. The UI was horrible, but it proved you could build a whole store through the browser, without any client software or typing anything into the command line on the server.
|
||||
|
||||
Now we felt like we were really onto something. I had visions of a whole new generation of software working this way. You wouldn't need versions, or ports, or any of that crap. At Interleaf there had been a whole group called Release Engineering that seemed to be at least as big as the group that actually wrote the software. Now you could just update the software right on the server.
|
||||
|
||||
We started a new company we called Viaweb, after the fact that our software worked via the web, and we got $10,000 in seed funding from Idelle's husband Julian. In return for that and doing the initial legal work and giving us business advice, we gave him 10% of the company. Ten years later this deal became the model for Y Combinator's. We knew founders needed something like this, because we'd needed it ourselves.
|
||||
|
||||
At this stage I had a negative net worth, because the thousand dollars or so I had in the bank was more than counterbalanced by what I owed the government in taxes. (Had I diligently set aside the proper proportion of the money I'd made consulting for Interleaf? No, I had not.) So although Robert had his graduate student stipend, I needed that seed funding to live on.
|
||||
|
||||
We originally hoped to launch in September, but we got more ambitious about the software as we worked on it. Eventually we managed to build a WYSIWYG site builder, in the sense that as you were creating pages, they looked exactly like the static ones that would be generated later, except that instead of leading to static pages, the links all referred to closures stored in a hash table on the server.
|
||||
|
||||
It helped to have studied art, because the main goal of an online store builder is to make users look legit, and the key to looking legit is high production values. If you get page layouts and fonts and colors right, you can make a guy running a store out of his bedroom look more legit than a big company.
|
||||
|
||||
(If you're curious why my site looks so old-fashioned, it's because it's still made with this software. It may look clunky today, but in 1996 it was the last word in slick.)
|
||||
|
||||
In September, Robert rebelled. "We've been working on this for a month," he said, "and it's still not done." This is funny in retrospect, because he would still be working on it almost 3 years later. But I decided it might be prudent to recruit more programmers, and I asked Robert who else in grad school with him was really good. He recommended Trevor Blackwell, which surprised me at first, because at that point I knew Trevor mainly for his plan to reduce everything in his life to a stack of notecards, which he carried around with him. But Rtm was right, as usual. Trevor turned out to be a frighteningly effective hacker.
|
||||
|
||||
It was a lot of fun working with Robert and Trevor. They're the two most independent-minded people I know, and in completely different ways. If you could see inside Rtm's brain it would look like a colonial New England church, and if you could see inside Trevor's it would look like the worst excesses of Austrian Rococo.
|
||||
|
||||
We opened for business, with 6 stores, in January 1996. It was just as well we waited a few months, because although we worried we were late, we were actually almost fatally early. There was a lot of talk in the press then about ecommerce, but not many people actually wanted online stores. [8]
|
||||
|
||||
There were three main parts to the software: the editor, which people used to build sites and which I wrote, the shopping cart, which Robert wrote, and the manager, which kept track of orders and statistics, and which Trevor wrote. In its time, the editor was one of the best general-purpose site builders. I kept the code tight and didn't have to integrate with any other software except Robert's and Trevor's, so it was quite fun to work on. If all I'd had to do was work on this software, the next 3 years would have been the easiest of my life. Unfortunately I had to do a lot more, all of it stuff I was worse at than programming, and the next 3 years were instead the most stressful.
|
||||
|
||||
There were a lot of startups making ecommerce software in the second half of the 90s. We were determined to be the Microsoft Word, not the Interleaf. Which meant being easy to use and inexpensive. It was lucky for us that we were poor, because that caused us to make Viaweb even more inexpensive than we realized. We charged $100 a month for a small store and $300 a month for a big one. This low price was a big attraction, and a constant thorn in the sides of competitors, but it wasn't because of some clever insight that we set the price low. We had no idea what businesses paid for things. $300 a month seemed like a lot of money to us.
|
||||
|
||||
We did a lot of things right by accident like that. For example, we did what's now called "doing things that don't scale," although at the time we would have described it as "being so lame that we're driven to the most desperate measures to get users." The most common of which was building stores for them. This seemed particularly humiliating, since the whole raison d'etre of our software was that people could use it to make their own stores. But anything to get users.
|
||||
|
||||
We learned a lot more about retail than we wanted to know. For example, that if you could only have a small image of a man's shirt (and all images were small then by present standards), it was better to have a closeup of the collar than a picture of the whole shirt. The reason I remember learning this was that it meant I had to rescan about 30 images of men's shirts. My first set of scans were so beautiful too.
|
||||
|
||||
Though this felt wrong, it was exactly the right thing to be doing. Building stores for users taught us about retail, and about how it felt to use our software. I was initially both mystified and repelled by "business" and thought we needed a "business person" to be in charge of it, but once we started to get users, I was converted, in much the same way I was converted to fatherhood once I had kids. Whatever users wanted, I was all theirs. Maybe one day we'd have so many users that I couldn't scan their images for them, but in the meantime there was nothing more important to do.
|
||||
|
||||
Another thing I didn't get at the time is that growth rate is the ultimate test of a startup. Our growth rate was fine. We had about 70 stores at the end of 1996 and about 500 at the end of 1997. I mistakenly thought the thing that mattered was the absolute number of users. And that is the thing that matters in the sense that that's how much money you're making, and if you're not making enough, you might go out of business. But in the long term the growth rate takes care of the absolute number. If we'd been a startup I was advising at Y Combinator, I would have said: Stop being so stressed out, because you're doing fine. You're growing 7x a year. Just don't hire too many more people and you'll soon be profitable, and then you'll control your own destiny.
|
||||
|
||||
Alas I hired lots more people, partly because our investors wanted me to, and partly because that's what startups did during the Internet Bubble. A company with just a handful of employees would have seemed amateurish. So we didn't reach breakeven until about when Yahoo bought us in the summer of 1998. Which in turn meant we were at the mercy of investors for the entire life of the company. And since both we and our investors were noobs at startups, the result was a mess even by startup standards.
|
||||
|
||||
It was a huge relief when Yahoo bought us. In principle our Viaweb stock was valuable. It was a share in a business that was profitable and growing rapidly. But it didn't feel very valuable to me; I had no idea how to value a business, but I was all too keenly aware of the near-death experiences we seemed to have every few months. Nor had I changed my grad student lifestyle significantly since we started. So when Yahoo bought us it felt like going from rags to riches. Since we were going to California, I bought a car, a yellow 1998 VW GTI. I remember thinking that its leather seats alone were by far the most luxurious thing I owned.
|
||||
|
||||
The next year, from the summer of 1998 to the summer of 1999, must have been the least productive of my life. I didn't realize it at the time, but I was worn out from the effort and stress of running Viaweb. For a while after I got to California I tried to continue my usual m.o. of programming till 3 in the morning, but fatigue combined with Yahoo's prematurely aged culture and grim cube farm in Santa Clara gradually dragged me down. After a few months it felt disconcertingly like working at Interleaf.
|
||||
|
||||
Yahoo had given us a lot of options when they bought us. At the time I thought Yahoo was so overvalued that they'd never be worth anything, but to my astonishment the stock went up 5x in the next year. I hung on till the first chunk of options vested, then in the summer of 1999 I left. It had been so long since I'd painted anything that I'd half forgotten why I was doing this. My brain had been entirely full of software and men's shirts for 4 years. But I had done this to get rich so I could paint, I reminded myself, and now I was rich, so I should go paint.
|
||||
|
||||
When I said I was leaving, my boss at Yahoo had a long conversation with me about my plans. I told him all about the kinds of pictures I wanted to paint. At the time I was touched that he took such an interest in me. Now I realize it was because he thought I was lying. My options at that point were worth about $2 million a month. If I was leaving that kind of money on the table, it could only be to go and start some new startup, and if I did, I might take people with me. This was the height of the Internet Bubble, and Yahoo was ground zero of it. My boss was at that moment a billionaire. Leaving then to start a new startup must have seemed to him an insanely, and yet also plausibly, ambitious plan.
|
||||
|
||||
But I really was quitting to paint, and I started immediately. There was no time to lose. I'd already burned 4 years getting rich. Now when I talk to founders who are leaving after selling their companies, my advice is always the same: take a vacation. That's what I should have done, just gone off somewhere and done nothing for a month or two, but the idea never occurred to me.
|
||||
|
||||
So I tried to paint, but I just didn't seem to have any energy or ambition. Part of the problem was that I didn't know many people in California. I'd compounded this problem by buying a house up in the Santa Cruz Mountains, with a beautiful view but miles from anywhere. I stuck it out for a few more months, then in desperation I went back to New York, where unless you understand about rent control you'll be surprised to hear I still had my apartment, sealed up like a tomb of my old life. Idelle was in New York at least, and there were other people trying to paint there, even though I didn't know any of them.
|
||||
|
||||
When I got back to New York I resumed my old life, except now I was rich. It was as weird as it sounds. I resumed all my old patterns, except now there were doors where there hadn't been. Now when I was tired of walking, all I had to do was raise my hand, and (unless it was raining) a taxi would stop to pick me up. Now when I walked past charming little restaurants I could go in and order lunch. It was exciting for a while. Painting started to go better. I experimented with a new kind of still life where I'd paint one painting in the old way, then photograph it and print it, blown up, on canvas, and then use that as the underpainting for a second still life, painted from the same objects (which hopefully hadn't rotted yet).
|
||||
|
||||
Meanwhile I looked for an apartment to buy. Now I could actually choose what neighborhood to live in. Where, I asked myself and various real estate agents, is the Cambridge of New York? Aided by occasional visits to actual Cambridge, I gradually realized there wasn't one. Huh.
|
||||
|
||||
Around this time, in the spring of 2000, I had an idea. It was clear from our experience with Viaweb that web apps were the future. Why not build a web app for making web apps? Why not let people edit code on our server through the browser, and then host the resulting applications for them? [9] You could run all sorts of services on the servers that these applications could use just by making an API call: making and receiving phone calls, manipulating images, taking credit card payments, etc.
|
||||
|
||||
I got so excited about this idea that I couldn't think about anything else. It seemed obvious that this was the future. I didn't particularly want to start another company, but it was clear that this idea would have to be embodied as one, so I decided to move to Cambridge and start it. I hoped to lure Robert into working on it with me, but there I ran into a hitch. Robert was now a postdoc at MIT, and though he'd made a lot of money the last time I'd lured him into working on one of my schemes, it had also been a huge time sink. So while he agreed that it sounded like a plausible idea, he firmly refused to work on it.
|
||||
|
||||
Hmph. Well, I'd do it myself then. I recruited Dan Giffin, who had worked for Viaweb, and two undergrads who wanted summer jobs, and we got to work trying to build what it's now clear is about twenty companies and several open source projects worth of software. The language for defining applications would of course be a dialect of Lisp. But I wasn't so naive as to assume I could spring an overt Lisp on a general audience; we'd hide the parentheses, like Dylan did.
|
||||
|
||||
By then there was a name for the kind of company Viaweb was, an "application service provider," or ASP. This name didn't last long before it was replaced by "software as a service," but it was current for long enough that I named this new company after it: it was going to be called Aspra.
|
||||
|
||||
I started working on the application builder, Dan worked on network infrastructure, and the two undergrads worked on the first two services (images and phone calls). But about halfway through the summer I realized I really didn't want to run a company — especially not a big one, which it was looking like this would have to be. I'd only started Viaweb because I needed the money. Now that I didn't need money anymore, why was I doing this? If this vision had to be realized as a company, then screw the vision. I'd build a subset that could be done as an open source project.
|
||||
|
||||
Much to my surprise, the time I spent working on this stuff was not wasted after all. After we started Y Combinator, I would often encounter startups working on parts of this new architecture, and it was very useful to have spent so much time thinking about it and even trying to write some of it.
|
||||
|
||||
The subset I would build as an open source project was the new Lisp, whose parentheses I now wouldn't even have to hide. A lot of Lisp hackers dream of building a new Lisp, partly because one of the distinctive features of the language is that it has dialects, and partly, I think, because we have in our minds a Platonic form of Lisp that all existing dialects fall short of. I certainly did. So at the end of the summer Dan and I switched to working on this new dialect of Lisp, which I called Arc, in a house I bought in Cambridge.
|
||||
|
||||
The following spring, lightning struck. I was invited to give a talk at a Lisp conference, so I gave one about how we'd used Lisp at Viaweb. Afterward I put a postscript file of this talk online, on paulgraham.com, which I'd created years before using Viaweb but had never used for anything. In one day it got 30,000 page views. What on earth had happened? The referring urls showed that someone had posted it on Slashdot. [10]
|
||||
|
||||
Wow, I thought, there's an audience. If I write something and put it on the web, anyone can read it. That may seem obvious now, but it was surprising then. In the print era there was a narrow channel to readers, guarded by fierce monsters known as editors. The only way to get an audience for anything you wrote was to get it published as a book, or in a newspaper or magazine. Now anyone could publish anything.
|
||||
|
||||
This had been possible in principle since 1993, but not many people had realized it yet. I had been intimately involved with building the infrastructure of the web for most of that time, and a writer as well, and it had taken me 8 years to realize it. Even then it took me several years to understand the implications. It meant there would be a whole new generation of essays. [11]
|
||||
|
||||
In the print era, the channel for publishing essays had been vanishingly small. Except for a few officially anointed thinkers who went to the right parties in New York, the only people allowed to publish essays were specialists writing about their specialties. There were so many essays that had never been written, because there had been no way to publish them. Now they could be, and I was going to write them. [12]
|
||||
|
||||
I've worked on several different things, but to the extent there was a turning point where I figured out what to work on, it was when I started publishing essays online. From then on I knew that whatever else I did, I'd always write essays too.
|
||||
|
||||
I knew that online essays would be a marginal medium at first. Socially they'd seem more like rants posted by nutjobs on their GeoCities sites than the genteel and beautifully typeset compositions published in The New Yorker. But by this point I knew enough to find that encouraging instead of discouraging.
|
||||
|
||||
One of the most conspicuous patterns I've noticed in my life is how well it has worked, for me at least, to work on things that weren't prestigious. Still life has always been the least prestigious form of painting. Viaweb and Y Combinator both seemed lame when we started them. I still get the glassy eye from strangers when they ask what I'm writing, and I explain that it's an essay I'm going to publish on my web site. Even Lisp, though prestigious intellectually in something like the way Latin is, also seems about as hip.
|
||||
|
||||
It's not that unprestigious types of work are good per se. But when you find yourself drawn to some kind of work despite its current lack of prestige, it's a sign both that there's something real to be discovered there, and that you have the right kind of motives. Impure motives are a big danger for the ambitious. If anything is going to lead you astray, it will be the desire to impress people. So while working on things that aren't prestigious doesn't guarantee you're on the right track, it at least guarantees you're not on the most common type of wrong one.
|
||||
|
||||
Over the next several years I wrote lots of essays about all kinds of different topics. O'Reilly reprinted a collection of them as a book, called Hackers & Painters after one of the essays in it. I also worked on spam filters, and did some more painting. I used to have dinners for a group of friends every thursday night, which taught me how to cook for groups. And I bought another building in Cambridge, a former candy factory (and later, twas said, porn studio), to use as an office.
|
||||
|
||||
One night in October 2003 there was a big party at my house. It was a clever idea of my friend Maria Daniels, who was one of the thursday diners. Three separate hosts would all invite their friends to one party. So for every guest, two thirds of the other guests would be people they didn't know but would probably like. One of the guests was someone I didn't know but would turn out to like a lot: a woman called Jessica Livingston. A couple days later I asked her out.
|
||||
|
||||
Jessica was in charge of marketing at a Boston investment bank. This bank thought it understood startups, but over the next year, as she met friends of mine from the startup world, she was surprised how different reality was. And how colorful their stories were. So she decided to compile a book of interviews with startup founders.
|
||||
|
||||
When the bank had financial problems and she had to fire half her staff, she started looking for a new job. In early 2005 she interviewed for a marketing job at a Boston VC firm. It took them weeks to make up their minds, and during this time I started telling her about all the things that needed to be fixed about venture capital. They should make a larger number of smaller investments instead of a handful of giant ones, they should be funding younger, more technical founders instead of MBAs, they should let the founders remain as CEO, and so on.
|
||||
|
||||
One of my tricks for writing essays had always been to give talks. The prospect of having to stand up in front of a group of people and tell them something that won't waste their time is a great spur to the imagination. When the Harvard Computer Society, the undergrad computer club, asked me to give a talk, I decided I would tell them how to start a startup. Maybe they'd be able to avoid the worst of the mistakes we'd made.
|
||||
|
||||
So I gave this talk, in the course of which I told them that the best sources of seed funding were successful startup founders, because then they'd be sources of advice too. Whereupon it seemed they were all looking expectantly at me. Horrified at the prospect of having my inbox flooded by business plans (if I'd only known), I blurted out "But not me!" and went on with the talk. But afterward it occurred to me that I should really stop procrastinating about angel investing. I'd been meaning to since Yahoo bought us, and now it was 7 years later and I still hadn't done one angel investment.
|
||||
|
||||
Meanwhile I had been scheming with Robert and Trevor about projects we could work on together. I missed working with them, and it seemed like there had to be something we could collaborate on.
|
||||
|
||||
As Jessica and I were walking home from dinner on March 11, at the corner of Garden and Walker streets, these three threads converged. Screw the VCs who were taking so long to make up their minds. We'd start our own investment firm and actually implement the ideas we'd been talking about. I'd fund it, and Jessica could quit her job and work for it, and we'd get Robert and Trevor as partners too. [13]
|
||||
|
||||
Once again, ignorance worked in our favor. We had no idea how to be angel investors, and in Boston in 2005 there were no Ron Conways to learn from. So we just made what seemed like the obvious choices, and some of the things we did turned out to be novel.
|
||||
|
||||
There are multiple components to Y Combinator, and we didn't figure them all out at once. The part we got first was to be an angel firm. In those days, those two words didn't go together. There were VC firms, which were organized companies with people whose job it was to make investments, but they only did big, million dollar investments. And there were angels, who did smaller investments, but these were individuals who were usually focused on other things and made investments on the side. And neither of them helped founders enough in the beginning. We knew how helpless founders were in some respects, because we remembered how helpless we'd been. For example, one thing Julian had done for us that seemed to us like magic was to get us set up as a company. We were fine writing fairly difficult software, but actually getting incorporated, with bylaws and stock and all that stuff, how on earth did you do that? Our plan was not only to make seed investments, but to do for startups everything Julian had done for us.
|
||||
|
||||
YC was not organized as a fund. It was cheap enough to run that we funded it with our own money. That went right by 99% of readers, but professional investors are thinking "Wow, that means they got all the returns." But once again, this was not due to any particular insight on our part. We didn't know how VC firms were organized. It never occurred to us to try to raise a fund, and if it had, we wouldn't have known where to start. [14]
|
||||
|
||||
The most distinctive thing about YC is the batch model: to fund a bunch of startups all at once, twice a year, and then to spend three months focusing intensively on trying to help them. That part we discovered by accident, not merely implicitly but explicitly due to our ignorance about investing. We needed to get experience as investors. What better way, we thought, than to fund a whole bunch of startups at once? We knew undergrads got temporary jobs at tech companies during the summer. Why not organize a summer program where they'd start startups instead? We wouldn't feel guilty for being in a sense fake investors, because they would in a similar sense be fake founders. So while we probably wouldn't make much money out of it, we'd at least get to practice being investors on them, and they for their part would probably have a more interesting summer than they would working at Microsoft.
|
||||
|
||||
We'd use the building I owned in Cambridge as our headquarters. We'd all have dinner there once a week — on tuesdays, since I was already cooking for the thursday diners on thursdays — and after dinner we'd bring in experts on startups to give talks.
|
||||
|
||||
We knew undergrads were deciding then about summer jobs, so in a matter of days we cooked up something we called the Summer Founders Program, and I posted an announcement on my site, inviting undergrads to apply. I had never imagined that writing essays would be a way to get "deal flow," as investors call it, but it turned out to be the perfect source. [15] We got 225 applications for the Summer Founders Program, and we were surprised to find that a lot of them were from people who'd already graduated, or were about to that spring. Already this SFP thing was starting to feel more serious than we'd intended.
|
||||
|
||||
We invited about 20 of the 225 groups to interview in person, and from those we picked 8 to fund. They were an impressive group. That first batch included reddit, Justin Kan and Emmett Shear, who went on to found Twitch, Aaron Swartz, who had already helped write the RSS spec and would a few years later become a martyr for open access, and Sam Altman, who would later become the second president of YC. I don't think it was entirely luck that the first batch was so good. You had to be pretty bold to sign up for a weird thing like the Summer Founders Program instead of a summer job at a legit place like Microsoft or Goldman Sachs.
|
||||
|
||||
The deal for startups was based on a combination of the deal we did with Julian ($10k for 10%) and what Robert said MIT grad students got for the summer ($6k). We invested $6k per founder, which in the typical two-founder case was $12k, in return for 6%. That had to be fair, because it was twice as good as the deal we ourselves had taken. Plus that first summer, which was really hot, Jessica brought the founders free air conditioners. [16]
|
||||
|
||||
Fairly quickly I realized that we had stumbled upon the way to scale startup funding. Funding startups in batches was more convenient for us, because it meant we could do things for a lot of startups at once, but being part of a batch was better for the startups too. It solved one of the biggest problems faced by founders: the isolation. Now you not only had colleagues, but colleagues who understood the problems you were facing and could tell you how they were solving them.
|
||||
|
||||
As YC grew, we started to notice other advantages of scale. The alumni became a tight community, dedicated to helping one another, and especially the current batch, whose shoes they remembered being in. We also noticed that the startups were becoming one another's customers. We used to refer jokingly to the "YC GDP," but as YC grows this becomes less and less of a joke. Now lots of startups get their initial set of customers almost entirely from among their batchmates.
|
||||
|
||||
I had not originally intended YC to be a full-time job. I was going to do three things: hack, write essays, and work on YC. As YC grew, and I grew more excited about it, it started to take up a lot more than a third of my attention. But for the first few years I was still able to work on other things.
|
||||
|
||||
In the summer of 2006, Robert and I started working on a new version of Arc. This one was reasonably fast, because it was compiled into Scheme. To test this new Arc, I wrote Hacker News in it. It was originally meant to be a news aggregator for startup founders and was called Startup News, but after a few months I got tired of reading about nothing but startups. Plus it wasn't startup founders we wanted to reach. It was future startup founders. So I changed the name to Hacker News and the topic to whatever engaged one's intellectual curiosity.
|
||||
|
||||
HN was no doubt good for YC, but it was also by far the biggest source of stress for me. If all I'd had to do was select and help founders, life would have been so easy. And that implies that HN was a mistake. Surely the biggest source of stress in one's work should at least be something close to the core of the work. Whereas I was like someone who was in pain while running a marathon not from the exertion of running, but because I had a blister from an ill-fitting shoe. When I was dealing with some urgent problem during YC, there was about a 60% chance it had to do with HN, and a 40% chance it had do with everything else combined. [17]
|
||||
|
||||
As well as HN, I wrote all of YC's internal software in Arc. But while I continued to work a good deal in Arc, I gradually stopped working on Arc, partly because I didn't have time to, and partly because it was a lot less attractive to mess around with the language now that we had all this infrastructure depending on it. So now my three projects were reduced to two: writing essays and working on YC.
|
||||
|
||||
YC was different from other kinds of work I've done. Instead of deciding for myself what to work on, the problems came to me. Every 6 months there was a new batch of startups, and their problems, whatever they were, became our problems. It was very engaging work, because their problems were quite varied, and the good founders were very effective. If you were trying to learn the most you could about startups in the shortest possible time, you couldn't have picked a better way to do it.
|
||||
|
||||
There were parts of the job I didn't like. Disputes between cofounders, figuring out when people were lying to us, fighting with people who maltreated the startups, and so on. But I worked hard even at the parts I didn't like. I was haunted by something Kevin Hale once said about companies: "No one works harder than the boss." He meant it both descriptively and prescriptively, and it was the second part that scared me. I wanted YC to be good, so if how hard I worked set the upper bound on how hard everyone else worked, I'd better work very hard.
|
||||
|
||||
One day in 2010, when he was visiting California for interviews, Robert Morris did something astonishing: he offered me unsolicited advice. I can only remember him doing that once before. One day at Viaweb, when I was bent over double from a kidney stone, he suggested that it would be a good idea for him to take me to the hospital. That was what it took for Rtm to offer unsolicited advice. So I remember his exact words very clearly. "You know," he said, "you should make sure Y Combinator isn't the last cool thing you do."
|
||||
|
||||
At the time I didn't understand what he meant, but gradually it dawned on me that he was saying I should quit. This seemed strange advice, because YC was doing great. But if there was one thing rarer than Rtm offering advice, it was Rtm being wrong. So this set me thinking. It was true that on my current trajectory, YC would be the last thing I did, because it was only taking up more of my attention. It had already eaten Arc, and was in the process of eating essays too. Either YC was my life's work or I'd have to leave eventually. And it wasn't, so I would.
|
||||
|
||||
In the summer of 2012 my mother had a stroke, and the cause turned out to be a blood clot caused by colon cancer. The stroke destroyed her balance, and she was put in a nursing home, but she really wanted to get out of it and back to her house, and my sister and I were determined to help her do it. I used to fly up to Oregon to visit her regularly, and I had a lot of time to think on those flights. On one of them I realized I was ready to hand YC over to someone else.
|
||||
|
||||
I asked Jessica if she wanted to be president, but she didn't, so we decided we'd try to recruit Sam Altman. We talked to Robert and Trevor and we agreed to make it a complete changing of the guard. Up till that point YC had been controlled by the original LLC we four had started. But we wanted YC to last for a long time, and to do that it couldn't be controlled by the founders. So if Sam said yes, we'd let him reorganize YC. Robert and I would retire, and Jessica and Trevor would become ordinary partners.
|
||||
|
||||
When we asked Sam if he wanted to be president of YC, initially he said no. He wanted to start a startup to make nuclear reactors. But I kept at it, and in October 2013 he finally agreed. We decided he'd take over starting with the winter 2014 batch. For the rest of 2013 I left running YC more and more to Sam, partly so he could learn the job, and partly because I was focused on my mother, whose cancer had returned.
|
||||
|
||||
She died on January 15, 2014. We knew this was coming, but it was still hard when it did.
|
||||
|
||||
I kept working on YC till March, to help get that batch of startups through Demo Day, then I checked out pretty completely. (I still talk to alumni and to new startups working on things I'm interested in, but that only takes a few hours a week.)
|
||||
|
||||
What should I do next? Rtm's advice hadn't included anything about that. I wanted to do something completely different, so I decided I'd paint. I wanted to see how good I could get if I really focused on it. So the day after I stopped working on YC, I started painting. I was rusty and it took a while to get back into shape, but it was at least completely engaging. [18]
|
||||
|
||||
I spent most of the rest of 2014 painting. I'd never been able to work so uninterruptedly before, and I got to be better than I had been. Not good enough, but better. Then in November, right in the middle of a painting, I ran out of steam. Up till that point I'd always been curious to see how the painting I was working on would turn out, but suddenly finishing this one seemed like a chore. So I stopped working on it and cleaned my brushes and haven't painted since. So far anyway.
|
||||
|
||||
I realize that sounds rather wimpy. But attention is a zero sum game. If you can choose what to work on, and you choose a project that's not the best one (or at least a good one) for you, then it's getting in the way of another project that is. And at 50 there was some opportunity cost to screwing around.
|
||||
|
||||
I started writing essays again, and wrote a bunch of new ones over the next few months. I even wrote a couple that weren't about startups. Then in March 2015 I started working on Lisp again.
|
||||
|
||||
The distinctive thing about Lisp is that its core is a language defined by writing an interpreter in itself. It wasn't originally intended as a programming language in the ordinary sense. It was meant to be a formal model of computation, an alternative to the Turing machine. If you want to write an interpreter for a language in itself, what's the minimum set of predefined operators you need? The Lisp that John McCarthy invented, or more accurately discovered, is an answer to that question. [19]
|
||||
|
||||
McCarthy didn't realize this Lisp could even be used to program computers till his grad student Steve Russell suggested it. Russell translated McCarthy's interpreter into IBM 704 machine language, and from that point Lisp started also to be a programming language in the ordinary sense. But its origins as a model of computation gave it a power and elegance that other languages couldn't match. It was this that attracted me in college, though I didn't understand why at the time.
|
||||
|
||||
McCarthy's 1960 Lisp did nothing more than interpret Lisp expressions. It was missing a lot of things you'd want in a programming language. So these had to be added, and when they were, they weren't defined using McCarthy's original axiomatic approach. That wouldn't have been feasible at the time. McCarthy tested his interpreter by hand-simulating the execution of programs. But it was already getting close to the limit of interpreters you could test that way — indeed, there was a bug in it that McCarthy had overlooked. To test a more complicated interpreter, you'd have had to run it, and computers then weren't powerful enough.
|
||||
|
||||
Now they are, though. Now you could continue using McCarthy's axiomatic approach till you'd defined a complete programming language. And as long as every change you made to McCarthy's Lisp was a discoveredness-preserving transformation, you could, in principle, end up with a complete language that had this quality. Harder to do than to talk about, of course, but if it was possible in principle, why not try? So I decided to take a shot at it. It took 4 years, from March 26, 2015 to October 12, 2019. It was fortunate that I had a precisely defined goal, or it would have been hard to keep at it for so long.
|
||||
|
||||
I wrote this new Lisp, called Bel, in itself in Arc. That may sound like a contradiction, but it's an indication of the sort of trickery I had to engage in to make this work. By means of an egregious collection of hacks I managed to make something close enough to an interpreter written in itself that could actually run. Not fast, but fast enough to test.
|
||||
|
||||
I had to ban myself from writing essays during most of this time, or I'd never have finished. In late 2015 I spent 3 months writing essays, and when I went back to working on Bel I could barely understand the code. Not so much because it was badly written as because the problem is so convoluted. When you're working on an interpreter written in itself, it's hard to keep track of what's happening at what level, and errors can be practically encrypted by the time you get them.
|
||||
|
||||
So I said no more essays till Bel was done. But I told few people about Bel while I was working on it. So for years it must have seemed that I was doing nothing, when in fact I was working harder than I'd ever worked on anything. Occasionally after wrestling for hours with some gruesome bug I'd check Twitter or HN and see someone asking "Does Paul Graham still code?"
|
||||
|
||||
Working on Bel was hard but satisfying. I worked on it so intensively that at any given time I had a decent chunk of the code in my head and could write more there. I remember taking the boys to the coast on a sunny day in 2015 and figuring out how to deal with some problem involving continuations while I watched them play in the tide pools. It felt like I was doing life right. I remember that because I was slightly dismayed at how novel it felt. The good news is that I had more moments like this over the next few years.
|
||||
|
||||
In the summer of 2016 we moved to England. We wanted our kids to see what it was like living in another country, and since I was a British citizen by birth, that seemed the obvious choice. We only meant to stay for a year, but we liked it so much that we still live there. So most of Bel was written in England.
|
||||
|
||||
In the fall of 2019, Bel was finally finished. Like McCarthy's original Lisp, it's a spec rather than an implementation, although like McCarthy's Lisp it's a spec expressed as code.
|
||||
|
||||
Now that I could write essays again, I wrote a bunch about topics I'd had stacked up. I kept writing essays through 2020, but I also started to think about other things I could work on. How should I choose what to do? Well, how had I chosen what to work on in the past? I wrote an essay for myself to answer that question, and I was surprised how long and messy the answer turned out to be. If this surprised me, who'd lived it, then I thought perhaps it would be interesting to other people, and encouraging to those with similarly messy lives. So I wrote a more detailed version for others to read, and this is the last sentence of it.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Notes
|
||||
|
||||
[1] My experience skipped a step in the evolution of computers: time-sharing machines with interactive OSes. I went straight from batch processing to microcomputers, which made microcomputers seem all the more exciting.
|
||||
|
||||
[2] Italian words for abstract concepts can nearly always be predicted from their English cognates (except for occasional traps like polluzione). It's the everyday words that differ. So if you string together a lot of abstract concepts with a few simple verbs, you can make a little Italian go a long way.
|
||||
|
||||
[3] I lived at Piazza San Felice 4, so my walk to the Accademia went straight down the spine of old Florence: past the Pitti, across the bridge, past Orsanmichele, between the Duomo and the Baptistery, and then up Via Ricasoli to Piazza San Marco. I saw Florence at street level in every possible condition, from empty dark winter evenings to sweltering summer days when the streets were packed with tourists.
|
||||
|
||||
[4] You can of course paint people like still lives if you want to, and they're willing. That sort of portrait is arguably the apex of still life painting, though the long sitting does tend to produce pained expressions in the sitters.
|
||||
|
||||
[5] Interleaf was one of many companies that had smart people and built impressive technology, and yet got crushed by Moore's Law. In the 1990s the exponential growth in the power of commodity (i.e. Intel) processors rolled up high-end, special-purpose hardware and software companies like a bulldozer.
|
||||
|
||||
[6] The signature style seekers at RISD weren't specifically mercenary. In the art world, money and coolness are tightly coupled. Anything expensive comes to be seen as cool, and anything seen as cool will soon become equally expensive.
|
||||
|
||||
[7] Technically the apartment wasn't rent-controlled but rent-stabilized, but this is a refinement only New Yorkers would know or care about. The point is that it was really cheap, less than half market price.
|
||||
|
||||
[8] Most software you can launch as soon as it's done. But when the software is an online store builder and you're hosting the stores, if you don't have any users yet, that fact will be painfully obvious. So before we could launch publicly we had to launch privately, in the sense of recruiting an initial set of users and making sure they had decent-looking stores.
|
||||
|
||||
[9] We'd had a code editor in Viaweb for users to define their own page styles. They didn't know it, but they were editing Lisp expressions underneath. But this wasn't an app editor, because the code ran when the merchants' sites were generated, not when shoppers visited them.
|
||||
|
||||
[10] This was the first instance of what is now a familiar experience, and so was what happened next, when I read the comments and found they were full of angry people. How could I claim that Lisp was better than other languages? Weren't they all Turing complete? People who see the responses to essays I write sometimes tell me how sorry they feel for me, but I'm not exaggerating when I reply that it has always been like this, since the very beginning. It comes with the territory. An essay must tell readers things they don't already know, and some people dislike being told such things.
|
||||
|
||||
[11] People put plenty of stuff on the internet in the 90s of course, but putting something online is not the same as publishing it online. Publishing online means you treat the online version as the (or at least a) primary version.
|
||||
|
||||
[12] There is a general lesson here that our experience with Y Combinator also teaches: Customs continue to constrain you long after the restrictions that caused them have disappeared. Customary VC practice had once, like the customs about publishing essays, been based on real constraints. Startups had once been much more expensive to start, and proportionally rare. Now they could be cheap and common, but the VCs' customs still reflected the old world, just as customs about writing essays still reflected the constraints of the print era.
|
||||
|
||||
Which in turn implies that people who are independent-minded (i.e. less influenced by custom) will have an advantage in fields affected by rapid change (where customs are more likely to be obsolete).
|
||||
|
||||
Here's an interesting point, though: you can't always predict which fields will be affected by rapid change. Obviously software and venture capital will be, but who would have predicted that essay writing would be?
|
||||
|
||||
[13] Y Combinator was not the original name. At first we were called Cambridge Seed. But we didn't want a regional name, in case someone copied us in Silicon Valley, so we renamed ourselves after one of the coolest tricks in the lambda calculus, the Y combinator.
|
||||
|
||||
I picked orange as our color partly because it's the warmest, and partly because no VC used it. In 2005 all the VCs used staid colors like maroon, navy blue, and forest green, because they were trying to appeal to LPs, not founders. The YC logo itself is an inside joke: the Viaweb logo had been a white V on a red circle, so I made the YC logo a white Y on an orange square.
|
||||
|
||||
[14] YC did become a fund for a couple years starting in 2009, because it was getting so big I could no longer afford to fund it personally. But after Heroku got bought we had enough money to go back to being self-funded.
|
||||
|
||||
[15] I've never liked the term "deal flow," because it implies that the number of new startups at any given time is fixed. This is not only false, but it's the purpose of YC to falsify it, by causing startups to be founded that would not otherwise have existed.
|
||||
|
||||
[16] She reports that they were all different shapes and sizes, because there was a run on air conditioners and she had to get whatever she could, but that they were all heavier than she could carry now.
|
||||
|
||||
[17] Another problem with HN was a bizarre edge case that occurs when you both write essays and run a forum. When you run a forum, you're assumed to see if not every conversation, at least every conversation involving you. And when you write essays, people post highly imaginative misinterpretations of them on forums. Individually these two phenomena are tedious but bearable, but the combination is disastrous. You actually have to respond to the misinterpretations, because the assumption that you're present in the conversation means that not responding to any sufficiently upvoted misinterpretation reads as a tacit admission that it's correct. But that in turn encourages more; anyone who wants to pick a fight with you senses that now is their chance.
|
||||
|
||||
[18] The worst thing about leaving YC was not working with Jessica anymore. We'd been working on YC almost the whole time we'd known each other, and we'd neither tried nor wanted to separate it from our personal lives, so leaving was like pulling up a deeply rooted tree.
|
||||
|
||||
[19] One way to get more precise about the concept of invented vs discovered is to talk about space aliens. Any sufficiently advanced alien civilization would certainly know about the Pythagorean theorem, for example. I believe, though with less certainty, that they would also know about the Lisp in McCarthy's 1960 paper.
|
||||
|
||||
But if so there's no reason to suppose that this is the limit of the language that might be known to them. Presumably aliens need numbers and errors and I/O too. So it seems likely there exists at least one path out of McCarthy's Lisp along which discoveredness is preserved.
|
||||
|
||||
|
||||
|
||||
Thanks to Trevor Blackwell, John Collison, Patrick Collison, Daniel Gackle, Ralph Hazell, Jessica Livingston, Robert Morris, and Harj Taggar for reading drafts of this.`;
|
||||
|
||||
export default essay;
|
||||
@@ -1,40 +0,0 @@
|
||||
import { stdin as input, stdout as output } from "node:process";
|
||||
// readline/promises is still experimental so not in @types/node yet
|
||||
// @ts-ignore
|
||||
import readline from "node:readline/promises";
|
||||
|
||||
import { ChatMessage, LlamaDeuce, OpenAI } from "llamaindex";
|
||||
|
||||
(async () => {
|
||||
const gpt4 = new OpenAI({ model: "gpt-4", temperature: 0.9 });
|
||||
const l2 = new LlamaDeuce({
|
||||
model: "Llama-2-70b-chat-4bit",
|
||||
temperature: 0.9,
|
||||
});
|
||||
|
||||
const rl = readline.createInterface({ input, output });
|
||||
const start = await rl.question("Start: ");
|
||||
const history: ChatMessage[] = [
|
||||
{
|
||||
content:
|
||||
"Prefer shorter answers. Keep your response to 100 words or less.",
|
||||
role: "system",
|
||||
},
|
||||
{ content: start, role: "user" },
|
||||
];
|
||||
|
||||
while (true) {
|
||||
const next = history.length % 2 === 1 ? gpt4 : l2;
|
||||
const r = await next.chat(
|
||||
history.map(({ content, role }) => ({
|
||||
content,
|
||||
role: next === l2 ? role : role === "user" ? "assistant" : "user",
|
||||
})),
|
||||
);
|
||||
history.push({
|
||||
content: r.message.content,
|
||||
role: next === l2 ? "assistant" : "user",
|
||||
});
|
||||
await rl.question((next === l2 ? "Llama: " : "GPT: ") + r.message.content);
|
||||
}
|
||||
})();
|
||||
@@ -1,21 +0,0 @@
|
||||
import { HTMLReader, VectorStoreIndex } from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
// Load page
|
||||
const reader = new HTMLReader();
|
||||
const documents = await reader.loadData("data/18-1_Changelog.html");
|
||||
|
||||
// Split text and create embeddings. Store them in a VectorStoreIndex
|
||||
const index = await VectorStoreIndex.fromDocuments(documents);
|
||||
|
||||
// Query the index
|
||||
const queryEngine = index.asQueryEngine();
|
||||
const response = await queryEngine.query(
|
||||
"What were the notable changes in 18.1?",
|
||||
);
|
||||
|
||||
// Output response
|
||||
console.log(response.toString());
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -1,32 +0,0 @@
|
||||
import {
|
||||
Document,
|
||||
KeywordTableIndex,
|
||||
KeywordTableRetrieverMode,
|
||||
} from "llamaindex";
|
||||
import essay from "./essay";
|
||||
|
||||
async function main() {
|
||||
const document = new Document({ text: essay, id_: "essay" });
|
||||
const index = await KeywordTableIndex.fromDocuments([document]);
|
||||
|
||||
const allModes: KeywordTableRetrieverMode[] = [
|
||||
KeywordTableRetrieverMode.DEFAULT,
|
||||
KeywordTableRetrieverMode.SIMPLE,
|
||||
KeywordTableRetrieverMode.RAKE,
|
||||
];
|
||||
allModes.forEach(async (mode) => {
|
||||
const queryEngine = index.asQueryEngine({
|
||||
retriever: index.asRetriever({
|
||||
mode,
|
||||
}),
|
||||
});
|
||||
const response = await queryEngine.query(
|
||||
"What did the author do growing up?",
|
||||
);
|
||||
console.log(response.toString());
|
||||
});
|
||||
}
|
||||
|
||||
main().catch((e: Error) => {
|
||||
console.error(e, e.stack);
|
||||
});
|
||||
@@ -1,7 +0,0 @@
|
||||
import { DeuceChatStrategy, LlamaDeuce } from "llamaindex";
|
||||
|
||||
(async () => {
|
||||
const deuce = new LlamaDeuce({ chatStrategy: DeuceChatStrategy.META });
|
||||
const result = await deuce.chat([{ content: "Hello, world!", role: "user" }]);
|
||||
console.log(result);
|
||||
})();
|
||||
@@ -1,47 +0,0 @@
|
||||
import { ChatMessage, SimpleChatEngine } from "llamaindex";
|
||||
import { stdin as input, stdout as output } from "node:process";
|
||||
import readline from "node:readline/promises";
|
||||
import { Anthropic } from "../../packages/core/src/llm/LLM";
|
||||
|
||||
async function main() {
|
||||
const query: string = `
|
||||
Where is Istanbul?
|
||||
`;
|
||||
|
||||
// const llm = new OpenAI({ model: "gpt-3.5-turbo", temperature: 0.1 });
|
||||
const llm = new Anthropic();
|
||||
const message: ChatMessage = { content: query, role: "user" };
|
||||
|
||||
//TODO: Add callbacks later
|
||||
|
||||
//Stream Complete
|
||||
//Note: Setting streaming flag to true or false will auto-set your return type to
|
||||
//either an AsyncGenerator or a Response.
|
||||
// Omitting the streaming flag automatically sets streaming to false
|
||||
|
||||
const chatEngine: SimpleChatEngine = new SimpleChatEngine({
|
||||
chatHistory: undefined,
|
||||
llm: llm,
|
||||
});
|
||||
|
||||
const rl = readline.createInterface({ input, output });
|
||||
while (true) {
|
||||
const query = await rl.question("Query: ");
|
||||
|
||||
if (!query) {
|
||||
break;
|
||||
}
|
||||
|
||||
//Case 1: .chat(query, undefined, true) => Stream
|
||||
//Case 2: .chat(query, undefined, false) => Response object
|
||||
//Case 3: .chat(query, undefined) => Response object
|
||||
const chatStream = await chatEngine.chat(query, undefined, true);
|
||||
var accumulated_result = "";
|
||||
for await (const part of chatStream) {
|
||||
accumulated_result += part;
|
||||
process.stdout.write(part);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,35 +0,0 @@
|
||||
import {
|
||||
Document,
|
||||
NodeWithScore,
|
||||
ResponseSynthesizer,
|
||||
SimpleNodeParser,
|
||||
TextNode,
|
||||
} from "llamaindex";
|
||||
|
||||
(async () => {
|
||||
const nodeParser = new SimpleNodeParser();
|
||||
const nodes = nodeParser.getNodesFromDocuments([
|
||||
new Document({ text: "I am 10 years old. John is 20 years old." }),
|
||||
]);
|
||||
|
||||
console.log(nodes);
|
||||
|
||||
const responseSynthesizer = new ResponseSynthesizer();
|
||||
|
||||
const nodesWithScore: NodeWithScore[] = [
|
||||
{
|
||||
node: new TextNode({ text: "I am 10 years old." }),
|
||||
score: 1,
|
||||
},
|
||||
{
|
||||
node: new TextNode({ text: "John is 20 years old." }),
|
||||
score: 0.5,
|
||||
},
|
||||
];
|
||||
|
||||
const response = await responseSynthesizer.synthesize(
|
||||
"What age am I?",
|
||||
nodesWithScore,
|
||||
);
|
||||
console.log(response.response);
|
||||
})();
|
||||
@@ -1,20 +0,0 @@
|
||||
import { MarkdownReader, VectorStoreIndex } from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
// Load Markdown file
|
||||
const reader = new MarkdownReader();
|
||||
const documents = await reader.loadData("node_modules/llamaindex/README.md");
|
||||
|
||||
// Split text and create embeddings. Store them in a VectorStoreIndex
|
||||
const index = await VectorStoreIndex.fromDocuments(documents);
|
||||
|
||||
// Query the index
|
||||
const queryEngine = index.asQueryEngine();
|
||||
|
||||
const response = await queryEngine.query("What does the example code do?");
|
||||
|
||||
// Output response
|
||||
console.log(response.toString());
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -1,68 +0,0 @@
|
||||
import { MongoClient } from "mongodb";
|
||||
import { Document } from "../../packages/core/src/Node";
|
||||
import { VectorStoreIndex } from "../../packages/core/src/indices";
|
||||
import { SimpleMongoReader } from "../../packages/core/src/readers/SimpleMongoReader";
|
||||
|
||||
import { stdin as input, stdout as output } from "node:process";
|
||||
import readline from "node:readline/promises";
|
||||
|
||||
async function main() {
|
||||
//Dummy test code
|
||||
const query: object = { _id: "waldo" };
|
||||
const options: object = {};
|
||||
const projections: object = { embedding: 0 };
|
||||
const limit: number = Infinity;
|
||||
const uri: string = process.env.MONGODB_URI ?? "fake_uri";
|
||||
const client: MongoClient = new MongoClient(uri);
|
||||
|
||||
//Where the real code starts
|
||||
const MR = new SimpleMongoReader(client);
|
||||
const documents: Document[] = await MR.loadData(
|
||||
"data",
|
||||
"posts",
|
||||
1,
|
||||
{},
|
||||
options,
|
||||
projections,
|
||||
);
|
||||
|
||||
//
|
||||
//If you need to look at low-level details of
|
||||
// a queryEngine (for example, needing to check each individual node)
|
||||
//
|
||||
|
||||
// Split text and create embeddings. Store them in a VectorStoreIndex
|
||||
// var storageContext = await storageContextFromDefaults({});
|
||||
// var serviceContext = serviceContextFromDefaults({});
|
||||
// const docStore = storageContext.docStore;
|
||||
|
||||
// for (const doc of documents) {
|
||||
// docStore.setDocumentHash(doc.id_, doc.hash);
|
||||
// }
|
||||
// const nodes = serviceContext.nodeParser.getNodesFromDocuments(documents);
|
||||
// console.log(nodes);
|
||||
|
||||
//
|
||||
//Making Vector Store from documents
|
||||
//
|
||||
|
||||
const index = await VectorStoreIndex.fromDocuments(documents);
|
||||
// Create query engine
|
||||
const queryEngine = index.asQueryEngine();
|
||||
|
||||
const rl = readline.createInterface({ input, output });
|
||||
while (true) {
|
||||
const query = await rl.question("Query: ");
|
||||
|
||||
if (!query) {
|
||||
break;
|
||||
}
|
||||
|
||||
const response = await queryEngine.query(query);
|
||||
|
||||
// Output response
|
||||
console.log(response.toString());
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,89 +0,0 @@
|
||||
import { Client } from "@notionhq/client";
|
||||
import { program } from "commander";
|
||||
import { NotionReader, VectorStoreIndex } from "llamaindex";
|
||||
import { stdin as input, stdout as output } from "node:process";
|
||||
// readline/promises is still experimental so not in @types/node yet
|
||||
// @ts-ignore
|
||||
import readline from "node:readline/promises";
|
||||
|
||||
program
|
||||
.argument("[page]", "Notion page id (must be provided)")
|
||||
.action(async (page, _options, command) => {
|
||||
// Initializing a client
|
||||
|
||||
if (!process.env.NOTION_TOKEN) {
|
||||
console.log(
|
||||
"No NOTION_TOKEN found in environment variables. You will need to register an integration https://www.notion.com/my-integrations and put it in your NOTION_TOKEN environment variable.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const notion = new Client({
|
||||
auth: process.env.NOTION_TOKEN,
|
||||
});
|
||||
|
||||
if (!page) {
|
||||
const response = await notion.search({
|
||||
filter: {
|
||||
value: "page",
|
||||
property: "object",
|
||||
},
|
||||
sort: {
|
||||
direction: "descending",
|
||||
timestamp: "last_edited_time",
|
||||
},
|
||||
});
|
||||
|
||||
const { results } = response;
|
||||
|
||||
if (results.length === 0) {
|
||||
console.log(
|
||||
"No pages found. You will need to share it with your integration. (tap the three dots on the top right, find Add connections, and add your integration)",
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
const pages = results
|
||||
.map((result) => {
|
||||
if (!("url" in result)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
id: result.id,
|
||||
url: result.url,
|
||||
};
|
||||
})
|
||||
.filter((page) => page !== null);
|
||||
console.log("Found pages:");
|
||||
console.table(pages);
|
||||
console.log(`To run, run ts-node ${command.name()} [page id]`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const reader = new NotionReader({ client: notion });
|
||||
const documents = await reader.loadData(page);
|
||||
console.log(documents);
|
||||
|
||||
// Split text and create embeddings. Store them in a VectorStoreIndex
|
||||
const index = await VectorStoreIndex.fromDocuments(documents);
|
||||
|
||||
// Create query engine
|
||||
const queryEngine = index.asQueryEngine();
|
||||
|
||||
const rl = readline.createInterface({ input, output });
|
||||
while (true) {
|
||||
const query = await rl.question("Query: ");
|
||||
|
||||
if (!query) {
|
||||
break;
|
||||
}
|
||||
|
||||
const response = await queryEngine.query(query);
|
||||
|
||||
// Output response
|
||||
console.log(response.toString());
|
||||
}
|
||||
});
|
||||
|
||||
program.parse();
|
||||
@@ -1,15 +0,0 @@
|
||||
import { OpenAI } from "llamaindex";
|
||||
|
||||
(async () => {
|
||||
const llm = new OpenAI({ model: "gpt-4-1106-preview", temperature: 0.1 });
|
||||
|
||||
// complete api
|
||||
const response1 = await llm.complete("How are you?");
|
||||
console.log(response1.message.content);
|
||||
|
||||
// chat api
|
||||
const response2 = await llm.chat([
|
||||
{ content: "Tell me a joke.", role: "user" },
|
||||
]);
|
||||
console.log(response2.message.content);
|
||||
})();
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"version": "0.0.33",
|
||||
"private": true,
|
||||
"name": "simple",
|
||||
"dependencies": {
|
||||
"@notionhq/client": "^2.2.13",
|
||||
"@pinecone-database/pinecone": "^1.1.2",
|
||||
"commander": "^11.1.0",
|
||||
"llamaindex": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.18.6",
|
||||
"ts-node": "^10.9.1"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint ."
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import { PDFReader, VectorStoreIndex } from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
// Load PDF
|
||||
const reader = new PDFReader();
|
||||
const documents = await reader.loadData("data/brk-2022.pdf");
|
||||
|
||||
// Split text and create embeddings. Store them in a VectorStoreIndex
|
||||
const index = await VectorStoreIndex.fromDocuments(documents);
|
||||
|
||||
// Query the index
|
||||
const queryEngine = index.asQueryEngine();
|
||||
const response = await queryEngine.query("What mistakes did they make?");
|
||||
|
||||
// Output response
|
||||
console.log(response.toString());
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -1,23 +0,0 @@
|
||||
import { Portkey } from "llamaindex";
|
||||
|
||||
(async () => {
|
||||
const llms = [{}];
|
||||
const portkey = new Portkey({
|
||||
mode: "single",
|
||||
llms: [
|
||||
{
|
||||
provider: "anyscale",
|
||||
virtual_key: "anyscale-3b3c04",
|
||||
model: "meta-llama/Llama-2-13b-chat-hf",
|
||||
max_tokens: 2000,
|
||||
},
|
||||
],
|
||||
});
|
||||
const result = portkey.stream_chat([
|
||||
{ role: "system", content: "You are a helpful assistant." },
|
||||
{ role: "user", content: "Tell me a joke." },
|
||||
]);
|
||||
for await (const res of result) {
|
||||
process.stdout.write(res);
|
||||
}
|
||||
})();
|
||||
@@ -1,16 +0,0 @@
|
||||
import fs from "node:fs/promises";
|
||||
|
||||
import { SentenceSplitter } from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
const path = "node_modules/llamaindex/examples/abramov.txt";
|
||||
const essay = await fs.readFile(path, "utf-8");
|
||||
|
||||
const textSplitter = new SentenceSplitter();
|
||||
|
||||
const chunks = textSplitter.splitTextWithOverlaps(essay);
|
||||
|
||||
console.log(chunks);
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,44 +0,0 @@
|
||||
import {
|
||||
Document,
|
||||
storageContextFromDefaults,
|
||||
VectorStoreIndex,
|
||||
} from "llamaindex";
|
||||
import essay from "./essay";
|
||||
|
||||
async function main() {
|
||||
// Create Document object with essay
|
||||
const document = new Document({ text: essay, id_: "essay" });
|
||||
|
||||
// Split text and create embeddings. Store them in a VectorStoreIndex
|
||||
// persist the vector store automatically with the storage context
|
||||
const storageContext = await storageContextFromDefaults({
|
||||
persistDir: "./storage",
|
||||
});
|
||||
const index = await VectorStoreIndex.fromDocuments([document], {
|
||||
storageContext,
|
||||
});
|
||||
|
||||
// Query the index
|
||||
const queryEngine = index.asQueryEngine();
|
||||
const response = await queryEngine.query(
|
||||
"What did the author do in college?",
|
||||
);
|
||||
|
||||
// Output response
|
||||
console.log(response.toString());
|
||||
|
||||
// load the index
|
||||
const secondStorageContext = await storageContextFromDefaults({
|
||||
persistDir: "./storage",
|
||||
});
|
||||
const loadedIndex = await VectorStoreIndex.init({
|
||||
storageContext: secondStorageContext,
|
||||
});
|
||||
const loadedQueryEngine = loadedIndex.asQueryEngine();
|
||||
const loadedResponse = await loadedQueryEngine.query(
|
||||
"What did the author do growing up?",
|
||||
);
|
||||
console.log(loadedResponse.toString());
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -1,26 +0,0 @@
|
||||
import { Document, SubQuestionQueryEngine, VectorStoreIndex } from "llamaindex";
|
||||
|
||||
import essay from "./essay";
|
||||
|
||||
(async () => {
|
||||
const document = new Document({ text: essay, id_: essay });
|
||||
const index = await VectorStoreIndex.fromDocuments([document]);
|
||||
|
||||
const queryEngine = SubQuestionQueryEngine.fromDefaults({
|
||||
queryEngineTools: [
|
||||
{
|
||||
queryEngine: index.asQueryEngine(),
|
||||
metadata: {
|
||||
name: "pg_essay",
|
||||
description: "Paul Graham essay on What I Worked On",
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const response = await queryEngine.query(
|
||||
"How was Paul Grahams life different before and after YC?",
|
||||
);
|
||||
|
||||
console.log(response.toString());
|
||||
})();
|
||||
@@ -1,31 +0,0 @@
|
||||
import {
|
||||
Document,
|
||||
SimpleNodeParser,
|
||||
SummaryIndex,
|
||||
SummaryRetrieverMode,
|
||||
serviceContextFromDefaults,
|
||||
} from "llamaindex";
|
||||
import essay from "./essay";
|
||||
|
||||
async function main() {
|
||||
const serviceContext = serviceContextFromDefaults({
|
||||
nodeParser: new SimpleNodeParser({
|
||||
chunkSize: 40,
|
||||
}),
|
||||
});
|
||||
const document = new Document({ text: essay, id_: "essay" });
|
||||
const index = await SummaryIndex.fromDocuments([document], {
|
||||
serviceContext,
|
||||
});
|
||||
const queryEngine = index.asQueryEngine({
|
||||
retriever: index.asRetriever({ mode: SummaryRetrieverMode.LLM }),
|
||||
});
|
||||
const response = await queryEngine.query(
|
||||
"What did the author do growing up?",
|
||||
);
|
||||
console.log(response.toString());
|
||||
}
|
||||
|
||||
main().catch((e: Error) => {
|
||||
console.error(e, e.stack);
|
||||
});
|
||||
@@ -1,27 +0,0 @@
|
||||
import fs from "node:fs/promises";
|
||||
|
||||
import { Document, VectorStoreIndex } from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
// Load essay from abramov.txt in Node
|
||||
const path = "node_modules/llamaindex/examples/abramov.txt";
|
||||
|
||||
const essay = await fs.readFile(path, "utf-8");
|
||||
|
||||
// Create Document object with essay
|
||||
const document = new Document({ text: essay, id_: path });
|
||||
|
||||
// Split text and create embeddings. Store them in a VectorStoreIndex
|
||||
const index = await VectorStoreIndex.fromDocuments([document]);
|
||||
|
||||
// Query the index
|
||||
const queryEngine = index.asQueryEngine();
|
||||
const response = await queryEngine.query(
|
||||
"What did the author do in college?",
|
||||
);
|
||||
|
||||
// Output response
|
||||
console.log(response.toString());
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -1,35 +0,0 @@
|
||||
import fs from "node:fs/promises";
|
||||
|
||||
import {
|
||||
Anthropic,
|
||||
Document,
|
||||
serviceContextFromDefaults,
|
||||
VectorStoreIndex,
|
||||
} from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
// Load essay from abramov.txt in Node
|
||||
const path = "node_modules/llamaindex/examples/abramov.txt";
|
||||
|
||||
const essay = await fs.readFile(path, "utf-8");
|
||||
|
||||
// Create Document object with essay
|
||||
const document = new Document({ text: essay, id_: path });
|
||||
|
||||
// Split text and create embeddings. Store them in a VectorStoreIndex
|
||||
const serviceContext = serviceContextFromDefaults({ llm: new Anthropic() });
|
||||
const index = await VectorStoreIndex.fromDocuments([document], {
|
||||
serviceContext,
|
||||
});
|
||||
|
||||
// Query the index
|
||||
const queryEngine = index.asQueryEngine();
|
||||
const response = await queryEngine.query(
|
||||
"What did the author do in college?",
|
||||
);
|
||||
|
||||
// Output response
|
||||
console.log(response.toString());
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -1,42 +0,0 @@
|
||||
import {
|
||||
Document,
|
||||
OpenAI,
|
||||
RetrieverQueryEngine,
|
||||
serviceContextFromDefaults,
|
||||
SimilarityPostprocessor,
|
||||
VectorStoreIndex,
|
||||
} from "llamaindex";
|
||||
import essay from "./essay";
|
||||
|
||||
// Customize retrieval and query args
|
||||
async function main() {
|
||||
const document = new Document({ text: essay, id_: "essay" });
|
||||
|
||||
const serviceContext = serviceContextFromDefaults({
|
||||
llm: new OpenAI({ model: "gpt-3.5-turbo", temperature: 0.1 }),
|
||||
});
|
||||
|
||||
const index = await VectorStoreIndex.fromDocuments([document], {
|
||||
serviceContext,
|
||||
});
|
||||
|
||||
const retriever = index.asRetriever();
|
||||
retriever.similarityTopK = 5;
|
||||
const nodePostprocessor = new SimilarityPostprocessor({
|
||||
similarityCutoff: 0.7,
|
||||
});
|
||||
// TODO: cannot pass responseSynthesizer into retriever query engine
|
||||
const queryEngine = new RetrieverQueryEngine(
|
||||
retriever,
|
||||
undefined,
|
||||
undefined,
|
||||
[nodePostprocessor],
|
||||
);
|
||||
|
||||
const response = await queryEngine.query(
|
||||
"What did the author do growing up?",
|
||||
);
|
||||
console.log(response.response);
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -1,197 +0,0 @@
|
||||
import {
|
||||
OpenAI,
|
||||
ResponseSynthesizer,
|
||||
RetrieverQueryEngine,
|
||||
serviceContextFromDefaults,
|
||||
TextNode,
|
||||
TreeSummarize,
|
||||
VectorIndexRetriever,
|
||||
VectorStore,
|
||||
VectorStoreIndex,
|
||||
VectorStoreQuery,
|
||||
VectorStoreQueryResult,
|
||||
} from "llamaindex";
|
||||
|
||||
import { Index, Pinecone, RecordMetadata } from "@pinecone-database/pinecone";
|
||||
|
||||
/**
|
||||
* Please do not use this class in production; it's only for demonstration purposes.
|
||||
*/
|
||||
class PineconeVectorStore<T extends RecordMetadata = RecordMetadata>
|
||||
implements VectorStore
|
||||
{
|
||||
storesText = true;
|
||||
isEmbeddingQuery = false;
|
||||
|
||||
indexName!: string;
|
||||
pineconeClient!: Pinecone;
|
||||
index!: Index<T>;
|
||||
|
||||
constructor({ indexName, client }: { indexName: string; client: Pinecone }) {
|
||||
this.indexName = indexName;
|
||||
this.pineconeClient = client;
|
||||
this.index = client.index<T>(indexName);
|
||||
}
|
||||
|
||||
client() {
|
||||
return this.pineconeClient;
|
||||
}
|
||||
|
||||
async query(
|
||||
query: VectorStoreQuery,
|
||||
kwargs?: any,
|
||||
): Promise<VectorStoreQueryResult> {
|
||||
let queryEmbedding: number[] = [];
|
||||
if (query.queryEmbedding) {
|
||||
if (typeof query.alpha === "number") {
|
||||
const alpha = query.alpha;
|
||||
queryEmbedding = query.queryEmbedding.map((v) => v * alpha);
|
||||
} else {
|
||||
queryEmbedding = query.queryEmbedding;
|
||||
}
|
||||
}
|
||||
|
||||
// Current LlamaIndexTS implementation only support exact match filter, so we use kwargs instead.
|
||||
const filter = kwargs?.filter || {};
|
||||
|
||||
const response = await this.index.query({
|
||||
filter,
|
||||
vector: queryEmbedding,
|
||||
topK: query.similarityTopK,
|
||||
includeValues: true,
|
||||
includeMetadata: true,
|
||||
});
|
||||
|
||||
console.log(
|
||||
`Numbers of vectors returned by Pinecone after preFilters are applied: ${
|
||||
response?.matches?.length || 0
|
||||
}.`,
|
||||
);
|
||||
|
||||
const topKIds: string[] = [];
|
||||
const topKNodes: TextNode[] = [];
|
||||
const topKScores: number[] = [];
|
||||
|
||||
const metadataToNode = (metadata?: T): Partial<TextNode> => {
|
||||
if (!metadata) {
|
||||
throw new Error("metadata is undefined.");
|
||||
}
|
||||
|
||||
const nodeContent = metadata["_node_content"];
|
||||
if (!nodeContent) {
|
||||
throw new Error("nodeContent is undefined.");
|
||||
}
|
||||
|
||||
if (typeof nodeContent !== "string") {
|
||||
throw new Error("nodeContent is not a string.");
|
||||
}
|
||||
|
||||
return JSON.parse(nodeContent);
|
||||
};
|
||||
|
||||
if (response.matches) {
|
||||
for (const match of response.matches) {
|
||||
const node = new TextNode({
|
||||
...metadataToNode(match.metadata),
|
||||
embedding: match.values,
|
||||
});
|
||||
|
||||
topKIds.push(match.id);
|
||||
topKNodes.push(node);
|
||||
topKScores.push(match.score ?? 0);
|
||||
}
|
||||
}
|
||||
|
||||
const result = {
|
||||
ids: topKIds,
|
||||
nodes: topKNodes,
|
||||
similarities: topKScores,
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
add(): Promise<string[]> {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
delete(): Promise<void> {
|
||||
throw new Error("Method `delete` not implemented.");
|
||||
}
|
||||
|
||||
persist(): Promise<void> {
|
||||
throw new Error("Method `persist` not implemented.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The goal of this example is to show how to use Pinecone as a vector store
|
||||
* for LlamaIndexTS with(out) preFilters.
|
||||
*
|
||||
* It should not be used in production like that,
|
||||
* as you might want to find a proper PineconeVectorStore implementation.
|
||||
*/
|
||||
async function main() {
|
||||
process.env.PINECONE_API_KEY = "Your Pinecone API Key.";
|
||||
process.env.PINECONE_ENVIRONMENT = "Your Pinecone Environment.";
|
||||
process.env.PINECONE_PROJECT_ID = "Your Pinecone Project ID.";
|
||||
process.env.PINECONE_INDEX_NAME = "Your Pinecone Index Name.";
|
||||
process.env.OPENAI_API_KEY = "Your OpenAI API Key.";
|
||||
process.env.OPENAI_API_ORGANIZATION = "Your OpenAI API Organization.";
|
||||
|
||||
const getPineconeVectorStore = async () => {
|
||||
return new PineconeVectorStore({
|
||||
indexName: process.env.PINECONE_INDEX_NAME || "index-name",
|
||||
client: new Pinecone(),
|
||||
});
|
||||
};
|
||||
|
||||
const getServiceContext = () => {
|
||||
const openAI = new OpenAI({
|
||||
model: "gpt-4",
|
||||
apiKey: process.env.OPENAI_API_KEY,
|
||||
});
|
||||
|
||||
return serviceContextFromDefaults({
|
||||
llm: openAI,
|
||||
});
|
||||
};
|
||||
|
||||
const getQueryEngine = async (filter: unknown) => {
|
||||
const vectorStore = await getPineconeVectorStore();
|
||||
const serviceContext = getServiceContext();
|
||||
|
||||
const vectorStoreIndex = await VectorStoreIndex.fromVectorStore(
|
||||
vectorStore,
|
||||
serviceContext,
|
||||
);
|
||||
|
||||
const retriever = new VectorIndexRetriever({
|
||||
index: vectorStoreIndex,
|
||||
similarityTopK: 500,
|
||||
});
|
||||
|
||||
const responseSynthesizer = new ResponseSynthesizer({
|
||||
serviceContext,
|
||||
responseBuilder: new TreeSummarize(serviceContext),
|
||||
});
|
||||
|
||||
return new RetrieverQueryEngine(retriever, responseSynthesizer, {
|
||||
filter,
|
||||
});
|
||||
};
|
||||
|
||||
// whatever is a key from your metadata
|
||||
const queryEngine = await getQueryEngine({
|
||||
whatever: {
|
||||
$gte: 1,
|
||||
$lte: 100,
|
||||
},
|
||||
});
|
||||
|
||||
const response = await queryEngine.query("How many results do you have?");
|
||||
|
||||
console.log(response.toString());
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -1,36 +0,0 @@
|
||||
import fs from "node:fs/promises";
|
||||
|
||||
import {
|
||||
Document,
|
||||
OpenAI,
|
||||
serviceContextFromDefaults,
|
||||
VectorStoreIndex,
|
||||
} from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
// Load essay from abramov.txt in Node
|
||||
const path = "node_modules/llamaindex/examples/abramov.txt";
|
||||
const essay = await fs.readFile(path, "utf-8");
|
||||
|
||||
// Create Document object with essay
|
||||
const document = new Document({ text: essay, id_: path });
|
||||
|
||||
// Split text and create embeddings. Store them in a VectorStoreIndex
|
||||
const serviceContext = serviceContextFromDefaults({
|
||||
llm: new OpenAI({ model: "gpt-4" }),
|
||||
});
|
||||
const index = await VectorStoreIndex.fromDocuments([document], {
|
||||
serviceContext,
|
||||
});
|
||||
|
||||
// Query the index
|
||||
const queryEngine = index.asQueryEngine();
|
||||
const response = await queryEngine.query(
|
||||
"What did the author do in college?",
|
||||
);
|
||||
|
||||
// Output response
|
||||
console.log(response.toString());
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -1,15 +0,0 @@
|
||||
import { OpenAI } from "llamaindex";
|
||||
|
||||
(async () => {
|
||||
const llm = new OpenAI({ model: "gpt-4-vision-preview", temperature: 0.1 });
|
||||
|
||||
// complete api
|
||||
const response1 = await llm.complete("How are you?");
|
||||
console.log(response1.message.content);
|
||||
|
||||
// chat api
|
||||
const response2 = await llm.chat([
|
||||
{ content: "Tell me a joke!", role: "user" },
|
||||
]);
|
||||
console.log(response2.message.content);
|
||||
})();
|
||||
@@ -1 +1,2 @@
|
||||
package-lock.json
|
||||
storage
|
||||
|
||||
@@ -1,9 +1,29 @@
|
||||
# Simple Examples
|
||||
|
||||
Make sure to run `npm install` and set your OpenAI environment variable before running these examples.
|
||||
Before running any of the examples, make sure to set your OpenAI environment variable:
|
||||
|
||||
```
|
||||
npm install
|
||||
```bash
|
||||
export OPENAI_API_KEY="sk-..."
|
||||
npx ts-node vectorIndex.ts
|
||||
```
|
||||
|
||||
There are two ways to run the examples, using the latest published version of `llamaindex` or using a local build.
|
||||
|
||||
## Using the latest published version
|
||||
|
||||
Make sure to call `npm install` before running these examples:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
Then run the examples with `ts-node`, for example `npx ts-node vectorIndex.ts`
|
||||
|
||||
## Using the local build
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
pnpm --filter llamaindex build
|
||||
pnpm link ../packages/core
|
||||
```
|
||||
|
||||
Then run the examples with `ts-node`, for example `pnpx ts-node vectorIndex.ts`
|
||||
|
||||
@@ -4,8 +4,6 @@ import { Anthropic } from "llamaindex";
|
||||
const anthropic = new Anthropic();
|
||||
const result = await anthropic.chat([
|
||||
{ content: "You want to talk in rhymes.", role: "system" },
|
||||
{ content: "Hello, world!", role: "user" },
|
||||
{ content: "Hello!", role: "assistant" },
|
||||
{
|
||||
content:
|
||||
"How much wood would a woodchuck chuck if a woodchuck could chuck wood?",
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { ClipEmbedding, similarity, SimilarityType } from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
const clip = new ClipEmbedding();
|
||||
|
||||
// Get text embeddings
|
||||
const text1 = "a car";
|
||||
const textEmbedding1 = await clip.getTextEmbedding(text1);
|
||||
const text2 = "a football match";
|
||||
const textEmbedding2 = await clip.getTextEmbedding(text2);
|
||||
|
||||
// Get image embedding
|
||||
const image =
|
||||
"https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/football-match.jpg";
|
||||
const imageEmbedding = await clip.getImageEmbedding(image);
|
||||
|
||||
// Calc similarity
|
||||
const sim1 = similarity(
|
||||
textEmbedding1,
|
||||
imageEmbedding,
|
||||
SimilarityType.DEFAULT,
|
||||
);
|
||||
const sim2 = similarity(
|
||||
textEmbedding2,
|
||||
imageEmbedding,
|
||||
SimilarityType.DEFAULT,
|
||||
);
|
||||
|
||||
console.log(`Similarity between "${text1}" and the image is ${sim1}`);
|
||||
console.log(`Similarity between "${text2}" and the image is ${sim2}`);
|
||||
}
|
||||
|
||||
main();
|
||||
|
After Width: | Height: | Size: 2.0 MiB |
|
After Width: | Height: | Size: 4.8 MiB |
|
After Width: | Height: | Size: 6.7 MiB |
|
After Width: | Height: | Size: 674 KiB |
|
After Width: | Height: | Size: 30 MiB |
|
After Width: | Height: | Size: 238 KiB |
@@ -0,0 +1,323 @@
|
||||
San Francisco ( SAN frən-SISS-koh; Spanish for 'Saint Francis'), officially the City and County of San Francisco, is the commercial, financial, and cultural center of Northern California. The city proper is the fourth most populous city in California, with 808,437 residents, and the 17th most populous city in the United States as of 2022. The city covers a land area of 46.9 square miles (121 square kilometers) at the end of the San Francisco Peninsula, making it the second-most densely populated large U.S. city after New York City and the fifth-most densely populated U.S. county, behind only four of the five New York City boroughs. Among the 91 U.S. cities proper with over 250,000 residents, San Francisco was ranked first by per capita income and sixth by aggregate income as of 2021. Colloquial nicknames for San Francisco include Frisco, San Fran, The City, and SF (although San Fran is generally not used by locals).Prior to European colonization, the modern city proper was inhabited by the Yelamu, who spoke a language now referred to as Ramaytush Ohlone. On June 29, 1776, settlers from New Spain established the Presidio of San Francisco at the Golden Gate, and the Mission San Francisco de Asís a few miles away, both named for Francis of Assisi. The California Gold Rush of 1849 brought rapid growth, transforming an unimportant hamlet into a busy port, making it the largest city on the West Coast at the time; between 1870 and 1900, approximately one quarter of California's population resided in the city proper. In 1856, San Francisco became a consolidated city-county. After three-quarters of the city was destroyed by the 1906 earthquake and fire, it was quickly rebuilt, hosting the Panama-Pacific International Exposition nine years later. In World War II, it was a major port of embarkation for naval service members shipping out to the Pacific Theater. In 1945, the United Nations Charter was signed in San Francisco, establishing the United Nations before permanently relocating to Manhattan, and in 1951, the Treaty of San Francisco re-established peaceful relations between Japan and the Allied Powers. After the war, the confluence of returning servicemen, significant immigration, liberalizing attitudes, the rise of the beatnik and hippie countercultures, the sexual revolution, the peace movement growing from opposition to United States involvement in the Vietnam War, and other factors led to the Summer of Love and the gay rights movement, cementing San Francisco as a center of liberal activism in the United States.
|
||||
San Francisco and the surrounding San Francisco Bay Area are a global center of economic activity and the arts and sciences, spurred by leading universities, high-tech, healthcare, finance, insurance, real estate, and professional services sectors. As of 2020, the metropolitan area, with 6.7 million residents, ranked 5th by GDP ($874 billion) and 2nd by GDP per capita ($131,082) across the OECD countries, ahead of global cities like Paris, London, and Singapore. San Francisco anchors the 13th most populous metropolitan statistical area in the United States with 4.6 million residents, and the fourth-largest by aggregate income and economic output, with a GDP of $669 billion in 2021. The wider San Jose–San Francisco–Oakland Combined Statistical Area is the fifth-most populous, with 9.5 million residents, and the third-largest by economic output, with a GDP of $1.1 trillion in 2021. In the same year, San Francisco proper had a GDP of $236.4 billion, and a GDP per capita of $289,990. San Francisco was ranked fifth in the world and second in the United States on the Global Financial Centres Index as of March 2023. The city houses the headquarters of numerous companies inside and outside of technology, including Wells Fargo, Salesforce, Uber, Airbnb, Twitter, Levi's, Gap, Dropbox, and Lyft.
|
||||
In 2022, San Francisco had over 1.7 million international visitors - the fifth-most visited city from abroad in the United States after New York City, Miami, Orlando, and Los Angeles - and approximately 20 million domestic visitors for a total of 21.9 million visitors. The city is known for its steep rolling hills and eclectic mix of architecture across varied neighborhoods, as well as its cool summers, fog, and landmarks, including the Golden Gate Bridge, cable cars, Alcatraz, along with the Chinatown and Mission districts. The city is home to a number of educational and cultural institutions, such as the University of California, San Francisco, the University of San Francisco, San Francisco State University, the San Francisco Conservatory of Music, the de Young Museum, the San Francisco Museum of Modern Art, the San Francisco Symphony, the San Francisco Ballet, the San Francisco Opera, the SFJAZZ Center, and the California Academy of Sciences. Two major league sports teams, the San Francisco Giants and the Golden State Warriors, play their home games within San Francisco proper. San Francisco's main international airport offers flights to over 125 destinations while a light rail and bus network, in tandem with the BART and Caltrain systems, connects nearly every part of San Francisco with the wider region.
|
||||
|
||||
|
||||
== Etymology ==
|
||||
|
||||
San Francisco, which is Spanish for "Saint Francis", takes its name from Mission San Francisco de Asís, which in turn was named after Saint Francis of Assisi. The mission received its name in 1776, when it was founded by the Spanish under the leadership of Padre Francisco Palóu. The city has officially been known as San Francisco since 1847, when Washington Allon Bartlett, then serving as the city's alcalde, renamed it from Yerba Buena (Spanish for "Good Herb"), which had been name used throughout the Spanish and Mexican eras since approximately 1776. The name Yerba Buena continues to be used in locations in the city, such as on Yerba Buena Island and in the Yerba Buena Center for the Arts and Yerba Buena Gardens.
|
||||
While residents outside the San Francisco Bay Area use nicknames including Frisco, San Fran, and SF, local residents in the Bay Area sometimes refer to San Francisco as "the City"; for residents of San Francisco living in the more suburban parts of the city, "the City" generally refers to the more densely populated downtown areas around Market Street. Its use, or lack thereof, is a common way for locals to distinguish long-time residents from tourists and recent arrivals. "San Fran" and "Frisco" are sometimes considered controversial as nicknames among San Francisco residents.
|
||||
|
||||
|
||||
== History ==
|
||||
|
||||
|
||||
=== Indigenous history ===
|
||||
The earliest archeological evidence of human habitation of the territory of San Francisco dates to 3000 BCE. The Yelamu group of the Ramaytush people resided in a few small villages when an overland Spanish exploration party arrived on November 2, 1769, the first documented European visit to San Francisco Bay. The Ohlone name for San Francisco was Ahwaste, meaning, "place at the bay". The arrival of Spanish colonists, and the implementation of their Mission system, marked the beginning of the genocide of the Ramaytush people, and the end of their language and culture.
|
||||
|
||||
|
||||
=== Spanish era ===
|
||||
The Spanish Empire claimed San Francisco as part of Las Californias, a province of the Viceroyalty of New Spain. The Spanish first arrived in what is now San Francisco on November 2, 1769, when the Portolá expedition led by Don Gaspar de Portolá and Juan Crespí arrived at San Francisco Bay. Having noted the strategic benefits of the area due to its large natural harbor, the Spanish dispatched Pedro Fages in 1770 to find a more direct route to the San Francisco Peninsula from Monterey, which would become part of the El Camino Real route. By 1774, Juan Bautista de Anza had arrived to the area to select the sites for a mission and presidio. The first European maritime presence in San Francisco Bay occurred on August 5, 1775, when the Spanish ship San Carlos, commanded by Juan Manuel de Ayala, became the first ship to anchor in the bay.Soon after, on March 28, 1776, Anza established the Presidio of San Francisco. On October 9, Mission San Francisco de Asís, also known as Mission Dolores, was founded by Padre Francisco Palóu. In 1794, the Presidio established the Castillo de San Joaquín, a fortification on the southern side of the Golden Gate, which later came to be known as Fort Point.
|
||||
In 1804, the province of Alta California was created, which included San Francisco. At its peak in 1810–1820, the average population at the Mission Dolores settlement was about 1,100 people.
|
||||
|
||||
|
||||
=== Mexican era ===
|
||||
In 1821, the Californias were ceded to Mexico by Spain. The extensive California mission system gradually lost its influence during the period of Mexican rule. Agricultural land became largely privatized as ranchos, as was occurring in other parts of California. Coastal trade increased, including a half-dozen barques from various Atlantic ports which regularly sailed in California waters.Yerba Buena (after a native herb), a trading post with settlements between the Presidio and Mission grew up around the Plaza de Yerba Buena. The plaza was later renamed Portsmouth Square (now located in the city's Chinatown and Financial District). The Presidio was commanded in 1833 by Captain Mariano G. Vallejo.In 1833, Juana Briones de Miranda built her rancho near El Polín Spring, founding the first civilian household in San Francisco, which had previously only been comprised by the military settlement at the Presidio and the religious settlement at Mission Dolores.In 1834, Francisco de Haro became the first Alcalde of Yerba Buena. De Haro was a native of Mexico, from that nation's west coast city of Compostela, Nayarit. A land survey of Yerba Buena was made by the Swiss immigrant Jean Jacques Vioget as prelude to the city plan. The second Alcalde José Joaquín Estudillo was a Californio from a prominent Monterey family. In 1835, while in office, he approved the first land grant in Yerba Buena: to William Richardson, a naturalized Mexican citizen of English birth. Richardson had arrived in San Francisco aboard a whaling ship in 1822. In 1825, he married Maria Antonia Martinez, eldest daughter of the Californio Ygnacio Martínez.
|
||||
Yerba Buena began to attract American and European settlers; an 1842 census listed 21 residents (11%) born in the United States or Europe, as well as one Filipino merchant.
|
||||
Following the Bear Flag Revolt in Sonoma and the beginning of the U.S. Conquest of California, American forces under the command of John B. Montgomery captured Yerba Buena on July 9, 1846, with little resistance from the local Californio population. At the end of the month, the Brooklyn arrived with a group of Mormon settlers, who had departed New York City six months earlier. Following the capture, U.S. forces appointed both José de Jesús Noé and Washington Allon Bartlett to serve as co-alcaldes (mayors), while the conquest continued on in the rest of California. Following the Treaty of Guadalupe Hidalgo in 1848, Alta California was ceded from Mexico to the United States.
|
||||
|
||||
|
||||
=== Post-Conquest era ===
|
||||
Despite its attractive location as a port and naval base, post-Conquest San Francisco was still a small settlement with inhospitable geography. Its 1847 population was said to be 459.The California Gold Rush brought a flood of treasure seekers (known as "forty-niners", as in "1849"). With their sourdough bread in tow, prospectors accumulated in San Francisco over rival Benicia, raising the population from 1,000 in 1848 to 25,000 by December 1849. The promise of wealth was so strong that crews on arriving vessels deserted and rushed off to the gold fields, leaving behind a forest of masts in San Francisco harbor. Some of these approximately 500 abandoned ships were used at times as storeships, saloons, and hotels; many were left to rot, and some were sunk to establish title to the underwater lot. By 1851, the harbor was extended out into the bay by wharves while buildings were erected on piles among the ships. By 1870, Yerba Buena Cove had been filled to create new land. Buried ships are occasionally exposed when foundations are dug for new buildings.California was quickly granted statehood in 1850, and the U.S. military built Fort Point at the Golden Gate and a fort on Alcatraz Island to secure the San Francisco Bay. San Francisco County was one of the state's 18 original counties established at California statehood in 1850. Until 1856, San Francisco's city limits extended west to Divisadero Street and Castro Street, and south to 20th Street. In 1856, the California state government divided the county. A straight line was then drawn across the tip of the San Francisco Peninsula just north of San Bruno Mountain. Everything south of the line became the new San Mateo County while everything north of the line became the new consolidated City and County of San Francisco.
|
||||
Entrepreneurs sought to capitalize on the wealth generated by the Gold Rush. Silver discoveries, including the Comstock Lode in Nevada in 1859, further drove rapid population growth. With hordes of fortune seekers streaming through the city, lawlessness was common, and the Barbary Coast section of town gained notoriety as a haven for criminals, prostitution, bootlegging, and gambling. Early winners were the banking industry, with the founding of Wells Fargo in 1852 and the Bank of California in 1864.
|
||||
Development of the Port of San Francisco and the establishment in 1869 of overland access to the eastern U.S. rail system via the newly completed Pacific Railroad (the construction of which the city only reluctantly helped support) helped make the Bay Area a center for trade. Catering to the needs and tastes of the growing population, Levi Strauss opened a dry goods business and Domingo Ghirardelli began manufacturing chocolate. Chinese immigrants made the city a polyglot culture, drawn to "Old Gold Mountain", creating the city's Chinatown quarter. By 1880, Chinese made up 9.3% of the population.
|
||||
The first cable cars carried San Franciscans up Clay Street in 1873. The city's sea of Victorian houses began to take shape, and civic leaders campaigned for a spacious public park, resulting in plans for Golden Gate Park. San Franciscans built schools, churches, theaters, and all the hallmarks of civic life. The Presidio developed into the most important American military installation on the Pacific coast. By 1890, San Francisco's population approached 300,000, making it the eighth-largest city in the United States at the time. Around 1901, San Francisco was a major city known for its flamboyant style, stately hotels, ostentatious mansions on Nob Hill, and a thriving arts scene. The first North American plague epidemic was the San Francisco plague of 1900–1904.
|
||||
|
||||
|
||||
=== 1906 earthquake and interwar era ===
|
||||
At 5:12 am on April 18, 1906, a major earthquake struck San Francisco and northern California. As buildings collapsed from the shaking, ruptured gas lines ignited fires that spread across the city and burned out of control for several days. With water mains out of service, the Presidio Artillery Corps attempted to contain the inferno by dynamiting blocks of buildings to create firebreaks. More than three-quarters of the city lay in ruins, including almost all of the downtown core. Contemporary accounts reported that 498 people died, though modern estimates put the number in the several thousands. More than half of the city's population of 400,000 was left homeless. Refugees settled temporarily in makeshift tent villages in Golden Gate Park, the Presidio, on the beaches, and elsewhere. Many fled permanently to the East Bay. Jack London is remembered for having famously eulogized the earthquake: "Not in history has a modern imperial city been so completely destroyed. San Francisco is gone."
|
||||
Rebuilding was rapid and performed on a grand scale. Rejecting calls to completely remake the street grid, San Franciscans opted for speed. Amadeo Giannini's Bank of Italy, later to become Bank of America, provided loans for many of those whose livelihoods had been devastated. The influential San Francisco Planning and Urban Research Association or SPUR was founded in 1910 to address the quality of housing after the earthquake. The earthquake hastened development of western neighborhoods that survived the fire, including Pacific Heights, where many of the city's wealthy rebuilt their homes. In turn, the destroyed mansions of Nob Hill became grand hotels. City Hall rose again in the Beaux Arts style, and the city celebrated its rebirth at the Panama–Pacific International Exposition in 1915.
|
||||
During this period, San Francisco built some of its most important infrastructure. Civil Engineer Michael O'Shaughnessy was hired by San Francisco Mayor James Rolph as chief engineer for the city in September 1912 to supervise the construction of the Twin Peaks Reservoir, the Stockton Street Tunnel, the Twin Peaks Tunnel, the San Francisco Municipal Railway, the Auxiliary Water Supply System, and new sewers. San Francisco's streetcar system, of which the J, K, L, M, and N lines survive today, was pushed to completion by O'Shaughnessy between 1915 and 1927. It was the O'Shaughnessy Dam, Hetch Hetchy Reservoir, and Hetch Hetchy Aqueduct that would have the largest effect on San Francisco. An abundant water supply enabled San Francisco to develop into the city it has become today.
|
||||
|
||||
In ensuing years, the city solidified its standing as a financial capital; in the wake of the 1929 stock market crash, not a single San Francisco-based bank failed. Indeed, it was at the height of the Great Depression that San Francisco undertook two great civil engineering projects, simultaneously constructing the San Francisco–Oakland Bay Bridge and the Golden Gate Bridge, completing them in 1936 and 1937, respectively. It was in this period that the island of Alcatraz, a former military stockade, began its service as a federal maximum security prison, housing notorious inmates such as Al Capone, and Robert Franklin Stroud, the Birdman of Alcatraz. San Francisco later celebrated its regained grandeur with a World's fair, the Golden Gate International Exposition in 1939–40, creating Treasure Island in the middle of the bay to house it.
|
||||
|
||||
|
||||
=== Contemporary era ===
|
||||
|
||||
During World War II, the city-owned Sharp Park in Pacifica was used as an internment camp to detain Japanese Americans. Hunters Point Naval Shipyard became a hub of activity, and Fort Mason became the primary port of embarkation for service members shipping out to the Pacific Theater of Operations. The explosion of jobs drew many people, especially African Americans from the South, to the area. After the end of the war, many military personnel returning from service abroad and civilians who had originally come to work decided to stay. The United Nations Charter creating the United Nations was drafted and signed in San Francisco in 1945 and, in 1951, the Treaty of San Francisco re-established peaceful relations between Japan and the Allied Powers.Urban planning projects in the 1950s and 1960s involved widespread destruction and redevelopment of west-side neighborhoods and the construction of new freeways, of which only a series of short segments were built before being halted by citizen-led opposition. The onset of containerization made San Francisco's small piers obsolete, and cargo activity moved to the larger Port of Oakland. The city began to lose industrial jobs and turned to tourism as the most important segment of its economy. The suburbs experienced rapid growth, and San Francisco underwent significant demographic change, as large segments of the white population left the city, supplanted by an increasing wave of immigration from Asia and Latin America. From 1950 to 1980, the city lost over 10 percent of its population.
|
||||
|
||||
Over this period, San Francisco became a magnet for America's counterculture movement. Beat Generation writers fueled the San Francisco Renaissance and centered on the North Beach neighborhood in the 1950s. Hippies flocked to Haight-Ashbury in the 1960s, reaching a peak with the 1967 Summer of Love. In 1974, the Zebra murders left at least 16 people dead. In the 1970s, the city became a center of the gay rights movement, with the emergence of The Castro as an urban gay village, the election of Harvey Milk to the Board of Supervisors, and his assassination, along with that of Mayor George Moscone, in 1978.Bank of America, now based in Charlotte, North Carolina, was founded in San Francisco; the bank completed 555 California Street in 1969. The Transamerica Pyramid was completed in 1972, igniting a wave of "Manhattanization" that lasted until the late 1980s, a period of extensive high-rise development downtown. The 1980s also saw a dramatic increase in the number of homeless people in the city, an issue that remains today, despite many attempts to address it.
|
||||
The 1989 Loma Prieta earthquake caused destruction and loss of life throughout the Bay Area. In San Francisco, the quake severely damaged structures in the Marina and South of Market districts and precipitated the demolition of the damaged Embarcadero Freeway and much of the damaged Central Freeway, allowing the city to reclaim The Embarcadero as its historic downtown waterfront and revitalizing the Hayes Valley neighborhood.The two recent decades have seen booms driven by the internet industry. During the dot-com boom of the late 1990s, startup companies invigorated the San Francisco economy. Large numbers of entrepreneurs and computer application developers moved into the city, followed by marketing, design, and sales professionals, changing the social landscape as once poorer neighborhoods became increasingly gentrified. Demand for new housing and office space ignited a second wave of high-rise development, this time in the South of Market district. By 2000, the city's population reached new highs, surpassing the previous record set in 1950. When the bubble burst in 2001 and again in 2023, many of these companies folded and their employees were laid off. Yet high technology and entrepreneurship remain mainstays of the San Francisco economy. By the mid-2000s (decade), the social media boom had begun, with San Francisco becoming a popular location for tech offices and a common place to live for people employed in Silicon Valley companies such as Apple and Google.The early 2020s featured an exodus of tech companies from Downtown San Francisco, in the wake of the Covid-19 pandemic; although San Francisco has since been widely characterized in the media to have entered an indefinite economic doom loop, other sources have refuted this broad-based characterization of the city as a whole, asserting that the issues of concern are restricted primarily to the urban core of San Francisco.The Ferry Station Post Office Building, Armour & Co. Building, Atherton House, and YMCA Hotel are historic buildings among dozens of historical landmarks in the city, according to the National Register of Historic Places listings in San Francisco.
|
||||
|
||||
|
||||
== Geography ==
|
||||
San Francisco is located on the West Coast of the United States, at the north end of the San Francisco Peninsula and includes significant stretches of the Pacific Ocean and San Francisco Bay within its boundaries. Several picturesque islands—Alcatraz, Treasure Island and the adjacent Yerba Buena Island, and small portions of Alameda Island, Red Rock Island, and Angel Island—are part of the city. Also included are the uninhabited Farallon Islands, 27 miles (43 km) offshore in the Pacific Ocean. The mainland within the city limits roughly forms a "seven-by-seven-mile square", a common local colloquialism referring to the city's shape, though its total area, including water, is nearly 232 square miles (600 km2).
|
||||
There are more than 50 hills within the city limits. Some neighborhoods are named after the hill on which they are situated, including Nob Hill, Potrero Hill, and Russian Hill.
|
||||
Near the geographic center of the city, southwest of the downtown area, are a series of less densely populated hills. Twin Peaks, a pair of hills forming one of the city's highest points, forms an overlook spot. San Francisco's tallest hill, Mount Davidson, is 928 feet (283 m) high and is capped with a 103-foot (31 m) tall cross built in 1934. Dominating this area is Sutro Tower, a large red and white radio and television transmission tower reaching 1,811 ft (552 m) above sea level.
|
||||
|
||||
The nearby San Andreas and Hayward Faults are responsible for much earthquake activity, although neither physically passes through the city itself. The San Andreas Fault caused the earthquakes in 1906 and 1989. Minor earthquakes occur on a regular basis. The threat of major earthquakes plays a large role in the city's infrastructure development. The city constructed an auxiliary water supply system and has repeatedly upgraded its building codes, requiring retrofits for older buildings and higher engineering standards for new construction. However, there are still thousands of smaller buildings that remain vulnerable to quake damage. USGS has released the California earthquake forecast which models earthquake occurrence in California.San Francisco's shoreline has grown beyond its natural limits. Entire neighborhoods such as the Marina, Mission Bay, and Hunters Point, as well as large sections of the Embarcadero, sit on areas of landfill. Treasure Island was constructed from material dredged from the bay as well as material resulting from the excavation of the Yerba Buena Tunnel through Yerba Buena Island during the construction of the Bay Bridge. Such land tends to be unstable during earthquakes. The resulting soil liquefaction causes extensive damage to property built upon it, as was evidenced in the Marina district during the 1989 Loma Prieta earthquake. A few natural lakes and creeks (Lake Merced, Mountain Lake, Pine Lake, Lobos Creek, El Polin Spring) are within parks and remain protected in what is essentially their original form, but most of the city's natural watercourses, such as Islais Creek and Mission Creek, have been partially or completely culverted and built over. Since the 1990s, however, the Public Utilities Commission has been studying proposals to daylight or restore some creeks.
|
||||
|
||||
|
||||
=== Neighborhoods ===
|
||||
|
||||
The historic center of San Francisco is the northeast quadrant of the city anchored by Market Street and the waterfront. Here the Financial District is centered, with Union Square, the principal shopping and hotel district, and the Tenderloin nearby. Cable cars carry riders up steep inclines to the summit of Nob Hill, once the home of the city's business tycoons, and down to the waterfront tourist attractions of Fisherman's Wharf, and Pier 39, where many restaurants feature Dungeness crab from a still-active fishing industry. Also in this quadrant are Russian Hill, a residential neighborhood with the famously crooked Lombard Street; North Beach, the city's Little Italy and the former center of the Beat Generation; and Telegraph Hill, which features Coit Tower. Abutting Russian Hill and North Beach is San Francisco's Chinatown, the oldest Chinatown in North America. The South of Market, which was once San Francisco's industrial core, has seen significant redevelopment following the construction of Oracle Park and an infusion of startup companies. New skyscrapers, live-work lofts, and condominiums dot the area. Further development is taking place just to the south in Mission Bay area, a former railroad yard, which now has a second campus of the University of California, San Francisco and Chase Center, which opened in 2019 as the new home of the Golden State Warriors.West of downtown, across Van Ness Avenue, lies the large Western Addition neighborhood, which became established with a large African American population after World War II. The Western Addition is usually divided into smaller neighborhoods including Hayes Valley, the Fillmore, and Japantown, which was once the largest Japantown in North America but suffered when its Japanese American residents were forcibly removed and interned during World War II. The Western Addition survived the 1906 earthquake with its Victorians largely intact, including the famous "Painted Ladies", standing alongside Alamo Square. To the south, near the geographic center of the city is Haight-Ashbury, famously associated with 1960s hippie culture. The Haight is now home to some expensive boutiques and a few controversial chain stores, although it still retains some bohemian character.
|
||||
|
||||
North of the Western Addition is Pacific Heights, an affluent neighborhood that features the homes built by wealthy San Franciscans in the wake of the 1906 earthquake. Directly north of Pacific Heights facing the waterfront is the Marina, a neighborhood popular with young professionals that was largely built on reclaimed land from the Bay.In the southeast quadrant of the city is the Mission District—populated in the 19th century by Californios and working-class immigrants from Germany, Ireland, Italy, and Scandinavia. In the 1910s, a wave of Central American immigrants settled in the Mission and, in the 1950s, immigrants from Mexico began to predominate. In recent years, gentrification has changed the demographics of parts of the Mission from Latino, to twenty-something professionals. Noe Valley to the southwest and Bernal Heights to the south are both increasingly popular among young families with children. East of the Mission is the Potrero Hill neighborhood, a mostly residential neighborhood that features sweeping views of downtown San Francisco. West of the Mission, the area historically known as Eureka Valley, now popularly called the Castro, was once a working-class Scandinavian and Irish area. It has become North America's first gay village, and is now the center of gay life in the city. Located near the city's southern border, the Excelsior District is one of the most ethnically diverse neighborhoods in San Francisco. The Bayview-Hunters Point in the far southeast corner of the city is one of the poorest neighborhoods, though the area has been the focus of several revitalizing and urban renewal projects.
|
||||
|
||||
The construction of the Twin Peaks Tunnel in 1918 connected southwest neighborhoods to downtown via streetcar, hastening the development of West Portal, and nearby affluent Forest Hill and St. Francis Wood. Further west, stretching all the way to the Pacific Ocean and north to Golden Gate Park lies the vast Sunset District, a large middle-class area with a predominantly Asian population.The northwestern quadrant of the city contains the Richmond, a mostly middle-class neighborhood north of Golden Gate Park, home to immigrants from other parts of Asia as well as many Russian and Ukrainian immigrants. Together, these areas are known as The Avenues. These two districts are each sometimes further divided into two regions: the Outer Richmond and Outer Sunset can refer to the more western portions of their respective district and the Inner Richmond and Inner Sunset can refer to the more eastern portions.
|
||||
Many piers remained derelict for years until the demolition of the Embarcadero Freeway reopened the downtown waterfront, allowing for redevelopment. The centerpiece of the port, the Ferry Building, while still receiving commuter ferry traffic, has been restored and redeveloped as a gourmet marketplace.
|
||||
|
||||
|
||||
=== Climate ===
|
||||
San Francisco has a warm-summer Mediterranean climate (Köppen Csb), characteristic of California's coast, with moist, mild winters and dry summers. San Francisco's weather is strongly influenced by the cool currents of the Pacific Ocean on the west side of the city, and the water of San Francisco Bay to the north and east. This moderates temperature swings and produces a remarkably mild year-round climate with little seasonal temperature variation.Among major U.S. cities, San Francisco has the coolest daily mean, maximum, and minimum temperatures for June, July, and August.
|
||||
During the summer, rising hot air in California's interior valleys creates a low-pressure area that draws winds from the North Pacific High through the Golden Gate, which creates the city's characteristic cool winds and fog. The fog is less pronounced in eastern neighborhoods and during the late summer and early fall. As a result, the year's warmest month, on average, is September, and on average, October is warmer than July, especially in daytime.
|
||||
Temperatures reach or exceed 80 °F (27 °C) on an average of only 21 and 23 days a year at downtown and San Francisco International Airport (SFO), respectively. The dry period of May to October is mild to warm, with the normal monthly mean temperature peaking in September at 62.7 °F (17.1 °C). The rainy period of November to April is slightly cooler, with the normal monthly mean temperature reaching its lowest in January at 51.3 °F (10.7 °C). On average, there are 73 rainy days a year, and annual precipitation averages 23.65 inches (601 mm). Variation in precipitation from year to year is high. Above-average rain years are often associated with warm El Niño conditions in the Pacific while dry years often occur in cold water La Niña periods. In 2013 (a "La Niña" year), a record low 5.59 in (142 mm) of rainfall was recorded at downtown San Francisco, where records have been kept since 1849. Snowfall in the city is very rare, with only 10 measurable accumulations recorded since 1852, most recently in 1976 when up to 5 inches (13 cm) fell on Twin Peaks.
|
||||
The highest recorded temperature at the official National Weather Service downtown observation station was 106 °F (41 °C) on September 1, 2017. During that hot spell, the warmest ever night of 71 °F (22 °C) was also recorded. The lowest recorded temperature was 27 °F (−3 °C) on December 11, 1932. The National Weather Service provides a helpful visual aid graphing the information in the table below to display visually by month the annual typical temperatures, the past year's temperatures, and record temperatures.During an average year between 1991 and 2020, San Francisco recorded a warmest night at 64 °F (18 °C) and a coldest day at 49 °F (9 °C). The coldest daytime high since the station's opening in 1945 was recorded in December 1972 at 37 °F (3 °C).As a coastal city, San Francisco will be heavily affected by climate change. As of 2021, sea levels are projected to rise by as much as 5 feet (1.5 m), resulting in periodic flooding, rising groundwater levels, and lowland floods from more severe storms.San Francisco falls under the USDA 10b Plant hardiness zone, though some areas, particularly downtown, border zone 11a.
|
||||
|
||||
|
||||
==== Time Series ====
|
||||
See or edit raw graph data.
|
||||
|
||||
|
||||
=== Ecology ===
|
||||
Historically, tule elk were present in San Francisco County, based on archeological evidence of elk remains in at least five different Native American shellmounds: at Hunter's Point, Fort Mason, Stevenson Street, Market Street, and Yerba Buena. Perhaps the first historical observer record was from the De Anza Expedition on March 23, 1776. Herbert Eugene Bolton wrote about the expedition camp at Mountain Lake, near the southern end of today's Presidio: "Round about were grazing deer, and scattered here and there were the antlers of large elk." Also, when Richard Henry Dana Jr. visited San Francisco Bay in 1835, he wrote about vast elk herds near the Golden Gate: on December 27 "...we came to anchor near the mouth of the bay, under a high and beautifully sloping hill, upon which herds of hundreds and hundreds of red deer [note: "red deer" is the European term for "elk"], and the stag, with his high branching antlers, were bounding about...", although it is not clear whether this was the Marin side or the San Francisco side.
|
||||
|
||||
|
||||
== Demographics ==
|
||||
|
||||
The 2020 United States census showed San Francisco's population to be 873,965, an increase of 8.5% from the 2010 census. With roughly one-quarter the population density of Manhattan, San Francisco is the second-most densely populated large American city, behind only New York City among cities greater than 200,000 population, and the fifth-most densely populated U.S. county, following only four of the five New York City boroughs.
|
||||
San Francisco is part of the five-county San Francisco–Oakland–Hayward, CA Metropolitan Statistical Area, a region of 4.7 million people (13th most populous in the U.S.), and has served as its traditional demographic focal point. It is also part of the greater 14-county San Jose-San Francisco-Oakland, CA Combined Statistical Area, whose population is over 9.6 million, making it the fifth-largest in the United States as of 2018.
|
||||
|
||||
|
||||
=== Race, ethnicity, religion, and languages ===
|
||||
San Francisco has a majority minority population, as non-Hispanic whites comprise less than half of the population, 41.9%, down from 92.5% in 1940. As of the 2020 census, the racial makeup and population of San Francisco included: 361,382 Whites (41.3%), 296,505 Asians (33.9%), 46,725 African Americans (5.3%), 86,233 Multiracial Americans (9.9%), 6,475 Native Americans and Alaska Natives (0.7%), 3,476 Native Hawaiians and other Pacific Islanders (0.4%) and 73,169 persons of other races (8.4%). There were 136,761 Hispanics or Latinos of any race (15.6%).
|
||||
In 2010, residents of Chinese ethnicity constituted the largest single ethnic minority group in San Francisco at 21% of the population; other large Asian groups include Filipinos (5%) and Vietnamese (2%), with Japanese, Koreans and many other Asian and Pacific Islander groups represented in the city.
|
||||
The population of Chinese ancestry is most heavily concentrated in Chinatown and the Sunset and Richmond Districts. Filipinos are most concentrated in SoMa and the Crocker-Amazon; the latter neighborhood shares a border with Daly City, which has one of the highest concentrations of Filipinos in North America. The Tenderloin District is home to a large portion of the city's Vietnamese population as well as businesses and restaurants, which is known as the city's Little Saigon.The principal Hispanic groups in the city were those of Mexican (7%) and Salvadoran (2%) ancestry. The Hispanic population is most heavily concentrated in the Mission District, Tenderloin District, and Excelsior District. The city's percentage of Hispanic residents is less than half of that of the state.
|
||||
African Americans constitute 6% of San Francisco's population, a percentage similar to that for California as a whole. The majority of the city's black population reside within the neighborhoods of Bayview-Hunters Point, Visitacion Valley, and the Fillmore District. There are smaller, yet sizeable Black communities in Diamond Heights, Glen Park, and Mission District.
|
||||
The city has long been home to a significant Jewish community, today Jewish Americans make up 10% (80,000) of the city's population as of 2018. The Jewish population of San Francisco is relatively young compared to many other major cities, and at 10% of the population, San Francisco has the third-largest Jewish community in terms of percentages after New York City, and Los Angeles, respectively. The Jewish community is one of the largest minority groups in the city and is scattered throughout the city, but the Richmond District is home to an ethnic enclave of mostly Russian Jews. The Fillmore District was formerly a mostly Jewish neighborhood from the 1920s until the 1970s, when many of its Jewish residents moved to other neighborhoods of the city as well as the suburbs of nearby Marin County.
|
||||
According to a 2018 study by the Jewish Community Federation of San Francisco, Jews make up 10% (80,000) of the city's population, making Judaism the second-largest religion in San Francisco after Christianity. A prior 2014 study by the Pew Research Center, the largest religious groupings in San Francisco's metropolitan area are Christians (48%), followed by those of no religion (35%), Hindus (5%), Jews (3%), Buddhists (2%), Muslims (1%) and a variety of other religions have smaller followings. According to the same study by the Pew Research Center, about 20% of residents in the area are Protestant, and 25% professing Roman Catholic beliefs. Meanwhile, 10% of the residents in metropolitan San Francisco identify as agnostics, while 5% identify as atheists.As of 2010, 55% (411,728) of San Francisco residents spoke only English at home, while 19% (140,302) spoke a variety of Chinese (mostly Taishanese and Cantonese), 12% (88,147) Spanish, 3% (25,767) Tagalog, and 2% (14,017) Russian. In total, 45% (342,693) of San Francisco's population spoke a language at home other than English.
|
||||
|
||||
|
||||
==== Ethnic clustering ====
|
||||
San Francisco has several prominent Chinese, Mexican, and Filipino neighborhoods including Chinatown and the Mission District. Research collected on the immigrant clusters in the city show that more than half of the Asian population in San Francisco is either Chinese-born (40.3%) or Philippine-born (13.1%), and of the Mexican population 21% were Mexican-born, meaning these are people who recently immigrated to the United States. Between the years of 1990 and 2000, the number of foreign-born residents increased from 33% to nearly 40%. During this same time period, the San Francisco metropolitan area received 850,000 immigrants, ranking third in the United States after Los Angeles and New York.
|
||||
|
||||
|
||||
=== Education, households, and income ===
|
||||
Of all major cities in the United States, San Francisco has the second-highest percentage of residents with a college degree, second only to Seattle. Over 44% of adults have a bachelor's or higher degree.
|
||||
San Francisco had the highest rate at 7,031 per square mile, or over 344,000 total graduates in the city's 46.7 square miles (121 km2).San Francisco has the highest estimated percentage of gay and lesbian individuals of any of the 50 largest U.S. cities, at 15%.
|
||||
San Francisco also has the highest percentage of same-sex households of any American county, with the Bay Area having a higher concentration than any other metropolitan area.San Francisco ranks third of American cities in median household income with a 2007 value of $65,519. Median family income is $81,136.
|
||||
An emigration of middle-class families has left the city with a lower proportion of children than any other large American city, with the dog population cited as exceeding the child population of 115,000, in 2018.
|
||||
The city's poverty rate is 12%, lower than the national average.Homelessness has been a chronic problem for San Francisco since the early 1970s.
|
||||
The city is believed to have the highest number of homeless inhabitants per capita of any major U.S. city.There are 345,811 households in the city, out of which: 133,366 households (39%) were individuals, 109,437 (32%) were opposite-sex married couples, 63,577 (18%) had children under the age of 18 living in them, 21,677 (6%) were unmarried opposite-sex partnerships, and 10,384 (3%) were same-sex married couples or partnerships. The average household size was 2.26; the average family size was 3.11. 452,986 people (56%) lived in rental housing units, and 327,985 people (41%) lived in owner-occupied housing units.
|
||||
The median age of the city population is 38 years.
|
||||
San Francisco declared itself a sanctuary city in 1989, and city officials strengthened the stance in 2013 with its 'Due Process for All' ordinance. The law declared local authorities could not hold immigrants for immigration offenses if they had no violent felonies on their records and did not currently face charges." The city issues a Resident ID Card regardless of the applicant's immigration status.
|
||||
|
||||
|
||||
=== Homelessness ===
|
||||
|
||||
Homelessness in San Francisco emerged as a major issue in the late 20th century and remains a growing problem in modern times.8,035 homeless people were counted in San Francisco's 2019 point-in-time street and shelter count. This was an increase of more than 17% over the 2017 count of 6,858 people. 5,180 of the people were living unsheltered on the streets and in parks. 26% of respondents in the 2019 count identified job loss as the primary cause of their homelessness, 18% cited alcohol or drug use, and 13% cited being evicted from their residence.
|
||||
The city of San Francisco has been dramatically increasing its spending to service the growing population homelessness crisis: spending jumped by $241 million in 2016–17 to total $275 million, compared to a budget of just $34 million the previous year. In 2017–18 the budget for combatting homelessness stood at $305 million. In the 2019–2020 budget year, the city budgeted $368 million for homelessness services. In the proposed 2020–2021 budget the city budgeted $850 million for homelessness services.In January 2018 a United Nations special rapporteur on homelessness, Leilani Farha, stated that she was "completely shocked" by San Francisco's homelessness crisis during a visit to the city. She compared the "deplorable conditions" of the homeless camps she witnessed on San Francisco's streets to those she had seen in Mumbai. In May 2020, San Francisco officially sanctioned homeless encampments.
|
||||
|
||||
|
||||
=== Crime ===
|
||||
|
||||
In 2011, 50 murders were reported, which is 6.1 per 100,000 people. There were about 134 rapes, 3,142 robberies, and about 2,139 assaults. There were about 4,469 burglaries, 25,100 thefts, and 4,210 motor vehicle thefts. The Tenderloin area has the highest crime rate in San Francisco: 70% of the city's violent crimes, and around one-fourth of the city's murders, occur in this neighborhood. The Tenderloin also sees high rates of drug abuse, gang violence, and prostitution. Another area with high crime rates is the Bayview-Hunters Point area. In the first six months of 2015 there were 25 murders compared to 14 in the first six months of 2014. However, the murder rate is still much lower than in past decades. That rate, though, did rise again by the close of 2016. According to the San Francisco Police Department, there were 59 murders in the city in 2016, an annual total that marked a 13.5% increase in the number of homicides (52) from 2015. The city has also gained a reputation for car break-ins, with over 19,000 car break-ins occurring in 2021.During the first half of 2018, human feces on San Francisco sidewalks were the second-most-frequent complaint of city residents, with about 65 calls per day. The city has formed a "poop patrol" to attempt to combat the problem.
|
||||
San Francisco is a center of sexual slavery.In January 2022, CBS News reported that a single suspect was "responsible for more than half of all reported hate crimes against the API community in San Francisco last year," and that he "was allowed to be out of custody despite the number of charges against him."Several street gangs have operated in the city over the decades, including MS-13, the Sureños and Norteños in the Mission District. In 2008, a MS-13 member killed three family members as they were arriving home in the city's Excelsior District. His victims had no relationship with him, nor did they have any known gang or street crime involvement.African-American street gangs familiar in other cities, including the Bloods, Crips and their sets, have struggled to establish footholds in San Francisco, while police and prosecutors have been accused of liberally labeling young African-American males as gang members. However, gangs founded in San Francisco with majority Black memberships have made their presence in the city.
|
||||
Criminal gangs with shotcallers in China, including Triad groups such as the Wo Hop To, have been reported active in San Francisco.
|
||||
|
||||
|
||||
== Economy ==
|
||||
|
||||
San Francisco has a diversified service economy, with employment spread across a wide range of professional services, including tourism, financial services, and (increasingly) high technology. In 2016, approximately 27% of workers were employed in professional business services; 14% in leisure and hospitality; 13% in government services; 12% in education and health care; 11% in trade, transportation, and utilities; and 8% in financial activities. In 2019, GDP in the five-county San Francisco metropolitan area grew 3.8% in real terms to $592 billion. Additionally, in 2019 the 14-county San Jose–San Francisco–Oakland combined statistical area had a GDP of $1.086 trillion, ranking 3rd among CSAs, and ahead of all but 16 countries. As of 2019, San Francisco County was the 7th highest-income county in the United States (among 3,142), with a per capita personal income of $139,405. Marin County, directly to the north over the Golden Gate Bridge, and San Mateo County, directly to the south on the Peninsula, were the 6th and 9th highest-income counties respectively.
|
||||
|
||||
The legacy of the California Gold Rush turned San Francisco into the principal banking and finance center of the West Coast in the early twentieth century. Montgomery Street in the Financial District became known as the "Wall Street of the West", home to the Federal Reserve Bank of San Francisco, the Wells Fargo corporate headquarters, and the site of the now-defunct Pacific Coast Stock Exchange. Bank of America, a pioneer in making banking services accessible to the middle class, was founded in San Francisco and in the 1960s, built the landmark modern skyscraper at 555 California Street for its corporate headquarters. eventually moving to Charlotte, North Carolina. Many large financial institutions, multinational banks, and venture capital firms are based in or have regional headquarters in the city. With over 30 international financial institutions, six Fortune 500 companies, and a large supporting infrastructure of professional services—including law, public relations, architecture and design—San Francisco is designated as an Alpha(-) World City. The 2017 Global Financial Centres Index ranked San Francisco as the sixth-most competitive financial center in the world.Beginning in the 1990s, San Francisco's economy diversified away from finance and tourism towards the growing fields of high tech, biotechnology, and medical research. Technology jobs accounted for just 1 percent of San Francisco's economy in 1990, growing to 4 percent in 2010 and an estimated 8 percent by the end of 2013. San Francisco became a center of Internet start-up companies during the dot-com bubble of the 1990s and the subsequent social media boom of the late 2000s (decade). Since 2010, San Francisco proper has attracted an increasing share of venture capital investments as compared to nearby Silicon Valley, attracting 423 financings worth US$4.58 billion in 2013. In 2004, the city approved a payroll tax exemption for biotechnology companies to foster growth in the Mission Bay neighborhood, site of a second campus and hospital of the University of California, San Francisco (UCSF). Mission Bay hosts the UCSF Medical Center, the California Institute for Regenerative Medicine, California Institute for Quantitative Biosciences, and Gladstone Institutes, as well as more than 40 private-sector life sciences companies.
|
||||
According to academic Rob Wilson, San Francisco is a global city, a status that pre-dated the city's popularity during the California Gold Rush. However, the COVID-19 pandemic has led to high office vacancy rates and the closure of many retail and tech businesses in the downtown core of San Francisco. Attributed causes include a shift to remote work in the technology and professional services sectors, as well as high levels of homelessness, drug use, and crime in areas around downtown San Francisco, such as the Tenderloin and Mid-Market neighborhoods.The top employer in the city is the city government itself, employing 5.6% (31,000+ people) of the city's workforce, followed by UCSF with over 25,000 employees. The largest private-sector employer is Salesforce, with 8,500 employees, as of 2018. Small businesses with fewer than 10 employees and self-employed firms made up 85% of city establishments in 2006, and the number of San Franciscans employed by firms of more than 1,000 employees has fallen by half since 1977. The growth of national big box and formula retail chains into the city has been made intentionally difficult by political and civic consensus. In an effort to buoy small privately owned businesses in San Francisco and preserve the unique retail personality of the city, the Small Business Commission started a publicity campaign in 2004 to keep a larger share of retail dollars in the local economy, and the Board of Supervisors has used the planning code to limit the neighborhoods where formula retail establishments can set up shop, an effort affirmed by San Francisco voters. However, by 2016, San Francisco was rated low by small businesses in a Business Friendliness Survey.
|
||||
Like many U.S. cities, San Francisco once had a significant manufacturing sector employing nearly 60,000 workers in 1969, but nearly all production left for cheaper locations by the 1980s. As of 2014, San Francisco has seen a small resurgence in manufacturing, with more than 4,000 manufacturing jobs across 500 companies, doubling since 2011. The city's largest manufacturing employer is Anchor Brewing Company, and the largest by revenue is Timbuk2.As of the first quarter of 2022, the median value of homes in San Francisco County was $1,297,030. It ranked third in the U.S. for counties with highest median home value, behind Nantucket, Massachusetts and San Mateo County, California.
|
||||
|
||||
|
||||
=== Technology ===
|
||||
San Francisco became a hub for technological driven economic growth during the internet boom of the 1990s, and still holds an important position in the world city network today. Intense redevelopment towards the "new economy" makes business more technologically minded. Between the years of 1999 and 2000, the job growth rate was 4.9%, creating over 50,000 jobs in technology firms and internet content production. However, the technology industry has become geographically dispersed.In the second technological boom driven by social media in the mid-2000s, San Francisco became a location for companies such as Apple, Google, Ubisoft, Facebook, and Twitter to base their tech offices and for their employees to live.
|
||||
|
||||
|
||||
=== Tourism and conventions ===
|
||||
|
||||
Tourism is one of San Francisco's most important private-sector industries, accounting for more than one out of seven jobs in the city. The city's frequent portrayal in music, film, and popular culture has made the city and its landmarks recognizable worldwide. In 2016, it attracted the fifth-highest number of foreign tourists of any city in the United States. More than 25 million visitors arrived in San Francisco in 2016, adding US$9.96 billion to the economy.
|
||||
With a large hotel infrastructure and a world-class convention facility in the Moscone Center, San Francisco is a popular destination for annual conventions and conferences.Some of the most popular tourist attractions in San Francisco, as noted by the Travel Channel, include the Golden Gate Bridge and Alamo Square Park, home to the famous "Painted Ladies". Both of these locations were often used as landscape shots for the hit American television sitcom Full House. There is also Lombard Street, known for its "crookedness" and extensive views. Tourists also visit Pier 39, which offers dining, shopping, entertainment, and views of the bay, sunbathing California sea lions, the Aquarium of the Bay, and the famous Alcatraz Island.
|
||||
San Francisco also offers tourists cultural and unique nightlife in its neighborhoods.The new Terminal Project at Pier 27 opened September 25, 2014, as a replacement for the old Pier 35. Itineraries from San Francisco usually include round-trip cruises to Alaska and Mexico.
|
||||
A heightened interest in conventioneering in San Francisco, marked by the establishment of convention centers such as Yerba Buena, acted as a feeder into the local tourist economy and resulted in an increase in the hotel industry: "In 1959, the city had fewer than thirty-three hundred first-class hotel rooms; by 1970, the number was nine thousand; and by 1999, there were more than thirty thousand." The commodification of the Castro District has contributed to San Francisco's tourist economy.
|
||||
|
||||
|
||||
== Arts and culture ==
|
||||
|
||||
Although the Financial District, Union Square, and Fisherman's Wharf are well known around the world, San Francisco is also characterized by its numerous culturally rich streetscapes featuring mixed-use neighborhoods anchored around central commercial corridors to which residents and visitors alike can walk. Because of these characteristics, San Francisco is ranked the "most walkable" city in the United States by Walkscore.com. Many neighborhoods feature a mix of businesses, restaurants and venues that cater to the daily needs of local residents while also serving many visitors and tourists. Some neighborhoods are dotted with boutiques, cafés and nightlife such as Union Street in Cow Hollow, 24th Street in Noe Valley, Valencia Street in the Mission, Grant Avenue in North Beach, and Irving Street in the Inner Sunset. This approach especially has influenced the continuing South of Market neighborhood redevelopment with businesses and neighborhood services rising alongside high-rise residences.
|
||||
Since the 1990s, the demand for skilled information technology workers from local startups and nearby Silicon Valley has attracted white-collar workers from all over the world and created a high standard of living in San Francisco. Many neighborhoods that were once blue-collar, middle, and lower class have been gentrifying, as many of the city's traditional business and industrial districts have experienced a renaissance driven by the redevelopment of the Embarcadero, including the neighborhoods South Beach and Mission Bay. The city's property values and household income have risen to among the highest in the nation, creating a large and upscale restaurant, retail, and entertainment scene. According to a 2014 quality of life survey of global cities, San Francisco has the highest quality of living of any U.S. city. However, due to the exceptionally high cost of living, many of the city's middle and lower-class families have been leaving the city for the outer suburbs of the Bay Area, or for California's Central Valley. By June 2, 2015, the median rent was reported to be as high as $4,225. The high cost of living is due in part to restrictive planning laws which limit new residential construction.
|
||||
The international character that San Francisco has enjoyed since its founding is continued today by large numbers of immigrants from Asia and Latin America. With 39% of its residents born overseas, San Francisco has numerous neighborhoods filled with businesses and civic institutions catering to new arrivals. In particular, the arrival of many ethnic Chinese, which began to accelerate in the 1970s, has complemented the long-established community historically based in Chinatown throughout the city and has transformed the annual Chinese New Year Parade into the largest event of its kind on the West Coast.
|
||||
With the arrival of the "beat" writers and artists of the 1950s and societal changes culminating in the Summer of Love in the Haight-Ashbury district during the 1960s, San Francisco became a center of liberal activism and of the counterculture that arose at that time. The Democrats and to a lesser extent the Green Party have dominated city politics since the late 1970s, after the last serious Republican challenger for city office lost the 1975 mayoral election by a narrow margin. San Francisco has not voted more than 20% for a Republican presidential or senatorial candidate since 1988. In 2007, the city expanded its Medicaid and other indigent medical programs into the Healthy San Francisco program, which subsidizes certain medical services for eligible residents.
|
||||
Since 1993, the San Francisco Department of Public Health has distributed 400,000 free syringes every month aimed at reducing HIV and other health risks for drug users, as well as providing disposal sites and services.San Francisco also has had a very active environmental community. Starting with the founding of the Sierra Club in 1892 to the establishment of the non-profit Friends of the Urban Forest in 1981, San Francisco has been at the forefront of many global discussions regarding the environment. The 1980 San Francisco Recycling Program was one of the earliest curbside recycling programs. The city's GoSolarSF incentive promotes solar installations and the San Francisco Public Utilities Commission is rolling out the CleanPowerSF program to sell electricity from local renewable sources. SF Greasecycle is a program to recycle used cooking oil for conversion to biodiesel.The Sunset Reservoir Solar Project, completed in 2010, installed 24,000 solar panels on the roof of the reservoir. The 5-megawatt plant more than tripled the city's 2-megawatt solar generation capacity when it opened in December 2010.
|
||||
|
||||
|
||||
=== LGBT ===
|
||||
|
||||
San Francisco has long had an LGBT-friendly history. It was home to the first lesbian-rights organization in the United States, Daughters of Bilitis; the first openly gay person to run for public office in the United States, José Sarria; the first openly gay man to be elected to public office in California, Harvey Milk; the first openly lesbian judge appointed in the U.S., Mary C. Morgan; and the first transgender police commissioner, Theresa Sparks. The city's large gay population has created and sustained a politically and culturally active community over many decades, developing a powerful presence in San Francisco's civic life. Survey data released in 2015 by Gallup places the proportion of LGBT adults in the San Francisco metro area at 6.2%, which is the highest proportion of the 50 most populous metropolitan areas as measured by the polling organization.
|
||||
One of the most popular destinations for gay tourists internationally, the city hosts San Francisco Pride, one of the largest and oldest pride parades. San Francisco Pride events have been held continuously since 1972. The events are themed and a new theme is created each year. In 2013, over 1.5 million people attended, around 500,000 more than the previous year. Pink Saturday is an annual street party held the Saturday before the pride parade, which coincides with the Dyke march.
|
||||
The Folsom Street Fair (FSF) is an annual BDSM and leather subculture street fair that is held in September, endcapping San Francisco's "Leather Pride Week". It started in 1984 and is California's third-largest single-day, outdoor spectator event and the world's largest leather event and showcase for BDSM products and culture.
|
||||
|
||||
|
||||
=== Performing arts ===
|
||||
|
||||
San Francisco's War Memorial and Performing Arts Center hosts some of the most enduring performing-arts companies in the country. The War Memorial Opera House houses the San Francisco Opera, the second-largest opera company in North America as well as the San Francisco Ballet, while the San Francisco Symphony plays in Davies Symphony Hall. Opened in 2013, the SFJAZZ Center hosts jazz performances year round.The Fillmore is a music venue located in the Western Addition. It is the second incarnation of the historic venue that gained fame in the 1960s, housing the stage where now-famous musicians such as the Grateful Dead, Janis Joplin, Led Zeppelin, and Jefferson Airplane first performed, fostering the San Francisco Sound. It closed its doors in 1971 with a final performance by Santana and reopened in 1994 with a show by the Smashing Pumpkins.San Francisco has a large number of theaters and live performance venues. Local theater companies have been noted for risk taking and innovation. The Tony Award-winning non-profit American Conservatory Theater (A.C.T.) is a member of the national League of Resident Theatres. Other local winners of the Regional Theatre Tony Award include the San Francisco Mime Troupe.
|
||||
San Francisco theaters frequently host pre-Broadway engagements and tryout runs, and some original San Francisco productions have later moved to Broadway.
|
||||
|
||||
|
||||
=== Museums ===
|
||||
|
||||
The San Francisco Museum of Modern Art (SFMOMA) houses 20th century and contemporary works of art. It moved to its current building in the South of Market neighborhood in 1995 and attracted more than 600,000 visitors annually. SFMOMA closed for renovation and expansion in 2013. The museum reopened on May 14, 2016, with an addition, designed by Snøhetta, that has doubled the museum's size.The Palace of the Legion of Honor holds primarily European antiquities and works of art at its Lincoln Park building modeled after its Parisian namesake. The de Young Museum in Golden Gate Park features American decorative pieces and anthropological holdings from Africa, Oceania and the Americas, while Asian art is housed in the Asian Art Museum. Opposite the de Young stands the California Academy of Sciences, a natural history museum that also hosts the Morrison Planetarium and Steinhart Aquarium. Located on Pier 15 on the Embarcadero, the Exploratorium is an interactive science museum. The Contemporary Jewish Museum is a non-collecting institution that hosts a broad array of temporary exhibitions. On Nob Hill, the Cable Car Museum is a working museum featuring the cable car powerhouse, which drives the cables.
|
||||
|
||||
|
||||
== Sports ==
|
||||
|
||||
Major League Baseball's San Francisco Giants have played in San Francisco since moving from New York in 1958. The Giants play at Oracle Park, which opened in 2000. The Giants won World Series titles in 2010, 2012, and in 2014. The Giants have boasted stars such as Willie Mays, Willie McCovey, and Barry Bonds (MLB's career home run leader). In 2012, San Francisco was ranked No. 1 in a study that examined which U.S. metro areas have produced the most Major Leaguers since 1920.The San Francisco 49ers of the National Football League (NFL) began play in 1946 as an All-America Football Conference (AAFC) league charter member, moved to the NFL in 1950 and into Candlestick Park in 1971. The team left the San Francisco area in 2014, moving approximately 50 miles south to Santa Clara, and began playing its home games at Levi's Stadium, but despite the relocation did not change its name from the "San Francisco" 49ers. The 49ers won five Super Bowl titles between 1982 and 1995.
|
||||
|
||||
NBA's Golden State Warriors have played in the San Francisco Bay Area since moving from Philadelphia in 1962. The Warriors played as the San Francisco Warriors, from 1962 to 1971, before being renamed the Golden State Warriors prior to the 1971–1972 season in an attempt to present the team as a representation of the whole state of California, which had already adopted "The Golden State" nickname. The Warriors' arena, Chase Center, is located in San Francisco. After winning two championships in Philadelphia, they have won five championships since moving to the San Francisco Bay Area, and made five consecutive NBA Finals from 2015 to 2019, winning three of them. They won again in 2022, the franchise's first championship while residing in San Francisco proper.
|
||||
At the collegiate level, the San Francisco Dons compete in NCAA Division I. Bill Russell led the Dons basketball team to NCAA championships in 1955 and 1956. There is also the San Francisco State Gators, who compete in NCAA Division II. Oracle Park hosted the annual Fight Hunger Bowl college football game from 2002 through 2013 before it moved to Santa Clara.
|
||||
There are a handful of lower-league soccer clubs in San Francisco playing mostly from April – June.
|
||||
|
||||
The Bay to Breakers footrace, held annually since 1912, is best known for colorful costumes and a celebratory community spirit. The San Francisco Marathon attracts more than 21,000 participants. The Escape from Alcatraz triathlon has, since 1980, attracted 2,000 top professional and amateur triathletes for its annual race. The Olympic Club, founded in 1860, is the oldest athletic club in the United States. Its private golf course has hosted the U.S. Open on five occasions. San Francisco hosted the 2013 America's Cup yacht racing competition.With an ideal climate for outdoor activities, San Francisco has ample resources and opportunities for amateur and participatory sports and recreation. There are more than 200 miles (320 km) of bicycle paths, lanes and bike routes in the city.
|
||||
San Francisco residents have often ranked among the fittest in the country. Golden Gate Park has miles of paved and unpaved running trails as well as a golf course and disc golf course.
|
||||
Boating, sailing, windsurfing and kitesurfing are among the popular activities on San Francisco Bay, and the city maintains a yacht harbor in the Marina District.
|
||||
San Francisco also has had Esports teams, such as the Overwatch League's San Francisco Shock. Established in 2017, they won two back-to-back championship titles in 2019 and 2020.
|
||||
|
||||
|
||||
== Parks and recreation ==
|
||||
|
||||
Several of San Francisco's parks and nearly all of its beaches form part of the regional Golden Gate National Recreation Area, one of the most visited units of the National Park system in the United States with over 13 million visitors a year. Among the GGNRA's attractions within the city are Ocean Beach, which runs along the Pacific Ocean shoreline and is frequented by a vibrant surfing community, and Baker Beach, which is located in a cove west of the Golden Gate.
|
||||
The Presidio of San Francisco is the former 18th century Spanish military base, which today is one of the city's largest parks and home to numerous museums and institutions. Also within the Presidio is Crissy Field, a former airfield that was restored to its natural salt marsh ecosystem. The GGNRA also administers Fort Funston, Lands End, Fort Mason, and Alcatraz. The National Park Service separately administers the San Francisco Maritime National Historical Park – a fleet of historic ships and waterfront property around Aquatic Park.
|
||||
There are more than 220 parks maintained by the San Francisco Recreation & Parks Department. The largest and best-known city park is Golden Gate Park, which stretches from the center of the city west to the Pacific Ocean. Once covered in native grasses and sand dunes, the park was conceived in the 1860s and was created by the extensive planting of thousands of non-native trees and plants. The large park is rich with cultural and natural attractions such as the Conservatory of Flowers, Japanese Tea Garden and San Francisco Botanical Garden.Lake Merced is a fresh-water lake surrounded by parkland and near the San Francisco Zoo, a city-owned park that houses more than 250 animal species, many of which are endangered. The only park managed by the California State Park system located principally in San Francisco, Candlestick Point was the state's first urban recreation area.Most of San Francisco's islands are protected as parkland or nature reserves. Alcatraz Island, operated by the National Park Service, is open to the public. The Farallon Islands are protected wildlife refuges. The Seal Rocks are protected as part of Golden Gate National Recreation Area. Red Rock Island is the only privately owned island in San Francisco Bay, but is uninhabited. Yerba Buena Island is largely utilized by the military.
|
||||
San Francisco is the first city in the U.S. to have a park within a 10-Minute Walk of every resident. It also ranks fifth in the U.S. for park access and quality in the 2018 ParkScore ranking of the top 100 park systems across the United States, according to the nonprofit Trust for Public Land.
|
||||
|
||||
|
||||
== Government ==
|
||||
|
||||
The mayor is also the county executive, and the county Board of Supervisors acts as the city council. The government of San Francisco is a charter city and is constituted of two co-equal branches: the executive branch is headed by the mayor and includes other citywide elected and appointed officials as well as the civil service; the 11-member Board of Supervisors, the legislative branch, is headed by a president and is responsible for passing laws and budgets, though San Franciscans also make use of direct ballot initiatives to pass legislation.Because of its unique city-county status, the local government is able to exercise jurisdiction over certain property outside city limits. San Francisco International Airport, though located in San Mateo County, is owned and operated by the City and County of San Francisco. San Francisco's largest jail complex (County Jail No. 5) is located in San Mateo County, in an unincorporated area adjacent to San Bruno. San Francisco was also granted a perpetual leasehold over the Hetch Hetchy Valley and watershed in Yosemite National Park by the Raker Act in 1913.
|
||||
The members of the Board of Supervisors are elected as representatives of specific districts within the city. Upon the death or resignation of the mayor, the President of the Board of Supervisors becomes acting mayor until the full Board elects an interim replacement for the remainder of the term. In 1978, Dianne Feinstein assumed the office following the assassination of George Moscone and was later selected by the board to finish the term. In 2011, Ed Lee was selected by the board to finish the term of Gavin Newsom, who resigned to take office as Lieutenant Governor of California. Lee (who won two elections to remain mayor) was temporarily replaced by San Francisco Board of Supervisors President London Breed after he died on December 12, 2017. Supervisor Mark Farrell was appointed by the Board of Supervisors to finish Lee's term on January 23, 2018.
|
||||
Most local offices in San Francisco are elected using ranked choice voting.
|
||||
San Francisco serves as the regional hub for many arms of the federal bureaucracy, including the U.S. Court of Appeals, the Federal Reserve Bank, and the U.S. Mint. Until decommissioning in the early 1990s, the city had major military installations at the Presidio, Treasure Island, and Hunters Point—a legacy still reflected in the annual celebration of Fleet Week. The State of California uses San Francisco as the home of the state supreme court and other state agencies. Foreign governments maintain more than seventy consulates in San Francisco.The municipal budget for fiscal year 2015–16 was $8.99 billion, and is one of the largest city budgets in the United States. The City of San Francisco spends more per resident than any city other than Washington, D.C., over $10,000 in FY 2015–2016. The city employs around 27,000 workers.
|
||||
In the California State Senate, San Francisco is in the 11th Senate District, represented by Democrat Scott Wiener. In the California State Assembly, it is split between the 17th Assembly District, represented by Democrat Matt Haney, and the 19th Assembly District, represented by Democrat Phil Ting.In the United States House of Representatives, San Francisco is split between two congressional districts. Most of the city is in the 11th District, represented by Nancy Pelosi (D–San Francisco). A sliver in the southwest is part of the 15th District represented by Kevin Mullin (D–South San Francisco). Pelosi served as the House Speaker from January 3, 2019, to January 3, 2023, a post she also held from 2007 through 2011. She has also held the post of House Minority Leader, from 2003 to 2007 and 2011 to 2019.
|
||||
|
||||
|
||||
== Education ==
|
||||
|
||||
|
||||
=== Colleges and universities ===
|
||||
|
||||
The University of California, San Francisco is the sole campus of the University of California system entirely dedicated to graduate education in health and biomedical sciences. It is ranked among the top five medical schools in the United States and operates the UCSF Medical Center, which ranks as the number one hospital in California and the number 5 in the country. UCSF is a major local employer, second in size only to the city and county government. A 43-acre (17 ha) Mission Bay campus was opened in 2003, complementing its original facility in Parnassus Heights. It contains research space and facilities to foster biotechnology and life sciences entrepreneurship and will double the size of UCSF's research enterprise. All in all, UCSF operates more than 20 facilities across San Francisco.The University of California College of the Law, San Francisco, founded in Civic Center in 1878, is the oldest law school in California and claims more judges on the state bench than any other institution.
|
||||
San Francisco's two University of California institutions have recently formed an official affiliation in the UCSF/UC Law SF Consortium on Law, Science & Health Policy.
|
||||
San Francisco State University is part of the California State University system and is located near Lake Merced. The school has approximately 30,000 students and awards undergraduate, master's and doctoral degrees in more than 100 disciplines. The City College of San Francisco, with its main facility in the Ingleside district, is one of the largest two-year community colleges in the country. It has an enrollment of about 100,000 students and offers an extensive continuing education program.
|
||||
Founded in 1855, the University of San Francisco, a private Jesuit university located on Lone Mountain, is the oldest institution of higher education in San Francisco and one of the oldest universities established west of the Mississippi River. Golden Gate University is a private, nonsectarian, coeducational university formed in 1901 and located in the Financial District.
|
||||
With an enrollment of 13,000 students, the Academy of Art University is the largest institute of art and design in the nation. Founded in 1871, the San Francisco Art Institute is the oldest art school west of the Mississippi. The California College of the Arts, located north of Potrero Hill, has programs in architecture, fine arts, design, and writing. The San Francisco Conservatory of Music, the only independent music school on the West Coast, grants degrees in orchestral instruments, chamber music, composition, and conducting.
|
||||
The California Culinary Academy, associated with the Le Cordon Bleu program, offers programs in the culinary arts, baking and pastry arts, and hospitality and restaurant management.
|
||||
California Institute of Integral Studies, founded in 1968, offers a variety of graduate programs in its Schools of Professional Psychology & Health, and Consciousness and Transformation.
|
||||
|
||||
|
||||
=== Primary and secondary schools ===
|
||||
|
||||
Public schools are run by the San Francisco Unified School District, which covers the entire city and county, as well as the California State Board of Education for some charter schools. Lowell High School, the oldest public high school in the U.S. west of the Mississippi, and the smaller School of the Arts High School are two of San Francisco's magnet schools at the secondary level. Public school students attend schools based on an assignment system rather than neighborhood proximity.Just under 30% of the city's school-age population attends one of San Francisco's more than 100 private or parochial schools, compared to a 10% rate nationwide. Nearly 40 of those schools are Catholic schools managed by the Archdiocese of San Francisco.San Francisco has nearly 300 preschool programs primarily operated by Head Start, San Francisco Unified School District, private for-profit, private non-profit and family child care providers. All four-year-old children living in San Francisco are offered universal access to preschool through the Preschool for All program.
|
||||
|
||||
|
||||
== Media ==
|
||||
|
||||
The major daily newspaper in San Francisco is the San Francisco Chronicle, which is currently Northern California's most widely circulated newspaper. The Chronicle is most famous for a former columnist, the late Herb Caen, whose daily musings attracted critical acclaim and represented the "voice of San Francisco". The San Francisco Examiner, once the cornerstone of William Randolph Hearst's media empire and the home of Ambrose Bierce, declined in circulation over the years and now takes the form of a free daily tabloid, under new ownership.Sing Tao Daily claims to be the largest of several Chinese language dailies that serve the Bay Area. SF Weekly is the city's alternative weekly newspaper. San Francisco and 7x7 are major glossy magazines about San Francisco. The national newsmagazine Mother Jones is also based in San Francisco. San Francisco is home to online-only media publications such as SFist, and AsianWeek.
|
||||
|
||||
The San Francisco Bay Area is the sixth-largest television market. It is the fourth-largest radio market after that of New York City, Los Angeles, and Chicago. in the U.S.
|
||||
All major U.S. television networks have affiliates serving the region, with most of them based in the city. CNN, MSNBC, BBC, Russia Today, and CCTV America also have regional news bureaus in San Francisco. Bloomberg West was launched in 2011 from a studio on the Embarcadero and CNBC broadcasts from One Market Plaza since 2015. ESPN uses the local ABC studio for their broadcasting. The regional sports network, Comcast SportsNet Bay Area and its sister station Comcast SportsNet California, are both located in San Francisco. The Pac-12 Network is also based in San Francisco.
|
||||
|
||||
Public broadcasting outlets include both a television station and a radio station, both broadcasting under the call letters KQED from a facility near the Potrero Hill neighborhood. KQED-FM is the most-listened-to National Public Radio affiliate in the country.KUSF is a student-run radio station by college students from the University of San Francisco. Another local broadcaster, KPOO, is an independent, African-American owned and operated noncommercial radio station established in 1971. CNET, founded 1994, and Salon.com, 1995, are based in San Francisco. Sutro Tower is an important broadcast tower located between Mount Sutro and the Twin Peaks, built in 1973 for KTVU, KRON, and KPIX.
|
||||
|
||||
|
||||
== Infrastructure ==
|
||||
|
||||
|
||||
=== Transportation ===
|
||||
|
||||
|
||||
==== Public transportation ====
|
||||
|
||||
Transit is the most used form of transportation every day in San Francisco. Every weekday, more than 560,000 people travel on Muni's 69 bus routes and more than 140,000 customers ride the Muni Metro light rail system. 32% of San Francisco residents use public transportation for their daily commute to work, ranking it fourth in the United States and first on the West Coast. The San Francisco Municipal Railway, primarily known as Muni, is the primary public transit system of San Francisco. Muni is the seventh-largest transit system in the United States, with 210,848,310 rides in 2006. The system operates a combined light rail and subway system, the Muni Metro, as well as large bus and trolley coach networks. Additionally, it runs a historic streetcar line, which runs on Market Street from Castro Street to Fisherman's Wharf. It also operates the famous cable cars, which have been designated as a National Historic Landmark and are a major tourist attraction.Bay Area Rapid Transit (BART), a regional Rapid Transit system, connects San Francisco with the East Bay and San Jose through the underwater Transbay Tube. The line runs under Market Street to Civic Center where it turns south to the Mission District, the southern part of the city, and through northern San Mateo County, to the San Francisco International Airport, and Millbrae.
|
||||
Another commuter rail system, Caltrain, runs from San Francisco along the San Francisco Peninsula to San Jose. Historically, trains operated by Southern Pacific Lines ran from San Francisco to Los Angeles, via Palo Alto and San Jose.
|
||||
Amtrak Thruway runs a shuttle bus from three locations in San Francisco to its station across the bay in Emeryville. Additionally, BART offers connections to San Francisco from Amtrak's stations in Emeryville, Oakland and Richmond, and Caltrain offers connections in San Jose and Santa Clara. Thruway service also runs south to San Luis Obispo with connection to the Pacific Surfliner.
|
||||
San Francisco was an early adopter of carsharing in America. The non-profit City CarShare opened in 2001 and Zipcar closely followed.
|
||||
San Francisco Bay Ferry operates from the Ferry Building and Pier 39 to points in Oakland, Alameda, Bay Farm Island, South San Francisco, Richmond, and north to Vallejo in Solano County. The Golden Gate Ferry is the other ferry operator with service between San Francisco and Marin County. SolTrans runs supplemental bus service between the Ferry Building and Vallejo.
|
||||
To accommodate the large amount of San Francisco citizens who commute to the Silicon Valley daily, employers like Genentech, Google, and Apple have begun to provide private bus transportation for their employees, from San Francisco locations. These buses have quickly become a heated topic of debate within the city, as protesters claim they block bus lanes and delay public buses.
|
||||
|
||||
|
||||
==== Freeways and roads ====
|
||||
|
||||
In 2014, only 41.3% of residents commuted by driving alone or carpooling in private vehicles in San Francisco, a decline from 48.6% in 2000. There are 1,088 miles of streets in San Francisco with 946 miles of these streets being surface streets, and 59 miles of freeways. Due to its unique geography, and the freeway revolts of the late 1950s,Interstate 80 begins at the approach to the Bay Bridge and is the only direct automobile link to the East Bay. U.S. Route 101 connects to the western terminus of Interstate 80 and provides access to the south of the city along San Francisco Bay toward Silicon Valley. Northward, the routing for U.S. 101 uses arterial streets to connect to the Golden Gate Bridge, the only direct automobile link to Marin County and the North Bay.
|
||||
As part of the retrofitting of the Golden Gate Bridge and installation of a suicide barrier, starting in 2019 the railings on the west side of the pedestrian walkway were replaced with thinner, more flexible slats in order to improve the bridge's aerodynamic tolerance of high wind to 100 mph (161 km/h). Starting in June 2020, reports were received of a loud hum produced by the new railing slats, heard across the city when a strong west wind was blowing.
|
||||
State Route 1 also enters San Francisco from the north via the Golden Gate Bridge and bisects the city as the 19th Avenue arterial thoroughfare, joining with Interstate 280 at the city's southern border. Interstate 280 continues south from San Francisco, and also turns to the east along the southern edge of the city, terminating just south of the Bay Bridge in the South of Market neighborhood. After the 1989 Loma Prieta earthquake, city leaders demolished the Embarcadero Freeway and a portion of the Central Freeway, converting them into street-level boulevards.State Route 35 enters the city from the south as Skyline Boulevard and terminates at its intersection with Highway 1. State Route 82 enters San Francisco from the south as Mission Street, and terminates shortly thereafter at its junction with 280. The western terminus of the historic transcontinental Lincoln Highway, the first road across America, is in San Francisco's Lincoln Park.
|
||||
|
||||
|
||||
===== Vision Zero =====
|
||||
In 2014, San Francisco committed to Vision Zero, with the goal of ending all traffic fatalities caused by motor vehicles within the city by 2024. San Francisco's Vision Zero plan calls for investing in engineering, enforcement, and education, and focusing on dangerous intersections. In 2013, 25 people were killed by car and truck drivers while walking and biking in the city and 9 car drivers and passengers were killed in collisions. In 2019, 42 people were killed in traffic collisions in San Francisco.
|
||||
|
||||
|
||||
==== Airports ====
|
||||
|
||||
Though located 13 miles (21 km) south of downtown in unincorporated San Mateo County, San Francisco International Airport (SFO) is under the jurisdiction of the City and County of San Francisco. SFO is a hub for United Airlines and Alaska Airlines. SFO is a major international gateway to Asia and Europe, with the largest international terminal in North America. In 2011, SFO was the eighth-busiest airport in the U.S. and the 22nd-busiest in the world, handling over 40.9 million passengers.Located in the South Bay, the San Jose International Airport (SJC) is the second-busiest airport in the Bay Area, followed by Oakland International Airport, which is a popular, low-cost alternative to SFO. Geographically, Oakland Airport is approximately the same distance from downtown San Francisco as SFO, but due to its location across San Francisco Bay, it is greater driving distance from San Francisco.
|
||||
|
||||
|
||||
==== Cycling and walking ====
|
||||
|
||||
Cycling is a popular mode of transportation in San Francisco, with 75,000 residents commuting by bicycle each day. In recent years, the city has installed better cycling infrastructure such as protected bike lanes and parking racks. Bay Wheels, previously named Bay Area Bike Share at inception, launched in August 2013 with 700 bikes in downtown San Francisco, selected cities in the East Bay, and San Jose. The San Francisco Municipal Transportation Agency and Bay Area Air Quality Management District are responsible for the operation with management provided by Motivate. A major expansion started in 2017, along with a rebranding as Ford GoBike; the company received its current name in 2019.
|
||||
Pedestrian traffic is also widespread. In 2015, Walk Score ranked San Francisco the second-most walkable city in the United States.San Francisco has significantly higher rates of pedestrian and bicyclist traffic deaths than the United States on average. In 2013, 21 pedestrians were killed in vehicle collisions, the highest since 2001, which is 2.5 deaths per 100,000 population – 70% higher than the national average of 1.5.
|
||||
Cycling is becoming increasingly popular in the city. The 2010 Municipal Transportation Agency (MTA) annual bicycle count showed the number of cyclists at 33 locations had increased 58% from the 2006 baseline counts. In 2008, the MTA estimated that about 128,000 trips were made by bicycle each day in the city, or 6% of total trips. As of 2019, 2.6% of the city's streets have protected bike lanes, with 28 miles of protected bike lanes in the city. Since 2006, San Francisco has received a Bicycle Friendly Community status of "Gold" from the League of American Bicyclists. In 2022 a measure on the ballot passed to protect JFK drive in Golden Gate Park as a pedestrian and biking space with 59% of voters in favor.
|
||||
|
||||
|
||||
=== Public safety ===
|
||||
|
||||
The San Francisco Police Department was founded in 1849. The portions of the Golden Gate National Recreation Area located within the city, including the Presidio and Ocean Beach, are patrolled by the United States Park Police.
|
||||
The San Francisco Fire Department provides both fire suppression and emergency medical services to the city.
|
||||
|
||||
|
||||
== Sister cities ==
|
||||
|
||||
San Francisco participates in the Sister Cities program. A total of 41 consulates general and 23 honorary consulates have offices in the San Francisco Bay Area.
|
||||
|
||||
|
||||
== Notable residents ==
|
||||
|
||||
|
||||
== See also ==
|
||||
|
||||
|
||||
== Notes ==
|
||||
|
||||
|
||||
== References ==
|
||||
|
||||
|
||||
== Bibliography ==
|
||||
|
||||
|
||||
== Further reading ==
|
||||
Asbury, Hubert (1989). The Barbary Coast: An Informal History of the San Francisco Underworld. Dorset Press. ISBN 978-0-88029-428-7. OCLC 22719465.
|
||||
Bronson, William (2006). The Earth Shook, the Sky Burned. Chronicle Books. ISBN 978-0-8118-5047-6. OCLC 65223734.
|
||||
Cassady, Stephen (1987). Spanning the Gate. Square Books. ISBN 978-0-916290-36-8. OCLC 15229396.
|
||||
Dillon, Richard H. (1998). High Steel: Building the Bridges Across San Francisco Bay. Celestial Arts (Reissue edition). ISBN 978-0-88029-428-7. OCLC 22719465.
|
||||
Eldredge, Zoeth Skinner (1912). The Beginnings of San Francisco: from the Expedition of Anza, 1774, to the City Charter of April 15, 1850 (PDF). New York: John C. Rankin Company.
|
||||
Ferlinghetti, Lawrence (1980). Literary San Francisco: A pictorial history from its beginnings to the present day. Harper & Row. ISBN 978-0-06-250325-1. OCLC 6683688.
|
||||
Hartman, Chester (2002). City for Sale: The Transformation of San Francisco. University of California Press. ISBN 978-0-520-08605-0. OCLC 48579085.
|
||||
Heller, Nathan. Bay Watched – How San Francisco's New Entrepreneurial Culture is Changing the Country (article) (October 2013). The New Yorker
|
||||
Holliday, J. S. (1999). Rush for Riches: Gold Fever and the Making of California. University of California Press. ISBN 978-0-520-21402-6. OCLC 37545551.
|
||||
Lotchin, Roger W. (1997). San Francisco, 1846–1856: From Hamlet to City. University of Illinois Press. ISBN 978-0-252-06631-3. OCLC 35650934.
|
||||
Margolin, Malcolm (1981). The Ohlone Way: Indian Life in the San Francisco-Monterey Bay Area. Heydey Books. ISBN 978-0-930588-01-4. OCLC 4628382.
|
||||
Maupin, Armistead (1978). Tales of the City. Harper Collins. ISBN 978-0-06-096404-7. OCLC 29847673.
|
||||
Solnit, Rebecca. Infinite City: A San Francisco Atlas (University of California Press, 2010). 144 pp. ISBN 978-0-520-26250-8; online review
|
||||
Thomas, Gordon & Witts, Max Morgan (1971). The San Francisco Earthquake. Stein and Day. ISBN 978-0-8128-1360-9. OCLC 154735.
|
||||
Watkins, James F. (January 1870). "San Francisco". The Overland Monthly. Vol. 4, no. 1. San Francisco: A. Roman & Co. pp. 9–23.
|
||||
Winfield, P.H., The Charter of San Francisco (The fortnightly review Vol. 157–58:2 (1945), p. 69–75)
|
||||
|
||||
|
||||
== External links ==
|
||||
Official website
|
||||
Virtual Museum of the City of San Francisco
|
||||
@@ -0,0 +1,364 @@
|
||||
Vincent Willem van Gogh (Dutch: [ˈvɪnsɛnt ˈʋɪləɱ vɑŋ ˈɣɔx] ; 30 March 1853 – 29 July 1890) was a Dutch Post-Impressionist painter who is among the most famous and influential figures in the history of Western art. In just over a decade he created approximately 2100 artworks, including around 860 oil paintings, most of them in the last two years of his life. They include landscapes, still lifes, portraits and self-portraits, and are characterised by bold, symbolic colours, and dramatic, impulsive and highly expressive brushwork that contributed to the foundations of modern art. Only one of his paintings was known by name to have been sold during his lifetime. Van Gogh became famous after his suicide at age 37, which followed years of poverty and mental illness.
|
||||
Born into an upper-middle-class family, Van Gogh drew as a child and was serious, quiet and thoughtful, but showed signs of mental instability. As a young man he worked as an art dealer, often travelling, but became depressed after he was transferred to London. He turned to religion, and spent time as a missionary in southern Belgium. Later he drifted in ill-health and solitude. He was keenly aware of modernist trends in art and, while back with his parents, took up painting in 1881. His younger brother, Theo, supported him financially, and the two of them kept up a long correspondence by letter.
|
||||
Van Gogh's early works consisted of mostly still lifes and depictions of peasant labourers. In 1886, he moved to Paris, where he met members of the artistic avant-garde, including Émile Bernard and Paul Gauguin, who were seeking new paths beyond Impressionism. Frustrated in Paris and inspired by a growing spirit of artistic change and collaboration, Van Gogh moved to Arles in south of France in February 1888 with the goal of establishing an artistic retreat and commune. Once there, Van Gogh's art changed. His paintings grew brighter and he turned his attention to the natural world, depicting local olive groves, wheat fields and sunflowers. Van Gogh invited Gauguin to join him in Arles and eagerly anticipated Gauguin's arrival in the fall of 1888.
|
||||
Van Gogh suffered from psychotic episodes and delusions. Though he worried about his mental stability, he often neglected his physical health, did not eat properly and drank heavily. His friendship with Gauguin ended after a confrontation with a razor when, in a rage, he severed part of his own left ear. He spent time in psychiatric hospitals, including a period at Saint-Rémy. After he discharged himself and moved to the Auberge Ravoux in Auvers-sur-Oise near Paris, he came under the care of the homeopathic doctor Paul Gachet. His depression persisted, and on 27 July 1890, Van Gogh is believed to have shot himself in the chest with a revolver, dying from his injuries two days later.
|
||||
Van Gogh's art gained critical recognition after his death and his life story captured public imagination as an emblem of misunderstood genius, due in large part to the efforts of his widowed sister-in-law Johanna van Gogh-Bonger. His bold use of color, expressive line and thick application of paint inspired avant garde artistic groups like the Fauves and German Expressionists in the early 20th century. Van Gogh's work gained widespread critical and commercial success in the following decades, and he has become a lasting icon of the romantic ideal of the tortured artist. Today, Van Gogh's works are among the world's most expensive paintings to have ever sold, and his legacy is honoured by a museum in his name, the Van Gogh Museum in Amsterdam, which holds the world's largest collection of his paintings and drawings.
|
||||
|
||||
|
||||
== Letters ==
|
||||
|
||||
The most comprehensive primary source on Van Gogh is his correspondence with younger brother, Theo. Their lifelong friendship, and most of what is known of Vincent's thoughts and theories of art, are recorded in the hundreds of letters they exchanged from 1872 until 1890. Theo van Gogh was an art dealer and provided his brother with financial and emotional support as well as access to influential people on the contemporary art scene.Theo kept all of Vincent's letters to him; but Vincent kept only a few of the letters he received. After both had died, Theo's widow Jo Bonger-van Gogh arranged for the publication of some of their letters. A few appeared in 1906 and 1913; the majority were published in 1914. Vincent's letters are eloquent and expressive, have been described as having a "diary-like intimacy", and read in parts like autobiography. Translator Arnold Pomerans wrote that their publication adds a "fresh dimension to the understanding of Van Gogh's artistic achievement, an understanding granted to us by virtually no other painter".
|
||||
|
||||
There are more than 600 letters from Vincent to Theo and around 40 from Theo to Vincent. There are 22 to his sister Wil, 58 to the painter Anthon van Rappard, 22 to Émile Bernard as well as individual letters to Paul Signac, Paul Gauguin, and the critic Albert Aurier. Some are illustrated with sketches. Many are undated, but art historians have been able to place most in chronological order. Problems in transcription and dating remain, mainly with those posted from Arles. While there, Vincent wrote around 200 letters in Dutch, French, and English. There is a gap in the record when he lived in Paris as the brothers lived together and had no need to correspond.The highly paid contemporary artist Jules Breton was frequently mentioned in Vincent's letters. In 1875 letters to Theo, Vincent mentions he saw Breton, discusses the Breton paintings he saw at a Salon, and discusses sending one of Breton's books but only on the condition that it be returned. In a March 1884 letter to Rappard he discusses one of Breton's poems that had inspired one of his own paintings. In 1885 he describes Breton's famous work The Song of the Lark as being "fine". In March 1880, roughly midway between these letters, Van Gogh set out on an 80-kilometre trip on foot to meet with Breton in the village of Courrières; however, he was apparently intimidated by Breton's success and/or the high wall around his estate. He turned around and returned without making his presence known. It appears Breton was unaware of Van Gogh or his attempted visit. There are no known letters between the two artists and Van Gogh is not one of the contemporary artists discussed by Breton in his 1891 autobiography Life of an Artist.
|
||||
|
||||
|
||||
== Life ==
|
||||
|
||||
|
||||
=== Early years ===
|
||||
|
||||
Vincent Willem van Gogh was born on 30 March 1853 in Groot-Zundert, in the predominantly Catholic province of North Brabant in the Netherlands. He was the oldest surviving child of Theodorus van Gogh (1822–1885), a minister of the Dutch Reformed Church, and his wife, Anna Cornelia Carbentus (1819–1907). Van Gogh was given the name of his grandfather and of a brother stillborn exactly a year before his birth. Vincent was a common name in the Van Gogh family. The name had been borne by his grandfather, the prominent art dealer Vincent (1789–1874), and a theology graduate at the University of Leiden in 1811. This Vincent had six sons, three of whom became art dealers, and may have been named after his own great-uncle, a sculptor (1729–1802).Van Gogh's mother came from a prosperous family in The Hague, and his father was the youngest son of a minister. The two met when Anna's younger sister, Cornelia, married Theodorus's older brother Vincent (Cent). Van Gogh's parents married in May 1851, and moved to Zundert. His brother Theo was born on 1 May 1857. There was another brother, Cor, and three sisters: Elisabeth, Anna, and Willemina (known as "Wil"). In later life, Van Gogh remained in touch only with Willemina and Theo. Van Gogh's mother was a rigid and religious woman who emphasized the importance of family to the point of claustrophobia for those around her. Theodorus's salary as a minister was modest, but the Church also supplied the family with a house, a maid, two cooks, a gardener, a carriage and horse; his mother Anna instilled in the children a duty to uphold the family's high social position.Van Gogh was a serious and thoughtful child. He was taught at home by his mother and a governess, and in 1860, was sent to the village school. In 1864, he was placed in a boarding school at Zevenbergen, where he felt abandoned, and he campaigned to come home. Instead, in 1866, his parents sent him to the middle school in Tilburg, where he was also deeply unhappy. His interest in art began at a young age. He was encouraged to draw as a child by his mother, and his early drawings are expressive, but do not approach the intensity of his later work. Constant Cornelis Huijsmans, who had been a successful artist in Paris, taught the students at Tilburg. His philosophy was to reject technique in favour of capturing the impressions of things, particularly nature or common objects. Van Gogh's profound unhappiness seems to have overshadowed the lessons, which had little effect. In March 1868, he abruptly returned home. He later wrote that his youth was "austere and cold, and sterile".In July 1869, Van Gogh's uncle Cent obtained a position for him at the art dealers Goupil & Cie in The Hague. After completing his training in 1873, he was transferred to Goupil's London branch on Southampton Street, and took lodgings at 87 Hackford Road, Stockwell. This was a happy time for Van Gogh; he was successful at work and, at 20, was earning more than his father. Theo's wife, Jo Van Gogh-Bonger, later remarked that this was the best year of Vincent's life. He became infatuated with his landlady's daughter, Eugénie Loyer, but she rejected him after confessing his feelings; she was secretly engaged to a former lodger. He grew more isolated and religiously fervent. His father and uncle arranged a transfer to Paris in 1875, where he became resentful of issues such as the degree to which the art dealers commodified art, and he was dismissed a year later.
|
||||
In April 1876, he returned to England to take unpaid work as a supply teacher in a small boarding school in Ramsgate. When the proprietor moved to Isleworth in Middlesex, Van Gogh went with him. The arrangement was not successful; he left to become a Methodist minister's assistant. His parents had meanwhile moved to Etten; in 1876 he returned home at Christmas for six months and took work at a bookshop in Dordrecht. He was unhappy in the position and spent his time doodling or translating passages from the Bible into English, French, and German. He immersed himself in Christianity, and became increasingly pious and monastic. According to his flatmate of the time, Paulus van Görlitz, Van Gogh ate frugally, avoiding meat.To support his religious conviction and his desire to become a pastor, in 1877, the family sent him to live with his uncle Johannes Stricker, a respected theologian, in Amsterdam. Van Gogh prepared for the University of Amsterdam theology entrance examination; he failed the exam and left his uncle's house in July 1878. He undertook, but also failed, a three-month course at a Protestant missionary school in Laken, near Brussels.In January 1879, he took up a post as a missionary at Petit-Wasmes in the working class, coal-mining district of Borinage in Belgium. To show support for his impoverished congregation, he gave up his comfortable lodgings at a bakery to a homeless person and moved to a small hut, where he slept on straw. His humble living conditions did not endear him to church authorities, who dismissed him for "undermining the dignity of the priesthood". He then walked the 75 kilometres (47 mi) to Brussels, returned briefly to Cuesmes in the Borinage, but he gave in to pressure from his parents to return home to Etten. He stayed there until around March 1880, which caused concern and frustration for his parents. His father was especially frustrated, and advised that his son be committed to the lunatic asylum in Geel.Van Gogh returned to Cuesmes in August 1880, where he lodged with a miner until October. He became interested in the people and scenes around him, and he recorded them in drawings after Theo's suggestion that he take up art in earnest. He traveled to Brussels later in the year, to follow Theo's recommendation that he study with the Dutch artist Willem Roelofs, who persuaded him – in spite of his dislike of formal schools of art – to attend the Académie Royale des Beaux-Arts. He registered at the Académie in November 1880, where he studied anatomy and the standard rules of modelling and perspective.
|
||||
|
||||
|
||||
=== Etten, Drenthe and The Hague ===
|
||||
|
||||
Van Gogh returned to Etten in April 1881 for an extended stay with his parents. He continued to draw, often using his neighbours as subjects. In August 1881, his recently widowed cousin, Cornelia "Kee" Vos-Stricker, daughter of his mother's older sister Willemina and Johannes Stricker, arrived for a visit. He was thrilled and took long walks with her. Kee was seven years older than he was and had an eight-year-old son. Van Gogh surprised everyone by declaring his love to her and proposing marriage. She refused with the words "No, nay, never" ("nooit, neen, nimmer"). After Kee returned to Amsterdam, Van Gogh went to The Hague to try to sell paintings and to meet with his second cousin, Anton Mauve. Mauve was the successful artist Van Gogh longed to be. Mauve invited him to return in a few months and suggested he spend the intervening time working in charcoal and pastels; Van Gogh returned to Etten and followed this advice.Late in November 1881, Van Gogh wrote a letter to Johannes Stricker, one which he described to Theo as an attack. Within days he left for Amsterdam. Kee would not meet him, and her parents wrote that his "persistence is disgusting". In despair, he held his left hand in the flame of a lamp, with the words: "Let me see her for as long as I can keep my hand in the flame." He did not recall the event well, but later assumed that his uncle had blown out the flame. Kee's father made it clear that her refusal should be heeded and that the two would not marry, largely because of Van Gogh's inability to support himself.Mauve took Van Gogh on as a student and introduced him to watercolour, which he worked on for the next month before returning home for Christmas. He quarrelled with his father, refusing to attend church, and left for The Hague. In January 1882, Mauve introduced him to painting in oil and lent him money to set up a studio. Within a month Van Gogh and Mauve fell out, possibly over the viability of drawing from plaster casts. Van Gogh could afford to hire only people from the street as models, a practice of which Mauve seems to have disapproved. In June Van Gogh suffered a bout of gonorrhoea and spent three weeks in hospital. Soon after, he first painted in oils, bought with money borrowed from Theo. He liked the medium, and he spread the paint liberally, scraping from the canvas and working back with the brush. He wrote that he was surprised at how good the results were.
|
||||
By March 1882, Mauve appeared to have gone cold towards Van Gogh, and he stopped replying to his letters. He had learned of Van Gogh's new domestic arrangement with an alcoholic prostitute, Clasina Maria "Sien" Hoornik (1850–1904), and her young daughter. Van Gogh had met Sien towards the end of January 1882, when she had a five-year-old daughter and was pregnant. She had previously borne two children who died, but Van Gogh was unaware of this. On 2 July, she gave birth to a baby boy, Willem. When Van Gogh's father discovered the details of their relationship, he put pressure on his son to abandon Sien and her two children. Vincent at first defied him, and considered moving the family out of the city, but in late 1883, he left Sien and the children.Poverty may have pushed Sien back into prostitution; the home became less happy and Van Gogh may have felt family life was irreconcilable with his artistic development. Sien gave her daughter to her mother and baby Willem to her brother. Willem remembered visiting Rotterdam when he was about 12, when an uncle tried to persuade Sien to marry to legitimise the child. He believed Van Gogh was his father, but the timing of his birth makes this unlikely. Sien drowned herself in the River Scheldt in 1904.In September 1883, Van Gogh moved to Drenthe in the northern Netherlands. In December driven by loneliness, he went to live with his parents, then in Nuenen, North Brabant.
|
||||
|
||||
|
||||
=== Emerging artist ===
|
||||
|
||||
|
||||
==== Nuenen and Antwerp (1883–1886) ====
|
||||
|
||||
In Nuenen, Van Gogh focused on painting and drawing. Working outside and very quickly, he completed sketches and paintings of weavers and their cottages. Van Gogh also completed The Parsonage Garden at Nuenen, which was stolen from the Singer Laren in March 2020. From August 1884, Margot Begemann, a neighbour's daughter ten years his senior, joined him on his forays; she fell in love and he reciprocated, though less enthusiastically. They wanted to marry, but neither side of their families were in favour. Margot was distraught and took an overdose of strychnine, but survived after Van Gogh rushed her to a nearby hospital. On 26 March 1885, his father died of a heart attack.Van Gogh painted several groups of still lifes in 1885. During his two-year stay in Nuenen, he completed numerous drawings and watercolours and nearly 200 oil paintings. His palette consisted mainly of sombre earth tones, particularly dark brown, and showed no sign of the vivid colours that distinguished his later work.There was interest from a dealer in Paris early in 1885. Theo asked Vincent if he had paintings ready to exhibit. In May, Van Gogh responded with his first major work, The Potato Eaters, and a series of "peasant character studies" which were the culmination of several years of work. When he complained that Theo was not making enough effort to sell his paintings in Paris, his brother responded that they were too dark and not in keeping with the bright style of Impressionism. In August his work was publicly exhibited for the first time, in the shop windows of the dealer Leurs in The Hague. One of his young peasant sitters became pregnant in September 1885; Van Gogh was accused of forcing himself upon her, and the village priest forbade parishioners to model for him.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
He moved to Antwerp that November and rented a room above a paint dealer's shop in the rue des Images (Lange Beeldekensstraat). He lived in poverty and ate poorly, preferring to spend the money Theo sent on painting materials and models. Bread, coffee and tobacco became his staple diet. In February 1886, he wrote to Theo that he could only remember eating six hot meals since the previous May. His teeth became loose and painful. In Antwerp he applied himself to the study of colour theory and spent time in museums—particularly studying the work of Peter Paul Rubens—and broadened his palette to include carmine, cobalt blue and emerald green. Van Gogh bought Japanese ukiyo-e woodcuts in the docklands, later incorporating elements of their style into the background of some of his paintings. He was drinking heavily again, and was hospitalised between February and March 1886, when he was possibly also treated for syphilis.
|
||||
|
||||
After his recovery, despite his antipathy towards academic teaching, he took the higher-level admission exams at the Academy of Fine Arts in Antwerp and, in January 1886, matriculated in painting and drawing. He became ill and run down by overwork, poor diet and excessive smoking. He started to attend drawing classes after plaster models at the Antwerp Academy on 18 January 1886. He quickly got into trouble with Charles Verlat, the director of the academy and teacher of a painting class, because of his unconventional painting style. Van Gogh had also clashed with the instructor of the drawing class Franz Vinck. Van Gogh finally started to attend the drawing classes after antique plaster models given by Eugène Siberdt. Soon Siberdt and Van Gogh came into conflict when the latter did not comply with Siberdt's requirement that drawings express the contour and concentrate on the line. When Van Gogh was required to draw the Venus de Milo during a drawing class, he produced the limbless, naked torso of a Flemish peasant woman. Siberdt regarded this as defiance against his artistic guidance and made corrections to Van Gogh's drawing with his crayon so vigorously that he tore the paper. Van Gogh then flew into a violent rage and shouted at Siberdt: 'You clearly do not know what a young woman is like, God damn it! A woman must have hips, buttocks, a pelvis in which she can carry a baby!' According to some accounts, this was the last time Van Gogh attended classes at the academy and he left later for Paris. On 31 March 1886, which was about a month after the confrontation with Siberdt, the teachers of the academy decided that 17 students, including Van Gogh, had to repeat a year. The story that Van Gogh was expelled from the academy by Siberdt is therefore unfounded.
|
||||
|
||||
|
||||
==== Paris (1886–1888) ====
|
||||
|
||||
Van Gogh moved to Paris in March 1886 where he shared Theo's rue Laval apartment in Montmartre and studied at Fernand Cormon's studio. In June the brothers took a larger flat at 54 rue Lepic. In Paris, Vincent painted portraits of friends and acquaintances, still life paintings, views of Le Moulin de la Galette, scenes in Montmartre, Asnières and along the Seine. In 1885 in Antwerp he had become interested in Japanese ukiyo-e woodblock prints and had used them to decorate the walls of his studio; while in Paris he collected hundreds of them. He tried his hand at Japonaiserie, tracing a figure from a reproduction on the cover of the magazine Paris Illustre, The Courtesan or Oiran (1887), after Keisai Eisen, which he then graphically enlarged in a painting.After seeing the portrait of Adolphe Monticelli at the Galerie Delareybarette, Van Gogh adopted a brighter palette and a bolder attack, particularly in paintings such as his Seascape at Saintes-Maries (1888). Two years later, Vincent and Theo paid for the publication of a book on Monticelli paintings, and Vincent bought some of Monticelli's works to add to his collection.Van Gogh learned about Fernand Cormon's atelier from Theo. He worked at the studio in April and May 1886, where he frequented the circle of the Australian artist John Russell, who painted his portrait in 1886. Van Gogh also met fellow students Émile Bernard, Louis Anquetin and Henri de Toulouse-Lautrec – who painted a portrait of him in pastel. They met at Julien "Père" Tanguy's paint shop, (which was, at that time, the only place where Paul Cézanne's paintings were displayed). In 1886, two large exhibitions were staged there, showing Pointillism and Neo-impressionism for the first time and bringing attention to Georges Seurat and Paul Signac. Theo kept a stock of Impressionist paintings in his gallery on boulevard Montmartre, but Van Gogh was slow to acknowledge the new developments in art.Conflicts arose between the brothers. At the end of 1886 Theo found living with Vincent to be "almost unbearable". By early 1887, they were again at peace, and Vincent had moved to Asnières, a northwestern suburb of Paris, where he got to know Signac. He adopted elements of Pointillism, a technique in which a multitude of small coloured dots are applied to the canvas so that when seen from a distance they create an optical blend of hues. The style stresses the ability of complementary colours – including blue and orange – to form vibrant contrasts.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
While in Asnières Van Gogh painted parks, restaurants and the Seine, including Bridges across the Seine at Asnières. In November 1887, Theo and Vincent befriended Paul Gauguin who had just arrived in Paris. Towards the end of the year, Vincent arranged an exhibition alongside Bernard, Anquetin, and probably Toulouse-Lautrec, at the Grand-Bouillon Restaurant du Chalet, 43 avenue de Clichy, Montmartre. In a contemporary account, Bernard wrote that the exhibition was ahead of anything else in Paris. There, Bernard and Anquetin sold their first paintings, and Van Gogh exchanged work with Gauguin. Discussions on art, artists, and their social situations started during this exhibition, continued and expanded to include visitors to the show, like Camille Pissarro and his son Lucien, Signac and Seurat. In February 1888, feeling worn out from life in Paris, Van Gogh left, having painted more than 200 paintings during his two years there. Hours before his departure, accompanied by Theo, he paid his first and only visit to Seurat in his studio.
|
||||
|
||||
|
||||
=== Artistic breakthrough ===
|
||||
|
||||
|
||||
==== Arles (1888–89) ====
|
||||
|
||||
Ill from drink and suffering from smoker's cough, in February 1888 Van Gogh sought refuge in Arles. He seems to have moved with thoughts of founding an art colony. The Danish artist Christian Mourier-Petersen became his companion for two months, and, at first, Arles appeared exotic. In a letter, he described it as a foreign country: "The Zouaves, the brothels, the adorable little Arlésienne going to her First Communion, the priest in his surplice, who looks like a dangerous rhinoceros, the people drinking absinthe, all seem to me creatures from another world."The time in Arles became one of Van Gogh's more prolific periods: he completed 200 paintings and more than 100 drawings and watercolours. He was enchanted by the local countryside and light; his works from this period are rich in yellow, ultramarine and mauve. They include harvests, wheat fields and general rural landmarks from the area, including The Old Mill (1888), one of seven canvases sent to Pont-Aven on 4 October 1888 in an exchange of works with Paul Gauguin, Émile Bernard, Charles Laval and others.
|
||||
The portrayals of Arles are informed by his Dutch upbringing; the patchworks of fields and avenues are flat and lacking perspective, but excel in their use of colour.In March 1888, he painted landscapes using a gridded "perspective frame"; three of the works were shown at the annual exhibition of the Société des Artistes Indépendants. In April, he was visited by the American artist Dodge MacKnight, who was living nearby at Fontvieille. On 1 May 1888, for 15 francs per month, he signed a lease for the eastern wing of the Yellow House at 2 place Lamartine. The rooms were unfurnished and had been uninhabited for months.On 7 May, Van Gogh moved from the Hôtel Carrel to the Café de la Gare, having befriended the proprietors, Joseph and Marie Ginoux. The Yellow House had to be furnished before he could fully move in, but he was able to use it as a studio. He wanted a gallery to display his work and started a series of paintings that eventually included Van Gogh's Chair (1888), Bedroom in Arles (1888), The Night Café (1888), Café Terrace at Night (September 1888), Starry Night Over the Rhone (1888), and Still Life: Vase with Twelve Sunflowers (1888), all intended for the decoration for the Yellow House.Van Gogh wrote that with The Night Café he tried "to express the idea that the café is a place where one can ruin oneself, go mad, or commit a crime". When he visited Saintes-Maries-de-la-Mer in June, he gave lessons to a Zouave second lieutenant – Paul-Eugène Milliet – and painted boats on the sea and the village. MacKnight introduced Van Gogh to Eugène Boch, a Belgian painter who sometimes stayed in Fontvieille, and the two exchanged visits in July.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
==== Gauguin's visit (1888) ====
|
||||
|
||||
When Gauguin agreed to visit Arles in 1888, Van Gogh hoped for friendship and to realize his idea of an artists' collective. Van Gogh prepared for Gauguin's arrival by painting four versions of Sunflowers in one week. "In the hope of living in a studio of our own with Gauguin," he wrote in a letter to Theo, "I'd like to do a decoration for the studio. Nothing but large Sunflowers."When Boch visited again, Van Gogh painted a portrait of him, as well as the study The Poet Against a Starry Sky.In preparation for Gauguin's visit, Van Gogh bought two beds on advice from the station's postal supervisor Joseph Roulin, whose portrait he painted. On 17 September, he spent his first night in the still sparsely furnished Yellow House. When Gauguin consented to work and live in Arles with him, Van Gogh started to work on the Décoration for the Yellow House, probably the most ambitious effort he ever undertook. He completed two chair paintings: Van Gogh's Chair and Gauguin's Chair.After much pleading from Van Gogh, Gauguin arrived in Arles on 23 October and, in November, the two painted together. Gauguin depicted Van Gogh in his The Painter of Sunflowers; Van Gogh painted pictures from memory, following Gauguin's suggestion. Among these "imaginative" paintings is Memory of the Garden at Etten. Their first joint outdoor venture was at the Alyscamps, when they produced the pendants Les Alyscamps. The single painting Gauguin completed during his visit was his portrait of Van Gogh.Van Gogh and Gauguin visited Montpellier in December 1888, where they saw works by Courbet and Delacroix in the Musée Fabre. Their relationship began to deteriorate; Van Gogh admired Gauguin and wanted to be treated as his equal, but Gauguin was arrogant and domineering, which frustrated Van Gogh. They often quarrelled; Van Gogh increasingly feared that Gauguin was going to desert him, and the situation, which Van Gogh described as one of "excessive tension", rapidly headed towards crisis point.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
==== Hospital in Arles (December 1888) ====
|
||||
|
||||
The exact sequence that led to the mutilation of van Gogh's ear is not known. Gauguin said, fifteen years later, that the night followed several instances of physically threatening behaviour. Their relationship was complex and Theo may have owed money to Gauguin, who suspected the brothers were exploiting him financially. It seems likely that Vincent realised that Gauguin was planning to leave. The following days saw heavy rain, leading to the two men being shut in the Yellow House. Gauguin recalled that Van Gogh followed him after he left for a walk and "rushed towards me, an open razor in his hand." This account is uncorroborated; Gauguin was almost certainly absent from the Yellow House that night, most likely staying in a hotel.After an altercation on the evening of 23 December 1888, Van Gogh returned to his room where he seemingly heard voices and either wholly or in part severed his left ear with a razor causing severe bleeding. He bandaged the wound, wrapped the ear in paper and delivered the package to a woman at a brothel Van Gogh and Gauguin both frequented. Van Gogh was found unconscious the next morning by a policeman and taken to hospital, where he was treated by Félix Rey, a young doctor still in training. The ear was brought to the hospital, but Rey did not attempt to reattach it as too much time had passed. Van Gogh researcher and art historian Bernadette Murphy discovered the true identity of the woman named Gabrielle, who died in Arles at the age of 80 in 1952, and whose descendants still live just outside Arles. Gabrielle, known in her youth as "Gaby," was a 17-year-old cleaning girl at the brothel and other local establishments at the time Van Gogh presented her with his ear.Van Gogh had no recollection of the event, suggesting that he may have suffered an acute mental breakdown. The hospital diagnosis was "acute mania with generalised delirium", and within a few days, the local police ordered that he be placed in hospital care. Gauguin immediately notified Theo, who, on 24 December, had proposed marriage to his old friend Andries Bonger's sister Johanna. That evening, Theo rushed to the station to board a night train to Arles. He arrived on Christmas Day and comforted Vincent, who seemed to be semi-lucid. That evening, he left Arles for the return trip to Paris.During the first days of his treatment, Van Gogh repeatedly and unsuccessfully asked for Gauguin, who asked a policeman attending the case to "be kind enough, Monsieur, to awaken this man with great care, and if he asks for me tell him I have left for Paris; the sight of me might prove fatal for him." Gauguin fled Arles, never to see Van Gogh again. They continued to correspond, and in 1890, Gauguin proposed they form a studio in Antwerp. Meanwhile, other visitors to the hospital included Marie Ginoux and Roulin.Despite a pessimistic diagnosis, Van Gogh recovered and returned to the Yellow House on 7 January 1889. He spent the following month between hospital and home, suffering from hallucinations and delusions of poisoning. In March, the police closed his house after a petition by 30 townspeople (including the Ginoux family) who described him as le fou roux "the redheaded madman"; Van Gogh returned to hospital. Paul Signac visited him twice in March; in April, Van Gogh moved into rooms owned by Dr Rey after floods damaged paintings in his own home. Two months later, he left Arles and voluntarily entered an asylum in Saint-Rémy-de-Provence. Around this time, he wrote, "Sometimes moods of indescribable anguish, sometimes moments when the veil of time and fatality of circumstances seemed to be torn apart for an instant."Van Gogh gave his 1889 Portrait of Doctor Félix Rey to Dr Rey. The physician was not fond of the painting and used it to repair a chicken coop, then gave it away. In 2016, the portrait was housed at the Pushkin Museum of Fine Arts and estimated to be worth over $50 million.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
==== Saint-Rémy (May 1889 – May 1890) ====
|
||||
|
||||
Van Gogh entered the Saint-Paul-de-Mausole asylum on 8 May 1889, accompanied by his caregiver, Frédéric Salles, a Protestant clergyman. Saint-Paul was a former monastery in Saint-Rémy, located less than 30 kilometres (19 mi) from Arles, and it was run by a former naval doctor, Théophile Peyron. Van Gogh had two cells with barred windows, one of which he used as a studio. The clinic and its garden became the main subjects of his paintings. He made several studies of the hospital's interiors, such as Vestibule of the Asylum and Saint-Rémy (September 1889), and its gardens, such as Lilacs (May 1889). Some of his works from this time are characterised by swirls, such as The Starry Night. He was allowed short supervised walks, during which time he painted cypresses and olive trees, including Valley with Ploughman Seen from Above, Olive Trees with the Alpilles in the Background 1889, Cypresses 1889, Cornfield with Cypresses (1889), Country road in Provence by Night (1890). In September 1889, he produced two further versions of Bedroom in Arles and The Gardener.Limited access to life outside the clinic resulted in a shortage of subject matter. Van Gogh instead worked on interpretations of other artist's paintings, such as Millet's The Sower and Noonday Rest, and variations on his own earlier work. Van Gogh was an admirer of the Realism of Jules Breton, Gustave Courbet and Millet, and he compared his copies to a musician's interpreting Beethoven.His Prisoners' Round (after Gustave Doré) (1890) was painted after an engraving by Gustave Doré (1832–1883). Tralbaut suggests that the face of the prisoner in the centre of the painting looking towards the viewer is Van Gogh himself; Jan Hulsker discounts this.Between February and April 1890, Van Gogh suffered a severe relapse. Depressed and unable to bring himself to write, he was still able to paint and draw a little during this time, and he later wrote to Theo that he had made a few small canvases "from memory ... reminisces of the North". Among these was Two Peasant Women Digging in a Snow-Covered Field at Sunset. Hulsker believes that this small group of paintings formed the nucleus of many drawings and study sheets depicting landscapes and figures that Van Gogh worked on during this time. He comments that this short period was the only time that Van Gogh's illness had a significant effect on his work. Van Gogh asked his mother and his brother to send him drawings and rough work he had done in the early 1880s so he could work on new paintings from his old sketches. Belonging to this period is Sorrowing Old Man ("At Eternity's Gate"), a colour study Hulsker describes as "another unmistakable remembrance of times long past". His late paintings show an artist at the height of his abilities, according to the art critic Robert Hughes, "longing for concision and grace".After the birth of his nephew, Van Gogh wrote, "I started right away to make a picture for him, to hang in their bedroom, branches of white almond blossom against a blue sky."
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
==== 1890 Exhibitions and recognition ====
|
||||
See also Vincent van Gogh's display at Les XX, 1890
|
||||
Albert Aurier praised his work in the Mercure de France in January 1890 and described him as "a genius". In February, Van Gogh painted five versions of L'Arlésienne (Madame Ginoux), based on a charcoal sketch Gauguin had produced when she sat for both artists in November 1888. Also in February, Van Gogh was invited by Les XX, a society of avant-garde painters in Brussels, to participate in their annual exhibition. At the opening dinner a Les XX member, Henry de Groux, insulted Van Gogh's work. Toulouse-Lautrec demanded satisfaction, and Signac declared he would continue to fight for Van Gogh's honour if Lautrec surrendered. De Groux apologised for the slight and left the group.
|
||||
From 20 March to 27 April 1890, Van Gogh was included in the sixth exhibition of the Société des Artistes Indépendants in the Pavillon de la Ville de Paris on the Champs-Elysées. Van Gogh exhibited ten paintings. While Van Gogh's exhibit was on display with the Artistes Indépendants in Paris, Claude Monet said that his work was the best in the show.
|
||||
|
||||
|
||||
==== Auvers-sur-Oise (May–July 1890) ====
|
||||
|
||||
In May 1890, Van Gogh left the clinic in Saint-Rémy to move nearer to both Dr Paul Gachet in the Paris suburb of Auvers-sur-Oise and to Theo. Gachet was an amateur painter and had treated several other artists – Camille Pissarro had recommended him. Van Gogh's first impression was that Gachet was "iller than I am, it seemed to me, or let's say just as much."The painter Charles Daubigny moved to Auvers in 1861 and in turn drew other artists there, including Camille Corot and Honoré Daumier. In July 1890, Van Gogh completed two paintings of Daubigny's Garden, one of which is likely his final work.
|
||||
During his last weeks at Saint-Rémy, his thoughts returned to "memories of the North", and several of the approximately 70 oils, painted during as many days in Auvers-sur-Oise, are reminiscent of northern scenes. In June 1890, he painted several portraits of his doctor, including Portrait of Dr Gachet, and his only etching. In each the emphasis is on Gachet's melancholic disposition. There are other paintings which are probably unfinished, including Thatched Cottages by a Hill.In July, Van Gogh wrote that he had become absorbed "in the immense plain against the hills, boundless as the sea, delicate yellow". He had first become captivated by the fields in May, when the wheat was young and green. In July, he described to Theo "vast fields of wheat under turbulent skies".He wrote that they represented his "sadness and extreme loneliness" and that the "canvases will tell you what I cannot say in words, that is, how healthy and invigorating I find the countryside". Wheatfield with Crows, although not his last oil work, is from July 1890 and Hulsker discusses it as being associated with "melancholy and extreme loneliness". Hulsker identifies seven oil paintings from Auvers that follow the completion of Wheatfield with Crows.
|
||||
|
||||
|
||||
=== Death ===
|
||||
|
||||
On 27 July 1890, aged 37, Van Gogh shot himself in the chest with a revolver. The shooting may have taken place in the wheat field in which he had been painting, or in a local barn. The bullet was deflected by a rib and passed through his chest without doing apparent damage to internal organs – possibly stopped by his spine. He was able to walk back to the Auberge Ravoux, where he was attended to by two doctors. One of them, Dr Gachet, served as a war surgeon in 1870 and had extensive knowledge of gunshots. Vincent was possibly attended to during the night by Dr Gachet's son Paul Louis Gachet and the innkeeper, Arthur Ravoux. The following morning, Theo rushed to his brother's side, finding him in good spirits. But within hours Vincent's health began to fail, suffering from an infection resulting from the wound. He died in the early hours of 29 July. According to Theo, Vincent's last words were: "The sadness will last forever".
|
||||
Van Gogh was buried on 30 July, in the municipal cemetery of Auvers-sur-Oise. The funeral was attended by Theo van Gogh, Andries Bonger, Charles Laval, Lucien Pissarro, Émile Bernard, Julien Tanguy and Paul Gachet, among twenty family members, friends and locals. Theo suffered from syphilis, and his health began to decline further after his brother's death. Weak and unable to come to terms with Vincent's absence, he died on 25 January 1891 at Den Dolder and was buried in Utrecht. In 1914, Johanna van Gogh-Bonger had Theo's body exhumed and moved from Utrecht to be re-buried alongside Vincent's at Auvers-sur-Oise.There have been numerous debates as to the nature of Van Gogh's illness and its effect on his work, and many retrospective diagnoses have been proposed. The consensus is that Van Gogh had an episodic condition with periods of normal functioning. Perry was the first to suggest bipolar disorder in 1947, and this has been supported by the psychiatrists Hemphill and Blumer. Biochemist Wilfred Arnold has countered that the symptoms are more consistent with acute intermittent porphyria, noting that the popular link between bipolar disorder and creativity might be spurious. Temporal lobe epilepsy with bouts of depression has also been suggested. Whatever the diagnosis, his condition was likely worsened by malnutrition, overwork, insomnia and alcohol.
|
||||
|
||||
|
||||
== Style and works ==
|
||||
|
||||
|
||||
=== Artistic development ===
|
||||
Van Gogh drew and painted with watercolours while at school, but only a few examples survive and the authorship of some has been challenged. When he took up art as an adult, he began at an elementary level. In early 1882, his uncle, Cornelis Marinus, owner of a well-known gallery of contemporary art in Amsterdam, asked for drawings of The Hague. Van Gogh's work did not live up to expectations. Marinus offered a second commission, specifying the subject matter in detail, but was again disappointed with the result. Van Gogh persevered; he experimented with lighting in his studio using variable shutters and different drawing materials. For more than a year he worked on single figures – highly elaborate studies in black and white, which at the time gained him only criticism. Later, they were recognised as early masterpieces.In August 1882, Theo gave Vincent money to buy materials for working en plein air. Vincent wrote that he could now "go on painting with new vigour". From early 1883, he worked on multi-figure compositions. He had some of them photographed, but when his brother remarked that they lacked liveliness and freshness, he destroyed them and turned to oil painting. Van Gogh turned to well-known Hague School artists like Weissenbruch and Blommers, and he received technical advice from them as well as from painters like De Bock and Van der Weele, both of the Hague School's second generation. He moved to Nuenen after a short period of time in Drenthe and began work on several large paintings but destroyed most of them. The Potato Eaters and its companion pieces are the only ones to have survived. Following a visit to the Rijksmuseum Van Gogh wrote of his admiration for the quick, economical brushwork of the Dutch Masters, especially Rembrandt and Frans Hals. He was aware many of his faults were due to lack of experience and technical expertise, so in November 1885 he travelled to Antwerp and later Paris to learn and develop his skills.
|
||||
Theo criticised The Potato Eaters for its dark palette, which he thought unsuitable for a modern style. During Van Gogh's stay in Paris between 1886 and 1887, he tried to master a new, lighter palette. His Portrait of Père Tanguy (1887) shows his success with the brighter palette and is evidence of an evolving personal style. Charles Blanc's treatise on colour interested him greatly and led him to work with complementary colours. Van Gogh came to believe that the effect of colour went beyond the descriptive; he said that "colour expresses something in itself". According to Hughes, Van Gogh perceived colour as having a "psychological and moral weight", as exemplified in the garish reds and greens of The Night Café, a work he wanted to "express the terrible passions of humanity". Yellow meant the most to him, because it symbolised emotional truth. He used yellow as a symbol for sunlight, life, and God.Van Gogh strove to be a painter of rural life and nature; during his first summer in Arles he used his new palette to paint landscapes and traditional rural life. His belief that a power existed behind the natural led him to try to capture a sense of that power, or the essence of nature in his art, sometimes through the use of symbols. His renditions of the sower, at first copied from Jean-François Millet, reflect the influence of Thomas Carlyle and Friedrich Nietzsche's thoughts on the heroism of physical labour, as well as Van Gogh's religious beliefs: the sower as Christ sowing life beneath the hot sun. These were themes and motifs he returned to often to rework and develop. His paintings of flowers are filled with symbolism, but rather than use traditional Christian iconography he made up his own, where life is lived under the sun and work is an allegory of life. In Arles, having gained confidence after painting spring blossoms and learning to capture bright sunlight, he was ready to paint The Sower.
|
||||
Van Gogh stayed within what he called the "guise of reality" and was critical of overly stylised works. He wrote afterwards that the abstraction of Starry Night had gone too far and that reality had "receded too far in the background". Hughes describes it as a moment of extreme visionary ecstasy: the stars are in a great whirl, reminiscent of Hokusai's Great Wave, the movement in the heaven above is reflected by the movement of the cypress on the earth below, and the painter's vision is "translated into a thick, emphatic plasma of paint".Between 1885 and his death in 1890, Van Gogh appears to have been building an oeuvre, a collection that reflected his personal vision and could be commercially successful. He was influenced by Blanc's definition of style, that a true painting required optimal use of colour, perspective and brushstrokes. Van Gogh applied the word "purposeful" to paintings he thought he had mastered, as opposed to those he thought of as studies. He painted many series of studies; most of which were still lifes, many executed as colour experiments or as gifts to friends. The work in Arles contributed considerably to his oeuvre: those he thought the most important from that time were The Sower, Night Cafe, Memory of the Garden in Etten and Starry Night. With their broad brushstrokes, inventive perspectives, colours, contours and designs, these paintings represent the style he sought.
|
||||
|
||||
|
||||
=== Major series ===
|
||||
|
||||
Van Gogh's stylistic developments are usually linked to the periods he spent living in different places across Europe. He was inclined to immerse himself in local cultures and lighting conditions, although he maintained a highly individual visual outlook throughout. His evolution as an artist was slow, and he was aware of his painterly limitations. He moved home often, perhaps to expose himself to new visual stimuli, and through exposure develop his technical skill. Art historian Melissa McQuillan believes the moves also reflect later stylistic changes, and that Van Gogh used the moves to avoid conflict, and as a coping mechanism for when the idealistic artist was faced with the realities of his then current situation.
|
||||
|
||||
|
||||
==== Portraits ====
|
||||
|
||||
Van Gogh said portaiture was his greatest interest. "What I'm most passionate about, much much more than all the rest in my profession", he wrote in 1890, "is the portrait, the modern portrait." It is "the only thing in painting that moves me deeply and that gives me a sense of the infinite." He wrote to his sister that he wished to paint portraits that would endure, and that he would use colour to capture their emotions and character rather than aiming for photographic realism. Those closest to Van Gogh are mostly absent from his portraits; he rarely painted Theo, Van Rappard or Bernard. The portraits of his mother were from photographs.Van Gogh painted Arles' postmaster Joseph Roulin and his family repeatedly. In five versions of La Berceuse (The Lullaby), Van Gogh painted Augustine Roulin quietly holding a rope that rocks the unseen cradle of her infant daughter. Van Gogh had planned for it to be the central image of a triptych, flanked by paintings of sunflowers.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
==== Self-portraits ====
|
||||
|
||||
Van Gogh created more than 43 self-portraits between 1885 and 1889. They were usually completed in series, such as those painted in Paris in mid-1887, and continued until shortly before his death. Generally the portraits were studies, created during periods when he was reluctant to mix with others, or when he lacked models, and so painted himself.The self-portraits reflect a high degree of self-scrutiny. Often they were intended to mark important periods in his life; for example, the mid-1887 Paris series were painted at the point where he became aware of Claude Monet, Paul Cézanne and Signac. In Self-Portrait with Grey Felt Hat, heavy strains of paint spread outwards across the canvas. It is one of his most renowned self-portraits of that period, "with its highly organized rhythmic brushstrokes, and the novel halo derived from the Neo-impressionist repertoire was what Van Gogh himself called a 'purposeful' canvas".They contain a wide array of physiognomical representations. Van Gogh's mental and physical condition is usually apparent; he may appear unkempt, unshaven or with a neglected beard, with deeply sunken eyes, a weak jaw, or having lost teeth. Some show him with full lips, a long face or prominent skull, or sharpened, alert features. His hair is sometimes depicted in a vibrant reddish hue and at other times ash colored.Van Gogh's self-portraits vary stylistically. In those painted after December 1888, the strong contrast of vivid colors highlight the haggard pallor of his skin. Some depict the artist with a beard, others without. He can be seen with bandages in portraits executed just after he mutilated his ear. In only a few does he depict himself as a painter. Those painted in Saint-Rémy show the head from the right, the side opposite his damaged ear, as he painted himself reflected in his mirror.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
==== Flowers ====
|
||||
|
||||
Van Gogh painted several landscapes with flowers, including roses, lilacs, irises, and sunflowers. Some reflect his interests in the language of colour, and also in Japanese ukiyo-e. There are two series of dying sunflowers. The first was painted in Paris in 1887 and shows flowers lying on the ground. The second set was completed a year later in Arles and is of bouquets in a vase positioned in early morning light. Both are built from thickly layered paintwork, which, according to the London National Gallery, evoke the "texture of the seed-heads".In these series, Van Gogh was not preoccupied by his usual interest in filling his paintings with subjectivity and emotion; rather, the two series are intended to display his technical skill and working methods to Gauguin, who was about to visit. The 1888 paintings were created during a rare period of optimism for the artist. Vincent wrote to Theo in August 1888:
|
||||
|
||||
I'm painting with the gusto of a Marseillais eating bouillabaisse, which won't surprise you when it's a question of painting large sunflowers ... If I carry out this plan there'll be a dozen or so panels. The whole thing will therefore be a symphony in blue and yellow. I work on it all these mornings, from sunrise. Because the flowers wilt quickly and it's a matter of doing the whole thing in one go.
|
||||
The sunflowers were painted to decorate the walls in anticipation of Gauguin's visit, and Van Gogh placed individual works around the Yellow House's guest room in Arles. Gauguin was deeply impressed and later acquired two of the Paris versions. After Gauguin's departure, Van Gogh imagined the two major versions of the sunflowers as wings of the Berceuse Triptych, and included them in his Les XX in Brussels exhibit. Today the major pieces of the series are among his best known, celebrated for the sickly connotations of the colour yellow and its tie-in with the Yellow House, the expressionism of the brush strokes, and their contrast against often dark backgrounds.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
==== Cypresses and olives ====
|
||||
|
||||
Fifteen canvases depict cypresses, a tree he became fascinated with in Arles. He brought life to the trees, which were traditionally seen as emblematic of death. The series of cypresses he began in Arles featured the trees in the distance, as windbreaks in fields; when he was at Saint-Rémy he brought them to the foreground. Vincent wrote to Theo in May 1889: "Cypresses still preoccupy me, I should like to do something with them like my canvases of sunflowers"; he went on to say, "They are beautiful in line and proportion like an Egyptian obelisk."In mid-1889, and at his sister Wil's request, Van Gogh painted several smaller versions of Wheat Field with Cypresses. The works are characterised by swirls and densely painted impasto, and include The Starry Night, in which cypresses dominate the foreground. In addition to this, other notable works on cypresses include Cypresses (1889), Cypresses with Two Figures (1889–90), and Road with Cypress and Star (1890).During the last six or seven months of the year 1889, he had also created at least fifteen paintings of olive trees, a subject which he considered as demanding and compelling. Among these works are Olive Trees with the Alpilles in the Background (1889), about which in a letter to his brother Van Gogh wrote, "At last I have a landscape with olives". While in Saint-Rémy, Van Gogh spent time outside the asylum, where he painted trees in the olive groves. In these works, natural life is rendered as gnarled and arthritic as if a personification of the natural world, which are, according to Hughes, filled with "a continuous field of energy of which nature is a manifestation".
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
==== Orchards ====
|
||||
|
||||
The Flowering Orchards (also the Orchards in Blossom) are among the first groups of work completed after Van Gogh's arrival in Arles in February 1888. The 14 paintings are optimistic, joyous and visually expressive of the burgeoning spring. They are delicately sensitive and unpopulated. He painted swiftly, and although he brought to this series a version of Impressionism, a strong sense of personal style began to emerge during this period. The transience of the blossoming trees, and the passing of the season, seemed to align with his sense of impermanence and belief in a new beginning in Arles. During the blossoming of the trees that spring, he found "a world of motifs that could not have been more Japanese". Vincent wrote to Theo on 21 April 1888 that he had 10 orchards and "one big [painting] of a cherry tree, which I've spoiled".During this period Van Gogh mastered the use of light by subjugating shadows and painting the trees as if they are the source of light – almost in a sacred manner. Early the following year he painted another smaller group of orchards, including View of Arles, Flowering Orchards. Van Gogh was enthralled by the landscape and vegetation of the south of France, and often visited the farm gardens near Arles. In the vivid light of the Mediterranean climate his palette significantly brightened.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
==== Wheat fields ====
|
||||
|
||||
Van Gogh made several painting excursions during visits to the landscape around Arles. He made paintings of harvests, wheat fields and other rural landmarks of the area, including The Old Mill (1888); a good example of a picturesque structure bordering the wheat fields beyond. At various points, Van Gogh painted the view from his window – at The Hague, Antwerp, and Paris. These works culminated in The Wheat Field series, which depicted the view from his cells in the asylum at Saint-Rémy.Many of the late paintings are sombre but essentially optimistic and, right up to the time of Van Gogh's death, reflect his desire to return to lucid mental health. Yet some of his final works reflect his deepening concerns. Writing in July 1890, from Auvers, Van Gogh said that he had become absorbed "in the immense plain against the hills, boundless as the sea, delicate yellow".Van Gogh was captivated by the fields in May when the wheat was young and green. His Wheatfields at Auvers with White House shows a more subdued palette of yellows and blues, which creates a sense of idyllic harmony.About 10 July 1890, Van Gogh wrote to Theo of "vast fields of wheat under troubled skies". Wheatfield with Crows shows the artist's state of mind in his final days; Hulsker describes the work as a "doom-filled painting with threatening skies and ill-omened crows". Its dark palette and heavy brushstrokes convey a sense of menace.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
== Reputation and legacy ==
|
||||
|
||||
After Van Gogh's first exhibitions in the late 1880s, his reputation grew steadily among artists, art critics, dealers and collectors. In 1887, André Antoine hung Van Gogh's alongside works of Georges Seurat and Paul Signac, at the Théâtre Libre in Paris; some were acquired by Julien Tanguy. In 1889, his work was described in the journal Le Moderniste Illustré by Albert Aurier as characterised by "fire, intensity, sunshine". Ten paintings were shown at the Société des Artistes Indépendants, in Brussels in January 1890. French president Marie François Sadi Carnot was said to have been impressed by Van Gogh's work.After Van Gogh's death, memorial exhibitions were held in Brussels, Paris, The Hague and Antwerp. His work was shown in several high-profile exhibitions, including six works at Les XX; in 1891 there was a retrospective exhibition in Brussels. In 1892, Octave Mirbeau wrote that Van Gogh's suicide was an "infinitely sadder loss for art ... even though the populace has not crowded to a magnificent funeral, and poor Vincent van Gogh, whose demise means the extinction of a beautiful flame of genius, has gone to his death as obscure and neglected as he lived."Theo died in January 1891, removing Vincent's most vocal and well-connected champion. Theo's widow Johanna van Gogh-Bonger was a Dutchwoman in her twenties who had not known either her husband or her brother-in-law very long and who suddenly had to take care of several hundreds of paintings, letters and drawings, as well as her infant son, Vincent Willem van Gogh. Gauguin was not inclined to offer assistance in promoting Van Gogh's reputation, and Johanna's brother Andries Bonger also seemed lukewarm about his work. Aurier, one of Van Gogh's earliest supporters among the critics, died of typhoid fever in 1892 at the age of 27.
|
||||
In 1892, Émile Bernard organised a small solo show of Van Gogh's paintings in Paris, and Julien Tanguy exhibited his Van Gogh paintings with several consigned from Johanna van Gogh-Bonger. In April 1894, the Durand-Ruel Gallery in Paris agreed to take 10 paintings on consignment from Van Gogh's estate. In 1896, the Fauvist painter Henri Matisse, then an unknown art student, visited John Russell on Belle Île off Brittany. Russell had been a close friend of Van Gogh; he introduced Matisse to the Dutchman's work, and gave him a Van Gogh drawing. Influenced by Van Gogh, Matisse abandoned his earth-coloured palette for bright colours.In Paris in 1901, a large Van Gogh retrospective was held at the Bernheim-Jeune Gallery, which excited André Derain and Maurice de Vlaminck, and contributed to the emergence of Fauvism. Important group exhibitions took place with the Sonderbund artists in Cologne in 1912, the Armory Show, New York in 1913, and Berlin in 1914. Henk Bremmer was instrumental in teaching and talking about Van Gogh, and introduced Helene Kröller-Müller to Van Gogh's art; she became an avid collector of his work. The early figures in German Expressionism such as Emil Nolde acknowledged a debt to Van Gogh's work. Bremmer assisted Jacob Baart de la Faille, whose catalogue raisonné L'Oeuvre de Vincent van Gogh appeared in 1928.
|
||||
Van Gogh's fame reached its first peak in Austria and Germany before World War I, helped by the publication of his letters in three volumes in 1914. His letters are expressive and literate, and have been described as among the foremost 19th-century writings of their kind. These began a compelling mythology of Van Gogh as an intense and dedicated painter who suffered for his art and died young. In 1934, the novelist Irving Stone wrote a biographical novel of Van Gogh's life titled Lust for Life, based on Van Gogh's letters to Theo. This novel and the 1956 film further enhanced his fame, especially in the United States where Stone surmised only a few hundred people had heard of Van Gogh prior to his surprise best-selling book.In 1957, Francis Bacon based a series of paintings on reproductions of Van Gogh's The Painter on the Road to Tarascon, the original of which was destroyed during the Second World War. Bacon was inspired by an image he described as "haunting", and regarded Van Gogh as an alienated outsider, a position which resonated with him. Bacon identified with Van Gogh's theories of art and quoted lines written to Theo: "[R]eal painters do not paint things as they are ... [T]hey paint them as they themselves feel them to be."Van Gogh's works are among the world's most expensive paintings. Those sold for over US$100 million (today's equivalent) include Portrait of Dr Gachet, Portrait of Joseph Roulin and Irises. The Metropolitan Museum of Art acquired a copy of Wheat Field with Cypresses in 1993 for US$57 million by using funds donated by publisher, diplomat and philanthropist Walter Annenberg. In 2015, L'Allée des Alyscamps sold for US$66.3 million at Sotheby's, New York, exceeding its reserve of US$40 million.Minor planet 4457 van Gogh is named in his honour.In October 2022, two activists protesting the effects of the fossil fuel industry on climate change threw a can of tomato soup on Van Gogh's Sunflowers in the National Gallery, London, and then glued their hands to the gallery wall. As the painting was covered by glass it was not damaged.
|
||||
|
||||
|
||||
=== Van Gogh Museum ===
|
||||
|
||||
Van Gogh's nephew and namesake, Vincent Willem van Gogh (1890–1978), inherited the estate after his mother's death in 1925. During the early 1950s he arranged for the publication of a complete edition of the letters presented in four volumes and several languages. He then began negotiations with the Dutch government to subsidise a foundation to purchase and house the entire collection. Theo's son participated in planning the project in the hope that the works would be exhibited under the best possible conditions. The project began in 1963; architect Gerrit Rietveld was commissioned to design it, and after his death in 1964 Kisho Kurokawa took charge. Work progressed throughout the 1960s, with 1972 as the target for its grand opening.The Van Gogh Museum opened in the Museumplein in Amsterdam in 1973. It became the second most popular museum in the Netherlands, after the Rijksmuseum, regularly receiving more than 1.5 million visitors a year. In 2015 it had a record 1.9 million. Eighty-five percent of the visitors come from other countries.
|
||||
|
||||
|
||||
== Nazi-looted art ==
|
||||
|
||||
During the Nazi period (1933–1945) a great number of artworks by Van Gogh changed hands, many of them looted from Jewish collectors who were forced into exile or murdered. Some of these works have disappeared into private collections. Others have since resurfaced in museums, or at auction, or have been reclaimed, often in high-profile lawsuits, by their former owners. The German Lost Art Foundation still lists dozens of missing van Goghs and the American Alliance of Museums lists 73 van Goghs on the Nazi Era Provenance Internet Portal.
|
||||
|
||||
|
||||
== References ==
|
||||
|
||||
|
||||
=== Explanatory footnotes ===
|
||||
|
||||
|
||||
=== Citations ===
|
||||
|
||||
|
||||
=== General and cited sources ===
|
||||
|
||||
|
||||
== External links ==
|
||||
|
||||
The Vincent van Gogh Gallery, the complete works and letters of Van Gogh
|
||||
Vincent van Gogh The letters, the complete letters of Van Gogh (translated into English and annotated)
|
||||
Vincent van Gogh, teaching resource on Van Gogh
|
||||
Works by Vincent van Gogh at Project Gutenberg
|
||||
Works by or about Vincent van Gogh at Internet Archive
|
||||
Works by Vincent van Gogh at LibriVox (public domain audiobooks)
|
||||
@@ -1,47 +0,0 @@
|
||||
import { ChatMessage, SimpleChatEngine } from "llamaindex";
|
||||
import { stdin as input, stdout as output } from "node:process";
|
||||
import readline from "node:readline/promises";
|
||||
import { Anthropic } from "../../packages/core/src/llm/LLM";
|
||||
|
||||
async function main() {
|
||||
const query: string = `
|
||||
Where is Istanbul?
|
||||
`;
|
||||
|
||||
// const llm = new OpenAI({ model: "gpt-3.5-turbo", temperature: 0.1 });
|
||||
const llm = new Anthropic();
|
||||
const message: ChatMessage = { content: query, role: "user" };
|
||||
|
||||
//TODO: Add callbacks later
|
||||
|
||||
//Stream Complete
|
||||
//Note: Setting streaming flag to true or false will auto-set your return type to
|
||||
//either an AsyncGenerator or a Response.
|
||||
// Omitting the streaming flag automatically sets streaming to false
|
||||
|
||||
const chatEngine: SimpleChatEngine = new SimpleChatEngine({
|
||||
chatHistory: undefined,
|
||||
llm: llm,
|
||||
});
|
||||
|
||||
const rl = readline.createInterface({ input, output });
|
||||
while (true) {
|
||||
const query = await rl.question("Query: ");
|
||||
|
||||
if (!query) {
|
||||
break;
|
||||
}
|
||||
|
||||
//Case 1: .chat(query, undefined, true) => Stream
|
||||
//Case 2: .chat(query, undefined, false) => Response object
|
||||
//Case 3: .chat(query, undefined) => Response object
|
||||
const chatStream = await chatEngine.chat(query, undefined, true);
|
||||
var accumulated_result = "";
|
||||
for await (const part of chatStream) {
|
||||
accumulated_result += part;
|
||||
process.stdout.write(part);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -0,0 +1,48 @@
|
||||
import {
|
||||
ImageNode,
|
||||
serviceContextFromDefaults,
|
||||
SimpleDirectoryReader,
|
||||
SimpleVectorStore,
|
||||
TextNode,
|
||||
VectorStoreIndex,
|
||||
} from "llamaindex";
|
||||
import * as path from "path";
|
||||
|
||||
async function main() {
|
||||
// read data into documents
|
||||
const reader = new SimpleDirectoryReader();
|
||||
const documents = await reader.loadData({
|
||||
directoryPath: "data/multi_modal",
|
||||
});
|
||||
// set up vector store index with two vector stores, one for text, the other for images
|
||||
const serviceContext = serviceContextFromDefaults({ chunkSize: 512 });
|
||||
const vectorStore = await SimpleVectorStore.fromPersistDir("./storage/text");
|
||||
const imageVectorStore =
|
||||
await SimpleVectorStore.fromPersistDir("./storage/images");
|
||||
const index = await VectorStoreIndex.fromDocuments(documents, {
|
||||
serviceContext,
|
||||
imageVectorStore,
|
||||
vectorStore,
|
||||
});
|
||||
// retrieve documents using the index
|
||||
const retriever = index.asRetriever();
|
||||
retriever.similarityTopK = 3;
|
||||
const results = await retriever.retrieve(
|
||||
"what are Vincent van Gogh's famous paintings",
|
||||
);
|
||||
for (const result of results) {
|
||||
const node = result.node;
|
||||
if (!node) {
|
||||
continue;
|
||||
}
|
||||
if (node instanceof ImageNode) {
|
||||
console.log(`Image: ${path.join(__dirname, node.id_)}`);
|
||||
} else if (node instanceof TextNode) {
|
||||
console.log("Text:", (node as TextNode).text.substring(0, 128));
|
||||
}
|
||||
console.log(`ID: ${node.id_}`);
|
||||
console.log(`Similarity: ${result.score}`);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -3,10 +3,14 @@
|
||||
"private": true,
|
||||
"name": "simple",
|
||||
"dependencies": {
|
||||
"@notionhq/client": "^2.2.13",
|
||||
"@pinecone-database/pinecone": "^1.1.2",
|
||||
"commander": "^11.1.0",
|
||||
"llamaindex": "latest"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18"
|
||||
"@types/node": "^18.18.6",
|
||||
"ts-node": "^10.9.1"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint ."
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# Postgres Vector Store
|
||||
|
||||
There are two scripts available here: load-docs.ts and query.ts
|
||||
|
||||
## Prerequisites
|
||||
|
||||
You'll need a postgres database instance against which to run these scripts. A simple docker command would look like this:
|
||||
|
||||
> `docker run -d --rm --name vector-db -p 5432:5432 -e "POSTGRES_HOST_AUTH_METHOD=trust" ankane/pgvector`
|
||||
|
||||
Set the PGHOST and PGUSER (and PGPASSWORD) environment variables to match your database setup.
|
||||
|
||||
You'll also need a value for OPENAI_API_KEY in your environment.
|
||||
|
||||
**NOTE:** Using `--rm` in the example docker command above means that the vector store will be deleted every time the container is stopped. For production purposes, use a volume to ensure persistence across restarts.
|
||||
|
||||
## Setup and Loading Docs
|
||||
|
||||
Read and follow the instructions in the README.md file located one directory up to make sure your JS/TS dependencies are set up. The commands listed below are also run from that parent directory.
|
||||
|
||||
To import documents and save the embedding vectors to your database:
|
||||
|
||||
> `npx ts-node pg-vector-store/load-docs.ts data`
|
||||
|
||||
where data is the directory containing your input files. Using the _data_ directory in the example above will read all of the files in that directory using the llamaindexTS default readers for each file type.
|
||||
|
||||
## RAG Querying
|
||||
|
||||
To query using the resulting vector store:
|
||||
|
||||
> `npx ts-node pg-vector-store/query.ts`
|
||||
|
||||
The script will prompt for a question, then process and present the answer using the PGVectorStore data and your OpenAI API key. It will continue to prompt until you enter `q`, `quit` or `exit` as the next query.
|
||||
@@ -0,0 +1,68 @@
|
||||
// load-docs.ts
|
||||
import fs from "fs/promises";
|
||||
import {
|
||||
PGVectorStore,
|
||||
SimpleDirectoryReader,
|
||||
storageContextFromDefaults,
|
||||
VectorStoreIndex,
|
||||
} from "llamaindex";
|
||||
|
||||
async function getSourceFilenames(sourceDir: string) {
|
||||
return await fs
|
||||
.readdir(sourceDir)
|
||||
.then((fileNames) => fileNames.map((file) => sourceDir + "/" + file));
|
||||
}
|
||||
|
||||
function callback(
|
||||
category: string,
|
||||
name: string,
|
||||
status: any,
|
||||
message: string = "",
|
||||
): boolean {
|
||||
console.log(category, name, status, message);
|
||||
return true;
|
||||
}
|
||||
|
||||
async function main(args: any) {
|
||||
const sourceDir: string = args.length > 2 ? args[2] : "../data";
|
||||
|
||||
console.log(`Finding documents in ${sourceDir}`);
|
||||
const fileList = await getSourceFilenames(sourceDir);
|
||||
const count = fileList.length;
|
||||
console.log(`Found ${count} files`);
|
||||
|
||||
console.log(`Importing contents from ${count} files in ${sourceDir}`);
|
||||
var fileName = "";
|
||||
try {
|
||||
// Passing callback fn to the ctor here
|
||||
// will enable looging to console.
|
||||
// See callback fn, defined above.
|
||||
const rdr = new SimpleDirectoryReader(callback);
|
||||
const docs = await rdr.loadData({ directoryPath: sourceDir });
|
||||
|
||||
const pgvs = new PGVectorStore();
|
||||
pgvs.setCollection(sourceDir);
|
||||
pgvs.clearCollection();
|
||||
|
||||
const ctx = await storageContextFromDefaults({ vectorStore: pgvs });
|
||||
|
||||
console.debug(" - creating vector store");
|
||||
const index = await VectorStoreIndex.fromDocuments(docs, {
|
||||
storageContext: ctx,
|
||||
});
|
||||
console.debug(" - done.");
|
||||
} catch (err) {
|
||||
console.error(fileName, err);
|
||||
console.log(
|
||||
"If your PGVectorStore init failed, make sure to set env vars for PGUSER or USER, PGHOST, PGPORT and PGPASSWORD as needed.",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(
|
||||
"Done. Try running query.ts to ask questions against the imported embeddings.",
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
main(process.argv).catch((err) => console.error(err));
|
||||
@@ -0,0 +1,69 @@
|
||||
import {
|
||||
PGVectorStore,
|
||||
VectorStoreIndex,
|
||||
serviceContextFromDefaults,
|
||||
} from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
const readline = require("readline").createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
});
|
||||
|
||||
try {
|
||||
const pgvs = new PGVectorStore();
|
||||
// Optional - set your collection name, default is no filter on this field.
|
||||
// pgvs.setCollection();
|
||||
|
||||
const ctx = serviceContextFromDefaults();
|
||||
const index = await VectorStoreIndex.fromVectorStore(pgvs, ctx);
|
||||
|
||||
// Query the index
|
||||
const queryEngine = await index.asQueryEngine();
|
||||
|
||||
let question = "";
|
||||
while (!isQuit(question)) {
|
||||
question = await getUserInput(readline);
|
||||
|
||||
if (isQuit(question)) {
|
||||
readline.close();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
try {
|
||||
const answer = await queryEngine.query(question);
|
||||
console.log(answer.response);
|
||||
} catch (error) {
|
||||
console.error("Error:", error);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
console.log(
|
||||
"If your PGVectorStore init failed, make sure to set env vars for PGUSER or USER, PGHOST, PGPORT and PGPASSWORD as needed.",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function isQuit(question: string) {
|
||||
return ["q", "quit", "exit"].includes(question.trim().toLowerCase());
|
||||
}
|
||||
|
||||
// Function to get user input as a promise
|
||||
function getUserInput(readline: any): Promise<string> {
|
||||
return new Promise((resolve) => {
|
||||
readline.question(
|
||||
"What would you like to know?\n>",
|
||||
(userInput: string) => {
|
||||
resolve(userInput);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
main()
|
||||
.catch(console.error)
|
||||
.finally(() => {
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -2,7 +2,10 @@ import fs from "node:fs/promises";
|
||||
|
||||
import {
|
||||
Anthropic,
|
||||
anthropicTextQaPrompt,
|
||||
CompactAndRefine,
|
||||
Document,
|
||||
ResponseSynthesizer,
|
||||
serviceContextFromDefaults,
|
||||
VectorStoreIndex,
|
||||
} from "llamaindex";
|
||||
@@ -18,12 +21,20 @@ async function main() {
|
||||
|
||||
// Split text and create embeddings. Store them in a VectorStoreIndex
|
||||
const serviceContext = serviceContextFromDefaults({ llm: new Anthropic() });
|
||||
|
||||
const responseSynthesizer = new ResponseSynthesizer({
|
||||
responseBuilder: new CompactAndRefine(
|
||||
serviceContext,
|
||||
anthropicTextQaPrompt,
|
||||
),
|
||||
});
|
||||
|
||||
const index = await VectorStoreIndex.fromDocuments([document], {
|
||||
serviceContext,
|
||||
});
|
||||
|
||||
// Query the index
|
||||
const queryEngine = index.asQueryEngine();
|
||||
const queryEngine = index.asQueryEngine({ responseSynthesizer });
|
||||
const response = await queryEngine.query(
|
||||
"What did the author do in college?",
|
||||
);
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
"devDependencies": {
|
||||
"@changesets/cli": "^2.26.2",
|
||||
"@turbo/gen": "^1.10.16",
|
||||
"@types/jest": "^29.5.8",
|
||||
"eslint": "^8.53.0",
|
||||
"@types/jest": "^29.5.10",
|
||||
"eslint": "^8.54.0",
|
||||
"eslint-config-custom": "workspace:*",
|
||||
"husky": "^8.0.3",
|
||||
"jest": "^29.7.0",
|
||||
|
||||
@@ -1,5 +1,22 @@
|
||||
# llamaindex
|
||||
|
||||
## 0.0.37
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 3bab231: Fixed errors (#225 and #226) Thanks @marcusschiesser
|
||||
|
||||
## 0.0.36
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Support for Claude 2.1
|
||||
- Add AssemblyAI integration (thanks @Swimburger)
|
||||
- Use cryptoJS (thanks @marcusschiesser)
|
||||
- Add PGVectorStore (thanks @mtutty)
|
||||
- Add CLIP embeddings (thanks @marcusschiesser)
|
||||
- Add MongoDB support (thanks @marcusschiesser)
|
||||
|
||||
## 0.0.35
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
{
|
||||
"name": "llamaindex",
|
||||
"version": "0.0.35",
|
||||
"version": "0.0.37",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "^0.9.0",
|
||||
"@anthropic-ai/sdk": "^0.9.1",
|
||||
"@notionhq/client": "^2.2.13",
|
||||
"js-tiktoken": "^1.0.7",
|
||||
"@xenova/transformers": "^2.8.0",
|
||||
"crypto-js": "^4.2.0",
|
||||
"js-tiktoken": "^1.0.8",
|
||||
"lodash": "^4.17.21",
|
||||
"mammoth": "^1.6.0",
|
||||
"md-utils-ts": "^2.0.0",
|
||||
"mongodb": "^6.2.0",
|
||||
"mongodb": "^6.3.0",
|
||||
"notion-md-crawler": "^0.0.2",
|
||||
"openai": "^4.16.1",
|
||||
"openai": "^4.20.0",
|
||||
"papaparse": "^5.4.1",
|
||||
"pdf-parse": "^1.1.1",
|
||||
"pg": "^8.11.3",
|
||||
"pgvector": "^0.1.5",
|
||||
"portkey-ai": "^0.1.16",
|
||||
"rake-modified": "^1.0.8",
|
||||
"replicate": "^0.21.1",
|
||||
@@ -22,14 +26,16 @@
|
||||
"wink-nlp": "^1.14.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash": "^4.14.200",
|
||||
"@types/node": "^18.18.8",
|
||||
"@types/papaparse": "^5.3.10",
|
||||
"@types/pdf-parse": "^1.1.3",
|
||||
"@types/uuid": "^9.0.6",
|
||||
"@types/crypto-js": "^4.2.1",
|
||||
"@types/lodash": "^4.14.202",
|
||||
"@types/node": "^18.18.12",
|
||||
"@types/papaparse": "^5.3.13",
|
||||
"@types/pdf-parse": "^1.1.4",
|
||||
"@types/pg": "^8.10.7",
|
||||
"@types/uuid": "^9.0.7",
|
||||
"node-stdlib-browser": "^1.2.0",
|
||||
"tsup": "^7.2.0",
|
||||
"typescript": "^5.2.2"
|
||||
"typescript": "^5.3.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
@@ -44,4 +50,4 @@
|
||||
"build": "tsup src/index.ts --format esm,cjs --dts",
|
||||
"dev": "tsup src/index.ts --format esm,cjs --dts --watch"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ export interface ChatEngine {
|
||||
T extends boolean | undefined = undefined,
|
||||
R = T extends true ? AsyncGenerator<string, void, unknown> : Response,
|
||||
>(
|
||||
message: string,
|
||||
message: MessageContent,
|
||||
chatHistory?: ChatMessage[],
|
||||
streaming?: T,
|
||||
): Promise<R>;
|
||||
@@ -56,7 +56,11 @@ export class SimpleChatEngine implements ChatEngine {
|
||||
async chat<
|
||||
T extends boolean | undefined = undefined,
|
||||
R = T extends true ? AsyncGenerator<string, void, unknown> : Response,
|
||||
>(message: string, chatHistory?: ChatMessage[], streaming?: T): Promise<R> {
|
||||
>(
|
||||
message: MessageContent,
|
||||
chatHistory?: ChatMessage[],
|
||||
streaming?: T,
|
||||
): Promise<R> {
|
||||
//Streaming option
|
||||
if (streaming) {
|
||||
return this.streamChat(message, chatHistory) as R;
|
||||
@@ -72,7 +76,7 @@ export class SimpleChatEngine implements ChatEngine {
|
||||
}
|
||||
|
||||
protected async *streamChat(
|
||||
message: string,
|
||||
message: MessageContent,
|
||||
chatHistory?: ChatMessage[],
|
||||
): AsyncGenerator<string, void, unknown> {
|
||||
chatHistory = chatHistory ?? this.chatHistory;
|
||||
@@ -144,14 +148,14 @@ export class CondenseQuestionChatEngine implements ChatEngine {
|
||||
T extends boolean | undefined = undefined,
|
||||
R = T extends true ? AsyncGenerator<string, void, unknown> : Response,
|
||||
>(
|
||||
message: string,
|
||||
message: MessageContent,
|
||||
chatHistory?: ChatMessage[] | undefined,
|
||||
streaming?: T,
|
||||
): Promise<R> {
|
||||
chatHistory = chatHistory ?? this.chatHistory;
|
||||
|
||||
const condensedQuestion = (
|
||||
await this.condenseQuestion(chatHistory, message)
|
||||
await this.condenseQuestion(chatHistory, extractText(message))
|
||||
).message.content;
|
||||
|
||||
const response = await this.queryEngine.query(condensedQuestion);
|
||||
@@ -256,7 +260,7 @@ export class ContextChatEngine implements ChatEngine {
|
||||
T extends boolean | undefined = undefined,
|
||||
R = T extends true ? AsyncGenerator<string, void, unknown> : Response,
|
||||
>(
|
||||
message: string,
|
||||
message: MessageContent,
|
||||
chatHistory?: ChatMessage[] | undefined,
|
||||
streaming?: T,
|
||||
): Promise<R> {
|
||||
@@ -272,7 +276,10 @@ export class ContextChatEngine implements ChatEngine {
|
||||
type: "wrapper",
|
||||
tags: ["final"],
|
||||
};
|
||||
const context = await this.contextGenerator.generate(message, parentEvent);
|
||||
const context = await this.contextGenerator.generate(
|
||||
extractText(message),
|
||||
parentEvent,
|
||||
);
|
||||
|
||||
chatHistory.push({ content: message, role: "user" });
|
||||
|
||||
@@ -291,7 +298,7 @@ export class ContextChatEngine implements ChatEngine {
|
||||
}
|
||||
|
||||
protected async *streamChat(
|
||||
message: string,
|
||||
message: MessageContent,
|
||||
chatHistory?: ChatMessage[] | undefined,
|
||||
): AsyncGenerator<string, void, unknown> {
|
||||
chatHistory = chatHistory ?? this.chatHistory;
|
||||
@@ -301,7 +308,10 @@ export class ContextChatEngine implements ChatEngine {
|
||||
type: "wrapper",
|
||||
tags: ["final"],
|
||||
};
|
||||
const context = await this.contextGenerator.generate(message, parentEvent);
|
||||
const context = await this.contextGenerator.generate(
|
||||
extractText(message),
|
||||
parentEvent,
|
||||
);
|
||||
|
||||
chatHistory.push({ content: message, role: "user" });
|
||||
|
||||
@@ -330,8 +340,8 @@ export class ContextChatEngine implements ChatEngine {
|
||||
|
||||
export interface MessageContentDetail {
|
||||
type: "text" | "image_url";
|
||||
text: string;
|
||||
image_url: { url: string };
|
||||
text?: string;
|
||||
image_url?: { url: string };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -339,6 +349,24 @@ export interface MessageContentDetail {
|
||||
*/
|
||||
export type MessageContent = string | MessageContentDetail[];
|
||||
|
||||
/**
|
||||
* Extracts just the text from a multi-modal message or the message itself if it's just text.
|
||||
*
|
||||
* @param message The message to extract text from.
|
||||
* @returns The extracted text
|
||||
*/
|
||||
function extractText(message: MessageContent): string {
|
||||
if (Array.isArray(message)) {
|
||||
// message is of type MessageContentDetail[] - retrieve just the text parts and concatenate them
|
||||
// so we can pass them to the context generator
|
||||
return (message as MessageContentDetail[])
|
||||
.filter((c) => c.type === "text")
|
||||
.map((c) => c.text)
|
||||
.join("\n\n");
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* HistoryChatEngine is a ChatEngine that uses a `ChatHistory` object
|
||||
* to keeps track of chat's message history.
|
||||
@@ -413,15 +441,8 @@ export class HistoryChatEngine {
|
||||
let requestMessages;
|
||||
let context;
|
||||
if (this.contextGenerator) {
|
||||
if (Array.isArray(message)) {
|
||||
// message is of type MessageContentDetail[] - retrieve just the text parts and concatenate them
|
||||
// so we can pass them to the context generator
|
||||
message = (message as MessageContentDetail[])
|
||||
.filter((c) => c.type === "text")
|
||||
.map((c) => c.text)
|
||||
.join("\n\n");
|
||||
}
|
||||
context = await this.contextGenerator.generate(message);
|
||||
const textOnly = extractText(message);
|
||||
context = await this.contextGenerator.generate(textOnly);
|
||||
}
|
||||
requestMessages = await chatHistory.requestMessages(
|
||||
context ? [context.message] : undefined,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import crypto from "crypto"; // TODO Node dependency
|
||||
import CryptoJS from "crypto-js";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
export enum NodeRelationship {
|
||||
@@ -14,6 +14,7 @@ export enum ObjectType {
|
||||
IMAGE = "IMAGE",
|
||||
INDEX = "INDEX",
|
||||
DOCUMENT = "DOCUMENT",
|
||||
IMAGE_DOCUMENT = "IMAGE_DOCUMENT",
|
||||
}
|
||||
|
||||
export enum MetadataMode {
|
||||
@@ -175,13 +176,13 @@ export class TextNode<T extends Metadata = Metadata> extends BaseNode<T> {
|
||||
* @returns
|
||||
*/
|
||||
generateHash() {
|
||||
const hashFunction = crypto.createHash("sha256");
|
||||
const hashFunction = CryptoJS.algo.SHA256.create();
|
||||
hashFunction.update(`type=${this.getType()}`);
|
||||
hashFunction.update(
|
||||
`startCharIdx=${this.startCharIdx} endCharIdx=${this.endCharIdx}`,
|
||||
);
|
||||
hashFunction.update(this.getContent(MetadataMode.ALL));
|
||||
return hashFunction.digest("base64");
|
||||
return hashFunction.finalize().toString(CryptoJS.enc.Base64);
|
||||
}
|
||||
|
||||
getType(): ObjectType {
|
||||
@@ -229,14 +230,6 @@ export class TextNode<T extends Metadata = Metadata> extends BaseNode<T> {
|
||||
}
|
||||
}
|
||||
|
||||
// export class ImageNode extends TextNode {
|
||||
// image: string = "";
|
||||
|
||||
// getType(): ObjectType {
|
||||
// return ObjectType.IMAGE;
|
||||
// }
|
||||
// }
|
||||
|
||||
export class IndexNode<T extends Metadata = Metadata> extends TextNode<T> {
|
||||
indexId: string = "";
|
||||
|
||||
@@ -272,26 +265,60 @@ export class Document<T extends Metadata = Metadata> extends TextNode<T> {
|
||||
}
|
||||
}
|
||||
|
||||
export function jsonToNode(json: any) {
|
||||
if (!json.type) {
|
||||
export function jsonToNode(json: any, type?: ObjectType) {
|
||||
if (!json.type && !type) {
|
||||
throw new Error("Node type not found");
|
||||
}
|
||||
const nodeType = type || json.type;
|
||||
|
||||
switch (json.type) {
|
||||
switch (nodeType) {
|
||||
case ObjectType.TEXT:
|
||||
return new TextNode(json);
|
||||
case ObjectType.INDEX:
|
||||
return new IndexNode(json);
|
||||
case ObjectType.DOCUMENT:
|
||||
return new Document(json);
|
||||
case ObjectType.IMAGE_DOCUMENT:
|
||||
return new ImageDocument(json);
|
||||
default:
|
||||
throw new Error(`Invalid node type: ${json.type}`);
|
||||
throw new Error(`Invalid node type: ${nodeType}`);
|
||||
}
|
||||
}
|
||||
|
||||
// export class ImageDocument extends Document {
|
||||
// image?: string;
|
||||
// }
|
||||
export type ImageType = string | Blob | URL;
|
||||
|
||||
export type ImageNodeConstructorProps<T extends Metadata> = Pick<
|
||||
ImageNode<T>,
|
||||
"image" | "id_"
|
||||
> &
|
||||
Partial<ImageNode<T>>;
|
||||
|
||||
export class ImageNode<T extends Metadata = Metadata> extends TextNode<T> {
|
||||
image: ImageType; // image as blob
|
||||
|
||||
constructor(init: ImageNodeConstructorProps<T>) {
|
||||
super(init);
|
||||
this.image = init.image;
|
||||
}
|
||||
|
||||
getType(): ObjectType {
|
||||
return ObjectType.IMAGE;
|
||||
}
|
||||
}
|
||||
|
||||
export class ImageDocument<T extends Metadata = Metadata> extends ImageNode<T> {
|
||||
constructor(init: ImageNodeConstructorProps<T>) {
|
||||
super(init);
|
||||
|
||||
if (new.target === ImageDocument) {
|
||||
this.hash = this.generateHash();
|
||||
}
|
||||
}
|
||||
|
||||
getType() {
|
||||
return ObjectType.IMAGE_DOCUMENT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node with a similarity score
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import { Document, NodeRelationship, TextNode } from "./Node";
|
||||
import {
|
||||
BaseNode,
|
||||
Document,
|
||||
ImageDocument,
|
||||
NodeRelationship,
|
||||
TextNode,
|
||||
} from "./Node";
|
||||
import { SentenceSplitter } from "./TextSplitter";
|
||||
import { DEFAULT_CHUNK_OVERLAP, DEFAULT_CHUNK_SIZE } from "./constants";
|
||||
|
||||
@@ -27,12 +33,19 @@ export function getTextSplitsFromDocument(
|
||||
* @returns An array of nodes.
|
||||
*/
|
||||
export function getNodesFromDocument(
|
||||
document: Document,
|
||||
doc: BaseNode,
|
||||
textSplitter: SentenceSplitter,
|
||||
includeMetadata: boolean = true,
|
||||
includePrevNextRel: boolean = true,
|
||||
) {
|
||||
let nodes: TextNode[] = [];
|
||||
if (doc instanceof ImageDocument) {
|
||||
return [doc];
|
||||
}
|
||||
if (!(doc instanceof Document)) {
|
||||
throw new Error("Expected either an Image Document or Document");
|
||||
}
|
||||
const document = doc as Document;
|
||||
const nodes: TextNode[] = [];
|
||||
|
||||
const textSplits = getTextSplitsFromDocument(document, textSplitter);
|
||||
|
||||
@@ -62,7 +75,7 @@ export function getNodesFromDocument(
|
||||
}
|
||||
|
||||
/**
|
||||
* A NodeParser generates TextNodes from Documents
|
||||
* A NodeParser generates Nodes from Documents
|
||||
*/
|
||||
export interface NodeParser {
|
||||
/**
|
||||
@@ -70,7 +83,7 @@ export interface NodeParser {
|
||||
* @param documents - The documents to generate nodes from.
|
||||
* @returns An array of nodes.
|
||||
*/
|
||||
getNodesFromDocuments(documents: Document[]): TextNode[];
|
||||
getNodesFromDocuments(documents: BaseNode[]): BaseNode[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,7 +134,7 @@ export class SimpleNodeParser implements NodeParser {
|
||||
* Generate Node objects from documents
|
||||
* @param documents
|
||||
*/
|
||||
getNodesFromDocuments(documents: Document[]) {
|
||||
getNodesFromDocuments(documents: BaseNode[]) {
|
||||
return documents
|
||||
.map((document) => getNodesFromDocument(document, this.textSplitter))
|
||||
.flat();
|
||||
|
||||
@@ -36,6 +36,15 @@ Answer:`;
|
||||
|
||||
export type TextQaPrompt = typeof defaultTextQaPrompt;
|
||||
|
||||
export const anthropicTextQaPrompt = ({ context = "", query = "" }) => {
|
||||
return `Context information:
|
||||
<context>
|
||||
${context}
|
||||
</context>
|
||||
Given the context information and not prior knowledge, answer the query.
|
||||
Query: ${query}`;
|
||||
};
|
||||
|
||||
/*
|
||||
DEFAULT_SUMMARY_PROMPT_TMPL = (
|
||||
"Write a summary of the following. Try to use only the "
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { Event } from "./callbacks/CallbackManager";
|
||||
import { BaseNodePostprocessor } from "./indices/BaseNodePostprocessor";
|
||||
import { NodeWithScore, TextNode } from "./Node";
|
||||
import {
|
||||
BaseQuestionGenerator,
|
||||
@@ -10,8 +12,6 @@ import { CompactAndRefine, ResponseSynthesizer } from "./ResponseSynthesizer";
|
||||
import { BaseRetriever } from "./Retriever";
|
||||
import { ServiceContext, serviceContextFromDefaults } from "./ServiceContext";
|
||||
import { QueryEngineTool, ToolMetadata } from "./Tool";
|
||||
import { Event } from "./callbacks/CallbackManager";
|
||||
import { BaseNodePostprocessor } from "./indices/BaseNodePostprocessor";
|
||||
|
||||
/**
|
||||
* A query engine is a question answerer that can use one or more steps.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { BaseEmbedding, OpenAIEmbedding } from "./Embedding";
|
||||
import { CallbackManager } from "./callbacks/CallbackManager";
|
||||
import { BaseEmbedding, OpenAIEmbedding } from "./embeddings";
|
||||
import { LLM, OpenAI } from "./llm/LLM";
|
||||
import { NodeParser, SimpleNodeParser } from "./NodeParser";
|
||||
import { PromptHelper } from "./PromptHelper";
|
||||
import { CallbackManager } from "./callbacks/CallbackManager";
|
||||
import { LLM, OpenAI } from "./llm/LLM";
|
||||
|
||||
/**
|
||||
* The ServiceContext is a collection of components that are used in different parts of the application.
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
import { ImageType } from "../Node";
|
||||
import { MultiModalEmbedding } from "./MultiModalEmbedding";
|
||||
import { readImage } from "./utils";
|
||||
|
||||
export enum ClipEmbeddingModelType {
|
||||
XENOVA_CLIP_VIT_BASE_PATCH32 = "Xenova/clip-vit-base-patch32",
|
||||
XENOVA_CLIP_VIT_BASE_PATCH16 = "Xenova/clip-vit-base-patch16",
|
||||
}
|
||||
|
||||
export class ClipEmbedding extends MultiModalEmbedding {
|
||||
modelType: ClipEmbeddingModelType =
|
||||
ClipEmbeddingModelType.XENOVA_CLIP_VIT_BASE_PATCH16;
|
||||
|
||||
private tokenizer: any;
|
||||
private processor: any;
|
||||
private visionModel: any;
|
||||
private textModel: any;
|
||||
|
||||
async getTokenizer() {
|
||||
if (!this.tokenizer) {
|
||||
const { AutoTokenizer } = await import("@xenova/transformers");
|
||||
this.tokenizer = await AutoTokenizer.from_pretrained(this.modelType);
|
||||
}
|
||||
return this.tokenizer;
|
||||
}
|
||||
|
||||
async getProcessor() {
|
||||
if (!this.processor) {
|
||||
const { AutoProcessor } = await import("@xenova/transformers");
|
||||
this.processor = await AutoProcessor.from_pretrained(this.modelType);
|
||||
}
|
||||
return this.processor;
|
||||
}
|
||||
|
||||
async getVisionModel() {
|
||||
if (!this.visionModel) {
|
||||
const { CLIPVisionModelWithProjection } = await import(
|
||||
"@xenova/transformers"
|
||||
);
|
||||
this.visionModel = await CLIPVisionModelWithProjection.from_pretrained(
|
||||
this.modelType,
|
||||
);
|
||||
}
|
||||
|
||||
return this.visionModel;
|
||||
}
|
||||
|
||||
async getTextModel() {
|
||||
if (!this.textModel) {
|
||||
const { CLIPTextModelWithProjection } = await import(
|
||||
"@xenova/transformers"
|
||||
);
|
||||
this.textModel = await CLIPTextModelWithProjection.from_pretrained(
|
||||
this.modelType,
|
||||
);
|
||||
}
|
||||
|
||||
return this.textModel;
|
||||
}
|
||||
|
||||
async getImageEmbedding(image: ImageType): Promise<number[]> {
|
||||
const loadedImage = await readImage(image);
|
||||
const imageInputs = await (await this.getProcessor())(loadedImage);
|
||||
const { image_embeds } = await (await this.getVisionModel())(imageInputs);
|
||||
return image_embeds.data;
|
||||
}
|
||||
|
||||
async getTextEmbedding(text: string): Promise<number[]> {
|
||||
const textInputs = await (
|
||||
await this.getTokenizer()
|
||||
)([text], { padding: true, truncation: true });
|
||||
const { text_embeds } = await (await this.getTextModel())(textInputs);
|
||||
return text_embeds.data;
|
||||
}
|
||||
|
||||
async getQueryEmbedding(query: string): Promise<number[]> {
|
||||
return this.getTextEmbedding(query);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { ImageType } from "../Node";
|
||||
import { BaseEmbedding } from "./types";
|
||||
|
||||
/*
|
||||
* Base class for Multi Modal embeddings.
|
||||
*/
|
||||
|
||||
export abstract class MultiModalEmbedding extends BaseEmbedding {
|
||||
abstract getImageEmbedding(images: ImageType): Promise<number[]>;
|
||||
|
||||
async getImageEmbeddings(images: ImageType[]): Promise<number[][]> {
|
||||
return Promise.all(
|
||||
images.map((imgFilePath) => this.getImageEmbedding(imgFilePath)),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
import { ClientOptions as OpenAIClientOptions } from "openai";
|
||||
import {
|
||||
AzureOpenAIConfig,
|
||||
getAzureBaseUrl,
|
||||
getAzureConfigFromEnv,
|
||||
getAzureModel,
|
||||
shouldUseAzure,
|
||||
} from "../llm/azure";
|
||||
import { OpenAISession, getOpenAISession } from "../llm/openai";
|
||||
import { BaseEmbedding } from "./types";
|
||||
|
||||
export enum OpenAIEmbeddingModelType {
|
||||
TEXT_EMBED_ADA_002 = "text-embedding-ada-002",
|
||||
}
|
||||
|
||||
export class OpenAIEmbedding extends BaseEmbedding {
|
||||
model: OpenAIEmbeddingModelType;
|
||||
|
||||
// OpenAI session params
|
||||
apiKey?: string = undefined;
|
||||
maxRetries: number;
|
||||
timeout?: number;
|
||||
additionalSessionOptions?: Omit<
|
||||
Partial<OpenAIClientOptions>,
|
||||
"apiKey" | "maxRetries" | "timeout"
|
||||
>;
|
||||
|
||||
session: OpenAISession;
|
||||
|
||||
constructor(init?: Partial<OpenAIEmbedding> & { azure?: AzureOpenAIConfig }) {
|
||||
super();
|
||||
|
||||
this.model = OpenAIEmbeddingModelType.TEXT_EMBED_ADA_002;
|
||||
|
||||
this.maxRetries = init?.maxRetries ?? 10;
|
||||
this.timeout = init?.timeout ?? 60 * 1000; // Default is 60 seconds
|
||||
this.additionalSessionOptions = init?.additionalSessionOptions;
|
||||
|
||||
if (init?.azure || shouldUseAzure()) {
|
||||
const azureConfig = getAzureConfigFromEnv({
|
||||
...init?.azure,
|
||||
model: getAzureModel(this.model),
|
||||
});
|
||||
|
||||
if (!azureConfig.apiKey) {
|
||||
throw new Error(
|
||||
"Azure API key is required for OpenAI Azure models. Please set the AZURE_OPENAI_KEY environment variable.",
|
||||
);
|
||||
}
|
||||
|
||||
this.apiKey = azureConfig.apiKey;
|
||||
this.session =
|
||||
init?.session ??
|
||||
getOpenAISession({
|
||||
azure: true,
|
||||
apiKey: this.apiKey,
|
||||
baseURL: getAzureBaseUrl(azureConfig),
|
||||
maxRetries: this.maxRetries,
|
||||
timeout: this.timeout,
|
||||
defaultQuery: { "api-version": azureConfig.apiVersion },
|
||||
...this.additionalSessionOptions,
|
||||
});
|
||||
} else {
|
||||
this.apiKey = init?.apiKey ?? undefined;
|
||||
this.session =
|
||||
init?.session ??
|
||||
getOpenAISession({
|
||||
apiKey: this.apiKey,
|
||||
maxRetries: this.maxRetries,
|
||||
timeout: this.timeout,
|
||||
...this.additionalSessionOptions,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async getOpenAIEmbedding(input: string) {
|
||||
const { data } = await this.session.openai.embeddings.create({
|
||||
model: this.model,
|
||||
input,
|
||||
});
|
||||
|
||||
return data[0].embedding;
|
||||
}
|
||||
|
||||
async getTextEmbedding(text: string): Promise<number[]> {
|
||||
return this.getOpenAIEmbedding(text);
|
||||
}
|
||||
|
||||
async getQueryEmbedding(query: string): Promise<number[]> {
|
||||
return this.getOpenAIEmbedding(query);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export * from "./ClipEmbedding";
|
||||
export * from "./MultiModalEmbedding";
|
||||
export * from "./OpenAIEmbedding";
|
||||
export * from "./types";
|
||||
export * from "./utils";
|
||||
@@ -0,0 +1,24 @@
|
||||
import { similarity } from "./utils";
|
||||
|
||||
/**
|
||||
* Similarity type
|
||||
* Default is cosine similarity. Dot product and negative Euclidean distance are also supported.
|
||||
*/
|
||||
export enum SimilarityType {
|
||||
DEFAULT = "cosine",
|
||||
DOT_PRODUCT = "dot_product",
|
||||
EUCLIDEAN = "euclidean",
|
||||
}
|
||||
|
||||
export abstract class BaseEmbedding {
|
||||
similarity(
|
||||
embedding1: number[],
|
||||
embedding2: number[],
|
||||
mode: SimilarityType = SimilarityType.DEFAULT,
|
||||
): number {
|
||||
return similarity(embedding1, embedding2, mode);
|
||||
}
|
||||
|
||||
abstract getTextEmbedding(text: string): Promise<number[]>;
|
||||
abstract getQueryEmbedding(query: string): Promise<number[]>;
|
||||
}
|
||||
@@ -1,33 +1,17 @@
|
||||
import { ClientOptions as OpenAIClientOptions } from "openai";
|
||||
|
||||
import { DEFAULT_SIMILARITY_TOP_K } from "./constants";
|
||||
import {
|
||||
AzureOpenAIConfig,
|
||||
getAzureBaseUrl,
|
||||
getAzureConfigFromEnv,
|
||||
getAzureModel,
|
||||
shouldUseAzure,
|
||||
} from "./llm/azure";
|
||||
import { OpenAISession, getOpenAISession } from "./llm/openai";
|
||||
import { VectorStoreQueryMode } from "./storage/vectorStore/types";
|
||||
|
||||
/**
|
||||
* Similarity type
|
||||
* Default is cosine similarity. Dot product and negative Euclidean distance are also supported.
|
||||
*/
|
||||
export enum SimilarityType {
|
||||
DEFAULT = "cosine",
|
||||
DOT_PRODUCT = "dot_product",
|
||||
EUCLIDEAN = "euclidean",
|
||||
}
|
||||
import _ from "lodash";
|
||||
import { ImageType } from "../Node";
|
||||
import { DEFAULT_SIMILARITY_TOP_K } from "../constants";
|
||||
import { VectorStoreQueryMode } from "../storage";
|
||||
import { SimilarityType } from "./types";
|
||||
|
||||
/**
|
||||
* The similarity between two embeddings.
|
||||
* @param embedding1
|
||||
* @param embedding2
|
||||
* @param mode
|
||||
* @returns similartiy score with higher numbers meaning the two embeddings are more similar
|
||||
* @returns similarity score with higher numbers meaning the two embeddings are more similar
|
||||
*/
|
||||
|
||||
export function similarity(
|
||||
embedding1: number[],
|
||||
embedding2: number[],
|
||||
@@ -42,7 +26,6 @@ export function similarity(
|
||||
// will probably cause some avoidable loss of floating point precision
|
||||
// ml-distance is worth watching although they currently also use the naive
|
||||
// formulas
|
||||
|
||||
function norm(x: number[]): number {
|
||||
let result = 0;
|
||||
for (let i = 0; i < x.length; i++) {
|
||||
@@ -202,97 +185,13 @@ export function getTopKMMREmbeddings(
|
||||
return [resultSimilarities, resultIds];
|
||||
}
|
||||
|
||||
export abstract class BaseEmbedding {
|
||||
similarity(
|
||||
embedding1: number[],
|
||||
embedding2: number[],
|
||||
mode: SimilarityType = SimilarityType.DEFAULT,
|
||||
): number {
|
||||
return similarity(embedding1, embedding2, mode);
|
||||
}
|
||||
|
||||
abstract getTextEmbedding(text: string): Promise<number[]>;
|
||||
abstract getQueryEmbedding(query: string): Promise<number[]>;
|
||||
}
|
||||
|
||||
enum OpenAIEmbeddingModelType {
|
||||
TEXT_EMBED_ADA_002 = "text-embedding-ada-002",
|
||||
}
|
||||
|
||||
export class OpenAIEmbedding extends BaseEmbedding {
|
||||
model: OpenAIEmbeddingModelType;
|
||||
|
||||
// OpenAI session params
|
||||
apiKey?: string = undefined;
|
||||
maxRetries: number;
|
||||
timeout?: number;
|
||||
additionalSessionOptions?: Omit<
|
||||
Partial<OpenAIClientOptions>,
|
||||
"apiKey" | "maxRetries" | "timeout"
|
||||
>;
|
||||
|
||||
session: OpenAISession;
|
||||
|
||||
constructor(init?: Partial<OpenAIEmbedding> & { azure?: AzureOpenAIConfig }) {
|
||||
super();
|
||||
|
||||
this.model = OpenAIEmbeddingModelType.TEXT_EMBED_ADA_002;
|
||||
|
||||
this.maxRetries = init?.maxRetries ?? 10;
|
||||
this.timeout = init?.timeout ?? 60 * 1000; // Default is 60 seconds
|
||||
this.additionalSessionOptions = init?.additionalSessionOptions;
|
||||
|
||||
if (init?.azure || shouldUseAzure()) {
|
||||
const azureConfig = getAzureConfigFromEnv({
|
||||
...init?.azure,
|
||||
model: getAzureModel(this.model),
|
||||
});
|
||||
|
||||
if (!azureConfig.apiKey) {
|
||||
throw new Error(
|
||||
"Azure API key is required for OpenAI Azure models. Please set the AZURE_OPENAI_KEY environment variable.",
|
||||
);
|
||||
}
|
||||
|
||||
this.apiKey = azureConfig.apiKey;
|
||||
this.session =
|
||||
init?.session ??
|
||||
getOpenAISession({
|
||||
azure: true,
|
||||
apiKey: this.apiKey,
|
||||
baseURL: getAzureBaseUrl(azureConfig),
|
||||
maxRetries: this.maxRetries,
|
||||
timeout: this.timeout,
|
||||
defaultQuery: { "api-version": azureConfig.apiVersion },
|
||||
...this.additionalSessionOptions,
|
||||
});
|
||||
} else {
|
||||
this.apiKey = init?.apiKey ?? undefined;
|
||||
this.session =
|
||||
init?.session ??
|
||||
getOpenAISession({
|
||||
apiKey: this.apiKey,
|
||||
maxRetries: this.maxRetries,
|
||||
timeout: this.timeout,
|
||||
...this.additionalSessionOptions,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async getOpenAIEmbedding(input: string) {
|
||||
const { data } = await this.session.openai.embeddings.create({
|
||||
model: this.model,
|
||||
input,
|
||||
});
|
||||
|
||||
return data[0].embedding;
|
||||
}
|
||||
|
||||
async getTextEmbedding(text: string): Promise<number[]> {
|
||||
return this.getOpenAIEmbedding(text);
|
||||
}
|
||||
|
||||
async getQueryEmbedding(query: string): Promise<number[]> {
|
||||
return this.getOpenAIEmbedding(query);
|
||||
export async function readImage(input: ImageType) {
|
||||
const { RawImage } = await import("@xenova/transformers");
|
||||
if (input instanceof Blob) {
|
||||
return await RawImage.fromBlob(input);
|
||||
} else if (_.isString(input) || input instanceof URL) {
|
||||
return await RawImage.fromURL(input);
|
||||
} else {
|
||||
throw new Error(`Unsupported input type: ${typeof input}`);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
export * from "./ChatEngine";
|
||||
export * from "./ChatHistory";
|
||||
export * from "./Embedding";
|
||||
export * from "./GlobalsHelper";
|
||||
export * from "./Node";
|
||||
export * from "./NodeParser";
|
||||
@@ -17,6 +16,7 @@ export * from "./TextSplitter";
|
||||
export * from "./Tool";
|
||||
export * from "./callbacks/CallbackManager";
|
||||
export * from "./constants";
|
||||
export * from "./embeddings";
|
||||
export * from "./indices";
|
||||
export * from "./llm/LLM";
|
||||
export * from "./readers/CSVReader";
|
||||
@@ -25,5 +25,6 @@ export * from "./readers/MarkdownReader";
|
||||
export * from "./readers/NotionReader";
|
||||
export * from "./readers/PDFReader";
|
||||
export * from "./readers/SimpleDirectoryReader";
|
||||
export * from "./readers/SimpleMongoReader";
|
||||
export * from "./readers/base";
|
||||
export * from "./storage";
|
||||
|
||||
@@ -10,11 +10,11 @@ import {
|
||||
ServiceContext,
|
||||
serviceContextFromDefaults,
|
||||
} from "../../ServiceContext";
|
||||
import { BaseDocumentStore, RefDocInfo } from "../../storage/docStore/types";
|
||||
import {
|
||||
StorageContext,
|
||||
storageContextFromDefaults,
|
||||
} from "../../storage/StorageContext";
|
||||
import { BaseDocumentStore, RefDocInfo } from "../../storage/docStore/types";
|
||||
import {
|
||||
BaseIndex,
|
||||
BaseIndexInit,
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { Event } from "../../callbacks/CallbackManager";
|
||||
import { DEFAULT_SIMILARITY_TOP_K } from "../../constants";
|
||||
import { BaseEmbedding } from "../../embeddings";
|
||||
import { globalsHelper } from "../../GlobalsHelper";
|
||||
import { NodeWithScore } from "../../Node";
|
||||
import { Metadata, NodeWithScore } from "../../Node";
|
||||
import { BaseRetriever } from "../../Retriever";
|
||||
import { ServiceContext } from "../../ServiceContext";
|
||||
import {
|
||||
VectorStoreQuery,
|
||||
VectorStoreQueryMode,
|
||||
VectorStoreQueryResult,
|
||||
} from "../../storage/vectorStore/types";
|
||||
import { VectorStoreIndex } from "./VectorStoreIndex";
|
||||
|
||||
@@ -37,16 +39,67 @@ export class VectorIndexRetriever implements BaseRetriever {
|
||||
parentEvent?: Event,
|
||||
preFilters?: unknown,
|
||||
): Promise<NodeWithScore[]> {
|
||||
const queryEmbedding =
|
||||
await this.serviceContext.embedModel.getQueryEmbedding(query);
|
||||
let nodesWithScores = await this.textRetrieve(query, preFilters);
|
||||
nodesWithScores = nodesWithScores.concat(
|
||||
await this.textToImageRetrieve(query, preFilters),
|
||||
);
|
||||
this.sendEvent(query, nodesWithScores, parentEvent);
|
||||
return nodesWithScores;
|
||||
}
|
||||
|
||||
const q: VectorStoreQuery = {
|
||||
protected async textRetrieve(
|
||||
query: string,
|
||||
preFilters?: unknown,
|
||||
): Promise<NodeWithScore[]> {
|
||||
const q = await this.buildVectorStoreQuery(this.index.embedModel, query);
|
||||
const result = await this.index.vectorStore.query(q, preFilters);
|
||||
return this.buildNodeListFromQueryResult(result);
|
||||
}
|
||||
|
||||
private async textToImageRetrieve(query: string, preFilters?: unknown) {
|
||||
if (!this.index.imageEmbedModel || !this.index.imageVectorStore) {
|
||||
// no-op if image embedding and vector store are not set
|
||||
return [];
|
||||
}
|
||||
const q = await this.buildVectorStoreQuery(
|
||||
this.index.imageEmbedModel,
|
||||
query,
|
||||
);
|
||||
const result = await this.index.imageVectorStore.query(q, preFilters);
|
||||
return this.buildNodeListFromQueryResult(result);
|
||||
}
|
||||
|
||||
protected sendEvent(
|
||||
query: string,
|
||||
nodesWithScores: NodeWithScore<Metadata>[],
|
||||
parentEvent: Event | undefined,
|
||||
) {
|
||||
if (this.serviceContext.callbackManager.onRetrieve) {
|
||||
this.serviceContext.callbackManager.onRetrieve({
|
||||
query,
|
||||
nodes: nodesWithScores,
|
||||
event: globalsHelper.createEvent({
|
||||
parentEvent,
|
||||
type: "retrieve",
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected async buildVectorStoreQuery(
|
||||
embedModel: BaseEmbedding,
|
||||
query: string,
|
||||
): Promise<VectorStoreQuery> {
|
||||
const queryEmbedding = await embedModel.getQueryEmbedding(query);
|
||||
|
||||
return {
|
||||
queryEmbedding: queryEmbedding,
|
||||
mode: VectorStoreQueryMode.DEFAULT,
|
||||
similarityTopK: this.similarityTopK,
|
||||
};
|
||||
const result = await this.index.vectorStore.query(q, preFilters);
|
||||
}
|
||||
|
||||
protected buildNodeListFromQueryResult(result: VectorStoreQueryResult) {
|
||||
let nodesWithScores: NodeWithScore[] = [];
|
||||
for (let i = 0; i < result.ids.length; i++) {
|
||||
const nodeFromResult = result.nodes?.[i];
|
||||
@@ -61,17 +114,6 @@ export class VectorIndexRetriever implements BaseRetriever {
|
||||
});
|
||||
}
|
||||
|
||||
if (this.serviceContext.callbackManager.onRetrieve) {
|
||||
this.serviceContext.callbackManager.onRetrieve({
|
||||
query,
|
||||
nodes: nodesWithScores,
|
||||
event: globalsHelper.createEvent({
|
||||
parentEvent,
|
||||
type: "retrieve",
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
return nodesWithScores;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
import { BaseNode, Document, MetadataMode } from "../../Node";
|
||||
import {
|
||||
BaseNode,
|
||||
Document,
|
||||
ImageNode,
|
||||
MetadataMode,
|
||||
ObjectType,
|
||||
TextNode,
|
||||
jsonToNode,
|
||||
} from "../../Node";
|
||||
import { BaseQueryEngine, RetrieverQueryEngine } from "../../QueryEngine";
|
||||
import { ResponseSynthesizer } from "../../ResponseSynthesizer";
|
||||
import { BaseRetriever } from "../../Retriever";
|
||||
@@ -6,11 +14,16 @@ import {
|
||||
ServiceContext,
|
||||
serviceContextFromDefaults,
|
||||
} from "../../ServiceContext";
|
||||
import { BaseDocumentStore } from "../../storage/docStore/types";
|
||||
import {
|
||||
BaseEmbedding,
|
||||
ClipEmbedding,
|
||||
MultiModalEmbedding,
|
||||
} from "../../embeddings";
|
||||
import {
|
||||
StorageContext,
|
||||
storageContextFromDefaults,
|
||||
} from "../../storage/StorageContext";
|
||||
import { BaseIndexStore } from "../../storage/indexStore/types";
|
||||
import { VectorStore } from "../../storage/vectorStore/types";
|
||||
import {
|
||||
BaseIndex,
|
||||
@@ -21,16 +34,21 @@ import {
|
||||
import { BaseNodePostprocessor } from "../BaseNodePostprocessor";
|
||||
import { VectorIndexRetriever } from "./VectorIndexRetriever";
|
||||
|
||||
export interface VectorIndexOptions {
|
||||
nodes?: BaseNode[];
|
||||
interface IndexStructOptions {
|
||||
indexStruct?: IndexDict;
|
||||
indexId?: string;
|
||||
}
|
||||
export interface VectorIndexOptions extends IndexStructOptions {
|
||||
nodes?: BaseNode[];
|
||||
serviceContext?: ServiceContext;
|
||||
storageContext?: StorageContext;
|
||||
imageVectorStore?: VectorStore;
|
||||
vectorStore?: VectorStore;
|
||||
}
|
||||
|
||||
export interface VectorIndexConstructorProps extends BaseIndexInit<IndexDict> {
|
||||
vectorStore: VectorStore;
|
||||
indexStore: BaseIndexStore;
|
||||
imageVectorStore?: VectorStore;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -38,15 +56,24 @@ export interface VectorIndexConstructorProps extends BaseIndexInit<IndexDict> {
|
||||
*/
|
||||
export class VectorStoreIndex extends BaseIndex<IndexDict> {
|
||||
vectorStore: VectorStore;
|
||||
indexStore: BaseIndexStore;
|
||||
embedModel: BaseEmbedding;
|
||||
imageVectorStore?: VectorStore;
|
||||
imageEmbedModel?: MultiModalEmbedding;
|
||||
|
||||
private constructor(init: VectorIndexConstructorProps) {
|
||||
super(init);
|
||||
this.vectorStore = init.vectorStore;
|
||||
this.indexStore = init.indexStore;
|
||||
this.vectorStore = init.vectorStore ?? init.storageContext.vectorStore;
|
||||
this.embedModel = init.serviceContext.embedModel;
|
||||
this.imageVectorStore = init.imageVectorStore;
|
||||
if (this.imageVectorStore) {
|
||||
this.imageEmbedModel = new ClipEmbedding();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The async init function should be called after the constructor.
|
||||
* This is needed to handle persistence.
|
||||
* The async init function creates a new VectorStoreIndex.
|
||||
* @param options
|
||||
* @returns
|
||||
*/
|
||||
@@ -55,11 +82,43 @@ export class VectorStoreIndex extends BaseIndex<IndexDict> {
|
||||
options.storageContext ?? (await storageContextFromDefaults({}));
|
||||
const serviceContext =
|
||||
options.serviceContext ?? serviceContextFromDefaults({});
|
||||
const docStore = storageContext.docStore;
|
||||
const vectorStore = storageContext.vectorStore;
|
||||
const indexStore = storageContext.indexStore;
|
||||
const docStore = storageContext.docStore;
|
||||
|
||||
// Setup IndexStruct from storage
|
||||
let indexStruct = await VectorStoreIndex.setupIndexStructFromStorage(
|
||||
indexStore,
|
||||
options,
|
||||
);
|
||||
|
||||
if (!options.nodes && !indexStruct) {
|
||||
throw new Error(
|
||||
"Cannot initialize VectorStoreIndex without nodes or indexStruct",
|
||||
);
|
||||
}
|
||||
|
||||
indexStruct = indexStruct ?? new IndexDict();
|
||||
|
||||
const index = new this({
|
||||
storageContext,
|
||||
serviceContext,
|
||||
docStore,
|
||||
indexStruct,
|
||||
indexStore,
|
||||
vectorStore: options.vectorStore,
|
||||
imageVectorStore: options.imageVectorStore,
|
||||
});
|
||||
|
||||
if (options.nodes) {
|
||||
// If nodes are passed in, then we need to update the index
|
||||
await index.buildIndexFromNodes(options.nodes);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
private static async setupIndexStructFromStorage(
|
||||
indexStore: BaseIndexStore,
|
||||
options: IndexStructOptions,
|
||||
) {
|
||||
let indexStructs = (await indexStore.getIndexStructs()) as IndexDict[];
|
||||
let indexStruct: IndexDict | undefined;
|
||||
|
||||
@@ -77,55 +136,23 @@ export class VectorStoreIndex extends BaseIndex<IndexDict> {
|
||||
indexStruct = (await indexStore.getIndexStruct(
|
||||
options.indexId,
|
||||
)) as IndexDict;
|
||||
} else {
|
||||
indexStruct = undefined;
|
||||
}
|
||||
|
||||
// check indexStruct type
|
||||
// Check indexStruct type
|
||||
if (indexStruct && indexStruct.type !== IndexStructType.SIMPLE_DICT) {
|
||||
throw new Error(
|
||||
"Attempting to initialize VectorStoreIndex with non-vector indexStruct",
|
||||
);
|
||||
}
|
||||
|
||||
if (options.nodes) {
|
||||
// If nodes are passed in, then we need to update the index
|
||||
indexStruct = await VectorStoreIndex.buildIndexFromNodes(
|
||||
options.nodes,
|
||||
serviceContext,
|
||||
vectorStore,
|
||||
docStore,
|
||||
indexStruct,
|
||||
);
|
||||
|
||||
await indexStore.addIndexStruct(indexStruct);
|
||||
} else if (!indexStruct) {
|
||||
throw new Error(
|
||||
"Cannot initialize VectorStoreIndex without nodes or indexStruct",
|
||||
);
|
||||
}
|
||||
|
||||
return new VectorStoreIndex({
|
||||
storageContext,
|
||||
serviceContext,
|
||||
docStore,
|
||||
vectorStore,
|
||||
indexStruct,
|
||||
});
|
||||
return indexStruct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the embeddings for nodes.
|
||||
* @param nodes
|
||||
* @param serviceContext
|
||||
* @param logProgress log progress to console (useful for debugging)
|
||||
* @returns
|
||||
*/
|
||||
static async getNodeEmbeddingResults(
|
||||
nodes: BaseNode[],
|
||||
serviceContext: ServiceContext,
|
||||
logProgress = false,
|
||||
) {
|
||||
async getNodeEmbeddingResults(nodes: BaseNode[], logProgress = false) {
|
||||
const nodesWithEmbeddings: BaseNode[] = [];
|
||||
|
||||
for (let i = 0; i < nodes.length; ++i) {
|
||||
@@ -133,7 +160,7 @@ export class VectorStoreIndex extends BaseIndex<IndexDict> {
|
||||
if (logProgress) {
|
||||
console.log(`getting embedding for node ${i}/${nodes.length}`);
|
||||
}
|
||||
const embedding = await serviceContext.embedModel.getTextEmbedding(
|
||||
const embedding = await this.embedModel.getTextEmbedding(
|
||||
node.getContent(MetadataMode.EMBED),
|
||||
);
|
||||
node.embedding = embedding;
|
||||
@@ -146,77 +173,47 @@ export class VectorStoreIndex extends BaseIndex<IndexDict> {
|
||||
/**
|
||||
* Get embeddings for nodes and place them into the index.
|
||||
* @param nodes
|
||||
* @param serviceContext
|
||||
* @param vectorStore
|
||||
* @returns
|
||||
*/
|
||||
static async buildIndexFromNodes(
|
||||
nodes: BaseNode[],
|
||||
serviceContext: ServiceContext,
|
||||
vectorStore: VectorStore,
|
||||
docStore: BaseDocumentStore,
|
||||
indexDict?: IndexDict,
|
||||
): Promise<IndexDict> {
|
||||
indexDict = indexDict ?? new IndexDict();
|
||||
|
||||
async buildIndexFromNodes(nodes: BaseNode[]) {
|
||||
// Check if the index already has nodes with the same hash
|
||||
const newNodes = nodes.filter((node) =>
|
||||
Object.entries(indexDict!.nodesDict).reduce((acc, [key, value]) => {
|
||||
if (value.hash === node.hash) {
|
||||
acc = false;
|
||||
}
|
||||
return acc;
|
||||
}, true),
|
||||
Object.entries(this.indexStruct!.nodesDict).reduce(
|
||||
(acc, [key, value]) => {
|
||||
if (value.hash === node.hash) {
|
||||
acc = false;
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
true,
|
||||
),
|
||||
);
|
||||
|
||||
const embeddingResults = await this.getNodeEmbeddingResults(
|
||||
newNodes,
|
||||
serviceContext,
|
||||
);
|
||||
|
||||
await vectorStore.add(embeddingResults);
|
||||
|
||||
if (!vectorStore.storesText) {
|
||||
await docStore.addDocuments(embeddingResults, true);
|
||||
}
|
||||
|
||||
for (const node of embeddingResults) {
|
||||
indexDict.addNode(node);
|
||||
}
|
||||
|
||||
return indexDict;
|
||||
await this.insertNodes(newNodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* High level API: split documents, get embeddings, and build index.
|
||||
* @param documents
|
||||
* @param storageContext
|
||||
* @param serviceContext
|
||||
* @param args
|
||||
* @returns
|
||||
*/
|
||||
static async fromDocuments(
|
||||
documents: Document[],
|
||||
args: {
|
||||
storageContext?: StorageContext;
|
||||
serviceContext?: ServiceContext;
|
||||
} = {},
|
||||
args: VectorIndexOptions = {},
|
||||
): Promise<VectorStoreIndex> {
|
||||
let { storageContext, serviceContext } = args;
|
||||
storageContext = storageContext ?? (await storageContextFromDefaults({}));
|
||||
serviceContext = serviceContext ?? serviceContextFromDefaults({});
|
||||
const docStore = storageContext.docStore;
|
||||
args.storageContext =
|
||||
args.storageContext ?? (await storageContextFromDefaults({}));
|
||||
args.serviceContext = args.serviceContext ?? serviceContextFromDefaults({});
|
||||
const docStore = args.storageContext.docStore;
|
||||
|
||||
for (const doc of documents) {
|
||||
docStore.setDocumentHash(doc.id_, doc.hash);
|
||||
}
|
||||
|
||||
const nodes = serviceContext.nodeParser.getNodesFromDocuments(documents);
|
||||
const index = await VectorStoreIndex.init({
|
||||
nodes,
|
||||
storageContext,
|
||||
serviceContext,
|
||||
});
|
||||
return index;
|
||||
args.nodes =
|
||||
args.serviceContext.nodeParser.getNodesFromDocuments(documents);
|
||||
return await this.init(args);
|
||||
}
|
||||
|
||||
static async fromVectorStore(
|
||||
@@ -231,7 +228,7 @@ export class VectorStoreIndex extends BaseIndex<IndexDict> {
|
||||
|
||||
const storageContext = await storageContextFromDefaults({ vectorStore });
|
||||
|
||||
const index = await VectorStoreIndex.init({
|
||||
const index = await this.init({
|
||||
nodes: [],
|
||||
storageContext,
|
||||
serviceContext,
|
||||
@@ -259,51 +256,131 @@ export class VectorStoreIndex extends BaseIndex<IndexDict> {
|
||||
);
|
||||
}
|
||||
|
||||
async insertNodes(nodes: BaseNode[]): Promise<void> {
|
||||
const embeddingResults = await VectorStoreIndex.getNodeEmbeddingResults(
|
||||
nodes,
|
||||
this.serviceContext,
|
||||
);
|
||||
protected async insertNodesToStore(
|
||||
vectorStore: VectorStore,
|
||||
nodes: BaseNode[],
|
||||
): Promise<void> {
|
||||
const newIds = await vectorStore.add(nodes);
|
||||
|
||||
const newIds = await this.vectorStore.add(embeddingResults);
|
||||
|
||||
if (!this.vectorStore.storesText) {
|
||||
for (let i = 0; i < nodes.length; ++i) {
|
||||
this.indexStruct.addNode(nodes[i], newIds[i]);
|
||||
this.docStore.addDocuments([nodes[i]], true);
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < nodes.length; ++i) {
|
||||
if (nodes[i].getType() === "INDEX") {
|
||||
this.indexStruct.addNode(nodes[i], newIds[i]);
|
||||
this.docStore.addDocuments([nodes[i]], true);
|
||||
}
|
||||
// NOTE: if the vector store doesn't store text,
|
||||
// we need to add the nodes to the index struct and document store
|
||||
// NOTE: if the vector store keeps text,
|
||||
// we only need to add image and index nodes
|
||||
for (let i = 0; i < nodes.length; ++i) {
|
||||
const type = nodes[i].getType();
|
||||
if (
|
||||
!vectorStore.storesText ||
|
||||
type === ObjectType.INDEX ||
|
||||
type === ObjectType.IMAGE
|
||||
) {
|
||||
const nodeWithoutEmbedding = jsonToNode(nodes[i].toJSON());
|
||||
nodeWithoutEmbedding.embedding = undefined;
|
||||
this.indexStruct.addNode(nodeWithoutEmbedding, newIds[i]);
|
||||
this.docStore.addDocuments([nodeWithoutEmbedding], true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await this.storageContext.indexStore.addIndexStruct(this.indexStruct);
|
||||
async insertNodes(nodes: BaseNode[]): Promise<void> {
|
||||
if (!nodes || nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
const { imageNodes, textNodes } = this.splitNodes(nodes);
|
||||
if (imageNodes.length > 0) {
|
||||
if (!this.imageVectorStore) {
|
||||
throw new Error("Cannot insert image nodes without image vector store");
|
||||
}
|
||||
const imageNodesWithEmbedding =
|
||||
await this.getImageNodeEmbeddingResults(imageNodes);
|
||||
await this.insertNodesToStore(
|
||||
this.imageVectorStore,
|
||||
imageNodesWithEmbedding,
|
||||
);
|
||||
}
|
||||
const embeddingResults = await this.getNodeEmbeddingResults(textNodes);
|
||||
await this.insertNodesToStore(this.vectorStore, embeddingResults);
|
||||
await this.indexStore.addIndexStruct(this.indexStruct);
|
||||
}
|
||||
|
||||
async deleteRefDoc(
|
||||
refDocId: string,
|
||||
deleteFromDocStore: boolean = true,
|
||||
): Promise<void> {
|
||||
this.vectorStore.delete(refDocId);
|
||||
|
||||
if (!this.vectorStore.storesText) {
|
||||
const refDocInfo = await this.docStore.getRefDocInfo(refDocId);
|
||||
|
||||
if (refDocInfo) {
|
||||
for (const nodeId of refDocInfo.nodeIds) {
|
||||
this.indexStruct.delete(nodeId);
|
||||
}
|
||||
}
|
||||
|
||||
await this.storageContext.indexStore.addIndexStruct(this.indexStruct);
|
||||
await this.deleteRefDocFromStore(this.vectorStore, refDocId);
|
||||
if (this.imageVectorStore) {
|
||||
await this.deleteRefDocFromStore(this.imageVectorStore, refDocId);
|
||||
}
|
||||
|
||||
if (deleteFromDocStore) {
|
||||
await this.docStore.deleteDocument(refDocId, false);
|
||||
}
|
||||
}
|
||||
|
||||
protected async deleteRefDocFromStore(
|
||||
vectorStore: VectorStore,
|
||||
refDocId: string,
|
||||
): Promise<void> {
|
||||
vectorStore.delete(refDocId);
|
||||
|
||||
if (!vectorStore.storesText) {
|
||||
const refDocInfo = await this.docStore.getRefDocInfo(refDocId);
|
||||
|
||||
if (refDocInfo) {
|
||||
for (const nodeId of refDocInfo.nodeIds) {
|
||||
this.indexStruct.delete(nodeId);
|
||||
vectorStore.delete(nodeId);
|
||||
}
|
||||
}
|
||||
await this.indexStore.addIndexStruct(this.indexStruct);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the embeddings for image nodes.
|
||||
* @param nodes
|
||||
* @param serviceContext
|
||||
* @param logProgress log progress to console (useful for debugging)
|
||||
* @returns
|
||||
*/
|
||||
async getImageNodeEmbeddingResults(
|
||||
nodes: ImageNode[],
|
||||
logProgress: boolean = false,
|
||||
): Promise<BaseNode[]> {
|
||||
if (!this.imageEmbedModel) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const nodesWithEmbeddings: ImageNode[] = [];
|
||||
|
||||
for (let i = 0; i < nodes.length; ++i) {
|
||||
const node = nodes[i];
|
||||
if (logProgress) {
|
||||
console.log(`getting embedding for node ${i}/${nodes.length}`);
|
||||
}
|
||||
node.embedding = await this.imageEmbedModel.getImageEmbedding(node.image);
|
||||
nodesWithEmbeddings.push(node);
|
||||
}
|
||||
|
||||
return nodesWithEmbeddings;
|
||||
}
|
||||
|
||||
private splitNodes(nodes: BaseNode[]): {
|
||||
imageNodes: ImageNode[];
|
||||
textNodes: TextNode[];
|
||||
} {
|
||||
let imageNodes: ImageNode[] = [];
|
||||
let textNodes: TextNode[] = [];
|
||||
|
||||
for (let node of nodes) {
|
||||
if (node instanceof ImageNode) {
|
||||
imageNodes.push(node);
|
||||
} else if (node instanceof TextNode) {
|
||||
textNodes.push(node);
|
||||
}
|
||||
}
|
||||
return {
|
||||
imageNodes,
|
||||
textNodes,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -639,7 +639,7 @@ If a question does not make any sense, or is not factually coherent, explain why
|
||||
|
||||
export const ALL_AVAILABLE_ANTHROPIC_MODELS = {
|
||||
// both models have 100k context window, see https://docs.anthropic.com/claude/reference/selecting-a-model
|
||||
"claude-2": { contextWindow: 100000 },
|
||||
"claude-2": { contextWindow: 200000 },
|
||||
"claude-instant-1": { contextWindow: 100000 },
|
||||
};
|
||||
|
||||
@@ -705,10 +705,12 @@ export class Anthropic implements LLM {
|
||||
return (
|
||||
acc +
|
||||
`${
|
||||
message.role === "assistant"
|
||||
? ANTHROPIC_AI_PROMPT
|
||||
: ANTHROPIC_HUMAN_PROMPT
|
||||
} ${message.content} `
|
||||
message.role === "system"
|
||||
? ""
|
||||
: message.role === "assistant"
|
||||
? ANTHROPIC_AI_PROMPT + " "
|
||||
: ANTHROPIC_HUMAN_PROMPT + " "
|
||||
}${message.content.trim()}`
|
||||
);
|
||||
}, "") + ANTHROPIC_AI_PROMPT
|
||||
);
|
||||
@@ -729,6 +731,7 @@ export class Anthropic implements LLM {
|
||||
}
|
||||
return this.streamChat(messages, parentEvent) as R;
|
||||
}
|
||||
|
||||
//Non-streaming
|
||||
const response = await this.session.anthropic.completions.create({
|
||||
model: this.model,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import mammoth from "mammoth";
|
||||
import { Document } from "../Node";
|
||||
import { GenericFileSystem } from "../storage/FileSystem";
|
||||
import { DEFAULT_FS } from "../storage/constants";
|
||||
import { GenericFileSystem } from "../storage/FileSystem";
|
||||
import { BaseReader } from "./base";
|
||||
|
||||
export class DocxReader implements BaseReader {
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { Document, ImageDocument } from "../Node";
|
||||
import { DEFAULT_FS } from "../storage/constants";
|
||||
import { GenericFileSystem } from "../storage/FileSystem";
|
||||
import { BaseReader } from "./base";
|
||||
|
||||
/**
|
||||
* Reads the content of an image file into a Document object (which stores the image file as a Blob).
|
||||
*/
|
||||
export class ImageReader implements BaseReader {
|
||||
/**
|
||||
* Public method for this reader.
|
||||
* Required by BaseReader interface.
|
||||
* @param file Path/name of the file to be loaded.
|
||||
* @param fs fs wrapper interface for getting the file content.
|
||||
* @returns Promise<Document[]> A Promise object, eventually yielding zero or one ImageDocument of the specified file.
|
||||
*/
|
||||
async loadData(
|
||||
file: string,
|
||||
fs: GenericFileSystem = DEFAULT_FS,
|
||||
): Promise<Document[]> {
|
||||
const dataBuffer = await fs.readFile(file);
|
||||
const blob = new Blob([dataBuffer]);
|
||||
return [new ImageDocument({ image: blob, id_: file })];
|
||||
}
|
||||
}
|
||||