<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kyle Eaton</title>
    <description>The latest articles on DEV Community by Kyle Eaton (@kyle_eaton_268b8b0d67b221).</description>
    <link>https://dev.to/kyle_eaton_268b8b0d67b221</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3170922%2F30cda8b8-31d7-4973-8d9f-c91467a72889.jpg</url>
      <title>DEV Community: Kyle Eaton</title>
      <link>https://dev.to/kyle_eaton_268b8b0d67b221</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kyle_eaton_268b8b0d67b221"/>
    <language>en</language>
    <item>
      <title>Semantic Code Search</title>
      <dc:creator>Kyle Eaton</dc:creator>
      <pubDate>Tue, 27 May 2025 14:49:15 +0000</pubDate>
      <link>https://dev.to/kyle_eaton_268b8b0d67b221/semantic-code-search-f4</link>
      <guid>https://dev.to/kyle_eaton_268b8b0d67b221/semantic-code-search-f4</guid>
      <description>&lt;h2&gt;
  
  
  From Prompt to Product
&lt;/h2&gt;

&lt;p&gt;We at &lt;a href="https://ducky.ai/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=technical-use_case&amp;amp;utm_content=semantic-code-search" rel="noopener noreferrer"&gt;Ducky.ai&lt;/a&gt; noticed a strange thing has happened in software development, we’re no longer writing code in the traditional sense. Instead, we describe what we want and ask the machine to write the first draft. Tools like &lt;a href="https://github.com/features/copilot" rel="noopener noreferrer"&gt;GitHub Copilot&lt;/a&gt;, &lt;a href="https://www.cursor.com/" rel="noopener noreferrer"&gt;Cursor&lt;/a&gt;, &lt;a href="https://replit.com/" rel="noopener noreferrer"&gt;Replit&lt;/a&gt;, and &lt;a href="https://devin.ai/" rel="noopener noreferrer"&gt;Devin&lt;/a&gt; have changed what it means to build. The keyboard isn’t gone, but it’s quieter. Developers are prompting, guiding, reviewing. Code appears in response to our intent.&lt;/p&gt;

&lt;p&gt;This isn’t a distant future. It’s happening now. Describe a function in a comment and Copilot autocompletes it. Open a new file in Cursor and ask for a feature, and it drafts the architecture across files. The role of a developer is less that of a typist, but more akin to a curator or conductor.&lt;/p&gt;

&lt;p&gt;But even the best AI tools come with hallucinations; they end up guessing when they should know. Unlike other AI applications, such as a customer support where agents can improvise around vague answers, coding doesn’t tolerate bluffing. The truth in software is explicit. Ask a coding agent to help you with session handling, and it might invent a helper function that doesn’t exist, when the correct one is already defined two files over.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frh731n16wd13q0e5ndi4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frh731n16wd13q0e5ndi4.png" alt="screenshot of someone working with the ducky slack bot to vibecode" width="800" height="650"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&amp;gt; ✨Vibe coding✨ is more fun in a public Slack channel&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This bottleneck is not in generation, but in awareness. A coding agent can write a brilliant one-liner and then immediately trip over your codebase because it doesn’t remember what it wrote, can’t find what it needs, and has no understanding of how your large codebase works.&lt;/p&gt;

&lt;p&gt;This is where semantic code search comes in. It doesn’t just match strings. It finds meaning. Ask “Where are users authenticated?” and it retrieves the right files, even if those exact words never appear. Ask “How is billing handled?” and it surfaces the file with your invoice scheduler. It acts like memory or intuition, the kind of context a smart developer builds over weeks of immersion.&lt;/p&gt;

&lt;p&gt;Let’s help the agent stop guessing and give it the context it needs. Traditionally, that would mean stitching together a pipeline of embedding models, chunking logic, and a vector database, just to get basic retrieval working. This is typically fragile and hard to maintain, but &lt;a href="https://ducky.ai/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=technical-use_case&amp;amp;utm_content=semantic-code-search" rel="noopener noreferrer"&gt;Ducky&lt;/a&gt; abstracts all of that. We can skip the plumbing, and get semantic code search working in minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Semantic Code Search with Ducky AI
&lt;/h2&gt;

&lt;p&gt;Making your codebase searchable shouldn’t require setting up a vector database or designing a custom pipeline. With Ducky, it takes one script and a few lines of setup.&lt;/p&gt;

