Shinydocs Pro

AI Enrichment (Content Tagging)

This feature is currently in development but is available to use. Please note that UI and functionality might change from release to release.

Heads up!

The GPT-OSS model family by OpenAI does not currently support structured output, meaning it is not able to be used for AI Enrichment.

Important tip!

This process often takes a bit of trial and error.

We recommend starting with a small set of sample documents, some relevant and some irrelevant to the prompts you're testing in Shinydocs Pro. This lets you quickly see how the model responds and make adjustments to your prompt or model choice without sifting through a massive dataset.

Different models can interpret prompts differently, and outputs may not always be what you expect. Testing with a small, focused sample helps you dial it in faster.

AI Enrichment allows you to analyze document content and generate structured metadata fields using large language models. These fields can be used for tagging, classification, or extraction during a crawl. Enrichments are defined through prompts and executed conditionally based on the document’s metadata.

This guide will walk you through how to configure your enrichment, what each field does, and how to design effective prompts.

How it works/workflow

Ai Enrichment Workflow.jpeg
AI Enrichment Workflow
  1. Start of Analysis
    When a source's analysis runs, AI analysis runs as its last step, for each source that has AI analysis turned on. It doesn't run when a source only crawls.

  2. Prompt Cards
    Each configured prompt card is grouped by its model for efficiency. The system checks whether the running source is included in the applied sources for that prompt card. If not, the card is skipped.

  3. Query Conditions
    If the source matches, the model processes only the index items that meet the defined query conditions (for example, ensuring the file has text, or that it hasn’t already been enriched).

  4. Model Execution
    The model runs the prompt card against the filtered items. The model’s response is then checked.

  5. Ignored Responses
    If the model returns a value defined as an ignored response (such as “N/A”), the system does not tag the document.

  6. Tagging Documents
    If the response is valid, the document is tagged with the specified fields. All AI enrichment fields are automatically prefixed with ai-text-analysis for easy identification.

Guidelines for AI Enrichment

  • Use ISO date format
    If requesting date/time information, always ask in the system prompt to
    return or normalize dates in ISO 8601 format (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ssZ).

  • Start with small test sets
    Test your prompts and model choice on a small set of documents first to refine results before scaling up.

  • Pick the right model for the task

    • Small models (≤1b): fast, good for summarization, tagging, or simple classification.

    • Larger models (≥8b): slower, better for extraction, detailed classification, or complex analysis.

    • Very large models (≥ 30b): only use these models on small datasets that are very complex. These models take a long time to produce a response.

  • Be specific in prompts
    Write prompts as if you’re instructing a junior analyst. State exactly what you want returned and how to handle uncertain cases. Use {{text}} to inject document content.

  • Set query conditions
    Always define conditions to control when enrichment runs. Common examples:

    • fullText | exists (only process files with extracted text)

    • path-valid | is not | false (skip deleted files)

    • Skip files already enriched by checking if enrichment fields exist.

      • e.g. ai-text-analysis-summary | does not exist

  • Handle uncertain or null results
    Define ignored responses like N/A or [N/A] so they don’t get written as real values.

  • Define result fields properly

    • Mark a field Required when the model must always answer it. Fields that aren't required can be left empty.

    • Primarily use Text field types.

    • Use Number only for values that can only be numeric (using it incorrectly will cause errors).

    • Use List of text only when you expect multiple values (like keywords).

  • Use the seed option for consistency
    Setting a seed ensures the model gives repeatable results during testing. Seed and temperature are set on the model, under Settings > Intelligence > Models.

  • Control randomness with temperature

    • Use 0.2–0.5 for reliable results.

    • Use 0.0 if asking the model to find content that exists in the system prompt

    • Use higher values only when creativity is more important than consistency.

  • Save before running
    Prompts run when a source's analysis runs, so make sure you save all changes to prompts and fields first.

Turn on the feature

AI analysis needs the Intelligence Engine add-on on your license. Contact Shinydocs for details.

  1. Add a provider and check that it has a model that generates text. See the Intelligence Configuration Guide.

  2. Open the feature flags page at https://<server>:9701/settings/flags and turn on AI Analysis Tool. It shows the AI tab under Settings > Analysis and the AI analysis step on each source.

  3. Go to Sources, open each source you want to enrich and turn on AI analysis in its Analysis panel.

