import streamlit as st import datetime import tempfile import black from streamlit_ace import st_ace from streamlit_extras.colored_header import colored_header from streamlit_extras.add_vertical_space import add_vertical_space import re from typing import Optional, Dict, List import ast from transformers import AutoTokenizer, AutoModelForCausalLM import torch # Initialize model and tokenizer globally @st.cache_resource def load_model_and_tokenizer(): tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-1.5B-Instruct") model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-1.5B-Instruct") if torch.cuda.is_available(): model = model.to("cuda") return model, tokenizer def clear_chat(): """Clear the chat history""" if 'messages' in st.session_state: st.session_state.messages = [] if 'current_session' in st.session_state: st.session_state.current_session = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") def handle_file_upload(): """Handle file upload functionality""" uploaded_file = st.file_uploader( "Upload a file", type=["txt", "pdf", "py", "json", "csv"], help="Upload a file to discuss with the AI" ) if uploaded_file is not None: file_contents = uploaded_file.read() if uploaded_file.type == "application/pdf": return f"Uploaded PDF: {uploaded_file.name}" else: try: return file_contents.decode() except UnicodeDecodeError: return "Binary file uploaded" return None def generate_response(prompt: str, temperature: float, max_tokens: int, system_prompt: str) -> str: """Generate response using the Qwen model""" model, tokenizer = load_model_and_tokenizer() # Format the input with system prompt full_prompt = f"System: {system_prompt}\n\nUser: {prompt}\n\nAssistant:" try: inputs = tokenizer(full_prompt, return_tensors="pt", padding=True) if torch.cuda.is_available(): inputs = {k: v.to("cuda") for k, v in inputs.items()} # Generate response outputs = model.generate( **inputs, max_new_tokens=max_tokens, temperature=temperature, do_sample=True, pad_token_id=tokenizer.pad_token_id ) response = tokenizer.decode(outputs[0], skip_special_tokens=True) # Extract assistant's response response = response.split("Assistant:")[-1].strip() return response except Exception as e: st.error(f"Error generating response: {str(e)}") return f"Error: {str(e)}" class CodeAnalyzer: @staticmethod def extract_code_blocks(text: str) -> List[str]: """Extract code blocks from markdown text""" code_blocks = re.findall(r'```(?:python)?\n(.*?)\n```', text, re.DOTALL) return code_blocks @staticmethod def is_code_complete(code: str) -> bool: """Check if the code block is syntactically complete""" try: ast.parse(code) return True except SyntaxError: return False @staticmethod def get_context(code: str) -> Dict: """Analyze code to extract context (variables, functions, classes)""" context = { 'variables': [], 'functions': [], 'classes': [] } try: tree = ast.parse(code) for node in ast.walk(tree): if isinstance(node, ast.Name) and isinstance(node.ctx, ast.Store): context['variables'].append(node.id) elif isinstance(node, ast.FunctionDef): context['functions'].append(node.name) elif isinstance(node, ast.ClassDef): context['classes'].append(node.name) except: pass return context class CodeCompletion: def __init__(self): pass def get_completion_suggestions(self, code: str, context: Dict) -> str: """Generate code completion suggestions based on context""" prompt = f"""Given the following code context: Code: {code} Context: Variables: {', '.join(context['variables'])} Functions: {', '.join(context['functions'])} Classes: {', '.join(context['classes'])} Please complete or continue this code in a natural way.""" return generate_response(prompt, 0.3, 500, "You are a Python coding assistant. Provide only code completion, no explanations.") def handle_code_continuation(incomplete_code: str) -> str: """Handle continuation of incomplete code""" prompt = f"""Complete the following Python code: {incomplete_code} Provide only the completion part that would make this code syntactically complete and logical.""" return generate_response(prompt, 0.3, 500, "You are a Python coding assistant. Complete the code naturally.") def format_code(code: str) -> str: """Format Python code using black""" try: return black.format_str(code, mode=black.FileMode()) except: return code def init_session_state(): """Initialize session state variables""" if "messages" not in st.session_state: st.session_state.messages = [] if "sessions" not in st.session_state: st.session_state.sessions = {} if "current_session" not in st.session_state: st.session_state.current_session = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") if "system_prompt" not in st.session_state: st.session_state.system_prompt = "You are a helpful AI assistant." if "saved_code_snippets" not in st.session_state: st.session_state.saved_code_snippets = [] if "code_context" not in st.session_state: st.session_state.code_context = {} if "current_code_block" not in st.session_state: st.session_state.current_code_block = None if "code_history" not in st.session_state: st.session_state.code_history = [] if "last_code_state" not in st.session_state: st.session_state.last_code_state = None def setup_page_config(): """Setup page configuration and styling""" st.set_page_config( page_title="Qwen Coder Chat", page_icon="🤖", layout="wide", initial_sidebar_state="expanded" ) st.markdown(""" """, unsafe_allow_html=True) def code_editor_section(): """Render the code editor section""" st.subheader("📝 Code Editor") code_content = st_ace( value=st.session_state.current_code_block or "", language="python", theme="monokai", key="code_editor", height=300, show_gutter=True, wrap=True, auto_update=True ) col1, col2 = st.columns(2) with col1: if st.button("Format Code"): st.session_state.current_code_block = format_code(code_content) with col2: if st.button("Get Completion Suggestions"): if code_content: code_analyzer = CodeAnalyzer() context = code_analyzer.get_context(code_content) completion = CodeCompletion() suggestions = completion.get_completion_suggestions(code_content, context) st.code(suggestions, language="python") def main(): """Main application logic""" setup_page_config() init_session_state() # Initialize model with st.spinner("Loading Qwen2.5-Coder model..."): load_model_and_tokenizer() # Sidebar configuration with st.sidebar: colored_header(label="Model Settings", description="Configure your chat parameters", color_name="blue-70") with st.expander("Advanced Settings", expanded=False): temperature = st.slider("Temperature", 0.0, 2.0, 0.7, 0.1) max_tokens = st.number_input("Max Tokens", 50, 4096, 2048) system_prompt = st.text_area("System Prompt", st.session_state.system_prompt) if st.button("Clear Chat"): clear_chat() st.title("🤖 Qwen2.5-Coder Chat") st.caption("Powered by Qwen2.5-Coder-32B-Instruct") # Main interface tabs tab1, tab2 = st.tabs(["Chat", "Code Editor"]) with tab1: # File upload section uploaded_content = handle_file_upload() if uploaded_content: st.session_state.messages.append({ "role": "user", "content": f"I've uploaded the following content:\n\n{uploaded_content}" }) # Display chat messages for message in st.session_state.messages: with st.chat_message(message["role"]): st.markdown(message["content"]) # Check for code blocks in the message code_blocks = CodeAnalyzer.extract_code_blocks(message["content"]) if code_blocks and message["role"] == "assistant": for code in code_blocks: if not CodeAnalyzer.is_code_complete(code): st.info("This code block appears to be incomplete. Would you like to complete it?") if st.button("Complete Code", key=f"complete_{len(code)}"): completion = handle_code_continuation(code) st.code(completion, language="python") # Chat input if prompt := st.chat_input("Message (use @ to attach a file)"): with st.chat_message("user"): st.markdown(prompt) st.session_state.messages.append({"role": "user", "content": prompt}) with st.chat_message("assistant"): with st.spinner("Thinking..."): response = generate_response(prompt, temperature, max_tokens, system_prompt) st.markdown(response) # Store code blocks in context code_blocks = CodeAnalyzer.extract_code_blocks(response) if code_blocks: st.session_state.last_code_state = code_blocks[-1] st.session_state.messages.append({"role": "assistant", "content": response}) with tab2: code_editor_section() # Footer add_vertical_space(2) st.markdown("---") st.markdown("Made with ❤️ using Streamlit and Qwen2.5-Coder") if __name__ == "__main__": main()