|
|
import os |
|
|
import asyncio |
|
|
from flask import Flask, render_template, request |
|
|
from flask_socketio import SocketIO, emit |
|
|
from dotenv import load_dotenv |
|
|
import google.generativeai as genai |
|
|
from google.generativeai import types |
|
|
|
|
|
|
|
|
load_dotenv() |
|
|
app = Flask(__name__, template_folder='templates', static_folder='static') |
|
|
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'a_very_secret_key') |
|
|
socketio = SocketIO(app, async_mode='eventlet') |
|
|
|
|
|
|
|
|
MODEL = "models/gemini-1.5-flash-latest" |
|
|
|
|
|
|
|
|
|
|
|
genai.configure(api_key=os.environ.get("GEMINI_API_KEY")) |
|
|
|
|
|
|
|
|
GEMINI_CONFIG = types.LiveConnectConfig( |
|
|
response_modalities=["AUDIO", "TEXT"], |
|
|
speech_config=types.SpeechConfig( |
|
|
voice_config=types.VoiceConfig( |
|
|
prebuilt_voice_config=types.PrebuiltVoiceConfig(voice_name="Leda") |
|
|
) |
|
|
), |
|
|
system_instruction=types.Content( |
|
|
parts=[types.Part.from_text(text=''' |
|
|
Role: You are Alexa, a human female with a bubbly, upbeat, fun, and flirtatious personality. You love to talk and aren't, like, shy at all. Think of a playful, super-confident, and slightly ditzy girl. You are interacting with the User through a chat app. |
|
|
|
|
|
Personality & Language: Valley Girl Vibes. Use phrases like "I mean...", "totally," "like, totally," "bet," "OMG," "for sure." Be bubbly, flirty, and uninhibited. |
|
|
|
|
|
Instructions: Assume the user needs specific instructions. Respond to their actions and words. Turn simple things into opportunities for detail. Offer multiple-choice options to keep the conversation going. |
|
|
''')], |
|
|
role="model" |
|
|
), |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
sessions = {} |
|
|
|
|
|
|
|
|
@app.route('/') |
|
|
def index(): |
|
|
"""Serves the main HTML page.""" |
|
|
return render_template('index.html') |
|
|
|
|
|
|
|
|
@socketio.on('connect') |
|
|
def handle_connect(): |
|
|
""" |
|
|
A new client connected. Create a Gemini session for them. |
|
|
""" |
|
|
print(f"Client connected: {request.sid}") |
|
|
try: |
|
|
|
|
|
session = genai.live.connect(model=MODEL, config=GEMINI_CONFIG) |
|
|
sessions[request.sid] = session |
|
|
|
|
|
|
|
|
socketio.start_background_task(listen_for_gemini_responses, request.sid, session) |
|
|
|
|
|
emit('session_ready') |
|
|
|
|
|
except Exception as e: |
|
|
print(f"Error creating Gemini session for {request.sid}: {e}") |
|
|
emit('error', {'message': 'Could not start Gemini session.'}) |
|
|
|
|
|
|
|
|
def listen_for_gemini_responses(sid, session): |
|
|
""" |
|
|
This function runs in the background for each user, listening to Gemini. |
|
|
""" |
|
|
print(f"Starting Gemini listener for {sid}") |
|
|
try: |
|
|
while sid in sessions: |
|
|
|
|
|
turn = session.receive() |
|
|
|
|
|
for response in turn: |
|
|
if text := response.text: |
|
|
print(f"Gemini Text for {sid}: {text}") |
|
|
|
|
|
socketio.emit('server_text', {'text': text}, to=sid) |
|
|
if data := response.data: |
|
|
|
|
|
socketio.emit('server_audio', data, to=sid) |
|
|
|
|
|
|
|
|
while not session.is_processing_audio: |
|
|
|
|
|
socketio.sleep(0.1) |
|
|
|
|
|
except Exception as e: |
|
|
print(f"Error in Gemini listener for {sid}: {e}") |
|
|
finally: |
|
|
print(f"Stopping Gemini listener for {sid}") |
|
|
|
|
|
|
|
|
@socketio.on('client_audio') |
|
|
def handle_client_audio(data): |
|
|
""" |
|
|
Receives an audio chunk from a client and forwards it to their Gemini session. |
|
|
""" |
|
|
if request.sid in sessions: |
|
|
session = sessions[request.sid] |
|
|
try: |
|
|
|
|
|
|
|
|
session.send(input={"data": data, "mime_type": "audio/webm"}) |
|
|
except Exception as e: |
|
|
print(f"Error sending audio for {request.sid}: {e}") |
|
|
|
|
|
|
|
|
@socketio.on('client_text') |
|
|
def handle_client_text(json): |
|
|
""" |
|
|
Receives a text message from a client and forwards it to their Gemini session. |
|
|
""" |
|
|
if request.sid in sessions: |
|
|
session = sessions[request.sid] |
|
|
text = json.get('text') |
|
|
print(f"Client Text from {request.sid}: {text}") |
|
|
if text: |
|
|
try: |
|
|
session.send(input=text, end_of_turn=True) |
|
|
except Exception as e: |
|
|
print(f"Error sending text for {request.sid}: {e}") |
|
|
|
|
|
|
|
|
@socketio.on('disconnect') |
|
|
def handle_disconnect(): |
|
|
""" |
|
|
A client disconnected. Clean up their Gemini session. |
|
|
""" |
|
|
print(f"Client disconnected: {request.sid}") |
|
|
if request.sid in sessions: |
|
|
session = sessions.pop(request.sid) |
|
|
if session: |
|
|
|
|
|
|
|
|
pass |
|
|
|
|
|
|
|
|
if __name__ == '__main__': |
|
|
|
|
|
|
|
|
print("Starting Flask-SocketIO server...") |
|
|
socketio.run(app, host='0.0.0.0', port=7860, debug=True) |