cc-ai-10-source-26-5-light.png

Turn AI analysis on only for the sources you are testing with. Running prompts over a large source can take a long time.

Step 1 - Add a prompt

Go to Settings > Analysis and open the AI tab. Each prompt is a card showing its name, its model and how many sources it applies to. Select Add prompt, then give the prompt a Name.

cc-ai-06-add-prompt-26-5-light.png

Step 2 - Choose the documents

Under Documents, use Sources to choose which sources the prompt runs on. New sources are not added automatically. The Conditions narrow it further; see Step 5.

Step 3 - Choose the model and speed

  • Model to use: only models that are switched on and generate text are listed. Manage them under Settings > Intelligence.

  • Documents at a time: how many documents this prompt sends to its model at once. Leave it empty to use the model's Maximum threads setting. Send fewer when documents are long: some servers, such as LM Studio, share the model's context window between them.

A larger model gives better answers but takes longer per document. For simple tasks such as a topic or a document type, a small model is often enough; test before you scale up.

Options such as temperature, seed, top K and the context window are now set on the model, not on the prompt. Open the model under Settings > Intelligence > Models and expand Advanced Options. To use different options for different prompts, add the same model twice with different nicknames.

Step 4 - Write the Prompts

System Prompt

The system prompt defines the role and goal of the model. This is what sets context for the model's behavior and should explain the task in simple but precise terms.

Important tip!

Write this like you're briefing a junior analyst. Be specific about the task, what you expect returned, and how to handle uncertain cases.

image-20250724-200250.png
Example of a System prompt

Example

You are a data extraction assistant. Your task is to analyze a document and determine if it pertains to any of the client matters listed below. If you identify a match, return all fields from the matching row exactly as shown. If you are not sure or cannot confidently match the document to a matter, respond with "N/A".

User Prompt

This is where you inject the actual text of the document. Use {{text}} in your prompt to insert the full document content that Shinydocs Pro extracted during the crawl. The User prompt is usually much simpler than the System prompt.

Available placeholders:

Placeholder

Use

{{text}}

Replaced with the text data Shinydocs Pro has extracted for the document.

Index field used: fullText

{{path}}

Replaced with the path value for the document.

Index field used: path

{{name}}

Replaced with the file name for the document (including the extension).

Index field used: name

{{created}}

Replaced with the document’s creation time.

Index field used: creationTimeUtc

{{modified}}

Replaced with the document’s last modified time.

Index field used: lastWriteTimeUtc

{{system}}

Replaced with the system prompt.

Document text limit: how many characters of each document's text are sent. 0 sends all of it. Lower it if long documents are slow or fail: a model reads only as much as its context window holds.

A prompt can't be saved until it uses at least one document placeholder: {{text}}, {{name}}, {{path}}, {{created}} or {{modified}}.

Example

Document to check:
{{text}}

You can also add follow-up instructions after the injected text if needed, such as "Return results in JSON format" or "Respond with field values only." which can help with older or smaller parameter models.

To get started, we recommend the following configurations based on your use case. These are starting points, prompts and model choice may need to be refined given your data.

Try to use the Source selection & Query conditions in the prompt card to limit the content the model is analyzing to save processing time on irrelevant content.

Starting prompts and models

Starting prompts and models

These prompts offer a great starting point on your AI journey. If a prompt looks similar to what you are trying to achieve, try adapting it to your use case.

If you would like to install these models on your Ollama, use the following commands in your OS terminal (e.g. CMD):

ollama pull qwen3:0.6b

ollama pull qwen3:8b

ollama pull cogito:3b

ollama pull cogito:8b

ollama pull phi4:14b

Shinydocs recommends phi4:14b for complex tasks like client/matter discovery, logical/conditional extraction, and other prompts that require very accurate analysis.

💡Remember this is a large model, it can take 10-20 seconds for a single response for a large document depending on your hardware. Use query conditions to minimize the analyzed content.

