<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: btkcodedev</title>
    <description>The latest articles on DEV Community by btkcodedev (@btkcodedev).</description>
    <link>https://dev.to/btkcodedev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F480146%2Fbc17c13a-a029-4372-b53c-b679ae2cd379.jpg</url>
      <title>DEV Community: btkcodedev</title>
      <link>https://dev.to/btkcodedev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/btkcodedev"/>
    <language>en</language>
    <item>
      <title>I Just Wanted a WhatsApp Channel That Teaches Me One German Word a Day. It Took a Week and a Git History Rewrite.</title>
      <dc:creator>btkcodedev</dc:creator>
      <pubDate>Sun, 16 Aug 2026 04:42:09 +0000</pubDate>
      <link>https://dev.to/btkcodedev/i-just-wanted-a-whatsapp-channel-that-teaches-me-one-german-word-a-day-it-took-a-week-and-a-git-3a5k</link>
      <guid>https://dev.to/btkcodedev/i-just-wanted-a-whatsapp-channel-that-teaches-me-one-german-word-a-day-it-took-a-week-and-a-git-3a5k</guid>
      <description>&lt;p&gt;Here's the thing nobody tells you about WhatsApp automation. The hard part was never the AI, and it was never the German. It was WhatsApp itself.&lt;/p&gt;

&lt;p&gt;I wanted something dumb simple: a WhatsApp Channel that posts one German word every morning, A1 level, with an example sentence and a mnemonic. Gemini can write that in a second. The actual project turned into an argument with WhatsApp's session model, two hosting platforms, and, at one point, my own repo's git history.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 43MB problem
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;whatsapp-web.js&lt;/code&gt; is the library most people reach for first. It drives a real headless Chrome instance that logs into web.whatsapp.com like your browser would, and it works, locally. The moment you try to deploy it, you hit the same wall everyone hits: the session it needs to stay logged in is a full Chromium profile. Cookies, IndexedDB, cache, the works. Mine was 43MB.&lt;/p&gt;

&lt;p&gt;GitHub Secrets cap out in the kilobytes. So the "obvious" fix, the one a dozen tutorials suggest, is: tar it, base64-encode it, shove it into a secret anyway, decode it back into place on every CI run. I actually did this. I had a script called &lt;code&gt;setup.ts&lt;/code&gt; whose entire job was printing a giant base64 blob for me to paste into GitHub's secret editor by hand.&lt;/p&gt;

&lt;p&gt;It's exactly as bad as it sounds, and it doesn't even solve the real problem, because that session expires. Not on a schedule you control. Whenever WhatsApp feels like it. Phone offline too long, and it's gone. Which means eventually you're back to scanning a QR code, except now you're doing it on a server that has no screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where do you even scan the QR on a headless box?
&lt;/h2&gt;

&lt;p&gt;This is the question I actually came in asking, because I genuinely didn't know. Turns out there are two real answers.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run the linking step once, locally, pointed at the &lt;em&gt;same&lt;/em&gt; database your deployed job uses. Scan it on your own laptop, and the session persists wherever you told it to.&lt;/li&gt;
&lt;li&gt;Or just watch your CI provider's live log stream. The QR prints as ASCII art, and you can scan a phone camera off a terminal on a screen, no problem.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Neither needs a screen physically attached to the server. I'd been overcomplicating this in my head for no reason.&lt;/p&gt;

&lt;h2&gt;
  
  
  Railway said no, and I didn't know why yet
&lt;/h2&gt;

&lt;p&gt;I had this deployed in three places at once: Railway, Render, GitHub, and none of them worked, and I couldn't figure out why. Turns out Railway's fair-use policy explicitly bans "userbots," anything that logs into a personal account via an unofficial, reverse-engineered protocol instead of a real bot API. &lt;code&gt;whatsapp-web.js&lt;/code&gt; is precisely that. It's not a bug I could fix. It's a platform I had to stop using for this.&lt;/p&gt;

&lt;p&gt;Render fared a little better, but I kept hitting a different, more annoying issue. &lt;code&gt;RemoteAuth&lt;/code&gt; with a Mongo-backed session store has open, unresolved GitHub issues where the session saves fine but doesn't reliably restore, silently forcing a fresh QR scan on restart. Not something I broke. Just a library with rough edges.&lt;/p&gt;

