From 9ca1f8273c436a849584aee337ed540a6af6493e Mon Sep 17 00:00:00 2001 From: talksik Date: Sun, 27 Jul 2025 14:47:41 -0700 Subject: [PATCH] organize audio and intelligence modules --- ai-conversation/Makefile | 4 +- ai-conversation/{audio_capture.c => audio.c} | 166 ++----------------- ai-conversation/audio.h | 29 ++++ ai-conversation/audio_capture | Bin 24944 -> 0 bytes ai-conversation/intelligence.c | 86 ++++++++++ ai-conversation/intelligence.h | 9 + ai-conversation/main | Bin 0 -> 74592 bytes ai-conversation/main.c | 44 ++++- 8 files changed, 185 insertions(+), 153 deletions(-) rename ai-conversation/{audio_capture.c => audio.c} (59%) create mode 100644 ai-conversation/audio.h delete mode 100755 ai-conversation/audio_capture create mode 100644 ai-conversation/intelligence.c create mode 100644 ai-conversation/intelligence.h create mode 100755 ai-conversation/main diff --git a/ai-conversation/Makefile b/ai-conversation/Makefile index 176686d..196abb6 100644 --- a/ai-conversation/Makefile +++ b/ai-conversation/Makefile @@ -1,7 +1,7 @@ CC = gcc CFLAGS = -Wall -g -TARGET = audio_capture -SRC = audio_capture.c deepgram_client.c utils.c +TARGET = main +SRC = main.c deepgram_client.c utils.c intelligence.c audio.c LIBS = -lavdevice -lavformat -lavcodec -lavutil -lasound -lcurl $(TARGET): $(SRC) diff --git a/ai-conversation/audio_capture.c b/ai-conversation/audio.c similarity index 59% rename from ai-conversation/audio_capture.c rename to ai-conversation/audio.c index d672d20..99f8366 100644 --- a/ai-conversation/audio_capture.c +++ b/ai-conversation/audio.c @@ -1,113 +1,12 @@ -#include "deepgram_client.h" -#include "utils.h" -#include -#include -#include -#include -#include -#include +#include "audio.h" -// NOTE: find this via `arecord -l` -#define ALSA_MIC_HARDWARE_DEVICE "hw:3" -#define ALSA_SPEAKER_HARDWARE_DEVICE "default" - -void print_pcm_state(snd_pcm_t *pcm_handle) { +static void print_pcm_state(snd_pcm_t *pcm_handle) { snd_pcm_state_t state = snd_pcm_state(pcm_handle); const char *state_name = snd_pcm_state_name(state); printf("State of pcm handle: %s\n", state_name); } -char *find_ai_response(char *json_response) { - printf("Parsing response: %s \n", json_response); - char *start = strstr(json_response, "\"text\":\""); - if (!start) - return NULL; - - start += 8; // Skip past "text":" - char *end = strchr(start, '"'); - if (!end) - return NULL; - - size_t len = end - start; - char *result = malloc(len + 1); - strncpy(result, start, len); - result[len] = '\0'; - return result; -} - -char *ask_ai(char *question) { - 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; - - // Create JSON payload - char json_payload[2048]; - snprintf(json_payload, sizeof(json_payload), - "{" - "\"model\":\"claude-3-haiku-20240307\"," - "\"max_tokens\":1024," - "\"messages\":[{\"role\":\"user\",\"content\":\"%s\"}]" - "}", - question); - - curl = curl_easy_init(); - if (curl) { - char *anthropic_api_key = getenv("ANTHROPIC_API_KEY"); - if (!anthropic_api_key) { - printf("ANTHROPIC_API_KEY not set\n"); - free(response.data); - curl_easy_cleanup(curl); - return NULL; - } - char auth_header[256]; - snprintf(auth_header, sizeof(auth_header), "x-api-key: %s", - anthropic_api_key); - headers = curl_slist_append(headers, "content-type: application/json"); - headers = curl_slist_append(headers, auth_header); - headers = curl_slist_append(headers, "anthropic-version: 2023-06-01"); - - curl_easy_setopt(curl, CURLOPT_URL, - "https://api.anthropic.com/v1/messages"); - 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); - curl_slist_free_all(headers); - curl_easy_cleanup(curl); - return NULL; - } - - curl_slist_free_all(headers); - curl_easy_cleanup(curl); - } - - // Parse AI response from complete response - char *answer = find_ai_response(response.data); - free(response.data); - - return answer; -} - -/* count: how many bytes in the buffer - * returns int: 0 if success, -1 if failure - * NOTE: This function assumes that the audio data is using: - * - linear16 formatting (each sample is 16 bits) - * - one channel (1 sample) - * - with 48000 HZ sampling rate - * Hence, it's 2 bytes per frame. - */ -int play_pcm_data(char *buf, size_t byte_count) { +int audio_play(char *buf, size_t byte_count) { printf("going to play audio of %d bytes of data\n", (int)byte_count); snd_pcm_t *pcm_handle; @@ -192,7 +91,9 @@ int play_pcm_data(char *buf, size_t byte_count) { return 0; } -int main() { +char *audio_capture(uint seconds) { + char *output_file = "output.pcm"; + snd_pcm_t *pcm_handle = NULL; int err; @@ -200,7 +101,7 @@ int main() { SND_PCM_STREAM_CAPTURE, 0); if (err < 0) { printf("unable to open pcm device"); - return -1; + return NULL; } print_pcm_state(pcm_handle); @@ -213,14 +114,14 @@ int main() { if (err < 0) { snd_pcm_close(pcm_handle); printf("unable to get info of pcm device"); - return -1; + return NULL; } name = snd_pcm_info_get_name(pcm_info); if (err < 0) { printf("unable to get card info"); snd_pcm_close(pcm_handle); snd_pcm_info_free(pcm_info); - return -1; + return NULL; } printf("got pcm name: %s \n", name); @@ -231,14 +132,14 @@ int main() { err = snd_pcm_hw_params_malloc(¶ms); if (err < 0) { fprintf(stderr, "unable to mallow hw params"); - return -1; + return NULL; } err = snd_pcm_hw_params_any(pcm_handle, params); if (err < 0) { fprintf(stderr, "unable to find ranges for hw device"); snd_pcm_close(pcm_handle); snd_pcm_hw_params_free(params); - return -1; + return NULL; } uint period_size = 1024; @@ -259,7 +160,7 @@ int main() { fprintf(stderr, "unable to prepare pcm\n"); snd_pcm_close(pcm_handle); snd_pcm_hw_params_free(params); - return -1; + return NULL; } print_pcm_state(pcm_handle); @@ -269,12 +170,12 @@ int main() { fprintf(stderr, "unable to start pcm"); snd_pcm_close(pcm_handle); snd_pcm_hw_params_free(params); - return -1; + return NULL; } print_pcm_state(pcm_handle); - const uint seconds_to_capture = 5; + const uint seconds_to_capture = seconds; const uint periods_to_read = (samples_per_second * seconds_to_capture) / period_size; char *buf = malloc(period_size * channel_count * bytes_per_sample); @@ -285,10 +186,10 @@ int main() { * Each period is 2048 BYTES because each frame is 2 bytes. * Each frame is 2 bytes because of 1 channel, and 16 bit format */ - FILE *file = fopen("output.pcm", "wb"); + FILE *file = fopen(output_file, "wb"); if (file == NULL) { perror("Error opening file"); - return 1; + return NULL; } printf("======READING FRAMES for 5 seconds========\n"); while (snd_pcm_readi(pcm_handle, (void *)buf, period_size) > 0 && @@ -306,42 +207,9 @@ int main() { fclose(file); - // Reopen file for reading and transcribe - file = fopen("output.pcm", "rb"); - if (file != NULL) { - char *transcript = dg_transcribe(file); - if (transcript) { - printf("Transcript: %s\n", transcript); - - char *ai_answer = ask_ai(transcript); - if (ai_answer) { - printf("AI answer: %s\n", ai_answer); - - struct curl_response_data *tts_response = dg_text_to_speech(ai_answer); - int result = play_pcm_data(tts_response->data, tts_response->size); - if (result != 0) { - fprintf(stderr, "failure in playback"); - } - - free(tts_response->data); - free(tts_response); - - // we have this response data, and buffer within it. we can loop through - // it and write the pcm data within it to alsa - free(ai_answer); - } - free(transcript); - } else { - fprintf(stderr, "unable to get transcript"); - } - fclose(file); - } else { - fprintf(stderr, "unable to open file for reading\n"); - } - free(buf); snd_pcm_close(pcm_handle); snd_pcm_hw_params_free(params); - return 0; + return output_file; } diff --git a/ai-conversation/audio.h b/ai-conversation/audio.h new file mode 100644 index 0000000..4f86357 --- /dev/null +++ b/ai-conversation/audio.h @@ -0,0 +1,29 @@ +#ifndef AUDIOCAPTURE_H +#define AUDIOCAPTURE_H + +#include +#include +#include +#include +#include +#include + +// NOTE: find this via `arecord -l` +#define ALSA_MIC_HARDWARE_DEVICE "hw:3" +#define ALSA_SPEAKER_HARDWARE_DEVICE "default" + +// Captures audio for given seconds, and returns file name that we captured the +// audio into +char *audio_capture(uint seconds); + +/* count: how many bytes in the buffer + * returns int: 0 if success, -1 if failure + * NOTE: This function assumes that the audio data is using: + * - linear16 formatting (each sample is 16 bits) + * - one channel (1 sample) + * - with 48000 HZ sampling rate + * Hence, it's 2 bytes per frame. + */ +int audio_play(char *buf, size_t byte_count); + +#endif // AUDIOCAPTURE_H diff --git a/ai-conversation/audio_capture b/ai-conversation/audio_capture deleted file mode 100755 index 99d283e0d4c5fc496151a473d5710dd3b8549066..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24944 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 +#include + +static char *find_ai_response(char *json_response) { + printf("Parsing response: %s \n", json_response); + char *start = strstr(json_response, "\"text\":\""); + if (!start) + return NULL; + + start += 8; // Skip past "text":" + char *end = strchr(start, '"'); + if (!end) + return NULL; + + size_t len = end - start; + char *result = malloc(len + 1); + strncpy(result, start, len); + result[len] = '\0'; + return result; +} + +char *ai_ask(char *question) { + 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; + + // Create JSON payload + char json_payload[2048]; + snprintf(json_payload, sizeof(json_payload), + "{" + "\"model\":\"claude-3-haiku-20240307\"," + "\"max_tokens\":256," + "\"messages\":[{\"role\":\"user\",\"content\":\"Make it one sentence answer: %s\"}]" + "}", + question); + + curl = curl_easy_init(); + if (curl) { + char *anthropic_api_key = getenv("ANTHROPIC_API_KEY"); + if (!anthropic_api_key) { + printf("ANTHROPIC_API_KEY not set\n"); + free(response.data); + curl_easy_cleanup(curl); + return NULL; + } + char auth_header[256]; + snprintf(auth_header, sizeof(auth_header), "x-api-key: %s", + anthropic_api_key); + headers = curl_slist_append(headers, "content-type: application/json"); + headers = curl_slist_append(headers, auth_header); + headers = curl_slist_append(headers, "anthropic-version: 2023-06-01"); + + curl_easy_setopt(curl, CURLOPT_URL, + "https://api.anthropic.com/v1/messages"); + 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); + curl_slist_free_all(headers); + curl_easy_cleanup(curl); + return NULL; + } + + curl_slist_free_all(headers); + curl_easy_cleanup(curl); + } + + // Parse AI response from complete response + char *answer = find_ai_response(response.data); + free(response.data); + + return answer; +} diff --git a/ai-conversation/intelligence.h b/ai-conversation/intelligence.h new file mode 100644 index 0000000..7404e05 --- /dev/null +++ b/ai-conversation/intelligence.h @@ -0,0 +1,9 @@ +#ifndef INTELLIGENCE_H +#define INTELLIGENCE_H + +#include +#include + +char *ai_ask(char *question); + +#endif //INTELLIGENCE_H diff --git a/ai-conversation/main b/ai-conversation/main new file mode 100755 index 0000000000000000000000000000000000000000..cd90b24db9c0356492d304cdef244d3e20e7a55f GIT binary patch literal 74592 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 +#include -int main() { - printf("hello world \n"); +int main(int argc, char *argv[]) { + char *capture_audio_file = audio_capture(5); + + // Reopen file for reading and transcribe + FILE *file = fopen(capture_audio_file, "rb"); + if (file != NULL) { + char *transcript = dg_transcribe(file); + if (transcript) { + printf("Transcript: %s\n", transcript); + + char *ai_answer = ai_ask(transcript); + if (ai_answer) { + printf("AI answer: %s\n", ai_answer); + + struct curl_response_data *tts_response = dg_text_to_speech(ai_answer); + int result = audio_play(tts_response->data, tts_response->size); + if (result != 0) { + fprintf(stderr, "failure in playback"); + } + + free(tts_response->data); + free(tts_response); + + // we have this response data, and buffer within it. we can loop through + // it and write the pcm data within it to alsa + free(ai_answer); + } + free(transcript); + } else { + fprintf(stderr, "unable to get transcript"); + } + fclose(file); + } else { + fprintf(stderr, "unable to open file for reading\n"); + } + + return 0; }