Spaces:
Sleeping
Sleeping
Upload 7 files
Browse files- .dockerignore +5 -0
- .env +2 -0
- .gitignore +3 -0
- Dockerfile +21 -0
- README.md +8 -11
- app.py +118 -0
- requirements.txt +6 -0
.dockerignore
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
__pycache__
|
2 |
+
*.pyc
|
3 |
+
.git
|
4 |
+
.venv
|
5 |
+
uploads/
|
.env
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
GOOGLE_API_KEY=AIzaSyAHpElgh7EQ8SvLf7Sa2HwK-TtjOd6ZcqU
|
2 |
+
ASSEMBLYAI_API_KEY=ya54c7e8b00f746a4bdb501a312a197e7
|
.gitignore
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
# Ignore the virtual environment directory
|
2 |
+
venv/
|
3 |
+
.env
|
Dockerfile
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Use an official Python runtime as a parent image
|
2 |
+
FROM python:3.9-slim
|
3 |
+
|
4 |
+
# Set the working directory in the container
|
5 |
+
WORKDIR /app
|
6 |
+
|
7 |
+
# Copy the current directory contents into the container at /app
|
8 |
+
COPY . /app
|
9 |
+
|
10 |
+
# Install any needed packages specified in requirements.txt
|
11 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
12 |
+
|
13 |
+
# Make port 7860 available to the world outside this container
|
14 |
+
EXPOSE 7860
|
15 |
+
|
16 |
+
# Define environment variables if needed
|
17 |
+
ENV GOOGLE_API_KEY = "AIzaSyAHpElgh7EQ8SvLf7Sa2HwK-TtjOd6ZcqU"
|
18 |
+
ENV ASSEMBLYAI_API_KEY = "ya54c7e8b00f746a4bdb501a312a197e7"
|
19 |
+
|
20 |
+
# Run app.py when the container launches using Gunicorn
|
21 |
+
CMD ["gunicorn", "-b", "0.0.0.0:7860", "app:app"]
|
README.md
CHANGED
@@ -1,11 +1,8 @@
|
|
1 |
-
---
|
2 |
-
title: Basic Docker SDK Space
|
3 |
-
emoji: 🐳
|
4 |
-
colorFrom: purple
|
5 |
-
colorTo: gray
|
6 |
-
sdk: docker
|
7 |
-
app_port: 7860
|
8 |
-
---
|
9 |
-
|
10 |
-
|
11 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
1 |
+
---
|
2 |
+
title: Basic Docker SDK Space
|
3 |
+
emoji: 🐳
|
4 |
+
colorFrom: purple
|
5 |
+
colorTo: gray
|
6 |
+
sdk: docker
|
7 |
+
app_port: 7860
|
8 |
+
---
|
|
|
|
|
|
app.py
ADDED
@@ -0,0 +1,118 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import json
|
3 |
+
from flask import Flask, jsonify, request, send_file, send_from_directory
|
4 |
+
from langchain_core.messages import HumanMessage
|
5 |
+
from langchain_google_genai import ChatGoogleGenerativeAI
|
6 |
+
import assemblyai as aai
|
7 |
+
import mimetypes
|
8 |
+
from dotenv import load_dotenv
|
9 |
+
|
10 |
+
|
11 |
+
mimetypes.add_type('application/javascript', '.js')
|
12 |
+
mimetypes.add_type('text/css', '.css')
|
13 |
+
|
14 |
+
load_dotenv()
|
15 |
+
|
16 |
+
# Initialize the Flask app
|
17 |
+
app = Flask(__name__)
|
18 |
+
|
19 |
+
# Get API keys from environment variables
|
20 |
+
ASSEMBLYAI_API_KEY = os.getenv("ASSEMBLYAI_API_KEY")
|
21 |
+
GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
|
22 |
+
|
23 |
+
# Set AssemblyAI API key
|
24 |
+
aai.settings.api_key = ASSEMBLYAI_API_KEY
|
25 |
+
|
26 |
+
# Set Google API key for Gemini model
|
27 |
+
os.environ["GOOGLE_API_KEY"] = GOOGLE_API_KEY
|
28 |
+
|
29 |
+
# Define a directory to save uploaded audio files
|
30 |
+
UPLOAD_FOLDER = 'uploads'
|
31 |
+
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
|
32 |
+
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
|
33 |
+
|
34 |
+
# Refined Instructions for Gemini
|
35 |
+
GEMINI_INSTRUCTIONS = """
|
36 |
+
The purpose of the category 'Reason for Outbound Call' is to identify the reason that a connected call was placed by the caller.
|
37 |
+
|
38 |
+
Consider the following options and select the one that best matches the content of the call:
|
39 |
+
1. Yes: The agent attempted to discuss buying, selling, trading, leasing, or test driving a vehicle. This includes any discussion of vehicle needs, interests, or potential sales, but this only applies if the call was live.
|
40 |
+
2. No: The agent followed up on a previous purchase or had a general discussion. This option should be selected if the call does not include any sales-related discussion.
|
41 |
+
3. No: The agent only confirmed, changed, or canceled an existing appointment. This includes any mention of scheduling, rescheduling, confirming, or canceling appointments.
|
42 |
+
4. Correction: The call was not connected to the intended party (e.g., it was a voicemail or a one-sided message).
|
43 |
+
|
44 |
+
Remember:
|
45 |
+
- Option 1 should only be selected if there was a live conversation with the intended contact.
|
46 |
+
- Option 4 should be selected if the call was not connected (e.g., it was a voicemail or no live interaction occurred).
|
47 |
+
- Option 4 it is voice mail, make it option 4
|
48 |
+
"""
|
49 |
+
|
50 |
+
# Home route to serve the index.html file
|
51 |
+
@app.route('/')
|
52 |
+
def home():
|
53 |
+
return send_file('web/index.html')
|
54 |
+
|
55 |
+
# API route to handle file upload, transcription, and model interaction
|
56 |
+
@app.route("/api/upload", methods=["POST"])
|
57 |
+
def generate_api():
|
58 |
+
if request.method == "POST":
|
59 |
+
try:
|
60 |
+
# Check if an audio file was uploaded
|
61 |
+
if 'audio_file' not in request.files:
|
62 |
+
return jsonify({"error": "No audio file provided"}), 400
|
63 |
+
|
64 |
+
audio_file = request.files['audio_file']
|
65 |
+
if audio_file.filename == '':
|
66 |
+
return jsonify({"error": "No selected file"}), 400
|
67 |
+
|
68 |
+
# Save the uploaded file to the server
|
69 |
+
file_path = os.path.join(app.config['UPLOAD_FOLDER'], audio_file.filename)
|
70 |
+
audio_file.save(file_path)
|
71 |
+
|
72 |
+
# Transcribe the audio using AssemblyAI
|
73 |
+
transcriber = aai.Transcriber()
|
74 |
+
transcript = transcriber.transcribe(file_path)
|
75 |
+
|
76 |
+
# Send transcription and instructions to Gemini model
|
77 |
+
model = ChatGoogleGenerativeAI(model="gemini-pro")
|
78 |
+
message = HumanMessage(content=f"{GEMINI_INSTRUCTIONS}\n\nCall Transcription: {transcript.text}")
|
79 |
+
response = model.stream([message])
|
80 |
+
|
81 |
+
# Interpret the model's response to select the correct option
|
82 |
+
buffer = []
|
83 |
+
for chunk in response:
|
84 |
+
buffer.append(chunk.content)
|
85 |
+
|
86 |
+
result_text = ''.join(buffer).lower()
|
87 |
+
|
88 |
+
# Adjusted logic to determine the correct option
|
89 |
+
if ("option 4" in result_text or "voicemail" in result_text or
|
90 |
+
"just wanted to reach out" in result_text or "thank you, bye" in result_text or
|
91 |
+
"this is" in result_text and "see if" in result_text and not "response" in result_text):
|
92 |
+
selected_option = 4
|
93 |
+
elif "option 1" in result_text or "yes" in result_text or "vehicle needs" in result_text:
|
94 |
+
selected_option = 1
|
95 |
+
elif "option 2" in result_text:
|
96 |
+
selected_option = 2
|
97 |
+
elif "option 3" in result_text or "reschedule" in result_text or "confirm" in result_text or "cancel" in result_text:
|
98 |
+
selected_option = 3
|
99 |
+
else:
|
100 |
+
selected_option = "Could not determine the correct option."
|
101 |
+
|
102 |
+
# Return the transcription and selected option
|
103 |
+
return jsonify({
|
104 |
+
"transcription": transcript.text,
|
105 |
+
"selected_option": selected_option
|
106 |
+
}), 200
|
107 |
+
|
108 |
+
except Exception as e:
|
109 |
+
return jsonify({"error": str(e)})
|
110 |
+
|
111 |
+
# Route to serve static files
|
112 |
+
@app.route('/<path:path>')
|
113 |
+
def serve_static(path):
|
114 |
+
return send_from_directory('web', path)
|
115 |
+
|
116 |
+
# Run the Flask application
|
117 |
+
if __name__ == '__main__':
|
118 |
+
app.run(debug=True)
|
requirements.txt
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Flask
|
2 |
+
gunicorn
|
3 |
+
langchain-google-genai
|
4 |
+
langchain-core
|
5 |
+
assemblyai
|
6 |
+
python-dotenv
|