| | |
| | |
| | |
| | import logging |
| | import os |
| |
|
| | |
| | os.makedirs("logs", exist_ok=True) |
| |
|
| | |
| | logging.basicConfig( |
| | level=logging.DEBUG, |
| | format="%(asctime)s [%(levelname)s] %(name)s: %(message)s", |
| | handlers=[ |
| | logging.FileHandler("logs/app.log", mode="a"), |
| | logging.StreamHandler() |
| | ] |
| | ) |
| |
|
| | logger = logging.getLogger(__name__) |
| |
|
| | |
| | logger.info("App started") |
| | logger.debug("This is debug info") |
| |
|
| |
|
| |
|
| | import gradio as gr |
| | from data_handler import DataHandler |
| | from gradio_callbacks import GradioCallbacks |
| | from gradio_components import ( |
| | create_qa_tab, create_filters_tab, create_about_tab |
| | ) |
| |
|
| | def main(): |
| | |
| | data_handler = DataHandler() |
| | callbacks = GradioCallbacks(data_handler) |
| | data = data_handler.get_data() |
| | |
| | |
| | with gr.Blocks( |
| | theme=gr.themes.Monochrome(), |
| | title="FCAS Research Methods Evidence Mapping", |
| | css=""" |
| | @import url('https://fonts.googleapis.com/css2?family=Libre+Franklin:wght@400;700&display=swap'); |
| | |
| | :root { |
| | --primary: #012069; |
| | --secondary: #5E548E; |
| | --accent: #231942; |
| | --text: #686868; |
| | --background: #F9F9F9; |
| | --heading-font: 'Libre Franklin', Sans-serif; |
| | --body-font: 'Helvetica Neue', Arial, Helvetica, sans-serif; |
| | } |
| | |
| | .gradio-container { |
| | max-width: 1200px !important; |
| | font-family: var(--body-font); |
| | background-color: var(--background); |
| | color: var(--text); |
| | } |
| | /* Make Gradio primary buttons navy blue with white text */ |
| | .gr-button, |
| | .gr-button-primary, |
| | button[class*="primary"] { |
| | background: #012069 !important; |
| | color: #fff !important; |
| | border: none !important; |
| | font-family: var(--body-font); |
| | } |
| | |
| | h1, h2, h3, .main-header { |
| | font-family: var(--heading-font); |
| | color: var(--primary); |
| | } |
| | |
| | .main-header { |
| | background: var(--secondary); |
| | color: var(--background); |
| | padding: 2rem; |
| | border-radius: 10px; |
| | margin-bottom: 2rem; |
| | } |
| | |
| | .gr-button { |
| | background: var(--accent); |
| | color: var(--background); |
| | font-family: var(--body-font); |
| | } |
| | /* Synthesis and references styling */ |
| | #synthesis_md, #references_md { |
| | background: linear-gradient(90deg, #ffffff 0%, #fbfdff 100%); |
| | border: 1px solid rgba(1,32,105,0.06); |
| | padding: 16px; |
| | border-radius: 8px; |
| | box-shadow: 0 1px 4px rgba(2,6,23,0.02); |
| | margin-bottom: 0.75rem; |
| | } |
| | #synthesis_md h1, #synthesis_md h2, #synthesis_md h3 { |
| | color: var(--primary); |
| | margin-top: 0; |
| | } |
| | """ |
| | ) as app: |
| | |
| | qa_synthesis_state = gr.State("") |
| |
|
| | with gr.Tabs(): |
| | create_qa_tab(callbacks, qa_synthesis_state) |
| | create_filters_tab(callbacks, data['countries_list'], data['sectors_list']) |
| | create_about_tab() |
| | return app |
| |
|
| | if __name__ == "__main__": |
| | import argparse |
| |
|
| | parser = argparse.ArgumentParser(description='FCAS app launcher and utilities') |
| | parser.add_argument('--gemini-multi', action='store_true', help='Run a one-off Gemini multi-speaker TTS generation (CLI mode)') |
| | parser.add_argument('--text', type=str, default=None, help='Text to synthesize (use with --gemini-multi)') |
| | parser.add_argument('--file', type=str, default=None, help='Path to a text file to synthesize (use with --gemini-multi)') |
| | parser.add_argument('--use-stub', action='store_true', help='Set USE_TTS_STUB=1 for offline testing') |
| | args = parser.parse_args() |
| |
|
| | if args.gemini_multi: |
| | |
| | if args.use_stub: |
| | os.environ['USE_TTS_STUB'] = '1' |
| | |
| | dh = DataHandler() |
| | cb = GradioCallbacks(dh) |
| |
|
| | |
| | synth_text = None |
| | if args.text: |
| | synth_text = args.text |
| | elif args.file: |
| | try: |
| | with open(args.file, 'r', encoding='utf-8') as f: |
| | synth_text = f.read() |
| | except Exception as e: |
| | logger.error('Failed to read input file: %s', e) |
| | raise |
| | else: |
| | logger.error('No --text or --file provided for --gemini-multi. Use --text "..." or --file path.') |
| | raise SystemExit(2) |
| |
|
| | logger.info('Running Gemini multi-speaker generation (CLI)') |
| | out_path, err, provider, tts_used = cb.generate_podcast_episode(synth_text) |
| | print('Result:', (out_path, err, provider, tts_used)) |
| | raise SystemExit(0) |
| | else: |
| | |
| | |
| | if os.environ.get('AUTO_RUN_GEMINI', '0') in ('1', 'true', 'True'): |
| | |
| | synth_text = os.environ.get('PODCAST_TEXT') |
| | if not synth_text and os.path.exists('podcast_input.txt'): |
| | try: |
| | with open('podcast_input.txt', 'r', encoding='utf-8') as f: |
| | synth_text = f.read() |
| | except Exception as e: |
| | logger.error('Failed to read podcast_input.txt: %s', e) |
| | if not synth_text: |
| | logger.error('AUTO_RUN_GEMINI set but no PODCAST_TEXT or podcast_input.txt found.') |
| | raise SystemExit(2) |
| | dh = DataHandler() |
| | cb = GradioCallbacks(dh) |
| | logger.info('AUTO_RUN_GEMINI: running Gemini multi-speaker generation') |
| | out_path, err, provider, tts_used = cb.generate_podcast_episode(synth_text) |
| | print('Result:', (out_path, err, provider, tts_used)) |
| | raise SystemExit(0) |
| |
|
| | app = main() |
| | app.launch( |
| | share=True, |
| | server_name="0.0.0.0", |
| | server_port=7860, |
| | show_error=True |
| | ) |