<?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: Katie Liu</title>
    <description>The latest articles on DEV Community by Katie Liu (@katiel).</description>
    <link>https://dev.to/katiel</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1156769%2F84aaefe1-248b-4635-8853-b3c75d9dd078.png</url>
      <title>DEV Community: Katie Liu</title>
      <link>https://dev.to/katiel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/katiel"/>
    <language>en</language>
    <item>
      <title>ChatCraft week 14: Releasing v2.0!</title>
      <dc:creator>Katie Liu</dc:creator>
      <pubDate>Fri, 19 Apr 2024 22:05:57 +0000</pubDate>
      <link>https://dev.to/katiel/chatcraft-week-14-releasing-v20-26h4</link>
      <guid>https://dev.to/katiel/chatcraft-week-14-releasing-v20-26h4</guid>
      <description>&lt;p&gt;Today marks the final day on the open source team working on &lt;a href="https://chatcraft.org"&gt;ChatCraft&lt;/a&gt;! It's been an eventful week as everyone scrambles to polish up their feature code with final bug fixes.&lt;/p&gt;

&lt;h1&gt;
  
  
  Meeting with Taras
&lt;/h1&gt;

&lt;p&gt;This week we met with Taras, the founder of &lt;a href="https://chatcraft.org"&gt;ChatCraft&lt;/a&gt; online to showcase our contributions and get some professional advice from him. It was very rewarding to see what we managed to get done in the span of four months with our small team of six!&lt;/p&gt;

&lt;p&gt;Some of our notable features include but are not limited to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Image reading and image generation&lt;/li&gt;
&lt;li&gt;Custom provider support&lt;/li&gt;
&lt;li&gt;Text to Speech&lt;/li&gt;
&lt;li&gt;Google OAuth support&lt;/li&gt;
&lt;li&gt;Mobile support&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Coding
&lt;/h1&gt;

&lt;p&gt;This week, I focused my attention on bug fixes since this is the last week and I didn't want to risk introducing any new issues. The &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/345"&gt;issue&lt;/a&gt; I worked on was something brought up to me by Rachit in the previous week - we don't want to save an api key into localStorage unless it has been validated.&lt;/p&gt;

&lt;p&gt;It was not a problem previously to save invalid api keys, but now it has become a problem since we can now toggle between Providers by using the up arrow next to the "Ask" button:&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%2Fp1t99p7jkmeujj91sgr3.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%2Fp1t99p7jkmeujj91sgr3.png" alt="Image description" width="496" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you press the up arrow, as you can see in the screenshot above, you get to toggle between all the providers you have saved keys for. This includes any custom providers you have added! However we don't want to show any provider with an invalid key in this list, since even if a user selects it they won't be able to use it. (They will get error when they try to send a message)&lt;/p&gt;

&lt;p&gt;To fix this issue I opened the following PR:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/597"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Enhancement - only save keys to settings.providers if validated
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#597&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/kliu57"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s---woZC-z---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/98062538%3Fv%3D4" alt="kliu57 avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/kliu57"&gt;kliu57&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/597"&gt;&lt;time&gt;Apr 17, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Fixes #596&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt; No longer saving providers or their api keys to &lt;code&gt;settings.providers&lt;/code&gt; array unless the api key is validated. If an invalid or blank is entered, the provider is REMOVED from &lt;code&gt;settings.providers&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important coding points:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Removed the placeholder text in the api key field when you create a new custom provider row (placeholder text was showing up as asterix)&lt;/li&gt;
&lt;li&gt;Removed the &lt;code&gt;useDebounce&lt;/code&gt; code, it wasn't working and is not worth the trouble to fix. &lt;code&gt;useDebounce&lt;/code&gt; is sort of like a &lt;code&gt;useEffect&lt;/code&gt;, but which allows us to wait until the user stops typing to validate the key. However, we do not expect anyone to be typing out a 32 character api key anyways, so opted to remove.&lt;/li&gt;
&lt;li&gt;The keys are stored in &lt;code&gt;tableProviders&lt;/code&gt; and only when they are validated they are stored to &lt;code&gt;settings.providers&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;In these scenarios, &lt;code&gt;tableProviders&lt;/code&gt; is synced with &lt;code&gt;settings.providers&lt;/code&gt;: (when "syncing" happens, those invalid and blank api keys will disappear)
&lt;ul&gt;
&lt;li&gt;When modal first opens&lt;/li&gt;
&lt;li&gt;When modal closes&lt;/li&gt;
&lt;li&gt;When current provider is set (need to sync to update the checkmark)&lt;/li&gt;
&lt;li&gt;When a custom provider is deleted (need to sync to show the row deleted)&lt;/li&gt;
&lt;li&gt;When a custom provider is added (need to sync to show the new row)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Note:&lt;/strong&gt; If you create a custom provider and then later set the key to something invalid, when you close the modal the custom provider row will disappear since we only save it if it has a valid key.&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/pull/597"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;I am no longer automatically updating localStorage when the user enters a key; instead, I store the key in the &lt;code&gt;tableProviders&lt;/code&gt; array. Only when the key has been validated I will store it to &lt;code&gt;settings.providers&lt;/code&gt; (localStorage). And if a key is invalid or blank, I will remove it from localStorage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
  const handleApiKeyChange = async (provider: ChatCraftProvider, apiKey: string) =&amp;gt; {
    const newProvider = providerFromUrl(
      provider.apiUrl,
      apiKey,
      provider.name,
      provider.defaultModel
    );

    setFocusedProvider(newProvider);

    const newProviders = { ...settings.providers };

    // Update api key in table
    tableProviders[newProvider.name] = newProvider;

    // Api key validation
    try {
      setIsApiKeyInvalid(false);
      setIsValidating(true);

      const result = await newProvider.validateApiKey(newProvider.apiKey!);

      setIsApiKeyInvalid(!result);
      setIsValidating(false);

      if (result) {
        // Valid key, update in settings.providers
        newProviders[newProvider.name] = newProvider;
      } else {
        // Invalid key, remove from settings.providers
        delete newProviders[newProvider.name];
      }
    } catch (err: any) {
      setIsApiKeyInvalid(true);
      setIsValidating(false);

      // Invalid key, remove from settings.providers
      delete newProviders[newProvider.name];
    }

    setSettings({
      ...settings,
      ...(newProvider.name === settings.currentProvider.name &amp;amp;&amp;amp; { currentProvider: newProvider }),
      providers: newProviders,
    });

    if (newProvider.name === selectedProvider?.name) {
      setSelectedProvider(newProvider);
    }

    setApiKeySaved(true);
  };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Sheriff
&lt;/h1&gt;

&lt;p&gt;This week I am the sheriff, meaning I am the go-to contact person whenever there is any issues with PRs blocked or needed reviews. As I result I reviewed 5 PRs this week! I also contributed code to &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/600"&gt;one PR&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;See all the PR's in this week's &lt;a href="https://github.com/tarasglek/chatcraft.org/releases/tag/v2.0.0"&gt;2.0 release&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>chatcraft</category>
      <category>opensource</category>
      <category>typescript</category>
      <category>react</category>
    </item>
    <item>
      <title>ChatCraft week 13: Fixing bugs</title>
      <dc:creator>Katie Liu</dc:creator>
      <pubDate>Sat, 13 Apr 2024 13:03:01 +0000</pubDate>
      <link>https://dev.to/katiel/chatcraft-week-13-fixing-bugs-112g</link>
      <guid>https://dev.to/katiel/chatcraft-week-13-fixing-bugs-112g</guid>
      <description>&lt;p&gt;This week on &lt;a href="https://chatcraft.org/"&gt;ChatCraft&lt;/a&gt;, I fixed a few bugs I found in production that have arisen since the new custom provider feature was implemented. I was able to find these bugs because I reviewed many PRs this week and during testing those PRs I was able to see some abnormal behaviour.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/tarasglek/chatcraft.org/issues/583"&gt;This&lt;/a&gt; is the issue I created which outlines how to recreate the 4 bugs I found.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug 1
&lt;/h2&gt;

&lt;p&gt;The first bug involved the Instructions page. This page is no longer in use for the most part, but will still come up when the user clears their current provider's api key.&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%2F0pwnd0gmr5rhhw0314oa.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%2F0pwnd0gmr5rhhw0314oa.png" alt="Image description" width="544" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the user uses a custom provider however, the dropdown list in the Instructions page did not include that custom provider, which leads to unexpected behaviour.&lt;/p&gt;

&lt;p&gt;I fixed this by merging the supported providers list with the user's saved providers (which would include the custom provider).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/tarasglek/chatcraft.org/pull/584/files#diff-9fcdb80f3814fd658a3bb7dcaf58478d27938a43cde9049d449210652e77434c"&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%2F3dndckh6irlm2icbk8w2.png" alt="Image description" width="377" height="80"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug 2
&lt;/h2&gt;

