-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.py
More file actions
182 lines (153 loc) · 6.88 KB
/
Copy pathapp.py
File metadata and controls
182 lines (153 loc) · 6.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
import os
import tempfile
import time
import streamlit as st
from google import genai
from google.genai import types
# Import personas from your local personas.py file
from personas import PERSONAS
# -----------------------------
# Configuration: Models
# -----------------------------
AVAILABLE_MODELS = {
"Gemini 3.5 Flash (Default - Most Intelligent & Stable)": "gemini-3.5-flash",
"Gemini 3.1 Pro (Preview - Advanced Problem Solving)": "gemini-3.1-pro",
"Gemini 3.1 Flash-Lite (Stable - Fastest & Most Cost-Efficient)": "gemini-3.1-flash-lite",
"Gemini 2.5 Pro (Stable - Deep Reasoning & Complex Tasks)": "gemini-2.5-pro",
"Gemini 2.5 Flash (Stable - High-Volume Price/Performance)": "gemini-2.5-flash"
}
# -----------------------------
# Page Config & Professional CSS
# -----------------------------
st.set_page_config(page_title="Transcript AI Demo ", layout="wide", page_icon="🧠")
st.markdown("""
<style>
.main { background-color: #F4F7F9; font-family: 'Inter', sans-serif; }
h1, h2, h3 { color: #0F172A; font-weight: 700 !important; }
/* Professional Card Styling */
.stFileUploader, .config-section {
background-color: #FFFFFF;
border-radius: 12px;
padding: 20px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.04);
border: 1px solid #E2E8F0;
margin-bottom: 20px;
}
/* Executive Button */
.stButton>button {
background: linear-gradient(135deg, #2563EB 0%, #1D4ED8 100%);
color: white;
border-radius: 8px;
border: none;
padding: 12px 28px;
font-weight: 600;
width: 100%;
box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);
}
/* Report Output Card */
.ai-output-card {
background-color: #FFFFFF;
padding: 30px;
border-radius: 12px;
box-shadow: 0 8px 24px rgba(0,0,0,0.06);
border-left: 6px solid #2563EB;
color: #1E293B;
line-height: 1.7;
}
</style>
""", unsafe_allow_html=True)
# -----------------------------
# UI Header
# -----------------------------
st.title("🧠 Transcript AI Demo")
st.markdown("Synthesize multiple audio and text sources into persona-driven executive reports.")
# --- Section 1: Authentication ---
with st.expander("🔑 Step 1: Authentication", expanded=True):
user_api_key = st.text_input("Enter Gemini API Key:", type="password", help="Key is used only for this session and never stored.")
# --- Section 2: Source Uploads ---
st.subheader("📂 Step 2: Upload Sources")
col1, col2 = st.columns(2)
with col1:
audio_files = st.file_uploader("🎙️ Audio Sources (MP3, WAV, M4A)", type=["mp3", "wav", "m4a"], accept_multiple_files=True)
with col2:
text_files = st.file_uploader("📄 Text Documents (TXT)", type=["txt"], accept_multiple_files=True)
# --- Section 3: Configuration ---
st.markdown("---")
st.subheader("⚙️ Step 3: Reporting Options")
c1, c2, c3 = st.columns([1.5, 1, 1])
with c1:
report_scope = st.radio("Analysis Scope:", ["All Sources", "Audio Only", "Text Only"], horizontal=True)
with c2:
selected_persona = st.selectbox("Reporting Persona:", list(PERSONAS.keys()))
with c3:
selected_model_name = st.selectbox("AI Model:", list(AVAILABLE_MODELS.keys()))
st.markdown("<br>", unsafe_allow_html=True)
# -----------------------------
# Execution Logic
# -----------------------------
if st.button("🚀 Generate Executive Report"):
if not user_api_key:
st.error("Please provide a Gemini API Key to proceed.")
st.stop()
# Initialize Client
client = genai.Client(api_key=user_api_key)
model_id = AVAILABLE_MODELS[selected_model_name]
persona_data = PERSONAS[selected_persona]
# Prompt Setup
contents = [persona_data['prompt_template']]
try:
with st.spinner(f"Analyzing sources via {model_id}..."):
# 1. Process Audio (Gemini Native Files API)
if audio_files and report_scope in ["All Sources", "Audio Only"]:
for f in audio_files:
extension = f.name.split('.')[-1].lower()
# 1. Manually determine the MIME type
# .m4a is technically audio/mp4 for Gemini's purposes
mime_map = {
"m4a": "audio/mp4",
"mp3": "audio/mpeg",
"wav": "audio/wav",
"aac": "audio/aac"
}
# Use our map, or try to guess, or default to mp4
mime_type = mime_map.get(extension) or mimetypes.guess_type(f.name)[0] or "audio/mp4"
with tempfile.NamedTemporaryFile(delete=False, suffix=f".{extension}") as tmp:
tmp.write(f.getbuffer())
tmp_path = tmp.name
try:
st.write(f"Processing {f.name} ({mime_type})...")
# 2. Pass the mime_type explicitly in the config
g_file = client.files.upload(
file=tmp_path,
config={'mime_type': mime_type}
)
# Wait logic remains the same
while g_file.state.name == "PROCESSING":
time.sleep(2)
g_file = client.files.get(name=g_file.name)
contents.append(g_file)
finally:
if os.path.exists(tmp_path):
os.remove(tmp_path)
# 2. Process Text
if text_files and report_scope in ["All Sources", "Text Only"]:
for f in text_files:
text_content = f.read().decode("utf-8")
contents.append(f"\nDOCUMENT: {f.name}\nCONTENT:\n{text_content}")
# 3. Generate Content
if len(contents) > 1:
response = client.models.generate_content(
model=model_id,
contents=contents,
config=types.GenerateContentConfig(
system_instruction=persona_data['system_instruction'],
temperature=0.2
)
)
st.markdown("### 📊 Synthesized Executive Report")
st.markdown(f'<div class="ai-output-card">{response.text}</div>', unsafe_allow_html=True)
else:
st.warning("No files were uploaded or matched your selected scope.")
except Exception as e:
st.error(f"An error occurred: {e}")
st.info("Ensure your API key is valid for the selected model family.")