&lt;p&gt;Here’s how it works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step one&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s prepare each file into a structured document with metadata so we can use semantic search and apply metadata filters later if we need to narrow things down. Our document looks something like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "content": content, # code content
    "doc_id": f.relative_to(root), # unique identifier
    "title": f.name,
    "metadata": {
        "root": root,
        "full_path": f.as_posix(),
        "file_type": f.suffix,
    },
    "index_name": "code-memory", # data store
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step two&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ducky supports up to 100 documents in a single upload. If you're working with a larger codebase, you’ll want to split your documents into batches. This keeps indexing smooth and avoids hitting the upload limit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for i in range(0, len(docs), batch_size):
    batch = docs[i : i + batch_size]
    ducky.documents.batch_index(documents=batch)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step three&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now let’s get Ducky set up.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a Ducky AI account&lt;/li&gt;
&lt;li&gt;Create a project and an index — in the example above, we used code-memory&lt;/li&gt;
&lt;li&gt;Get your API key from the project settings&lt;/li&gt;
&lt;li&gt;Install the Python SDK
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install duckyai
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Initialize the client with your API key
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ducky = DuckyAI(api_key="DUCKYAI_API_KEY")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now putting everything together in less than 50 lines of code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import sys
from pathlib import Path
from duckyai import DuckyAI
from typing import List

ducky = DuckyAI(api_key='DUCKYAI_API_KEY')

def prepare_documents(files: List[Path], root: str) -&amp;gt; List[dict]:
    """Prepare documents for indexing."""
    return [
        {
            "content": content,
            "doc_id": str(f.relative_to(root)).replace("/", "-").replace(".", "-"),
            "title": f.name,
            "metadata": {
                "root": root,
                "full_path": f.as_posix(),
                "file_type": f.suffix,
            },
            "index_name": "code-memory",
        }
        for f in files
        if (content := f.read_text())
    ]

def batch_index_documents(docs: List[dict], batch_size: int = 100):
    """Index documents in batches."""
    for i in range(0, len(docs), batch_size):
        print(
            f"INFO: Indexing batch {i // batch_size + 1} of {len(docs) // batch_size + 1}"
        )
        ducky.documents.batch_index(documents=docs[i : i + batch_size])

if __name__ == "__main__":
    if len(sys.argv) &amp;lt; 2:
        sys.exit("Usage: python ingest.py &amp;lt;repo_path&amp;gt;")

    directory = sys.argv[1]
    files = list(Path(directory).rglob("*.py"))
    print(f"Found {len(files)} Python files.")

    docs = prepare_documents(files, directory)
    print(f"INFO: Prepared {len(docs)} documents for indexing.")

    batch_index_documents(docs)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step four&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once your documents are indexed, you can search across your codebase using natural language. You can do this directly in the developer dashboard or use the SDK to retrieve results in your application.&lt;br&gt;
Here’s how to run a simple query with the Python client:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;results = ducky.documents.retrieve(
    index_name="code-memory",
    query="how do we track customer usage?",
    top_k=5,
    rerank=True,
)

for doc in results.documents:
    print(doc.title)
    print(doc.metadata)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What’s Next
&lt;/h2&gt;

&lt;p&gt;We’ve made the codebase fully searchable in under 50 lines of code. No infrastructure setup. No model tuning. Just a clean semantic layer that lets you ask real questions about your own code and get useful answers back.&lt;/p&gt;

&lt;p&gt;This isn’t just about search. It’s about enabling better tools, tighter feedback loops, and assistants that actually understand the systems they’re working in. If you’re building with AI, retrieval is not a nice-to-have. It’s foundational.&lt;/p&gt;

&lt;p&gt;Try it on your own codebase, or check out our other resources&lt;/p&gt;

&lt;p&gt;📘 &lt;a href="https://docs.ducky.ai/docs/getting-started?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=technical-use_case&amp;amp;utm_content=semantic-code-search" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt; – for detailed setup, search tuning, and advanced features&lt;br&gt;
🧑‍🍳 &lt;a href="https://github.com/lycoai/ducky-cookbook" rel="noopener noreferrer"&gt;Cookbooks&lt;/a&gt; – for practical examples and quick-start guides&lt;/p&gt;