&lt;p&gt;The second bug is also on the Instructions page. The previous behaviour was that when we toggle between the providers in the dropdown, if one of them had a saved api key (from localStorage), then we set that key to &lt;code&gt;settings.currentProvider&lt;/code&gt;. This poses a problem, since we are bypassing the key validation code and taking the user away from the Instructions page (Instructions page only shows up for users when the &lt;code&gt;settings.currentProvider&lt;/code&gt; api key is blank, and it's no longer blank so we leave). The stored api key could be a stored key that is invalid. Or, the stored key could have become invalid after time passed.&lt;/p&gt;

&lt;p&gt;I fixed this by introducing a state variable &lt;code&gt;selectedProvider&lt;/code&gt; in &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/584/files#diff-9fcdb80f3814fd658a3bb7dcaf58478d27938a43cde9049d449210652e77434c"&gt;&lt;code&gt;Instructions.tsx&lt;/code&gt;&lt;/a&gt; so we can keep track of the dropdown's selected provider's api key. This allows us to delay the setting of the currentProvider's api key until after we click the Save button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/tarasglek/chatcraft.org/pull/584/files#diff-9fcdb80f3814fd658a3bb7dcaf58478d27938a43cde9049d449210652e77434c"&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%2F9fkcv1ksskv477wbspwr.png" alt="Image description" width="614" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug 3
&lt;/h2&gt;

&lt;p&gt;The third bug involves the User Settings modal. When the user enters a blank or invalid key we get a form error message as expected. However, when we close the modal and reopen it, that message is still there. There is also strange behaviour where if the user input a correct key into that field, the form error message still persists.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/tarasglek/chatcraft.org/pull/584/files#diff-1025748a16e04005898c20c05840616be48ca0eb4eb4c156248de41a2f3bdd7d"&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%2Fwtdoefdbj0xbligmivqb.png" alt="Image description" width="595" height="260"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I fixed this by adding one line of code to the use effect that runs when the modal is closed, clearing the field validation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/tarasglek/chatcraft.org/pull/584/files#diff-1025748a16e04005898c20c05840616be48ca0eb4eb4c156248de41a2f3bdd7d"&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%2Fni5mrelj6xk8k2tf5idf.png" alt="Image description" width="293" height="125"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug 4
&lt;/h2&gt;

&lt;p&gt;The last bug was brought to my attention while Yumei was testing my PR. I quickly found a fix so I just added it.&lt;/p&gt;

&lt;p&gt;The bug involves browsers' password saving ability. When users enter an api key in Instructions page or when they create a custom provider, they were prompted by their browser whether they want to save the password. Users who have a key saved in their browser will experience a bug. The moment they clear their api key the browser will sense that the field is empty and repopulated it with their saved password. Also, when we create one or more providers with the same api url, it will indiscriminately populate the key for those providers.&lt;/p&gt;

&lt;p&gt;I don't have a fix for users who have already saved an api key as their password, but I can stop ChatCraft from prompting users to save future keys as passwords. This took a bit of digging online, because many online solutions don't actually work. A lot of the time the browsers will not listen even if you set &lt;code&gt;autoComplete="off"&lt;/code&gt;. I tried many online solutions one by one, and finally found one that worked.&lt;/p&gt;

&lt;p&gt;I found that when &lt;a href="https://v2.chakra-ui.com/"&gt;Chakra UI&lt;/a&gt;'s &lt;a href="https://v2.chakra-ui.com/docs/components/input"&gt;&lt;code&gt;Input&lt;/code&gt; component&lt;/a&gt; is set to &lt;code&gt;password&lt;/code&gt; that is when the browsers will prompt the saving of the password. Therefore I changed it to always be &lt;code&gt;text&lt;/code&gt;. Now I lost a feature of component, which used to use &lt;code&gt;type = "password"&lt;/code&gt; to disguise the user key with asterix. However I was able to find a different way to hide the user key with asterix (see below!)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/tarasglek/chatcraft.org/pull/584/files#diff-489784f1d0127d723b28422bf45e60d2be2c40dadf51167c76db55e9977da062"&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%2Ft3wg7itni11fxjffml0k.png" alt="Image description" width="469" height="57"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  PR
&lt;/h1&gt;

&lt;p&gt;My &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/584"&gt;PR&lt;/a&gt; for these bug fixes was reviewed by three contributors and landed in release &lt;a href="https://github.com/tarasglek/chatcraft.org/releases/tag/v1.9.0"&gt;v1.9.0&lt;/a&gt;!&lt;/p&gt;

&lt;h1&gt;
  
  
  Reviews
&lt;/h1&gt;

&lt;p&gt;I did reviews on the following PRs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/tarasglek/chatcraft.org/pull/577"&gt;PR #577&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tarasglek/chatcraft.org/pull/579"&gt;PR #579&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tarasglek/chatcraft.org/pull/575"&gt;PR #575&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tarasglek/chatcraft.org/pull/582"&gt;PR #582&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most of these were bug fixes and there is minimal code additions, so I just did testing of the issue to make sure the bug is fixed and no new bugs were introduced.&lt;/p&gt;

&lt;p&gt;Unfortunately I found a new bug after a PR had already been merged. PR #577 was a toast message width fix, but for some reason it affected the API Key validation toasts, making them appear when they should not, and in greater numbers. &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/586"&gt;Here&lt;/a&gt; is the issue I created which details how to reproduce the issue. It took me a while to track down which PR this bug originated from. At first I was worried this bug originated from one of my PRs. I went through each commit in ChatCraft in sequence until I found where the bug was no longer occurring. Although I managed to narrow down when the bug started occurring, I did not have time to investigate what part of the code from that PR was causing it. I contacted Roy since it was his PR and I believe he is looking into it now. &lt;/p&gt;

</description>
      <category>chatcraft</category>
      <category>typescript</category>
      <category>opensource</category>
      <category>chatgpt</category>
    </item>
    <item>
      <title>ChatCraft week 12: PR merged and follow ups!</title>
      <dc:creator>Katie Liu</dc:creator>
      <pubDate>Sat, 06 Apr 2024 00:35:59 +0000</pubDate>
      <link>https://dev.to/katiel/chatcraft-week-12-pr-merged-and-follow-ups-3l1n</link>
      <guid>https://dev.to/katiel/chatcraft-week-12-pr-merged-and-follow-ups-3l1n</guid>
      <description>&lt;h1&gt;
  
  
  Landed PR
&lt;/h1&gt;

&lt;p&gt;This week I finally landed the custom providers feature I have been working on! See my last &lt;a href="https://dev.to/katiel/chatcraft-week-11-add-support-for-custom-providers-4d4p"&gt;blog&lt;/a&gt; for more details about it. Now if you have an Open AI compatible API url and key, you can use &lt;a href="https://chatcraft.org/"&gt;ChatCraft&lt;/a&gt; as your user interface to communicating with the API!&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/530"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Support custom providers
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#530&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/kliu57"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s---woZC-z---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/98062538%3Fv%3D4" alt="kliu57 avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/kliu57"&gt;kliu57&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/530"&gt;&lt;time&gt;Mar 27, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Closes #503
Closes #440&lt;/p&gt;
&lt;p&gt;Users are now able to add custom providers and the user settings modal now shows a table of providers.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/tarasglek/chatcraft.org/assets/98062538/0655bb4a-7bd6-46e3-a8d5-50d346a757d6"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9d7qx9ql--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/tarasglek/chatcraft.org/assets/98062538/0655bb4a-7bd6-46e3-a8d5-50d346a757d6" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Implemented functionalities:&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Changed the display of the providers section to include a user-friendly and responsive table&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Add Provider button:&lt;/h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Add custom providers by clicking "Add", typing info, clicking "Save" button&lt;/li&gt;
&lt;li&gt;Users are allowed to add any provider that we currently support (openai, openrouter, and any future ones we implement - excluding FreeModelProvider) as well as any custom provider that is open ai compatible.&lt;/li&gt;
&lt;li&gt;If the provider is not compatible, key or url is invalid, provider will not get added and user will see an error message.&lt;/li&gt;
&lt;li&gt;Allowing the users to create multiples of the same provider (i.e. openai) since they may want to manage multiple keys.&lt;/li&gt;
&lt;li&gt;Not allowing users to create FreeModelProvider since that does not have a key so you wouldn't need multiples of it.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Other buttons/fields:&lt;/h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Delete custom providers using "Delete" button (only custom ones can be deleted)&lt;/li&gt;
&lt;li&gt;Change the current provider using "Set as Current Provider" button&lt;/li&gt;
&lt;li&gt;Change the Api Key any of provider in the list by editing the Api Key field, automatically key validation will occur (error message will display if the key is invalid)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Code changes (only summary of important points):&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;PreferencesModal.tsx&lt;/code&gt; (core code is here)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;focusedProvider&lt;/code&gt; state var tracks which provider row we are editing. This is what allows us to display the "Key is invalid" message on the correct corresponding row.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;selectedProvider&lt;/code&gt; state var tracks which provider we have clicked the checkbox on&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;newCustomProvider&lt;/code&gt; stat var stores the data user typed in the new provider row&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;SmallRevealablePasswordInput.tsx&lt;/code&gt;&lt;/strong&gt;
created this so I don't mess with the styles of &lt;code&gt;RevealablePasswordInput.tsx&lt;/code&gt; since we still use that in Instructions page and we may bring back Instructions page someday&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;use-alert.ts&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;added two more types of toast alert in here since the existing types don't disappear fast enough for my liking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Had to make changes to &lt;strong&gt;&lt;code&gt;OpenAiProvider.ts&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;OpenRouterProvider.ts&lt;/code&gt;&lt;/strong&gt;
to take in a name param so that users will be able to have multiple Open AI or Open Router providers with different names&lt;/p&gt;

&lt;p&gt;Had to add &lt;code&gt;defaultModel&lt;/code&gt; member var to &lt;strong&gt;&lt;code&gt;ChatCraftProvider&lt;/code&gt;&lt;/strong&gt; class
to store the defaultModel, since for the custom providers users will add themselves we have no way of hardcoding the defaultModel. So we will query the first model from list of models and store it in this &lt;code&gt;ChatCraftProvider&lt;/code&gt; member var.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Follow ups issues:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/tarasglek/chatcraft.org/issues/524"&gt;https://github.com/tarasglek/chatcraft.org/issues/524&lt;/a&gt;
&lt;a href="https://github.com/tarasglek/chatcraft.org/issues/542"&gt;https://github.com/tarasglek/chatcraft.org/issues/542&lt;/a&gt;
&lt;a href="https://github.com/tarasglek/chatcraft.org/issues/548"&gt;https://github.com/tarasglek/chatcraft.org/issues/548&lt;/a&gt;
&lt;a href="https://github.com/tarasglek/chatcraft.org/issues/550"&gt;https://github.com/tarasglek/chatcraft.org/issues/550&lt;/a&gt;
&lt;a href="https://github.com/tarasglek/chatcraft.org/issues/551"&gt;https://github.com/tarasglek/chatcraft.org/issues/551&lt;/a&gt;
&lt;a href="https://github.com/tarasglek/chatcraft.org/issues/552"&gt;https://github.com/tarasglek/chatcraft.org/issues/552&lt;/a&gt;
&lt;a href="https://github.com/tarasglek/chatcraft.org/issues/553"&gt;https://github.com/tarasglek/chatcraft.org/issues/553&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to test:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Currently I don't have any custom provider urls/keys to use for testing. If anyone has any please help me to test if those providers are open ai compatible.&lt;/p&gt;
&lt;p&gt;You may add new providers using the providers we currently support:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://api.openai.com/v1 (you can create multiple with diff names if you want to manage more than one api key)
https://openrouter.ai/api/v1 (you can create multiple with diff names if you want to manage more than one api key)
https://free-chatcraft-ai.deno.dev/api/v1 (not allowing them to create one since there is no api key so you would not need multiples)
&lt;/code&gt;&lt;/pre&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/pull/530"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Before this got merged I did a lot of small refactoring and bug fixes, such as consolidating components, making sure the new provider row disappears after we close the modal, etc.&lt;/p&gt;

&lt;p&gt;And as with any major feature, we can't forget about the follow up issues and hotfixes.&lt;/p&gt;

&lt;h1&gt;
  
  
  Bug fixes
&lt;/h1&gt;

&lt;p&gt;Some bug fixes I completed this week:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/556"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Hotfix for user settings provider table
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#556&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/kliu57"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s---woZC-z---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/98062538%3Fv%3D4" alt="kliu57 avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/kliu57"&gt;kliu57&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/556"&gt;&lt;time&gt;Apr 03, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;This bug was missed when we landed #530&lt;/p&gt;
&lt;p&gt;Closes #555
Details of the bug can be found in the issue linked above&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/pull/556"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/562"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Logo bg color fix for all models that don't have logo
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#562&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/kliu57"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s---woZC-z---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/98062538%3Fv%3D4" alt="kliu57 avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/kliu57"&gt;kliu57&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/562"&gt;&lt;time&gt;Apr 04, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;&lt;strong&gt;Bug:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Currently some logos in OpenRouter and custom providers appear as white, since they have a default white logo on a white bg.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Set the default Avatar to have green bg color.&lt;/p&gt;

&lt;p&gt;code change:&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/tarasglek/chatcraft.org/assets/98062538/4e3bef96-a4f4-4300-8f2c-c405d5ea4889"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6LNVg6-a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/tarasglek/chatcraft.org/assets/98062538/4e3bef96-a4f4-4300-8f2c-c405d5ea4889" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/pull/562"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h1&gt;
  
  
  Follow up issues
&lt;/h1&gt;

&lt;p&gt;There are many follow up issues, but here are the two major ones I am currently focusing on.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/561"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Make Options dialog more dense/compact
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#561&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/tarasglek"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ftZUWbb5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/857083%3Fv%3D4" alt="tarasglek avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/tarasglek"&gt;tarasglek&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/561"&gt;&lt;time&gt;Apr 04, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Lets make it look something like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Models (put the temperature setting and add free provider button here)
&lt;ul&gt;
&lt;li&gt;free&lt;/li&gt;
&lt;li&gt;openai&lt;/li&gt;
&lt;li&gt;openrouter&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;WebHandlers&lt;/li&gt;
&lt;li&gt;UI Customization (all the other settings?)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ui would look like vs code:&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/tarasglek/chatcraft.org/assets/857083/bd57b6a0-6f8d-4a16-a8bb-974f2563ac94"&gt;&lt;img width="842" alt="image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ws3vBzxo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/tarasglek/chatcraft.org/assets/857083/bd57b6a0-6f8d-4a16-a8bb-974f2563ac94"&gt;&lt;/a&gt;&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/issues/561"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;This issue aims at revamping the UI of the User Settings modal, to make sure it encompasses all our settings in a user-friendly way.&lt;/p&gt;

&lt;p&gt;With taras' guidance, I have created some &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/561#issuecomment-2040328542"&gt;mock up UI designs&lt;/a&gt;, and I am waiting to get feedback on them. I also spoke with mingming about how to create this two-column modal, as this task may need to be divided up among more people.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/524"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Update Settings model option to be per provider
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#524&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/humphd"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ol0-8Egz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/427398%3Fv%3D4" alt="humphd avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/humphd"&gt;humphd&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/524"&gt;&lt;time&gt;Mar 23, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;The Settings modal used to be the place where you changed the model you were using:&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/tarasglek/chatcraft.org/assets/427398/974d183c-f9d2-421e-bc62-06d8cb5e524d"&gt;&lt;img width="525" alt="Screenshot 2024-03-23 at 2 15 49 PM" src="https://res.cloudinary.com/practicaldev/image/fetch/s--D2X6Rxjz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/tarasglek/chatcraft.org/assets/427398/974d183c-f9d2-421e-bc62-06d8cb5e524d"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;However, this is no longer true, since we have the "Ask" button and menu.&lt;/p&gt;
&lt;p&gt;Let's either remove it or convert the "GPT Model" part of the form to be "Default Model for Provider" and make it so that you can specify a default model when you switch between provider.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/issues/524"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The second issue I have my focus on is this issue which would allow the user to store a "current model" for each provider. Currently whenever the user switches between providers (let's say they switch from OpenAI to OpenRouter), the model will stay the same but when the switched provider doesn't have the model it will just change to some default model. This is not very convenient for the user because most likely this default model is not what they want to use.&lt;/p&gt;

&lt;p&gt;I plan to change the way we store the current modal information. We currently store one "current modal" in the localStorage as settings.model. I plan to add a new member variable to the ChatCraftProvider class so that we store the model in the settings.currentProvider object. This way when the user switches between providers, they can have back the model they were last using with that provider! For those users who have more than one providers, I would assume that they have a preferred go-to model for each of their providers.&lt;/p&gt;

&lt;h1&gt;
  
  
  Code Reviews
&lt;/h1&gt;

