Files
research_and_development/ai-conversation/deepgram_client.c
T
talksik c93267c9ee create full flow with stt, anthropic, tts, and playback
This organizes some components like deepgram into own module, and also
allows gets the full flow to work every time we run the program.
2025-07-27 14:18:12 -07:00

169 lines
5.1 KiB
C

#include "deepgram_client.h"
#include <string.h>
// Returns string that caller must free
static char *dg_find_transcript(char *json_response) {
printf("Parsing response: %s \n", json_response);
char *start = strstr(json_response, "\"transcript\":\"");
if (!start)
return NULL;
start += 14; // Skip past "transcript":"
char *end = strchr(start, '"'); // Find closing quote
// Copy substring between start and end
size_t len = end - start;
char *result = malloc(len + 1);
strncpy(result, start, len);
result[len] = '\0';
return result;
}
char *dg_transcribe(FILE *audio_file) {
CURL *curl;
CURLcode res;
struct curl_slist *headers = NULL;
// Initialize response buffer
struct curl_response_data response = {0};
response.data = malloc(1);
response.size = 0;
// Get file size
fseek(audio_file, 0, SEEK_END);
long file_size = ftell(audio_file);
fseek(audio_file, 0, SEEK_SET);
struct curl_file_data data;
data.file = audio_file;
data.size = file_size;
curl = curl_easy_init();
if (curl) {
// Set headers for Deepgram API
char *deepgram_api_key = getenv("DEEPGRAM_API_KEY");
if (!deepgram_api_key) {
fprintf(stderr, "DEEPGRAM_API_KEY environment variable not set\n");
free(response.data);
curl_easy_cleanup(curl);
return NULL;
}
char auth_header[256];
snprintf(auth_header, sizeof(auth_header), "Authorization: Token %s", deepgram_api_key);
headers = curl_slist_append(headers, auth_header);
curl_easy_setopt(curl, CURLOPT_URL,
"https://api.deepgram.com/v1/"
"listen?encoding=linear16&sample_rate=48000&channels=1");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, curl_read_callback_file);
curl_easy_setopt(curl, CURLOPT_READDATA, &data);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, file_size);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_callback_response);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
fprintf(stderr, "curl failed: %s\n", curl_easy_strerror(res));
free(response.data);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
return NULL;
}
printf("done performing curl\n");
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
}
// Parse transcript from complete response
char *transcript = dg_find_transcript(response.data);
free(response.data);
return transcript;
}
struct curl_response_data *dg_text_to_speech(char *text) {
CURL *curl;
CURLcode res;
struct curl_slist *headers = NULL;
// Create JSON payload - need to escape the text properly
// Worst case: every char needs escaping, so allocate 2x + overhead
size_t text_len = strlen(text);
size_t payload_size = text_len * 2 + 100;
char *json_payload = malloc(payload_size);
// Simple approach: replace problematic chars with spaces
char *escaped_text = malloc(text_len + 1);
strcpy(escaped_text, text);
for (int i = 0; escaped_text[i]; i++) {
if (escaped_text[i] == '"' || escaped_text[i] == '\n' ||
escaped_text[i] == '\r' || escaped_text[i] == '\t') {
escaped_text[i] = ' ';
}
}
snprintf(json_payload, payload_size,
"{"
"\"text\":\"%s\""
"}",
escaped_text);
free(escaped_text);
// Initialize response buffer
struct curl_response_data *response =
malloc(sizeof(struct curl_response_data));
response->data = malloc(1);
response->size = 0;
curl = curl_easy_init();
if (curl) {
char *deepgram_api_key = getenv("DEEPGRAM_API_KEY");
if (!deepgram_api_key) {
fprintf(stderr, "DEEPGRAM_API_KEY environment variable not set\n");
free(response->data);
curl_easy_cleanup(curl);
return NULL;
}
char auth_header[256];
snprintf(auth_header, sizeof(auth_header), "Authorization: Token %s", deepgram_api_key);
headers = curl_slist_append(headers, auth_header);
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_URL,
"https://api.deepgram.com/v1/"
"speak?encoding=linear16&sample_rate=48000");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_payload);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_callback_response);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, response);
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
fprintf(stderr, "curl failed: %s\n", curl_easy_strerror(res));
free(response->data);
free(response);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
return NULL;
}
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
}
printf("received audio of %d length for tts\n", (int)response->size);
// Debug: print first 100 chars to see if it's audio or error message
printf("First 100 chars: %.100s\n", response->data);
free(json_payload);
return response;
}