Task/Prompt type

Suggested starting model (or)

Query conditions

System Prompt

User Prompt

Result fields

Summarization

  • qwen3:0.6b

  • cogito:3b

  • llama3.2:1b

  • fullText | exists

  • path-valid | is not | false

  • extension | is one of | pdf, docx, doc, ppt, pptx, msg, eml

Summarize the provided document in one sentence in English. The summary will provide enough insight to know what the document is about at a glance. If unsure or no summary can be made, respond with “N/A”


Document text: {{text}}


  • Field name: summary
    Field type: Text
    Required:
    Yes

Topic identification

  • qwen3:0.6b

  • cogito:3b

  • llama3.2:1b

  • fullText | exists

  • path-valid | is not | false

Using 4 words or less, assign a topic to this document based only on the contents. If there is no topic (e.g. just numbers) return N/A.
Document text: {{text}}
  • Field name: topic
    Field type: Text
    Required:
    Yes

Document sensitivity

  • qwen3:0.6b

  • fullText | exists

  • path-valid | is not | false

You are a classification assistant. Assign a simple classification of "Public", "Internal", "Confidential", or "Restricted" to the text below.

Definitions:

Public: Information approved for anyone to see. No business or security risk if shared outside the organization.

Internal: Information intended for employees or approved partners only. Low impact if disclosed, but not meant for public distribution.

Confidential: Sensitive business or client information. Unauthorized disclosure could cause harm to the organization, its clients, or partners.

Restricted: Highly sensitive information. Unauthorized disclosure could cause severe damage, legal exposure, or regulatory violations. Access should be strictly limited.

If you cannot determine the class, return classification "Internal" and a short reason.


Document path: {{path}}
Document text: {{text}}
  • Field name: sensitivity_classification
    Field type: Text
    Required:
    Yes

  • Field name: sensitivity_reason
    Field type: Text
    Required:
    Yes

Extract entities from resumes

  • qwen3:0.6b

  • fullText | exists

  • path-valid | is not | false

  • path | is | resumes

    • Assuming resumes are in a folder called “resumes”

Extract resume fields and return only JSON.
If the document is not a resume or CV, return "N/A" for the values.
Document text: {{text}}
  • Field name:
    resume_name
    Field type: Text
    Required:
    Yes

  • Field name:
    resume_email
    Field type: Text
    Required:
    Yes

  • Field name:
    resume_phone
    Field type: Text
    Required:
    Yes

  • Field name:
    resume_skills
    Field type:
    List of text
    Required:
    Yes

  • Field name:
    resume_last_role
    Field type:
    Text
    Required:
    Yes

Document type

  • cogito:3b

  • fullText | exists

  • path-valid | is not | false

Determine the type of document based on its content. Examples: 
Contract  
Invoice  
Purchase Order  
Receipt  
Statement of Work (SOW)  
Proposal  
Request for Proposal (RFP)  
Quote / Estimate  
Budget Document  
Business Plan  
Strategy Document  
Meeting Notes / Minutes  
Agenda  
Email  
Memo  
Newsletter  
Announcement  
Presentation / Slide Deck  
CV / Resume  
Cover Letter  
Job Description  
Offer Letter  
Performance Review  
Training Manual  
Policy Document  
Non-Disclosure Agreement (NDA)  
Legal Filing / Court Document  
Terms & Conditions  
Privacy Policy  
Compliance Report  
Audit Report  
Regulatory Filing  
Technical Specification  
User Manual / Guide  
Knowledge Base Article  
Standard Operating Procedure (SOP)  
White Paper  
Research Paper  
Patent Document  
Report  
Financial Statement  
Annual Report  
Risk Assessment  
Procurement Document  
Inventory Report  
FOIA Response  
Permit / License  
Grant Proposal  
Municipal Report  
Census / Survey Document  
Press Release  
Marketing Brochure  
Case Study  
Product Datasheet  
FAQ  
If none fit, return "Other".
Document path: {{path}}
Document text: {{text}}
  • Field name:
    document_type
    Field type:
    Text
    Required:
    Yes

  • Field name:
    document_type_reason
    Field type:
    Text
    Required:
    Yes