&lt;p&gt;I did many code reviews this week. Here are the PRs I reviewed which were later merged!&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/554"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Replace "Cancel Adding Provider" SVG with an IconButton
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#554&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/Amnish04"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZiJtd-eT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/78865303%3Fv%3D4" alt="Amnish04 avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/Amnish04"&gt;Amnish04&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/554"&gt;&lt;time&gt;Apr 03, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;As discussed in &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/530#discussion_r1545481317"&gt;https://github.com/tarasglek/chatcraft.org/pull/530#discussion_r1545481317&lt;/a&gt;, we should not use Svg's directly as an alternative of a button since it is semantically incorrect.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.reddit.com/r/webdev/comments/r72zq6/comment/hmwvobm/?utm_source=share&amp;amp;utm_medium=web3x&amp;amp;utm_name=web3xcss&amp;amp;utm_term=1&amp;amp;utm_content=share_button" rel="nofollow"&gt;https://www.reddit.com/r/webdev/comments/r72zq6/comment/hmwvobm/?utm_source=share&amp;amp;utm_medium=web3x&amp;amp;utm_name=web3xcss&amp;amp;utm_term=1&amp;amp;utm_content=share_button&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I tried preserving the look of the button, and was successful for the most part.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Normal:&lt;/strong&gt;
&lt;a rel="noopener noreferrer" href="https://github.com/tarasglek/chatcraft.org/assets/78865303/8f0b36b5-501d-415b-be13-ed7ceffaab5c"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RvMfO33_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/tarasglek/chatcraft.org/assets/78865303/8f0b36b5-501d-415b-be13-ed7ceffaab5c" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Active:&lt;/strong&gt;
&lt;a rel="noopener noreferrer" href="https://github.com/tarasglek/chatcraft.org/assets/78865303/d4cf2d69-eb47-47c0-8cc1-5d028ab7ef66"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iZPPRQfn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/tarasglek/chatcraft.org/assets/78865303/d4cf2d69-eb47-47c0-8cc1-5d028ab7ef66" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This fixes #551&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/pull/554"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/557"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Hide voice selection option in prefs menu when tts is not supported
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#557&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/Amnish04"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZiJtd-eT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/78865303%3Fv%3D4" alt="Amnish04 avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/Amnish04"&gt;Amnish04&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/557"&gt;&lt;time&gt;Apr 03, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;This is to make sure that the voice selection options in Preferences Modal are hidden when TTS is not supported by the current provider.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;With OpenAI:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/tarasglek/chatcraft.org/assets/78865303/0419126e-d276-4667-b682-1f7e2b21f0ce"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--owdk1cmg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/tarasglek/chatcraft.org/assets/78865303/0419126e-d276-4667-b682-1f7e2b21f0ce" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;With Free Provider:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/tarasglek/chatcraft.org/assets/78865303/a17cd831-acd9-4538-b9ec-44636b1472ee"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--u93HdZA5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/tarasglek/chatcraft.org/assets/78865303/a17cd831-acd9-4538-b9ec-44636b1472ee" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Fixes #523&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/pull/557"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/559"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Updated regex to ignore backslash
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#559&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/Rachit1313"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--_xZG9ehX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/58596563%3Fv%3D4" alt="Rachit1313 avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/Rachit1313"&gt;Rachit1313&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/559"&gt;&lt;time&gt;Apr 04, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Closes #427&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Changes Made:&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;Updated regex to ignore backslash in github commands.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;How to test:&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;Both the links with backslash at the end or without would recieve diff when a link of github PR is imported using /import command.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/pull/559"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/549"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Fix image generated not available after some time
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#549&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/mingming-ma"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--qfvZ3bKb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/133393905%3Fv%3D4" alt="mingming-ma avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/mingming-ma"&gt;mingming-ma&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/549"&gt;&lt;time&gt;Apr 03, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Description&lt;/h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;In the DALL·E 3 generations, if response returned as URL, it will expire after &lt;a href="https://platform.openai.com/docs/guides/images/example-dall-e-3-generations" rel="nofollow"&gt;an hour&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This update change the response format to &lt;code&gt;b64_json&lt;/code&gt; so we can keep the image's Data&lt;/p&gt;
&lt;p&gt;Fixes #496&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/pull/549"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;It amazes me how many fixes and PRs we get merged every week! See the list of all the PRs merged from this week's &lt;a href="https://github.com/tarasglek/chatcraft.org/releases/tag/v1.8.0"&gt;release v1.8.0&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>chatcraft</category>
      <category>typescript</category>
      <category>chatgpt</category>
    </item>
    <item>
      <title>ChatCraft week 11: Add support for custom providers!</title>
      <dc:creator>Katie Liu</dc:creator>
      <pubDate>Sat, 30 Mar 2024 08:00:57 +0000</pubDate>
      <link>https://dev.to/katiel/chatcraft-week-11-add-support-for-custom-providers-4d4p</link>
      <guid>https://dev.to/katiel/chatcraft-week-11-add-support-for-custom-providers-4d4p</guid>
      <description>&lt;p&gt;This was a very eventful week, I completed a big feature which is giving the User Settings a makeover and supporting custom providers!&lt;/p&gt;

&lt;p&gt;Now users can add their own provider url and key to use with &lt;a href="https://chatcraft.org"&gt;ChatCraft&lt;/a&gt;, so long as their provider is open ai compatible.&lt;/p&gt;

&lt;p&gt;This feature is currently under review so not in production yet, but you can check out a development version &lt;a href="https://944d4d98.console-overthinker-dev.pages.dev"&gt;here&lt;/a&gt;. Once I have gotten reviews from my team this should be good to enter production.&lt;/p&gt;

&lt;p&gt;Here are the before and after screenshots:&lt;/p&gt;

&lt;h3&gt;
  
  
  Before
&lt;/h3&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%2Fmy42uwggkt1czarc4zwc.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%2Fmy42uwggkt1czarc4zwc.png" alt="Image description" width="537" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  After
&lt;/h3&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%2Fsrx7vk9v433vqpla1a8l.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%2Fsrx7vk9v433vqpla1a8l.png" alt="Image description" width="593" height="323"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding a custom provider
&lt;/h3&gt;

&lt;p&gt;Unfortunately I only have an open ai and open ai key at this time, so I am not able to test with more providers. I will try to acquire some more to use for testing.&lt;/p&gt;

&lt;p&gt;Click add button which creates a new row, enter your info and click Save&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%2F8amnn6tcru6nhpnpbitf.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%2F8amnn6tcru6nhpnpbitf.png" alt="Image description" width="595" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The new provider key has been validated and the provider is saved to localStorage and shows up in the table!&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%2Friw189ek22qfebsgt220.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%2Friw189ek22qfebsgt220.png" alt="Image description" width="592" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Set it as the current provider so you can starting using!&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%2F6ghwm9x1tyayce9iix5b.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%2F6ghwm9x1tyayce9iix5b.png" alt="Image description" width="595" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It talks!&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%2Fevk3o9qrik3b2vrcyj6s.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%2Fevk3o9qrik3b2vrcyj6s.png" alt="Image description" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/530"&gt;Pull Request&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Unfortunately there is too much code in this PR for me to talk about without this blog post getting too long. I used a number of state variables to track which provider the use checked the checkbox of, which provider's api key the user is editing, and to track the data of the new provider that is about to get created.&lt;/p&gt;

&lt;p&gt;I also tried to make a visually appealing UI and a user friendly experience, which includes validating the api key immediately after editing a key and providing instant feedback if the key is invalid by printing a message under the field. Also a spinner would show if the validation is in progress. I had to utilize the state variable I set up so that I could correctly identify which row the error message would appear under.&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%2Fk20rems1acnpand8v9ai.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%2Fk20rems1acnpand8v9ai.png" alt="Image description" width="513" height="60"&gt;&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%2Fg7q5jd7zvyb65ita3961.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%2Fg7q5jd7zvyb65ita3961.png" alt="Image description" width="516" height="58"&gt;&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%2Fwa6pxasq7ayvos8ombgr.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%2Fwa6pxasq7ayvos8ombgr.png" alt="Image description" width="487" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looking forward to getting this merged next week so users can test this feature out!&lt;/p&gt;
&lt;h3&gt;
  
  
  Hotfixes
&lt;/h3&gt;

