Athspi commited on
Commit
14c0817
·
verified ·
1 Parent(s): e81567c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +79 -10
app.py CHANGED
@@ -6,29 +6,54 @@ import os
6
  from flask_cors import CORS
7
  import markdown2
8
  import re
 
 
9
 
10
  # Load environment variables
11
  load_dotenv()
12
 
 
 
 
 
 
13
  # Initialize Flask app
14
  app = Flask(__name__, static_folder='static')
15
  CORS(app) # Enable CORS for all routes
16
 
17
- # Configure Gemini
 
 
 
 
 
 
 
 
 
 
 
 
18
  genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
19
- model = genai.GenerativeModel('gemini-2.5-flash')
 
 
 
 
20
 
21
  def convert_markdown_to_html(text):
22
  # Convert markdown to HTML
23
- html = markdown2.markdown(text)
 
24
 
25
- # Add custom styling to code blocks
26
- html = html.replace('<code>', '<code class="code-block">')
 
27
 
28
- # Convert **bold** to <strong> for better visibility
29
  html = re.sub(r'\*\*(.*?)\*\*', r'<strong>\1</strong>', html)
30
 
31
- # Convert *italic* to <em>
32
  html = re.sub(r'\*(.*?)\*', r'<em>\1</em>', html)
33
 
34
  return html
@@ -43,25 +68,69 @@ def chat():
43
  return jsonify({"error": "No message provided"}), 400
44
 
45
  # Generate response using Gemini
 
46
  response = model.generate_content(user_message)
47
 
48
- # Convert markdown to HTML with styling
49
- formatted_response = convert_markdown_to_html(response.text)
 
 
 
50
 
51
  return jsonify({
52
- "response": formatted_response
 
53
  })
54
 
55
  except Exception as e:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  return jsonify({"error": str(e)}), 500
57
 
 
58
  @app.route('/')
59
  def serve_index():
60
  return send_from_directory('static', 'index.html')
61
 
 
62
  @app.route('/<path:path>')
63
  def serve_static(path):
 
64
  return send_from_directory('static', path)
65
 
66
  if __name__ == '__main__':
 
 
67
  app.run(host="0.0.0.0", port=7860)
 
6
  from flask_cors import CORS
7
  import markdown2
8
  import re
9
+ from gtts import gTTS # <-- Import gTTS
10
+ import uuid # <-- Import UUID for unique filenames
11
 
12
  # Load environment variables
13
  load_dotenv()
14
 
15
+ # Define paths and create static audio directory if it doesn't exist
16
+ AUDIO_FOLDER = os.path.join('static', 'audio')
17
+ if not os.path.exists(AUDIO_FOLDER):
18
+ os.makedirs(AUDIO_FOLDER)
19
+
20
  # Initialize Flask app
21
  app = Flask(__name__, static_folder='static')
22
  CORS(app) # Enable CORS for all routes
23
 
24
+ # Configure Gemini with a system instruction
25
+ # This guides the AI's behavior and ensures responses are good for TTS.
26
+ system_instruction_text = """
27
+ You are a helpful, friendly, and informative AI assistant named AstroChat.
28
+ Your goal is to provide clear, concise, and natural-sounding answers to user queries.
29
+ When you respond:
30
+ - Use clear and simple language.
31
+ - Avoid overly complex sentence structures that might be hard to read aloud.
32
+ - Keep the user engaged and offer follow-up questions or related topics where appropriate.
33
+ - Ensure your responses are suitable for text-to-speech conversion.
34
+ - Provide factual and accurate information.
35
+ """
36
+
37
  genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
38
+ # Initialize the model with the system instruction
39
+ model = genai.GenerativeModel(
40
+ 'gemini-2.5-flash', # Using 1.5-flash for better performance and system_instruction support
41
+ system_instruction=system_instruction_text
42
+ )
43
 
44
  def convert_markdown_to_html(text):
45
  # Convert markdown to HTML