</description>
      <category>rag</category>
      <category>llm</category>
      <category>ducky</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to build a Legal Document Chat with OpenAI, Ducky.ai, Next.js and Browserless</title>
      <dc:creator>Kyle Eaton</dc:creator>
      <pubDate>Fri, 16 May 2025 15:57:06 +0000</pubDate>
      <link>https://dev.to/kyle_eaton_268b8b0d67b221/how-to-build-a-legal-document-chat-with-openai-duckyai-nextjs-and-browserless-2559</link>
      <guid>https://dev.to/kyle_eaton_268b8b0d67b221/how-to-build-a-legal-document-chat-with-openai-duckyai-nextjs-and-browserless-2559</guid>
      <description>&lt;h2&gt;
  
  
  What if anyone could chat with a legal document instead of having to read the whole thing?
&lt;/h2&gt;

&lt;p&gt;I wanted to create a tool where users could paste a link to a legal document and instantly start asking it questions like:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Who owns the content I create?" - Figma ToS&lt;/li&gt;
&lt;li&gt;What happens if I violate these terms?" - Apple T&amp;amp;Cs&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Today, &lt;a href="https://www.askfineprint.com/" rel="noopener noreferrer"&gt;Fineprint&lt;/a&gt; is live and working. It took surprisingly little time to build, thanks to &lt;a href="https://ducky.ai/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=use_case&amp;amp;utm_content=legal-blog" rel="noopener noreferrer"&gt;Ducky&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flffsecibjwlfk1n3z4rz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flffsecibjwlfk1n3z4rz.png" alt="screen grab of a user asking a chatbot details about Disney's terms of service" width="800" height="299"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The stack
&lt;/h2&gt;

&lt;p&gt;Here’s the technology that powers Fineprint&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frontend | Next.js - React.js &amp;amp; TypeScript&lt;/li&gt;
&lt;li&gt;Backend Scraping | Browserless (headless Chrome)&lt;/li&gt;
&lt;li&gt;Semantic Search &amp;amp; Retrieval | Ducky.ai&lt;/li&gt;
&lt;li&gt;Language Generation | OpenAI&lt;/li&gt;
&lt;li&gt;Hosting | Vercel&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How It Works (with some code)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Submitting a document to analyze &amp;amp; index
&lt;/h3&gt;

&lt;p&gt;Step 1 - We first create an index name based on the url and then use &lt;strong&gt;Browserless&lt;/strong&gt; to load and scrape the visible text from the page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const processDocument = async (url: string) =&amp;gt; {
  setIsProcessing(true)
  setError(null)

  const indexName = getIndexNameFromUrl(url)
  const content = await scrapeContent(url)

  // Index the document using the nextjs API (code in 2. below)
  const response = await fetch("/api/document", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      indexName,
      title: indexName,
      content,
      url
    })
  })

  if (!response.ok) throw new Error("Failed to index document")

  return { indexName }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 2 - A &lt;strong&gt;new index&lt;/strong&gt; is created for each document and the extracted “fine print” is &lt;strong&gt;indexed&lt;/strong&gt; using [Ducky.ai’s API]&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(https://docs.ducky.ai/reference/indextext#/).
export async function POST(req: Request) {
  const { indexName, title, content, url } = await req.json()

  // First create the index
  await DuckyClient.createIndex(indexName)

  // Then index the document
  const result = await DuckyClient.indexDocument({
    indexName,
    title,
    content,
    url
  })

  return NextResponse.json(result)
}

...

export type DuckyIndexDocumentParams = {
  indexName: string
  title: string
  content: string
  url: string
  docId?: string
}

export class DuckyClient {
  static async createIndex(indexName: string) {
    const response = await fetch(`${DUCKY_API}/indexes`, {
      method: "POST",
      headers: {
        "x-api-key": DUCKY_API_KEY,
        "Content-Type": "application/json"
      },
      body: JSON.stringify({ index_name: indexName })
    })

    if (!response.ok) {
      throw new Error(`Failed to create index: ${response.body}`)
    }

    return response.json()
  }

  static async indexDocument(params: DuckyIndexDocumentParams) {
    const response = await fetch(`${DUCKY_API}/documents/index-text`, {
      method: "POST",
      headers: {
        "x-api-key": DUCKY_API_KEY,
        "Content-Type": "application/json"
      },
      body: JSON.stringify({
        index_name: params.indexName,
        title: params.title,
        content: params.content,
        url: params.url,
        doc_id: params.docId || ""
      })
    })

    if (!response.ok) {
      throw new Error(`Failed to index content: ${response.statusText}`)
    }

    return response.json()
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Users ask questions about the document
&lt;/h3&gt;

&lt;p&gt;Step 1 - &lt;strong&gt;Fineprint&lt;/strong&gt; retrieves relevant chunks of content from &lt;a href="https://ducky.ai/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=use_case&amp;amp;utm_content=legal-blog" rel="noopener noreferrer"&gt;Ducky&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { indexName, question } = await req.json() // From UI

// First, get relevant chunks from Ducky
const duckyResponse = await DuckyClient.retrieve({
  indexName,
  query: question,
  alpha: 1,
  topK: 3 // Get top 3 chunks for better context
})

// Prepare context from chunks
const context = duckyResponse.chunks.map((chunk) =&amp;gt; chunk.content).join("\n\n")

...

type DuckyRetrieveParams = {
  indexName: string
  query: string
  alpha?: number
  topK?: number
}

static async retrieve(params: DuckyRetrieveParams): Promise&amp;lt;DuckyRetrieveResponse&amp;gt; {
  const response = await fetch(`${DUCKY_API_BASE}/documents/retrieve`, {
    method: "POST",
    headers: {
      "x-api-key": DUCKY_API_KEY,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      index_name: params.indexName,
      query: params.query,
      alpha: params.alpha || 1,
      top_k: params.topK || 1
    })
  })

  if (!response.ok) {
    throw new Error(`Failed to retrieve documents: ${response.statusText}`)
  }

  return response.json()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 2 - The uses &lt;strong&gt;OpenAI&lt;/strong&gt; to synthesise a clear, natural response based on the context.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Prepare the prompt for OpenAI based on context and question
const messages = [
  {
    role: "system",
    content:
      "You are a helpful assistant that answers questions about terms and conditions documents. " + 
      "Use the provided context to answer questions accurately and concisely."
  },
  {
    role: "user",
    content: `Context from the document:\n\n${context}\n\nQuestion: ${question}`
  }
]

const response = await fetch(OPENAI_API_URL, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${OPENAI_API_KEY}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    model: "gpt-3.5-turbo",
    messages,
    temperature: 0.7,
    max_tokens: 500
  })
})