&lt;p&gt;I also merged two hotfixes this week. Unfortunately the second was to fix a mistake I made in the first one.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/537"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Migration fix for settings.providers
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#537&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/kliu57"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s---woZC-z---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/98062538%3Fv%3D4" alt="kliu57 avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/kliu57"&gt;kliu57&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/537"&gt;&lt;time&gt;Mar 28, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Closes #536&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Code changes:&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Part 1 - Changing settings.providers to use name as the key&lt;/h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;Files:
&lt;a href="https://github.com/tarasglek/chatcraft.org/pull/537/files#diff-9fcdb80f3814fd658a3bb7dcaf58478d27938a43cde9049d449210652e77434c"&gt;&lt;code&gt;src/components/Message/AppMessage/Instructions.tsx&lt;/code&gt;&lt;/a&gt;
&lt;a href="https://github.com/tarasglek/chatcraft.org/pull/537/files#diff-1025748a16e04005898c20c05840616be48ca0eb4eb4c156248de41a2f3bdd7d"&gt;&lt;code&gt;src/components/PreferencesModal.tsx&lt;/code&gt;&lt;/a&gt;
&lt;a href="https://github.com/tarasglek/chatcraft.org/pull/537/files#diff-b5f5521c9795e314efdf6293ad3afda789a1402bbf5e2a304e20efa8134d2a15"&gt;&lt;code&gt;src/lib/settings.ts&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Part 2 - Deserializing settings.providers in &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/537/files#diff-b5f5521c9795e314efdf6293ad3afda789a1402bbf5e2a304e20efa8134d2a15"&gt;&lt;code&gt;settings.ts&lt;/code&gt;&lt;/a&gt;
&lt;/h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;To test this you can set your settings json to the following (replace YOUR_OPENAI_KEY with your key). Using my json you start with two openai providers and two openrouter providers and after navigating to or refreshing chatcraft the deserializer will change it to having two.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{"model":"openai/gpt-3.5-turbo","temperature":0,"enterBehaviour":"send","countTokens":false,"sidebarVisible":false,"alwaysSendFunctionResult":false,"textToSpeech":{"announceMessages":false,"voice":"alloy"},"providers":{"OpenAI":{"id":"Jnc3KkY4--dQm7KwMWy7Y","name":"OpenAI","apiUrl":"https://api.openai.com/v1","apiKey":"aaaaaaaa"},"OpenRouter.ai":{"id":"XG_lpq_xG-nMIbD1ZRCG-","name":"OpenRouter.ai","apiUrl":"https://openrouter.ai/api/v1","apiKey":"bbbbbbbb"},"https://api.openai.com/v1":{"id":"Jnc3KkY4--dQm7KwMWy7Y","name":"OpenAI","apiUrl":"https://api.openai.com/v1","apiKey":"YOUR_OPENAI_KEY"},"https://openrouter.ai/api/v1":{"id":"XG_lpq_xG-nMIbD1ZRCG-","name":"OpenRouter.ai","apiUrl":"https://openrouter.ai/api/v1","apiKey":"YOUR_OPENROUTER_KEY"}},"currentProvider":{"id":"XG_lpq_xG-nMIbD1ZRCG-","name":"OpenRouter.ai","apiUrl":"https://openrouter.ai/api/v1","apiKey":"YOUR_OPENROUTER_KEY"},"compressionFactor":1,"maxCompressedFileSizeMB":20,"maxImageDimension":2048}
&lt;/code&gt;&lt;/pre&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Part 3 - Removing unnecessary calls to &lt;code&gt;getSettings()&lt;/code&gt; in useEffects to decrease how many times our deserializer runs&lt;/h4&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;As discussed with &lt;a class="mentioned-user" href="https://dev.to/amnish04"&gt;@amnish04&lt;/a&gt; already, there are some locations where we can call &lt;code&gt;getSettings()&lt;/code&gt; a lesser amount of times.
Files: &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/537/files#diff-6d071d338ac4fef38a1aff98d7885eb7dcdbfbd07984436fca89685520bd9225"&gt;&lt;code&gt;src/hooks/use-chat-openai.ts&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/537/files#diff-1e3019f58d4740d97c73bcc9d005579ec23be1a4ec6d4c25ed3072d742831a95"&gt;&lt;code&gt;src/lib/ai.ts&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a class="mentioned-user" href="https://dev.to/rachit1313"&gt;@rachit1313&lt;/a&gt; If this PR is merged to main before your &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/535"&gt;PR#535&lt;/a&gt;, then I need you to merge the code from main into your branch and then modify your code to use the name as the key instead of the apiUrl as the key whenever you access &lt;code&gt;settings.providers&lt;/code&gt;&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/pull/537"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/538"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Hotfix for bug introduced in pr 537
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#538&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/kliu57"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s---woZC-z---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/98062538%3Fv%3D4" alt="kliu57 avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/kliu57"&gt;kliu57&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/538"&gt;&lt;time&gt;Mar 28, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Accidentally introduced a bug in this morning's merged PR #537&lt;/p&gt;
&lt;p&gt;Took a statement out of an if statement in &lt;code&gt;settings.ts&lt;/code&gt;, which may cause some users to be unable to load ChatCraft.&lt;/p&gt;
&lt;p&gt;The users that are affected are users who have not logged into ChatCraft since last month.
They have a &lt;code&gt;settings&lt;/code&gt; JSON in their localStorage, but do not have &lt;code&gt;settings.currentProvider&lt;/code&gt;. (Because the last time they logged in was last month, back before I introduced &lt;code&gt;settings.currentProvider&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;Also if a user went to localStorage and manually set settings to {}, they would also be affected.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The code from PR 537 which caused the bug:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/tarasglek/chatcraft.org/assets/98062538/c110c974-83c9-47cb-83b3-19e31c33b8a4"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SxoWwLuC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/tarasglek/chatcraft.org/assets/98062538/c110c974-83c9-47cb-83b3-19e31c33b8a4" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fix&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Restoring the if statement in this hotfix fixes the issue.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How to test:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to localStorage and remove the currentProvider part of the settings json, or just clear the entire settings json and put {}&lt;/li&gt;
&lt;li&gt;Load ChatCraft&lt;/li&gt;
&lt;li&gt;Result - (it should have an error in production, but not in this PR's preview)&lt;/li&gt;
&lt;/ol&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/pull/538"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Reviews
&lt;/h3&gt;

&lt;p&gt;I reviewed a teammate's PR which involved allowing users to easily switch between the providers they have keys saved for in their localStorage. Now instead of going to User Settings modal to change providers, users can change it from the models dropdown.&lt;/p&gt;

&lt;p&gt;I had a call with my teammate to discuss some changes I needed him to make in his PR once my hotfix was merged, and also some &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/534"&gt;strange behaviour&lt;/a&gt; he experience with being unable to get the list of models, however I was not able to help with debugging as I could not find a way to reproduce the issue on my side. He updated me later to say it was related to his network config issues.&lt;/p&gt;

&lt;p&gt;Also, since I am familiar with working with providers and the settings saved in localStorage, I was able to review his PR code and ask him to do a bit of &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/535/commits/2dd9addbb845d2263cf0b25b7a90d6a658ceba2e"&gt;refactoring&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>react</category>
      <category>chatcraft</category>
      <category>chatgpt</category>
    </item>
    <item>
      <title>ChatCraft week 10: useMemo and Chakra alert banner</title>
      <dc:creator>Katie Liu</dc:creator>
      <pubDate>Sat, 23 Mar 2024 00:04:40 +0000</pubDate>
      <link>https://dev.to/katiel/chatcraft-week-10-follow-up-issues-3fed</link>
      <guid>https://dev.to/katiel/chatcraft-week-10-follow-up-issues-3fed</guid>
      <description>&lt;p&gt;Following my last week's &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/498"&gt;PR&lt;/a&gt; where I added a free provider that users could use to try out &lt;a href="https://chatcraft.org"&gt;ChatCraft&lt;/a&gt; without entering an API key, this week I handled a follow up task to make this new provider the default provider for all new &lt;a href="https://chatcraft.org"&gt;ChatCraft&lt;/a&gt; users.&lt;/p&gt;

&lt;p&gt;This means that if you have never gone to &lt;a href="https://chatcraft.org"&gt;https://chatcraft.org&lt;/a&gt; and you visit it now, you will automatically be using the free provider from the get go!&lt;/p&gt;

&lt;p&gt;But since the free model is limited and does not have as good of a response as say, OpenAi, I added a &lt;a href="https://chakra-ui.com/docs/components/alert"&gt;chakra alert banner&lt;/a&gt; at the top to notify users that they can change the provider by going to the user settings.&lt;/p&gt;

&lt;p&gt;Once in the user settings they can select a different provider such as OpenAi and enter their OpenAi API key.&lt;/p&gt;

&lt;p&gt;If you don't know about &lt;a href="https://chatcraft.org"&gt;ChatCraft&lt;/a&gt;, it is an open source web app designed to work with GPT models like ChatGPT with many other features designed for programmers! You can toggle between a variety of providers such as OpenAi, OpenRouter, and more to come. We also have image generation, image reading, functions, and so much more.&lt;/p&gt;




&lt;h1&gt;
  
  
  Merged Pull Request
&lt;/h1&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/517"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Set init provider for new users to free model, added info alert banner
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#517&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/kliu57"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s---woZC-z---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/98062538%3Fv%3D4" alt="kliu57 avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/kliu57"&gt;kliu57&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/517"&gt;&lt;time&gt;Mar 21, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;ul&gt;
&lt;li&gt;Set initial provider for new users to &lt;code&gt;FreeModelProvider&lt;/code&gt; (can test by clearing cache)&lt;/li&gt;
&lt;li&gt;New users will not see the Instructions page upon their first visit to chatcraft, they can start talking to FreeModelProvider right away&lt;/li&gt;
&lt;li&gt;Users currently using &lt;code&gt;FreeModelProvider&lt;/code&gt; will see the following alert banner with link which opens user settings&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/tarasglek/chatcraft.org/assets/98062538/c504c713-2931-4ff1-9031-6360465eddd9"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gGVLPPZ9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/tarasglek/chatcraft.org/assets/98062538/c504c713-2931-4ff1-9031-6360465eddd9" alt="alert_banner"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Closes #501&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Code changes:&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;Modifications to &lt;code&gt;settings.ts&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Made &lt;code&gt;FreeModelProvider&lt;/code&gt; the &lt;strong&gt;initial provider&lt;/strong&gt; for new users instead of &lt;code&gt;OpenAiProvider&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Made the default model of &lt;code&gt;FreeModelProvider&lt;/code&gt; the &lt;strong&gt;initial model&lt;/strong&gt; instead of &lt;code&gt;OpenAiProvider&lt;/code&gt;'s default model&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Modifications to &lt;code&gt;ChatBase.tsx&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Modified &lt;code&gt;ChatBase.tsx&lt;/code&gt; to show the alert banner to users using &lt;code&gt;FreeModelProvider&lt;/code&gt; as their currentProvider&lt;/li&gt;
&lt;li&gt;Clicking the link in alert banner opens the User Settings&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Modifications to &lt;code&gt;Instructions.tsx&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Made api key field not a required field for &lt;code&gt;FreeModelProvider&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Modified form submission handler function so that it will skip key validation for &lt;code&gt;FreeModelProvider&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Kept this change even though we are not currently using Instructions page, just in case we need that page in the future&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;How to test:&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Either clear your cache (you will automatically be set to free provider) or manually change your provider to the free provider in settings&lt;/li&gt;
&lt;li&gt;Go to the chatcraft main url, you should not see the instructions page and should be able to talk to chatcraft right away&lt;/li&gt;
&lt;li&gt;You should also see the alert banner, which notifies you that you are using free provider&lt;/li&gt;
&lt;li&gt;Click the link in the banner&lt;/li&gt;
&lt;li&gt;The User Settings modal should now open&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/pull/517"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;For switching the initial provider for new users from OpenAi to the free provider, all I had to do was make the change in &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/517/files#diff-b5f5521c9795e314efdf6293ad3afda789a1402bbf5e2a304e20efa8134d2a15"&gt;&lt;code&gt;settings.ts&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As for adding the alert banner at the top of the page, it took me a while to figure out which file I should be editing to add that. After a bit of testing, I found that &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/517/files#diff-a5f1eb4e566f31ab6bd0268de9336ec778c9bed2e2a834a3695f0fc761c68ff5"&gt;&lt;code&gt;ChatBase.tsx&lt;/code&gt;&lt;/a&gt; was where most of the page components such as the &lt;code&gt;Header&lt;/code&gt; , &lt;code&gt;Sidebar&lt;/code&gt;, &lt;code&gt;MessagesView&lt;/code&gt;, &lt;code&gt;PromptForm&lt;/code&gt;, were. I added my alert banner component right above the &lt;code&gt;Header&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I used the &lt;a href="https://react.dev/reference/react/useMemo"&gt;&lt;code&gt;useMemo&lt;/code&gt;&lt;/a&gt; React Hook to create the alert banner.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const defaultProviderAlert = useMemo(() =&amp;gt; {
    // If we are using default provider, show alert banner to notify user
    if (showAlert &amp;amp;&amp;amp; settings.currentProvider instanceof FreeModelProvider) {
      return (
        &amp;lt;Alert status="info" variant="solid" sx={{ py: 1 }}&amp;gt;
          &amp;lt;AlertIcon boxSize="4" /&amp;gt;
          &amp;lt;AlertDescription fontSize="sm"&amp;gt;
            You are using the default free AI Provider, which has limited features.{" "}
            &amp;lt;Text
              as="span"
              cursor="pointer"
              fontSize="sm"
              textDecoration="underline"
              onClick={onPrefModalOpen}
            &amp;gt;
              Click here
            &amp;lt;/Text&amp;gt;{" "}
            to add other AI providers.
          &amp;lt;/AlertDescription&amp;gt;
          &amp;lt;CloseButton
            position="absolute"
            right="8px"
            top="4px"
            size="sm"
            onClick={() =&amp;gt; setShowAlert(false)}
          /&amp;gt;
        &amp;lt;/Alert&amp;gt;
      );
    }
  }, [onPrefModalOpen, settings.currentProvider, showAlert]);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Result:&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%2Fvch81ovtguw4a1n74102.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%2Fvch81ovtguw4a1n74102.png" alt="Image description" width="707" height="30"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h1&gt;
  
  
  Upcoming Issues
&lt;/h1&gt;

&lt;p&gt;In the upcoming weeks, I will be working to allow users to add their own custom providers by entering a provider URL! I also ran a &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/503#issuecomment-2010031012"&gt;design idea&lt;/a&gt; by Taras.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/503"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Custom AI Completion Endpoint
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#503&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/tarasglek"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ftZUWbb5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/857083%3Fv%3D4" alt="tarasglek avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/tarasglek"&gt;tarasglek&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/503"&gt;&lt;time&gt;Mar 15, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Lets extend the work in &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/498"&gt;https://github.com/tarasglek/chatcraft.org/pull/498&lt;/a&gt; to enable a custom provider.&lt;/p&gt;
&lt;p&gt;Eg I would provide a url like "&lt;a href="https://taras-free_open_router.web.val.run/api/v1" rel="nofollow"&gt;https://taras-free_open_router.web.val.run/api/v1&lt;/a&gt;" or "&lt;a href="https://api.%5Bdeepinfra.com%5D(https://deepinfra.com/docs/advanced/function_calling)/v1/openai" rel="nofollow"&gt;https://api.[deepinfra.com](https://deepinfra.com/docs/advanced/function_calling)/v1/openai&lt;/a&gt;"  and a token and be able to talk to a custom model.&lt;/p&gt;
&lt;p&gt;Chatcraft require that [url]/completion and [url]/models are openai-compatible. Note this should be done in such a way that we could have multiple custom providers, eg deepinfra and anyscale.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/issues/503"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;






&lt;h1&gt;
  
  
  Other PRs in this week's release
&lt;/h1&gt;

&lt;p&gt;I reviewed two PRs by my teammates this week. The &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/506"&gt;first PR&lt;/a&gt; is a shared chat bug that has been in production for a long time. &lt;a href="https://dev.to/rjwignar"&gt;Roy&lt;/a&gt; has found a workaround fix for the bug and I tested it. Now, if you create a Shared Chat and you access the same shared chat you created by clicking it in the sidebar, you will no longer get an error.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/520"&gt;second PR&lt;/a&gt; I reviewed was a fix by &lt;a href="https://dev.to/amnish04"&gt;Amnish&lt;/a&gt; on the message dropdown options. The message dropdown options should only show the "Speak" and "Download as Audio" options when the user is currently using OpenAi provider since only this provider has this feature. Now if you are using OpenRouter or the free provider, you will not see these features in the message dropdown. Also, if you did not know, you can get ChatCraft to speak messages out loud. Just enter an OpenAi API key and right click any message and click Speak. Or toggle the sound icon and it will speak all the messages aloud as it generates them.&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%2Fcgtkhglujfr6iauge6xo.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%2Fcgtkhglujfr6iauge6xo.png" alt="Image description" width="800" height="371"&gt;&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%2Fijoley25spc18wyiy05g.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%2Fijoley25spc18wyiy05g.png" alt="Image description" width="800" height="128"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>chatgpt</category>
      <category>opensource</category>
      <category>typescript</category>
      <category>chakra</category>
    </item>
    <item>
      <title>ChatCraft week 9: Free Model Provider!</title>
      <dc:creator>Katie Liu</dc:creator>
      <pubDate>Sat, 16 Mar 2024 05:54:39 +0000</pubDate>
      <link>https://dev.to/katiel/chatcraft-week-9-free-model-provider-386n</link>
      <guid>https://dev.to/katiel/chatcraft-week-9-free-model-provider-386n</guid>
      <description>&lt;p&gt;This week I got a PR merged which established a free new provider for new users to try out! So now, even if you don't have any Open Router or Open AI api keys in your name, you can try ChatCraft out with our free model provider!&lt;/p&gt;

&lt;p&gt;Simply go to &lt;a href="https://chatcraft.org"&gt;https://chatcraft.org&lt;/a&gt; and select Free AI Models from the Provider dropdown.&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%2Fuynqdnidgqa659c3lb9q.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%2Fuynqdnidgqa659c3lb9q.png" alt="Image description" width="568" height="194"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The responses from the free model won't be as good as Open AI's chatgpt or gpt4 models but you can try out ChatCraft and see what it's capable of! For example, editing prompts, saving or sharing chats, adding functions and more.&lt;/p&gt;




&lt;h1&gt;
  
  
  Coding