&lt;h2&gt;
  
  
  Baileys, and why it's what most of these channels actually run on
&lt;/h2&gt;

&lt;p&gt;The fix that actually stuck was switching libraries entirely, to &lt;a href="https://github.com/WhiskeySockets/Baileys" rel="noopener noreferrer"&gt;Baileys&lt;/a&gt;. It speaks WhatsApp's multi-device protocol directly over a WebSocket. No Chromium, no Puppeteer, nothing to render. The session is a handful of small JSON credential files, kilobytes, not tens of megabytes.&lt;/p&gt;

&lt;p&gt;That one change collapsed two separate problems at once. The session fits anywhere now (I put it in a free MongoDB Atlas cluster instead of a secret), and without a browser to spin up, the whole thing runs fine on a constrained free-tier box instead of choking on headless-Chrome memory pressure.&lt;/p&gt;

&lt;p&gt;It also made the hosting question moot. My actual requirement was "post one message a day," which doesn't need an always-on server at all. It needs about sixty seconds of compute, once every 24 hours. That's a GitHub Actions cron job, for free. I deleted the Dockerfile, deleted Render, deleted Railway, and the whole deployment surface became one YAML file with a &lt;code&gt;cron:&lt;/code&gt; line in it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The security scare I almost shipped
&lt;/h2&gt;

&lt;p&gt;Somewhere in the earlier, messier phase, I had committed a full &lt;code&gt;.wwebjs_auth&lt;/code&gt; session folder straight into git: 204 files, plus a couple of standalone tar/base64 dumps of the same thing, at 27MB and 41MB. That's not hypothetical risk. That folder &lt;em&gt;is&lt;/em&gt; an active login session. Anyone who could read that repo could have hijacked my WhatsApp account with it.&lt;/p&gt;

&lt;p&gt;Deleting the files from the working tree isn't enough. They're still sitting in every earlier commit, recoverable by anyone who clones the repo. Fixing it for real meant &lt;code&gt;git filter-repo&lt;/code&gt; to strip those paths out of the &lt;em&gt;entire&lt;/em&gt; history, followed by a force-push. My &lt;code&gt;.git&lt;/code&gt; folder went from 84MB to 284KB in about a second. If you've ever committed something you regret, this is the actual fix. Not &lt;code&gt;git rm&lt;/code&gt;. The history itself has to go.&lt;/p&gt;

&lt;p&gt;I only caught this because I asked for a full audit before making the repo public. Worth doing that even if you're sure you didn't leak anything. I was sure. I was wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  The model chain
&lt;/h2&gt;

&lt;p&gt;Gemini deprecates old models too quickly, and the solution isn't "use the newest model." It's "never hardcode one." I wrote a small fallback chain: try the latest Flash model, and on a 404, 429, or 503, fall through to the next one down the list automatically. I know it works because I watched it happen live. The newest model hit a genuine &lt;code&gt;503 Service Unavailable&lt;/code&gt; mid-run, fell through to the one behind it, and posted anyway without me touching anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's actually running now
&lt;/h2&gt;

&lt;p&gt;One GitHub Actions workflow, triggered on a cron schedule. It pulls a WhatsApp session out of a free MongoDB cluster, asks Gemini for a word it hasn't used yet, posts it to the channel, and writes the updated state back to Mongo. No server. No Docker image. No monthly bill. The entire compute cost is about a minute of free CI time a day.&lt;/p&gt;

&lt;p&gt;The message itself ended up plainer than I expected too. I started with a version stuffed with emoji and flag icons and a line advertising DM commands, and once I actually deleted the interactive bot half of the project, that line was just false advertising to a channel with nobody listening on the other end. It reads like a dictionary entry now: word, pronunciation, meaning, an example sentence, a note. That turned out to be the right call anyway. It's a vocabulary channel, not a chat app.&lt;/p&gt;