// Simplified without error handling for readability
return { answer: result.choices[0].message.content }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  System Flow
&lt;/h2&gt;

&lt;p&gt;Here’s a simple breakdown of how it all connects:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy08o82iru72ze2ok3ury.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy08o82iru72ze2ok3ury.png" alt="system flow chart breaking down how everything connects" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Ducky.ai?
&lt;/h2&gt;

&lt;p&gt;Honestly, Ducky was a game changer for this project.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Simple indexing&lt;/strong&gt; — I didn’t have to build any custom indexing/search engine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliable retrieval&lt;/strong&gt; — The API delivers semantically relevant context with minimal tuning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero infra management&lt;/strong&gt; — No hosting embeddings, no worrying about scale.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In a world where retrieval is often the hardest part of building an AI product, Ducky made it easy.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s Next
&lt;/h2&gt;

&lt;p&gt;I’m excited to keep building on top of &lt;a href="https://www.askfineprint.com/" rel="noopener noreferrer"&gt;Fineprint&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Support PDFs and uploads&lt;/strong&gt; (not just URLs)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Highlight referenced sections&lt;/strong&gt; directly in the document view&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expand offering and categorise documents&lt;/strong&gt;: include privacy policies, insurance docs, contracts etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More sophisticated multi-document search&lt;/strong&gt; (e.g., compare terms between providers)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Final Thoughts: Anyone Can Build AI Tools Now
&lt;/h2&gt;

&lt;p&gt;This project helped reinforce the idea that you don’t need a giant ML team to build something magical with AI.&lt;/p&gt;

&lt;p&gt;With tools like &lt;a href="https://ducky.ai/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=use_case&amp;amp;utm_content=legal-blog" rel="noopener noreferrer"&gt;Ducky&lt;/a&gt;, OpenAI and Next.js/Vercel, developers can prototype and launch powerful AI-powered tools incredibly quickly.&lt;/p&gt;

&lt;p&gt;Fineprint was essentially a 1 day project — imagine what’s possible when we really push the boundaries.&lt;/p&gt;

&lt;p&gt;If you’ve been thinking about building something with AI — this is your sign to start.&lt;/p&gt;

&lt;p&gt;Try it yourself&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Visit &lt;a href="https://www.askfineprint.com/" rel="noopener noreferrer"&gt;www.askfineprint.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ducky.ai/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=use_case&amp;amp;utm_content=legal-blog" rel="noopener noreferrer"&gt;Learn more about Ducky&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rag</category>
      <category>gpt3</category>
      <category>nextjs</category>
      <category>browserless</category>
    </item>
  </channel>
</rss>