&lt;/h1&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/498"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Add FreeModelProvider and more provider refactoring
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#498&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/kliu57"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s---woZC-z---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/98062538%3Fv%3D4" alt="kliu57 avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/kliu57"&gt;kliu57&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/498"&gt;&lt;time&gt;Mar 14, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Added new provider (free provider for new users to try)
Further providers refactoring&lt;/p&gt;
&lt;p&gt;Closes #401&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Code changes:&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Moved &lt;code&gt;validateApiKey&lt;/code&gt;, &lt;code&gt;queryModels&lt;/code&gt;, &lt;code&gt;createClient&lt;/code&gt; out of &lt;code&gt;ais.ts&lt;/code&gt; and into &lt;code&gt;ChatCraftProvider.ts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Moved &lt;code&gt;usingOfficialOpenAI&lt;/code&gt;, &lt;code&gt;usingOfficialOpenRouter&lt;/code&gt; out of &lt;code&gt;ai.ts&lt;/code&gt; and into &lt;code&gt;providers/index.ts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Added new free provider &lt;code&gt;providers/DefaultProvider/FreeModelProvider.ts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Configured &lt;code&gt;ModelAvatar.tsx&lt;/code&gt; for &lt;code&gt;DefaultProvider&lt;/code&gt; so logo will display with the green bg&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Potential future follow up items:&lt;/h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Make FreeModelProvider the default provider for new users (this will make the Instructions page obsolete so we need to design a new way to instruct new users about ChatCraft)&lt;/li&gt;
&lt;li&gt;Query the first available free provider in the list of providers instead of hardcoding (currently not sure how since requires making &lt;code&gt;defaultModelForProvider()&lt;/code&gt; async and affecting alot of other files)&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/pull/498"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The free model provider endpoint was provided by Taras (see &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/401"&gt;issue&lt;/a&gt;). I created a new provider class called &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/498/files#diff-c7e5b9bfd927a8c000ef494e651239771e970ba010faacf3959ed6ebe7167dfc"&gt;&lt;code&gt;FreeModelProvider&lt;/code&gt;&lt;/a&gt; which has the provider url. I also overloaded the parent class' &lt;code&gt;queryModels&lt;/code&gt; function to fetch the available models. Lastly, I made the &lt;code&gt;validateApiKey&lt;/code&gt; function always return true since this model does not require a key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  async queryModels(key: string) {
    const res = await fetch(`${FREEMODELPROVIDER_API_URL}/models`, {
      method: "GET",
    });

    if (!res.ok) {
      throw new Error(`${res.status} ${await res.text()}`);
    }

    try {
      const result = await res.json();
      return result.data.map((model: { id: string }) =&amp;gt; model.id) as string[];
    } catch (err: any) {
      throw new Error(`error querying models API: ${err.message}`);
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result of my &lt;code&gt;queryModels&lt;/code&gt; function:&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%2F4juo0ilyhuypg0yha34a.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%2F4juo0ilyhuypg0yha34a.png" alt="Image description" width="800" height="319"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also had to make modifications to other project files. For example, I had to make it so that when the user selects the free provider, instead of waiting for them to enter an api key, I would submit a mock key automatically which would be automatically validated. That means the moment they select the free provider they are taken to the next page where they can start using ChatCraft! See code &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/498/files#diff-9fcdb80f3814fd658a3bb7dcaf58478d27938a43cde9049d449210652e77434c"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I also made many small code adjustments after getting feedback from Dave and Taras, and also debugged an issue where the logo was not appearing.&lt;/p&gt;

&lt;p&gt;I'm very happy that this code is not in production, and the refactoring of provider code that I have been working on the last few weeks have finally paid off. Moving forward expect to see even more new providers on ChatCraft!&lt;/p&gt;




&lt;h1&gt;
  
  
  Running Ruby on ChatCraft
&lt;/h1&gt;

&lt;p&gt;I did functionality testing for my teammate Yumei's PR this week. This week she managed to allow ChatCraft to run Ruby code on the browser! Check out her &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/492#pullrequestreview-1938151470"&gt;PR&lt;/a&gt;! Also, see other PR's from this week's ChatCraft &lt;a href="https://github.com/tarasglek/chatcraft.org/releases/tag/v1.5.0"&gt;release v.1.5.0&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>chatgpt</category>
      <category>chatcraft</category>
      <category>typescript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>ChatCraft week 8: Successful refactoring PR!</title>
      <dc:creator>Katie Liu</dc:creator>
      <pubDate>Sat, 09 Mar 2024 05:28:17 +0000</pubDate>
      <link>https://dev.to/katiel/chatcraft-week-8-successful-refactoring-pr-h2d</link>
      <guid>https://dev.to/katiel/chatcraft-week-8-successful-refactoring-pr-h2d</guid>
      <description>&lt;h1&gt;
  
  
  Sheriff Duty
&lt;/h1&gt;

&lt;p&gt;This week on &lt;a href="https://chatcraft.org"&gt;ChatCraft&lt;/a&gt;, I am the designated Sheriff for our project team. This means that I lead the weekly team meeting, &lt;a href="https://github.com/humphd/osd700-winter-2024/wiki/Meeting-Minutes-%E2%80%90-Milestone-1.4"&gt;took notes&lt;/a&gt;, and I was the point of contact person when issues arise. I also monitored the to-do items for this weeks release and pushed a new &lt;a href="https://github.com/tarasglek/chatcraft.org/releases/tag/v1.4.0"&gt;release&lt;/a&gt; to GitHub today since it is the end of the week!&lt;/p&gt;

&lt;h1&gt;
  
  
  Largest Pull Request Yet
&lt;/h1&gt;

&lt;p&gt;This release marked my largest merged &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/479"&gt;pull request&lt;/a&gt; to date with a whopping 15 file changes!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/tarasglek/chatcraft.org/pull/479"&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%2Fnq7v2wa47vnfa4b0y8tz.png" alt="large_pr" width="800" height="141"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this PR I worked with React use states, use effects and use context. ChatCraft uses React Context to provide access to and store the data in localStorage. The api key and api url used to be stored in &lt;code&gt;settings.apiKey&lt;/code&gt; and &lt;code&gt;settings.apiUrl&lt;/code&gt; respectively. &lt;/p&gt;

&lt;p&gt;However, since I have recently introduced a &lt;code&gt;ChatCraftProvider&lt;/code&gt; class which holds all the information about a provider such as name, key, url, some refactoring of the project is needed. I also introduced two child classes called &lt;code&gt;OpenAiProvider&lt;/code&gt; and &lt;code&gt;OpenRouterProvider&lt;/code&gt;. The goal is to establish another new provider in the coming weeks.&lt;/p&gt;

&lt;p&gt;I replaced &lt;code&gt;settings.apiUrl&lt;/code&gt; and &lt;code&gt;settings.apiKey&lt;/code&gt; with &lt;code&gt;settings.currentProvider&lt;/code&gt;. I also had to deal with the deserialization of &lt;code&gt;currentProvider&lt;/code&gt; in the &lt;code&gt;deserializer&lt;/code&gt; function of &lt;a href="https://github.com/tarasglek/chatcraft.org/blob/main/src/lib/settings.ts"&gt;&lt;code&gt;settings.ts&lt;/code&gt;&lt;/a&gt;. I parsed the JSON of &lt;code&gt;currentProvider&lt;/code&gt; into a &lt;code&gt;ChatCraftProvider&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;I also implemented the migration of current ChatCraft users who still have &lt;code&gt;apiKey&lt;/code&gt; and &lt;code&gt;apiUrl&lt;/code&gt; values in their localStorage. I migrated those values to &lt;code&gt;currentProvider&lt;/code&gt; and removed those fields.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const deserializer = (value: string): Settings =&amp;gt; {
  const settings = JSON.parse(value);
  if (!settings.model) {
    settings.model = defaults.model;
  }

  if (typeof settings.model === "string") {
    settings.model = new ChatCraftModel(settings.model);
  }

  if (settings.currentProvider) {
    // Handle deserialization of currentProvider
    settings.currentProvider = providerFromJSON(settings.currentProvider);
  } else {
    // No current provider, check if we need to handle migration of deprecated apiKey, apiUrl
    if (settings.apiKey &amp;amp;&amp;amp; settings.apiUrl) {
      const newProvider = providerFromUrl(settings.apiUrl, settings.apiKey);
      settings.currentProvider = newProvider;
      settings.providers = { ...settings.providers, [newProvider.apiUrl]: newProvider };
      delete settings.apiKey;
      delete settings.apiUrl;
      console.warn("Migrated deprecated apiKey, apiUrl");
    }
  }

  return { ...defaults, ...settings };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h1&gt;
  
  
  Code Changes after Review
&lt;/h1&gt;

&lt;p&gt;At first I was using dynamic imports in &lt;code&gt;ChatCraftProvider&lt;/code&gt; to circumvent a circular dependency issue. But after speaking to Dave I realized it would be better to simply move the code out of that class and into another file, providers/index.ts.&lt;/p&gt;

&lt;p&gt;This made my code a lot simpler since without the dynamic imports, I wouldn't have to deal with the functions being &lt;code&gt;async&lt;/code&gt;. This allowed me to move my deserialization code and migration code into the &lt;code&gt;deserializer&lt;/code&gt; function of &lt;code&gt;settings.ts&lt;/code&gt;. This was the best place for it, but I previously could not place it there due to the &lt;code&gt;deserializer&lt;/code&gt; function only allowing asynchronous calls.&lt;/p&gt;
&lt;h1&gt;
  
  
  My Reviews on Team's PR
&lt;/h1&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/485"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Add python-wasi on run-code
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#485&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/WangGithub0"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--9I3bjbRA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/20795443%3Fv%3D4" alt="WangGithub0 avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/WangGithub0"&gt;WangGithub0&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/485"&gt;&lt;time&gt;Mar 06, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Add python-wasi in run-code, and also addressing typeScript type declarations for it.
#312&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/tarasglek/chatcraft.org/assets/20795443/74855f7d-c7b8-40ff-890b-8c01dfa08357"&gt;&lt;img width="943" alt="image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--PlSWJOQa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/tarasglek/chatcraft.org/assets/20795443/74855f7d-c7b8-40ff-890b-8c01dfa08357"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/tarasglek/chatcraft.org/assets/20795443/25b0decf-b19a-4f48-a7f8-7de439ccb509"&gt;&lt;img width="913" alt="image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--zs6wEBgB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/tarasglek/chatcraft.org/assets/20795443/25b0decf-b19a-4f48-a7f8-7de439ccb509"&gt;&lt;/a&gt;&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/pull/485"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;I &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/485#pullrequestreview-1924071095"&gt;reviewed&lt;/a&gt; this very cool PR this week and I urge you to check it out. My teammate &lt;a href="https://dev.to/wanggithub0"&gt;Yumei&lt;/a&gt; has made it possible for users to run Python code in ChatCraft! If you ask for or give ChatCraft some Python code, there is now a run icon you can click to execute the code!&lt;/p&gt;

&lt;p&gt;I tested this and the only problem I saw with it was that it cannot run any code that requires input from the user. Not yet anyways :)&lt;/p&gt;

&lt;p&gt;So apparently she was able to get this working using &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/312#issuecomment-1962128589"&gt;python-wasi&lt;/a&gt; &lt;/p&gt;

&lt;h1&gt;
  
  
  More about Python WASI
&lt;/h1&gt;

&lt;p&gt;Imagine you want to run Python code, but instead of running it on your computer directly, you want to run it in a web browser. python-wasi is a version of Python that's been modified to run in a web environment using WebAssembly.&lt;/p&gt;

&lt;p&gt;WebAssembly (often abbreviated as WASM) is a technology that lets you run code written in languages other than JavaScript (like Python, in this case) right in your web browser, at near-native speed.&lt;/p&gt;

</description>
      <category>chatgpt</category>
      <category>chatcraft</category>
      <category>typescript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>ChatCraft week 7: New issue, new provider?</title>
      <dc:creator>Katie Liu</dc:creator>
      <pubDate>Fri, 23 Feb 2024 22:54:11 +0000</pubDate>
      <link>https://dev.to/katiel/chatcraft-week-7-new-issue-new-provider-437j</link>
      <guid>https://dev.to/katiel/chatcraft-week-7-new-issue-new-provider-437j</guid>
      <description>&lt;p&gt;This week on ChatCraft, I am beginning work on a new issue.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/401"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Do not require chatcraft users to enter a key to use it
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#401&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/tarasglek"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ftZUWbb5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/857083%3Fv%3D4" alt="tarasglek avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/tarasglek"&gt;tarasglek&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/401"&gt;&lt;time&gt;Feb 04, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;If a user does not enter a key, we should use a free model endpoint provided by something like &lt;a href="https://taras-free_open_router.web.val.run" rel="nofollow"&gt;https://taras-free_open_router.web.val.run&lt;/a&gt; implemented by &lt;a href="https://www.val.town/v/taras/free_open_router" rel="nofollow"&gt;https://www.val.town/v/taras/free_open_router&lt;/a&gt; .  Should still have a banner prompting for user to enter their key while in limited to free models mode.
This makes use of a new openrouter feature where free models are singled out with :free suffix&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/issues/401"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;This issue involves adding a new default provider so users can try it for free. However since the issue is so big I have broken it up into a smaller issue:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/478"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Create OpenAiProvider and OpenRouterProvider
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#478&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/kliu57"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s---woZC-z---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/98062538%3Fv%3D4" alt="kliu57 avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/kliu57"&gt;kliu57&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/478"&gt;&lt;time&gt;Feb 21, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Subtask of issue #401&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create &lt;code&gt;providers/OpenAiProvider.ts&lt;/code&gt;, &lt;code&gt;providers/OpenRouterAiProvider.ts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Copy provider-specific methods (for example &lt;code&gt;validateOpenAiApiKey&lt;/code&gt;, &lt;code&gt;validateOpenRouterApiKey&lt;/code&gt;) to &lt;code&gt;providers/OpenAiProvider.ts&lt;/code&gt;, &lt;code&gt;providers/OpenRouterAiProvider.ts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Test these copied functions on local, but no need to commit code to use them yet&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/issues/478"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h1&gt;
  
  
  PR
&lt;/h1&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/479"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Created OpenAiProvider and OpenRouterProvider
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#479&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/kliu57"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s---woZC-z---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/98062538%3Fv%3D4" alt="kliu57 avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/kliu57"&gt;kliu57&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/479"&gt;&lt;time&gt;Feb 22, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Closes #478&lt;/p&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Summary:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;created &lt;code&gt;providers/OpenAiProvider.ts&lt;/code&gt; and &lt;code&gt;providers/OpenRouterAiProvider.ts&lt;/code&gt; containing provider-specific methods&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Code changes in this PR:&lt;/h3&gt;
&lt;p&gt;src/components/Message/AppMessage/Instructions.tsx:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the &lt;code&gt;API URL&lt;/code&gt; dropdown field now iterates through the list of &lt;code&gt;supportedProviders&lt;/code&gt; (missed update from &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/423"&gt;PR 423&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;src/components/PreferencesModal.tsx&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;added &lt;code&gt;await&lt;/code&gt; and &lt;code&gt;async&lt;/code&gt; since &lt;code&gt;fromJSON&lt;/code&gt; method is now async&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;src/lib/ChatCraftProvider.ts&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;modified &lt;code&gt;fromJSON&lt;/code&gt; to be async and to return an &lt;code&gt;OpenAiProvider&lt;/code&gt; or &lt;code&gt;OpenRouterProvider&lt;/code&gt; instead of a &lt;code&gt;ChatCraftProvider&lt;/code&gt; object. (&lt;code&gt;OpenAiProvider&lt;/code&gt; and &lt;code&gt;OpenRouterProvider&lt;/code&gt; are derived/child classes of &lt;code&gt;ChatCraftProvider&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;had to make method async to avoid circular dependency&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;src/lib/providers/OpenAiProvider.ts&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;created derived/child class of &lt;code&gt;ChatCraftProvider&lt;/code&gt; to represent an OpenAi provider&lt;/li&gt;
&lt;li&gt;copied provided-specific methods to this class&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;src/lib/providers/OpenRouterProvider.ts&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;created derived/child class of &lt;code&gt;ChatCraftProvider&lt;/code&gt; to represent an OpenRouter provider&lt;/li&gt;
&lt;li&gt;copied provided-specific methods to this class&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/pull/479"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;I created &lt;code&gt;providers/OpenAiProvider.ts&lt;/code&gt; and &lt;code&gt;providers/OpenRouterAiProvider.ts&lt;/code&gt; containing provider-specific methods. These classes are child classes of the parent class &lt;code&gt;ChatCraftProvider&lt;/code&gt; which I created last month. Eventually I will also create one called &lt;code&gt;DefaultProvider.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Most of the provider-specific methods I copied over from &lt;a href="https://github.com/tarasglek/chatcraft.org/blob/main/src/lib/ai.ts"&gt;&lt;code&gt;ai.ts&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I also made changes to the &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/479/files#diff-163489fb9d67f12a96f71b1a06ec2c3cc41152124ad90c14adcc6ded77869f1a"&gt;&lt;code&gt;fromJSON&lt;/code&gt;&lt;/a&gt; method. This method used to take JSON and return a &lt;code&gt;ChatCraftProvider&lt;/code&gt; object. Now it returns either a &lt;code&gt;OpenAiProvider&lt;/code&gt; or &lt;code&gt;OpenRouter&lt;/code&gt; object depending on the provider url in the json. To do this I had to use dynamic imports.&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%2F6hcsrbt0z22y8eo20imm.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%2F6hcsrbt0z22y8eo20imm.png" alt="Image description" width="623" height="321"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Code Changes after Review
&lt;/h1&gt;

&lt;p&gt;I have received a code reviews from Taras and Amnish who have both given me advice on how to refactor my code further.&lt;/p&gt;

&lt;p&gt;Here are my &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/479#issuecomment-1962839950"&gt;code changes&lt;/a&gt; after receiving their feedback and making the requested changes:&lt;/p&gt;

&lt;h1&gt;
  
  
  What's Next
&lt;/h1&gt;

&lt;p&gt;My PR is yet to be merged, but once it is, the next step is for me to create another subtask/issue so that we can start using these methods from their provider-specific classes rather than from &lt;code&gt;ai.ts&lt;/code&gt;. This will also involve storing our provider settings information into a &lt;code&gt;ChatCraftProvider&lt;/code&gt; object in &lt;code&gt;settings.currentProvider&lt;/code&gt; or something, so that we can use &lt;code&gt;currentProvider isinstanceof OpenAiProvider&lt;/code&gt; and &lt;code&gt;currentProvider isinstanceof OpenRouterProvider&lt;/code&gt; to check which provider we are using so that we can call on the correct methods.&lt;/p&gt;

&lt;h1&gt;
  
  
  My Reviews on Team's PR
&lt;/h1&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/463"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Minimize duplication for sidebar code
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#463&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/Amnish04"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZiJtd-eT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/78865303%3Fv%3D4" alt="Amnish04 avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/Amnish04"&gt;Amnish04&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/463"&gt;&lt;time&gt;Feb 16, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;#437 introduced a lot of duplication for sidebar related styles and logic as we now had different sidebar views for mobile and desktop.&lt;/p&gt;
&lt;p&gt;I have tried to minimize that duplication, by creating separate components for mobile and desktop sidebar and exposing through a common &lt;code&gt;Sidebar&lt;/code&gt; api, taking inspiration from the way &lt;code&gt;PromptForm&lt;/code&gt; is done.&lt;/p&gt;
&lt;p&gt;This way, the places that use the sidebar now look the same as before since all the changes have been abstracted in its own module.&lt;/p&gt;
&lt;p&gt;Here's a summary of changes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Renamed the existing &lt;code&gt;Sidebar&lt;/code&gt; component to &lt;code&gt;SidebarContent&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Added a &lt;code&gt;SidebarMobile&lt;/code&gt; component that uses &lt;code&gt;SidebarContent&lt;/code&gt; and extends it by adding the search field and ChatCraft brand at the top.&lt;/li&gt;
&lt;li&gt;Similarly, &lt;code&gt;SidebarDesktop&lt;/code&gt; component wraps &lt;code&gt;SidebarContent&lt;/code&gt; to apply the new open/close transition effect. This way, we don't have to repeat the &lt;code&gt;keyframe&lt;/code&gt; definitions at evey place where sidebar is used.&lt;/li&gt;
&lt;li&gt;These Sidebar components are exposed by the common &lt;code&gt;Sidebar&lt;/code&gt; in index.tsx based on the screen width using &lt;code&gt;isMobile&lt;/code&gt; hook.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This fixes #457.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/pull/463"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;I &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/463#pullrequestreview-1896887855"&gt;reviewed&lt;/a&gt; Amnish's &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/463"&gt;PR&lt;/a&gt; which was about refactoring code to minimize code duplication introduced from his previous sidebar UI changes. I looked through his code, it involved renaming some things and extracting a context for clarity. I also did regression testing on the sidebar functionalities in desktop and mobile to make sure his code did not introduce any issues.&lt;/p&gt;

</description>
      <category>chatcraft</category>
      <category>chatgpt</category>
      <category>opensource</category>
      <category>typescript</category>
    </item>
    <item>
      <title>ChatCraft week 6: Refactoring code</title>
      <dc:creator>Katie Liu</dc:creator>
      <pubDate>Sat, 17 Feb 2024 01:09:01 +0000</pubDate>
      <link>https://dev.to/katiel/chatcraft-week-6-refactoring-code-mom</link>
      <guid>https://dev.to/katiel/chatcraft-week-6-refactoring-code-mom</guid>
      <description>&lt;h1&gt;
  
  
  Issue
&lt;/h1&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/423"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Refactor settings API URL dropdown to read from list of ChatCraftProvider
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#423&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/kliu57"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s---woZC-z---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/98062538%3Fv%3D4" alt="kliu57 avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/kliu57"&gt;kliu57&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/423"&gt;&lt;time&gt;Feb 08, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Now that we have the ChatCraftProvider class,&lt;/p&gt;
&lt;p&gt;In Settings:&lt;/p&gt;
&lt;p&gt;API URL dropdown contents should be a list ChatCraftProvider objects&lt;/p&gt;

&lt;p&gt;This issue originates from:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This comment in Issue#345: &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/345#issuecomment-1909001948"&gt;The UI in the settings would change to iterate over the list of providers, and show the various fields for each (i.e., show the Name, URL, API Key for each).&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Also see &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/371#issuecomment-1912969306"&gt;this&lt;/a&gt; comment in PR371 and &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/371#issuecomment-1913167443"&gt;this&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/issues/423"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;This week on &lt;a href="https://chatcraft.org"&gt;ChatCraft&lt;/a&gt;, I tackled a follow up &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/423"&gt;issue&lt;/a&gt; from the PRs (&lt;a href="https://github.com/tarasglek/chatcraft.org/pull/371"&gt;1&lt;/a&gt;, &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/421"&gt;2&lt;/a&gt;) I merged last two weeks, which allowed users to store provider information for multiple providers using a new &lt;code&gt;ChatCraftProvider&lt;/code&gt; class I created.&lt;/p&gt;

&lt;p&gt;Now that we have a &lt;code&gt;ChatCraftProvider&lt;/code&gt; class, we want to create and maintain an associative array of providers that we currently support. Right now &lt;a href="https://chatcraft.org"&gt;ChatCraft&lt;/a&gt; only supports OpenAI and OpenRouter, but we plan to add more soon!&lt;/p&gt;

&lt;h1&gt;
  
  
  PR
&lt;/h1&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/449"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Created list of supported ChatCraftProviders
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#449&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/kliu57"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s---woZC-z---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/98062538%3Fv%3D4" alt="kliu57 avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/kliu57"&gt;kliu57&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/449"&gt;&lt;time&gt;Feb 13, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Closes #423&lt;/p&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Summary:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Settings &lt;code&gt;API URL&lt;/code&gt; field now displays list of &lt;code&gt;supportedProviders&lt;/code&gt; which is stored in &lt;code&gt;ChatCraftProvider.ts&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/tarasglek/chatcraft.org/assets/98062538/5cbeef17-84c3-42ec-bb21-6ff6dcd7b631"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zjDjoaAm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/tarasglek/chatcraft.org/assets/98062538/5cbeef17-84c3-42ec-bb21-6ff6dcd7b631" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Code changes in this PR:&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;src/components/PreferencesModal.tsx&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Modified code of the event handler of the &lt;code&gt;API URL&lt;/code&gt; dropdown field, so that it iterates through the list of &lt;code&gt;supportedProviders&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;src/lib/ChatCraftProvider.ts&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Moved &lt;code&gt;ProviderData&lt;/code&gt; (associative array of ChatCraftProvider) from &lt;code&gt;src/lib/settings.ts&lt;/code&gt; to &lt;code&gt;src/lib/ChatCraftProvider.ts&lt;/code&gt; since it is something that is solely used by settings&lt;/li&gt;
&lt;li&gt;Added &lt;code&gt;supportedProviders&lt;/code&gt; (list of currently supported providers)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;src/lib/settings.ts&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Moved &lt;code&gt;ProviderData&lt;/code&gt; out of this file, see above explanation&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/pull/449"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;My &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/449"&gt;PR&lt;/a&gt; was merged, and now users can go to the ChatCraft settings, and the list of providers in the dropdown there will iterate through our newly created array of supported providers.&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%2Frksproe3kbsnf0712w59.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%2Frksproe3kbsnf0712w59.png" alt="Image description" width="497" height="139"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The difficulty I had was determining where the supported providers should be stored. Dave was able to help me with this, and ultimately we put it in &lt;a href="https://github.com/tarasglek/chatcraft.org/blob/main/src/lib/ChatCraftProvider.ts"&gt;&lt;code&gt;ChatCraftProvider.ts&lt;/code&gt;&lt;/a&gt; as a static array.&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%2Fgkxxccuepe69zdvbzkq6.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%2Fgkxxccuepe69zdvbzkq6.png" alt="Image description" width="467" height="105"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Investigating an Upcoming Issue
&lt;/h1&gt;

&lt;p&gt;The next &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/401"&gt;issue&lt;/a&gt; I have started to work on, will involve refactoring code and then adding a new free provider that users will be allowed to try out.&lt;/p&gt;

&lt;p&gt;In the next release, I will be creating a &lt;code&gt;.ts&lt;/code&gt; file for each of our current providers (OpenAi.ts, OpenRouter.ts) and moving the relevant methods to that file (for example: validateOpenAiKey to OpenAi.ts and validateOpenRouterKey to OpenRouter.ts).&lt;/p&gt;




&lt;h1&gt;
  
  
  Code reviews
&lt;/h1&gt;

&lt;p&gt;I did two code reviews this week of new features that my teammates worked on.&lt;/p&gt;

&lt;h2&gt;
  
  
  PR 437 UI Fix for Mobile
&lt;/h2&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/437"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Sidebar Enhancement Reboot
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#437&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/Amnish04"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZiJtd-eT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/78865303%3Fv%3D4" alt="Amnish04 avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/Amnish04"&gt;Amnish04&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/437"&gt;&lt;time&gt;Feb 10, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Pull Request #300 has been open for a while, and since then a lot of our preferences have changed regarding sidebar.&lt;/p&gt;
&lt;p&gt;I really wanted to get it done, but would have been really difficult to continue on that branch.&lt;/p&gt;
&lt;p&gt;Which is why, I have &lt;strong&gt;redone&lt;/strong&gt; the sidebar enhancement from scratch.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;As per our discussion, the overlay effect is only applied to mobile devices now and I am using &lt;strong&gt;Chakra&lt;/strong&gt; &lt;a href="https://chakra-ui.com/docs/components/drawer/usage" rel="nofollow"&gt;Drawer&lt;/a&gt; for that.&lt;/li&gt;
&lt;li&gt;I have also moved the &lt;strong&gt;search field&lt;/strong&gt; to the sidebar on mobile devices due to lack of real estate in the header.&lt;/li&gt;
&lt;li&gt;The behaviour on desktop remains the same, except I have added a few animations to make the &lt;strong&gt;push content&lt;/strong&gt; effect smoother.&lt;/li&gt;
&lt;li&gt;I also made sure there is no redundant animation on page reloads as it was one of the problems in last PR.&lt;/li&gt;
&lt;li&gt;The Pin Sidebar feature has also been removed&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here's how it looks:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;On Desktop:&lt;/strong&gt;
&lt;a rel="noopener noreferrer" href="https://github.com/tarasglek/chatcraft.org/assets/78865303/dfaa70e8-dbbe-4ce1-8035-e77b75937b85"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w-nQm-Ik--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/tarasglek/chatcraft.org/assets/78865303/dfaa70e8-dbbe-4ce1-8035-e77b75937b85" alt="SidebarRebootDesktop"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;On Mobile:&lt;/strong&gt;
&lt;a rel="noopener noreferrer" href="https://github.com/tarasglek/chatcraft.org/assets/78865303/f64707d2-1c1e-459f-bdaf-c7430aabda17"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9ynBFj_w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/tarasglek/chatcraft.org/assets/78865303/f64707d2-1c1e-459f-bdaf-c7430aabda17" alt="SidebarRebootMobile"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Breakpoint:&lt;/strong&gt;
&lt;a rel="noopener noreferrer" href="https://github.com/tarasglek/chatcraft.org/assets/78865303/2dfa6aa9-eeeb-46df-b965-4a1725144900"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3bcJXyQB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/tarasglek/chatcraft.org/assets/78865303/2dfa6aa9-eeeb-46df-b965-4a1725144900" alt="SidebarRebootBreakpoint"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This fixes #299&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/pull/437"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;This first PR I &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/437#pullrequestreview-1884150177"&gt;reviewed&lt;/a&gt; was a UI fix to change the behaviour of the mobile ChatCraft sidebar. &lt;/p&gt;

&lt;p&gt;Old behaviour on mobile:&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%2F6vvl1m23ddbp5nxtvggo.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%2F6vvl1m23ddbp5nxtvggo.png" alt="Image description" width="350" height="579"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;New behaviour:&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%2Fiyoerh5onbp0afwzlu26.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%2Fiyoerh5onbp0afwzlu26.png" alt="Image description" width="352" height="577"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is also animation added to the sidebar now, and the search field has been moved to somewhere more noticeable.&lt;/p&gt;

&lt;h2&gt;
  
  
  PR 457 Twitter Card
&lt;/h2&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/459"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Add twitter card metadata
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#459&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/rjwignar"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZgXe6CaV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/78163326%3Fv%3D4" alt="rjwignar avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/rjwignar"&gt;rjwignar&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/459"&gt;&lt;time&gt;Feb 16, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;This fixes #432.&lt;/p&gt;
&lt;h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Summary&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Added an &lt;code&gt;og:type&lt;/code&gt; property.
From &lt;a href="https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/markup" rel="nofollow"&gt;https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/markup&lt;/a&gt;,
&lt;a rel="noopener noreferrer" href="https://github.com/tarasglek/chatcraft.org/assets/78163326/fd5e3b40-f204-422e-90b8-ad660b13c35e"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YFgYCgfU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/tarasglek/chatcraft.org/assets/78163326/fd5e3b40-f204-422e-90b8-ad660b13c35e" alt="image"&gt;&lt;/a&gt;
A Twitter Summary card can be rendered if an &lt;code&gt;og:type&lt;/code&gt;, &lt;code&gt;og:title&lt;/code&gt; and &lt;code&gt;og:description&lt;/code&gt; exist but not &lt;code&gt;twitter:card&lt;/code&gt;, but I ended up also adding required Twitter meta tags for robustness.&lt;/li&gt;
&lt;li&gt;added Twitter meta tags required to render a Summary Card w/ Image&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Testing Requirements?&lt;/h2&gt;
&lt;p&gt;I am going to run the generated preview against the &lt;a href="https://cards-dev.twitter.com/validator" rel="nofollow"&gt;Twitter Card Validator&lt;/a&gt;.
I hope the validator can test the preview website&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/pull/459"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The second PR I &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/459#pullrequestreview-1884244310"&gt;reviewed&lt;/a&gt; was a twitter card metadata enhancement. Now, when you paste a ChatCraft link to twitter, it will automatically generate a Card like such:&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%2Fzfh88f5wi1xhmooo34fk.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%2Fzfh88f5wi1xhmooo34fk.png" alt="Image description" width="542" height="145"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>chatcraft</category>
      <category>opensource</category>
      <category>chatgpt</category>
      <category>typescript</category>
    </item>
    <item>
      <title>ChatCraft week 5: Storing multiple providers</title>
      <dc:creator>Katie Liu</dc:creator>
      <pubDate>Fri, 09 Feb 2024 22:29:41 +0000</pubDate>
      <link>https://dev.to/katiel/chatcraft-week-5-storing-multiple-providers-2mab</link>
      <guid>https://dev.to/katiel/chatcraft-week-5-storing-multiple-providers-2mab</guid>
      <description>&lt;h1&gt;
  
  
  Issue
&lt;/h1&gt;

&lt;p&gt;This week I finally was able to close the &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/345"&gt;issue&lt;/a&gt; I was working on which was allowing &lt;a href="https://chatcraft.org"&gt;ChatCraft&lt;/a&gt; users to store api keys for multiple providers. &lt;a href="https://chatcraft.org"&gt;ChatCraft&lt;/a&gt; currently only supports two providers (OpenAI and OpenRouter) but we may add more providers in the future!&lt;/p&gt;

&lt;p&gt;If you are a &lt;a href="https://chatcraft.org"&gt;ChatCraft&lt;/a&gt; user, you can now toggle between OpenAI and OpenRouter in User Settings without having to re-enter your API key.&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%2Ftsi3p2kfa3iik9732309.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%2Ftsi3p2kfa3iik9732309.png" alt="user settings" width="545" height="805"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  PR
&lt;/h1&gt;

&lt;p&gt;This is &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/421"&gt;PR&lt;/a&gt; I worked on which resolved the above issue.&lt;/p&gt;

&lt;p&gt;This PR builds upon the &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/371"&gt;PR&lt;/a&gt; I did last week, which completed the set up necessary for this functionality.&lt;/p&gt;

&lt;p&gt;Since all the set up was already completed last week, I did not need to make many code changes to complete this. The main things I did was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;when switching providers, saving the user's current api key to settings.providers array if it is not already saved&lt;/li&gt;
&lt;li&gt;when switching providers, loading the api key from settings.providers if it is there&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the event handler function I wrote which will be triggered when the user toggles the provider:&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%2Fxlxz6kq3as3xbb6f26oz.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%2Fxlxz6kq3as3xbb6f26oz.png" alt="Image description" width="486" height="62"&gt;&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%2Fh4b25u39b3tgg7xn9kd0.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%2Fh4b25u39b3tgg7xn9kd0.png" alt="handleProviderChange" width="656" height="643"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Reviews of my PR
&lt;/h1&gt;

&lt;p&gt;Before my PR got merged, I had many useful reviews from the repo admin and fellow teammates, which helped me discover issues with my code and ways to refactor the code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/tarasglek/chatcraft.org/pull/421#discussion_r1483084154"&gt;This review&lt;/a&gt; by Dave helped me find an issue with my old code.&lt;/p&gt;

&lt;p&gt;Old code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (newProvider.name in settings.providers) {
  newProvider = settings.providers[newProvider.name];
  ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here I forgot to parse &lt;code&gt;settings.providers[newProvider.name]&lt;/code&gt; into  a &lt;code&gt;ChatCraftProvider&lt;/code&gt; object. We are getting this data from localStorage, so it is safer to use my &lt;code&gt;fromJSON&lt;/code&gt; function to parse it into a &lt;code&gt;ChatCraftProvider&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;New code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const newProvider = settings.providers[selectedProvider.name] ? 
  ChatCraftProvider.fromJSON(
    settings.providers[selectedProvider.name]
  ) : 
  selectedProvider;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/421#discussion_r1483356811"&gt;review&lt;/a&gt; by Amnish helped me refactor my code by moving it into a handler function.&lt;/p&gt;

&lt;h1&gt;
  
  
  My Reviews on Teammates' PRs
&lt;/h1&gt;

&lt;p&gt;I reviewed multiple PRs this week and commented on issues I found and suggestions on how the user experience could be improved.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://chatcraft.org"&gt;ChatCraft&lt;/a&gt; now supports uploading images! See &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/286"&gt;PR#286&lt;/a&gt; and try it for yourself by going to &lt;a href="https://chatcraft.org"&gt;ChatCraft.org&lt;/a&gt; selecting "Ask gpt-4-vision-preview" and uploading some images. This functionality is extremely useful! ChatCraft is faster than other image parsing web apps at converting images into text, and you could even do something like upload a UI and ask it to code it for you!&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%2F2eqjgskww62h7vlwcmje.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%2F2eqjgskww62h7vlwcmje.png" alt="Image description" width="800" height="134"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My reviews on this PR and its associated PRs:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/tarasglek/chatcraft.org/pull/286#pullrequestreview-1867992290"&gt;PR#286 review 1&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/tarasglek/chatcraft.org/pull/286#pullrequestreview-1868465556"&gt;PR#286 review 2&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/tarasglek/chatcraft.org/pull/419#pullrequestreview-1868664848"&gt;PR#419 review 1&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/tarasglek/chatcraft.org/pull/419#issuecomment-1932781337"&gt;PR#419 review 2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also reviewed &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/402"&gt;PR#402&lt;/a&gt; which allows users to download a ChatCraft message as an image!&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%2F8lpf22oazaiq0ypvqzd3.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%2F8lpf22oazaiq0ypvqzd3.png" alt="download as image" width="800" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/tarasglek/chatcraft.org/pull/402#pullrequestreview-1868835705"&gt;PR#402 review&lt;/a&gt;&lt;/p&gt;

</description>
      <category>chatcraft</category>
      <category>chatgpt</category>
      <category>typescript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>ChatCraft week 4: Release 1.1 PR</title>
      <dc:creator>Katie Liu</dc:creator>
      <pubDate>Sat, 03 Feb 2024 04:41:19 +0000</pubDate>
      <link>https://dev.to/katiel/chatcraft-week-4-release-11-pr-gmp</link>
      <guid>https://dev.to/katiel/chatcraft-week-4-release-11-pr-gmp</guid>
      <description>&lt;p&gt;This week of working with the &lt;a href="https://chatcraft.org"&gt;ChatCraft&lt;/a&gt; team, it was interesting to see what each team member was working on during our weekly triage meeting. We also, as a team, went through the list of existing issues so that everyone could choose more issues to work on in the future. Today was our first &lt;a href="https://github.com/tarasglek/chatcraft.org/releases/tag/v1.1.0"&gt;release&lt;/a&gt; as a team, and I am happy to see my code be a part of it!&lt;/p&gt;

&lt;h1&gt;
  
  
  Coding
&lt;/h1&gt;

&lt;p&gt;I broke down the &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/345"&gt;issue&lt;/a&gt; I was previously working on into two pieces so that I could get a PR merged in &lt;a href="https://github.com/tarasglek/chatcraft.org/releases/tag/v1.1.0"&gt;Release 1.1&lt;/a&gt; which happened today.&lt;/p&gt;

&lt;h1&gt;
  
  
  Issue &amp;amp; PR
&lt;/h1&gt;

&lt;p&gt;The &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/383"&gt;smaller issue&lt;/a&gt; I created is meant to be a precursor to solving the larger issue of storing info for multiple providers.&lt;/p&gt;

&lt;p&gt;In my &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/371"&gt;PR&lt;/a&gt;, I laid down the foundation for storing the provider information, while not changing any existing behaviour.&lt;/p&gt;

&lt;p&gt;Here is what I did:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating the class &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/371/files#diff-163489fb9d67f12a96f71b1a06ec2c3cc41152124ad90c14adcc6ded77869f1a"&gt;&lt;code&gt;ChatCraftProvider.ts&lt;/code&gt;&lt;/a&gt; which stores information for a provider such as provider name, url, key&lt;/li&gt;
&lt;li&gt;Adding the &lt;code&gt;providers&lt;/code&gt; var to &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/371/files#diff-b5f5521c9795e314efdf6293ad3afda789a1402bbf5e2a304e20efa8134d2a15"&gt;&lt;code&gt;src/lib/settings.ts&lt;/code&gt;&lt;/a&gt;, which is an associative array of &lt;code&gt;ChatCraftProvider&lt;/code&gt; objects&lt;/li&gt;
&lt;li&gt;Adding code to the &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/371/files#diff-9fcdb80f3814fd658a3bb7dcaf58478d27938a43cde9049d449210652e77434c"&gt;&lt;code&gt;Instructions.tsx&lt;/code&gt;&lt;/a&gt; view so that when new &lt;a href="https://chatcraft.org"&gt;ChatCraft&lt;/a&gt; users enters a key and clicks the Save button, the provider info is stored to &lt;code&gt;settings.providers&lt;/code&gt; (thus saved to localStorage)&lt;/li&gt;
&lt;/ul&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%2Fli58tae8jig90mi1bxz9.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%2Fli58tae8jig90mi1bxz9.png" alt="screenshot1" width="632" height="277"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adding code to the event handlers in &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/371/files#diff-1025748a16e04005898c20c05840616be48ca0eb4eb4c156248de41a2f3bdd7d"&gt;&lt;code&gt;PreferencesModal.tsx&lt;/code&gt;&lt;/a&gt; view so that the Settings dialog window will store and remove info from &lt;code&gt;settings.providers&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&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%2Fjsptrpc9tbb2ckl99vcz.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%2Fjsptrpc9tbb2ckl99vcz.png" alt="screenshot2" width="481" height="263"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Code Changes
&lt;/h1&gt;

&lt;p&gt;I received code reviews from &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/371#pullrequestreview-1855161179"&gt;Dave&lt;/a&gt; and &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/371#issuecomment-1920306781"&gt;Amnish&lt;/a&gt;, and I revised my code after getting their comments.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/371#issuecomment-1920368076"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Comment for
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#371&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/kliu57"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--a7j2alrJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/98062538%3Fu%3D3772714d30515490e8d7feef4d4084443b9726f5%26v%3D4" alt="kliu57 avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/kliu57"&gt;kliu57&lt;/a&gt;
        &lt;/strong&gt; commented on &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/371#issuecomment-1920368076"&gt;&lt;time&gt;Feb 01, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;@humphd Made the following changes to &lt;code&gt;ChatCraftProvider&lt;/code&gt;, addressing all your review comments&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;changed &lt;code&gt;fromUrl&lt;/code&gt; function to take &lt;code&gt;apiKey&lt;/code&gt; param as well&lt;/li&gt;
&lt;li&gt;removed &lt;code&gt;setUrl&lt;/code&gt; and &lt;code&gt;setKey&lt;/code&gt; functions&lt;/li&gt;
&lt;li&gt;changed &lt;code&gt;name&lt;/code&gt; member var of ChatCraftProvider from &lt;code&gt;string&lt;/code&gt; data type to &lt;code&gt;ProviderName&lt;/code&gt; where &lt;code&gt;type ProviderName = "OpenAI" | "OpenRouter.ai"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;added &lt;code&gt;fromJSON&lt;/code&gt; function&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a class="mentioned-user" href="https://dev.to/amnish04"&gt;@amnish04&lt;/a&gt; I created an urlToNameMap object which can map the url to the name&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const urlToNameMap: { [key: string]: ProviderName } = {


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

&lt;p&gt;Tested &lt;code&gt;fromJSON()&lt;/code&gt; function to make sure it can parse JSON to &lt;code&gt;ChatCraftProvider&lt;/code&gt; object:&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/tarasglek/chatcraft.org/assets/98062538/8b8d1314-6280-4d44-ab21-d917c697cbcb"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nz7iUpUG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/tarasglek/chatcraft.org/assets/98062538/8b8d1314-6280-4d44-ab21-d917c697cbcb" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/pull/371#issuecomment-1920368076"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;I was pleasantly surprised that I was able to address all the code changes without needing to ask for help. Being able to refer to previously written code in other files of &lt;a href="https://chatcraft.org"&gt;ChatCraft&lt;/a&gt; and having ChatGPT to explain concepts to made my work go faster. My &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/371"&gt;PR&lt;/a&gt; was approved and merged as a part of &lt;a href="https://github.com/tarasglek/chatcraft.org/releases/tag/v1.1.0"&gt;Release 1.1&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Next up in release 1.2, I will be completing the original &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/345"&gt;issue&lt;/a&gt; in full. This means we will be reading from the list of multiple providers, and users can toggle back and forth between OpenAI and OpenRouter without their API key being cleared.&lt;/p&gt;

&lt;h1&gt;
  
  
  Leaving Reviews
&lt;/h1&gt;

&lt;p&gt;I reviewed a &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/369"&gt;PR&lt;/a&gt; which was a small UI change revolving around the Speech-to-text Mic button in ChatCraft.&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%2Fffpoogtyeuo7l3kbkmiq.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%2Fffpoogtyeuo7l3kbkmiq.png" alt="screenshot3" width="800" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The current behaviour of this Mic button is that you have to hold it and speak and then when you let go, it will transcribe your speed to text and send it to ChatCraft.&lt;/p&gt;

&lt;p&gt;This &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/369"&gt;PR&lt;/a&gt; is changing the behaviour for mobile to press to start, press to stop, instead of hold to speak. There is also some strange behaviour allowing users to drag the button which is being addressed.&lt;/p&gt;

&lt;p&gt;I installed &lt;a href="https://cli.github.com/"&gt;GitHub CLI&lt;/a&gt; so I was able to quickly pull the branch code with a simple one-line command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gh pr checkout THE_PR_NUMBER
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once I did that I ran and tested it on my local. I left my &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/369#pullrequestreview-1856911414"&gt;review&lt;/a&gt; on the &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/369"&gt;PR&lt;/a&gt;, but I will review it once more when Amnish is done making additional changes to it.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>chatcraft</category>
      <category>typescript</category>
      <category>chatgpt</category>
    </item>
    <item>
      <title>ChatCraft week 3: Coding and code reviews</title>
      <dc:creator>Katie Liu</dc:creator>
      <pubDate>Sat, 27 Jan 2024 04:52:51 +0000</pubDate>
      <link>https://dev.to/katiel/chatcraft-week-3-coding-and-code-reviews-3706</link>
      <guid>https://dev.to/katiel/chatcraft-week-3-coding-and-code-reviews-3706</guid>
      <description>&lt;h1&gt;
  
  
  Coding
&lt;/h1&gt;

&lt;p&gt;This week of working with the &lt;a href="https://chatcraft.org"&gt;ChatCraft&lt;/a&gt; team, I started to tackle issue 345.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/345"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Allow multiple providers to be used simultaniously
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#345&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/tarasglek"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ftZUWbb5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://avatars.githubusercontent.com/u/857083%3Fv%3D4" alt="tarasglek avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/tarasglek"&gt;tarasglek&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/tarasglek/chatcraft.org/issues/345"&gt;&lt;time&gt;Jan 16, 2024&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;At the moment to switch providers we have to go to preferences and swap out provider + key. Would like to just have a set of providers, with keys and switch between them and their models as easily as we do within one provider.&lt;/p&gt;
&lt;p&gt;Currently openrouter has some really unique models eg perplexity model that can query the internet:
&lt;a rel="noopener noreferrer" href="https://github.com/tarasglek/chatcraft.org/assets/857083/9bbd89b4-2288-4eb0-830f-5e6405d258c6"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B20Gt8YY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/tarasglek/chatcraft.org/assets/857083/9bbd89b4-2288-4eb0-830f-5e6405d258c6" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Useless openai response:
&lt;a rel="noopener noreferrer" href="https://github.com/tarasglek/chatcraft.org/assets/857083/0545d555-2753-4cde-9b30-33040c271ed3"&gt;&lt;img width="724" alt="image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--JH2830LV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/tarasglek/chatcraft.org/assets/857083/0545d555-2753-4cde-9b30-33040c271ed3"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;However there are some downsides of accessing gpt through openrouter(robustness, speed, privacy, etc). Also in the future we might want to use dedicated openai within Azure. For all these reasons we would like to be able to list models across multiple providers and switch between then when doing retry-with...&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tarasglek/chatcraft.org/issues/345"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Currently, &lt;a href="https://chatcraft.org"&gt;ChatCraft&lt;/a&gt; allows users to switch between two providers, OpenAI and OpenRouter, however it only stores the API key of one provider. That means when we switch to a different provider, the old key is cleared from storage. We want to allow for the storage of multiple providers.&lt;/p&gt;

&lt;p&gt;I started working on my issue by analyzing the code and thinking about how I would implement this. I came up with multiple ways this could be implemented, and discussed it with the team during our weekly triage meeting. My main question was should I just add another field in localStorage to store the second api provider info, or use an array or something similar to store them in case we have more than two providers in the future.&lt;/p&gt;

&lt;p&gt;Following the meeting, I was able to quickly write some code to store the data in an array in localStorage and I commented in the issue with more details of my proposed implementation, as well as some questions I had.&lt;/p&gt;

&lt;p&gt;The ChatCraft admins were quick to respond to me. Dave gave me detailed specs and Taras added that it would be better to use an associated array rather than a list.&lt;/p&gt;

&lt;p&gt;With this information in hand, I reworked my code and created a &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/371"&gt;Draft PR&lt;/a&gt; with my current progress. I listed what has been implemented thus far and what has yet to be done. Very optimistic about completing this issue next week!&lt;/p&gt;

&lt;p&gt;File: &lt;code&gt;src/lib/settings.ts&lt;/code&gt;&lt;br&gt;
Creating an associative array &lt;code&gt;settings.providers&lt;/code&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%2Fyyf9zor55mop0bnv0x7o.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%2Fyyf9zor55mop0bnv0x7o.png" alt="code change 1" width="558" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;File: &lt;code&gt;src/components/PreferencesModal.tsx&lt;/code&gt;&lt;br&gt;
Editing the &lt;code&gt;onChange&lt;/code&gt; event handler of the api key field in Settings to store the provider info in &lt;code&gt;settings.providers&lt;/code&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%2F7yjpjza3184ix1il85uh.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%2F7yjpjza3184ix1il85uh.png" alt="code change 2" width="705" height="358"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Testing:&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%2Fbar4sh02q30pynsqfb1o.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%2Fbar4sh02q30pynsqfb1o.png" alt="testing" width="800" height="553"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Code Reviews
&lt;/h1&gt;

&lt;p&gt;I did a couple code reviews of my fellow teammates!&lt;/p&gt;

&lt;p&gt;See my &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/300#pullrequestreview-1844413310"&gt;review&lt;/a&gt; of &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/300"&gt;PR 300&lt;/a&gt;, which was a UI change by Amnish to have the sidebar overlap the main app instead of displacing it to the right.&lt;/p&gt;

&lt;p&gt;See my &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/286#pullrequestreview-1844494192"&gt;review&lt;/a&gt; of Mingming's &lt;a href="https://github.com/tarasglek/chatcraft.org/pull/286"&gt;PR 286&lt;/a&gt;, which was allowing ChatCraft to parse images and answer questions based on those images! Very cool :)&lt;/p&gt;

&lt;p&gt;In my reviews I mainly focused on testing the features that should be implemented. I also gave my thoughts on any behaviours that potentially may negatively impact users.&lt;/p&gt;

&lt;h1&gt;
  
  
  Using ChatCraft for Coding
&lt;/h1&gt;

&lt;p&gt;While coding, I used &lt;a href="https://chatcraft.org"&gt;ChatCraft&lt;/a&gt; to help me and found it was faster than using google when I needed to describe a very specific thing I was trying to code. It was also useful in suggesting potential reasons why I was getting syntax errors in VS Code.&lt;/p&gt;

&lt;p&gt;Example:&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%2Fgwtnc8x4rt65w71lo8xh.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%2Fgwtnc8x4rt65w71lo8xh.png" alt="ChatCraft example" width="800" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>chatcraft</category>
      <category>typescript</category>
      <category>chatgpt</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
