diff --git a/.gitignore b/.gitignore index 032eab8..dface39 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ **.bin **.wav **.db +ai-hub/data/* diff --git a/.gitignore b/.gitignore index 032eab8..dface39 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ **.bin **.wav **.db +ai-hub/data/* diff --git a/ai-hub/test_speach.sh b/ai-hub/test_speach.sh deleted file mode 100644 index 931540e..0000000 --- a/ai-hub/test_speach.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/bin/bash - -# --- 0. Load environment variables from .env file --- -# Check if .env file exists -if [ -f .env ]; then - echo "Loading environment variables from .env" - # Use 'source' to read and set the variables from the file. - # This pattern correctly handles variables with or without quotes and comments. - export $(grep -v '^#' .env | xargs) -fi -export LOG_LEVEL=DEBUG - -# Define the API endpoint -API_URL="http://localhost:8000/documents" - -DEFAULT_MODEL="gemini" -CURRENT_MODEL="" # The model used in the last turn - -# --- 1. Check for Dependencies --- -if ! command -v jq &> /dev/null -then - echo "❌ 'jq' is not installed. Please install it to run this script." - exit 1 -fi - -# --- 2. Start the FastAPI Server in the Background --- -echo "--- Starting AI Hub Server ---" -# Ensure the API key is passed to the uvicorn process, -# either directly or by ensuring it's in the environment. -# The 'export' command above ensures this. -uvicorn app.main:app --host 127.00.1 --port 8000 & -SERVER_PID=$! - -# Define a cleanup function to kill the server on exit -cleanup() { - echo "" - echo "--- Shutting Down Server (PID: $SERVER_PID) ---" - kill $SERVER_PID -} -# Register the cleanup function to run when the script exits (e.g., Ctrl+C or typing 'exit') -trap cleanup EXIT - -echo "Server started with PID: $SERVER_PID. Waiting for it to initialize..." -sleep 5 # Wait for the server to be ready - -BASE_URL="http://localhost:8000" - -# --- 3. Test both non-streaming and streaming modes --- -TEST_TEXT="The old clock in the corner of the study ticked with a slow, deliberate rhythm, a metronome for the quiet dust motes dancing in the sunbeams that slanted through the window. Its brass pendulum swung with a hypnotizing arc, a steady pulse in the otherwise silent room. Elara, with a frown of concentration, dipped her quill into the inkwell, the black liquid swirling like a miniature galaxy. She was trying to translate an ancient text, a forgotten language filled with serpentine characters and cryptic symbols. The work was painstaking, each character a puzzle box waiting to be opened. Outside, a gentle rain began to fall, pattering softly against the glass in a counterpoint to the clock’s beat. - -The manuscript she was working on was rumored to hold the key to a lost library, a repository of knowledge that had vanished from the world centuries ago. Elara, a historian with a thirst for the past, had dedicated her life to its recovery. She believed the library wasn't just a place of books, but a sanctuary of ideas, of stories untold and wisdom unwritten. A sudden gust of wind rattled the windowpane, and a drop of water streaked across the glass like a tear. She paused, her eyes drifting from the text to the stormy sky, a sense of foreboding settling over her. The story she was reading spoke of a great flood, a cataclysm that had swept away all traces of the library, leaving only this fragmented manuscript as a breadcrumb trail. It was a warning, she realized, not just a tale. The storm outside seemed to be echoing the prophecy within the text, a chilling reminder of the cyclical nature of history. - -As the light began to fade, replaced by the bruised purple of twilight, Elara lit a small oil lamp. The flame cast flickering shadows on the walls, making the bookshelves appear as if they were filled with sleeping giants. The air grew heavy with the scent of old paper and dust. She returned to her work, her mind racing with newfound purpose. The text wasn't just a map to the library, it was a warning of what could happen if its knowledge remained hidden. It was a plea to prevent history from repeating itself. The clock ticked on, a relentless march towards an uncertain future. Elara, however, was no longer just a translator. She was a guardian, a custodian of the past, tasked with saving the future. Her quill scratched across the paper, the sound a defiant whisper in the growing darkness, a promise to not let the words of the past be silenced by the storms of the present" - -# Create a temporary file to store the JSON payload -TEMP_JSON_FILE=$(mktemp) -cat > "$TEMP_JSON_FILE" << EOF -{ - "text": "$TEST_TEXT" -} -EOF - -# # --- Test non-streaming mode --- -# echo "" -# echo "--- Testing non-streaming mode for /speech endpoint ---" -# NON_STREAM_OUTPUT_FILE="speech_nostream.wav" -# curl -s -X POST "$BASE_URL/speech" \ -# -H "Content-Type: application/json" \ -# --data "@$TEMP_JSON_FILE" \ -# --output "$NON_STREAM_OUTPUT_FILE" - -# if [ -f "$NON_STREAM_OUTPUT_FILE" ]; then -# echo "✅ Success! Non-streaming audio saved to $NON_STREAM_OUTPUT_FILE" -# else -# echo "❌ Failed to get non-streaming audio" -# fi - -# --- Test streaming mode --- -echo "" -echo "--- Testing streaming mode for /speech endpoint ---" -STREAM_OUTPUT_FILE="data/speech_stream.wav" -curl -s -X POST "$BASE_URL/speech?stream=true" \ - -H "Content-Type: application/json" \ - --data "@$TEMP_JSON_FILE" \ - --output "$STREAM_OUTPUT_FILE" - -if [ -f "$STREAM_OUTPUT_FILE" ]; then - echo "✅ Success! Streaming audio saved to $STREAM_OUTPUT_FILE" -else - echo "❌ Failed to get streaming audio" -fi - -# Remove the temporary file -rm "$TEMP_JSON_FILE" - -echo "" -echo "--- Tests complete. ---" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 032eab8..dface39 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ **.bin **.wav **.db +ai-hub/data/* diff --git a/ai-hub/test_speach.sh b/ai-hub/test_speach.sh deleted file mode 100644 index 931540e..0000000 --- a/ai-hub/test_speach.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/bin/bash - -# --- 0. Load environment variables from .env file --- -# Check if .env file exists -if [ -f .env ]; then - echo "Loading environment variables from .env" - # Use 'source' to read and set the variables from the file. - # This pattern correctly handles variables with or without quotes and comments. - export $(grep -v '^#' .env | xargs) -fi -export LOG_LEVEL=DEBUG - -# Define the API endpoint -API_URL="http://localhost:8000/documents" - -DEFAULT_MODEL="gemini" -CURRENT_MODEL="" # The model used in the last turn - -# --- 1. Check for Dependencies --- -if ! command -v jq &> /dev/null -then - echo "❌ 'jq' is not installed. Please install it to run this script." - exit 1 -fi - -# --- 2. Start the FastAPI Server in the Background --- -echo "--- Starting AI Hub Server ---" -# Ensure the API key is passed to the uvicorn process, -# either directly or by ensuring it's in the environment. -# The 'export' command above ensures this. -uvicorn app.main:app --host 127.00.1 --port 8000 & -SERVER_PID=$! - -# Define a cleanup function to kill the server on exit -cleanup() { - echo "" - echo "--- Shutting Down Server (PID: $SERVER_PID) ---" - kill $SERVER_PID -} -# Register the cleanup function to run when the script exits (e.g., Ctrl+C or typing 'exit') -trap cleanup EXIT - -echo "Server started with PID: $SERVER_PID. Waiting for it to initialize..." -sleep 5 # Wait for the server to be ready - -BASE_URL="http://localhost:8000" - -# --- 3. Test both non-streaming and streaming modes --- -TEST_TEXT="The old clock in the corner of the study ticked with a slow, deliberate rhythm, a metronome for the quiet dust motes dancing in the sunbeams that slanted through the window. Its brass pendulum swung with a hypnotizing arc, a steady pulse in the otherwise silent room. Elara, with a frown of concentration, dipped her quill into the inkwell, the black liquid swirling like a miniature galaxy. She was trying to translate an ancient text, a forgotten language filled with serpentine characters and cryptic symbols. The work was painstaking, each character a puzzle box waiting to be opened. Outside, a gentle rain began to fall, pattering softly against the glass in a counterpoint to the clock’s beat. - -The manuscript she was working on was rumored to hold the key to a lost library, a repository of knowledge that had vanished from the world centuries ago. Elara, a historian with a thirst for the past, had dedicated her life to its recovery. She believed the library wasn't just a place of books, but a sanctuary of ideas, of stories untold and wisdom unwritten. A sudden gust of wind rattled the windowpane, and a drop of water streaked across the glass like a tear. She paused, her eyes drifting from the text to the stormy sky, a sense of foreboding settling over her. The story she was reading spoke of a great flood, a cataclysm that had swept away all traces of the library, leaving only this fragmented manuscript as a breadcrumb trail. It was a warning, she realized, not just a tale. The storm outside seemed to be echoing the prophecy within the text, a chilling reminder of the cyclical nature of history. - -As the light began to fade, replaced by the bruised purple of twilight, Elara lit a small oil lamp. The flame cast flickering shadows on the walls, making the bookshelves appear as if they were filled with sleeping giants. The air grew heavy with the scent of old paper and dust. She returned to her work, her mind racing with newfound purpose. The text wasn't just a map to the library, it was a warning of what could happen if its knowledge remained hidden. It was a plea to prevent history from repeating itself. The clock ticked on, a relentless march towards an uncertain future. Elara, however, was no longer just a translator. She was a guardian, a custodian of the past, tasked with saving the future. Her quill scratched across the paper, the sound a defiant whisper in the growing darkness, a promise to not let the words of the past be silenced by the storms of the present" - -# Create a temporary file to store the JSON payload -TEMP_JSON_FILE=$(mktemp) -cat > "$TEMP_JSON_FILE" << EOF -{ - "text": "$TEST_TEXT" -} -EOF - -# # --- Test non-streaming mode --- -# echo "" -# echo "--- Testing non-streaming mode for /speech endpoint ---" -# NON_STREAM_OUTPUT_FILE="speech_nostream.wav" -# curl -s -X POST "$BASE_URL/speech" \ -# -H "Content-Type: application/json" \ -# --data "@$TEMP_JSON_FILE" \ -# --output "$NON_STREAM_OUTPUT_FILE" - -# if [ -f "$NON_STREAM_OUTPUT_FILE" ]; then -# echo "✅ Success! Non-streaming audio saved to $NON_STREAM_OUTPUT_FILE" -# else -# echo "❌ Failed to get non-streaming audio" -# fi - -# --- Test streaming mode --- -echo "" -echo "--- Testing streaming mode for /speech endpoint ---" -STREAM_OUTPUT_FILE="data/speech_stream.wav" -curl -s -X POST "$BASE_URL/speech?stream=true" \ - -H "Content-Type: application/json" \ - --data "@$TEMP_JSON_FILE" \ - --output "$STREAM_OUTPUT_FILE" - -if [ -f "$STREAM_OUTPUT_FILE" ]; then - echo "✅ Success! Streaming audio saved to $STREAM_OUTPUT_FILE" -else - echo "❌ Failed to get streaming audio" -fi - -# Remove the temporary file -rm "$TEMP_JSON_FILE" - -echo "" -echo "--- Tests complete. ---" \ No newline at end of file diff --git a/ai-hub/test_stt.sh b/ai-hub/test_stt.sh new file mode 100644 index 0000000..9612819 --- /dev/null +++ b/ai-hub/test_stt.sh @@ -0,0 +1,81 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [ $# -lt 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +AUDIO_PATH="$1" +DISPLAY_NAME="AUDIO" + +if [ ! -f "$AUDIO_PATH" ]; then + echo "Error: File not found: $AUDIO_PATH" + exit 1 +fi + +if [ -z "${GEMINI_API_KEY:-}" ]; then + echo "Error: GEMINI_API_KEY environment variable not set." + exit 1 +fi + +MIME_TYPE=$(file -b --mime-type "${AUDIO_PATH}") +NUM_BYTES=$(wc -c < "${AUDIO_PATH}") +TMP_HEADER_FILE=$(mktemp) + +# Remove any old JSON files +rm -f file_info.json request.json + +# Step 1: Start resumable upload +curl -s "https://generativelanguage.googleapis.com/upload/v1beta/files" \ + -H "x-goog-api-key: $GEMINI_API_KEY" \ + -D "$TMP_HEADER_FILE" \ + -H "X-Goog-Upload-Protocol: resumable" \ + -H "X-Goog-Upload-Command: start" \ + -H "X-Goog-Upload-Header-Content-Length: ${NUM_BYTES}" \ + -H "X-Goog-Upload-Header-Content-Type: ${MIME_TYPE}" \ + -H "Content-Type: application/json" \ + -d "{\"file\": {\"display_name\": \"${DISPLAY_NAME}\"}}" >/dev/null + +UPLOAD_URL=$(grep -i "x-goog-upload-url: " "$TMP_HEADER_FILE" | cut -d" " -f2 | tr -d "\r") +rm "$TMP_HEADER_FILE" + +# Step 2: Upload the file +curl -s "${UPLOAD_URL}" \ + -H "Content-Length: ${NUM_BYTES}" \ + -H "X-Goog-Upload-Offset: 0" \ + -H "X-Goog-Upload-Command: upload, finalize" \ + --data-binary "@${AUDIO_PATH}" > data/file_info.json + +FILE_URI="https://generativelanguage.googleapis.com/v1beta/files/$(jq -r '.file.name' data/file_info.json | cut -d'/' -f2)" + +# Step 3: Prepare request +cat > data/request.json < /dev/null -then - echo "❌ 'jq' is not installed. Please install it to run this script." - exit 1 -fi - -# --- 2. Start the FastAPI Server in the Background --- -echo "--- Starting AI Hub Server ---" -# Ensure the API key is passed to the uvicorn process, -# either directly or by ensuring it's in the environment. -# The 'export' command above ensures this. -uvicorn app.main:app --host 127.00.1 --port 8000 & -SERVER_PID=$! - -# Define a cleanup function to kill the server on exit -cleanup() { - echo "" - echo "--- Shutting Down Server (PID: $SERVER_PID) ---" - kill $SERVER_PID -} -# Register the cleanup function to run when the script exits (e.g., Ctrl+C or typing 'exit') -trap cleanup EXIT - -echo "Server started with PID: $SERVER_PID. Waiting for it to initialize..." -sleep 5 # Wait for the server to be ready - -BASE_URL="http://localhost:8000" - -# --- 3. Test both non-streaming and streaming modes --- -TEST_TEXT="The old clock in the corner of the study ticked with a slow, deliberate rhythm, a metronome for the quiet dust motes dancing in the sunbeams that slanted through the window. Its brass pendulum swung with a hypnotizing arc, a steady pulse in the otherwise silent room. Elara, with a frown of concentration, dipped her quill into the inkwell, the black liquid swirling like a miniature galaxy. She was trying to translate an ancient text, a forgotten language filled with serpentine characters and cryptic symbols. The work was painstaking, each character a puzzle box waiting to be opened. Outside, a gentle rain began to fall, pattering softly against the glass in a counterpoint to the clock’s beat. - -The manuscript she was working on was rumored to hold the key to a lost library, a repository of knowledge that had vanished from the world centuries ago. Elara, a historian with a thirst for the past, had dedicated her life to its recovery. She believed the library wasn't just a place of books, but a sanctuary of ideas, of stories untold and wisdom unwritten. A sudden gust of wind rattled the windowpane, and a drop of water streaked across the glass like a tear. She paused, her eyes drifting from the text to the stormy sky, a sense of foreboding settling over her. The story she was reading spoke of a great flood, a cataclysm that had swept away all traces of the library, leaving only this fragmented manuscript as a breadcrumb trail. It was a warning, she realized, not just a tale. The storm outside seemed to be echoing the prophecy within the text, a chilling reminder of the cyclical nature of history. - -As the light began to fade, replaced by the bruised purple of twilight, Elara lit a small oil lamp. The flame cast flickering shadows on the walls, making the bookshelves appear as if they were filled with sleeping giants. The air grew heavy with the scent of old paper and dust. She returned to her work, her mind racing with newfound purpose. The text wasn't just a map to the library, it was a warning of what could happen if its knowledge remained hidden. It was a plea to prevent history from repeating itself. The clock ticked on, a relentless march towards an uncertain future. Elara, however, was no longer just a translator. She was a guardian, a custodian of the past, tasked with saving the future. Her quill scratched across the paper, the sound a defiant whisper in the growing darkness, a promise to not let the words of the past be silenced by the storms of the present" - -# Create a temporary file to store the JSON payload -TEMP_JSON_FILE=$(mktemp) -cat > "$TEMP_JSON_FILE" << EOF -{ - "text": "$TEST_TEXT" -} -EOF - -# # --- Test non-streaming mode --- -# echo "" -# echo "--- Testing non-streaming mode for /speech endpoint ---" -# NON_STREAM_OUTPUT_FILE="speech_nostream.wav" -# curl -s -X POST "$BASE_URL/speech" \ -# -H "Content-Type: application/json" \ -# --data "@$TEMP_JSON_FILE" \ -# --output "$NON_STREAM_OUTPUT_FILE" - -# if [ -f "$NON_STREAM_OUTPUT_FILE" ]; then -# echo "✅ Success! Non-streaming audio saved to $NON_STREAM_OUTPUT_FILE" -# else -# echo "❌ Failed to get non-streaming audio" -# fi - -# --- Test streaming mode --- -echo "" -echo "--- Testing streaming mode for /speech endpoint ---" -STREAM_OUTPUT_FILE="data/speech_stream.wav" -curl -s -X POST "$BASE_URL/speech?stream=true" \ - -H "Content-Type: application/json" \ - --data "@$TEMP_JSON_FILE" \ - --output "$STREAM_OUTPUT_FILE" - -if [ -f "$STREAM_OUTPUT_FILE" ]; then - echo "✅ Success! Streaming audio saved to $STREAM_OUTPUT_FILE" -else - echo "❌ Failed to get streaming audio" -fi - -# Remove the temporary file -rm "$TEMP_JSON_FILE" - -echo "" -echo "--- Tests complete. ---" \ No newline at end of file diff --git a/ai-hub/test_stt.sh b/ai-hub/test_stt.sh new file mode 100644 index 0000000..9612819 --- /dev/null +++ b/ai-hub/test_stt.sh @@ -0,0 +1,81 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [ $# -lt 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +AUDIO_PATH="$1" +DISPLAY_NAME="AUDIO" + +if [ ! -f "$AUDIO_PATH" ]; then + echo "Error: File not found: $AUDIO_PATH" + exit 1 +fi + +if [ -z "${GEMINI_API_KEY:-}" ]; then + echo "Error: GEMINI_API_KEY environment variable not set." + exit 1 +fi + +MIME_TYPE=$(file -b --mime-type "${AUDIO_PATH}") +NUM_BYTES=$(wc -c < "${AUDIO_PATH}") +TMP_HEADER_FILE=$(mktemp) + +# Remove any old JSON files +rm -f file_info.json request.json + +# Step 1: Start resumable upload +curl -s "https://generativelanguage.googleapis.com/upload/v1beta/files" \ + -H "x-goog-api-key: $GEMINI_API_KEY" \ + -D "$TMP_HEADER_FILE" \ + -H "X-Goog-Upload-Protocol: resumable" \ + -H "X-Goog-Upload-Command: start" \ + -H "X-Goog-Upload-Header-Content-Length: ${NUM_BYTES}" \ + -H "X-Goog-Upload-Header-Content-Type: ${MIME_TYPE}" \ + -H "Content-Type: application/json" \ + -d "{\"file\": {\"display_name\": \"${DISPLAY_NAME}\"}}" >/dev/null + +UPLOAD_URL=$(grep -i "x-goog-upload-url: " "$TMP_HEADER_FILE" | cut -d" " -f2 | tr -d "\r") +rm "$TMP_HEADER_FILE" + +# Step 2: Upload the file +curl -s "${UPLOAD_URL}" \ + -H "Content-Length: ${NUM_BYTES}" \ + -H "X-Goog-Upload-Offset: 0" \ + -H "X-Goog-Upload-Command: upload, finalize" \ + --data-binary "@${AUDIO_PATH}" > data/file_info.json + +FILE_URI="https://generativelanguage.googleapis.com/v1beta/files/$(jq -r '.file.name' data/file_info.json | cut -d'/' -f2)" + +# Step 3: Prepare request +cat > data/request.json < /dev/null; then + echo "❌ 'jq' is not installed. Please install it to run this script." + exit 1 +fi + +# --- 2. Start the FastAPI Server in the Background --- +echo "--- Starting AI Hub Server ---" +uvicorn app.main:app --host 127.0.0.1 --port 8000 & +SERVER_PID=$! + +cleanup() { + echo "" + echo "--- Shutting Down Server (PID: $SERVER_PID) ---" + kill $SERVER_PID +} +trap cleanup EXIT + +echo "Server started with PID: $SERVER_PID. Waiting for it to initialize..." +sleep 5 + +BASE_URL="http://localhost:8000" + +# --- 3. Get TEST_TEXT from CLI argument --- +if [ -z "$1" ]; then + echo "❌ No input text provided." + echo "Usage: $0 \"Your text to send to /speech\"" + exit 1 +fi +TEST_TEXT="$1" + +# Create a temporary file to store the JSON payload +TEMP_JSON_FILE=$(mktemp) +cat > "$TEMP_JSON_FILE" << EOF +{ + "text": "$TEST_TEXT" +} +EOF + +# --- Test streaming mode --- +echo "" +echo "--- Testing streaming mode for /speech endpoint ---" +STREAM_OUTPUT_FILE="data/speech_stream.wav" +curl -s -X POST "$BASE_URL/speech?stream=true" \ + -H "Content-Type: application/json" \ + --data "@$TEMP_JSON_FILE" \ + --output "$STREAM_OUTPUT_FILE" + +if [ -f "$STREAM_OUTPUT_FILE" ]; then + echo "✅ Success! Streaming audio saved to $STREAM_OUTPUT_FILE" +else + echo "❌ Failed to get streaming audio" +fi + +rm "$TEMP_JSON_FILE" +echo "" +echo "--- Tests complete. ---" diff --git a/.gitignore b/.gitignore index 032eab8..dface39 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ **.bin **.wav **.db +ai-hub/data/* diff --git a/ai-hub/test_speach.sh b/ai-hub/test_speach.sh deleted file mode 100644 index 931540e..0000000 --- a/ai-hub/test_speach.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/bin/bash - -# --- 0. Load environment variables from .env file --- -# Check if .env file exists -if [ -f .env ]; then - echo "Loading environment variables from .env" - # Use 'source' to read and set the variables from the file. - # This pattern correctly handles variables with or without quotes and comments. - export $(grep -v '^#' .env | xargs) -fi -export LOG_LEVEL=DEBUG - -# Define the API endpoint -API_URL="http://localhost:8000/documents" - -DEFAULT_MODEL="gemini" -CURRENT_MODEL="" # The model used in the last turn - -# --- 1. Check for Dependencies --- -if ! command -v jq &> /dev/null -then - echo "❌ 'jq' is not installed. Please install it to run this script." - exit 1 -fi - -# --- 2. Start the FastAPI Server in the Background --- -echo "--- Starting AI Hub Server ---" -# Ensure the API key is passed to the uvicorn process, -# either directly or by ensuring it's in the environment. -# The 'export' command above ensures this. -uvicorn app.main:app --host 127.00.1 --port 8000 & -SERVER_PID=$! - -# Define a cleanup function to kill the server on exit -cleanup() { - echo "" - echo "--- Shutting Down Server (PID: $SERVER_PID) ---" - kill $SERVER_PID -} -# Register the cleanup function to run when the script exits (e.g., Ctrl+C or typing 'exit') -trap cleanup EXIT - -echo "Server started with PID: $SERVER_PID. Waiting for it to initialize..." -sleep 5 # Wait for the server to be ready - -BASE_URL="http://localhost:8000" - -# --- 3. Test both non-streaming and streaming modes --- -TEST_TEXT="The old clock in the corner of the study ticked with a slow, deliberate rhythm, a metronome for the quiet dust motes dancing in the sunbeams that slanted through the window. Its brass pendulum swung with a hypnotizing arc, a steady pulse in the otherwise silent room. Elara, with a frown of concentration, dipped her quill into the inkwell, the black liquid swirling like a miniature galaxy. She was trying to translate an ancient text, a forgotten language filled with serpentine characters and cryptic symbols. The work was painstaking, each character a puzzle box waiting to be opened. Outside, a gentle rain began to fall, pattering softly against the glass in a counterpoint to the clock’s beat. - -The manuscript she was working on was rumored to hold the key to a lost library, a repository of knowledge that had vanished from the world centuries ago. Elara, a historian with a thirst for the past, had dedicated her life to its recovery. She believed the library wasn't just a place of books, but a sanctuary of ideas, of stories untold and wisdom unwritten. A sudden gust of wind rattled the windowpane, and a drop of water streaked across the glass like a tear. She paused, her eyes drifting from the text to the stormy sky, a sense of foreboding settling over her. The story she was reading spoke of a great flood, a cataclysm that had swept away all traces of the library, leaving only this fragmented manuscript as a breadcrumb trail. It was a warning, she realized, not just a tale. The storm outside seemed to be echoing the prophecy within the text, a chilling reminder of the cyclical nature of history. - -As the light began to fade, replaced by the bruised purple of twilight, Elara lit a small oil lamp. The flame cast flickering shadows on the walls, making the bookshelves appear as if they were filled with sleeping giants. The air grew heavy with the scent of old paper and dust. She returned to her work, her mind racing with newfound purpose. The text wasn't just a map to the library, it was a warning of what could happen if its knowledge remained hidden. It was a plea to prevent history from repeating itself. The clock ticked on, a relentless march towards an uncertain future. Elara, however, was no longer just a translator. She was a guardian, a custodian of the past, tasked with saving the future. Her quill scratched across the paper, the sound a defiant whisper in the growing darkness, a promise to not let the words of the past be silenced by the storms of the present" - -# Create a temporary file to store the JSON payload -TEMP_JSON_FILE=$(mktemp) -cat > "$TEMP_JSON_FILE" << EOF -{ - "text": "$TEST_TEXT" -} -EOF - -# # --- Test non-streaming mode --- -# echo "" -# echo "--- Testing non-streaming mode for /speech endpoint ---" -# NON_STREAM_OUTPUT_FILE="speech_nostream.wav" -# curl -s -X POST "$BASE_URL/speech" \ -# -H "Content-Type: application/json" \ -# --data "@$TEMP_JSON_FILE" \ -# --output "$NON_STREAM_OUTPUT_FILE" - -# if [ -f "$NON_STREAM_OUTPUT_FILE" ]; then -# echo "✅ Success! Non-streaming audio saved to $NON_STREAM_OUTPUT_FILE" -# else -# echo "❌ Failed to get non-streaming audio" -# fi - -# --- Test streaming mode --- -echo "" -echo "--- Testing streaming mode for /speech endpoint ---" -STREAM_OUTPUT_FILE="data/speech_stream.wav" -curl -s -X POST "$BASE_URL/speech?stream=true" \ - -H "Content-Type: application/json" \ - --data "@$TEMP_JSON_FILE" \ - --output "$STREAM_OUTPUT_FILE" - -if [ -f "$STREAM_OUTPUT_FILE" ]; then - echo "✅ Success! Streaming audio saved to $STREAM_OUTPUT_FILE" -else - echo "❌ Failed to get streaming audio" -fi - -# Remove the temporary file -rm "$TEMP_JSON_FILE" - -echo "" -echo "--- Tests complete. ---" \ No newline at end of file diff --git a/ai-hub/test_stt.sh b/ai-hub/test_stt.sh new file mode 100644 index 0000000..9612819 --- /dev/null +++ b/ai-hub/test_stt.sh @@ -0,0 +1,81 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [ $# -lt 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +AUDIO_PATH="$1" +DISPLAY_NAME="AUDIO" + +if [ ! -f "$AUDIO_PATH" ]; then + echo "Error: File not found: $AUDIO_PATH" + exit 1 +fi + +if [ -z "${GEMINI_API_KEY:-}" ]; then + echo "Error: GEMINI_API_KEY environment variable not set." + exit 1 +fi + +MIME_TYPE=$(file -b --mime-type "${AUDIO_PATH}") +NUM_BYTES=$(wc -c < "${AUDIO_PATH}") +TMP_HEADER_FILE=$(mktemp) + +# Remove any old JSON files +rm -f file_info.json request.json + +# Step 1: Start resumable upload +curl -s "https://generativelanguage.googleapis.com/upload/v1beta/files" \ + -H "x-goog-api-key: $GEMINI_API_KEY" \ + -D "$TMP_HEADER_FILE" \ + -H "X-Goog-Upload-Protocol: resumable" \ + -H "X-Goog-Upload-Command: start" \ + -H "X-Goog-Upload-Header-Content-Length: ${NUM_BYTES}" \ + -H "X-Goog-Upload-Header-Content-Type: ${MIME_TYPE}" \ + -H "Content-Type: application/json" \ + -d "{\"file\": {\"display_name\": \"${DISPLAY_NAME}\"}}" >/dev/null + +UPLOAD_URL=$(grep -i "x-goog-upload-url: " "$TMP_HEADER_FILE" | cut -d" " -f2 | tr -d "\r") +rm "$TMP_HEADER_FILE" + +# Step 2: Upload the file +curl -s "${UPLOAD_URL}" \ + -H "Content-Length: ${NUM_BYTES}" \ + -H "X-Goog-Upload-Offset: 0" \ + -H "X-Goog-Upload-Command: upload, finalize" \ + --data-binary "@${AUDIO_PATH}" > data/file_info.json + +FILE_URI="https://generativelanguage.googleapis.com/v1beta/files/$(jq -r '.file.name' data/file_info.json | cut -d'/' -f2)" + +# Step 3: Prepare request +cat > data/request.json < /dev/null; then + echo "❌ 'jq' is not installed. Please install it to run this script." + exit 1 +fi + +# --- 2. Start the FastAPI Server in the Background --- +echo "--- Starting AI Hub Server ---" +uvicorn app.main:app --host 127.0.0.1 --port 8000 & +SERVER_PID=$! + +cleanup() { + echo "" + echo "--- Shutting Down Server (PID: $SERVER_PID) ---" + kill $SERVER_PID +} +trap cleanup EXIT + +echo "Server started with PID: $SERVER_PID. Waiting for it to initialize..." +sleep 5 + +BASE_URL="http://localhost:8000" + +# --- 3. Get TEST_TEXT from CLI argument --- +if [ -z "$1" ]; then + echo "❌ No input text provided." + echo "Usage: $0 \"Your text to send to /speech\"" + exit 1 +fi +TEST_TEXT="$1" + +# Create a temporary file to store the JSON payload +TEMP_JSON_FILE=$(mktemp) +cat > "$TEMP_JSON_FILE" << EOF +{ + "text": "$TEST_TEXT" +} +EOF + +# --- Test streaming mode --- +echo "" +echo "--- Testing streaming mode for /speech endpoint ---" +STREAM_OUTPUT_FILE="data/speech_stream.wav" +curl -s -X POST "$BASE_URL/speech?stream=true" \ + -H "Content-Type: application/json" \ + --data "@$TEMP_JSON_FILE" \ + --output "$STREAM_OUTPUT_FILE" + +if [ -f "$STREAM_OUTPUT_FILE" ]; then + echo "✅ Success! Streaming audio saved to $STREAM_OUTPUT_FILE" +else + echo "❌ Failed to get streaming audio" +fi + +rm "$TEMP_JSON_FILE" +echo "" +echo "--- Tests complete. ---" diff --git a/ai-hub/tests/api/test_routes.py b/ai-hub/tests/api/test_routes.py index 5e26ac0..c4da460 100644 --- a/ai-hub/tests/api/test_routes.py +++ b/ai-hub/tests/api/test_routes.py @@ -248,10 +248,9 @@ mock_services.tts_service.create_speech_non_stream.assert_called_once_with(text="Hello, this is a test") -# New test to cover the streaming endpoint @pytest.mark.asyncio async def test_create_speech_stream_response(async_client): - """Test the new /speech/stream endpoint returns a streaming response.""" + """Test the consolidated /speech endpoint with stream=true returns a streaming response.""" test_client, mock_services = await anext(async_client) mock_audio_bytes_chunks = [b"chunk1", b"chunk2", b"chunk3"] @@ -263,7 +262,8 @@ # We mock `create_speech_stream` with a MagicMock returning the async generator mock_services.tts_service.create_speech_stream = MagicMock(return_value=mock_async_generator()) - response = await test_client.post("/speech/stream", json={"text": "Hello, this is a test"}) + # Correct the endpoint URL to use the consolidated /speech endpoint with the stream query parameter + response = await test_client.post("/speech?stream=true", json={"text": "Hello, this is a test"}) assert response.status_code == 200 assert response.headers["content-type"] == "audio/wav"