Pamudu13 commited on
Commit
b054134
·
verified ·
1 Parent(s): eb705e9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +98 -55
app.py CHANGED
@@ -1,4 +1,5 @@
1
- from flask import Flask, request, jsonify
 
2
  import os
3
  from dotenv import load_dotenv
4
  import requests
@@ -7,13 +8,34 @@ from csv_handler import CSVHandler
7
  import ssl
8
  import logging
9
  from web_scraper import research_topic
 
 
10
 
11
- # Set up logging
12
- logging.basicConfig(level=logging.INFO)
13
- logger = logging.getLogger(__name__)
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
  app = Flask(__name__)
16
- load_dotenv()
 
 
 
 
 
 
 
17
 
18
  # Configuration
19
  OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')
@@ -75,16 +97,16 @@ Create the preliminary plan."""
75
  },
76
  timeout=60
77
  )
78
-
79
  logger.info(f"OpenRouter API Response: {response.text}")
80
-
81
  if response.status_code != 200:
82
  raise Exception(f"OpenRouter API error: {response.text}")
83
-
84
  response_data = response.json()
85
  if 'choices' not in response_data:
86
  raise Exception(f"Unexpected API response format: {response_data}")
87
-
88
  return response_data['choices'][0]['message']['content']
89
  except Exception as e:
90
  logger.error(f"Error in generate_preliminary_plan: {e}")
@@ -95,46 +117,46 @@ def do_research(plan, openrouter_key):
95
  try:
96
  # Extract key points from plan to create search queries
97
  plan_lines = [line.strip('* -').strip() for line in plan.split('\n') if line.strip()]
98
-
99
  # Take only the first 3 points
100
  plan_lines = plan_lines[:3]
101
  logger.info(f"Researching top 3 points: {plan_lines}")
102
-
103
  all_research = []
104
-
105
  # Research each main point in the plan (limited to 3 points)
106
  for point in plan_lines:
107
  if not point: # Skip empty lines
108
  continue
109
-
110
  # Get research results including both web content and AI analysis
111
  # Using 5 sites per point for more comprehensive research
112
  results = research_topic(point, num_sites=5, openrouter_key=openrouter_key)
113
-
114
  if results['success']:
115
  all_research.append({
116
  'topic': point,
117
  'analysis': results['analysis'],
118
  'sources': results['sources']
119
  })
120
-
121
  # Format all research into a comprehensive markdown document
122
  formatted_research = "# Research Results\n\n"
123
-
124
  for research in all_research:
125
  formatted_research += f"## {research['topic']}\n\n"
126
  formatted_research += f"{research['analysis']}\n\n"
127
  formatted_research += "### Sources Referenced\n\n"
128
-
129
  for source in research['sources']:
130
  formatted_research += f"- [{source['title']}]({source['source']})\n"
131
  if source['meta_info']['description']:
132
  formatted_research += f" {source['meta_info']['description']}\n"
133
-
134
  formatted_research += "\n---\n\n"
135
-
136
  return formatted_research
137
-
138
  except Exception as e:
139
  logger.error(f"Error in do_research: {e}")
140
  raise
@@ -143,20 +165,20 @@ def do_research(plan, openrouter_key):
143
  def generate_blog():
144
  try:
145
  logger.info("Starting blog generation process for multiple clusters...")
146
-
147
  # Initialize handlers
148
  blog_gen = BlogGenerator(OPENAI_API_KEY, OPENROUTER_API_KEY)
149
  csv_handler = CSVHandler()
150
 
151
  generated_blogs = []
152
-
153
  # Get all available clusters
154
  all_clusters = csv_handler.get_all_clusters()
155
-
156
  for cluster_data in all_clusters:
157
  try:
158
  logger.info(f"Processing cluster with primary keyword: {cluster_data['Primary Keyword']}")
159
-
160
  # 2. Generate preliminary plan
161
  logger.info("Generating preliminary plan...")
162
  plan = generate_preliminary_plan(cluster_data)
@@ -266,57 +288,57 @@ def generate_from_csv():
266
  try:
267
  if 'file' not in request.files:
268
  return jsonify({'error': 'No file uploaded'}), 400
269
-
270
  file = request.files['file']
271
  if file.filename == '':
272
  return jsonify({'error': 'No file selected'}), 400
273
-
274
  # Read and decode the CSV content
275
  csv_content = file.read().decode('utf-8')
276
-
277
  # Initialize handlers
278
  blog_gen = BlogGenerator(OPENAI_API_KEY, OPENROUTER_API_KEY)
279
  csv_handler = CSVHandler()
280
-
281
  # Process the uploaded CSV
282
  clusters = csv_handler.process_uploaded_csv(csv_content)
283
-
284
  if not clusters:
285
  return jsonify({'error': 'No valid clusters found in CSV'}), 400
286
-
287
  generated_blogs = []
288
-
289
  # Process each cluster
290
  for cluster_data in clusters:
291
  try:
292
  logger.info(f"Processing cluster with primary keyword: {cluster_data['Primary Keyword']}")
293
-
294
  # Generate preliminary plan
295
  plan = generate_preliminary_plan(cluster_data)
296
-
297
  # Do research
298
  research = do_research(plan, OPENROUTER_API_KEY)
299
-
300
  # Create detailed plan
301
  detailed_plan = blog_gen.create_detailed_plan(cluster_data, plan, research)
302
-
303
  # Write blog post
304
  blog_content = blog_gen.write_blog_post(detailed_plan, cluster_data)
305
-
306
  # Add internal links
307
  previous_posts = csv_handler.get_previous_posts()
308
  blog_content = blog_gen.add_internal_links(blog_content, previous_posts)
309
-
310
  # Convert to HTML
311
  cover_image_url = blog_gen.get_cover_image(cluster_data['Primary Keyword'])
312
  html_content = blog_gen.convert_to_html(blog_content, cover_image_url)
313
-
314
  # Generate metadata
315
  metadata = blog_gen.generate_metadata(blog_content, cluster_data['Primary Keyword'], cluster_data)
316
-
317
  # Get cover image
318
  cover_image_url = blog_gen.get_cover_image(metadata['title'])
319
-
320
  # Create blog post data
321
  blog_post_data = {
322
  'title': metadata['title'],
@@ -329,13 +351,13 @@ def generate_from_csv():
329
  'research': research,
330
  'detailed_plan': detailed_plan
331
  }
332
-
333
  generated_blogs.append({
334
  'status': 'success',
335
  'message': f"Blog post generated successfully for {cluster_data['Primary Keyword']}",
336
  'data': blog_post_data
337
  })
338
-
339
  except Exception as e:
340
  logger.error(f"Error processing cluster {cluster_data['Primary Keyword']}: {e}")
341
  generated_blogs.append({
@@ -343,53 +365,53 @@ def generate_from_csv():
343
  'message': f"Failed to generate blog post for {cluster_data['Primary Keyword']}",
344
  'error': str(e)
345
  })
346
-
347
  return jsonify({
348
  'status': 'success',
349
  'message': f'Generated {len(generated_blogs)} blog posts from uploaded CSV',
350
  'blogs': generated_blogs
351
  })
352
-
353
  except Exception as e:
354
  logger.error(f"Error in generate_from_csv: {e}")
355
  return jsonify({'error': str(e)}), 500
356
-
357
 
358
  @app.route('/generate-from-csv-text', methods=['POST'])
359
  def generate_from_csv_text():
360
  try:
361
  logger.info("Starting blog generation process for multiple clusters...")
362
-
363
  # Get CSV content and OpenRouter API key from request JSON
364
  data = request.get_json()
365
  if not data or 'csv_content' not in data:
366
  return jsonify({'error': 'No CSV content provided'}), 400
367
  if 'openrouter_key' not in data:
368
  return jsonify({'error': 'OpenRouter API key is required'}), 400
369
-
370
  csv_content = data['csv_content']
371
  openrouter_key = data['openrouter_key']
372
-
373
  # Initialize handlers with the provided OpenRouter key
374
  blog_gen = BlogGenerator(OPENAI_API_KEY, openrouter_key)
375
  csv_handler = CSVHandler()
376
-
377
  # Process the CSV text
378
  clusters = csv_handler.process_csv_text(csv_content)
379
-
380
  if not clusters:
381
  return jsonify({'error': 'No valid clusters found in CSV'}), 400
382
-
383
  generated_blogs = []
384
-
385
  # Process each cluster
386
  for cluster_data in clusters:
387
  try:
388
  logger.info(f"Processing cluster with primary keyword: {cluster_data['Primary Keyword']}")
389
-
390
  # Add OpenRouter key to cluster_data for use in functions
391
  cluster_data['openrouter_key'] = openrouter_key
392
-
393
  # Generate preliminary plan
394
  logger.info("Generating preliminary plan...")
395
  plan = generate_preliminary_plan(cluster_data)
@@ -464,5 +486,26 @@ def generate_from_csv_text():
464
  logger.error(f"Error in generate_from_csv_text: {e}")
465
  return jsonify({'error': str(e)}), 500
466
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
467
  if __name__ == '__main__':
468
- app.run(host='127.0.0.1', port=5001, debug=True)
 
 
1
+ from flask import Flask, request, jsonify, Response, stream_with_context
2
+ from flask_cors import CORS
3
  import os
4
  from dotenv import load_dotenv
5
  import requests
 
8
  import ssl
9
  import logging
10
  from web_scraper import research_topic
11
+ import queue
12
+ import threading
13
 
14
+ # Create a queue for log messages
15
+ log_queue = queue.Queue()
16
+
17
+ # Custom log handler that puts messages in the queue
18
+ class QueueHandler(logging.Handler):
19
+ def emit(self, record):
20
+ log_entry = self.format(record)
21
+ log_queue.put(log_entry)
22
+
23
+ # Set up logging with the custom handler
24
+ logger = logging.getLogger()
25
+ queue_handler = QueueHandler()
26
+ queue_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
27
+ logger.addHandler(queue_handler)
28
+ logger.setLevel(logging.INFO)
29
 
30
  app = Flask(__name__)
31
+ # Enable CORS with specific settings
32
+ CORS(app, resources={
33
+ r"/*": {
34
+ "origins": "*",
35
+ "methods": ["GET", "POST", "OPTIONS"],
36
+ "allow_headers": ["Content-Type", "Authorization"]
37
+ }
38
+ })
39
 
40
  # Configuration
41
  OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')
 
97
  },
98
  timeout=60
99
  )
100
+
101
  logger.info(f"OpenRouter API Response: {response.text}")
102
+
103
  if response.status_code != 200:
104
  raise Exception(f"OpenRouter API error: {response.text}")
105
+
106
  response_data = response.json()
107
  if 'choices' not in response_data:
108
  raise Exception(f"Unexpected API response format: {response_data}")
109
+
110
  return response_data['choices'][0]['message']['content']
111
  except Exception as e:
112
  logger.error(f"Error in generate_preliminary_plan: {e}")
 
117
  try:
118
  # Extract key points from plan to create search queries
119
  plan_lines = [line.strip('* -').strip() for line in plan.split('\n') if line.strip()]
120
+
121
  # Take only the first 3 points
122
  plan_lines = plan_lines[:3]
123
  logger.info(f"Researching top 3 points: {plan_lines}")
124
+
125
  all_research = []
126
+
127
  # Research each main point in the plan (limited to 3 points)
128
  for point in plan_lines:
129
  if not point: # Skip empty lines
130
  continue
131
+
132
  # Get research results including both web content and AI analysis
133
  # Using 5 sites per point for more comprehensive research
134
  results = research_topic(point, num_sites=5, openrouter_key=openrouter_key)
135
+
136
  if results['success']:
137
  all_research.append({
138
  'topic': point,
139
  'analysis': results['analysis'],
140
  'sources': results['sources']
141
  })
142
+
143
  # Format all research into a comprehensive markdown document
144
  formatted_research = "# Research Results\n\n"
145
+
146
  for research in all_research:
147
  formatted_research += f"## {research['topic']}\n\n"
148
  formatted_research += f"{research['analysis']}\n\n"
149
  formatted_research += "### Sources Referenced\n\n"
150
+
151
  for source in research['sources']:
152
  formatted_research += f"- [{source['title']}]({source['source']})\n"
153
  if source['meta_info']['description']:
154
  formatted_research += f" {source['meta_info']['description']}\n"
155
+
156
  formatted_research += "\n---\n\n"
157
+
158
  return formatted_research
159
+
160
  except Exception as e:
161
  logger.error(f"Error in do_research: {e}")
162
  raise
 
165
  def generate_blog():
166
  try:
167
  logger.info("Starting blog generation process for multiple clusters...")
168
+
169
  # Initialize handlers
170
  blog_gen = BlogGenerator(OPENAI_API_KEY, OPENROUTER_API_KEY)
171
  csv_handler = CSVHandler()
172
 
173
  generated_blogs = []
174
+
175
  # Get all available clusters
176
  all_clusters = csv_handler.get_all_clusters()
177
+
178
  for cluster_data in all_clusters:
179
  try:
180
  logger.info(f"Processing cluster with primary keyword: {cluster_data['Primary Keyword']}")
181
+
182
  # 2. Generate preliminary plan
183
  logger.info("Generating preliminary plan...")
184
  plan = generate_preliminary_plan(cluster_data)
 
288
  try:
289
  if 'file' not in request.files:
290
  return jsonify({'error': 'No file uploaded'}), 400
291
+
292
  file = request.files['file']
293
  if file.filename == '':
294
  return jsonify({'error': 'No file selected'}), 400
295
+
296
  # Read and decode the CSV content
297
  csv_content = file.read().decode('utf-8')
298
+
299
  # Initialize handlers
300
  blog_gen = BlogGenerator(OPENAI_API_KEY, OPENROUTER_API_KEY)
301
  csv_handler = CSVHandler()
302
+
303
  # Process the uploaded CSV
304
  clusters = csv_handler.process_uploaded_csv(csv_content)
305
+
306
  if not clusters:
307
  return jsonify({'error': 'No valid clusters found in CSV'}), 400
308
+
309
  generated_blogs = []
310
+
311
  # Process each cluster
312
  for cluster_data in clusters:
313
  try:
314
  logger.info(f"Processing cluster with primary keyword: {cluster_data['Primary Keyword']}")
315
+
316
  # Generate preliminary plan
317
  plan = generate_preliminary_plan(cluster_data)
318
+
319
  # Do research
320
  research = do_research(plan, OPENROUTER_API_KEY)
321
+
322
  # Create detailed plan
323
  detailed_plan = blog_gen.create_detailed_plan(cluster_data, plan, research)
324
+
325
  # Write blog post
326
  blog_content = blog_gen.write_blog_post(detailed_plan, cluster_data)
327
+
328
  # Add internal links
329
  previous_posts = csv_handler.get_previous_posts()
330
  blog_content = blog_gen.add_internal_links(blog_content, previous_posts)
331
+
332
  # Convert to HTML
333
  cover_image_url = blog_gen.get_cover_image(cluster_data['Primary Keyword'])
334
  html_content = blog_gen.convert_to_html(blog_content, cover_image_url)
335
+
336
  # Generate metadata
337
  metadata = blog_gen.generate_metadata(blog_content, cluster_data['Primary Keyword'], cluster_data)
338
+
339
  # Get cover image
340
  cover_image_url = blog_gen.get_cover_image(metadata['title'])
341
+
342
  # Create blog post data
343
  blog_post_data = {
344
  'title': metadata['title'],
 
351
  'research': research,
352
  'detailed_plan': detailed_plan
353
  }
354
+
355
  generated_blogs.append({
356
  'status': 'success',
357
  'message': f"Blog post generated successfully for {cluster_data['Primary Keyword']}",
358
  'data': blog_post_data
359
  })
360
+
361
  except Exception as e:
362
  logger.error(f"Error processing cluster {cluster_data['Primary Keyword']}: {e}")
363
  generated_blogs.append({
 
365
  'message': f"Failed to generate blog post for {cluster_data['Primary Keyword']}",
366
  'error': str(e)
367
  })
368
+
369
  return jsonify({
370
  'status': 'success',
371
  'message': f'Generated {len(generated_blogs)} blog posts from uploaded CSV',
372
  'blogs': generated_blogs
373
  })
374
+
375
  except Exception as e:
376
  logger.error(f"Error in generate_from_csv: {e}")
377
  return jsonify({'error': str(e)}), 500
378
+
379
 
380
  @app.route('/generate-from-csv-text', methods=['POST'])
381
  def generate_from_csv_text():
382
  try:
383
  logger.info("Starting blog generation process for multiple clusters...")
384
+
385
  # Get CSV content and OpenRouter API key from request JSON
386
  data = request.get_json()
387
  if not data or 'csv_content' not in data:
388
  return jsonify({'error': 'No CSV content provided'}), 400
389
  if 'openrouter_key' not in data:
390
  return jsonify({'error': 'OpenRouter API key is required'}), 400
391
+
392
  csv_content = data['csv_content']
393
  openrouter_key = data['openrouter_key']
394
+
395
  # Initialize handlers with the provided OpenRouter key
396
  blog_gen = BlogGenerator(OPENAI_API_KEY, openrouter_key)
397
  csv_handler = CSVHandler()
398
+
399
  # Process the CSV text
400
  clusters = csv_handler.process_csv_text(csv_content)
401
+
402
  if not clusters:
403
  return jsonify({'error': 'No valid clusters found in CSV'}), 400
404
+
405
  generated_blogs = []
406
+
407
  # Process each cluster
408
  for cluster_data in clusters:
409
  try:
410
  logger.info(f"Processing cluster with primary keyword: {cluster_data['Primary Keyword']}")
411
+
412
  # Add OpenRouter key to cluster_data for use in functions
413
  cluster_data['openrouter_key'] = openrouter_key
414
+
415
  # Generate preliminary plan
416
  logger.info("Generating preliminary plan...")
417
  plan = generate_preliminary_plan(cluster_data)
 
486
  logger.error(f"Error in generate_from_csv_text: {e}")
487
  return jsonify({'error': str(e)}), 500
488
 
489
+ @app.route('/logs/stream')
490
+ def stream_logs():
491
+ def generate():
492
+ while True:
493
+ try:
494
+ # Get log message from queue, timeout after 1 second
495
+ log_message = log_queue.get(timeout=1)
496
+ yield f"data: {log_message}\n\n"
497
+ except queue.Empty:
498
+ # Send a heartbeat to keep the connection alive
499
+ yield "data: heartbeat\n\n"
500
+ except GeneratorExit:
501
+ break
502
+
503
+ response = Response(stream_with_context(generate()), mimetype='text/event-stream')
504
+ response.headers['Cache-Control'] = 'no-cache'
505
+ response.headers['Connection'] = 'keep-alive'
506
+ response.headers['Access-Control-Allow-Origin'] = '*'
507
+ return response
508
+
509
  if __name__ == '__main__':
510
+ logger.info("Starting Flask API server...")
511
+ app.run(host='127.0.0.1', port=5001, debug=True, threaded=True)