&lt;p&gt;If you're building anything that automates a personal WhatsApp account, expect the session/auth layer to be the actual project, and the thing you originally wanted to build to be the easy 10%.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>german</category>
      <category>learning</category>
      <category>ai</category>
    </item>
    <item>
      <title>Developer Activity and Collaboration Analysis with Airbyte Quickstarts ft. Dagster, BigQuery, Google Colab, dbt and Terraform</title>
      <dc:creator>btkcodedev</dc:creator>
      <pubDate>Thu, 11 Jul 2024 06:33:19 +0000</pubDate>
      <link>https://dev.to/btkcodedev/developer-activity-and-collaboration-analysis-with-airbyte-quickstarts-ft-dagster-bigquery-google-colab-dbt-and-terraform-4184</link>
      <guid>https://dev.to/btkcodedev/developer-activity-and-collaboration-analysis-with-airbyte-quickstarts-ft-dagster-bigquery-google-colab-dbt-and-terraform-4184</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;em&gt;Airbyte could be used as a wonderful tool in-order to leverage the power of data with useful transformations&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Those transformed data could be further used for training AI models (Examples at the end)&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this tutorial, GitHub source API is used as source and transformed with trends in developer activity, which could be feed for an AI modal for image training purposes for enhancing its prediction capabilities&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I've made a full code walk-through at &lt;a href="https://colab.research.google.com/drive/14U7NYK4dy5fBN3891Tbkl3SJYEqxkMYr?usp=sharing" rel="noopener noreferrer"&gt;colab reference&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;
