<?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: Trollgen Studios</title>
    <description>The latest articles on DEV Community by Trollgen Studios (@tejsharma).</description>
    <link>https://dev.to/tejsharma</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%2F1202086%2F62238313-6ae3-4a6c-87ac-57eab51a6b66.jpeg</url>
      <title>DEV Community: Trollgen Studios</title>
      <link>https://dev.to/tejsharma</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tejsharma"/>
    <language>en</language>
    <item>
      <title>OpenAI Text To Speech (TTS) Streaming with FastAPI + Python + React Frontend</title>
      <dc:creator>Trollgen Studios</dc:creator>
      <pubDate>Tue, 31 Dec 2024 03:13:02 +0000</pubDate>
      <link>https://dev.to/tejsharma/openai-text-to-speech-tts-streaming-with-fastapi-python-react-frontend-oda</link>
      <guid>https://dev.to/tejsharma/openai-text-to-speech-tts-streaming-with-fastapi-python-react-frontend-oda</guid>
      <description>&lt;p&gt;This code worked for me to get the chunks streaming in:&lt;br&gt;
`await websocket.send_text('|AUDIO_START|')&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;            with openai_client.audio.speech.with_streaming_response.create(
                model="tts-1",
                voice="nova",
                response_format="mp3",  # Changed to mp3 format
                input=text_message,
            ) as response:
                for chunk in response.iter_bytes(chunk_size=1024):
                    await websocket.send_bytes(chunk)


            await websocket.send_text('|AUDIO_END|')`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Then, the challenge was figuring it out on the frontend on React.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Handle incoming messages
    useEffect(() =&amp;gt; {
      if (lastMessage?.data === '|AUDIO_START|') {
        setAudioBuffers([]); // Clear existing buffers
        setIsAudioStreaming(true);
        chunksRef.current = [];
      } else if (lastMessage?.data === '|AUDIO_END|') {
        setIsAudioStreaming(false);
        playAudioChunks();
      } else if (isAudioStreaming &amp;amp;&amp;amp; lastMessage?.data) {
        console.log('trying to parse audio chunk:');
        console.log(lastMessage.data);
        chunksRef.current.push(lastMessage.data);
        // playAudioChunk(lastMessage.data);
      }
}, []);

const playAudioChunks = async () =&amp;gt; {
      const audioBlob = new Blob(chunksRef.current, { type: 'audio/mp3' });
      const audioUrl = URL.createObjectURL(audioBlob);
      const audio = new Audio(audioUrl);

      try {
        await audio.play();
      } catch (err) {
        console.error('Error playing audio:', err);
      }

      // Clean up the URL after audio is done playing
      audio.onended = () =&amp;gt; {
        URL.revokeObjectURL(audioUrl);
      };
    };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sorry for the bad formatting, but hope this helps if you are struggling.&lt;/p&gt;

&lt;p&gt;I am trying to figure out how to play chunk by chunk the best way. If I play each chunk as it comes in, the audio sounds weird so need to look into modifying this code (a larger chunk size? a delay?). Feel free to comment if any insights to share with the community.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const playAudioChunk = async (chunk) =&amp;gt; {
      const audioBlob = new Blob([chunk], { type: 'audio/mp3' });
      const audioUrl = URL.createObjectURL(audioBlob);
      const audio = new Audio(audioUrl);

      try {
        await audio.play();
      } catch (err) {
        console.error('Error playing audio:', err);
      }

      // Clean up the URL after audio is done playing
      audio.onended = () =&amp;gt; {
        URL.revokeObjectURL(audioUrl);
      };
    };

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

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Google Sign In and Google Calendar API tutorial with client and server (iOS and Pyhton backend)</title>
      <dc:creator>Trollgen Studios</dc:creator>
      <pubDate>Sat, 11 Nov 2023 06:12:59 +0000</pubDate>
      <link>https://dev.to/tejsharma/google-calendar-api-tutorial-with-frontend-backend-authentication-1b2i</link>
      <guid>https://dev.to/tejsharma/google-calendar-api-tutorial-with-frontend-backend-authentication-1b2i</guid>
      <description>&lt;p&gt;I'll briefly show you how to do 2 things:&lt;br&gt;
1) Logging in on iOS with Google&lt;br&gt;
2) Getting the access and refresh tokens &lt;/p&gt;

&lt;p&gt;Here are the steps:&lt;/p&gt;

&lt;p&gt;Go to Google API and enable Google Calendar&lt;br&gt;
Create OAuth Consent Screen&lt;br&gt;
Generate a OAuth for your frontend (iOS / Android / Web)&lt;br&gt;
Integrate sign in with Firebase&lt;br&gt;
Make sure to add scope on sign in with Google (this is for iOS but similar for other frontends)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let additionalScopes = [
                "https://www.googleapis.com/auth/calendar.readonly",
                "https://www.googleapis.com/auth/userinfo.email",
                "https://www.googleapis.com/auth/userinfo.profile",
            ]
            let result2 = try await gidSignInResult.user.addScopes(additionalScopes, presenting: getRootViewController())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then a serverAuthCode will be returned. Call a backend POST route to obtain access and refresh tokens (more details here: &lt;a href="https://developers.google.com/identity/sign-in/ios/offline-access"&gt;https://developers.google.com/identity/sign-in/ios/offline-access&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Use Google’s client libraries on backend to generate&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;credentials = client.credentials_from_clientsecrets_and_code(
            CLIENT_SECRET_FILE,
            ['https://www.googleapis.com/auth/calendar.readonly'],
            auth_code,
            redirect_uri="" # this must be there!
        )
if gcal_access_token:
  creds = Credentials.from_authorized_user_info(
   gcal_access_token,
   scopes=CALENDAR_SCOPES
  )
  print(creds.to_json())
 if not creds or not creds.valid:
  # If the credentials are expired, refresh them
  if creds and creds.expired and creds.refresh_token:
   creds.refresh(Request())
   print(creds.to_json())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;You can then use the creds with the library to get events:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
   calendar_event_result = service.events().list(
    calendarId="primary",
    singleEvents=False,
    orderBy="updated",
   ).execute()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I spent at least 10 hours of my life on navigating this maze due to improper documentation on how to authenticate with google sign in on frontend and then use Google Calendar API on backend, so hope this helps someone!&lt;/p&gt;

&lt;p&gt;BY the way, if on the server you get a &lt;code&gt;redirect_uri_mismatch&lt;/code&gt; bug, make sure to enable your localhost / production urls and then also have &lt;code&gt;redirect_uri=""&lt;/code&gt; above&lt;/p&gt;

</description>
      <category>googlecloud</category>
      <category>firebase</category>
      <category>calendar</category>
    </item>
  </channel>
</rss>
