<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Akriti Upadhyay on Medium]]></title>
        <description><![CDATA[Stories by Akriti Upadhyay on Medium]]></description>
        <link>https://medium.com/@akriti.upadhyay?source=rss-f6c4eb90254------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*AI0KLpsRPvNaGV2UZttKgQ.jpeg</url>
            <title>Stories by Akriti Upadhyay on Medium</title>
            <link>https://medium.com/@akriti.upadhyay?source=rss-f6c4eb90254------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 07:00:44 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@akriti.upadhyay/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[How to Build an AI Content Personalization Engine Using Salesforce, SingleStore, and Groq Llama]]></title>
            <link>https://medium.com/@akriti.upadhyay/how-to-build-an-ai-content-personalization-engine-using-salesforce-singlestore-and-groq-llama-9f5cc11df99e?source=rss-f6c4eb90254------2</link>
            <guid isPermaLink="false">https://medium.com/p/9f5cc11df99e</guid>
            <category><![CDATA[singlestore]]></category>
            <category><![CDATA[groq]]></category>
            <category><![CDATA[cloud-functions]]></category>
            <category><![CDATA[salesforce]]></category>
            <category><![CDATA[fastapi]]></category>
            <dc:creator><![CDATA[Akriti Upadhyay]]></dc:creator>
            <pubDate>Wed, 29 Apr 2026 14:05:23 GMT</pubDate>
            <atom:updated>2026-04-29T18:00:03.139Z</atom:updated>
            <content:encoded><![CDATA[<h3>How to Build an AI Content Personalization Engine Using Salesforce, SingleStore Helios, and Groq Llama</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UioK1p_IXA0k_waXcmrFGA.png" /><figcaption>AI Content Personalization Engine using Salesforce, SingleStore Helios, and Groq Llama</figcaption></figure><h3>Introduction</h3><p>AI-powered personalization is becoming an important part of modern enterprise applications. Businesses across marketing, sales, customer support, and e-commerce are using AI systems to generate personalized recommendations, customer interactions, and content based on user behavior and contextual information. Building such systems involves multiple challenges, including handling customer data across different platforms, retrieving relevant context, and generating accurate responses tailored to individual users.</p><p>In this article, we will build an AI Content Personalization Engine using Salesforce, SingleStore Helios, and Groq Llama. We will explore how vector embeddings, semantic retrieval, and Retrieval-Augmented Generation (RAG) can be integrated to generate personalized AI-driven content using customer context and data retrieval.</p><h3>What is AI Content Personalization?</h3><p>AI Content Personalization is the process of generating content based on individual user behavior, preferences, and contextual data. It uses signals such as past interactions, purchase history, browsing activity, and CRM records to understand user intent and produce relevant outputs. This can include personalized emails, product recommendations, support responses, marketing messages, and in-app experiences. The aim is to ensure each user receives content that matches their current needs and interests instead of generic communication.</p><h4>Why do we need it?</h4><p>Users interact with multiple digital touchpoints every day, and the volume of available content continues to grow. Generic messaging often fails to capture attention or drive meaningful engagement. Businesses also deal with large volumes of customer data spread across systems such as CRMs, analytics platforms, and support tools.</p><p>AI Content Personalization helps in addressing these challenges by connecting data from multiple sources and generating content that is relevant to each user. It improves engagement, supports better decision-making in sales and marketing workflows, and helps in creating more consistent customer experiences across channels.</p><h3>Building an AI Content Personalization Engine on SingleStore Helios</h3><p>Before integrating Salesforce with SingleStore Helios and building the personalization pipeline, the first step is setting up a Salesforce Developer Edition environment and preparing it for API-based access. This setup ensures we can extract CRM data such as Contacts, Leads, Accounts, Campaigns, and Opportunities, and use them for our AI personalization engine.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*SlgJbWBWtA4M7OELMhnqOw.png" /><figcaption>Image Generated by ChatGPT</figcaption></figure><h4>Setting Up Salesforce for Data Access and Integration</h4><p>To get started, create a free Salesforce Developer Edition account at <a href="https://www.salesforce.com/products/free-trial/developer/"><strong>https://www.salesforce.com/products/free-trial/developer/</strong></a>. No credit card is required for this setup. Once registered, you get access to a fully functional Salesforce CRM environment that includes preloaded sample data.</p><p>After logging in, navigate to the <strong>Setup Menu</strong> (Gear icon) and open the <strong>Developer Console</strong> to explore the sample datasets using <strong>Query Editor</strong>. Salesforce provides realistic sample records such as Contacts, Accounts, Leads, Campaigns, and Opportunities, which help in simulating enterprise CRM scenarios.</p><p>To verify the available data, you can use the <strong>Developer Console</strong> and run a SOQL query like:</p><pre>SELECT Id, FirstName, LastName,<br>       Title, Email, Department,<br>       LeadSource, AccountId<br>FROM Contact</pre><p>This will return sample contacts such as business personas similar to procurement heads, finance executives, and operations leaders, which will later be used for personalization workflows.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7Vi3h98JZ4bqvtq92O36aQ.png" /><figcaption>Run SOQL query in Query Editor in Developer Console</figcaption></figure><p>To connect Salesforce with external systems such as SingleStore Helios or backend services, API access must be enabled through OAuth.</p><p>The following are the steps:</p><ul><li>Navigate to the <strong>Setup Menu </strong>(Gear icon) →<strong> Setup</strong></li><li>Search for <strong>OAuth and OpenID Connect Settings</strong></li><li>Enable <strong>Allow</strong> <strong>OAuth Username-Password Flows</strong></li><li>Save the configuration</li></ul><p>This allows secure authentication for API-based data extraction.</p><p>A Connected App is required to generate API credentials for external integrations.</p><p>The following are the steps to create a Connected App:</p><ul><li>Navigate to the <strong>Setup Menu </strong>(Gear icon) → <strong>Setup</strong></li><li>Search for <strong>External Client Apps</strong></li><li>Navigate to <strong>Settings</strong></li><li>Select <strong>New Connected App</strong></li><li>Fill in the details:<br>- App Name: PersonalizationApp<br>- Email address: <em>&lt;your-registered-email-address&gt;</em><br>- Enable <strong>OAuth Settings<br>-</strong> Set Callback URL:<a href="http://localhost:8080/callback">http://localhost:8080/callback</a><br>- Select OAuth Scopes: Full access (full)<br>- Save the app</li></ul><p>Once created, review the controls, confirm them, and Salesforce will generate credentials: Consumer Key and Consumer Secret.</p><p>These credentials will be used to authenticate API calls from external services.</p><p>Salesforce requires a security token for API authentication from external environments.</p><p>To generate it, the following steps are taken:</p><ul><li>Click on your profile avatar</li><li>Go to <strong>Settings</strong></li><li>Search for <strong>Reset My Security Token</strong></li><li>Click <strong>Reset Security Token</strong></li><li>Check your registered email for the new token</li></ul><p>This token is used along with username and password during API authentication flows.</p><p>To support AI-driven personalization, we extend the <strong>Contacts</strong> object with additional fields that store AI-generated metadata.</p><ul><li>Navigate to <strong>Setup → Object Manager → Contact → Fields &amp; Relationships → New</strong></li><li>Create the following fields:</li></ul><p><strong>Field 1: AI Persona</strong></p><ul><li>Data Type: Text</li><li>Field Label: AI Persona</li><li>API Name: AI_Persona__c</li><li>Length: 50</li></ul><p><strong>Field 2: AI Persona Score</strong></p><ul><li>Data Type: Number</li><li>Field Label: AI Persona Score</li><li>API Name: AI_Persona_Score__c</li><li>Decimal Places: 0</li></ul><p><strong>Field 3: AI Last Personalized</strong></p><ul><li>Data Type: Date/Time</li><li>Field Label: AI Last Personalized</li><li>API Name: AI_Last_Personalized__c</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*REv5D6YhbON4mglFrAbKBQ.png" /><figcaption>New AI Persona Fields in Salesforce Contact Object</figcaption></figure><p>Later, these fields will help in tracking personalization outputs generated by the AI system in SingleStore Helios and storing enrichment metadata for each customer profile.</p><h4>Connecting Salesforce with SingleStore Helios</h4><p>Now that Salesforce is configured, the next step is to extract CRM data and load it into <a href="http://portal.singlestore.com/intention/cloud?utm_source=akriti-upadhyay">SingleStore Helios</a>.</p><p>Install the required libraries for Salesforce integration, data processing, and SingleStore connectivity.</p><pre>!pip install -q simple-salesforce faker pandas</pre><p>Securely load Salesforce credentials using SingleStore <a href="https://docs.singlestore.com/cloud/developer-resources/secrets/">Secrets</a>.</p><pre>from singlestoredb.management import get_secret<br>SF_USERNAME = get_secret(&#39;SF_USERNAME&#39;)<br>SF_PASSWORD = get_secret(&#39;SF_PASSWORD&#39;)<br>SF_SECURITY_TOKEN = get_secret(&#39;SF_SECURITY_TOKEN&#39;)<br>SF_INSTANCE_URL = get_secret(&#39;SF_INSTANCE_URL&#39;)</pre><p>Next, initialize the Salesforce connection:</p><pre>from simple_salesforce import Salesforce<br>sf = Salesforce(<br>    username=SF_USERNAME,<br>    password=SF_PASSWORD,<br>    security_token=SF_SECURITY_TOKEN<br>)</pre><p>To verify connectivity, run a simple SOQL query:</p><pre>result = sf.query(&quot;&quot;&quot;<br>SELECT Id, FirstName, LastName, Title<br>FROM Contact<br>LIMIT 5<br>&quot;&quot;&quot;)<br><br>for record in result[&#39;records&#39;]:<br>    print(f&quot;{record[&#39;FirstName&#39;]} {record[&#39;LastName&#39;]} - {record[&#39;Title&#39;]}&quot;)</pre><p>This confirms that Salesforce data is accessible through the API.</p><p>Extract data from multiple Salesforce objects, including Contacts, Accounts, Leads, Campaigns, and Opportunities.</p><p>Each object provides a different business context required for personalization.</p><p>For example, Contacts contain role and persona information:</p><pre>contacts_query = sf.query(&quot;&quot;&quot;<br>    SELECT Id, FirstName, LastName,<br>           Title, Email, Department,<br>           LeadSource, AccountId<br>    FROM Contact<br>&quot;&quot;&quot;)</pre><p>Similarly, we extract account-level company data, lead acquisition data, campaign performance data, and opportunity pipeline information.</p><p>Each dataset is converted into a Pandas DataFrame for further processing.</p><p>After extraction, save the CRM datasets as CSV files.</p><pre>contacts_df.to_csv(&#39;data/contacts.csv&#39;, index=False)<br>accounts_df.to_csv(&#39;data/accounts.csv&#39;, index=False)<br>leads_df.to_csv(&#39;data/leads.csv&#39;, index=False)<br>campaigns_df.to_csv(&#39;data/campaigns.csv&#39;, index=False)<br>opps_df.to_csv(&#39;data/opportunities.csv&#39;, index=False)</pre><p>This creates a reusable local data layer for downstream ingestion into SingleStore Helios.</p><p>Once the Salesforce data has been extracted, we create the required relational tables in SingleStore Helios.</p><pre>import singlestoredb as s2<br><br>conn = s2.connect(<br>    host=SS_HOST,<br>    port=3306,<br>    user=&quot;admin&quot;,<br>    password=SS_PASSWORD,<br>    database=&quot;salesforce&quot;<br>)</pre><p>We then initialize a cursor to execute SQL queries.</p><p>We create dedicated tables for contacts, accounts, leads, campaigns, opportunities, and visitor_events.</p><p>For example:</p><pre>CREATE TABLE IF NOT EXISTS contacts (<br>    id              VARCHAR(50) PRIMARY KEY,<br>    first_name      VARCHAR(100),<br>    last_name       VARCHAR(100),<br>    title           VARCHAR(200),<br>    email           VARCHAR(200),<br>    department      VARCHAR(100),<br>    lead_source     VARCHAR(100),<br>    account_id      VARCHAR(50),<br>    persona         VARCHAR(50)<br>)</pre><p>The visitor_events table is important because it stores behavioral tracking signals such as page visits, button clicks, scroll depth, and engagement activity.</p><p>These behavioral signals later become inputs for personalization and retrieval workflows.</p><p>Before loading the CRM records, we classify users into personas based on job titles.</p><pre>def map_persona(title):<br>    if pd.isna(title):<br>        return &#39;Unknown&#39;<br>    title = title.upper()<br>    if any(x in title for x in [&#39;CEO&#39;, &#39;CFO&#39;, &#39;SVP&#39;, &#39;PRESIDENT&#39;, &#39;FOUNDER&#39;]):<br>        return &#39;Executive&#39;<br>    elif any(x in title for x in [&#39;VP&#39;, &#39;TECHNOLOGY&#39;, &#39;ENGINEER&#39;, &#39;DEVELOPER&#39;]):<br>        return &#39;Technical&#39;<br>    elif any(x in title for x in [&#39;FINANCE&#39;, &#39;PROCUREMENT&#39;, &#39;VENDOR&#39;, &#39;ADMIN&#39;]):<br>        return &#39;Finance&#39;<br>    else:<br>        return &#39;Other&#39;</pre><p>This creates structured customer segmentation categories used later for personalization.</p><p>Now, load all CRM datasets into SingleStore Helios using SQL insert operations.</p><p>For example:</p><pre>for _, row in contacts_df.iterrows():<br>    cursor.execute(&quot;&quot;&quot;<br>        INSERT IGNORE INTO contacts <br>        (id, first_name, last_name, title, email, <br>         department, lead_source, account_id, persona)<br>        VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)<br>    &quot;&quot;&quot;, (<br>        row[&#39;Id&#39;], row[&#39;FirstName&#39;], row[&#39;LastName&#39;],<br>        row[&#39;Title&#39;], row[&#39;Email&#39;], row[&#39;Department&#39;],<br>        row[&#39;LeadSource&#39;], row[&#39;AccountId&#39;], row[&#39;persona&#39;]<br>    ))</pre><p>At this stage, Salesforce CRM data becomes fully queryable inside SingleStore.</p><p>Once the data is loaded, we can run segmentation queries directly on SingleStore.</p><pre>SELECT persona, COUNT(*) as total<br>FROM contacts<br>GROUP BY persona<br>ORDER BY total DESC</pre><p>Next, we integrate <a href="https://console.groq.com/keys">Groq</a> for LLM-based persona reasoning and content generation.</p><pre>from groq import Groq<br><br>client = Groq(api_key=GROQ_API_KEY)</pre><p>We then validate the connection using a simple completion request.</p><h4>Building the AI Content Personalization Engine</h4><p>The personalization engine combines the following to generate role-specific content:</p><ul><li>Salesforce CRM context</li><li>SingleStore segmentation data</li><li>Groq Llama reasoning</li></ul><p>We first define content templates for different personas:</p><pre>content_variants = {<br>    &quot;Executive&quot;: {<br>        &quot;headline&quot;: &quot;Scale Your Business with Enterprise-Grade AI&quot;,<br>        &quot;subheadline&quot;: &quot;Trusted by CEOs and SVPs at 500+ companies worldwide&quot;,<br>        &quot;cta&quot;: &quot;Book Executive Briefing&quot;,<br>        &quot;social_proof&quot;: &quot;Used by Fortune 500 leadership teams&quot;<br>    },<br>    &quot;Technical&quot;: {<br>        &quot;headline&quot;: &quot;Build Faster with Our Developer-First Platform&quot;,<br>        &quot;subheadline&quot;: &quot;REST API, SDKs, and 10k free calls/month&quot;,<br>        &quot;cta&quot;: &quot;Start Building Free&quot;,<br>        &quot;social_proof&quot;: &quot;Loved by 50,000+ developers globally&quot;<br>    },<br>    &quot;Finance&quot;: {<br>      &quot;headline&quot;: &quot;Accelerate Growth and Maximize ROI with AI Automation&quot;,<br>      &quot;subheadline&quot;: &quot;Achieve up to 3x ROI in 90 days — backed by real data&quot;,<br>      &quot;cta&quot;: &quot;Explore ROI Potential&quot;,<br>      &quot;social_proof&quot;: &quot;Trusted by finance leaders at Deloitte and KPMG&quot;<br>    },<br>    &quot;Other&quot;: {<br>        &quot;headline&quot;: &quot;AI-Powered Solutions for Every Team&quot;,<br>        &quot;subheadline&quot;: &quot;Easy to use, powerful at scale&quot;,<br>        &quot;cta&quot;: &quot;Get Started Free&quot;,<br>        &quot;social_proof&quot;: &quot;Join 100,000+ happy users&quot;<br>    }<br>}</pre><p>The personalization pipeline sends visitor context to the Llama model:</p><pre>response = groq_client.chat.completions.create(<br>        model=&quot;llama-3.1-8b-instant&quot;,<br>        messages=[<br>            {<br>                &quot;role&quot;: &quot;system&quot;,<br>                &quot;content&quot;: &quot;&quot;&quot;You are a B2B SaaS personalization engine.<br>Your job is to analyze visitor profiles and return <br>personalization recommendations as valid JSON only.<br>Never include explanations or markdown, only raw JSON.&quot;&quot;&quot;<br>            },<br>            {<br>                &quot;role&quot;: &quot;user&quot;,<br>                &quot;content&quot;: f&quot;&quot;&quot;<br>{visitor_context}<br><br>Analyze this visitor and return JSON with these exact keys:<br>{{<br>    &quot;confirmed_persona&quot;: &quot;Executive or Technical or Finance or Other&quot;,<br>    &quot;confidence_score&quot;: 0-100,<br>    &quot;reasoning&quot;: &quot;one sentence explanation&quot;,<br>    &quot;personalized_message&quot;: &quot;one sentence tailored to their role&quot;,<br>    &quot;recommended_campaign&quot;: &quot;Webinar or Conference or Direct Mail or Trade Show&quot;<br>}}<br><br>Return ONLY the JSON object, nothing else.<br>                &quot;&quot;&quot;<br>            }<br>        ],<br>        temperature=0.3,<br>        max_tokens=500<br>    )</pre><p>The model analyzes job title, industry, company size, revenue, lead source, and predicts persona type, personalization confidence, campaign recommendation, and personalized messaging. The response is returned as structured JSON.</p><p>To expose the personalization engine as a production-ready service, we built a FastAPI application using SingleStore <a href="https://docs.singlestore.com/cloud/container-services/cloud-functions/">Cloud Function</a>.</p><p>The API provides endpoints such as:</p><ul><li>/health</li><li>/visitors</li><li>/segments</li><li>/personalize</li></ul><pre>@app.post(&quot;/personalize&quot;)<br>async def personalize(request: PersonalizeRequest):<br>    def query():<br>        if request.contact_id:<br>            result = execute_query(&quot;&quot;&quot;<br>                SELECT c.first_name, c.last_name, c.title,<br>                       c.persona, c.lead_source,<br>                       a.industry, a.annual_revenue,<br>                       a.number_of_employees<br>                FROM contacts c<br>                LEFT JOIN accounts a ON c.account_id = a.id<br>                WHERE c.id = :id<br>            &quot;&quot;&quot;, {&quot;id&quot;: request.contact_id})<br>        elif request.lead_id:<br>            result = execute_query(&quot;&quot;&quot;<br>                SELECT first_name, last_name, title,<br>                       persona, lead_source,<br>                       industry, 0, 0<br>                FROM leads WHERE id = :id<br>            &quot;&quot;&quot;, {&quot;id&quot;: request.lead_id})<br>        else:<br>            raise HTTPException(<br>                status_code=400,<br>                detail=&quot;Provide contact_id or lead_id&quot;<br>            )<br><br>        row = result.fetchone()<br>        if not row:<br>            raise HTTPException(status_code=404, detail=&quot;Visitor not found&quot;)<br><br>        (first_name, last_name, title, persona,<br>         lead_source, industry, revenue, employees) = row<br><br>        # Groq persona reasoning<br>        response = groq_client.chat.completions.create(<br>            model=&quot;llama-3.1-8b-instant&quot;,<br>            messages=[<br>                {<br>                    &quot;role&quot;: &quot;system&quot;,<br>                    &quot;content&quot;: &quot;You are a B2B SaaS personalization engine. Return only valid JSON.&quot;<br>                },<br>                {<br>                    &quot;role&quot;: &quot;user&quot;,<br>                    &quot;content&quot;: f&quot;&quot;&quot;<br>Visitor: {first_name} {last_name}<br>Title: {title or &#39;Unknown&#39;}<br>Industry: {industry or &#39;Technology&#39;}<br>Revenue: ${revenue:,.0f}<br><br>Return JSON:<br>{{<br>    &quot;confirmed_persona&quot;: &quot;Executive or Technical or Finance or Other&quot;,<br>    &quot;confidence_score&quot;: 0-100,<br>    &quot;reasoning&quot;: &quot;one sentence&quot;,<br>    &quot;personalized_message&quot;: &quot;one sentence for this visitor&quot;,<br>    &quot;recommended_campaign&quot;: &quot;Webinar or Conference or Direct Mail or Trade Show&quot;<br>}}<br>                    &quot;&quot;&quot;<br>                }<br>            ],<br>            temperature=0.3,<br>            max_tokens=300<br>        )<br><br>        raw = response.choices[0].message.content<br>        raw = raw.replace(&#39;```json&#39;, &#39;&#39;).replace(&#39;```&#39;, &#39;&#39;).strip()<br><br>        try:<br>            analysis = json.loads(raw)<br>        except Exception:<br>            analysis = {<br>                &quot;confirmed_persona&quot;: persona or &quot;Other&quot;,<br>                &quot;confidence_score&quot;: 70,<br>                &quot;reasoning&quot;: &quot;Rule-based fallback&quot;,<br>                &quot;personalized_message&quot;: f&quot;Welcome {first_name}!&quot;,<br>                &quot;recommended_campaign&quot;: &quot;Webinar&quot;<br>            }<br><br>        confirmed_persona = analysis.get(&#39;confirmed_persona&#39;, &#39;Other&#39;)<br>        content = content_variants.get(confirmed_persona, content_variants[&#39;Other&#39;])<br><br>        # Get matching campaign from SingleStore<br>        campaign_result = execute_query(&quot;&quot;&quot;<br>            SELECT name, type, status<br>            FROM campaigns<br>            WHERE type = :type LIMIT 1<br>        &quot;&quot;&quot;, {&quot;type&quot;: analysis.get(&#39;recommended_campaign&#39;, &#39;Webinar&#39;)})<br>        campaign = campaign_result.fetchone()<br><br>        # Salesforce Write-Back<br>        writeback_result = salesforce_writeback(<br>            contact_id=request.contact_id,<br>            persona=confirmed_persona,<br>            confidence_score=analysis.get(&#39;confidence_score&#39;, 70), <br>            recommended_campaign_type=analysis.get(&#39;recommended_campaign&#39;, &#39;Webinar&#39;)<br>        ) if request.contact_id else {&quot;status&quot;: &quot;skipped&quot;}<br><br>        return {<br>            &quot;visitor&quot;:    f&quot;{first_name} {last_name}&quot;,<br>            &quot;title&quot;:      title or &quot;Professional&quot;,<br>            &quot;persona&quot;:    confirmed_persona,<br>            &quot;confidence_score&quot;:    analysis.get(&#39;confidence_score&#39;, 70),<br>            &quot;reasoning&quot;:           analysis.get(&#39;reasoning&#39;, &#39;&#39;),<br>            &quot;personalized_message&quot;: analysis.get(&#39;personalized_message&#39;, &#39;&#39;),<br>            &quot;content&quot;:             content,<br>            &quot;recommended_campaign&quot;: {<br>                &quot;name&quot;:   campaign[0] if campaign else &quot;Default Campaign&quot;,<br>                &quot;type&quot;:   campaign[1] if campaign else &quot;Webinar&quot;,<br>                &quot;status&quot;: campaign[2] if campaign else &quot;Planned&quot;<br>            },<br>            &quot;salesforce_writeback&quot;: writeback_result  <br>        }<br><br>    try:<br>        return await run_in_thread(query)<br>    except HTTPException as e:<br>        raise e<br>    except Exception as e:<br>        logging.error(f&quot;Error: {str(e)}&quot;)<br>        raise HTTPException(status_code=500, detail=str(e))</pre><p>This endpoint retrieves CRM context from SingleStore, sends visitor data to Groq Llama, generates persona-specific recommendations, returns personalized content, and writes AI metadata back into Salesforce.</p><p>The Salesforce writeback step updates Salesforce with AI-generated enrichment data. The system also automatically enrolls contacts into recommended campaigns using Salesforce Campaign Members.</p><p>Create a cloud function by selecting the <strong>Create Cloud Function</strong> button on the right-upper side.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bjKDhGEu7obDCetj035u7g.png" /><figcaption>Cloud Function of the AI Personalization Engine</figcaption></figure><p>Once the cloud function is created, go to the cloud function and click <strong>View API Keys</strong> on the right-upper side. Create the API key and save it as a secret to use the API key of the cloud function. We used this API key in creating the Dash App.</p><h4>Building the Personalization Dashboard with Dash</h4><p>After building the Cloud Function layer for the AI Content Personalization Engine, the next step is to create an internal dashboard for visualizing and testing the system. This dashboard is not the visitor-facing experience; it is our monitoring and demo tool, similar to how Google Analytics works behind the scenes. For this, we use Plotly Dash with Dash Bootstrap Components, which connects directly to the SingleStore Cloud Function endpoint built earlier.</p><p>The dashboard fetches initial visitor and segment data from the API and dynamically renders customer personas identified from Salesforce CRM, segment-level distribution of contacts, a live personalization simulation interface, and a structured table of all CRM visitors.</p><p>The UI simulates visitor signals such as the page visited and the traffic source. These signals are sent to the /personalize endpoint, which triggers the full AI pipeline; Salesforce data lookup, SingleStore query, and Groq LLaMA persona reasoning.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UjLnfTw23RCkncrlZNgEgg.png" /><figcaption>Internal Dashboard for AI Content Personalization Engine</figcaption></figure><p>Once a visitor is selected, the system returns a fully personalized landing page experience, including a persona-specific headline and messaging, Groq LLaMA reasoning for persona classification, a recommended Salesforce campaign based on CRM context, CTA variation based on visitor segment, and a Salesforce write-back status showing campaign enrollment.</p><h3>Conclusion</h3><p>I found it interesting to build an end-to-end AI Content Personalization Engine by connecting Salesforce, SingleStore Helios, and Groq Llama into a single workflow that handles CRM data extraction, storage, persona segmentation, and AI-driven content generation.</p><p>Working with Salesforce objects and mapping them into SingleStore tables made the data flow much clearer, and using Groq Llama for persona reasoning added a practical layer of decision-making on top of structured CRM data. The experience of tying together API integrations, SQL-based analytics, and LLM responses showed how quickly personalization systems can be built with the right stack. Adding on top of this, the Dash-based dashboard completes the system by providing an interface to simulate user behavior and visualize personalized outputs directly.</p><p>Now it’s your turn to experiment with CRM-driven AI pipelines, extend the personalization logic, and explore how far RAG can go in enterprise use cases.</p><p><em>Thank you for reading!</em></p><h3>Source Code</h3><p><a href="https://github.com/akritiupadhyay-au/AI-Content-Personalization-Engine/tree/main">AI Content Personalization Engine — Github Repo</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9f5cc11df99e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Enhancing Gemma 3’s Capabilities with Fine-Tuning for Function Calling]]></title>
            <link>https://medium.com/@akriti.upadhyay/enhancing-gemma-3s-capabilities-with-fine-tuning-for-function-calling-f1bc74051abe?source=rss-f6c4eb90254------2</link>
            <guid isPermaLink="false">https://medium.com/p/f1bc74051abe</guid>
            <category><![CDATA[gemma-3]]></category>
            <category><![CDATA[llm-function-calling]]></category>
            <category><![CDATA[hugging-face]]></category>
            <category><![CDATA[fine-tuning]]></category>
            <category><![CDATA[ai-agent]]></category>
            <dc:creator><![CDATA[Akriti Upadhyay]]></dc:creator>
            <pubDate>Mon, 05 May 2025 04:19:29 GMT</pubDate>
            <atom:updated>2025-05-05T04:19:29.142Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*N2Hx5tIXr-_-zcfh4qlpSA.png" /></figure><h3>Introduction</h3><p>Function calling enables large language models to interact dynamically with external tools such as APIs, databases, or custom functions.</p><p>Fine-tuning an LLM for function calling involves training the model not only to generate natural language responses but also to determine when and how to invoke external functions based on the user’s query. During this process, the model learns to identify the need for a function call, generate the appropriate arguments, and pass them to external systems or APIs.</p><p>To leverage the capabilities of function calling, we will fine-tune <a href="https://huggingface.co/google/gemma-3-27b-it">Gemma 3</a> on the <a href="https://huggingface.co/datasets/Salesforce/xlam-function-calling-60k">Salesforce function calling dataset</a>, which contains 60,000 examples collected by APIGen for function calling applications. The data is generated using <a href="https://github.com/deepseek-ai/DeepSeek-V2">DeepSeek-V2-Chat</a> and <a href="https://huggingface.co/mistral-community/Mixtral-8x22B-v0.1">Mixtral-8x22B-Inst</a>. Before delving deeper, let’s understand what function calling is.</p><h3>What is Function Calling?</h3><p>Function calling refers to the ability of the large language models to invoke external functions or APIs based on user inputs to retrieve information or perform tasks beyond their built-in knowledge.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*oKsAf_TKv7hBsptlQwuktQ.png" /><figcaption>Function Calling</figcaption></figure><p>With Function calling, the model follows the following steps:</p><ol><li><strong>Detect the need for an external tool or function</strong>: When a user request requires a specific data or actions outside the model’s internal capabilities, the model identifies that an external function must be called.</li><li><strong>Generate appropriate arguments</strong>: The model determines what inputs or parameters are needed based on the user’s query and structures them in a way that the target function can understand.</li><li><strong>Call the external function or API</strong>: The model sends the generated arguments to the appropriate tool, whether it’s a database, an API, or a custom function.</li><li><strong>Process and return the results</strong>: After receiving the output from the external function, the model incorporates that information into its response, which provides more accurate, data-driven results.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mrmzZraHvPO94YNamuOb0A.png" /><figcaption>Example: Using Function Calling in a Flight Search Application</figcaption></figure><p>Function calling lays the foundation for building autonomous agents. Whether it is a customer support assistant, a research tool, or an automated DevOps bot, it enables the model to take meaningful actions on its own.</p><p>Without function calling, a language model is limited to making suggestions. It can tell you what to do or explain possible outcomes, but it cannot take action. It remains a passive advisor, which relies entirely on humans to interpret and implement its outputs.</p><p>With function calling, however, the model gains the ability to perform tasks, interact with systems, and respond to real-world inputs. It can take action, observe the results, and use that information to decide what to do next. This transforms the model from a static assistant into a dynamic, decision-making agent capable of following through on tasks and adapting as needed.</p><pre>|----------------------|--------------------------|-----------------------------|<br>| Concept              | Without Function Calling | With Function Calling       |<br>|----------------------|--------------------------|-----------------------------|<br>| Output Type          | Text only                | Text + structured calls     |<br>| Reasoning            | Verbal                   | Verbal + actionable         |<br>| Autonomy             | Passive                  | Active agent                |<br>| Use in Production    | Limited                  | Full workflows possible     |<br>|----------------------|--------------------------|-----------------------------|</pre><h3>Enhancing Agent’s Capabilities with Function Calling</h3><p>Fine-tuning a model with function calling transforms an AI agent from a passive language generator into an active, action-oriented system. This enhancement allows the agent to go beyond simply talking about tasks to executing them, such as querying databases, calling APIs, or controlling software and devices. By training on examples of tool usage, the model learns not just <em>what</em> actions to take, but <em>how</em> to format function calls correctly and respond meaningfully to tool outputs. This significantly reduces hallucinations and increases reliability.</p><p>Moreover, it enables the model to translate user intents into structured actions and interpret responses to deliver informed answers. It reduces the need for complex prompt engineering, which allows the agent to generalize more effectively, simplify implementation, and operate more efficiently in real-world workflows.</p><p>The transition from passive response generation to active task execution is enabled by defining a set of tools the agent can use. Each tool should include:</p><ul><li>A unique name</li><li>A clear description</li><li>A parameter<strong> </strong>schema defined in JSON format</li></ul><p>It should be fine-tuned on annotated function calling examples to train the model for effective tool use. This is the following structure:</p><ul><li>The user provides a query</li><li>The model generates a function call</li><li>The tool returns a result</li><li>The model then uses that result to respond appropriately</li></ul><p>Through this process, the model learns not only when to invoke a tool but also how to format the call and integrate the output into its response. This reduces reliance on hard-coded prompts and boosts the model’s generalization across tasks.</p><p>During deployment, function calling becomes part of the agent’s reasoning loop. The model:</p><ul><li>Receives the user’s input</li><li>Determines which function to call and with what parameters</li><li>Relays the function call to a backend system</li><li>Receives the function’s output</li><li>Incorporates the result into the next step of the conversation or task</li></ul><p>To support this structure, some models or frameworks allow the use of <strong><em>special tokens</em></strong> to define each stage of the interaction. These tokens are custom tokens added to the model that help in maintaining a modular and consistent workflow during multi-step reasoning.</p><p>The agent’s capabilities can be scaled by adding more tools, such as web search, document retrieval, file access, calendar management, or third-party service integration. This increases the agent’s ability to handle complex tasks across domains.</p><p>Furthermore, function calling enables <strong><em>multi-step planning</em></strong>: the agent can execute one function, evaluate its output, and determine the next step, which allows it to perform sequences of actions toward a defined goal.</p><h3>Fine-Tuning Gemma 3 for Function Calling</h3><p>We will fine-tune the <a href="https://huggingface.co/google/gemma-3-27b-it">Gemma 3 model</a>, which is instruction-tuned and has 27B parameters, with the <a href="https://huggingface.co/datasets/Salesforce/xlam-function-calling-60k">Salesforce function calling dataset</a>.</p><p><em>Let’s code!</em></p><p>To get started, we will need an A100 GPU to work with the Gemma 3 27B model. I used Google Colab Pro. Install and import the required dependencies. Set environment and seed for deterministic runs.</p><pre>!pip install -q &quot;torch&gt;=2.4.0&quot; tensorboard<br>!pip install -q flash-attn<br>!pip install -q git+https://github.com/huggingface/transformers@v4.49.0<br>!pip install -q --upgrade \<br>  datasets==3.3.2 \<br>  accelerate==1.4.0 \<br>  evaluate==0.4.3 \<br>  bitsandbytes==0.45.3 \<br>  trl==0.15.2 \<br>  peft==0.14.0 \<br>  protobuf==3.20.3 \<br>  sentencepiece</pre><pre>import torch<br>from transformers import AutoTokenizer, Gemma3ForConditionalGeneration, BitsAndBytesConfig, set_seed<br>from datasets import load_dataset<br>from trl import SFTTrainer, SFTConfig<br>from peft import LoraConfig, PeftModel, PeftConfig<br>from enum import Enum<br>import json<br>import gc<br>import os<br>os.environ[&quot;PYTORCH_CUDA_ALLOC_CONF&quot;] = &quot;expandable_segments:True&quot;<br><br>seed = 42<br>set_seed(seed)</pre><p>Then, we will select the GPU and precision.</p><pre>torch_dtype = torch.bfloat16 if torch.cuda.get_device_capability()[0] &gt;= 8 else torch.float16<br>device = torch.device(&quot;cuda&quot; if torch.cuda.is_available() else &quot;cpu&quot;)</pre><p>Next, we will load the model with QLoRA and quantization. QLoRA significantly reduces computational resource usage while preserving strong model performance. It works by first quantizing the pretrained model to 4-bit precision and freezing its original weights. Instead of updating the full model, QLoRA introduces lightweight, trainable adapter layers (via LoRA), which are the only components fine-tuned during training. After training, the adapter weights can either be merged back into the base model or kept separate for modular use.</p><p>For better model training, we will use <em>Gemma3ForConditionalGeneration</em> instead of using <em>AutoModelForCausalLM</em>.</p><pre>model_name = &quot;google/gemma-3-27b-it&quot;<br>dataset_name = &quot;Salesforce/xlam-function-calling-60k&quot;<br><br>model_kwargs = dict(<br>    attn_implementation=&quot;flash_attention_2&quot;,<br>    torch_dtype=torch_dtype,<br>    device_map=&quot;auto&quot;,<br>    quantization_config=BitsAndBytesConfig(<br>        load_in_4bit=True,<br>        bnb_4bit_use_double_quant=True,<br>        bnb_4bit_quant_type=&#39;nf4&#39;,<br>        bnb_4bit_compute_dtype=torch_dtype,<br>        bnb_4bit_quant_storage=torch_dtype,<br>        llm_int8_enable_fp32_cpu_offload=True<br>    )<br>)<br><br>model = Gemma3ForConditionalGeneration.from_pretrained(model_name, **model_kwargs)</pre><p>Now, we will define custom special tokens with the tokenizer and load the tokenizer with the chat template.</p><pre>class ChatmlSpecialTokens(str, Enum):<br>    tools = &quot;&lt;tools&gt;&quot;<br>    eotools = &quot;&lt;/tools&gt;&quot;<br>    think = &quot;&lt;think&gt;&quot;<br>    eothink = &quot;&lt;/think&gt;&quot;<br>    tool_call=&quot;&lt;tool_call&gt;&quot;<br>    eotool_call=&quot;&lt;/tool_call&gt;&quot;<br>    tool_response=&quot;&lt;tool_response&gt;&quot;<br>    eotool_response=&quot;&lt;/tool_response&gt;&quot;<br>    pad_token = &quot;&lt;pad&gt;&quot;<br>    eos_token = &quot;&lt;eos&gt;&quot;<br><br>    @classmethod<br>    def list(cls):<br>        return [c.value for c in cls]<br><br>tokenizer = AutoTokenizer.from_pretrained(<br>    model_name,<br>    pad_token=ChatmlSpecialTokens.pad_token.value,<br>    additional_special_tokens=ChatmlSpecialTokens.list()<br>)<br><br>tokenizer.chat_template = &quot;&quot;&quot;{{ bos_token }}{% if messages[0][&#39;role&#39;] == &#39;system&#39; %}{{ raise_exception(&#39;System role not supported&#39;) }}{% endif %}{% for message in messages %}{{ &#39;&lt;start_of_turn&gt;&#39; + message[&#39;role&#39;] + &#39;\n&#39; + message[&#39;content&#39;] | trim + &#39;&lt;end_of_turn&gt;&lt;eos&gt;\n&#39; }}{% endfor %}{% if add_generation_prompt %}{{&#39;&lt;start_of_turn&gt;model\n&#39;}}{% endif %}&quot;&quot;&quot;<br><br>model.resize_token_embeddings(len(tokenizer))<br>model.to(device)</pre><p>We will preprocess the dataset through the <em>preprocess</em> function to format the input. Then, we will load and transform the dataset.</p><pre>def preprocess(sample):<br>    try:<br>        tools = json.loads(sample[&quot;tools&quot;])<br>        answers = json.loads(sample[&quot;answers&quot;])<br>        user_query = sample[&quot;query&quot;]<br>    except Exception as e:<br>        print(&quot;Error decoding JSON:&quot;, sample)<br>        raise e<br><br>    messages = [<br>        {<br>            &quot;role&quot;: &quot;user&quot;,<br>            &quot;content&quot;: (<br>                &quot;You have access to the following tools:\n\n&quot;<br>                + &quot;\n\n&quot;.join(f&quot;- {tool[&#39;name&#39;]}: {tool[&#39;description&#39;]}&quot; for tool in tools)<br>                + &quot;\n\nUser query:\n&quot; + user_query<br>            )<br>        },<br>        {<br>            &quot;role&quot;: &quot;assistant&quot;,<br>            &quot;content&quot;: &quot;\n&quot;.join(<br>                f&quot;&lt;function_call&gt;\n{json.dumps(answer)}\n&lt;/function_call&gt;&quot;<br>                for answer in answers<br>            )<br>        }<br>    ]<br><br>    return {<br>        &quot;text&quot;: tokenizer.apply_chat_template(messages, add_generation_prompt=True, tokenize=False)<br>    }<br><br>dataset = load_dataset(dataset_name)<br>dataset = dataset[&quot;train&quot;].map(preprocess, remove_columns=[&quot;id&quot;, &quot;query&quot;, &quot;answers&quot;, &quot;tools&quot;])<br>dataset = dataset.train_test_split(0.1)<br>print(dataset)</pre><pre>DatasetDict({<br>    train: Dataset({<br>        features: [&#39;text&#39;],<br>        num_rows: 54000<br>    })<br>    test: Dataset({<br>        features: [&#39;text&#39;],<br>        num_rows: 6000<br>    })<br>})</pre><p>Let’s see one of the dataset’s columns.</p><pre>print(dataset[&quot;train&quot;][19][&quot;text&quot;])</pre><pre>&lt;bos&gt;&lt;start_of_turn&gt;user<br>You have access to the following tools:<br><br>- max_points_on_line: Finds the maximum number of points that lie on the same straight line.<br><br>- solve_quadratic: Computes the roots of a quadratic equation given its coefficients.<br><br>- greatest_common_divisor: Computes the greatest common divisor (GCD) of two non-negative integers.<br><br>- chi_square_independence_test: Performs a Chi-Square test for independence on a 2x2 contingency table.<br><br>- can_attend_all_meetings: Determines if a person can attend all meetings given a list of meeting time intervals.<br><br>- binomial_probability: Calculates the probability of getting exactly k successes in n independent trials,<br><br>User query:<br>What are the roots of the quadratic equation 2x^2 - 3x + 1 = 0?&lt;end_of_turn&gt;&lt;eos&gt;<br>&lt;start_of_turn&gt;assistant<br>&lt;function_call&gt;<br>{&quot;name&quot;: &quot;solve_quadratic&quot;, &quot;arguments&quot;: {&quot;a&quot;: 2, &quot;b&quot;: -3, &quot;c&quot;: 1}}<br>&lt;/function_call&gt;&lt;end_of_turn&gt;&lt;eos&gt;<br>&lt;start_of_turn&gt;model</pre><p>We will define PEFT configurations by configuring LoRA adapters to fine-tune a small subset of model parameters. This is faster, cheaper, and more memory efficient than full fine-tuning.</p><pre>peft_config = LoraConfig(<br>    lora_alpha=16,<br>    lora_dropout=0.05,<br>    r=16,<br>    bias=&quot;none&quot;,<br>    target_modules=&quot;all-linear&quot;,<br>    task_type=&quot;CAUSAL_LM&quot;,<br>    modules_to_save=[&quot;lm_head&quot;, &quot;embed_tokens&quot;] # make sure to save the lm_head and embed_tokens as you train the special tokens<br>)</pre><p>Then, we will define the training arguments.</p><pre>training_arguments = SFTConfig(<br>    output_dir=&quot;gemma-3-27b-it-thinking-function_calling-V0&quot;,<br>    per_device_train_batch_size=1,<br>    per_device_eval_batch_size=1,<br>    gradient_accumulation_steps=32,<br>    save_strategy=&quot;epoch&quot;,<br>    eval_strategy=&quot;epoch&quot;,<br>    logging_steps=50,<br>    learning_rate=3e-4,<br>    max_grad_norm=0.3,<br>    weight_decay=0.1,<br>    warmup_ratio=0.03,<br>    lr_scheduler_type=&quot;constant&quot;,<br>    report_to=None,<br>    bf16=True,<br>    optim=&quot;paged_adamw_8bit&quot;,<br>    torch_compile=False,<br>    push_to_hub=False,<br>    num_train_epochs=3,<br>    gradient_checkpointing=True,<br>    gradient_checkpointing_kwargs={&quot;use_reentrant&quot;: False},<br>    packing=False,<br>    max_seq_length=512,<br>    dataset_kwargs={<br>        &quot;add_special_tokens&quot;: False,<br>        &quot;append_concat_token&quot;: True,<br>    }<br>)</pre><p>We will clear the unused GPU memory before training to prevent OOM errors.</p><pre>torch.cuda.empty_cache()<br>torch.cuda.ipc_collect()<br>gc.collect()</pre><p>Now, we will wrap the model, tokenizer, datasets, and configurations into <em>SFTTrainer</em>. We will start fine-tuning with all the optimized settings. Then, we will save the model.</p><pre>trainer = SFTTrainer(<br>    model=model,<br>    args=training_arguments,<br>    train_dataset=dataset[&quot;train&quot;],<br>    eval_dataset=dataset[&quot;test&quot;],<br>    tokenizer=tokenizer,<br>    peft_config=peft_config,<br>)<br><br>trainer.train()<br>trainer.save_model()</pre><p>While training, a WandB API will be required. Enter the API, and see the run results on the WandB page under Overview or Workspace.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VAM5aLUUCRaK6ykPsubFog.png" /><figcaption>Run Results</figcaption></figure><p>Then, we will push the model and the tokenizer to the Hugging Face Hub.</p><pre>trainer.push_to_hub(f&quot;{username}/{output_dir}&quot;)</pre><p>Since we also modified the <em>chat_template,</em> which is contained in the tokenizer, we will push the tokenizer with the model.</p><pre>tokenizer.eos_token = &quot;&lt;eos&gt;&quot;<br>tokenizer.push_to_hub(f&quot;{username}/{output_dir}&quot;, token=True)</pre><p>We will define the PEFT model, which will serve as our trained model, and evaluate its fine-tuned performance.</p><pre>peft_model_id = f&quot;{username}/{output_dir}&quot; <br>device = &quot;auto&quot;<br>config = PeftConfig.from_pretrained(peft_model_id)<br>model = Gemma3ForConditionalGeneration.from_pretrained(&quot;google/gemma-3-27b-it&quot;,<br>                                             device_map=&quot;auto&quot;,<br>                                             )<br>tokenizer = AutoTokenizer.from_pretrained(peft_model_id)<br>model.resize_token_embeddings(len(tokenizer))<br>model = PeftModel.from_pretrained(model, peft_model_id)<br>model.to(torch.bfloat16)<br>model.eval()</pre><p>Next, we will test our model by providing it with a user query as input.</p><pre>prompt = &quot;&quot;&quot;&lt;bos&gt;&lt;start_of_turn&gt;user<br>You have access to the following tools:<br><br>- numerical_derivative: Estimate the derivative of a mathematical function<br><br>User query:<br>I need to estimate the derivative of the function y = sin(x) at x = π/4 and x = π. Can you help with that?&lt;end_of_turn&gt;&lt;eos&gt;<br>&lt;start_of_turn&gt;assistant<br>&quot;&quot;&quot;<br><br>inputs = tokenizer(prompt, return_tensors=&quot;pt&quot;, add_special_tokens=False).to(model.device)<br><br>outputs = model.generate(<br>    **inputs,<br>    max_new_tokens=256,<br>    do_sample=True,<br>    temperature=0.01,<br>    top_p=0.95,<br>    repetition_penalty=1.1,<br>    eos_token_id=tokenizer.eos_token_id<br>)<br><br>response = tokenizer.decode(outputs[0], skip_special_tokens=False)<br>print(response)</pre><p>The response is:</p><pre>&lt;bos&gt;&lt;start_of_turn&gt;user<br>You have access to the following tools:<br><br>- numerical_derivative: Estimate the derivative of a mathematical function<br><br>User query:<br>I need to estimate the derivative of the function y = sin(x) at x = π/4 and x = π. Can you help with that?&lt;end_of_turn&gt;&lt;eos&gt;<br>&lt;start_of_turn&gt;assistant<br>&lt;tool_call&gt;<br>{&#39;name&#39;: &#39;numerical_derivative&#39;, &#39;arguments&#39;: {&#39;function_name&#39;: &#39;sin&#39;, &#39;point1&#39;: 3.14159, &#39;point2&#39;: 3.14159}}<br>&lt;/tool_call&gt;&lt;end_of_turn&gt;&lt;eos&gt;</pre><p><em>The results are fascinating!</em></p><h3>Conclusion</h3><p>Fine-tuning Gemma 3 for function calling came with its challenges, especially when it came to memory management on the A100 GPU, which turned out to be a great learning opportunity. Despite the hurdles, the process was genuinely enjoyable! The test results were promising, and overall, it was a fun and insightful experience. Now it’s your turn to roll up your sleeves, experiment with different models, and explore function calling.</p><h3>References</h3><p><a href="https://huggingface.co/learn/agents-course/bonus-unit1/what-is-function-calling">Hugging Face Agents Course — Bonus Unit</a></p><p><a href="https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/function-calling#:~:text=Function%20calling%20is%20sometimes%20referred,respond%20to%20the%20user&#39;s%20prompt.">Google Cloud Documentation — Function Calling</a></p><p><a href="https://platform.openai.com/docs/guides/function-calling?api-mode=responses">OpenAI — Function Calling</a></p><p><a href="https://docs.mistral.ai/capabilities/function_calling/">Mistral — Function Calling</a></p><p><a href="https://www.promptingguide.ai/applications/function_calling">Function Calling with LLMs</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f1bc74051abe" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building an Ayurveda Healthcare Multi-PDF Agent with SingleStore and LlamaIndex]]></title>
            <link>https://medium.com/@akriti.upadhyay/building-an-ayurveda-healthcare-multi-pdf-agent-with-singlestore-and-llamaindex-22d4b69aa97c?source=rss-f6c4eb90254------2</link>
            <guid isPermaLink="false">https://medium.com/p/22d4b69aa97c</guid>
            <category><![CDATA[ayurveda]]></category>
            <category><![CDATA[llamaindex]]></category>
            <category><![CDATA[healthcare]]></category>
            <category><![CDATA[agents]]></category>
            <category><![CDATA[singlestore]]></category>
            <dc:creator><![CDATA[Akriti Upadhyay]]></dc:creator>
            <pubDate>Fri, 21 Jun 2024 13:04:38 GMT</pubDate>
            <atom:updated>2024-06-24T14:36:56.556Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*LXSki-ixGP2ydPWAolHs-g.png" /></figure><h3>Introduction</h3><p>With the advent of AI agents and RAG, the healthcare industry has undergone significant transformation. This transformation impacts various areas, including patient demographics, medical history, treatment recommendations, drug development, and more. Imagine how fascinating it would be to have an AI agent capable of providing information on proper diet, yoga, herbal remedies, and medicines. The adage <strong><em>Prevention is better than Cure</em></strong> aligns well with the principles of Ayurveda, which offers comprehensive guidance on maintaining a healthy lifestyle.</p><p>Developing AI agents and RAG applications with a single PDF document is easy, but we encounter some challenges when dealing with Multi-PDFs. To address this, we have implemented a query pipeline that optimizes retrieval using HyDE. Before delving deeper into creating an Ayurveda Healthcare Multi-PDF agent, let’s understand what HyDE is.</p><h3>An Overview of HyDE</h3><p>HyDE is a retrieval method that uses large language models to create hypothetical documents based on user queries. These documents aim to capture the essence and context of the query. Once the hypothetical documents are generated, HyDE encodes them into dense vectors using a contrastive encoder. This encoding process captures the semantic similarities between the hypothetical documents and the actual documents in the retrieval corpus. The encoded vectors of the hypothetical documents are then compared with the vectors of real documents in the corpus. The documents that show the highest similarity to the hypothetical representation of the query are retrieved and presented to the user.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*oKBVs4dHTfmPr-cinqqhfw.png" /><figcaption>Source: <a href="https://arxiv.org/pdf/2212.10496">Precise Zero-Shot Dense Retrieval without Relevance Labels</a></figcaption></figure><p>HyDE has demonstrated outstanding performance in various retrieval tasks such as web search, low-resource retrieval, and multilingual retrieval.</p><h3>Implementing Query Pipelines with HyDE on SingleStore Helios</h3><p>We will utilize <a href="https://www.singlestore.com/product-overview/">SingleStore Helios</a>, which provides a shared edition including a complimentary starter workspace for developing our production apps for free. <a href="https://www.singlestore.com/cloud-trial/?utm_source=akriti-upadhyay">Sign up</a> for the free shared tier to leverage the starter workspace.</p><p>The starter workspace contains one attached database. In SingleStore Helios, we can utilize <a href="https://docs.singlestore.com/cloud/developer-resources/notebooks/">Notebooks </a>and <a href="https://docs.singlestore.com/cloud/developer-resources/secrets/">Secrets</a> without installing the SingleStore library. We can secure outbound access to our notebooks using the Firewall by adding the external endpoint.</p><p><em>Let’s code!</em></p><p>To get started, create a notebook in Notebooks under the Develop page in the cloud portal (SingleStore Helios). Install and import the required dependencies.</p><pre>!pip install -q llama-index<br>!pip install -q pyvis<br>!pip install -q llama-index-embeddings-huggingface<br>!pip install -q llama-index-llms-openai<br>!pip install -q -U llama-index-vector-stores-singlestoredb</pre><pre>import logging<br>import sys<br>from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, StorageContext, load_index_from_storage<br>from llama_index.core.indices.query.query_transform import HyDEQueryTransform<br>from llama_index.core.node_parser.text import SentenceSplitter<br>from llama_index.embeddings.huggingface import HuggingFaceEmbedding<br>from llama_index.llms.openai import OpenAI<br>from llama_index.core.query_engine import TransformQueryEngine<br>from IPython.display import Markdown, display<br>from llama_index.vector_stores.singlestoredb import SingleStoreVectorStore<br>from llama_index.core.tools import QueryEngineTool, ToolMetadata, BaseTool<br>from llama_index.core.settings import Settings<br>from llama_index.core.callbacks import CallbackManager<br>from llama_index.core.agent.react.types import (<br>    ActionReasoningStep,<br>    ObservationReasoningStep,<br>    ResponseReasoningStep,<br>)<br>from llama_index.core.agent import Task, AgentChatResponse, ReActChatFormatter, QueryPipelineAgentWorker<br>from llama_index.core.query_pipeline import (<br>    AgentInputComponent,<br>    AgentFnComponent,<br>    CustomAgentComponent,<br>    QueryComponent,<br>    ToolRunnerComponent,<br>    InputComponent,<br>    Link,<br>    QueryPipeline <br>)<br>from llama_index.core.llms import MessageRole, ChatMessage, ChatResponse<br>from typing import Dict, Any, Optional, Tuple, List, Set, cast<br>from singlestoredb.management import get_secret<br>from sqlalchemy import *<br>from pyvis.network import Network<br>from IPython.display import display, HTML<br><br>logging.basicConfig(stream=sys.stdout, level=logging.INFO)<br>logging.getLogger().addHandler(logging.StreamHandler(stream=sys.stdout))<br><br>callback_manager = CallbackManager()<br>Settings.callback_manager = callback_manager</pre><p>To create an Ayurveda Healthcare Multi-PDF agent, I gathered 40 Ayurveda ebooks and utilized my GitHub repository to import the data into the SingleStore Notebooks.</p><pre>!git clone &lt;link_to_github_repo&gt;</pre><p>To work with SingleStore, the first step is to get the connection information. The connection information consists of the username, password, database name, host, and port, which can be obtained from any of the clients while connecting to the starter workspace.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hmTfApRHRpiqjgKhFGS9Fg.png" /></figure><p>I accessed this information from the SQL IDE.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0t8dYHOjEeIHmNIO66C2nw.png" /></figure><p>We can save that information in Secrets. Along with this information, we should also save the OpenAI API key, as we are going to utilize the OpenAI model GPT-4.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iFAD7vKnxq6t5WTv2ZLI2A.png" /></figure><p>Let’s retrieve the secrets.</p><pre>user = get_secret(&#39;user&#39;)<br>password = get_secret(&#39;password&#39;)<br>host = get_secret(&#39;host&#39;)<br>database = get_secret(&#39;database&#39;)<br>openai = get_secret(&#39;openai&#39;)</pre><p>Now, we will initiate the vector store using the information saved in the Secrets.</p><pre>vector_store = SingleStoreVectorStore(<br>    table_name=&quot;embeddings&quot;,<br>    content_field=&quot;content&quot;,<br>    metadata_field=&quot;metadata&quot;,<br>    vector_field=&quot;vector&quot;,<br>    host = host,<br>    port = &quot;3333&quot;,<br>    database = database,<br>    user = user,<br>    password = password,<br>)</pre><p>We will store the vector in the storage context because we will use it to create the vector index.</p><pre>storage_context = StorageContext.from_defaults(vector_store=vector_store)</pre><p>Next, we will create embeddings, which will be required to create the vector store index.</p><pre>embed_model = HuggingFaceEmbedding()<br><br>Settings.embed_model = embed_model</pre><p>As we have 40 PDFs, we will load them and generate indices for each in a dictionary format. The indices will be generated after creating a vector store index. The vector store index will use nodes, storage context, and the sentence splitter as transformations.</p><pre><br><br>pdf_directory = &quot;./AyurvedicData&quot;<br><br>pdf_files = [file for file in os.listdir(pdf_directory) if file.endswith(&#39;.pdf&#39;)]<br><br>storage_base_dir = &quot;./storage&quot;<br>Settings.transformations = [SentenceSplitter(chunk_size=1024)]<br><br>def generate_storage_dir(file_name):<br>    base_name = os.path.splitext(file_name)[0]  # Remove extension<br>    safe_name = base_name.replace(&#39; &#39;, &#39;_&#39;).replace(&#39;&amp;&#39;, &#39;and&#39;)<br>    return os.path.join(storage_base_dir, safe_name)<br><br>all_indices_loaded = True<br><br>indices = {}<br><br>for pdf_file in pdf_files:<br>    try:<br>        storage_dir = generate_storage_dir(pdf_file)<br>        storage_context = StorageContext.from_defaults(persist_dir=storage_dir)<br>        index = load_index_from_storage(storage_context)<br>        indices[pdf_file] = index<br>    except Exception as e:<br>        print(f&quot;Failed to load index for {pdf_file}: {e}&quot;)<br>        all_indices_loaded = False<br><br>if not all_indices_loaded:<br>    for pdf_file in pdf_files:<br>        if pdf_file not in indices:  <br>            try:<br>                input_path = os.path.join(pdf_directory, pdf_file)<br>                docs = SimpleDirectoryReader(input_files=[input_path]).load_data()<br>                <br>                text_parser = SentenceSplitter(chunk_size=1024)<br>                text_chunks = []<br>                doc_idxs = []<br><br>                for doc_idx, doc in enumerate(docs):<br>                    cur_text_chunks = text_parser.split_text(doc.text)<br>                    text_chunks.extend(cur_text_chunks)<br>                    doc_idxs.extend([doc_idx] * len(cur_text_chunks))<br><br>                from llama_index.core.schema import TextNode<br>                nodes = []<br>                for idx, text_chunk in enumerate(text_chunks):<br>                    node = TextNode(text=text_chunk)<br>                    src_doc = docs[doc_idxs[idx]]<br>                    node.metadata = src_doc.metadata<br>                    nodes.append(node)<br>                <br>                vectorstoreindex = VectorStoreIndex(nodes = nodes, storage_context=storage_context,transformations=Settings.transformations,)<br>                index = vectorstoreindex.from_documents(docs)<br>                <br>                storage_dir = generate_storage_dir(pdf_file)<br>                index.storage_context.persist(persist_dir=storage_dir)<br>                <br>                indices[pdf_file] = index<br>            except Exception as e:<br>                print(f&quot;Failed to process {pdf_file}: {e}&quot;)</pre><p>Now, the <em>indices</em> variable contains all the loaded or newly created indices. We will initialize LLM after creating the indices. In this process, we are utilizing OpenAI&#39;s GPT-3.5.</p><pre>llm = OpenAI(model=&quot;gpt-3.5-turbo&quot;)<br>Settings.llm = llm</pre><p>For each item in indices, we will create HyDE query engines.</p><pre>query_engines={}<br><br>for pdf_name, index in indices.items():<br>    try:<br>        query_engine = index.as_query_engine(similarity_top_k=3)<br>        <br>        hyde = HyDEQueryTransform(include_original=True)<br>        <br>        hyde_query_engine = TransformQueryEngine(query_engine, hyde)<br>        <br>        query_engines[pdf_name] = hyde_query_engine<br>        <br>        print(f&quot;HyDE query engine created for {pdf_name}&quot;)<br><br>    except Exception as e:<br>        print(f&quot;An error occurred while creating query engine for {pdf_name}: {e}&quot;)</pre><p>For each index, we will instantiate a <em>QueryEngineTool </em>using HyDE query engines.</p><pre><br>query_engine_tools = []<br><br>for pdf_name, hyde_query_engine in query_engines.items():<br>    try:<br>        description = &quot;Provides information about improving lifestyle, diet, and medicinal benefits using Ayurveda. Use a detailed plain text question as input to the tool.&quot;<br>        <br>        metadata = ToolMetadata(<br>            name=pdf_name.replace(&quot;.pdf&quot;, &quot;&quot;).replace(&quot; &quot;, &quot;_&quot;).lower(),<br>            description=description<br>        )<br>        <br>        tool = QueryEngineTool(<br>            query_engine=hyde_query_engine,<br>            metadata=metadata<br>        )<br>        <br>        query_engine_tools.append(tool)<br>        <br>        print(f&quot;QueryEngineTool created for {pdf_name}&quot;)<br>    <br>    except Exception as e:<br>        print(f&quot;An error occurred while creating QueryEngineTool for {pdf_name}: {e}&quot;)</pre><p>We will now initiate the agent input component.</p><pre>def agent_input_fn(task: Task, state: Dict[str, Any]) -&gt; Dict[str, Any]:<br>    &quot;&quot;&quot;Agent input function.<br><br>    Returns:<br>        A Dictionary of output keys and values. If you are specifying<br>        src_key when defining links between this component and other<br>        components, make sure the src_key matches the specified output_key.<br><br>    &quot;&quot;&quot;<br>    if &quot;current_reasoning&quot; not in state:<br>        state[&quot;current_reasoning&quot;] = []<br>    reasoning_step = ObservationReasoningStep(observation=task.input)<br>    state[&quot;current_reasoning&quot;].append(reasoning_step)<br>    return {&quot;input&quot;: task.input}<br><br><br>agent_input_component = AgentInputComponent(fn=agent_input_fn)</pre><p>We defined the agent component that is responsible for creating a ReAct prompt. After the LLM generates the output, it is parsed into a structured object. When input is received, the LLM is called upon with the ReAct agent prompt. Using the <em>Chain-Of-Thought + Acting</em> method we will define the ReAct Prompt component.</p><pre>def react_prompt_fn(<br>    task: Task, state: Dict[str, Any], input: str, tools: List[BaseTool]<br>) -&gt; List[ChatMessage]:<br>    chat_formatter = ReActChatFormatter()<br>    return chat_formatter.format(<br>        tools,<br>        chat_history=task.memory.get() + state[&quot;memory&quot;].get_all(),<br>        current_reasoning=state[&quot;current_reasoning&quot;],<br>    )<br><br><br>react_prompt_component = AgentFnComponent(<br>    fn=react_prompt_fn, partial_dict={&quot;tools&quot;: query_engine_tools}<br>)</pre><p>After the LLM produces an output, we follow a decision tree process:</p><ul><li>If an answer is generated, we directly process the output.</li><li>However, if an action is specified, we execute the designated tool with the specified arguments and then process the resulting output.</li></ul><p>To process the agent’s response, we will define some functions which will ultimately follow the decision tree process.</p><pre>def parse_react_output_fn(<br>    task: Task, state: Dict[str, Any], chat_response: ChatResponse<br>):<br>    &quot;&quot;&quot;Parse ReAct output into a reasoning step.&quot;&quot;&quot;<br>    output_parser = ReActOutputParser()<br>    reasoning_step = output_parser.parse(chat_response.message.content)<br>    return {&quot;done&quot;: reasoning_step.is_done, &quot;reasoning_step&quot;: reasoning_step}<br><br><br>parse_react_output = AgentFnComponent(fn=parse_react_output_fn)<br><br><br>def run_tool_fn(<br>    task: Task, state: Dict[str, Any], reasoning_step: ActionReasoningStep<br>):<br>    &quot;&quot;&quot;Run tool and process tool output.&quot;&quot;&quot;<br>    tool_runner_component = ToolRunnerComponent(<br>        query_engine_tools, callback_manager=task.callback_manager<br>    )<br>    tool_output = tool_runner_component.run_component(<br>        tool_name=reasoning_step.action,<br>        tool_input=reasoning_step.action_input,<br>    )<br>    observation_step = ObservationReasoningStep(observation=str(tool_output))<br>    state[&quot;current_reasoning&quot;].append(observation_step)<br><br>    return {&quot;response_str&quot;: observation_step.get_content(), &quot;is_done&quot;: False}<br><br><br>run_tool = AgentFnComponent(fn=run_tool_fn)<br><br><br>def process_response_fn(<br>    task: Task, state: Dict[str, Any], response_step: ResponseReasoningStep<br>):<br>    &quot;&quot;&quot;Process response.&quot;&quot;&quot;<br>    state[&quot;current_reasoning&quot;].append(response_step)<br>    response_str = response_step.response<br>    state[&quot;memory&quot;].put(ChatMessage(content=task.input, role=MessageRole.USER))<br>    state[&quot;memory&quot;].put(<br>        ChatMessage(content=response_str, role=MessageRole.ASSISTANT)<br>    )<br><br>    return {&quot;response_str&quot;: response_str, &quot;is_done&quot;: True}<br><br><br>process_response = AgentFnComponent(fn=process_response_fn)<br><br><br>def process_agent_response_fn(<br>    task: Task, state: Dict[str, Any], response_dict: dict<br>):<br>    &quot;&quot;&quot;Process agent response.&quot;&quot;&quot;<br>    return (<br>        AgentChatResponse(response_dict[&quot;response_str&quot;]),<br>        response_dict[&quot;is_done&quot;],<br>    )<br><br><br>process_agent_response = AgentFnComponent(fn=process_agent_response_fn)</pre><p>Now, we will create a query pipeline, where we will add the created components as modules. We will add a chain and links to the query pipeline.</p><pre>qp = QueryPipeline(verbose=True)<br><br>qp.add_modules(<br>    {<br>        &quot;agent_input&quot;: agent_input_component,<br>        &quot;react_prompt&quot;: react_prompt_component,<br>        &quot;llm&quot;: llm,<br>        &quot;react_output_parser&quot;: parse_react_output,<br>        &quot;run_tool&quot;: run_tool,<br>        &quot;process_response&quot;: process_response,<br>        &quot;process_agent_response&quot;: process_agent_response,<br>    }<br>)<br><br>qp.add_chain([&quot;agent_input&quot;, &quot;react_prompt&quot;, &quot;llm&quot;, &quot;react_output_parser&quot;])<br><br>qp.add_link(<br>    &quot;react_output_parser&quot;,<br>    &quot;run_tool&quot;,<br>    condition_fn=lambda x: not x[&quot;done&quot;],<br>    input_fn=lambda x: x[&quot;reasoning_step&quot;],<br>)<br>qp.add_link(<br>    &quot;react_output_parser&quot;,<br>    &quot;process_response&quot;,<br>    condition_fn=lambda x: x[&quot;done&quot;],<br>    input_fn=lambda x: x[&quot;reasoning_step&quot;],<br>)<br><br>qp.add_link(&quot;process_response&quot;, &quot;process_agent_response&quot;)<br>qp.add_link(&quot;run_tool&quot;, &quot;process_agent_response&quot;)</pre><p>To visualize the query pipeline, we will use <em>Network </em>from the <em>Pyvis </em>library.</p><pre>net = Network(notebook=True, cdn_resources=&quot;in_line&quot;, directed=True)<br>net.from_nx(qp.clean_dag)<br>print(net)</pre><p>The following will be the resultant pipeline.</p><pre>{<br>    &quot;Nodes&quot;: [<br>        &quot;agent_input&quot;,<br>        &quot;react_prompt&quot;,<br>        &quot;llm&quot;,<br>        &quot;react_output_parser&quot;,<br>        &quot;run_tool&quot;,<br>        &quot;process_response&quot;,<br>        &quot;process_agent_response&quot;<br>    ],<br>    &quot;Edges&quot;: [<br>        {<br>            &quot;src_key&quot;: null,<br>            &quot;dest_key&quot;: null,<br>            &quot;condition_fn&quot;: null,<br>            &quot;input_fn&quot;: null,<br>            &quot;width&quot;: 1,<br>            &quot;from&quot;: &quot;agent_input&quot;,<br>            &quot;to&quot;: &quot;react_prompt&quot;,<br>            &quot;arrows&quot;: &quot;to&quot;<br>        },<br>        {<br>            &quot;src_key&quot;: null,<br>            &quot;dest_key&quot;: null,<br>            &quot;condition_fn&quot;: null,<br>            &quot;input_fn&quot;: null,<br>            &quot;width&quot;: 1,<br>            &quot;from&quot;: &quot;react_prompt&quot;,<br>            &quot;to&quot;: &quot;llm&quot;,<br>            &quot;arrows&quot;: &quot;to&quot;<br>        },<br>        {<br>            &quot;src_key&quot;: null,<br>            &quot;dest_key&quot;: null,<br>            &quot;condition_fn&quot;: null,<br>            &quot;input_fn&quot;: null,<br>            &quot;width&quot;: 1,<br>            &quot;from&quot;: &quot;llm&quot;,<br>            &quot;to&quot;: &quot;react_output_parser&quot;,<br>            &quot;arrows&quot;: &quot;to&quot;<br>        },<br>        {<br>            &quot;src_key&quot;: null,<br>            &quot;dest_key&quot;: null,<br>            &quot;width&quot;: 1,<br>            &quot;from&quot;: &quot;react_output_parser&quot;,<br>            &quot;to&quot;: &quot;run_tool&quot;,<br>            &quot;arrows&quot;: &quot;to&quot;<br>        },<br>        {<br>            &quot;src_key&quot;: null,<br>            &quot;dest_key&quot;: null,<br>            &quot;width&quot;: 1,<br>            &quot;from&quot;: &quot;react_output_parser&quot;,<br>            &quot;to&quot;: &quot;process_response&quot;,<br>            &quot;arrows&quot;: &quot;to&quot;<br>        },<br>        {<br>            &quot;src_key&quot;: null,<br>            &quot;dest_key&quot;: null,<br>            &quot;condition_fn&quot;: null,<br>            &quot;input_fn&quot;: null,<br>            &quot;width&quot;: 1,<br>            &quot;from&quot;: &quot;run_tool&quot;,<br>            &quot;to&quot;: &quot;process_agent_response&quot;,<br>            &quot;arrows&quot;: &quot;to&quot;<br>        },<br>        {<br>            &quot;src_key&quot;: null,<br>            &quot;dest_key&quot;: null,<br>            &quot;condition_fn&quot;: null,<br>            &quot;input_fn&quot;: null,<br>            &quot;width&quot;: 1,<br>            &quot;from&quot;: &quot;process_response&quot;,<br>            &quot;to&quot;: &quot;process_agent_response&quot;,<br>            &quot;arrows&quot;: &quot;to&quot;<br>        }<br>    ],<br>    &quot;Height&quot;: &quot;600px&quot;,<br>    &quot;Width&quot;: &quot;100%&quot;,<br>    &quot;Heading&quot;: &quot;&quot;<br>}</pre><p>We will save the network as an HTML file and display the content.</p><pre>net.write_html(&quot;agent.html&quot;)<br><br>with open(&quot;agent.html&quot;, &quot;r&quot;) as file:<br>    html_content = file.read()<br><br>display(HTML(html_content))</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/573/1*GFBlxQ2bz1AM1A3gTjGmag.png" /><figcaption>Query Pipeline</figcaption></figure><p>The next step is to set up the agent worker around the query engines.</p><pre>agent_worker = QueryPipelineAgentWorker(qp)<br>agent = agent_worker.as_agent(<br>    callback_manager=CallbackManager([]), verbose=True<br>)</pre><p>We will create the task with the agent and ask questions.</p><pre><br>task = agent.create_task(<br>    &quot;What are ayurvedic treatments and prevention of migraine?&quot;<br>)<br><br>step_output = agent.run_step(task.task_id)<br>print(step_output)</pre><p>The agent will give the following answer:</p><blockquote>In Ayurveda, the treatment and prevention of migraines focus on restoring balance among the body’s doshas, particularly Vata and Kapha. Preventative measures include avoiding daytime sleep, protecting oneself from cold, especially in the mornings, and managing allergic conditions promptly. It also emphasizes dietary restrictions, such as avoiding yogurt, greasy foods, and the combination of milk with acidic foods or fish. Treatment involves the use of herbal remedies to dilate capillaries, reduce fluid exudation, and promote fluid filtration. Key herbs and compounds, such as Guggulu for capillary dilation, Vachadi for drying exudation, and Pippalishrita for inducing cleansing sneezing, are employed. Additionally, remedies like Shirashularivajrarasa and Sadbindutaila are used to restore the coordination between the nervous, arterial, and venous systems, essential for relieving and preventing migraine attacks.</blockquote><p>Let’s try another question.</p><pre>task = agent.create_task(<br>    &quot;What dosha does the person have if his skin is dry and thin, and he also has joint pains?&quot;<br>)<br><br>step_output = agent.run_step(task.task_id)<br>print(step_output)</pre><p>The agent will give the following answer:</p><blockquote>If a person has dry and thin skin along with joint pains, it indicates an imbalance in the Vata dosha. Vata governs all movement and is associated with dryness and coldness in the body. When Vata is out of balance, it can lead to symptoms such as dry, rough skin and discomfort in the joints, manifesting as pain or stiffness. These characteristics are typical signs of elevated Vata that require balancing to restore harmony in the body and alleviate the symptoms.</blockquote><h3>Conclusion</h3><p>I found it interesting to use the SingleStore vector database within SingleStore Notebooks to build an Ayurvedic healthcare multi-PDF agent. The <a href="https://www.singlestore.com/cloud-trial/?utm_source=akriti-upadhyay">free shared tier</a> is easy to use and we saw that it can handle 40 ebooks. It is also easy to transition this application to a production environment with the SingleStore free shared tier.</p><p>Thanks for reading!</p><h3>References</h3><p><a href="https://docs.llamaindex.ai/en/latest/examples/agent/agent_runner/agent_around_query_pipeline_with_HyDE_for_PDFs/">Agent around query pipeline with HyDE for PDFs</a></p><p><a href="https://docs.llamaindex.ai/en/stable/api_reference/storage/vector_store/singlestoredb/">LlamaIndex with SingleStoreDB</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=22d4b69aa97c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Text-to-SQL Using SingleStore Helios, Groq, and Llama 3]]></title>
            <link>https://medium.com/@akriti.upadhyay/text-to-sql-using-singlestore-helios-groq-and-llama-3-0ebe1150cbe2?source=rss-f6c4eb90254------2</link>
            <guid isPermaLink="false">https://medium.com/p/0ebe1150cbe2</guid>
            <category><![CDATA[groq]]></category>
            <category><![CDATA[singlestore]]></category>
            <category><![CDATA[llama-3]]></category>
            <category><![CDATA[text-to-sql]]></category>
            <category><![CDATA[llamaindex]]></category>
            <dc:creator><![CDATA[Akriti Upadhyay]]></dc:creator>
            <pubDate>Tue, 28 May 2024 03:12:48 GMT</pubDate>
            <atom:updated>2024-05-29T04:50:03.130Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/919/1*GUWdh-pFDnKviT7YZdQkbA.png" /></figure><h3><strong>Introduction</strong></h3><p>With the day-to-day advancements in large language models, retrieving SQL results has become easier. It has eliminated the need to enter SQL statements manually each time. While the traditional method of using SQL statements to interact with databases was effective, the advanced capabilities of LLMs have made SQL retrieval even more efficient and interesting.</p><p>Text-to-SQL has revolutionized our interaction with databases. As advanced language models continue to progress, new methods are also emerging. Before delving into the tools featured in this blog, let’s first grasp the concept of text-to-SQL.</p><p><em>Let’s get started!</em></p><h3>What is Text-to-SQL?</h3><p>Text-to-SQL is the task of translating a user’s natural language question into a valid SQL query that can be executed over a database. This process allows users, who may not have expertise in SQL or an understanding of the database’s structure, to interact with the database using natural language. For example, a user might ask a question about financial transactions in plain English, and text-to-SQL would convert this question into an SQL query that retrieves the desired information from the database. This capability has attracted significant attention from both the database and natural language processing communities, as it bridges the gap between user-friendly language and complex database queries.</p><p>Now that we understand text-to-SQL, let’s learn how to implement it using the tools we will use.</p><h3>Implementing Text-to-SQL with SingleStore Helios</h3><p>In this implementation, we will use the LlamaIndex framework, Groq, and Llama 3 model in the SingleStore Helios platform. Let’s find out what SingleStore Helios is.</p><h4>SingleStore Helios</h4><p>SingleStore Helios is a cloud database-as-a-service that provides elastic scalability, high availability, and excellent price performance for applications on leading public clouds. It separates storage from compute, enables independent scaling, and incorporates features such as Jupyter notebooks, data integration services, and a compute service for AI workloads. It supports low latency, high concurrency, and fast data ingestion from multiple sources, with horizontal scalability and workspace capabilities for independent compute scaling.</p><p>As a fully multi-cloud database, it gives users complete control over deployment across various cloud platforms by avoiding vendor lock-in. It simplifies application architecture with its SQL compatibility, extensive connector support, multi-model data handling, and API-driven workflows. It ensures secure and efficient database management for enterprise applications through robust security protocols and compliance with industry standards. For more information, visit its <a href="https://docs.singlestore.com/">documentation</a>.</p><p>Let’s plug into SingleStore Helios by <a href="https://www.singlestore.com/cloud-trial/">signing up</a> for a free trial. There are two editions of workspace available in a free trial:</p><ul><li><strong>Starter Workspace:</strong> When you sign up, you will receive a starter workspace with an attached database.</li><li><strong>Standard Workspace:</strong> When you register, you will receive $600 in credits, which you can earn in 5 learning stages. You can utilize your earned credits in the standard workspace.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/357/1*lfuSnyPq0ZFo1vz5sl65VQ.png" /></figure><h4>Integrating Groq, Llama 3, and LlamaIndex with SingleStore Helios</h4><p>While creating a text-to-SQL application, having your database and notebook on a single platform is compatible. SingleStore Helios provides such an interface, which allows you to ingest your data into the database without creating a pipeline and work with it directly in your notebooks.</p><p>To start, create a workspace by selecting <strong><em>+Group</em></strong> in the left navigation panel.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*uIqq0fbYE3mSwtt8BYSUiw.png" /><figcaption>Create Workspace</figcaption></figure><p>Using your free trial credits, you can create a standard workspace.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CpKLoe20vRgrcwIl3mNxPg.png" /><figcaption>Workspace Details</figcaption></figure><p>To know more about how to create a workspace, visit <a href="https://docs.singlestore.com/cloud/getting-started-with-singlestore-helios/about-workspaces/creating-and-using-workspaces/">here</a>. After creating your workspace, it will begin deploying and may take a few minutes to complete.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GMcT_WKEu63IqGyennjF0A.png" /></figure><p>Once the deployment is complete, create a database.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/612/1*6Uw0PbrlLZDpAdFgFjdmCA.png" /></figure><p>For our text-to-SQL application, we will use the <a href="https://www.kaggle.com/datasets/equinxx/stock-tweets-for-sentiment-analysis-and-prediction?resource=download&amp;select=stock_tweets.csv">Stock Tweets dataset</a> from Kaggle. To load the dataset in your <strong><em>Stocks</em></strong> database, there is no need to create a pipeline. Click on the <a href="https://docs.singlestore.com/cloud/developer-resources/stage-storage-service/"><strong><em>Stage</em></strong></a> in the left navigation panel.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/355/1*yPDjKQ1_oZj45KNKJZUAxw.png" /></figure><p>Upload the CSV files.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/605/1*IRGysANifiLjpwECcxD3ZA.png" /></figure><p>Load the CSV files one by one to the created database.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5rtd36aaCFWYepKJZ5ELXA.png" /></figure><p>Generate a notebook.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tkwyYS_N5a664_llov2tMQ.png" /></figure><p>Execute the cells of the notebook after verifying the column names.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*X6wuu4ReXTKRfFStdfOBUQ.png" /></figure><p>Our data will be stored by creating a table in the <strong><em>Stocks</em></strong> database. This way both of the CSV files will be ingested in the created database.</p><p>Now that our data has been ingested into the database, we can begin building the text-to-SQL application. To create a notebook, select <strong><em>Develop</em></strong> from the left navigation panel.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YsrctU_WvrI2k6I5PCqN-w.png" /><figcaption>Develop</figcaption></figure><p>After creating a notebook, it is time to start coding!</p><p>Before rolling our sleeves up, let’s install and import the required dependencies.</p><pre>!pip install -q llama-index matplotlib<br>!pip install -q llama-index-llms-groq<br>!pip install -q llama-index-embeddings-huggingface</pre><pre># Import nest_asyncio to allow nested event loops<br>import nest_asyncio<br>nest_asyncio.apply()<br><br># Access the secret in the SingleStore notebook<br>from singlestoredb.management import get_secret<br><br># Import necessary libraries and modules<br>from llama_index.llms.groq import Groq  # Import Groq from llama_index for Text-to-SQL processing<br>from llama_index.core import Settings<br>from llama_index.embeddings.huggingface import HuggingFaceEmbedding # Import Hugging Face embedding model<br>from sqlalchemy import *  # Import SQLAlchemy for database interaction<br>from llama_index.core import SQLDatabase  # Import SQLDatabase for handling database operations<br>from llama_index.core.indices.struct_store import NLSQLTableQueryEngine  # Import engine for NL to SQL query processing<br>from llama_index.core.indices.struct_store.sql_query import (<br>    SQLTableRetrieverQueryEngine,  # Import query engine for SQL table retrieval<br>)<br>from llama_index.core.objects import (<br>    SQLTableNodeMapping,  # Import mapping for SQL table nodes<br>    ObjectIndex,  # Import ObjectIndex for indexing database objects<br>    SQLTableSchema,  # Import schema definition for SQL tables<br>)<br>from llama_index.core import VectorStoreIndex  # Import VectorStoreIndex for indexing vectors<br>from llama_index.core.retrievers import NLSQLRetriever  # Import retriever for NL to SQL conversion<br>from llama_index.core.response.notebook_utils import display_source_node  # Import utility to display source nodes in notebooks<br>from llama_index.core.query_engine import RetrieverQueryEngine  # Import general query engine for data retrieval<br></pre><p>With Groq, it is easy to load models. To work with Groq, create an API key on <a href="https://console.groq.com/keys">Groq Cloud</a>. You can save the API key in <a href="https://docs.singlestore.com/cloud/developer-resources/secrets/"><strong><em>Secrets</em></strong></a><strong><em> </em></strong>under<strong><em> </em></strong>the<strong><em> Develop </em></strong>section.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WRj72duPTRAy2IBfO6gXgw.png" /></figure><pre>secret = get_secret(&#39;groq&#39;)</pre><p>Set the model as <a href="https://huggingface.co/meta-llama/Meta-Llama-3-8B">Llama 3 8B</a>.</p><pre>llm = Groq(model=&quot;llama3–8b-8192&quot;, api_key = secret)</pre><p>With LLM, it is important to set the embedding model, because the <em>NLSQLTableQueryEngine</em> takes the embed model as OpenAI embedding model as default. Here we are using the Hugging Face embedding model.</p><pre>embed_model = HuggingFaceEmbedding(model_name=&quot;BAAI/bge-small-en-v1.5&quot;)<br>Settings.llm = llm<br>Settings.embed_model = embed_model</pre><p>For implementing text-to-SQL, an engine connection is required. To connect with the SingleStore engine, navigate to your workspace and click on <strong><em>Connect Directly</em></strong>. You will find this information in your <strong><em>SQL IDE</em></strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Kw_U_1xzaG1pd4iLN7jTlg.png" /></figure><p>If you forgot your password, you can reset it by visiting <strong><em>Access</em></strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tQcc1Ix0ZWVUhx81nj3E3Q.png" /></figure><p>After the setup, let’s connect the engine.</p><pre>engine = create_engine(&quot;singlestoredb://&quot;+&quot;admin&quot;+&quot;:&quot;+&quot;Password123&quot;+&quot;@&quot;+&quot;svc-998ada03–1742–45c8–924f-b8a15f4a4a75-dml.aws-virginia-5.svc.singlestore.com&quot;+&quot;:&quot;+&quot;3306&quot;+&quot;/&quot;+&quot;Stocks&quot;)<br>sql_database = SQLDatabase(engine)</pre><p>We have set up the SQL database and can use the <em>NLSQLTableQueryEngine</em> to create natural language queries, which will then be translated into SQL queries.</p><pre># Initialize the NLSQLTableQueryEngine with the specified SQL database, tables, and language model<br>query_engine = NLSQLTableQueryEngine(<br> sql_database=sql_database, # The SQL database instance to query<br> tables=[&quot;stock_tweets&quot;, &quot;stock_yfinance_data&quot;], # List of tables to include in the query engine<br> llm=llm, # The language model used for processing natural language queries<br>)</pre><p><em>Let’s query!</em></p><pre>response = query_engine.query(&quot;What is current tweet of TSLA stock name? Also, tell the date.&quot;)<br>print(response)</pre><p>The response will be:</p><blockquote>Here is the synthesized response:</blockquote><blockquote>“The current tweet about TSLA stock is: ‘Mainstream media has done an amazing job at brainwashing people. Today at work, we were asked what companies we believe in &amp;amp; I said <a href="http://twitter.com/Tesla">@Tesla</a> because they make the safest cars &amp;amp; EVERYONE disagreed with me because they heard“they catch on fire &amp;amp; the batteries cost 20k to replace”’. This tweet was posted on September 29th, 2022 at 11:41 PM.”</blockquote><p>If we are uncertain about which table we will need ahead of time, and if the total size of the table schema is larger than the context window size, we should store the table schema in an index. This will enable us to retrieve the correct schema during query time.</p><p>To do this, we can utilize the <em>SQLTableNodeMapping</em> object, which takes an SQL database and generates a <em>Node</em> object for each <em>SQLTableSchema</em> object passed into the <em>ObjectIndex</em> constructor.</p><pre># Initialize the SQLTableNodeMapping with the sql_database<br>table_node_mapping = SQLTableNodeMapping(sql_database)<br># Define table schemas<br>table_schema_objs = [<br> SQLTableSchema(table_name=&quot;stock_tweets&quot;),<br> SQLTableSchema(table_name=&quot;stock_yfinance_data&quot;)<br>]<br># Create the ObjectIndex from the schema objects and node mapping<br>obj_index = ObjectIndex.from_objects(<br> table_schema_objs,<br> table_node_mapping,<br> VectorStoreIndex,<br>)<br># Initialize the SQLTableRetrieverQueryEngine<br>query_engine = SQLTableRetrieverQueryEngine(<br> sql_database, obj_index.as_retriever(similarity_top_k=1)<br>)</pre><p><em>Let’s try this query engine!</em></p><pre>response = query_engine.query(&quot;What is current tweet of TSLA stock name? Also, tell the date.&quot;)<br>print(response)</pre><p>The response will be:</p><blockquote>Here is the synthesized response:</blockquote><blockquote>“The current tweet about TSLA stock is: ‘Mainstream media has done an amazing job at brainwashing people. Today at work, we were asked what companies we believe in &amp;amp; I said <a href="http://twitter.com/Tesla">@Tesla</a> because they make the safest cars &amp;amp; EVERYONE disagreed with me because they heard“they catch on fire &amp;amp; the batteries cost 20k to replace”’. This tweet was posted on September 29th, 2022 at 23:41:16 UTC.”</blockquote><p>The response from both query engines is similar, but there is a slight difference in the time in the response.</p><p>Let’s see its metadata.</p><pre>response.metadata[&quot;result&quot;]</pre><p>Here’s the metadata:</p><blockquote>[(‘2022–09–29 23:41:16+00:00’, ‘Mainstream media has done an amazing job at brainwashing people. Today at work, we were asked what companies we believe in &amp;amp; I said <a href="http://twitter.com/Tesla">@Tesla</a> because they make the safest cars &amp;amp; EVERYONE disagreed with me because they heard“they catch on fire &amp;amp; the batteries cost 20k to replace”’)]</blockquote><p>Our text-to-SQL capability is currently encapsulated in a query engine that handles both retrieval and synthesis. You can use the SQL retriever independently. Now we will integrate it into <em>RetrieverQueryEngine</em> to achieve similar results with nodes.</p><pre>nl_sql_retriever = NLSQLRetriever(<br> sql_database, tables=[&quot;stock_tweets&quot;,&quot;stock_yfinance_data&quot;], return_raw=True<br>)<br><br>results = nl_sql_retriever.retrieve(<br>    &quot;Return the top 5 stocks (along with their company names) with the highest volume.&quot;<br>)<br><br>for n in results:<br>    display_source_node(n)</pre><p>These are the source nodes:</p><blockquote><strong>Node ID:</strong> 129fd86a-a12d-418c-8b63-ed5a7997ceb2<br><strong>Similarity:</strong> None<br><strong>Text:</strong> [(‘Ford Motor Company’, ‘F’, 311645200), (‘Ford Motor Company’, ‘F’, 311645200), (‘Ford Motor Com…</blockquote><p>The default setting in the <em>NLSQLRetriever</em> is <em>return_raw = True</em>. Let’s make it <em>False</em>.</p><pre>nl_sql_retriever = NLSQLRetriever(<br>    sql_database, tables=[&quot;stock_tweets&quot;,&quot;stock_yfinance_data&quot;], return_raw=False<br>)<br><br>results = nl_sql_retriever.retrieve(<br>    &quot;Return the top 5 stocks (along with their company names) with the highest volume.&quot;<br>)<br><br>for n in results:<br>    display_source_node(n, show_source_metadata=True)</pre><p>These are the source nodes:</p><blockquote><strong>Node ID:</strong> c175c114-b565–422e-b576–2e4f8d44b9a5<br><strong>Similarity:</strong> None<br><strong>Text:</strong><br><strong>Metadata:</strong> {‘Company_Name’: ‘Ford Motor Company’, ‘Stock_Name’: ‘F’, ‘Volume’: 311645200}</blockquote><p>Now we will integrate our SQL Retriever with the standard <em>RetrieverQueryEngine</em> to generate a response. This will complete our Text-to-SQL retriever query engine.</p><pre>query_engine = RetrieverQueryEngine.from_args(nl_sql_retriever)<br><br>results = query_engine.query(<br>    &quot;Return the top 5 stock names (along with their company names) with the highest volume.&quot;<br>)<br><br>print(str(results))</pre><p>The results will be:</p><blockquote>Apple Inc.<br>Microsoft Corporation<br>Alphabet Inc.<br>Amazon.com, Inc.<br>Facebook, Inc.</blockquote><h3>Conclusion</h3><p>We saw how easy it was to query in natural language and retrieve results using the Text-to-SQL retriever. Additionally, we found it easy to use Stages and Secrets in SingleStore Helios, with a single interface for Database and Notebooks. It was thrilling for me to explore SingleStore Helios, now it’s your turn to experiment with it.</p><p><em>Thanks for reading!</em></p><h3>References</h3><p><a href="https://docs.llamaindex.ai/en/stable/examples/index_structs/struct_indices/SQLIndexDemo/">Text-to-SQL Guide</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=0ebe1150cbe2" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building Real-Time Financial News RAG Chatbot with Gemini and Qdrant]]></title>
            <link>https://medium.com/@akriti.upadhyay/building-real-time-financial-news-rag-chatbot-with-gemini-and-qdrant-64c0a3fbe45b?source=rss-f6c4eb90254------2</link>
            <guid isPermaLink="false">https://medium.com/p/64c0a3fbe45b</guid>
            <category><![CDATA[qdrant]]></category>
            <category><![CDATA[rag-chatbot]]></category>
            <category><![CDATA[gemini]]></category>
            <category><![CDATA[fastembed]]></category>
            <category><![CDATA[llamaindex]]></category>
            <dc:creator><![CDATA[Akriti Upadhyay]]></dc:creator>
            <pubDate>Fri, 29 Mar 2024 03:44:02 GMT</pubDate>
            <atom:updated>2024-03-29T04:09:08.598Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0ghUThfHYj_zGbA9W1BXvA.png" /></figure><h3>Introduction</h3><p>Most of us have invested time and effort in buying real estate, mutual funds, bonds, and more. Before investing, we search for a suitable banking partner. For long-term investments, we research which banks are performing well minus scams or frauds, and offer reasonable interest rates and returns. So we need to stay updated with financial news.</p><p>What if you had at your disposal a real-time financial news chatbot that could provide you with all the news related to finance and economics? Does that sound interesting? Retrieval Augmented Generation (RAG) has now made this possible. We can leverage large language models and vector databases to get our queries answered.</p><p>Let’s create a real-time financial news RAG chatbot and see if it accurately answers questions using available data. It can be real-time by feeding a vector database with the latest news.</p><h3>Real-Time Financial News RAG Chatbot Using Gemini</h3><p>As our starting point, we took the <a href="https://www.kaggle.com/datasets/hkapoor/indian-financial-news-articles-20032020">Indian Financial News dataset</a>. This dataset consists of financial news related to Indian banks. It is updated till 26th May 2020.</p><p>Before we get started, let’s install the required dependencies.</p><pre>%pip install -q llama-index &#39;google-generativeai&gt;=0.3.0&#39; qdrant_client llama-index-embeddings-fastembed fastembed llama-index-llms-gemini</pre><h4>Preparing the Node</h4><p>As the dataset is a CSV file, let’s load the data.</p><pre>from llama_index.core import SimpleDirectoryReader<br>docs = SimpleDirectoryReader(&quot;Dataset&quot;).load_data()</pre><p>All the documents are ready; now we will split the sentences into defined chunk sizes.</p><pre>from llama_index.core.node_parser.text import SentenceSplitter<br># Initialize the SentenceSplitter with a specific chunk size<br>text_parser = SentenceSplitter(chunk_size=1024)<br>text_chunks = [] # This will hold all the chunks of text from all documents<br>doc_idxs = [] # This will keep track of the document each chunk came from<br>for doc_idx, doc in enumerate(docs):<br> # Split the current document&#39;s text into chunks<br> cur_text_chunks = text_parser.split_text(doc.text)<br> <br> # Extend the list of all text chunks with the chunks from the current document<br> text_chunks.extend(cur_text_chunks)<br> <br> # Extend the document index list with the index of the current document, repeated for each chunk<br> doc_idxs.extend([doc_idx] * len(cur_text_chunks))</pre><p>Then, we will create a text node object and assign the metadata to it. We will store all the nodes in one node list.</p><pre>from llama_index.core.schema import TextNode<br>nodes = [] # This will hold all TextNode objects created from the text chunks<br># Iterate over each text chunk and its index<br>for idx, text_chunk in enumerate(text_chunks):<br> # Create a TextNode object with the current text chunk<br> node = TextNode(text=text_chunk)<br> <br> # Retrieve the source document using the current index mapped through doc_idxs<br> src_doc = docs[doc_idxs[idx]]<br> <br> # Assign the source document&#39;s metadata to the node&#39;s metadata attribute<br> node.metadata = src_doc.metadata<br> <br> # Append the newly created node to the list of nodes<br> nodes.append(node)</pre><h4>Initializing the Qdrant Vector Store</h4><p>To store the nodes, we need a vector store. Here, we have chosen <a href="https://qdrant.tech/">Qdrant</a> as our vector store. Qdrant is a high-performance vector database with all the specific features that a vector store should have. It is fast and accurate by utilizing the HNSW algorithm for approximate nearest neighbor search. Qdrant supports additional payload and filters based on payload values by providing an easy-to-use API. Additionally, it supports docker installation, is equipped with in-memory storage of vectors, is cloud-native, and scales horizontally. Developed in the Rust language, Qdrant implements dynamic query planning and payload data indexing.</p><p>First, we’ll create a collection in the vector store index.</p><pre>from llama_index.core import VectorStoreIndex, StorageContext<br>from llama_index.vector_stores.qdrant import QdrantVectorStore<br>from llama_index.core import Settings<br>from llama_index.core import StorageContext<br>import qdrant_client<br><br># Create a local Qdrant vector store<br>client = qdrant_client.QdrantClient(path=&quot;financialnews&quot;)<br>vector_store = QdrantVectorStore(client=client, collection_name=&quot;collection&quot;)</pre><h4>Gemini Embeddings and Text Model</h4><p>The vector store and nodes are ready, but the vector store is not going to directly accept the nodes. They require embeddings, and for embeddings, we are using the Gemini embedding model here. We’ll be leveraging the Gemini LLM, which is a very capable family of multimodal models. Built on the transformer architecture and trained on TPUs, the Gemini model excels in summarization, reading comprehension tasks with per-task fine-tuning, multilinguality, long context, coding, complex reasoning, mathematics, and of course, multimodality.</p><p>We’ll initiate the Google API key, which you can obtain from <a href="https://aistudio.google.com/app/apikey">Google AI Studio</a>.</p><pre>%env GOOGLE_API_KEY = &quot;your-api-key&quot;<br>import os<br>GOOGLE_API_KEY = &quot;your-api-key&quot; # add your GOOGLE API key here<br>os.environ[&quot;GOOGLE_API_KEY&quot;] = GOOGLE_API_KEY</pre><p>Now, using the API key, we will generate the embeddings using the FastEmbed embedding model and the Gemini LLM in Llamaindex’s Settings.</p><pre>from llama_index.embeddings.fastembed import FastEmbedEmbedding<br>embed_model = FastEmbedEmbedding(model_name=&quot;BAAI/bge-small-en-v1.5&quot;)<br>for node in nodes:<br> node_embedding = embed_model.get_text_embedding(<br> node.get_content(metadata_mode=&quot;all&quot;)<br> )<br> node.embedding = node_embedding<br>from llama_index.llms.gemini import Gemini<br>Settings.embed_model = embed_model<br>Settings.llm = Gemini(model=&quot;models/gemini-pro&quot;)<br>Settings.transformations = [SentenceSplitter(chunk_size=1024)]<br>storage_context = StorageContext.from_defaults(vector_store=vector_store)<br>index = VectorStoreIndex(<br> nodes=nodes,<br> storage_context=storage_context,<br>transformations=Settings.transformations,<br>)</pre><p>The vector store is saved in the storage context, and the index has been initiated with it and the nodes.</p><h4>HyDE Query Transformation</h4><p>Now, we’ll initiate the vector query engine with a response synthesizer and vector retriever. Vector Retriever is initiated with the vector index retriever in which the index was included. Response Synthesizer generates a response from an LLM, using a user query and a given set of text chunks. The output of a response synthesizer is a Response Object.</p><pre>from llama_index.core import get_response_synthesizer<br>from llama_index.core.query_engine import RetrieverQueryEngine<br>from llama_index.core.retrievers import VectorIndexRetriever<br>vector_retriever = VectorIndexRetriever(index=index, similarity_top_k=2)<br>response_synthesizer = get_response_synthesizer()<br>vector_query_engine = RetrieverQueryEngine(<br> retriever=vector_retriever,<br> response_synthesizer=response_synthesizer,<br>)</pre><p>We will employ the HyDE query transformer for advanced retrieval. HyDE (Hypothetical Document Embeddings) facilitates zero-shot prompt-based instruction-following in a large language model. It generates a hypothetical document encapsulating relevant text patterns, converts them into embedding vectors, and averages them to create a single embedding. This procedure identifies the corresponding actual embedding through vector similarity in the document embedding space, thereby eliminating the need for a retrieval step involving querying an input and obtaining a document from a large database.</p><p>The HyDE query transformation assists in delivering responses directly and concisely.</p><pre>from llama_index.core.indices.query.query_transform import HyDEQueryTransform<br>from llama_index.core.query_engine import TransformQueryEngine<br>hyde = HyDEQueryTransform(include_original=True)<br>hyde_query_engine = TransformQueryEngine(vector_query_engine, hyde)</pre><h4>Leveraging Gradio UI for Chatbot Implementation</h4><p>For deploying a chatbot, we will use Gradio.</p><pre>def queries(query_str):<br> response = hyde_query_engine.query(query_str)<br> return str(response)<br>import gradio as gr<br>import os<br>gr.close_all()<br>with gr.Blocks(theme=gr.themes.Soft()) as demo:<br> gr.Markdown(<br> &quot;&quot;&quot;<br> # Welcome to Gemini-Powered Stock Predictor RAG Chatbot!<br> &quot;&quot;&quot;)<br> chatbot = gr.Chatbot()<br> msg = gr.Textbox()<br> clear = gr.ClearButton([msg, chatbot])<br> def respond(message, chat_history):<br> bot_message = queries(message)<br> chat_history.append((message, bot_message))<br> return &quot;&quot;, chat_history<br> msg.submit(respond, [msg, chatbot], [msg, chatbot])<br> <br>demo.launch(share=True)</pre><h4>Query Time!</h4><p>Let’s query the chatbot.</p><p><strong>Question 1:</strong></p><blockquote><strong>Tell me all the news about scam.</strong></blockquote><blockquote>PNB scam fallout: Trade finance hit as caution prevails, premium soars<br>PNB scam fallout widens as NCLT bars over 60 entities from selling assets<br>PNB scam: CBI arrests 4 officials of Nirav Modi, Mehul Choksi’s companies<br>PNB scam: Court issues non-bailable warrants against Nirav Modi, Choksi<br>PNB chief Sunil Mehta admits the collusion of employees in LoUs scam<br>Nirav Modi case: CBI recovers LoU documents, arrests another PNB executive<br>Assets worth Rs 57.16 bn, 1st LoU issued in Mar 2011 seized: ED on PNB scam<br>‘Explain how scam took place’: CVC seeks report from PNB, FinMin in 10 days<br>PNB fraud case: Congress says it will oppose PSBs privatisation<br>PNB fraud: Govt thinks RBI may be unable to ensure effective supervision?<br>7 public sector bank stocks hit 52-week lows on Rs 114-bn PNB fraud case<br>PNB tanks 7% on Monday; m-cap plunges Rs 109.75 bn in four sessions<br>PNB will have to own responsibility of bona fide transactions, says FinMin<br>Nirav Modi PNB fraud: PM Modi’s silence speaks of his loyalties, says Rahul<br>Nirav Modi PNB fraud: Vijay Aggarwal to be absconding diamantaire’s lawyer<br>Before PNB fraud: Nirav Modi, Choksi left 18 businessmen, 24 firms bankrupt<br>Nirav Modi PNB fraud: CBI seals bank’s Brady House Branch in Mumbai<br>Once the pride of Punjab, PNB is now a theme for WhatsApp memes in India<br>Eyes wide shut: The $1.8 billion PNB fraud that went completely unnoticed<br>Bank Union wants CBI probe into PNB fraud, alleges RBI failed as regulator<br>CBI questions Nirav Modi’s CFO Vipul Ambani; searches PNB Mumbai branch<br>PNB scam: Jewellers expect more casualties and tighter regulations<br>Rs 114-bn PNB scam: Why fraudsters prefer to use Letter of Undertaking</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*YcpLZR6rOcC4A_lx" /></figure><p><strong>Question 2:</strong></p><blockquote><strong>What is the latest news about RBI?</strong></blockquote><blockquote>The RBI has deferred the launch of IndAs again, awaiting amendments to the banking laws.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*0YydZiFUhH27YXHd" /></figure><p><strong>Question 3:</strong></p><blockquote><strong>Can you tell me all the news related to home loans?</strong></blockquote><blockquote>Lending rates cut leads to balance transfers in home loan market: ICRA<br>Can’t match home loan rates with BoB: United Bank of India<br>After rate cut, Bank of Baroda eyes bigger home loan pie<br>Bank of Baroda offers lowest home loans rates at 8.35%<br>For SBI, home loan queries jump three times since rate cut<br>HDFC cuts home loan rates by up to 0.45%<br>Hamara Ghar offer: SBI’s new home loan<br>Banks cut lending rates: How home-loan borrowers will benefit<br>SBI cuts lending rate by 90 bps; home, auto loans to become cheaper</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*gm5yTZtSV449E5Em" /></figure><p><strong>Question 4:</strong></p><blockquote><strong>Tell me about the news of Yes Bank Scam.</strong></blockquote><blockquote>The RBI discovered more than $450 million in extra bad loans at Yes Bank. The gross non-performing assets assessed by the Reserve Bank of India were $457 million higher than Yes Bank had disclosed as of November 20, 2019.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*I1-S_np3qlLRsyFE" /></figure><p><strong>Question 5:</strong></p><blockquote><strong>What is the latest news about NBFC?</strong></blockquote><blockquote>The latest news about NBFC is that RBI eases norms for banks to lend more to NBFCs, housing finance companies. RBI enhances single-borrower exposure limit to 15% of bank’s capital.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*d-8ouhXRDxYJmJob" /></figure><h3>Conclusion</h3><p>Building a real-time financial news RAG chatbot using the Indian Financial News dataset proved to be a rewarding journey. Now you know that you can easily ask questions about banks and get instant answers! It’s now time for you to make your own chatbot. Hope you enjoyed reading this blog.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=64c0a3fbe45b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Perform Image-Driven Reverse Image Search on E-Commerce Sites with ImageBind and Qdrant]]></title>
            <link>https://medium.com/@akriti.upadhyay/perform-image-driven-reverse-image-search-on-e-commerce-sites-with-imagebind-and-qdrant-0a62f0169e19?source=rss-f6c4eb90254------2</link>
            <guid isPermaLink="false">https://medium.com/p/0a62f0169e19</guid>
            <category><![CDATA[embedding]]></category>
            <category><![CDATA[qdrant]]></category>
            <category><![CDATA[imagebind]]></category>
            <category><![CDATA[reverse-image-search]]></category>
            <category><![CDATA[gradio]]></category>
            <dc:creator><![CDATA[Akriti Upadhyay]]></dc:creator>
            <pubDate>Wed, 28 Feb 2024 13:39:40 GMT</pubDate>
            <atom:updated>2024-02-28T13:57:12.402Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/899/0*D0Cq3yyVnjY-HC12" /></figure><h3>Introduction</h3><p>In 1950, when Alan Turing introduced the term <em>“Machine Intelligence”</em> in his paper <em>“Computing Machinery and Intelligence,”</em> no one had imagined that one day, in the future, it would lead to various innovations using artificial intelligence in different domains. One domain that is very popular and important among users is online shopping. With the surge in e-commerce, users increasingly rely on visual cues to guide them in their purchasing decisions. In response to this shift in consumer behavior, image-driven product search has emerged as a powerful tool to enhance the shopping experience. E-commerce platforms like Amazon, Myntra, Ajio, and Meesho are using image-driven product search widely.</p><p>You must be familiar with image-driven searches on shopping websites. This innovative approach uses the visual content in images to let users explore products more intuitively and efficiently. By simply uploading or capturing an image, shoppers can quickly find similar or related items within a vast catalog. Whether seeking fashion inspiration, home decor ideas, or specific product recommendations, image-driven search offers a dynamic and personalized shopping journey tailored to individual preferences and tastes.</p><p>We can make the results accurate by using the recently developed all-in-one embedding model by Meta: ImageBind. But before using the embedding model, we need to use a vector database to store them.</p><p>When it comes to image search, vector databases have been particularly transformative. Traditional image search methods often rely on metadata tags or textual descriptions, which can be limited in capturing the rich visual content of images. With vector databases, images are transformed into high-dimensional vectors that encapsulate their visual features by allowing for more accurate and nuanced similarity comparisons. This means that users can search for images based on visual similarity by enabling tasks for e-commerce product search from images with remarkable precision. However, when it comes to vector databases, we are faced with a dilemma: which database will be the best for our application?</p><p>Here, I have chosen the Qdrant Vector database, which offers an advanced search algorithm for approximate nearest neighbor search for advanced AI applications, namely the HNSW algorithm. Meesho is already using the Qdrant vector database but still, the results are not very accurate. We can make the results more accurate by integrating the Qdrant and ImageBind embedding models. Before diving into the content, let’s look at the steps:</p><ol><li>Loading the Dataset.</li><li>Initializing the Qdrant Vector DB.</li><li>Image Embeddings with ImageBind.</li><li>Deploying with Gradio.</li></ol><h3>Reverse Product Image Search with Qdrant</h3><p>Let’s install the dependencies first to get started with the reverse product image search.</p><pre>%pip install opendatasets gradio qdrant-client transformers sentence_transformers sentencepiece tqdm</pre><h4>Loading the Dataset</h4><p>Using the <em>opendatasets </em>library, download the Kaggle <a href="https://www.kaggle.com/datasets/vikashrajluhaniwal/fashion-images">dataset </a>using your username and key. You can obtain them by visiting the Settings page on Kaggle. Click on <em>“Access API Keys,”</em> and a <em>kaggle.json</em> file will be downloaded. This file will contain your username and API key.</p><pre>import opendatasets as od<br>od.download(&quot;https://www.kaggle.com/datasets/vikashrajluhaniwal/fashion-images&quot;)</pre><p>Now, let’s store the images in a list so that we can easily access the images.</p><pre>import random<br>import gradio as gr<br>from PIL import Image<br>from qdrant_client import QdrantClient<br>from qdrant_client.http import models<br>import tempfile<br>import os<br>from tqdm import tqdm<br>import os<br>def get_image_paths(directory):<br> # Initialize an empty list to store the image paths<br> image_paths = []<br> # Iterate through all files and directories within the given directory<br> for root, dirs, files in os.walk(directory):<br> for file in files:<br> # Check if the file has an image extension (e.g., .jpg, .png, .jpeg, etc.)<br> if file.lower().endswith((&#39;.png&#39;, &#39;.jpg&#39;, &#39;.jpeg&#39;, &#39;.gif&#39;, &#39;.bmp&#39;)):<br> # Construct the full path to the image file<br> image_path = os.path.join(root, file)<br> # Append the image path to the list<br> image_paths.append(image_path)<br> <br> return image_paths<br># Directory paths<br>women_directory = &#39;./fashion-images/data/Footwear_Women/Images/images_with_product_ids/&#39;<br>men_directory = &#39;./fashion-images/data/Footwear_Men/Images/images_with_product_ids/&#39;<br>girls_directory = &#39;./fashion-images/data/Apparel_Girls/Images/images_with_product_ids/&#39;<br>boys_directory = &#39;./fashion-images/data/Apparel_Boys/Images/images_with_product_ids/&#39;<br># Get image paths for different categories<br>image_paths_Women = get_image_paths(women_directory)<br>image_paths_Men = get_image_paths(men_directory)<br>image_paths_Girls = get_image_paths(girls_directory)<br>image_paths_Boys = get_image_paths(boys_directory)<br>all_image_paths = []<br>all_image_paths.append(image_paths_Boys)<br>all_image_paths.append(image_paths_Girls)<br>all_image_paths.append(image_paths_Men)<br>all_image_paths.append(image_paths_Women)</pre><h4>Initializing the Qdrant Vector DB</h4><p>Initialize the <a href="https://qdrant.tech/">Qdrant </a>Client with in-memory storage. The collection name will be <em>“imagebind_data”</em> and we will be using cosine distance.</p><pre># Initialize Qdrant client and load collection<br>client = QdrantClient(&quot;:memory:&quot;)<br>client.recreate_collection(collection_name = &quot;imagebind_data&quot;,<br>vectors_config = {&quot;image&quot;: models.VectorParams( size = 1024, distance = models.Distance.COSINE ) } )</pre><h4>Image Embeddings with ImageBind</h4><p>ImageBind is an innovative model developed by Meta AI’s FAIR Lab. This model is designed to learn a joint embedding across six different modalities: images, text, audio, depth, thermal, and IMU data. One of the key features of ImageBind is its ability to learn this joint embedding without requiring all combinations of paired data. It has been discovered that only image-paired data is necessary to bind the modalities together effectively. This unique capability allows ImageBind to leverage recent large-scale vision-language models and extend their zero-shot capabilities to new modalities simply by utilizing their natural pairing with images.</p><p>We’ll use ImageBind for creating embeddings, but before diving deep, first, let’s follow some steps required for installing ImageBind.</p><blockquote><strong>Clone the git repository of Imagebind:</strong></blockquote><pre>git clone https://github.com/facebookresearch/ImageBind.git</pre><blockquote><strong>Change the directory:</strong></blockquote><pre>cd Imagebind</pre><blockquote><strong>Edit the requirements.txt file: Delete Mayavi and Cartopy if getting errors or facing problems.</strong></blockquote><blockquote><strong>Install the requirements:</strong></blockquote><pre>pip install -r requirements.txt</pre><blockquote><strong>Come back to your system.</strong></blockquote><p>Then, load the model.</p><pre>import sys <br>sys.path.append(&quot;./ImageBind/&quot;)<br>device = &quot;cuda&quot;<br>import imagebind<br>from imagebind.models import imagebind_model<br>model = imagebind_model.imagebind_huge(pretrained=True)<br>model.eval()<br>model.to(device)</pre><p>After initializing the model, we will now create embeddings.</p><pre>from imagebind.models.imagebind_model import ModalityType<br>from imagebind import data<br>import torch<br>embeddings_list = []<br>for image_paths in [image_paths_Boys, image_paths_Girls, image_paths_Men, image_paths_Women]:<br> inputs = {ModalityType.VISION: data.load_and_transform_vision_data(image_paths, device)}<br> with torch.no_grad():<br> embeddings = model(inputs)<br> embeddings_list.append(embeddings)</pre><p>Then we’ll update the Qdrant Vector DB with the generated embeddings.</p><pre>import uuid<br>points = []<br># Iterate over each embeddings and corresponding image paths<br>for idx, (embedding, image_paths) in enumerate(zip(embeddings, all_image_paths)):<br> for sub_idx, sample in enumerate(image_paths):<br> # Convert the sample to a dictionary<br> payload = {&quot;path&quot;: sample}<br> # Generate a unique UUID for each point<br> point_id = str(uuid.uuid4())<br> points.append(models.PointStruct(id=point_id,<br> vector= {&quot;image&quot;: embedding[&#39;vision&#39;][sub_idx]}, <br> payload=payload)<br> )<br>client.upsert(collection_name=&quot;imagebind_data&quot;, points=points)</pre><p>We’ll prepare a processing function in which we will take the image as an input and perform a reverse image search with the help of the embeddings.</p><pre>def process_text(image_query):<br> <br> user_query = [image_query]<br> dtype, modality = ModalityType.VISION, &#39;image&#39;<br> user_input = {dtype: data.load_and_transform_vision_data(user_query, device)}<br> with torch.no_grad():<br> user_embeddings = model(user_input)<br> <br> image_hits = client.search(<br> collection_name=&#39;imagebind_data&#39;,<br> query_vector=models.NamedVector(<br> name=&quot;image&quot;,<br> vector=user_embeddings[dtype][0].tolist()<br> )<br> )<br> # Check if &#39;path&#39; is in the payload of the first hit<br> if image_hits and &#39;path&#39; in image_hits[0].payload:<br> return (image_hits[0].payload[&#39;path&#39;])<br> else:<br> return None</pre><h4>Deploying with Gradio</h4><p>Now that we have prepared the processing image function, we’ll use Gradio to deploy by defining its interface.</p><pre>import tempfile<br>tempfile.tempdir = &quot;./fashion-images/data&quot;<br># Gradio Interface<br>iface = gr.Interface(<br> title=&quot;Reverse Image Search with Imagebind&quot;,<br> description=&quot;Leveraging Imagebind to perform reverse image search for ecommerce products&quot;,<br> fn=process_text,<br> inputs=[<br> gr.Image(label=&quot;image_query&quot;, type=&quot;filepath&quot;)<br> ],<br> outputs=[<br> gr.Image(label=&quot;Image&quot;)], <br>)</pre><h3>Image Search Using Product Category</h3><p>If you want to search images with the product category, then you have to define some functions. We’ll define a function to get images from the category.</p><pre># Define function to get images of selected category<br>def get_images_from_category(category):<br> # Convert category to string<br> category_str = str(category)<br> # Directory path for selected category<br> category_dir = f&quot;./fashion-images/data/{category_str.replace(&#39; &#39;, &#39;_&#39;)}/Images/images_with_product_ids/&quot;<br> # List of image paths<br> image_paths = os.listdir(category_dir)<br> # Open and return images<br> images = [Image.open(os.path.join(category_dir, img_path)) for img_path in image_paths]<br> return images</pre><p>Then list the product categories.</p><pre># Define your product categories<br>product_categories = [&quot;Apparel Boys&quot;, &quot;Apparel Girls&quot;, &quot;Footwear Men&quot;, &quot;Footwear Women&quot;]</pre><p>After that, we’ll define a function for category selection.</p><pre># Define function to handle category selection<br>def select_category(category):<br> # Get images corresponding to the selected category<br> images = get_images_from_category(category)<br> # Return a random image from the list<br> return random.choice(images)</pre><h4>Deploying with Gradio</h4><p>Now, we’ll create Gradio interface components for the category selection, such as category dropdown and submit button.</p><pre># Create interface components for the category selection<br>category_dropdown = gr.Dropdown(product_categories, label=&quot;Select a product category&quot;)<br>submit_button = gr.Button()<br>images_output = gr.Image(label=&quot;Images of Selected Category&quot;)</pre><p>After that, we’ll create a Gradio interface and pass the functions and components.</p><pre>category_search_interface = gr.Interface(<br> fn=select_category,<br> inputs=category_dropdown,<br> outputs=images_output,<br> title=&quot;Category-driven Product Search for Ecommerce&quot;,<br> description=&quot;Select a product category to view a random image from the corresponding directory.&quot;,<br>)</pre><h4>Merging Two Gradio Interfaces</h4><p>We have deployed two Gradio Interfaces: one is Reverse Image Search and another is Image Search Using Product Category. What if we can see both in one application? That can be performed by using TabbedInterface.</p><pre># Combine both interfaces into the same API<br>combined_interface = gr.TabbedInterface([iface, category_search_interface])<br># Launch the combined interface<br>combined_interface.launch(share=True)</pre><p>Now, we’ll get an internal URL and a public URL. The application is ready with two tabs.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*50c3XyeX6GjulM33" /></figure><blockquote><strong>Tab 0: Reverse Image Search with ImageBind for E-Commerce</strong></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*rP0iWiYNWfSVpPB2" /></figure><blockquote><strong>Tab 1: Category-Driven Product Search for E-Commerce</strong></blockquote><h3>Examples</h3><p>Let’s see how our application performs.</p><p>I passed a girl’s image who was wearing a sleeveless Dress. Let’s see if our application can find a similar image from the products.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*bCbNtuaenwtbF36x" /></figure><p>The application found a dress which is quite similar. Impressive!</p><p>Let’s try passing Shoes as an Image. I passed a picture of three people’s feet with sneakers. Let’s see the result.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*PigBSYM24YCZ-p-Z" /></figure><p>The result is impressive. The output is sneakers of the same style.</p><p>Let’s try a category search. For example, I want to see what are the products in the Boys Apparel category. Gradio can give only one image as output, but in this application, it will not give the same image for every search.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*f3i1BOQUNKbNLDUx" /></figure><p>The first search gave an image of a white t-shirt. Let’s search again to see what other t-shirts there are.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*e1IfzFVpgzzEtW5-" /></figure><p>The result is a blue-gray t-shirt. So, the results are not repeated. Great!</p><h3>Conclusion</h3><p>With Qdrant Vector DB, reverse image search is possible for e-commerce products. We saw from our results how to perform a reverse image search by uploading an image and getting images of similar products from select product categories. The results were accurate with the help of the ImageBind embedding model.</p><p>Hope you enjoyed reading this blog. Now it is your turn to try this integration.</p><h3>CodeSpace</h3><p>You can find the code on <a href="https://github.com/akritiupadhyay-au/How-to-Perform-Image-Driven-Reverse-Image-Search-on-E-Commerce-Sites/tree/main">GitHub</a>.</p><p>Thanks for reading!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=0a62f0169e19" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A Technical Deep-Dive Into Stable Diffusion 3]]></title>
            <link>https://medium.com/superteams-ai-blog/a-technical-deep-dive-into-stable-diffusion-3-f6e60e4b14e9?source=rss-f6c4eb90254------2</link>
            <guid isPermaLink="false">https://medium.com/p/f6e60e4b14e9</guid>
            <category><![CDATA[flowmatching]]></category>
            <category><![CDATA[stable-diffusion-3]]></category>
            <category><![CDATA[diffusion]]></category>
            <category><![CDATA[transformers]]></category>
            <category><![CDATA[architecture]]></category>
            <dc:creator><![CDATA[Akriti Upadhyay]]></dc:creator>
            <pubDate>Fri, 23 Feb 2024 08:45:34 GMT</pubDate>
            <atom:updated>2024-02-23T09:06:19.076Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/613/0*7wGGedUgNNN6UiNG" /></figure><h3>Introduction to Stable Diffusion 3</h3><p>Stability AI has just announced the most capable text-to-image model with enhanced performance in multi-subject prompts, image quality, and spelling abilities: Stable Diffusion 3. While the model is in an early preview stage, the waitlist is now open for interested users to participate and provide valuable feedback for further refinement before its broader release.</p><h4>Key Highlights of Stable Diffusion 3</h4><p>Let’s see what difference Stable Diffusion 3 is going to make in the evolving realm of Text-to-Image Generation.</p><ol><li><strong>Improved Performance and Quality: </strong>The suite of models in Stable Diffusion 3 ranges from 800 million to 8 billion parameters, which offers scalability and quality options to cater to diverse creative needs. The model leverages a diffusion transformer architecture combined with flow matching, which enhances its capabilities to generate high-quality images from text prompts.</li><li><strong>Focus on Safety and Responsibility: </strong>The development team has implemented various safeguards throughout the training, evaluation, and deployment phases to prevent misuse by bad actors which emphasizes safe and responsible AI practices. Researchers, experts, and the community are collaborating with the ongoing innovation with integrity, prioritizing safety and ethical considerations.</li></ol><p>One of the most exciting elements of this new Stable Diffusion release is the 800 million variant. This would dramatically enhance the accessibility of image synthesis AI. This falls in line with the direction that Google has taken with Gemma 2b and Microsoft has done with Phi-2 language models.</p><p>Stable Diffusion 3 combines the diffusion transformer architecture with flow matching. Let’s see what that means.</p><h3>Diffusion Transformer Architecture: A Technical Overview</h3><p>The Diffusion Transformer (DiT) architecture combines the power of diffusion models with the scalability and flexibility of transformer-based architectures.</p><p>Diffusion models have shown remarkable success in generative modeling tasks by leveraging the principle of iteratively denoising samples. Transformers, known for their ability to capture long-range dependencies in data, have demonstrated outstanding performance in various natural language processing and computer vision tasks.</p><p>Combining the strengths of diffusion models and transformers leads to more powerful and efficient generative models capable of capturing complex data distributions.</p><h4>Architecture</h4><p>The backbone of the DiT architecture consists of a stack of transformer layers, similar to those found in standard transformer models like the Vision Transformer (ViT) or the Transformer architecture used in natural language processing tasks. Each transformer layer in the DiT is augmented to incorporate the diffusion process.</p><p>This involves integrating the diffusion mechanism into the self-attention mechanism of the transformer. DiTs typically incorporate a conditioning mechanism to allow for class-conditional image generation. This conditioning mechanism can be implemented using various techniques, such as injecting class tokens into the input sequence or conditioning the attention mechanism on class information.</p><p>Similar to vision transformer architectures, DiTs process images in a patchwise manner. Each patch of the input image is flattened into a sequence of tokens, which are then processed by the transformer layers. DiTs often employ adaptive layer normalization (adaLN) to improve training stability and model performance. adaLN adjusts the normalization parameters based on the input data, allowing the model to adapt to different input distributions.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*exjV8abBrleGM-xC" /><figcaption>Source: <a href="https://arxiv.org/pdf/2212.09748.pdf">https://arxiv.org/pdf/2212.09748.pdf</a></figcaption></figure><h4>Training</h4><p>DiTs are typically trained using standard generative modeling techniques, such as maximum likelihood estimation or variational inference. Training data is fed into the model, and the model parameters are updated iteratively to minimize a suitable loss function, such as the negative log-likelihood of the training data.</p><p>During training, the model may use additional techniques such as the exponential moving average (EMA) of model weights, data augmentation, and regularization to improve performance and stability. One of the key advantages of DiTs is their <em>scalability</em>. By leveraging the scalability of transformer architectures, DiTs can efficiently handle large-scale generative modeling tasks, including high-resolution image generation.</p><p>DiTs have shown impressive performance on benchmark datasets and often achieve state-of-the-art results in terms of image quality metrics such as Frechet Inception Distance (FID), Inception Score (IS), and Precision/Recall.</p><h3>Why use Flow Matching? An Overview</h3><p>Flow Matching (FM) is a novel framework for training Continuous Normalizing Flow (CNF) models, designed to overcome some of the limitations associated with traditional training approaches. It introduces a simulation-free methodology that leverages conditional constructions to efficiently scale to high-dimensional datasets while providing improved sampling and generation capabilities.</p><p>Traditional training methods for CNF models often involve computationally expensive simulations, especially when dealing with high-dimensional data. These simulations can hinder scalability and efficiency.</p><p>Flow Matching aims to address these challenges by offering a simulation-free alternative that simplifies training while maintaining high-quality sampling and generation performance.</p><h4>Key Concepts</h4><ol><li><strong>Conditional Constructions: </strong>FM relies on conditional probability paths and vector fields to model the flow of data through the latent space. By conditioning on relevant variables, FM can capture complex data distributions more effectively.</li><li><strong>Probability Paths: </strong>Instead of relying on diffusion processes or stochastic simulations, FM directly specifies the probability path through the latent space. This allows for more precise control over the data generation process.</li><li><strong>Vector Fields:</strong> FM utilizes vector fields to define the dynamics of the flow, which guides the transformation of data from the input space to the latent space. These vector fields can be optimized to match the desired probability path.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*aCwj1b2v8TQm-FIL" /><figcaption>Source: <a href="https://arxiv.org/pdf/2210.02747.pdf">https://arxiv.org/pdf/2210.02747.pdf</a></figcaption></figure><h4>Training Methodology</h4><ol><li><strong>Simulation-Free Approach: </strong>FM eliminates the need for costly simulations by directly specifying the probability path and optimizing the vector fields accordingly. This results in faster and more efficient training.</li><li><strong>Gradient-Based Optimization:</strong> FM employs gradient-based optimization techniques to iteratively update the parameters of the CNF model, which ensures convergence towards the desired probability distribution.</li><li><strong>Conditional Flow Matching Objective:</strong> FM defines a novel objective function, called the Conditional Flow Matching (CFM) objective, which enables unbiased estimation of gradients and efficient training.</li></ol><p>FM demonstrates effectiveness in various image datasets, including CIFAR-10 and ImageNet, at different resolutions. It achieves state-of-the-art results in terms of negative log-likelihood (NLL), sample quality (measured by Frechet Inception Distance, FID), and training efficiency (measured by the number of function evaluations, NFE). Comparative experiments with existing methods highlight the superior performance of FM, particularly in terms of faster convergence and improved sampling efficiency.</p><h3>How Will the Fusion of DiT and FM Be?</h3><p>The fusion of diffusion transformer architecture and flow matching represents an interesting approach in text-to-image generation AI. Once Stable Diffusion 3 releases, we will know what capabilities this combination can yield, but the concept is extremely promising.</p><p>The diffusion transformer architecture integrates the transformer model’s powerful sequence modeling capabilities with diffusion models’ ability to generate high-quality images.</p><p>This combination allows the model to effectively capture complex relationships between text prompts and corresponding images, which results in more coherent and contextually relevant outputs. The relationship between language and image is vital, as eventually the model’s ability to understand human language, and its meaning and incorporate that into the generation process is when we move towards more controllable image generation systems.</p><p>Flow matching techniques enable the model to learn the underlying distribution of image data and generate samples that closely match this distribution. By aligning the generated images with the target distribution, flow matching ensures that the outputs are visually appealing and exhibit realistic characteristics.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/888/0*8jd8ni1Y_DO7a_By" /></figure><p>According to Stability researchers, the integration between diffusion transformer architecture and flow matching leads to significant improvements in image quality. The model can produce images with finer details, sharper textures, and more accurate representations of the input text prompts. This enhancement in image fidelity enhances the overall user experience and widens the range of potential applications in fields such as digital art, design, and entertainment.</p><p>Another challenge in text-to-image generation has been to handle multi-subject prompts. Due to this, most AI-generated images you would see would typically feature a single human. The diffusion transformer architecture, coupled with flow matching, enables the model to process complex, multi-subject prompts with greater accuracy and coherence. This capability allows users to generate diverse and intricate images based on nuanced textual descriptions, which opens up new possibilities for creative expression and storytelling.</p><h3>Final Words</h3><p>The combination of diffusion transformer architecture and flow matching represents a significant advancement in text-to-image generation methodologies. By harnessing the strengths of both approaches, this innovative framework offers improved modeling capabilities, enhanced image quality, and effective handling of multi-subject prompts while prioritizing safety and ethical considerations.</p><p>The overview of DiT and FM, along with the fusion between them, has us excited about the new Stable Diffusion 3 model. Join the <a href="https://stability.ai/stablediffusion3">waitlist </a>and be a part of this revolution!</p><h3>About Superteams.ai</h3><p>Superteams.ai connects top AI talent with companies seeking accelerated product and content development. These “Superteamers” offer individual or team-based solutions for projects involving cutting-edge technologies like LLMs, image synthesis, audio or voice synthesis, and other cutting-edge open-source AI solutions. With over 500 AI researchers and developers, Superteams has facilitated diverse projects like 3D e-commerce model generation, advertising creative generation, enterprise-grade RAG pipelines, geospatial applications, and more. Focusing on talent from India and the global South, Superteams offers competitive solutions for companies worldwide. To explore partnership opportunities, please write to <a href="/service/mailto:founders@superteams.ai">founders@superteams.ai</a> or visit this <a href="https://www.superteams.ai/demo">link</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f6e60e4b14e9" width="1" height="1" alt=""><hr><p><a href="https://medium.com/superteams-ai-blog/a-technical-deep-dive-into-stable-diffusion-3-f6e60e4b14e9">A Technical Deep-Dive Into Stable Diffusion 3</a> was originally published in <a href="https://medium.com/superteams-ai-blog">Superteams.ai</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Steps to Build RAG Application with Gemma 7B LLM]]></title>
            <link>https://medium.com/superteams-ai-blog/steps-to-build-rag-application-with-gemma-7b-llm-43f7251a36a1?source=rss-f6c4eb90254------2</link>
            <guid isPermaLink="false">https://medium.com/p/43f7251a36a1</guid>
            <category><![CDATA[hugging-face]]></category>
            <category><![CDATA[langchain]]></category>
            <category><![CDATA[rags]]></category>
            <category><![CDATA[gemma]]></category>
            <category><![CDATA[faiss]]></category>
            <dc:creator><![CDATA[Akriti Upadhyay]]></dc:creator>
            <pubDate>Thu, 22 Feb 2024 12:43:27 GMT</pubDate>
            <atom:updated>2024-02-23T09:06:42.212Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ireimPdcCcsa4ro0" /></figure><h3>Introduction</h3><p>As large language models are advancing, the craze for building RAG (Retrieval Augmented Generation) applications is increasing. Google just launched an open-source model: Gemma. As we know, RAG represents a fusion between two fundamental methodologies: retrieval-based techniques and generative models. Retrieval-based techniques involve sourcing pertinent information from expansive knowledge repositories or corpora in response to specific queries. Generative models excel in crafting original text or responses by leveraging insights taken from training data to create new content from scratch. With this launch, why not try the new open-source model for building a RAG pipeline and see how it is performing?</p><p>Let’s get started and break the process into these steps:</p><ol><li>Loading the Dataset: Cosmopedia</li><li>Embedding Generation with Hugging Face</li><li>Storing in the FAISS DB</li><li>Gemma: Introducing the SOTA model</li><li>Querying the RAG Pipeline</li></ol><h3>Building RAG Application on Gemma 7B</h3><p>Before rolling our sleeves on, let’s install and import the required dependencies.</p><pre>%pip install -q -U langchain torch transformers sentence-transformers datasets faiss-cpu</pre><pre>import torch<br>from datasets import load_dataset<br>from langchain_community.document_loaders.csv_loader import CSVLoader<br>from langchain.text_splitter import RecursiveCharacterTextSplitter<br>from langchain.embeddings import HuggingFaceEmbeddings<br>from langchain.vectorstores import FAISS<br>from transformers import AutoTokenizer, AutoModelForCausalLM<br>from transformers import AutoTokenizer, pipeline<br>from langchain import HuggingFacePipeline<br>from langchain.chains import RetrievalQA</pre><h4>Loading the Dataset: Cosmopedia</h4><p>To make a RAG application, we have selected a Hugging Face dataset, <a href="https://huggingface.co/datasets/HuggingFaceTB/cosmopedia">Cosmopedia</a>. This dataset consists of synthetic textbooks, blog posts, stories, posts, and WikiHow articles generated by Mixtral-8x7B-Instruct-v0.1. The dataset contains over 30 million files and 25 billion tokens, which makes it the largest open synthetic dataset to date.</p><p>This dataset contains 8 subsets. We’ll move with the ‘stories’ subset. We’ll load the dataset using the datasets library.</p><pre>data = load_dataset(&quot;HuggingFaceTB/cosmopedia&quot;, &quot;stories&quot;, split=&quot;train&quot;)</pre><p>Then, we will convert it to a Pandas dataframe, and save it to a CSV file.</p><pre>data = data.to_pandas()<br>data.to_csv(&quot;dataset.csv&quot;)<br>data.head()</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*XtMa3g-HR-NpdgzI" /></figure><p>Now that the dataset is saved on our system, we will use LangChain to load the dataset.</p><pre>loader = CSVLoader(file_path=&#39;./dataset.csv&#39;)<br>data = loader.load()</pre><p>Now that the data is loaded, we need to split the documents inside the data. Here, we split the documents into chunk sizes of 1000. This will help the model to work fast and efficiently.</p><pre>text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=150)<br>docs = text_splitter.split_documents(data)</pre><h4>Embedding Generation with Hugging Face</h4><p>After that, we will generate embeddings using Hugging Face Embeddings and with the help of the Sentence Transformers model.</p><pre>modelPath = &quot;sentence-transformers/all-MiniLM-l6-v2&quot;<br>model_kwargs = {&#39;device&#39;:&#39;cpu&#39;}<br>encode_kwargs = {&#39;normalize_embeddings&#39;: False}<br>embeddings = HuggingFaceEmbeddings(<br> model_name=modelPath, <br> model_kwargs=model_kwargs, <br> encode_kwargs=encode_kwargs <br>)</pre><h4>Storing in the FAISS DB</h4><p>The embeddings are generated, but we need them to be stored in a vector database. We’ll be saving those embeddings in the FAISS vector store, which is a library for efficient similarity search and clustering dense vectors.</p><pre>db = FAISS.from_documents(docs, embeddings)</pre><h4>Gemma: Introducing the SOTA model</h4><p>Gemma offers two model sizes, with 2 billion and 7 billion parameters respectively, catering to different computational constraints and application scenarios. Both pre-trained and fine-tuned checkpoints are provided, along with an open-source codebase for inference and serving. It is trained on up to 6 trillion tokens of text data and leverages similar architectures, datasets, and training methodologies as the Gemini models. Both exhibit strong generalist capabilities across text domains and excel in understanding and reasoning tasks on a large scale.</p><p>The release includes raw, pre-trained checkpoints as well as fine-tuned checkpoints optimized for specific tasks such as dialogue, instruction-following, helpfulness, and safety. Comprehensive evaluations have been conducted to assess the models’ performance and address any shortcomings, which enables thorough research and investigation into model tuning regimes and the development of safer and more responsible model development methodologies. Gemma’s performance surpasses that of comparable-scale open models across various domains, including question-answering, commonsense reasoning, mathematics and science, and coding, as demonstrated through both automated benchmarks and human evaluations. To know more about the Gemma model, visit this <a href="https://storage.googleapis.com/deepmind-media/gemma/gemma-report.pdf">technical report</a>.</p><p>To get started with the <a href="https://huggingface.co/google/gemma-7b">Gemma</a> model, you should acknowledge their terms on Hugging Face. Then pass the Hugging Face token while logging in.</p><pre>from huggingface_hub import notebook_login<br>notebook_login()</pre><p>Initialize the tokenizer with the model.</p><pre>model = AutoModelForCausalLM.from_pretrained(&quot;google/gemma-7b&quot;)<br>tokenizer = AutoTokenizer.from_pretrained(&quot;google/gemma-7b&quot;, padding=True, truncation=True, max_length=512)</pre><p>Create a text generation pipeline.</p><pre>pipe = pipeline(<br> &quot;text-generation&quot;, <br> model=model, <br> tokenizer=tokenizer,<br> return_tensors=&#39;pt&#39;,<br> max_length=512,<br> max_new_tokens=512,<br> model_kwargs={&quot;torch_dtype&quot;: torch.bfloat16},<br> device=&quot;cuda&quot;<br>)</pre><p>Initialize the LLM with pipeline and model kwargs.</p><pre>llm = HuggingFacePipeline(<br> pipeline=pipe,<br> model_kwargs={&quot;temperature&quot;: 0.7, &quot;max_length&quot;: 512},<br>)</pre><p>Now it is time to use the vector store and the LLM for question-answering retrieval.</p><pre>qa = RetrievalQA.from_chain_type(<br> llm=llm,<br> chain_type=&quot;stuff&quot;,<br> retriever=db.as_retriever()<br>)</pre><h4>Querying the RAG Pipeline</h4><p>The RAG pipeline is ready; let’s pass the queries and see how it performs.</p><pre>qa.invoke(&quot;Write an educational story for young children.&quot;)</pre><p>The result is:</p><pre>Once upon a time, in a cozy little village nestled between rolling hills and green meadows, there lived a curious kitten named Whiskers. Whiskers loved to explore every nook and cranny of the village, from the bustling marketplace to the quiet corners where flowers bloomed. One sunny morning, as Whiskers trotted down the cobblestone path, he spotted something shimmering in the distance. With his whiskers twitching in excitement, he scampered towards it, his little paws pitter-pattering on the ground. To his delight, he found a shiny object peeking out from beneath a bush - a beautiful, colorful kite! With a twinkle in his eye, Whiskers decided to take the kite on an adventure. He tugged at the string, and the kite soared into the sky, dancing gracefully with the gentle breeze. Whiskers giggled with joy as he watched the kite soar higher and higher, painting the sky with its vibrant colors.</pre><h3>Final Words</h3><p>The Gemma 7B model performed very well. We got to read a beautiful story about a kitten. The new SOTA model was interesting and exciting to use. With the help of the FAISS vector store, we were able to build a RAG pipeline. Thanks for reading!</p><h3>About Superteams.ai</h3><p>Superteams.ai connects top AI talent with companies seeking accelerated product and content development. These “Superteamers” offer individual or team-based solutions for projects involving cutting-edge technologies like LLMs, image synthesis, audio or voice synthesis, and other cutting-edge open-source AI solutions. With over 500 AI researchers and developers, Superteams has facilitated diverse projects like 3D e-commerce model generation, advertising creative generation, enterprise-grade RAG pipelines, geospatial applications, and more. Focusing on talent from India and the global South, Superteams offers competitive solutions for companies worldwide. To explore partnership opportunities, please write to <a href="/service/mailto:founders@superteams.ai">founders@superteams.ai</a> or visit this <a href="https://www.superteams.ai/demo">link</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=43f7251a36a1" width="1" height="1" alt=""><hr><p><a href="https://medium.com/superteams-ai-blog/steps-to-build-rag-application-with-gemma-7b-llm-43f7251a36a1">Steps to Build RAG Application with Gemma 7B LLM</a> was originally published in <a href="https://medium.com/superteams-ai-blog">Superteams.ai</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Build an Advanced AI-Powered Enterprise Content Pipeline Using Mixtral 8x7B and Qdrant]]></title>
            <link>https://medium.com/superteams-ai-blog/how-to-build-an-advanced-ai-powered-enterprise-content-pipeline-using-mixtral-8x7b-and-qdrant-b01aa66e3884?source=rss-f6c4eb90254------2</link>
            <guid isPermaLink="false">https://medium.com/p/b01aa66e3884</guid>
            <category><![CDATA[diffbot]]></category>
            <category><![CDATA[qdrant]]></category>
            <category><![CDATA[rags]]></category>
            <category><![CDATA[mixtral-8x7b]]></category>
            <category><![CDATA[llamaindex]]></category>
            <dc:creator><![CDATA[Akriti Upadhyay]]></dc:creator>
            <pubDate>Mon, 19 Feb 2024 01:15:41 GMT</pubDate>
            <atom:updated>2024-02-23T09:06:11.311Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*1DovHVUzqtSMd9_M" /></figure><h3>Introduction</h3><p>As the digital landscape rapidly evolves, enterprises are facing the challenge of managing and harnessing the exponential growth of data to drive business success. With the expansion of volume and complexity of content, traditional content management approaches are failing to provide the agility and intelligence required to scale or extract valuable insights.</p><p>The integration of vector databases and the mixture of experts, such as Mixtral 8x7B LLM, offers a transformative solution for enterprises seeking to unlock the full potential of their content pipelines. In this blog post, we will explore the essential components and strategies for building an advanced AI-powered enterprise content pipeline using Mixtral 8x7B and Qdrant — an advanced vector database following the HNSW algorithm for approximate nearest neighbor search.</p><p>To build the advanced AI-powered pipeline, we’ll leverage a Retrieval Augmented Generation (RAG) pipeline by following these steps:</p><ol><li>Loading the Dataset using LlamaIndex</li><li>Embedding Generation using Hugging Face</li><li>Building the Model using Mixtral 8x7B</li><li>Storing the Embedding in the Vector Store</li><li>Building a Retrieval pipeline</li><li>Querying the Retriever Query Engine</li></ol><p>Let’s get started!</p><h3>Enterprise Content Generation with Mixtral 8x7B</h3><p>To build a RAG pipeline with Mixtral 8x7B, we’ll install the following dependencies:</p><pre>%pip install -q llama-index==0.9.3 qdrant-client transformers[torch]</pre><h4>Loading the Dataset Using LlamaIndex</h4><p>For the dataset, we have used Diffbot Knowledge Graph API. Diffbot is a sophisticated web scraping and data extraction tool that utilizes artificial intelligence to automatically retrieve and structure data from web pages. Unlike traditional web scraping methods that rely on manual programming to extract specific data elements, Diffbot uses machine learning algorithms to comprehend and interpret web content much like a human would. This allows Diffbot to accurately identify and extract various types of data, including articles, product details, and contact information, from a wide range of websites.</p><p>One of the standout features of Diffbot is its Knowledge Graph Search, which organizes the extracted data into a structured database known as a knowledge graph. A knowledge graph is a powerful representation of interconnected data that enables efficient searching, querying, and analysis. Diffbot’s Knowledge Graph Search not only extracts individual data points from web pages but also establishes relationships between them by creating a comprehensive network of information.</p><p>To get the URL, make an account on <a href="https://www.diffbot.com/">Diffbot</a>. Go to Knowledge Graph, and Search. Here we have used Organization in the Visual, and filtered by Industries-&gt;Pharmaceutical Companies.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*53icVt1P8fUZDlno" /></figure><p>Then, we chose GSK, which is a renowned pharmaceutical company, and clicked Articles.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1020/0*IOEsAlewnfHXQ77D" /></figure><p>After clicking Articles, we got an option to export it as CSV or make an API call.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*oqTAPLulRxu4BDG8" /></figure><p>We made an API call and used that URL to access the data in Python.</p><pre>import requests<br>import json<br># The Diffbot API URL<br>url = &quot;https://kg.diffbot.com/&lt;your-url&gt;&quot;<br># Make a GET request to the API<br>response = requests.get(url)<br># Parse the response text as JSON<br>data = response.json()<br># Open a file in write mode<br>with open(&#39;json/response_text.json&#39;, &#39;w&#39;) as file:<br> # Write the data to the file as JSON<br> json.dump(data, file)<br>print(&quot;Response text has been saved to &#39;json/response_text.json&#39;.&quot;)</pre><p>The data is saved now in a JSON file. Using LlamaIndex Simple Directory Reader, we will load the data from the “json” directory.</p><pre>from llama_index.core import SimpleDirectoryReader<br>documents = SimpleDirectoryReader(&quot;/home/akriti/Notebooks/json&quot;).load_data()</pre><p>Now, it’s time to split the documents into chunks using Sentence Splitter.</p><pre>from llama_index.node_parser.text import SentenceSplitter<br># Create a SentenceSplitter object with a specified chunk size<br>text_parser = SentenceSplitter(chunk_size=1024)<br># Initialize empty lists to store text chunks and corresponding document indexes<br>text_chunks = []<br>doc_idxs = []<br># Iterate over each document in the &#39;documents&#39; list along with its index<br>for doc_idx, doc in enumerate(documents):<br> # Split the text of the current document into smaller chunks using the SentenceSplitter<br> cur_text_chunks = text_parser.split_text(doc.text)<br> <br> # Extend the list of text chunks with the chunks from the current document<br> text_chunks.extend(cur_text_chunks)<br> <br> # Extend the list of document indexes with the index of the current document,<br> # repeated for each corresponding text chunk<br> doc_idxs.extend([doc_idx] * len(cur_text_chunks))</pre><p>After that, we will create a Text Node object where we will assign the metadata of the source document to the metadata attribute of the node so that the relationships between them can be managed easily.</p><pre># Import the TextNode class from the llama_index schema module<br>from llama_index.schema import TextNode<br># Initialize an empty list to store nodes<br>nodes = []<br># Iterate over each index and text chunk in the text_chunks list<br>for idx, text_chunk in enumerate(text_chunks):<br> # Create a new TextNode object with the current text chunk<br> node = TextNode(text=text_chunk)<br> <br> # Retrieve the corresponding source document using the document index from doc_idxs<br> src_doc = documents[doc_idxs[idx]]<br> <br> # Assign the metadata of the source document to the metadata attribute of the node<br> node.metadata = src_doc.metadata<br> <br> # Append the node to the list of nodes<br> nodes.append(node)</pre><h4>Embedding Generation Using Hugging Face</h4><p>There are many supported embedding tool integrations with LlamaIndex; here we are moving forward with the Hugging Face Embedding tool.</p><pre># Import the HuggingFaceEmbedding class from the llama_index embeddings module<br>from llama_index.embeddings import HuggingFaceEmbedding<br># Initialize a HuggingFaceEmbedding object with the specified model name<br>embed_model = HuggingFaceEmbedding(model_name=&quot;BAAI/bge-small-en&quot;)<br># Iterate over each node in the nodes list<br>for node in nodes:<br> # Get the content of the node along with its metadata<br> content_with_metadata = node.get_content(metadata_mode=&quot;all&quot;)<br> <br> # Use the embedding model to get the text embedding for the node&#39;s content<br> node_embedding = embed_model.get_text_embedding(content_with_metadata)<br> <br> # Assign the computed embedding to the embedding attribute of the node<br> node.embedding = node_embedding</pre><h4>Building the Model Using Mixtral 8x7B</h4><p>Mixtral 8x7B is a cutting-edge language model developed by Mistral AI. It is a sparse mixture of experts (MOE) model with open weights. It is designed to offer powerful AI capabilities by integrating elements from BERT, RoBERTa, and GPT-3. This model represents a significant advancement in natural language processing by providing a practical and accessible solution for various applications.</p><p>Mixtral 8x7B employs a Mixture of Experts (MoE) architecture and is a decoder-only model. In this architecture, each layer consists of 8 feedforward blocks, referred to as experts. During processing, a router network dynamically selects two experts for each token at every layer, which enables effective information processing and aggregation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/577/0*ayNhveylVLDTCq1A" /><figcaption>Source: <a href="https://arxiv.org/pdf/2401.04088.pdf">Mixtral of Experts</a></figcaption></figure><p>One of Mixtral 8x7B’s standout features is its exceptional performance, characterized by high-quality outputs across diverse tasks. The model is pre-trained with multilingual data using a context size of 32k tokens. It outperforms Llama 2 and GPT-3.5 on most benchmarks but, in some cases, it matches Llama 2 and the GPT-3.5 model.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/587/0*K6Z3SLLt7enUiH75" /><figcaption>Source: <a href="https://arxiv.org/pdf/2401.04088.pdf">Mixtral of Experts</a></figcaption></figure><p>Mixtral 8x7B is also available in an Instruct form, which is supervised and fine-tuned on an instruction-following dataset, and optimized through Direct Preference Optimization (DPO) training. To know more about Mixtral 8x7B in detail, visit this <a href="https://arxiv.org/pdf/2401.04088.pdf">paper</a>.</p><p>Using Hugging Face and LlamaIndex, we will load the model.</p><pre>import torch<br>from llama_index.llms import HuggingFaceLLM<br># Instantiate a HuggingFaceLLM object with specified parameters<br>llm = HuggingFaceLLM(<br> context_window=4096, # Maximum context window size<br> max_new_tokens=256, # Maximum number of new tokens to generate<br> generate_kwargs={&quot;temperature&quot;: 0.7, &quot;do_sample&quot;: False}, # Generation settings<br> tokenizer_name=&quot;mistralai/Mixtral-8x7B-v0.1&quot;, # Pre-trained tokenizer name<br> model_name=&quot;mistralai/Mixtral-8x7B-v0.1&quot;, # Pre-trained model name<br> device_map=&quot;auto&quot;, # Automatic device mapping<br> stopping_ids=[50278, 50279, 50277, 1, 0], # Tokens to stop generation<br> tokenizer_kwargs={&quot;max_length&quot;: 4096}, # Tokenizer arguments<br> model_kwargs={&quot;torch_dtype&quot;: torch.float16} # Model arguments<br>)</pre><p>After that, we will create a service context with the loaded LLM and the embedding model.</p><pre>from llama_index import ServiceContext<br>service_context = ServiceContext.from_defaults(llm=llm, embed_model=embed_model)</pre><h4>Storing the Embedding in the Vector Store</h4><p>Here, we have used the Qdrant Vector Database to store the embeddings. <a href="https://qdrant.tech/">Qdrant </a>is a high-performance open-source vector search engine designed to efficiently index and search through large collections of high-dimensional vectors. It’s particularly well-suited for use cases involving similarity search, where the goal is to find items that are most similar to a query vector within a large dataset.</p><p>We will initiate the Qdrant Client first, and create a collection by enabling hybrid search.</p><pre>import qdrant_client<br>from llama_index.vector_stores.qdrant import QdrantVectorStore<br>from llama_index.core import StorageContext<br>from llama_index.core import VectorStoreIndex, ServiceContext, SimpleDirectoryReader<br># Initialize Qdrant client<br>client = qdrant_client.QdrantClient(location=&quot;:memory:&quot;)<br># Create Qdrant vector store<br>vector_store = QdrantVectorStore(client=client, collection_name=&quot;my_collection&quot;,enable_hybrid=True)</pre><p>We will add the node to the vector store and create a storage context. Also, we will create an index where we will use documents, service context, and storage context.</p><pre># Add nodes to the vector store<br>vector_store.add(nodes)<br># Create a storage context<br>storage_context = StorageContext.from_defaults(vector_store=vector_store)<br>index = VectorStoreIndex.from_documents(documents, storage_context=storage_context, service_context=service_context)</pre><p>We will then use a query and embedding model to create a query embedding, which we will use later as a reference.</p><pre>query_str = &quot;Can you update me about shingles vaccine?&quot;<br>query_embedding = embed_model.get_query_embedding(query_str)</pre><p>Using hybrid query mode, we will create a vector store query using LlamaIndex, where we will use the query embedding and save the query result.</p><pre>from llama_index.vector_stores import VectorStoreQuery<br>query_mode = &quot;hybrid&quot;<br>vector_store_query = VectorStoreQuery(query_embedding=query_embedding, similarity_top_k=2, mode=query_mode)<br>query_result = vector_store.query(vector_store_query)</pre><p>Then, we will parse the query result into the set of nodes.</p><pre>from llama_index.schema import NodeWithScore<br>from typing import Optional<br>nodes_with_scores = []<br>for index, node in enumerate(query_result.nodes):<br> score: Optional[float] = None<br> if query_result.similarities is not None and index &lt; len(query_result.similarities):<br> score = query_result.similarities[index]<br> nodes_with_scores.append(NodeWithScore(node=node, score=score))</pre><h4>Building a Retrieval Pipeline</h4><p>For building a retrieval pipeline, we’ll use the above to create a retriever class.</p><pre>from llama_index import QueryBundle<br>from llama_index.retrievers import BaseRetriever<br>from typing import Any, List, Optional<br>from llama_index.vector_stores import VectorStoreQuery<br>from llama_index.schema import NodeWithScore<br>class VectorDBRetriever(BaseRetriever):<br> &quot;&quot;&quot;Retriever over a qdrant vector store.&quot;&quot;&quot;<br> def __init__(self,<br> vector_store: QdrantVectorStore,<br> embed_model: Any,<br> query_mode: str = &quot;hybrid&quot;,<br> similarity_top_k: int = 2) -&gt; None:<br> &quot;&quot;&quot;Initialize parameters.&quot;&quot;&quot;<br> self._vector_store = vector_store<br> self._embed_model = embed_model<br> self._query_mode = query_mode<br> self._similarity_top_k = similarity_top_k<br> super().__init__()<br> <br> def _retrieve(self, query_bundle: QueryBundle) -&gt; List[NodeWithScore]:<br> &quot;&quot;&quot;Retrieve.&quot;&quot;&quot;<br> query_embedding = self._embed_model.get_query_embedding(query_bundle.query_str)<br> vector_store_query = VectorStoreQuery(<br> query_embedding=query_embedding,<br> similarity_top_k=self._similarity_top_k,<br> mode=self._query_mode,<br> )<br> query_result = self._vector_store.query(vector_store_query)<br> nodes_with_scores = []<br> for index, node in enumerate(query_result.nodes):<br> score: Optional[float] = None<br> if query_result.similarities is not None and index &lt; len(query_result.similarities):<br> score = query_result.similarities[index]<br> nodes_with_scores.append(NodeWithScore(node=node, score=score))<br> return nodes_with_scores<br><br>retriever = VectorDBRetriever(<br> vector_store, embed_model, query_mode=&quot;hybrid&quot;, similarity_top_k=2<br>)</pre><p>Finally, our query engine will be ready with the help of Retriever Query Engine.</p><pre>from llama_index.query_engine import RetrieverQueryEngine<br>query_engine = RetrieverQueryEngine.from_args(<br> retriever, service_context=service_context<br>)from llama_index.query_engine import RetrieverQueryEngine<br>query_engine = RetrieverQueryEngine.from_args(<br> retriever, service_context=service_context<br>)</pre><h4>Querying the Retriever Query Engine</h4><p>As our query engine is ready, now is the time to pass some queries and see some results.</p><p><strong>Question 1:</strong></p><pre>query_str = &quot;Write a paragraph about GSK announcement about its shares.&quot;<br>response = query_engine.query(query_str)<br>print(str(response))</pre><p>The response will be:</p><pre>GSK plc announced the completion of its share consolidation on July 18, 2022. This followed the demerger of the Consumer Healthcare business from the GSK Group to form Haleon. The consolidation of GSK shares became effective at 8.00 a.m. on July 19, 2022. As part of the consolidation, a ratio of 4 new ordinary shares was applied for every 5 existing ordinary shares. Fractional entitlements that arose from the consolidation were aggregated and sold in the open market, with the net proceeds paid to each relevant shareholder according to their entitlement. Following the issuance and consolidation, the total number of voting rights in GSK as of July 19, 2022, was 4,067,352,076.</pre><p><strong>Question 2:</strong></p><pre>query_str = &quot;Write a paragraph about GSK&#39;s RSV vaccine.&quot;<br>response = query_engine.query(query_str)<br>print(str(response))</pre><p>The response will be:</p><pre>GSK&#39;s Arexvy is the world&#39;s first respiratory syncytial virus (RSV) vaccine for older adults. The US Food and Drug Administration (FDA) approved Arexvy for the prevention of lower respiratory tract disease (LRTD) caused by RSV in individuals 60 years of age and older. This groundbreaking approval enables adults aged 60 years and older to be protected from RSV disease for the first time. The approval is based on data from the positive pivotal AReSVi-006 phase III trial that showed exceptional efficacy in older adults, including those with underlying medical conditions, and in those with severe RSV disease. The US launch was planned before the 2023/24 RSV season. RSV is a common, contagious virus that can lead to potentially serious respiratory illness. It causes approximately 177,000 hospitalizations and an estimated 14,000 deaths in the US in adults aged 65 years and older each year.</pre><p><strong>Question 3:</strong></p><pre>query_str = &quot;Write a paragraph about GSK&#39;s Endrometrial Cancer Drug Development.&quot;<br>response = query_engine.query(query_str)<br>print(str(response))</pre><p>The response will be:</p><pre>GSK has made significant improvement in the development of drugs for endometrial cancer. Their drug, Jemperli (dostarlimab), has been approved by the European Commission and the US Food and Drug Administration (FDA) for the treatment of adult patients with mismatch repair-deficient (dMMR)/microsatellite instability-high (MSI-H) primary advanced or recurrent endometrial cancer. Jemperli, in combination with carboplatin and paclitaxel (chemotherapy), is the first and only frontline immuno-oncology treatment in the European Union for this type of endometrial cancer. The FDA has also granted accelerated approval for Jemperli as a monotherapy for treating adult patients with dMMR/MSI-H recurrent or advanced endometrial cancer that has progressed on or following prior treatment with a platinum-containing regimen. This approval is based on the results from the dMMR/MSI-H population of Part 1 of the RUBY/ENGOT-EN6/GOG3031/NSGO phase III trial. GSK continues to evaluate Jemperli in the hopes of further expansion for the drug as data mature.</pre><p><strong>Question 4:</strong></p><pre>query_str = &quot;Write a paragraph about GSK&#39;s Hepatocellular Carcinoma Drug Development.&quot;<br>response = query_engine.query(query_str)<br>print(str(response))</pre><p>The response will be:</p><pre>GSK is making significant progress in the development of drugs for hepatocellular carcinoma (HCC). One of their drugs, Cobolimab, is currently in Phase II clinical trials for HCC. Cobolimab is a humanized monoclonal IgG4 antibody that inhibits T cell immunoglobulin mucin-3 (TIM-3), and is under development for the treatment of solid tumors including melanoma, squamous and non-squamous non-small cell lung carcinoma, HCC, and colorectal cancer. It is administered through the intravenous route. The drug&#39;s phase transition success rate (PTSR) and likelihood of approval (LoA) are being closely monitored. GSK&#39;s efforts in this area demonstrate their commitment to advancing treatments for HCC.</pre><p><strong>Question 5:</strong></p><pre>query_str = &quot;Write a paragraph about GSK&#39;s Uncomplicated Cervical And Urethral Gonorrhea Drug Development.&quot;<br>response = query_engine.query(query_str)<br>print(str(response))</pre><p>The response will be:</p><pre>GSK is currently developing a potential first-in-class antibiotic, Gepotidacin, for the treatment of uncomplicated cervical and urethral gonorrhea. This drug is in Phase III of clinical development. Gepotidacin is the first in a new chemical class of antibiotics called triazaacenaphthylene bacterial topoisomerase inhibitors. It is being investigated for use in uncomplicated urinary tract infection and urogenital gonorrhea, two infections not addressed by new oral antibiotics in 20 years. The Phase III programme comprises two studies, EAGLE-1 and EAGLE-2, testing Gepotidacin in two common infections caused by bacteria identified as antibiotic-resistant threats. The development of Gepotidacin is the result of a successful public-private partnership between GSK, the US government&#39;s Biomedical Advanced Research and Development Authority (BARDA), and Defense Threat Reduction Agency (DTRA).</pre><h3>Conclusion</h3><p>With the help of the LlamaIndex framework, we used Diffbot API to extract enterprise content that was related to a pharmaceutical company, GSK. Using Hugging Face embeddings, Qdrant Vector Store, and Mixtral 8x7B, the retrieval pipeline was built. The results obtained using the retrieval query engine were quite fascinating. Building an advanced AI-powered enterprise content pipeline has become easy with the help of Mixtral 8x7B.</p><p>Thanks for Reading!</p><h3>References</h3><p><a href="https://arxiv.org/pdf/2401.04088.pdf">https://arxiv.org/pdf/2401.04088.pdf</a></p><p><a href="https://docs.diffbot.com/docs/getting-started-with-diffbot-knowledge-graph">https://docs.diffbot.com/docs/getting-started-with-diffbot-knowledge-graph</a></p><p><a href="https://docs.llamaindex.ai/en/stable/examples/low_level/oss_ingestion_retrieval.html">https://docs.llamaindex.ai/en/stable/examples/low_level/oss_ingestion_retrieval.html</a></p><h3>About Superteams.ai</h3><p>Superteams.ai connects top AI talent with companies seeking accelerated product and content development. These “Superteamers” offer individual or team-based solutions for projects involving cutting-edge technologies like LLMs, image synthesis, audio or voice synthesis, and other cutting-edge open-source AI solutions. With over 500 AI researchers and developers, Superteams has facilitated diverse projects like 3D e-commerce model generation, advertising creative generation, enterprise-grade RAG pipelines, geospatial applications, and more. Focusing on talent from India and the global South, Superteams offers competitive solutions for companies worldwide. To explore partnership opportunities, please write to <a href="/service/mailto:founders@superteams.ai">founders@superteams.ai</a> or visit this <a href="https://www.superteams.ai/demo">link</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b01aa66e3884" width="1" height="1" alt=""><hr><p><a href="https://medium.com/superteams-ai-blog/how-to-build-an-advanced-ai-powered-enterprise-content-pipeline-using-mixtral-8x7b-and-qdrant-b01aa66e3884">How to Build an Advanced AI-Powered Enterprise Content Pipeline Using Mixtral 8x7B and Qdrant</a> was originally published in <a href="https://medium.com/superteams-ai-blog">Superteams.ai</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Steps to Build Chinese Language AI Using DeepSeek and Qdrant]]></title>
            <link>https://medium.com/@akriti.upadhyay/steps-to-build-chinese-language-ai-using-deepseek-and-qdrant-74e5cda604c0?source=rss-f6c4eb90254------2</link>
            <guid isPermaLink="false">https://medium.com/p/74e5cda604c0</guid>
            <category><![CDATA[qdrant]]></category>
            <category><![CDATA[news-search]]></category>
            <category><![CDATA[llamaindex]]></category>
            <category><![CDATA[deepseek-llm]]></category>
            <category><![CDATA[fastembed]]></category>
            <dc:creator><![CDATA[Akriti Upadhyay]]></dc:creator>
            <pubDate>Tue, 13 Feb 2024 04:18:28 GMT</pubDate>
            <atom:updated>2024-02-13T04:18:28.319Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*maB94ZJyR7_ByDl5" /></figure><h3>Introduction</h3><p>As we step into the Chinese New Year — the Year of the Dragon — in 2024, I thought: why not build a Chinese News AI using DeepSeek and Qdrant? Especially so because, though LLMs are becoming vast in size and complexity, there are still a range of challenges in building an accurate and efficacious language AI beyond the English Language. In this context, DeepSeek LLM has embarked on a long-term project to overcome the inaccuracies in language application. DeepSeek LLM excels in the Chinese language, and here we’ll see how it performs while fetching news from a Chinese news dataset. We’ll utilize LlamaIndex, FastEmbed by Qdrant, and Qdrant Vector Store to develop an application where we can understand Chinese news with a robust RAG.</p><p><em>Let’s dive deeper!</em></p><h3>DeepSeek LLM: An Open-Source Language Model with Longtermism</h3><p>DeepSeek LLM is an advanced language model that has developed different models including Base and Chat. It has been trained from scratch on a dataset of 2 trillion tokens in both English and Chinese. In terms of size, there are two varieties of DeepSeek LLM models: one comprises 7 billion parameters and the other, 67 billion parameters.</p><p>The 7B model uses Multi-Head Attention, while the 67B model uses Grouped-Query Attention. These variants operate on the same architecture as the Llama 2 model, which is an autoregressive transformer decoder model.</p><p>DeepSeek LLM is a project dedicated to advancing open-source large language models in the long-term perspective. However, DeepSeek LLM 67B outperforms Llama 2 70B in various domains such as reasoning, mathematics, coding, and comprehension. Compared to other models, including GPT 3.5, DeepSeek LLM excels in Chinese language proficiency.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ZAqda49LtMno3UnC" /></figure><p>The alignment pipeline of DeepSeek LLM consists of two stages:</p><ol><li><strong>Supervised Fine-Tuning:</strong> The 7B model is fine-tuned for 4 epochs, while the 67B model is fine-tuned for 2 epochs. During supervised fine-tuning, the learning rate for the 7B model is 1e-5, while for the 67B model it is 5e-6. The repetition ratio of the model tends to increase when the quantity of math SFT data increases, although the math SFT data includes similar patterns in reasoning.</li><li><strong>Direct Preference Optimization:</strong> To address the repetition problem, the model’s ability was enhanced using DPO training, which proved to be an effective method for LLM alignment. The preference data for DPO training is constructed in terms of helpfulness and harmlessness.</li></ol><p>The model, along with all its variants, is available on <a href="https://huggingface.co/deepseek-ai">Hugging Face</a>. To learn more about DeepSeek LLM, visit their <a href="https://arxiv.org/pdf/2401.02954.pdf">paper </a>and <a href="https://github.com/deepseek-ai/DeepSeek-LLM">Github repository</a>.</p><h3>Qdrant: A High-Performance Vector Database</h3><p>Qdrant is an open-source vector database and vector similarity search engine written in Rust, engineered to empower the next generation of AI applications with advanced and high-performing vector similarity search technology. Its key features include multilingual support, which enables versatility across various data types, and filters for a wide array of applications.</p><p>Qdrant boasts speed and accuracy through a custom modification of the HNSW algorithm for Approximate Nearest Neighbor Search, which ensures state-of-the-art search capabilities by maintaining precise results. Moreover, it supports additional payload associated with vectors by allowing filterable results based on payload values. With a rich array of supported data types and query conditions, including string matching, numerical ranges, and geo-locations, Qdrant offers versatility in data management.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*1kD8CuJ7Yni23nY-" /></figure><p>As a cloud-native and horizontally scalable platform, Qdrant efficiently handles data scaling needs by effectively utilizing computational resources through dynamic query planning and payload data indexing. Its applications include semantic text search, recommendations, user behavior analysis, and more, which offers a production-ready service with a convenient API for storing, searching, and managing vectors along with additional payload. For further details, the <a href="https://qdrant.tech/documentation/">Qdrant Documentation</a> provides a comprehensive guide on installation, usage, tutorials, and examples.</p><h3>Utilizing FastEmbed for Lightweight Embedding Generation</h3><p>FastEmbed is a lightweight, fast, and accurate Python library built specifically for embedding generation, with maintenance overseen by <a href="https://qdrant.tech/">Qdrant</a>. It achieves efficiency and speed through the utilization of quantized model weights and ONNX Runtime, which sidesteps the necessity for a PyTorch dependency.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/663/0*3oBuldKLk6fVuEsf" /></figure><p>FastEmbed supports data parallelism for encoding vast datasets efficiently and is engineered with a CPU-centric approach. Moreover, it excels in accuracy and recall metrics compared to OpenAI Ada-002 by boasting the Flag Embedding as its default model, which leads the MTEB leaderboard. It also supports Jina Embedding and Text Embedding. There are several popular text models supported by FastEmbed. To learn more about the supported models, visit <a href="https://qdrant.github.io/fastembed/examples/Supported_Models/">here</a>.</p><h3>LlamaIndex Framework for Robust RAG</h3><p>LlamaIndex is a robust framework ideally suited for constructing Retrieval-Augmented Generation (RAG) applications. It facilitates the decoupling of chunks used for retrieval and synthesis, which is a crucial feature because the optimal representation for retrieval may differ from that for synthesis. As document volumes expand, LlamaIndex supports structured retrieval by ensuring more precise outcomes, particularly when a query is only relevant to a subset of documents.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/0*rZlWKBo453-EdY6m" /></figure><p>Moreover, LlamaIndex prioritizes optimized performance by offering an array of strategies to enhance the RAG pipeline efficiently. It aims to elevate retrieval and generation accuracy across complex datasets by mitigating hallucinations. LlamaIndex supports many embedding models as well as integration with large language models. Additionally, it seamlessly integrates with established technological platforms like LangChain, Flask, and Docker, which offers customization options such as seeding tree construction with custom summary prompts.</p><h3>Understanding Chinese News with DeepSeek</h3><p>Since DeepSeek LLM excels in Chinese language proficiency, let’s build a Chinese News AI using Retrieval Augmented Generation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*RCDiIEKREwNbxjTd" /></figure><p>To get started, let’s install all the dependencies.</p><pre>%pip install -q llama-index transformers datasets<br>%pip install -q llama-cpp-python<br>%pip install -q qdrant-client<br>%pip install -q llama_hub<br>%pip install -q fastembed</pre><p>Here, I have used this <a href="https://huggingface.co/datasets/intfloat/multilingual_cc_news">dataset</a>; it is a multilingual news dataset. I have picked the Chinese language. Load the dataset and save it to your directory. We’ll be using LlamaIndex to read the data with SimpleDirectoryReader.</p><pre>from datasets import load_dataset<br>dataset = load_dataset(&quot;intfloat/multilingual_cc_news&quot;, languages=[&quot;zh&quot;], split=&quot;train&quot;)<br>dataset.save_to_disk(&quot;Notebooks/dataset&quot;)</pre><p>Now, using LlamaIndex, load the data from the directory where we saved our dataset.</p><pre>from llama_index import SimpleDirectoryReader<br>documents = SimpleDirectoryReader(&quot;Notebooks/dataset&quot;).load_data()</pre><p>After that, split the documents into small chunks using SentenceSplitter. Here, we need to maintain the relationship between the document and the source document index so that it helps in injecting the document metadata.</p><pre>from llama_index.node_parser.text import SentenceSplitter<br>text_parser = SentenceSplitter(chunk_size=1024,)<br>text_chunks = []<br>doc_idxs = []<br>for doc_idx, doc in enumerate(documents):<br> cur_text_chunks = text_parser.split_text(doc.text)<br> text_chunks.extend(cur_text_chunks)<br> doc_idxs.extend([doc_idx] * len(cur_text_chunks))</pre><p>Then, we’ll construct nodes from text chunks manually.</p><pre>from llama_index.schema import TextNode<br>nodes = []<br>for idx, text_chunk in enumerate(text_chunks):<br> node = TextNode(text=text_chunk,)<br> src_doc = documents[doc_idxs[idx]]<br> node.metadata = src_doc.metadata<br> nodes.append(node)</pre><p>For each node, we’ll generate embeddings using the FastEmbed Embedding model.</p><pre>from llama_index.embeddings import FastEmbedEmbedding<br>embed_model = FastEmbedEmbedding(model_name=&quot;BAAI/bge-small-en-v1.5&quot;)<br>for node in nodes:<br> node_embedding = embed_model.get_text_embedding(node.get_content(metadata_mode=&quot;all&quot;))<br> node.embedding = node_embedding</pre><p>Now, it’s time to load the DeepSeek LLM using HuggingFaceLLM from LlamaIndex. Here, I used the <a href="https://huggingface.co/deepseek-ai/deepseek-llm-7b-chat">chat model</a>.</p><pre>from llama_index.llms import HuggingFaceLLM<br>llm = HuggingFaceLLM(<br> context_window=4096,<br> max_new_tokens=256,<br> generate_kwargs={&quot;temperature&quot;: 0.7, &quot;do_sample&quot;: False},<br> tokenizer_name=&quot;deepseek-ai/deepseek-llm-7b-chat&quot;,<br> model_name=&quot;deepseek-ai/deepseek-llm-7b-chat&quot;,<br> device_map=&quot;auto&quot;,<br> stopping_ids=[50278, 50279, 50277, 1, 0],<br> tokenizer_kwargs={&quot;max_length&quot;: 4096},<br> model_kwargs={&quot;torch_dtype&quot;: torch.float16}<br>)</pre><p>Then, we’ll define the ServiceContext, which consists of the embedding model and the large language model.</p><pre>from llama_index import ServiceContext<br>service_context = ServiceContext.from_defaults(llm=llm, embed_model=embed_model)</pre><p>After that, we’ll create a vector store collection using the Qdrant vector database and create a storage context using the vector store collection.</p><pre>import qdrant_client<br>from llama_index.vector_stores.qdrant import QdrantVectorStore<br>client = qdrant_client.QdrantClient(location=&quot;:memory:&quot;)<br>from llama_index.storage.storage_context import StorageContext<br>from llama_index import (VectorStoreIndex,<br> ServiceContext,<br> SimpleDirectoryReader,)<br>vector_store = QdrantVectorStore(client=client, collection_name=&quot;my_collection&quot;)<br>vector_store.add(nodes)<br>storage_context = StorageContext.from_defaults(vector_store=vector_store)</pre><p>We’ll pass the documents, storage context, and service context into the VectorStoreIndex.</p><pre>index = VectorStoreIndex.from_documents(documents, storage_context=storage_context, service_context=service_context)</pre><p>We’ll generate a query embedding using a query string to build a retrieval pipeline.</p><pre>query_str = &quot;Can you give me news around IPhone?&quot;<br>query_embedding = embed_model.get_query_embedding(query_str)</pre><p>Then, we’ll construct a Vector Store query and query the vector database.</p><pre>from llama_index.vector_stores import VectorStoreQuery<br>query_mode = &quot;default&quot;<br>vector_store_query = VectorStoreQuery(query_embedding=query_embedding, similarity_top_k=2, mode=query_mode)<br>query_result = vector_store.query(vector_store_query)<br>print(query_result.nodes[0].get_content())</pre><p>The following will be the result:</p><pre>8%，僅排名第五，位居華為、OPPO和Vivo等本土手機廠商之後 - - 這三家中國手機廠商的市場份額加起來達到47%。<br>普遍對iPhone 8更期待<br>除此之外，即將發布的iPhone 7恐怕會成為大獲成功的iPhone 6的&quot;犧牲品&quot;。去年第一季度，得益於iPhone 6銷量激增，蘋果在中國的營收增長了74%。一年後，由於iPhone 6S銷量疲軟，蘋果在全球的iPhone銷量首次出現下滑，而公司營收更是出現13年來的首次滑坡，盡管根據市場研究機構Strategy Analytics的數據，iPhone 6S是今年第二季度全球最暢銷的智能手機。<br>到目前為止，新浪微博網友對iPhone 7發布的討論，已經超過了去年iPhone 6S發布前的熱度。部分中國用戶甚至已經開始盤算著購買有望於明年發布的iPhone8。鑒於2017年是iPhone上市十周年，外界預計iPhone 8將作出更大的升級。<br>由於投資者擔心iPhone銷量已過巔峰，蘋果股價在今年始終承受著壓力。盡管今年以來蘋果股價累計上漲了2.35%，但仍然落後於標准普爾500指數的平均漲幅。<br>市場研究機構Stratechery科技行業分析師本·湯普森（Ben Thompson）說：&quot;相比2014年，今天最大的變化就是iPhone已無處不在。當人們第一次獲得購買iPhone的機會時，它還有巨大的增長空間，但如今那種潛力已經得到充分挖掘。&quot;◎ 陳國雄<br>美國在1978年立法制定國際銀行法(International Banking Act of 1978)，該法將外國銀行業納入與國內銀行相同準則。在此之前，外國銀行設立係依據州法沒有一致性。<br>1978年制定國際銀行法後，外國銀行設立採雙規制(Dual System)，可向聯邦銀行管理機構OCC (Office of the Comptroller of the Currency)或州銀行 (State Banking Department)當局申請，如果向州申請設立毋須經過聯邦銀行同意。到了1991年外國銀行在美迅速成長，大約有280家外國銀行，資產值達6,260億美元，佔美國銀行總資產18%，大部份是依州法設立。</pre><p>The response is:</p><blockquote>‘At 8 percent, it ranked fifth behind local handset makers Huawei, OPPO, and Vivo — the three Chinese handset makers with a combined market share of 47 percent.</blockquote><blockquote>Widespread anticipation for iPhone 8</blockquote><blockquote>On top of that, the upcoming iPhone 7 is feared to be a “casualty” of the hugely successful iPhone 6. In the first quarter of last year, Apple’s China revenue grew 74 percent, thanks to a surge in iPhone 6 sales. A year later, Apple’s global iPhone sales fell for the first time due to weak iPhone 6S sales, and the company’s revenue slipped for the first time in 13 years, even though the iPhone 6S was the world’s best-selling smartphone in the second quarter of this year, according to market researcher Strategy Analytics.</blockquote><blockquote>So far, discussions on Sina Weibo about the release of the iPhone 7 have surpassed the buzz surrounding the release of the iPhone 6S last year. Some Chinese users have even begun planning to buy the iPhone 8, which is expected to be released next year, and is expected to get even bigger upgrades given that 2017 marks the 10th anniversary of the iPhone’s launch.</blockquote><blockquote>As investors are worried that iPhone sales have peaked, Apple shares have been under pressure this year. Although Apple’s stock price has risen 2.35% since the beginning of the year, it still lags behind the average rate of increase of the Standard &amp; Poor’s 500 Index.</blockquote><blockquote>Market research organization Stratechery technology industry analyst Ben Thompson (Ben Thompson) said: “Compared to 2014, the biggest change today is that the iPhone is everywhere. When people first got the chance to buy an iPhone, there was huge room for growth, but today that potential has been fully realized.” ◎ Chen Guoxiong</blockquote><blockquote>The U.S. legislated the International Banking Act of 1978, which brought the foreign banking industry under the same criteria as domestic banks. Prior to that, foreign banks were established under state law with no consistency.</blockquote><blockquote>After the enactment of the International Banking Act of 1978, the establishment of foreign banks is based on a Dual System, which can be applied to the OCC (Office of the Comptroller of the Currency), the federal banking agency, or the State Banking Department (State Banking Department), and does not require the consent of the federal banking agency. The federal bank’s consent is not required if the application is made to a state. By 1991, foreign banks were growing rapidly in the U.S. There were about 280 foreign banks with assets of US$626 billion, accounting for 18% of total U.S. banking assets, most of which were established under state law.’</blockquote><p>Then we’ll parse the results into a set of nodes.</p><pre>from llama_index.schema import NodeWithScore<br>from typing import Optional<br>nodes_with_scores = []<br>for index, node in enumerate(query_result.nodes):<br> score: Optional[float] = None<br> if query_result.similarities is not None:<br> score = query_result.similarities[index]<br> nodes_with_scores.append(NodeWithScore(node=node, score=score))</pre><p>Now, using the above, we’ll create a retriever class.</p><pre>from llama_index import QueryBundle<br>from llama_index.retrievers import BaseRetriever<br>from typing import Any, List<br>class VectorDBRetriever(BaseRetriever):<br> &quot;&quot;&quot;Retriever over a qdrant vector store.&quot;&quot;&quot;<br> def __init__(self,<br> vector_store: QdrantVectorStore,<br> embed_model: Any,<br> query_mode: str = &quot;default&quot;,<br> similarity_top_k: int = 2) -&gt; None:<br> &quot;&quot;&quot;Init params.&quot;&quot;&quot;<br> self._vector_store = vector_store<br> self._embed_model = embed_model<br> self._query_mode = query_mode<br> self._similarity_top_k = similarity_top_k<br> super().__init__()<br> def _retrieve(self, query_bundle: QueryBundle) -&gt; List[NodeWithScore]:<br> &quot;&quot;&quot;Retrieve.&quot;&quot;&quot;<br> query_embedding = embed_model.get_query_embedding(<br> query_bundle.query_str<br> )<br> vector_store_query = VectorStoreQuery(<br> query_embedding=query_embedding,<br> similarity_top_k=self._similarity_top_k,<br> mode=self._query_mode,<br> )<br> query_result = vector_store.query(vector_store_query)<br> nodes_with_scores = []<br> for index, node in enumerate(query_result.nodes):<br> score: Optional[float] = None<br> if query_result.similarities is not None:<br> score = query_result.similarities[index]<br> nodes_with_scores.append(NodeWithScore(node=node, score=score))<br> return nodes_with_scores<br>retriever = VectorDBRetriever(<br> vector_store, embed_model, query_mode=&quot;default&quot;, similarity_top_k=2<br>)</pre><p>Then, create a retriever query engine.</p><pre>from llama_index.query_engine import RetrieverQueryEngine<br>query_engine = RetrieverQueryEngine.from_args(<br> retriever, service_context=service_context<br>)</pre><p>Finally, our retriever is ready to query and chat with. Let’s pass a query.</p><p>The query is: <em>“Tell me about South China Sea Issue.”</em></p><pre>query_str = &quot;告诉我南海问题&quot;<br>response = query_engine.query(query_str)<br>print(str(response))</pre><p>Following will be the response:</p><pre>南海问题是指涉及南海地区多个国家的主权和海洋权益争议的问题。该地区包括南海诸岛及其附近海域，涉及中国、菲律宾、越南、马来西亚、文莱和台湾等国家和地区。南海地区拥有丰富的油气资源，因此争议各方在该地区的领土和资源开发上存在分歧。中国主张对南海诸岛及其附近海域拥有主权，并提出&quot;九段线&quot;主张，而其他国家则对此持有不同看法。南海问题涉及复杂的政治、经济和安全利益，是地区和国际社会关注的焦点之一。</pre><p>The response is:</p><blockquote>‘South China Sea issues refer to issues involving disputes over the sovereignty and maritime rights and interests of multiple countries in the South China Sea region. This area includes the South China Sea Islands and their adjacent waters, involving countries and regions such as China, the Philippines, Vietnam, Malaysia, Brunei and Taiwan. The South China Sea is rich in oil and gas resources, so the parties to the dispute have differences over the territory and resource development in the area. China claims sovereignty over the South China Sea islands and adjacent waters and has proposed a “nine-dash line” claim, while other countries hold different views on this. The South China Sea issue involves complex political, economic, and security interests and is one of the focuses of attention of the regional and international communities.’</blockquote><h3>Conclusion</h3><p>DeepSeek LLM has performed very well in answering questions without facing challenges. Its architecture sets it apart from other models, and the most impressive aspect is its utilization of Direct Preference Optimization to enhance the model’s capabilities. It is a fine-tuned and optimized model in both Chinese and English languages, and we observed from the results how well such a fine-tuned and optimized model can perform.</p><p>We utilized FastEmbed and Qdrant for embedding generation and vector similarity search. Retrieval was fast using Qdrant. One of Qdrant’s most impressive features is its accessibility through Docker installation, on the cloud, and its in-memory capabilities. Qdrant is versatile in storing vector embeddings. It was intriguing for me to experiment with these tools.</p><p><em>Thanks for reading!</em></p><h3>References</h3><p><a href="https://arxiv.org/pdf/2401.02954.pdf">https://arxiv.org/pdf/2401.02954.pdf</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=74e5cda604c0" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>