Problem Statement: பிரச்னை கூறுதல் : ஒரு முதியவன் பாதாளங்களைத் தாண்டும் தன் மந்திரக்கோலால் சாய்த்தபடியிருக்கிறான் நாட்சத்திரங்களை. .............................................................................................................................................................................. இது எத்தனையாவது [...] Solution: AI Agentic Assistant Powered by Streamlit + Semantic Kernel இன்டர்நெட்: Streamlit + Semantic Kernel ஒரு முதியவன் பாதாளங்களைத் தாண்டும் தன் மந்திரக்கோலால் சாய்த்தபடியிருக்கிறான் நாட்சத்திரங்களை. .............................................................................................................................................................................. இது எத்தனையாவது [...] முதுகெலும்பு முதுகெலும்பு, Semantic Kernel for prompt management and chaining - விரைவில் நிர்வகிக்கப்படும். Azure OpenAI for natural language processing (சிறு மொழிகளின் செயல்பாடுகளைப் பொறுத்தவரை) பாதுகாப்பான மற்றும் Dynamic web scraping of Confluence பக்கங்கள். என்ன செய்கிறது இந்த கருவி திட்ட மேலாளர்கள் மற்றும் தலைவர்கள் செய்ய முடியும்: Select a from a dropdown, team or program name Automatically fetch the associated Confluence page URL, Scrape key content sections from that page (like Features, Epics, Dependencies, Risks, Team Members), Ask questions like “What are the team Q4 deliverables?” or “Summarize the features based on status,” etc., Display answers as summarized text. How it works - Pseudo Code அது எப்படி வேலை செய்கிறது - Pseudo Code Step 1. Confluence Page LookUp. அதேபோல், ஒவ்வொரு அணியின் பெயரையும் ஒரு மொழிபெயர்ப்பைப் பயன்படுத்தி Confluence URL-க்கு மாத்திரை செய்யப்படுகிறது.When a user selects "Team A" from the right pane, the backend automatically retrieves the associated URL and triggers scraping. team_to_url_map = { "இரவு A": "https://confluence.company.com/display/TEAM_A", "கடவுள் B": "https://confluence.company.com/display/TEAM_B", ... } team_to_url_map = { "Team A": "https://confluence.company.com/display/TEAM_A", "Team B": "https://confluence.company.com/display/TEAM_B", ... } Step 2. Web Scraping via Playwright இறுதியாக, நான் Playwright பயன்படுத்த முடிந்தது தலைமுறையற்ற உலாவி அடிப்படையான scraping, இது நமக்கு dynamic content load மற்றும் login செயல்படுத்த உதவுகிறது: தவறான வழிமுறைகள் - [ ]Python request library ஐப் பயன்படுத்தி, API ஐப் பயன்படுத்தி Confluence Data கிடைக்கும். authentication mechanisms failed. Otherwise, it would be an excellent way to get Confluence page data. [ ]Python BeautifySoup library பயன்படுத்தி. it was excluded because of dynamic content. [ ]I ended up with Python Playwright.The SSO layer had challenges, but finally, it worked after downloading the HTML state JSON and reusing it. @kernel_function(description="Scrape and return text content from a Confluence page.") async def get_confluence_page_content(self, team_name: Annotated[str, "Name of the Agile team"]) -> Annotated[str, "Returns extracted text content from the page"): @kernel_function(description="Scrape and return text content from a Confluence page.") async def get_confluence_page_content(self, team_name: Annotated[str, "Name of the Agile team"]) -> Annotated[str, "Returns extracted text content from the page"]: Step 3. Define Client, Agent, and Prompt Engineering with Semantic Kernel. இது ஒரு Program Management Enabler ஆகும்.The Agent Instructions are drafted to use the scraped content and produce a result suitable for PM questions.The instructions will help get output as a text summary or in a chart format.This is also an example of low code. மேலும், I defined the client as an AI Agent as a plugin. Agent_Instructions = “” » » வாடிக்கையாளர் = OpenAI(<Local open source LLM>) இன்டர்நெட் டைரக்டர் டைரக்டர் டைரக்டர் டைரக்டர் டைரக்டர் டைரக்டர் async_client = வாடிக்கையாளர் அலுவலகம் = ChatCompletionAgent( service=chat_completion_service, plugins=[ ConfluencePlugin() ], name="ConfluenceAgent", instructions=AGENT_INSTRUCTIONS ) AGENT_INSTRUCTIONS = “““ “““ client = OpenAI(<Local open source LLM>) chat_completion_service = OpenAIChatCompletion(ai_model_id="<>", async_client=client ) agent = ChatCompletionAgent( service=chat_completion_service, plugins=[ ConfluencePlugin() ], name="ConfluenceAgent", instructions=AGENT_INSTRUCTIONS ) Step 4. Decide on User Input to process the question with or without the tool. I decided to add an additional LLM client to check whether the user input is relevant to Program Management அல்லது இல்லை. இவ்வாறு கூறுகையில், அந்நிய செலாவணி அலுவலகத்தில், அந்நிய செலாவணி அலுவலகத்தில், அந்நிய செலாவணி அலுவலகத்தில், அந்நிய செலாவணி அலுவலகத்தில், அந்நிய செலாவணி அலுவலகத்தில், அந்நிய செலாவணி அலுவலகத்தில், அந்நிய செலாவணி அலுவலகத்தில், அந்நிய செலாவணி அலுவலகத்தில், அந்நிய செலாவணி அலுவலகத்தில், அந்நிய செலாவணி அலுவலகத்தில், அந்நிய செலாவணி அலுவலகத்தில், அந்நிய செலாவணி அலுவலகத்தில், அந்நிய செலாவணி அலுவலகத்தில், அந்நிய செலாவ completion = await client.chat.completions.create( model="gpt-4o", messages=[ {"role": "system", "content": "You are a Judge of the content of user input. Anlyze the user's input. If it asking to scrap internal COnfluence Page for a team then it is related to Program Management. If it is not related to Program Management, provide the reply but add 'False|' to the response. If it is related to Program Management, add 'True|' to the response."}, {"role": "user", "content": user_input} ], temperature=0.5 ) Step 5. The final step is to produce the result. Here is the entire code. இதோ முழு குறியீடு.நான் என் திட்டம் குறித்த விவரங்களை மறைத்தேன்.முதலில் state.json சேமிக்க வேண்டும் குறியீட்டில் அதை பயன்படுத்த ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்த Team_URL_MAPPING = { "Team 1": "Team 1 for Confluence URL", "Team 2": "Team 2 for Confluence URL", "Team 3": "Team 3 for Confluence URL", "Team 4": "Team 4 for Confluence URL", "Team 5": "Team 5 for Confluence URL", "Team 6": "Team 6 for Confluence URL" } # ---- Plugin விளக்கம் ---- இந்நிலையில், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறைய ஆஃப்ட்ராய்டு extract_json_from_response(text): # use regex to find the first JSON array in the text match = re.search(r"(\[\s*{.*}\s*\)", text, re.DOTALL) if match: return match.group(1) return No வகுப்பு ConfluencePlugin: def init(self): self.default_confluence_url = "<>" load_dotenv() @kernel_function(description="Scrape and return text content from a Confluence page.") async def get_confluence_page_content( self, team_name: Annotated\[str, "Name of the Agile team"\] ) -> Annotated\[str, "Returns extracted text content from the page"\]: print(f"Attempting to scrape Confluence page for team: '{team_name}'") # Added for debugging target_url = TEAM_URL_MAPPING.get(team_name) if not target_url: print(f"Failed to find URL for team: '{team_name}' in TEAM_URL_MAPPING.") # Added for debugging return f"❌ No Confluence URL mapped for team '{team_name}'" async with async_playwright() as p: browser = await p.chromium.launch() context = await browser.new_context(storage_state="state.json") page = await context.new_page() pages_to_scrape = \[target_url\] # Loop through each page URL and scrape the content for page_url in pages_to_scrape: await page.goto(page_url) await asyncio.sleep(30) # Wait for the page to load await page.wait_for_selector('div.refresh-module-id, table.some-jira-table') html = await page.content() soup = BeautifulSoup(html, "html.parser") body_div = soup.find("div", class_="wiki-content") or soup.body if not body_div: return "❌ Could not find content on the Confluence page." # Process the scraped content (example: extract headings) headings = soup.find_all('h2') text = body_div.get_text(separator="\\n", strip=True) return text\[:4000\] # Truncate if needed to stay within token limits await browser.close() @kernel_function(description="Summarize and structure scraped Confluence content into JSON.") async def summarize_confluence_data( self, raw_text: Annotated\[str, "Raw text scraped from the Confluence page"\], output_style: Annotated\[str, "Output style, either 'bullet' or 'json'"\] = "json" # Default to 'json' ) -> Annotated\[str, "Returns structured summary in JSON format"\]: prompt = f""" You are a Program Management Data Extractor. Your job is to analyze the following Confluence content and produce structured machine-readable output. Confluence Content: {raw_text} Instructions: - If output_style is 'bullet', return bullet points summary. - If output_style is 'json', return only valid JSON array by removing un printable characters and spaces from beginning and end. - DO NOT write explanations. - DO NOT suggest code snippets. - DO NOT wrap JSON inside triple backticks \`\`\`json - Output ONLY the pure JSON array or bullet points list. Output_style: {output_style} """ # Call OpenAI again completion = await client.chat.completions.create( model="gpt-4o", messages=\[ {"role": "system", "content": "You are a helpful Program Management Data Extractor."}, {"role": "user", "content": prompt} \], temperature=0.1 ) structured_json = completion.choices\[0\].message.content.strip() return structured_json # ---- Load API credentials ---- load_dotenv() client = AsyncAzureOpenAI( azure_endpoint="<>", api_key=os.getenv("AZURE_API_KEY"), api_version='<>' ) chat_completion_service = OpenAIChatCompletion( ai_model_id="<>", async_client=client ) Agent_Instructions = """You are a helpful Program Management AI Agent that can help extract key information such as Team Member, Features, Epics from a confluence page. Important: Users specify a Team page, only extract the Features and Epics of that team. பேச்சு தொடங்கும் போது, இந்த செய்தி உங்களை அறிமுகப்படுத்துங்கள்: "ஹலோ!நான் உங்கள் PM உதவியாளர்.நான் Features மற்றும் Epics நிலை பெற உதவ முடியும். எப்போதும் முதல் அழைப்பு `get_confluence_page_content` Confluence பக்கத்தை கிளிக் செய்ய. இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில். இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில்: இன்று நீங்கள் திட்டமிடுவதற்கு எந்த அணி உங்களுக்கு உதவ விரும்புகிறது?" எப்போதும் பயனர் விருப்பங்களை முதலீடு செய்யுங்கள். ஒரு குறிப்பிட்ட குழுவை அவர்கள் குறிப்பிட்டால், அத்தகைய குழுவில் உங்கள் தரவுகளை பரிந்துரைக்க வேண்டாம். """ agent = ChatCompletionAgent( service=chat_completion_service, plugins=[ ConfluencePlugin() ], name="ConfluenceAgent", instructions=AGENT_INSTRUCTIONS ) இந்நிலையில், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறைய async for response in agent.invoke_stream(messages=user_input, thread=thread): print("Response:", response) thread = response.thread agent_name = response.name for item in list(response.items): if isinstance(item, FunctionCallContent): pass # You can ignore this now elif isinstance(item, FunctionResultContent): if item.name == "summarize_confluence_data": raw_content = item.result extracted_json = extract_json_from_response(raw_content) if extracted_json: try: parsed_json = json.loads(extracted_json) yield parsed_json, thread, function_calls except Exception as e: st.error(f"Failed to parse extracted JSON: {e}") else: full_response.append(raw_content) else: full_response.append(item.result) elif isinstance(item, StreamingTextContent) and item.text: full_response.append(item.text) #print("Full Response:", full_response) # After loop ends, yield final result if parsed_json_result: yield parsed_json_result, thread, function_calls else: yield ''.join(full_response), thread, function_calls இவ்வாறான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான வி if "history" not in st.session_state: st.session_state.history = \[\] if "thread" not in st.session_state: st.session_state.thread = None if "charts" not in st.session_state: st.session_state.charts = \[\] # Each entry: {"df": ..., "title": ..., "question": ...} if "chart_dataframes" not in st.session_state: st.session_state.chart_dataframes = \[\] if st.button("🧹 Clear Chat"): st.session_state.history = \[\] st.session_state.thread = None st.rerun() # Input box at the top user_input = st.chat_input("Ask me about your team's features...") # Example: team_selected = st.session_state.get("selected_team") if st.session_state.get("selected_team") and user_input: user_input = f"Team: {st.session_state.get('selected_team')}. {user_input}" # Preserve chat history when program or team is selected if user_input and not st.session_state.get("selected_team_changed", False): st.session_state.selected_team_changed = False if user_input: df = pd.DataFrame() full_response_holder = {"text": "","df": None} with st.chat_message("assistant"): response_container = st.empty() assistant_text = "" try: chat_index = len(st.session_state.history) response_gen = stream_response(user_input, st.session_state.thread) print("Response generator started",response_gen) async def process_stream(): async for update in response_gen: nonlocal_thread = st.session_state.thread if len(update) == 3: content, nonlocal_thread, function_calls = update full_response_holder\["text"\] = content if isinstance(content, list): data = json.loads(re.sub(r'\[\\x00-\\x1F\\x7F\]', '', content.replace("\`\`\`json", "").replace("\`\`\`",""))) df = pd.DataFrame(data) df.columns = df.columns.str.lower() print("\\n📊 Features Status Chart") st.subheader("📊 Features Status Chart") plot_bar_chart(df) st.subheader("📋 Detailed Features Table") st.dataframe(df) chart_df.columns = chart_df.columns.str.lower() full_response_holder\["df"\] = chart_df elif (re.sub(r'\[\\x00-\\x1F\\x7F\]', '', content.replace("\`\`\`json", "").replace("\`\`\`","").replace(" ",""))\[0\] =="\[" and re.sub(r'\[\\x00-\\x1F\\x7F\]', '', content.replace("\`\`\`json", "").replace("\`\`\`","").replace(" ",""))\[-1\] == "\]"): data = json.loads(re.sub(r'\[\\x00-\\x1F\\x7F\]', '', content.replace("\`\`\`json", "").replace("\`\`\`",""))) df = pd.DataFrame(data) df.columns = df.columns.str.lower() chart_df = pd.DataFrame(data) chart_df.columns = chart_df.columns.str.lower() full_response_holder\["df"\] = chart_df else: if function_calls: st.markdown("\\n".join(function_calls)) flagtext = 'text' st.session_state.thread = nonlocal_thread try: with st.spinner("🤖 AI is thinking..."): flagtext = None # Run the async function to process the stream asyncio.run(process_stream()) # Update history with the assistant's response if full_response_holder\["df"\] is not None and flagtext is None: st.session_state.chart_dataframes.append({ "question": user_input, "data": full_response_holder\["df"\], "type": "chart" }) elif full_response_holder\["text"\].strip(): # Text-type response st.session_state.history.append({ "user": user_input, "assistant": full_response_holder\["text"\], "type": "text" }) flagtext = None except Exception as e: error_msg = f"⚠️ Error: {e}" response_container.markdown(error_msg) if chat_index > 0 and "Error" in full_response_holder\["text"\]: # Remove the last message only if it was an error st.session_state.history.pop(chat_index) # Handle any exceptions that occur during the async call except Exception as e: full_response_holder\["text"\] = f"⚠️ Error: {e}" response_container.markdown(full_response_holder\["text"\]) chat_index = len(st.session_state.history) #for item in st.session_state.history\[:-1\]: for item in reversed(st.session_state.history): if item\["type"\] == "text": with st.chat_message("user"): st.markdown(item\["user"\]) with st.chat_message("assistant"): st.markdown(item\["assistant"\]) with right_col:st.title("Select Wiley திட்டம்") team_list = { "Program 1": \["Team 1", "Team 2", "Team 3"\], "Program 2": \["Team 4", "Team 5", "Team 6"\] } selected_program = st.selectbox("Select the Program:", \["No selection"\] + list(team_list.keys()), key="program_selectbox") selected_team = st.selectbox("Select the Agile Team:", \["No selection"\] + team_list.get(selected_program, \[\]), key="team_selectbox") st.session_state\["selected_team"\] = selected_team if selected_team != "No selection" else None if st.button("🧹 Clear All Charts"): st.session_state.chart_dataframes = \[\] chart_idx = 1 #if len(st.session_state.chart_dataframes) == 1: for idx, item in enumerate(st.session_state.chart_dataframes): #for idx, item in enumerate(st.session_state.chart_dataframes): st.markdown(f"\*\*Chart {idx + 1}: {item\['question'\]}\*\*") st.subheader("📊 Features Status Chart") plot_bar_chart(item\["data"\]) st.subheader("📋 Detailed Features Table") st.dataframe(item\["data"\]) chart_idx += 1 ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்தி, ஆபீஸைப் பயன்படுத்த Team_URL_MAPPING = { "Team 1": "Team 1 for Confluence URL", "Team 2": "Team 2 for Confluence URL", "Team 3": "Team 3 for Confluence URL", "Team 4": "Team 4 for Confluence URL", "Team 5": "Team 5 for Confluence URL", "Team 6": "Team 6 for Confluence URL" } # ---- Plugin விளக்கம் ---- இந்நிலையில், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறைய ஆஃப்ட்ராய்டு extract_json_from_response(text): # use regex to find the first JSON array in the text match = re.search(r"(\[\s*{.*}\s*\)", text, re.DOTALL) if match: return match.group(1) return No வகுப்பு ConfluencePlugin: def init(self): self.default_confluence_url = "<>" load_dotenv() @kernel_function(description="Scrape and return text content from a Confluence page.") async def get_confluence_page_content( self, team_name: Annotated\[str, "Name of the Agile team"\] ) -> Annotated\[str, "Returns extracted text content from the page"\]: print(f"Attempting to scrape Confluence page for team: '{team_name}'") # Added for debugging target_url = TEAM_URL_MAPPING.get(team_name) if not target_url: print(f"Failed to find URL for team: '{team_name}' in TEAM_URL_MAPPING.") # Added for debugging return f"❌ No Confluence URL mapped for team '{team_name}'" async with async_playwright() as p: browser = await p.chromium.launch() context = await browser.new_context(storage_state="state.json") page = await context.new_page() pages_to_scrape = \[target_url\] # Loop through each page URL and scrape the content for page_url in pages_to_scrape: await page.goto(page_url) await asyncio.sleep(30) # Wait for the page to load await page.wait_for_selector('div.refresh-module-id, table.some-jira-table') html = await page.content() soup = BeautifulSoup(html, "html.parser") body_div = soup.find("div", class_="wiki-content") or soup.body if not body_div: return "❌ Could not find content on the Confluence page." # Process the scraped content (example: extract headings) headings = soup.find_all('h2') text = body_div.get_text(separator="\\n", strip=True) return text\[:4000\] # Truncate if needed to stay within token limits await browser.close() @kernel_function(description="Summarize and structure scraped Confluence content into JSON.") async def summarize_confluence_data( self, raw_text: Annotated\[str, "Raw text scraped from the Confluence page"\], output_style: Annotated\[str, "Output style, either 'bullet' or 'json'"\] = "json" # Default to 'json' ) -> Annotated\[str, "Returns structured summary in JSON format"\]: prompt = f""" You are a Program Management Data Extractor. Your job is to analyze the following Confluence content and produce structured machine-readable output. Confluence Content: {raw_text} Instructions: - If output_style is 'bullet', return bullet points summary. - If output_style is 'json', return only valid JSON array by removing un printable characters and spaces from beginning and end. - DO NOT write explanations. - DO NOT suggest code snippets. - DO NOT wrap JSON inside triple backticks \`\`\`json - Output ONLY the pure JSON array or bullet points list. Output_style: {output_style} """ # Call OpenAI again completion = await client.chat.completions.create( model="gpt-4o", messages=\[ {"role": "system", "content": "You are a helpful Program Management Data Extractor."}, {"role": "user", "content": prompt} \], temperature=0.1 ) structured_json = completion.choices\[0\].message.content.strip() return structured_json # ---- Load API credentials ---- load_dotenv() client = AsyncAzureOpenAI( azure_endpoint="<>", api_key=os.getenv("AZURE_API_KEY"), api_version='<>' ) chat_completion_service = OpenAIChatCompletion( ai_model_id="<>", async_client=client ) Agent_Instructions = """You are a helpful Program Management AI Agent that can help extract key information such as Team Member, Features, Epics from a confluence page. Important: Users specify a Team page, only extract the Features and Epics of that team. பேச்சு தொடங்கும் போது, இந்த செய்தி உங்களை அறிமுகப்படுத்துங்கள்: "ஹலோ!நான் உங்கள் PM உதவியாளர்.நான் Features மற்றும் Epics நிலை பெற உதவ முடியும். எப்போதும் முதல் அழைப்பு `get_confluence_page_content` Confluence பக்கத்தை கிளிக் செய்ய. இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில். இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில், இவ்வாறு கூறுகையில்: இன்று நீங்கள் திட்டமிடுவதற்கு எந்த அணி உங்களுக்கு உதவ விரும்புகிறது?" எப்போதும் பயனர் விருப்பங்களை முதலீடு செய்யுங்கள். ஒரு குறிப்பிட்ட குழுவை அவர்கள் குறிப்பிட்டால், அத்தகைய குழுவில் உங்கள் தரவுகளை பரிந்துரைக்க வேண்டாம். """ agent = ChatCompletionAgent( service=chat_completion_service, plugins=[ ConfluencePlugin() ], name="ConfluenceAgent", instructions=AGENT_INSTRUCTIONS ) இந்நிலையில், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறையினர், அந்நிய செலாவணி துறைய async for response in agent.invoke_stream(messages=user_input, thread=thread): print("Response:", response) thread = response.thread agent_name = response.name for item in list(response.items): if isinstance(item, FunctionCallContent): pass # You can ignore this now elif isinstance(item, FunctionResultContent): if item.name == "summarize_confluence_data": raw_content = item.result extracted_json = extract_json_from_response(raw_content) if extracted_json: try: parsed_json = json.loads(extracted_json) yield parsed_json, thread, function_calls except Exception as e: st.error(f"Failed to parse extracted JSON: {e}") else: full_response.append(raw_content) else: full_response.append(item.result) elif isinstance(item, StreamingTextContent) and item.text: full_response.append(item.text) #print("Full Response:", full_response) # After loop ends, yield final result if parsed_json_result: yield parsed_json_result, thread, function_calls else: yield ''.join(full_response), thread, function_calls இவ்வாறான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான விளைவுகளைக் கண்டுபிடிப்பதற்கான வி if "history" not in st.session_state: st.session_state.history = \[\] if "thread" not in st.session_state: st.session_state.thread = None if "charts" not in st.session_state: st.session_state.charts = \[\] # Each entry: {"df": ..., "title": ..., "question": ...} if "chart_dataframes" not in st.session_state: st.session_state.chart_dataframes = \[\] if st.button("🧹 Clear Chat"): st.session_state.history = \[\] st.session_state.thread = None st.rerun() # Input box at the top user_input = st.chat_input("Ask me about your team's features...") # Example: team_selected = st.session_state.get("selected_team") if st.session_state.get("selected_team") and user_input: user_input = f"Team: {st.session_state.get('selected_team')}. {user_input}" # Preserve chat history when program or team is selected if user_input and not st.session_state.get("selected_team_changed", False): st.session_state.selected_team_changed = False if user_input: df = pd.DataFrame() full_response_holder = {"text": "","df": None} with st.chat_message("assistant"): response_container = st.empty() assistant_text = "" try: chat_index = len(st.session_state.history) response_gen = stream_response(user_input, st.session_state.thread) print("Response generator started",response_gen) async def process_stream(): async for update in response_gen: nonlocal_thread = st.session_state.thread if len(update) == 3: content, nonlocal_thread, function_calls = update full_response_holder\["text"\] = content if isinstance(content, list): data = json.loads(re.sub(r'\[\\x00-\\x1F\\x7F\]', '', content.replace("\`\`\`json", "").replace("\`\`\`",""))) df = pd.DataFrame(data) df.columns = df.columns.str.lower() print("\\n📊 Features Status Chart") st.subheader("📊 Features Status Chart") plot_bar_chart(df) st.subheader("📋 Detailed Features Table") st.dataframe(df) chart_df.columns = chart_df.columns.str.lower() full_response_holder\["df"\] = chart_df elif (re.sub(r'\[\\x00-\\x1F\\x7F\]', '', content.replace("\`\`\`json", "").replace("\`\`\`","").replace(" ",""))\[0\] =="\[" and re.sub(r'\[\\x00-\\x1F\\x7F\]', '', content.replace("\`\`\`json", "").replace("\`\`\`","").replace(" ",""))\[-1\] == "\]"): data = json.loads(re.sub(r'\[\\x00-\\x1F\\x7F\]', '', content.replace("\`\`\`json", "").replace("\`\`\`",""))) df = pd.DataFrame(data) df.columns = df.columns.str.lower() chart_df = pd.DataFrame(data) chart_df.columns = chart_df.columns.str.lower() full_response_holder\["df"\] = chart_df else: if function_calls: st.markdown("\\n".join(function_calls)) flagtext = 'text' st.session_state.thread = nonlocal_thread try: with st.spinner("🤖 AI is thinking..."): flagtext = None # Run the async function to process the stream asyncio.run(process_stream()) # Update history with the assistant's response if full_response_holder\["df"\] is not None and flagtext is None: st.session_state.chart_dataframes.append({ "question": user_input, "data": full_response_holder\["df"\], "type": "chart" }) elif full_response_holder\["text"\].strip(): # Text-type response st.session_state.history.append({ "user": user_input, "assistant": full_response_holder\["text"\], "type": "text" }) flagtext = None except Exception as e: error_msg = f"⚠️ Error: {e}" response_container.markdown(error_msg) if chat_index > 0 and "Error" in full_response_holder\["text"\]: # Remove the last message only if it was an error st.session_state.history.pop(chat_index) # Handle any exceptions that occur during the async call except Exception as e: full_response_holder\["text"\] = f"⚠️ Error: {e}" response_container.markdown(full_response_holder\["text"\]) chat_index = len(st.session_state.history) #for item in st.session_state.history\[:-1\]: for item in reversed(st.session_state.history): if item\["type"\] == "text": with st.chat_message("user"): st.markdown(item\["user"\]) with st.chat_message("assistant"): st.markdown(item\["assistant"\]) with right_col:st.title("Select Wiley திட்டம்") team_list = { "Program 1": \["Team 1", "Team 2", "Team 3"\], "Program 2": \["Team 4", "Team 5", "Team 6"\] } selected_program = st.selectbox("Select the Program:", \["No selection"\] + list(team_list.keys()), key="program_selectbox") selected_team = st.selectbox("Select the Agile Team:", \["No selection"\] + team_list.get(selected_program, \[\]), key="team_selectbox") st.session_state\["selected_team"\] = selected_team if selected_team != "No selection" else None if st.button("🧹 Clear All Charts"): st.session_state.chart_dataframes = \[\] chart_idx = 1 #if len(st.session_state.chart_dataframes) == 1: for idx, item in enumerate(st.session_state.chart_dataframes): #for idx, item in enumerate(st.session_state.chart_dataframes): st.markdown(f"\*\*Chart {idx + 1}: {item\['question'\]}\*\*") st.subheader("📊 Features Status Chart") plot_bar_chart(item\["data"\]) st.subheader("📋 Detailed Features Table") st.dataframe(item\["data"\]) chart_idx += 1 முடிவு உன் உதாரணமாக, அணிகள் Confluence பக்கங்கள் இருந்து திட்ட அம்சங்கள் மற்றும் epics பின்பற்ற உதவும். OpenAI GPT-4o உடன் team-specific Confluence page content scrape செய்யவும் ஒரு முதியவன் பாதாளங்களைத் தாண்டும் தன் மந்திரக்கோலால் சாய்த்தபடியிருக்கிறான் நாட்சத்திரங்களை. .............................................................................................................................................................................. இது எத்தனையாவது [...] Streamlit-based Program Management AI chatbot Semantic Kernel agents Playwright பதிவிறக்கம் : https://github.com/microsoft/ai-agents-for-beginners?tab=readme-ov-file Playwright documentation.