You could either download it as ipynb and run with local jupyter or run step-by-step with local cmd&lt;br&gt;
(If hyperlink is broken, try: &lt;a href="https://colab.research.google.com/drive/14U7NYK4dy5fBN3891Tbkl3SJYEqxkMYr?usp=sharing" rel="noopener noreferrer"&gt;https://colab.research.google.com/drive/14U7NYK4dy5fBN3891Tbkl3SJYEqxkMYr?usp=sharing&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;The initial part of setting up Airbyte for pulling data from GitHub source to BigQuery and SQL transformations are already given precisely at &lt;a href="https://github.com/airbytehq/quickstarts/blob/main/developer_productivity_analytics_github/README.md" rel="noopener noreferrer"&gt;quickstarts directory&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;u&gt;&lt;strong&gt;Architecture&lt;/strong&gt;&lt;/u&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi5ttnw2eoa9ybmz8uv20.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi5ttnw2eoa9ybmz8uv20.png" alt="Architecture" width="500" height="500"&gt;&lt;/a&gt;&lt;br&gt;
&lt;u&gt;Explanation:&lt;/u&gt;&lt;br&gt;
Tech stacks: Dagster, dbt, Airbyte, GitHub API, BigQuery, Terraform&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We are intended to pull data from GitHub source via Airbyte User Interface towards BigQuery dataset, The Airbyte User Interface is automated via Terraform Provider.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;After the dataset creation, data build tool (dbt) is used for transforming data with SQL queries for various metric findings viz. average time per PR, mean of total commits etc...&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1.1: Setting Up the Data Pipeline
&lt;/h2&gt;

&lt;p&gt;Screenshots are attached to the colab notebook, &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Airbyte and GitHub API:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The GitHub source connector requires three credentials:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Repository name&lt;/li&gt;
&lt;li&gt;GitHub personal access token&lt;/li&gt;
&lt;li&gt;Workspace ID&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Airbyte and BigQuery:&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;The BigQuery destination connector requires three credentials:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;IAM &amp;amp; Admin service account JSON key&lt;/li&gt;
&lt;li&gt;Google cloud project ID&lt;/li&gt;
&lt;li&gt;BigQuery Dataset ID&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ref: &lt;a href="https://github.com/airbytehq/quickstarts/blob/8268d1b01ad2f8cfcff0a75c0bd4c0c9a45d197d/developer_productivity_analytics_github/README.md?plain=1#L120" rel="noopener noreferrer"&gt;Configuration steps&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In case you are wondering about behind the scenes, refer to &lt;a href="https://github.com/airbytehq/quickstarts/blob/main/developer_productivity_analytics_github/infra/airbyte/main.tf" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, where you could see the sync between GitHub and BigQuery&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnq3xp665x1npljg4s7b5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnq3xp665x1npljg4s7b5.png" alt="Sync" width="713" height="776"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After which the Terraform jobs are finished, Airbyte UI would be set ready with all the config which are provided and streams are ready to be pulled&lt;/p&gt;

&lt;p&gt;You could find the reference of number of streams at GitHub&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F12o4f5uc5j3gmpgl0bsq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F12o4f5uc5j3gmpgl0bsq.png" alt="GitHub" width="800" height="860"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After running &lt;code&gt;terraform apply&lt;/code&gt;, the Airbyte UI is configured with all the setup and the streams are ready to be pulled&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1.2: Transformations with dbt
&lt;/h2&gt;

&lt;p&gt;Setup the environment variables used for dbt setup, Currently three &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/airbytehq/quickstarts/blob/8268d1b01ad2f8cfcff0a75c0bd4c0c9a45d197d/developer_productivity_analytics_github/dbt_project/profiles.yml#L8" rel="noopener noreferrer"&gt;dbt_service_account_JSON_key&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/airbytehq/quickstarts/blob/8268d1b01ad2f8cfcff0a75c0bd4c0c9a45d197d/developer_productivity_analytics_github/dbt_project/profiles.yml#L13" rel="noopener noreferrer"&gt;bigquery_project_id&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/airbytehq/quickstarts/blob/8268d1b01ad2f8cfcff0a75c0bd4c0c9a45d197d/developer_productivity_analytics_github/dbt_project/models/sources/github_source.yml#L6" rel="noopener noreferrer"&gt;github_source.yml&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Either setup those env variables or hard code in the files for next steps.&lt;br&gt;
Run &lt;code&gt;dbt debug&lt;/code&gt; for confirming the setup.&lt;/p&gt;

&lt;p&gt;The schema for table population for each stream could be seen at &lt;a href="https://github.com/airbytehq/quickstarts/tree/8268d1b01ad2f8cfcff0a75c0bd4c0c9a45d197d/developer_productivity_analytics_github/dbt_project/models/staging" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F85t7t2dhkjym2y50shxi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F85t7t2dhkjym2y50shxi.png" alt="GitHub" width="800" height="860"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After running &lt;code&gt;dbt run --full-refresh&lt;/code&gt;, You could find the transformed tables populated in the BigQuery dataset &lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgss195f5l6c7zf9pjis2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgss195f5l6c7zf9pjis2.png" alt="BigQuery Dataset" width="708" height="816"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The &lt;a href="https://github.com/airbytehq/quickstarts/blob/8268d1b01ad2f8cfcff0a75c0bd4c0c9a45d197d/developer_productivity_analytics_github/dbt_project/models/marts/dev_activity_by_day_of_week_analysis.sql" rel="noopener noreferrer"&gt;dbt marts&lt;/a&gt; are very useful where insights are extracted from the pulled data and could be further utilized for AI training purposes (*Provided large dataset)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjzea9c8sva8svbtywzrk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjzea9c8sva8svbtywzrk.png" alt="dbt marts" width="800" height="860"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1.3: Orchestration using Dagster
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Dagster and BigQuery:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Dagster is a modern data orchestrator designed to help you build, test, and monitor your data workflows.&lt;/p&gt;

&lt;p&gt;After running &lt;code&gt;dagster dev&lt;/code&gt;, localport would be opened or dagster where the workflow could be seen and syncs could be monitored&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg9ifronpvg9j3dbp740d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg9ifronpvg9j3dbp740d.png" alt="Dagster" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1.4: Future Reference AI Model Creation in Colab ft. Tensorflow
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Export BigQuery data to Colab:&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use the BigQuery connector in Colab to load the desired data from your analysis tables.&lt;/li&gt;
&lt;li&gt;Preprocess the data by cleaning, filtering, and transforming it for your specific model inputs.&lt;/li&gt;
&lt;li&gt;Build a Tensorflow Model for Team Dynamics and Productivity:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Choose a suitable architecture like LSTM or RNN for time series analysis of developer activity, or use scikit-learn for quantitative analysis.&lt;br&gt;
Train the model on historical data, using features like time to merge PRs, commits per day, code review frequency, etc.&lt;br&gt;
Evaluate the model performance on validation data.&lt;/p&gt;

&lt;p&gt;Specific code example is provided at &lt;a href="https://colab.research.google.com/drive/14U7NYK4dy5fBN3891Tbkl3SJYEqxkMYr#scrollTo=1l9f-FNihyMr" rel="noopener noreferrer"&gt;Colab&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbg2yb905xlv2auqi7ki8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbg2yb905xlv2auqi7ki8.png" alt="Scikit learn model" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Another example of Tensorflow Model:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import tensorflow as tf
import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt

# Load data from BigQuery
client = bigquery.Client()
query = """
SELECT
  author.email,
  author.time_sec AS time_sec,
  committer.email,
  committer.time_sec AS time_sec_1,
  committer.time_sec - author.time_sec AS time_difference
FROM
  `micro-company-task-367016.transformed_data.stg_commits`,
  UNNEST(difference) AS difference
WHERE
  TIMESTAMP_SECONDS(author.time_sec) BETWEEN TIMESTAMP("2023-01-01") AND TIMESTAMP("2023-12-31")
LIMIT 1000
"""
data = client.query(query).to_dataframe()

# Preprocess data
features = ['time_sec', 'time_sec_1']
target = 'time_difference'

# Drop rows with missing values
data = data.dropna(subset=features + [target])

# Split the data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(data[features], data[target], test_size=0.2, random_state=42)

# Standardize features
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# Define TensorFlow model architecture
model = Sequential([
    Dense(32, activation='relu', input_shape=(len(features),)),
    Dense(16, activation='relu'),
    Dense(1)  # Output layer, no activation for regression
])

# Compile the model
model.compile(optimizer='adam', loss='mean_squared_error')

# Convert y_train to a NumPy array with a compatible dtype
y_train_np = y_train.values.astype('float32')

scaler_y = StandardScaler()
y_train_scaled = scaler_y.fit_transform(y_train_np.reshape(-1, 1))
y_test_scaled = scaler_y.transform(y_test.values.reshape(-1, 1))

# Train the model
model.fit(X_train_scaled, y_train_scaled, epochs=50, batch_size=32, validation_data=(X_test_scaled, y_test_scaled))


# Convert y_test to a NumPy array with a compatible dtype
y_test_np = y_test.values.astype('float32')

# Evaluate the model
mse = model.evaluate(X_test_scaled, y_test_np)
print(f'Mean Squared Error on Test Data: {mse}')

# Generate synthetic new data
new_data = pd.DataFrame({
    'time_sec': np.random.rand(10) * 1000,  # Adjust the range as needed
    'time_sec_1': np.random.rand(10) * 1000  # Adjust the range as needed
})

# Preprocess new data
new_data_scaled = scaler.transform(new_data[features])

# Make predictions on new data
predictions = model.predict(new_data_scaled)
predictions_inverse = scaler_y.inverse_transform(predictions)

# Display predictions 
print(predictions_inverse)


# Plot model predictions
plt.plot(predictions, label="Predicted Time Difference")
plt.plot(y_test.values, label="Actual Time Difference")
plt.xlabel("Data Point")
plt.ylabel("Time Difference")
plt.title("Predicted vs. Actual Time Difference")
plt.legend()
plt.show()

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Results of model:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqds1m9y2o4p9yw9qu94y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqds1m9y2o4p9yw9qu94y.png" alt="Results" width="800" height="622"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Other use cases&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;To predict future trends in team dynamics and productivity.&lt;/li&gt;
&lt;li&gt;Identify factors that influence collaboration and individual developer performance.&lt;/li&gt;
&lt;li&gt;Visualise the results using charts, graphs, and network visualisations.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;350+ source connectors and huge data warehouse destinations are definitely a plus at Airbyte. We could use this power of transformed data as training data for many AI modals specifically tailored for prediction especially in developer behavioural analysis , stock prediction etc...&lt;/p&gt;

&lt;p&gt;Links:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Colab Notebook: &lt;a href="https://colab.research.google.com/drive/14U7NYK4dy5fBN3891Tbkl3SJYEqxkMYr?usp=sharing" rel="noopener noreferrer"&gt;https://colab.research.google.com/drive/14U7NYK4dy5fBN3891Tbkl3SJYEqxkMYr?usp=sharing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Airbyte Quickstarts Repository: &lt;a href="https://github.com/airbytehq/quickstarts" rel="noopener noreferrer"&gt;https://github.com/airbytehq/quickstarts&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Airbyte Main Repository: 
&lt;a href="https://github.com/airbytehq/airbyte" rel="noopener noreferrer"&gt;https://github.com/airbytehq/airbyte&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>programming</category>
      <category>airbyte</category>
      <category>tutorial</category>
      <category>terraform</category>
    </item>
  </channel>
</rss>
