', unsafe_allow_html=True)
321 |
322 | # Add custom CSS for centering the title
323 | st.markdown("""
324 |
332 | """, unsafe_allow_html=True)
333 |
334 | # Create a placeholder for the centered header
335 | header_placeholder = st.empty()
336 |
337 | # Display the default title or the user-provided title
338 | if 'story_title' not in st.session_state:
339 | st.session_state.story_title = "Create a New Article"
340 |
341 | header_placeholder.markdown(f'
{st.session_state.story_title}
',
342 | unsafe_allow_html=True)
343 |
344 | # Display the chat input
345 | story_title = st.chat_input("Story Title", key="story_title_input")
346 | if story_title:
347 | # Convert the story title to title case
348 | st.session_state.story_title = story_title.title()
349 | prompt_helper.update_global_prompt_elem("story_title", st.session_state.story_title)
350 | header_placeholder.markdown(f'
{st.session_state.story_title}
',
351 | unsafe_allow_html=True)
352 |
353 | # Story blocks
354 | for block in st.session_state.story_blocks:
355 | output_tab, settings_tab, image_tab = st.tabs(["Output", "Settings", "Image"])
356 |
357 | with output_tab:
358 | title = st.chat_input(f"{block} Title", key=f"{block}_title_input")
359 |
360 | if title:
361 | prompt_helper.update_block_prompt_elem(block, "title", title)
362 |
363 | # Create a placeholder for the streamed content
364 | output_placeholder = st.empty()
365 |
366 |
367 | # Function to update the placeholder with streamed content
368 | def update_content():
369 | with st.spinner(f"Generating {block} content..."):
370 | try:
371 | content_generator = prompt_helper.generate_api_response(block)
372 |
373 | # Create a placeholder for the streamed content
374 | content_placeholder = output_placeholder.empty()
375 |
376 | # Accumulate the entire response
377 | full_response = ""
378 | for chunk in content_generator:
379 | full_response += chunk
380 | # Show a loading message or progress bar
381 | content_placeholder.text("Generating content...")
382 |
383 | # Format the complete content
384 | display_content = format_markdown_content(block, full_response)
385 |
386 | # Wrap the content in a block-content div
387 | wrapped_content = f'
{display_content}
'
388 |
389 | # Display the formatted content
390 | content_placeholder.markdown(wrapped_content, unsafe_allow_html=True)
391 |
392 | # Store the complete response in session state
393 | st.session_state[f"{block}_response"] = wrapped_content
394 | except Exception as e:
395 | error_message = prompt_helper.get_user_friendly_error_message(e)
396 | st.error(f"An error occurred while generating content: {error_message}")
397 | st.button("Retry", on_click=update_content)
398 |
399 |
400 | # Run the function
401 | update_content()
402 |
403 | elif f"{block}_response" in st.session_state:
404 | # Add the image at the top of the content if it exists
405 | if f"{block}_image_url" in st.session_state:
406 | image_html = img_to_html(st.session_state[f"{block}_image_url"])
407 | display_content = image_html + st.session_state[f'{block}_response']
408 | else:
409 | display_content = st.session_state[f'{block}_response']
410 |
411 | # st.markdown(f"""
412 | #
413 | #
{prompt_helper.get_block_prompt_elem(block, 'title')}
414 | # {display_content}
415 | #
416 | # """, unsafe_allow_html=True)
417 | st.markdown(st.session_state[f'{block}_response'], unsafe_allow_html=True)
418 |
419 | if block not in story_blocks:
420 | if st.button(f"Remove {block}"):
421 | remove_block(block)
422 | st.rerun()
423 |
424 | with settings_tab:
425 | # User input for word count
426 | word_count = st.slider("Word Count", 50, 200, prompt_helper.get_block_prompt_elem(block, "word_count", 60),
427 | key=f"{block}_word_count_slider")
428 | prompt_helper.update_block_prompt_elem(block, "word_count", word_count) # User input sent
429 |
430 | # User toggle for keywords
431 | if st.checkbox("Toggle Keywords", key=f"{block}_tgl_keywords",
432 | value=toggles_helper.get_block_toggle_state(block, "tgl_keywords")):
433 | toggles_helper.update_block_toggle_state(block, "tgl_keywords", True)
434 | # User input for keywords (only shown when toggle is activated)
435 | keywords = st.text_input("Keywords", prompt_helper.get_block_prompt_elem(block, "keywords"),
436 | key=f"{block}_keywords_input")
437 | prompt_helper.update_block_prompt_elem(block, "keywords", keywords) # User input sent
438 | else:
439 | toggles_helper.update_block_toggle_state(block, "tgl_keywords", False)
440 | prompt_helper.update_block_prompt_elem(block, "keywords", "")
441 |
442 | # New: User toggle for custom notes
443 | if st.checkbox("Toggle Custom Notes", key=f"{block}_tgl_notes",
444 | value=toggles_helper.get_block_toggle_state(block, "tgl_notes")):
445 | toggles_helper.update_block_toggle_state(block, "tgl_notes", True)
446 | # User input for custom notes (only shown when toggle is activated)
447 | notes = st.text_area("Custom Notes", prompt_helper.get_block_prompt_elem(block, "notes"),
448 | key=f"{block}_notes_input", height=150)
449 | prompt_helper.update_block_prompt_elem(block, "notes", notes) # User input sent
450 | else:
451 | toggles_helper.update_block_toggle_state(block, "tgl_notes", False)
452 | prompt_helper.update_block_prompt_elem(block, "notes", "")
453 |
454 | # Debug information
455 | st.text_area(f"Debug: Prompt for {block}", prompt_helper.get_formatted_prompt(block), height=150)
456 |
457 | with image_tab:
458 | st.subheader(f"Image Search for {block}")
459 | image_query = st.chat_input(f"Enter search query for {block} image", key=f"{block}_image_query")
460 | if image_query:
461 | image_urls = search_images(image_query)
462 | if image_urls:
463 | display_image_select(block, image_urls)
464 |
465 | if f"{block}_image_url" in st.session_state:
466 | st.image(st.session_state[f"{block}_image_url"], caption=f"Image for {block}", use_column_width=True)
467 |
468 | # Close the content-column div
469 | st.markdown('
', unsafe_allow_html=True)
470 | if st.button("Add New Block"):
471 | add_new_block()
472 | st.rerun()
473 |
474 | # New outline_column
475 | with outline_column:
476 | st.header("Overview")
477 |
478 | outline_tab, export_tab = st.tabs(["Outline", "Export"])
479 |
480 | with outline_tab:
481 | st.subheader("Article Outline")
482 | for block in st.session_state.story_blocks:
483 | block_title = prompt_helper.get_block_prompt_elem(block, 'title')
484 | if block_title:
485 | st.markdown(f"- **{block}**: {block_title}")
486 | else:
487 | st.markdown(f"- **{block}**: *No title set*")
488 |
489 | with export_tab:
490 | if st.button("Export to Rentry"):
491 | # Generate full content here
492 | full_content = f"# {st.session_state.story_title}\n\n"
493 | for block in st.session_state.story_blocks:
494 | if f"{block}_response" in st.session_state:
495 | block_title = prompt_helper.get_block_prompt_elem(block, 'title')
496 | full_content += f"## {block_title}\n\n"
497 | full_content += f"{st.session_state[f'{block}_response']}\n\n"
498 | else:
499 | st.warning(f"{block} not generated yet.")
500 | full_content += f"## {block}\n\n*Content not generated*\n\n"
501 |
502 | rentry_url, edit_code = export_to_rentry(full_content)
503 | if rentry_url:
504 | st.success(f"Successfully exported to Rentry. URL: {rentry_url}")
505 | st.info(f"Edit code: {edit_code}")
506 |
507 | # Open the Rentry URL in a new browser tab
508 | webbrowser.open_new_tab(rentry_url)
509 |
510 | # Provide a manual link in case automatic opening fails
511 | st.markdown(f"If the page doesn't open automatically, [click here to view your Rentry]({rentry_url})")
512 | else:
513 | st.error("Failed to export to Rentry. Please try again.")
514 |
--------------------------------------------------------------------------------
/openplexity_pages/groq_search.py:
--------------------------------------------------------------------------------
1 | import os
2 | from groq import Groq
3 | import json
4 | import requests
5 | from dotenv import load_dotenv
6 |
7 | # Load environment variables from .env file
8 | load_dotenv()
9 |
10 | # Initialize Groq client
11 | GROQ_API_KEY = os.getenv('GROQ_API_KEY')
12 | SERPER_API_KEY = os.getenv('SERPER_API_KEY')
13 |
14 | if not GROQ_API_KEY:
15 | raise ValueError("GROQ_API_KEY environment variable is not set")
16 | client = Groq(api_key=GROQ_API_KEY)
17 | MODEL = 'llama3-groq-70b-8192-tool-use-preview'
18 |
19 | def google_search(query):
20 | """Perform a Google search using Serper API and return detailed results"""
21 | url = 'https://google.serper.dev/search'
22 | payload = json.dumps({
23 | 'q': query,
24 | 'num': 5, # Request 10 results
25 | 'gl': 'us',
26 | 'hl': 'en',
27 | 'type': 'search'
28 | })
29 | headers = {
30 | 'X-API-KEY': SERPER_API_KEY,
31 | 'Content-Type': 'application/json'
32 | }
33 | response = requests.post(url, headers=headers, data=payload)
34 | results = response.json().get('organic', [])
35 |
36 | formatted_results = ["Search results:"]
37 | for r in results:
38 | formatted_result = f"Title: {r.get('title', '')}\nLink: {r.get('link', '')}\nSnippet: {r.get('snippet', '')}\n---"
39 | formatted_results.append(formatted_result)
40 |
41 | return "\n".join(formatted_results)
42 |
43 | def run_conversation(user_prompt):
44 | messages = [
45 | {
46 | "role": "system",
47 | "content": """
48 | You are an AI assistant designed to help with Google searches and provide comprehensive answers based on the search results. Your task is to use the google_search function to find information and present the results in a clear and informative manner.
49 |
50 | To perform a search, use the following function:
51 |