# Ingest Text

## Content: Ingest Text

### User Intent

"I want to ingest plain text directly into Graphlit without a file or URL"

### Operation

* **SDK Method**: `graphlit.ingestText()`
* **GraphQL**: `ingestText` mutation
* **Entity Type**: Content
* **Common Use Cases**: User-generated notes, chat messages, API responses, scraped text, clipboard content

### TypeScript (Canonical)

```typescript
import { Graphlit } from 'graphlit-client';
import { ContentState, ObservableTypes } from 'graphlit-client/dist/generated/graphql-types';

const graphlit = new Graphlit();

// Basic text ingestion (synchronous)
const response = await graphlit.ingestText(
  'This is my note about the project meeting. We discussed Q1 goals and timeline.',  // text
  'Meeting Notes - January 2025',  // name
  undefined,  // textType (optional)
  undefined,  // uri (optional - for reference)
  undefined,  // id (optional)
  undefined,  // identifier (optional)
  true,       // isSynchronous
  undefined,  // workflow (optional)
  undefined   // collections (optional)
);

const contentId = response.ingestText.id;
console.log(`Text ingested: ${contentId}`);

// Retrieve the content
const content = await graphlit.getContent(contentId);
console.log(`Content markdown: ${content.content.markdown}`);
```

## Ingest text (snake\_case method)

## Note: Python SDK uses named parameters, order doesn't matter

response = await graphlit.ingestText( text="This is my note about the project meeting.", name="Meeting Notes - January 2025", is\_synchronous=True )

content\_id = response.ingest\_text.id if response.ingest\_text else None

````

**C#**:
```csharp
using Graphlit;

var client = new Graphlit();

// Ingest text (PascalCase method)
var response = await graphlit.IngestText(
    text: "This is my note about the project meeting.",
    name: "Meeting Notes - January 2025",
    isSynchronous: true
);

var contentId = response.IngestText?.Id;
````

### Parameters

#### Required

* **`text`** (string): The text content to ingest
  * Can be plain text or markdown
  * No size limit specified, but keep reasonable for performance

#### Optional

* **`name`** (string): Display name for the content
* **`textType`** (TextTypes): Type hint for the text
  * `PLAIN` - Plain text (default)
  * `MARKDOWN` - Markdown formatted text
* **`uri`** (string): Optional reference URI for the text source
* **`id`** (string): Custom ID for the content
* **`identifier`** (string): Custom identifier for deduplication
* **`isSynchronous`** (boolean): Wait for ingestion to complete
  * **Default**: `false` (asynchronous)
  * **Recommended**: `true` for immediate use
* **`workflow`** (EntityReferenceInput): Workflow to apply during ingestion
* **`collections`** (EntityReferenceInput\[]): Collections to add content to
* **`observations`** (ObservationReferenceInput\[]): Observations to link
* **`correlationId`** (string): For tracking in production systems

### Response

```typescript
{
  ingestText: {
    id: string;              // Content ID
    name: string;            // Name you provided
    state: ContentState;     // FINISHED (if synchronous)
    type: ContentTEXT; // Always TEXT
    markdown: string;        // The ingested text
    textType?: TextTypes;    // PLAIN or MARKDOWN
    uri?: string;            // Reference URI if provided
  }
}
```

### Developer Hints

#### Key Differences from ingestUri

1. **No file parsing needed** - Text is used directly, no extraction step
2. **Immediate availability** - Even with `isSynchronous: false`, text is usually available immediately
3. **No file metadata** - No fileType, mimeType, or file-specific fields
4. **Markdown support** - Can ingest pre-formatted markdown

#### When to Use ingestText vs ingestUri

Use `ingestText` when:

* You already have the text in memory
* Text comes from user input, API, or database
* No file parsing needed
* You want to store snippets, notes, or short content

Use `ingestUri` when:

* Content is in a file (PDF, DOCX, etc.)
* Need file parsing/extraction
* Content is at a URL

#### Understanding isSynchronous

```typescript
// Asynchronous (default) - returns immediately
const response = await graphlit.ingestText(text, name, undefined, undefined, undefined, undefined, false);
// Content ID available immediately, processing happens in background