Step 5 - Set Query Conditions

Query conditions let you control when an enrichment should run. Only files that meet all conditions will be sent to the model.

Each condition checks metadata about the file. Some examples:

Field

Operator

Example Value

fullText

exists

Ensures the file has extracted text

extension

is one of

docx, pdf, txt (extensions are stored in lowercase, without the dot)

schemaType

is one of

filesystem_sharepoint-online

ai-text-analysis-custom1

does not exist

(Avoid re-processing already enriched files where the field ai-text-analysis-custom1 already has a value)

You can add multiple conditions to narrow down processing scope.

We recommend these conditions at minimum. New prompts start with fullText exists and path-valid is not false.

Field

Operator

Value

fullText

exists

Ensures the file has extracted text

ai-text-analysis-<field>

does not exist

Skips documents the prompt has already answered. Use one of the prompt's own result fields, such as ai-text-analysis-summary. To run the prompt again on those documents, remove this condition.

path-valid

is not

false

During Shinydocs Pro’s delta analysis, it checks if a file still exists or not. Adding this condition prevents the tool from running on data that doesn’t exist anymore.

Step 6 - Ignored Responses

Define any values that should be treated as a non-result and skipped from enrichment output. For example:

  • N/A

  • [N/A]

  • NA

Each field is checked on its own. If the model's answer for a field is exactly one of these values (matching is case-sensitive), that field is left empty; the other fields are still saved.

Enter them in Answers to ignore, separated by commas. New prompts start with N/A, [N/A], N\A, [N\A]. Adjust them to match how your model responds.

Step 7 - Define Result Fields

This section is where you map out what you want the AI to extract from the document and where that extracted information will be stored.

When the model processes a document, it doesn't just give you raw text back. Instead, it responds with a structured result, a set of named fields, like client, matter_number, or custom_description. Shinydocs Pro prefixes these fields with ai-text-analysis-, that way you know this field’s data came from AI enrichment. The values the model returns for those fields get saved as metadata alongside the document in the Shinydocs index. That means they can be searched, filtered, visualized, or exported just like any other metadata.

You’re telling the system: “Here’s what I expect back from the AI, and this is what type of data it should be.”

How it works

You're setting up the schema for what the AI should return - field names, their data types, and whether they're required. This tells the system how to handle the response, and it tells the model what kind of format you're expecting.

The results of AI Enrichment are dependent on the chosen model. Different models will respond in different ways, which is why choosing the right model for the task at hand is so important. Most models will respect the instructions you provide it, but will vary model-by-model. Experimentation is key!

Each field definition includes:

  • Field name: This is the name that will be stored in the index. Shinydocs will automatically prefix it with ai-text-analysis-.

    • For example, client becomes ai-text-analysis-client.

  • Field type: The expected data format of the returned value. Options include:

    • Text: A single piece of text (most common).

    • Number: A numeric value (integer or decimal).

    • Yes or no: true or false.

    • List of text: A list of values (e.g. a list of names, IDs, keywords).

      • When to use array:

        The array type is used when you expect the model to return multiple items for the same field, for example:

        • A list of people mentioned in the document

        • Multiple project codes or legal clauses

        • A list of risks or key terms

  • Required: required fields are always answered. The model can leave the other fields empty.

Example field setup

Field Name

Type

Required?

client_name

Text

✅ Yes

related_tags

List of text

❌ No

In this case:

  • client_name is required, so the model always answers it. Ask it in the system prompt to answer N/A when it can't find a client, and keep N/A in Answers to ignore, so the field is left empty instead of guessed.

  • related_tags is optional because it's supplemental. The model might extract useful keywords, topics, or flags if they exist, but you're not relying on them to validate the result. If they're missing or the document doesn't contain any, that’s fine, you still want to keep the enrichment.

Step 8 - Save

Select Save changes, or Discard changes to undo edits you haven't saved. The prompt runs the next time each of its sources runs its analysis (for example, with Run now on the source page), on the documents that match its conditions.