46
+ # Using 'fenced-code-blocks' and 'tables' for better markdown support
47
+ html = markdown2.markdown(text, extras=["fenced-code-blocks", "tables"])
48
 
49
+ # Add custom styling to code blocks (pre blocks)
50
+ # This specifically targets `<pre><code>` blocks generated by markdown2 for styling.
51
+ html = re.sub(r'<pre><code(.*?)>', r'<pre class="code-block"><code\1>', html)
52
 
53
+ # Convert **bold** to <strong> for better visibility (markdown2 usually handles this, but good to ensure)
54
  html = re.sub(r'\*\*(.*?)\*\*', r'<strong>\1</strong>', html)
55
 
56
+ # Convert *italic* to <em> (markdown2 usually handles this, but good to ensure)
57
  html = re.sub(r'\*(.*?)\*', r'<em>\1</em>', html)
58
 
59
  return html
 
68
  return jsonify({"error": "No message provided"}), 400
69
 
70
  # Generate response using Gemini
71
+ # For multi-turn conversations, you might manage chat history here
72
  response = model.generate_content(user_message)
73
 
74
+ # Get plain text for audio generation
75
+ plain_text_response = response.text
76
+
77
+ # Convert markdown to HTML for display
78
+ html_response = convert_markdown_to_html(plain_text_response)
79
 
80
  return jsonify({
81
+ "response_html": html_response,
82
+ "response_text": plain_text_response # Send plain text for TTS
83
  })
84
 
85
  except Exception as e:
86
+ app.logger.error(f"Chat Error: {e}")
87
+ return jsonify({"error": str(e)}), 500
88
+
89
+ @app.route('/generate-audio', methods=['POST'])
90
+ def generate_audio():
91
+ try:
92
+ data = request.json
93
+ text_to_speak = data.get('text')
94
+
95
+ if not text_to_speak:
96
+ return jsonify({"error": "No text provided"}), 400
97
+
98
+ # Sanitize text for TTS (remove common markdown characters for smoother pronunciation)
99
+ # This prevents gTTS from trying to pronounce asterisks, backticks, etc.
100
+ cleaned_text = re.sub(r'[\*_`#]', '', text_to_speak) # Remove bold, italic, code, headers markdown
101
+ cleaned_text = re.sub(r'\s+', ' ', cleaned_text).strip() # Replace multiple spaces with single space
102
+
103
+ if not cleaned_text: # If text becomes empty after cleaning
104
+ return jsonify({"error": "Text became empty after cleaning, cannot generate audio."}), 400
105
+
106
+ # Generate a unique filename using UUID to prevent collisions
107
+ filename = f"{uuid.uuid4()}.mp3"
108
+ filepath = os.path.join(AUDIO_FOLDER, filename)
109
+
110
+ # Create TTS object and save to file
111
+ tts = gTTS(text=cleaned_text, lang='en', slow=False) # 'en' for English, 'slow=False' for normal speed
112
+ tts.save(filepath)
113
+
114
+ # Return the URL to the audio file, converting path separators for web use
115
+ audio_url = f"/{filepath.replace(os.path.sep, '/')}"
116
+ return jsonify({"audio_url": audio_url})
117
+
118
+ except Exception as e:
119
+ app.logger.error(f"Audio Generation Error: {e}")
120
  return jsonify({"error": str(e)}), 500
121
 
122
+ # Serve the main index.html file
123
  @app.route('/')
124
  def serve_index():
125
  return send_from_directory('static', 'index.html')
126
 
127
+ # Serve other static files (CSS, JS, audio files)
128
  @app.route('/<path:path>')
129
  def serve_static(path):
130
+ # Ensure that only files from 'static' are served
131
  return send_from_directory('static', path)
132
 
133
  if __name__ == '__main__':
134
+ # Run the Flask app
135
+ # debug=True allows automatic reloading on code changes and provides more detailed error messages
136
  app.run(host="0.0.0.0", port=7860)