// Synchronous - waits for processing
const response = await graphlit.ingestText(text, name, undefined, undefined, undefined, undefined, true);
// Returns when content.state === 'FINISHED'
```

**For ingestText, the difference is minimal** since text doesn't require heavy processing. However, if you're using a workflow (e.g., entity extraction), synchronous mode ensures the workflow completes before returning.

### Variations

#### 1. Ingesting with Collections

Organize text into collections during ingestion:

```typescript
// Create a collection first
const collectionResponse = await graphlit.createCollection({
  name: 'Meeting Notes'
});

const collectionId = collectionResponse.createCollection.id;

// Ingest text into collection
const response = await graphlit.ingestText(
  'Discussion about Q1 product roadmap and feature priorities.',
  'Product Planning Meeting',
  undefined,  // textType
  undefined,  // uri
  undefined,  // workflow
  [{ id: collectionId }],  // collections
  true
);
```

#### 2. Ingesting Markdown

Preserve markdown formatting:

```typescript
const markdownText = `
# Project Update

## Completed Tasks
- Feature A implementation
- Bug fixes in module B

## Next Steps
- Code review
- Deployment planning
`;

const response = await graphlit.ingestText(
  markdownText,
  'Weekly Project Update',
  TextTypes.Markdown,  // Specify markdown type
  undefined,
  undefined,
  undefined,
  true
);

// The markdown structure is preserved
const content = await graphlit.getContent(response.ingestText.id);
console.log(content.content.markdown); // Includes formatting
```

#### 3. Ingesting with Entity Extraction

Apply a workflow to extract entities from text:

```typescript
// Create extraction workflow
const workflowInput: WorkflowInput = {
  name: 'Extract People and Orgs',
  extraction: {
    jobs: [
      {
        connector: {
          type: EntityExtractionServiceTypes.ModelText,
          modelText: {
            extractedTypes: [
              ObservableTypes.Person,
              ObservableTypes.Organization
            ]
          }
        }
      }
    ]
  }
};

const workflowResponse = await graphlit.createWorkflow(workflowInput);

// Ingest text with extraction
const response = await graphlit.ingestText(
  'John Smith from Acme Corp discussed the partnership with Jane Doe from TechCo.',
  'Partnership Discussion',
  undefined,
  undefined,
  { id: workflowResponse.createWorkflow.id },  // workflow
  undefined,
  true  // Must be synchronous to wait for extraction
);

// Retrieve with extracted entities
const content = await graphlit.getContent(response.ingestText.id);
console.log(`Extracted ${content.content.observations?.length || 0} entities`);
// Will include Person entities for "John Smith" and "Jane Doe"
// Will include Organization entities for "Acme Corp" and "TechCo"
```

#### 4. Ingesting with Reference URI

Track the source of text:

```typescript
// Text scraped from a web API
const scrapedText = 'Product description from external API...';

const response = await graphlit.ingestText(
  scrapedText,
  'Product Description - Widget A',
  TextTypes.Plain,
  'https://api.example.com/products/widget-a',  // Reference URI
  undefined,
  undefined,
  true
);

// The URI is stored for reference
const content = await graphlit.getContent(response.ingestText.id);
console.log(`Source: ${content.content.uri}`);
```

### Common Issues

**Issue**: Text ingested but not appearing in search\
**Solution**: Ensure embeddings are generated. Check project configuration for embedding model. If using asynchronous mode, wait a few seconds for embedding generation.

**Issue**: Special characters or formatting lost\
**Solution**: Use `textType: TextTypes.Markdown` if your text includes markdown formatting. Plain text is default.

**Issue**: Workflow not executing\
**Solution**: Must use `isSynchronous: true` when applying workflows. Asynchronous mode may return before workflow completes.

**Issue**: Content state is `AWAITING_EXTRACTION`\
**Solution**: Wait for processing to complete if using asynchronous mode. Or switch to synchronous mode.

### Production Example

**From Public Samples**:

```typescript
// Server-side text ingestion with all options
const response = await graphlit.ingestText(
  text,
  name,
  textType as TextTypes | undefined,
  uri,
  workflow ? { id: workflow } : undefined,
  collections?.map((id) => ({ id })),
  isSynchronous
);
```

**Re-ingesting updated text**:

```typescript
// Update content by re-ingesting with same name
const response = await graphlit.ingestText(
  editedText,
  originalName,
  TextTypes.Plain,
  undefined,
  undefined,
  undefined,
  true
);
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.graphlit.dev/api-guides/use-cases/content/content-ingest-text.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
