Spaces:
Sleeping
Sleeping
shamimjony1000
commited on
Upload 8 files
Browse files- .env +1 -0
- app.py +214 -0
- database.py +103 -0
- gemini_processor.py +86 -0
- memory_handler.py +15 -0
- requests.db +0 -0
- requirements.txt +6 -0
- voice_handler.py +50 -0
.env
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
GOOGLE_API_KEY=AIzaSyCLyDgZNcE_v4wLMFF8SoimKga9bbLSun0
|
app.py
ADDED
@@ -0,0 +1,214 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import pandas as pd
|
3 |
+
from database import Database
|
4 |
+
from voice_handler import VoiceHandler
|
5 |
+
from gemini_processor import GeminiProcessor
|
6 |
+
from memory_handler import MemoryHandler
|
7 |
+
import os
|
8 |
+
from dotenv import load_dotenv
|
9 |
+
|
10 |
+
load_dotenv()
|
11 |
+
|
12 |
+
# Initialize components
|
13 |
+
try:
|
14 |
+
db = Database()
|
15 |
+
voice_handler = VoiceHandler()
|
16 |
+
gemini_processor = GeminiProcessor()
|
17 |
+
if 'memory_handler' not in st.session_state:
|
18 |
+
st.session_state.memory_handler = MemoryHandler()
|
19 |
+
except Exception as e:
|
20 |
+
st.error(f"Error initializing components: {str(e)}")
|
21 |
+
st.stop()
|
22 |
+
|
23 |
+
def validate_request(project_number, project_name, amount, reason):
|
24 |
+
if not project_number or not project_name or not amount or not reason:
|
25 |
+
missing_fields = []
|
26 |
+
if not project_number: missing_fields.append("project number")
|
27 |
+
if not project_name: missing_fields.append("project name")
|
28 |
+
if not amount: missing_fields.append("amount")
|
29 |
+
if not reason: missing_fields.append("reason")
|
30 |
+
return False, f"Please provide the following missing information: {', '.join(missing_fields)}"
|
31 |
+
return True, ""
|
32 |
+
|
33 |
+
st.title("AI Agent Money Request System")
|
34 |
+
st.markdown("---")
|
35 |
+
|
36 |
+
# Language Selection
|
37 |
+
if 'language' not in st.session_state:
|
38 |
+
st.session_state.language = "en-US" # Default to English
|
39 |
+
|
40 |
+
st.sidebar.title("Settings")
|
41 |
+
language_option = st.sidebar.selectbox(
|
42 |
+
"Select Input Language",
|
43 |
+
options=["English", "Arabic", "Mixed (Arabic/English)"],
|
44 |
+
index=0,
|
45 |
+
key="language_select"
|
46 |
+
)
|
47 |
+
|
48 |
+
# Map selection to language codes
|
49 |
+
language_mapping = {
|
50 |
+
"English": "en-US",
|
51 |
+
"Arabic": "ar-SA",
|
52 |
+
"Mixed (Arabic/English)": "mixed"
|
53 |
+
}
|
54 |
+
|
55 |
+
# Input Method Tabs
|
56 |
+
tab1, tab2 = st.tabs(["Voice Input", "Text Input"])
|
57 |
+
|
58 |
+
# Voice Input Tab
|
59 |
+
with tab1:
|
60 |
+
col1, col2, col3 = st.columns([3, 1, 1])
|
61 |
+
with col1:
|
62 |
+
if language_option == "Arabic":
|
63 |
+
st.markdown("""
|
64 |
+
جرب أن تقول شيئاً مثل:
|
65 |
+
> "أحتاج إلى طلب 500 ريال للمشروع 223 المسمى جامعة أبها لشراء بعض الأدوات"
|
66 |
+
""")
|
67 |
+
else:
|
68 |
+
st.markdown("""
|
69 |
+
Try saying something like:
|
70 |
+
> "I need to request 500 riyals for project 223 named Abha University to buy some tools"
|
71 |
+
""")
|
72 |
+
with col2:
|
73 |
+
if st.button("🎤 Start Voice Input"):
|
74 |
+
with st.spinner("Listening... Please speak clearly"):
|
75 |
+
voice_text = voice_handler.listen_for_voice(language_mapping[language_option])
|
76 |
+
if not voice_text.startswith("Error") and not voice_text.startswith("Could not"):
|
77 |
+
st.success("Voice captured!")
|
78 |
+
st.write("You said:", voice_text)
|
79 |
+
|
80 |
+
# Add to memory
|
81 |
+
st.session_state.memory_handler.add_interaction(voice_text)
|
82 |
+
|
83 |
+
with st.spinner("Processing voice input..."):
|
84 |
+
context = st.session_state.memory_handler.get_context()
|
85 |
+
details = gemini_processor.extract_request_details(voice_text, context)
|
86 |
+
if details:
|
87 |
+
st.session_state['voice_details'] = details
|
88 |
+
if 'translated_text' in details:
|
89 |
+
st.info(f"Translated text: {details['translated_text']}")
|
90 |
+
if details.get('missing_fields'):
|
91 |
+
missing = ", ".join(details['missing_fields'])
|
92 |
+
st.warning(f"Please provide the following missing information: {missing}")
|
93 |
+
else:
|
94 |
+
st.success("Voice input processed! Please verify the details below.")
|
95 |
+
else:
|
96 |
+
st.error("Could not extract request details. Please try again or use manual input.")
|
97 |
+
else:
|
98 |
+
st.error(voice_text)
|
99 |
+
with col3:
|
100 |
+
if st.button("🗑️ Clear Memory"):
|
101 |
+
st.session_state.memory_handler.clear_memory()
|
102 |
+
if 'voice_details' in st.session_state:
|
103 |
+
del st.session_state['voice_details']
|
104 |
+
st.success("Memory cleared!")
|
105 |
+
|
106 |
+
# Text Input Tab
|
107 |
+
with tab2:
|
108 |
+
if language_option == "Arabic":
|
109 |
+
st.markdown("""
|
110 |
+
أدخل طلبك في شكل نص. مثال:
|
111 |
+
> "أحتاج إلى طلب 500 ريال للمشروع 223 المسمى جامعة أبها لشراء بعض الأدوات"
|
112 |
+
""")
|
113 |
+
else:
|
114 |
+
st.markdown("""
|
115 |
+
Enter your request in text format. Example:
|
116 |
+
> "I need to request 500 riyals for project 223 named Abha University to buy some tools"
|
117 |
+
""")
|
118 |
+
|
119 |
+
text_input = st.text_area("Enter your request:", height=100)
|
120 |
+
col1, col2 = st.columns([1, 4])
|
121 |
+
|
122 |
+
with col1:
|
123 |
+
if st.button("Process Text"):
|
124 |
+
if text_input:
|
125 |
+
with st.spinner("Processing text input..."):
|
126 |
+
context = st.session_state.memory_handler.get_context()
|
127 |
+
details = gemini_processor.extract_request_details(text_input, context)
|
128 |
+
if details:
|
129 |
+
st.session_state['voice_details'] = details
|
130 |
+
if 'translated_text' in details:
|
131 |
+
st.info(f"Translated text: {details['translated_text']}")
|
132 |
+
if details.get('missing_fields'):
|
133 |
+
missing = ", ".join(details['missing_fields'])
|
134 |
+
st.warning(f"Please provide the following missing information: {missing}")
|
135 |
+
else:
|
136 |
+
st.success("Text processed! Please verify the details below.")
|
137 |
+
else:
|
138 |
+
st.error("Could not extract request details. Please try again.")
|
139 |
+
else:
|
140 |
+
st.warning("Please enter some text first.")
|
141 |
+
|
142 |
+
# Show conversation history
|
143 |
+
if st.session_state.memory_handler.conversation_history:
|
144 |
+
with st.expander("Previous Inputs"):
|
145 |
+
for i, text in enumerate(st.session_state.memory_handler.conversation_history, 1):
|
146 |
+
st.text(f"{i}. {text}")
|
147 |
+
|
148 |
+
# Input form
|
149 |
+
st.markdown("---")
|
150 |
+
st.subheader("Submit Money Request")
|
151 |
+
with st.form("request_form"):
|
152 |
+
voice_details = st.session_state.get('voice_details', {})
|
153 |
+
|
154 |
+
project_number = st.text_input("Project Number", value=voice_details.get('project_number', ''))
|
155 |
+
project_name = st.text_input("Project Name", value=voice_details.get('project_name', ''))
|
156 |
+
amount = st.number_input("Amount (in riyals)",
|
157 |
+
value=float(voice_details.get('amount', 0)),
|
158 |
+
min_value=0.0,
|
159 |
+
step=100.0)
|
160 |
+
reason = st.text_input("Reason for Request", value=voice_details.get('reason', ''))
|
161 |
+
|
162 |
+
col1, col2 = st.columns(2)
|
163 |
+
with col1:
|
164 |
+
submitted = st.form_submit_button("Submit Request")
|
165 |
+
with col2:
|
166 |
+
confirmed = st.form_submit_button("Confirm & Save")
|
167 |
+
|
168 |
+
if submitted:
|
169 |
+
is_valid, message = validate_request(project_number, project_name, amount, reason)
|
170 |
+
if is_valid:
|
171 |
+
st.session_state.show_confirmation = True
|
172 |
+
confirmation_text = f"""
|
173 |
+
Please review the following request and click 'Confirm & Save' to proceed:
|
174 |
+
|
175 |
+
- Project Number: {project_number}
|
176 |
+
- Project Name: {project_name}
|
177 |
+
- Amount: {amount} riyals
|
178 |
+
- Reason: {reason}
|
179 |
+
"""
|
180 |
+
st.info(confirmation_text)
|
181 |
+
else:
|
182 |
+
st.error(message)
|
183 |
+
|
184 |
+
if confirmed:
|
185 |
+
is_valid, message = validate_request(project_number, project_name, amount, reason)
|
186 |
+
if is_valid:
|
187 |
+
try:
|
188 |
+
original_text = voice_details.get('original_text', '') if 'voice_details' in st.session_state else ''
|
189 |
+
db.add_request(project_number, project_name, amount, reason, original_text)
|
190 |
+
st.success("Request successfully added to the database!")
|
191 |
+
if 'voice_details' in st.session_state:
|
192 |
+
del st.session_state['voice_details']
|
193 |
+
st.session_state.show_confirmation = False
|
194 |
+
st.session_state.memory_handler.clear_memory()
|
195 |
+
except Exception as e:
|
196 |
+
st.error(f"Error saving request: {str(e)}")
|
197 |
+
else:
|
198 |
+
st.error(message)
|
199 |
+
|
200 |
+
# Display existing requests
|
201 |
+
st.markdown("---")
|
202 |
+
st.subheader("Existing Requests")
|
203 |
+
try:
|
204 |
+
requests = db.get_all_requests()
|
205 |
+
if requests:
|
206 |
+
df = pd.DataFrame(requests)
|
207 |
+
# Reorder columns to show original text
|
208 |
+
columns = ['timestamp', 'project_number', 'project_name', 'amount', 'reason', 'original_text']
|
209 |
+
df = df[columns]
|
210 |
+
st.dataframe(df, use_container_width=True)
|
211 |
+
else:
|
212 |
+
st.info("No requests submitted yet.")
|
213 |
+
except Exception as e:
|
214 |
+
st.error(f"Error loading requests: {str(e)}")
|
database.py
ADDED
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import sqlite3
|
2 |
+
from datetime import datetime
|
3 |
+
import os
|
4 |
+
import time
|
5 |
+
|
6 |
+
class Database:
|
7 |
+
def __init__(self, db_name="requests.db"):
|
8 |
+
self.db_name = db_name
|
9 |
+
self.max_retries = 3
|
10 |
+
self.retry_delay = 1
|
11 |
+
self.initialize_database()
|
12 |
+
|
13 |
+
def initialize_database(self):
|
14 |
+
for attempt in range(self.max_retries):
|
15 |
+
try:
|
16 |
+
|
17 |
+
self.conn = sqlite3.connect(self.db_name)
|
18 |
+
|
19 |
+
self.conn.execute('PRAGMA encoding="UTF-8"')
|
20 |
+
|
21 |
+
|
22 |
+
cursor = self.conn.cursor()
|
23 |
+
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='requests'")
|
24 |
+
if not cursor.fetchone():
|
25 |
+
self.create_table()
|
26 |
+
else:
|
27 |
+
# Verify columns
|
28 |
+
cursor.execute('PRAGMA table_info(requests)')
|
29 |
+
columns = [col[1] for col in cursor.fetchall()]
|
30 |
+
required_columns = ['id', 'timestamp', 'project_number', 'project_name', 'amount', 'reason', 'original_text']
|
31 |
+
|
32 |
+
if not all(col in columns for col in required_columns):
|
33 |
+
# Backup existing data
|
34 |
+
cursor.execute('ALTER TABLE requests RENAME TO requests_old')
|
35 |
+
self.create_table()
|
36 |
+
# Copy data from old table
|
37 |
+
cursor.execute('''
|
38 |
+
INSERT INTO requests (timestamp, project_number, project_name, amount, reason)
|
39 |
+
SELECT timestamp, project_number, project_name, amount, reason
|
40 |
+
FROM requests_old
|
41 |
+
''')
|
42 |
+
cursor.execute('DROP TABLE requests_old')
|
43 |
+
self.conn.commit()
|
44 |
+
|
45 |
+
return # Success
|
46 |
+
except sqlite3.OperationalError as e:
|
47 |
+
if attempt < self.max_retries - 1:
|
48 |
+
time.sleep(self.retry_delay)
|
49 |
+
continue
|
50 |
+
raise Exception(f"Could not initialize database after {self.max_retries} attempts: {str(e)}")
|
51 |
+
except Exception as e:
|
52 |
+
raise Exception(f"Database initialization error: {str(e)}")
|
53 |
+
|
54 |
+
def create_table(self):
|
55 |
+
cursor = self.conn.cursor()
|
56 |
+
cursor.execute('''
|
57 |
+
CREATE TABLE IF NOT EXISTS requests (
|
58 |
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
59 |
+
timestamp DATETIME,
|
60 |
+
project_number TEXT,
|
61 |
+
project_name TEXT,
|
62 |
+
amount REAL,
|
63 |
+
reason TEXT,
|
64 |
+
original_text TEXT
|
65 |
+
)
|
66 |
+
''')
|
67 |
+
self.conn.commit()
|
68 |
+
|
69 |
+
def add_request(self, project_number, project_name, amount, reason, original_text=""):
|
70 |
+
for attempt in range(self.max_retries):
|
71 |
+
try:
|
72 |
+
cursor = self.conn.cursor()
|
73 |
+
cursor.execute('''
|
74 |
+
INSERT INTO requests (timestamp, project_number, project_name, amount, reason, original_text)
|
75 |
+
VALUES (?, ?, ?, ?, ?, ?)
|
76 |
+
''', (datetime.now(), project_number, project_name, amount, reason, original_text))
|
77 |
+
self.conn.commit()
|
78 |
+
return # Success
|
79 |
+
except sqlite3.OperationalError as e:
|
80 |
+
if attempt < self.max_retries - 1:
|
81 |
+
time.sleep(self.retry_delay)
|
82 |
+
continue
|
83 |
+
raise Exception(f"Could not add request after {self.max_retries} attempts: {str(e)}")
|
84 |
+
|
85 |
+
def get_all_requests(self):
|
86 |
+
for attempt in range(self.max_retries):
|
87 |
+
try:
|
88 |
+
cursor = self.conn.cursor()
|
89 |
+
cursor.execute('SELECT * FROM requests ORDER BY timestamp DESC')
|
90 |
+
columns = [description[0] for description in cursor.description]
|
91 |
+
results = cursor.fetchall()
|
92 |
+
return [dict(zip(columns, row)) for row in results]
|
93 |
+
except sqlite3.OperationalError as e:
|
94 |
+
if attempt < self.max_retries - 1:
|
95 |
+
time.sleep(self.retry_delay)
|
96 |
+
continue
|
97 |
+
raise Exception(f"Could not fetch requests after {self.max_retries} attempts: {str(e)}")
|
98 |
+
|
99 |
+
def __del__(self):
|
100 |
+
try:
|
101 |
+
self.conn.close()
|
102 |
+
except:
|
103 |
+
pass
|
gemini_processor.py
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import google.generativeai as genai
|
2 |
+
import os
|
3 |
+
from dotenv import load_dotenv
|
4 |
+
import json
|
5 |
+
import re
|
6 |
+
|
7 |
+
load_dotenv()
|
8 |
+
|
9 |
+
class GeminiProcessor:
|
10 |
+
def __init__(self):
|
11 |
+
api_key = os.getenv('GOOGLE_API_KEY')
|
12 |
+
if not api_key:
|
13 |
+
raise ValueError("GOOGLE_API_KEY not found in environment variables")
|
14 |
+
genai.configure(api_key=api_key)
|
15 |
+
self.model = genai.GenerativeModel('gemini-pro')
|
16 |
+
|
17 |
+
def is_arabic(self, text):
|
18 |
+
arabic_pattern = re.compile('[\u0600-\u06FF]')
|
19 |
+
return bool(arabic_pattern.search(text))
|
20 |
+
|
21 |
+
def translate_arabic_to_english(self, text):
|
22 |
+
prompt = f"""
|
23 |
+
Translate the following Arabic text to English. If the text is mixed (Arabic and English),
|
24 |
+
translate only the Arabic parts and keep the English parts as is.
|
25 |
+
Keep numbers in their original format.
|
26 |
+
|
27 |
+
Text to translate: {text}
|
28 |
+
"""
|
29 |
+
try:
|
30 |
+
response = self.model.generate_content(prompt)
|
31 |
+
return response.text.strip()
|
32 |
+
except Exception as e:
|
33 |
+
print(f"Translation error: {e}")
|
34 |
+
return text
|
35 |
+
|
36 |
+
def extract_request_details(self, text, context=""):
|
37 |
+
full_text = f"{context} {text}".strip()
|
38 |
+
is_arabic_input = self.is_arabic(full_text)
|
39 |
+
|
40 |
+
# Translate if Arabic text is detected
|
41 |
+
if is_arabic_input:
|
42 |
+
translated_text = self.translate_arabic_to_english(full_text)
|
43 |
+
processing_text = translated_text
|
44 |
+
else:
|
45 |
+
processing_text = full_text
|
46 |
+
|
47 |
+
prompt = f"""
|
48 |
+
Extract the following information from this text and previous context.
|
49 |
+
The input has been translated from Arabic if it contained Arabic text.
|
50 |
+
|
51 |
+
If any information is missing, leave it empty.
|
52 |
+
Format the response exactly as a JSON object with these keys:
|
53 |
+
{{
|
54 |
+
"project_number": "extracted number or empty string",
|
55 |
+
"project_name": "extracted name or empty string",
|
56 |
+
"amount": extracted number or 0,
|
57 |
+
"reason": "extracted reason or empty string",
|
58 |
+
"missing_fields": ["list of missing required fields"],
|
59 |
+
"original_text": "the original input text"
|
60 |
+
}}
|
61 |
+
|
62 |
+
Text to analyze: {processing_text}
|
63 |
+
"""
|
64 |
+
|
65 |
+
try:
|
66 |
+
response = self.model.generate_content(prompt)
|
67 |
+
result = json.loads(response.text)
|
68 |
+
|
69 |
+
required_keys = ['project_number', 'project_name', 'amount', 'reason', 'missing_fields']
|
70 |
+
if not all(key in result for key in required_keys):
|
71 |
+
raise ValueError("Missing required keys in response")
|
72 |
+
|
73 |
+
result['amount'] = float(result.get('amount', 0))
|
74 |
+
result['original_text'] = full_text # Keep the original Arabic text
|
75 |
+
|
76 |
+
# Add translation if it was performed
|
77 |
+
if is_arabic_input:
|
78 |
+
result['translated_text'] = processing_text
|
79 |
+
|
80 |
+
return result
|
81 |
+
except json.JSONDecodeError as e:
|
82 |
+
print(f"JSON parsing error: {e}")
|
83 |
+
return None
|
84 |
+
except Exception as e:
|
85 |
+
print(f"Error processing request: {e}")
|
86 |
+
return None
|
memory_handler.py
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
class MemoryHandler:
|
2 |
+
def __init__(self):
|
3 |
+
self.conversation_history = []
|
4 |
+
self.max_history = 5 # Keep last 5 interactions
|
5 |
+
|
6 |
+
def add_interaction(self, text):
|
7 |
+
self.conversation_history.append(text)
|
8 |
+
if len(self.conversation_history) > self.max_history:
|
9 |
+
self.conversation_history.pop(0)
|
10 |
+
|
11 |
+
def get_context(self):
|
12 |
+
return " ".join(self.conversation_history)
|
13 |
+
|
14 |
+
def clear_memory(self):
|
15 |
+
self.conversation_history = []
|
requests.db
ADDED
Binary file (12.3 kB). View file
|
|
requirements.txt
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
streamlit
|
2 |
+
pandas
|
3 |
+
SpeechRecognition
|
4 |
+
google-generativeai
|
5 |
+
pyaudio
|
6 |
+
python-dotenv
|
voice_handler.py
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import speech_recognition as sr
|
2 |
+
|
3 |
+
class VoiceHandler:
|
4 |
+
def __init__(self):
|
5 |
+
self.recognizer = sr.Recognizer()
|
6 |
+
# Adjust recognition settings for better accuracy
|
7 |
+
self.recognizer.energy_threshold = 4000
|
8 |
+
self.recognizer.dynamic_energy_threshold = True
|
9 |
+
self.recognizer.pause_threshold = 0.8
|
10 |
+
|
11 |
+
def listen_for_voice(self, language="mixed"):
|
12 |
+
"""
|
13 |
+
Listen for voice input in specified language.
|
14 |
+
language can be:
|
15 |
+
- "ar-SA" for Arabic
|
16 |
+
- "en-US" for English
|
17 |
+
- "mixed" for both Arabic and English
|
18 |
+
"""
|
19 |
+
try:
|
20 |
+
with sr.Microphone() as source:
|
21 |
+
print("Adjusting for ambient noise...")
|
22 |
+
self.recognizer.adjust_for_ambient_noise(source, duration=1)
|
23 |
+
print("Listening...")
|
24 |
+
audio = self.recognizer.listen(source, timeout=5, phrase_time_limit=10)
|
25 |
+
print("Processing speech...")
|
26 |
+
|
27 |
+
# Try Arabic first if mixed or Arabic is specified
|
28 |
+
if language in ["ar-SA", "mixed"]:
|
29 |
+
try:
|
30 |
+
text = self.recognizer.recognize_google(audio, language="ar-SA")
|
31 |
+
return text
|
32 |
+
except sr.UnknownValueError:
|
33 |
+
if language == "mixed":
|
34 |
+
# If Arabic fails and mixed is specified, try English
|
35 |
+
text = self.recognizer.recognize_google(audio, language="en-US")
|
36 |
+
return text
|
37 |
+
raise
|
38 |
+
else:
|
39 |
+
# English only
|
40 |
+
text = self.recognizer.recognize_google(audio, language="en-US")
|
41 |
+
return text
|
42 |
+
|
43 |
+
except sr.RequestError as e:
|
44 |
+
return f"Could not request results from speech service: {str(e)}"
|
45 |
+
except sr.UnknownValueError:
|
46 |
+
return "Could not understand audio. Please speak clearly and try again."
|
47 |
+
except sr.WaitTimeoutError:
|
48 |
+
return "Listening timed out. Please try again."
|
49 |
+
except Exception as e:
|
50 |
+
return f"Error: {str(e)}"
|