58 changed files with 8673 additions and 0 deletions
@ -0,0 +1,49 @@
|
||||
# Version control |
||||
.git |
||||
.gitignore |
||||
|
||||
# Python |
||||
__pycache__/ |
||||
*.py[cod] |
||||
*$py.class |
||||
*.so |
||||
.Python |
||||
.env |
||||
.venv |
||||
env/ |
||||
venv/ |
||||
ENV/ |
||||
*.egg-info/ |
||||
dist/ |
||||
build/ |
||||
|
||||
# Logs and databases |
||||
*.log |
||||
logs/ |
||||
*.sqlite |
||||
|
||||
# Downloads and temporary files |
||||
downloads/ |
||||
tmp/ |
||||
temp/ |
||||
|
||||
# IDE specific files |
||||
.idea/ |
||||
.vscode/ |
||||
*.swp |
||||
*.swo |
||||
|
||||
# Docker |
||||
Dockerfile |
||||
.dockerignore |
||||
|
||||
# Documentation |
||||
docs/ |
||||
*.md |
||||
LICENSE |
||||
|
||||
# Test files |
||||
tests/ |
||||
.pytest_cache/ |
||||
.coverage |
||||
htmlcov/ |
@ -0,0 +1,9 @@
|
||||
# API Keys Configuration |
||||
OPENAI_API_KEY=your-openai-key |
||||
ANTHROPIC_API_KEY=your-anthropic-key |
||||
GOOGLE_API_KEY=your-google-key |
||||
DEEPSEEK_API_KEY=your-deepseek-key |
||||
GROQ_API_KEY=your-groq-key |
||||
|
||||
# Server Configuration |
||||
PORT=7860 # Change this if port 7860 is already in use |
@ -0,0 +1,51 @@
|
||||
# CodeXchange AI CI/CD Workflows |
||||
|
||||
This directory contains GitHub Actions workflows for continuous integration and deployment of the CodeXchange AI application. |
||||
|
||||
## Workflow Overview |
||||
|
||||
1. **python-test.yml**: Runs Python tests, linting, and code coverage |
||||
2. **docker-build.yml**: Builds and validates Docker images with security scanning |
||||
3. **deploy-staging.yml**: Deploys to staging environment when changes are pushed to develop branch |
||||
4. **deploy-production.yml**: Deploys to production environment when a new release is published |
||||
|
||||
## Required GitHub Secrets |
||||
|
||||
To use these workflows, you need to set up the following secrets in your GitHub repository: |
||||
|
||||
1. Go to your GitHub repository |
||||
2. Navigate to Settings → Secrets and Variables → Actions |
||||
3. Add the following secrets: |
||||
|
||||
| Secret Name | Description | |
||||
|-------------|-------------| |
||||
| `DOCKERHUB_USERNAME` | Your Docker Hub username | |
||||
| `DOCKERHUB_TOKEN` | A personal access token from Docker Hub (not your password) | |
||||
|
||||
## Getting a Docker Hub Access Token |
||||
|
||||
1. Log in to [Docker Hub](https://hub.docker.com) |
||||
2. Go to Account Settings → Security |
||||
3. Create a new access token with appropriate permissions |
||||
4. Copy the token immediately (it's only shown once) |
||||
5. Add it as a GitHub secret |
||||
|
||||
## Customizing Deployment |
||||
|
||||
The deployment workflows currently include placeholder comments where you would add your specific deployment commands. Update these sections based on your hosting environment: |
||||
|
||||
- For VPS hosting: Add SSH-based deployment steps |
||||
- For cloud providers: Add their specific deployment APIs |
||||
- For Kubernetes: Add kubectl commands or Helm chart updates |
||||
|
||||
## Testing GitHub Actions Locally |
||||
|
||||
You can test GitHub Actions locally using [act](https://github.com/nektos/act): |
||||
|
||||
```bash |
||||
# Install act |
||||
brew install act |
||||
|
||||
# Run a specific workflow |
||||
act -j test -W .github/workflows/python-test.yml |
||||
``` |
@ -0,0 +1,48 @@
|
||||
name: Deploy to Production |
||||
|
||||
on: |
||||
release: |
||||
types: [published] |
||||
|
||||
jobs: |
||||
build-and-deploy: |
||||
runs-on: ubuntu-latest |
||||
environment: production |
||||
steps: |
||||
- name: Checkout code |
||||
uses: actions/checkout@v3 |
||||
|
||||
- name: Set up Docker Buildx |
||||
uses: docker/setup-buildx-action@v2 |
||||
|
||||
- name: Login to DockerHub |
||||
uses: docker/login-action@v2 |
||||
with: |
||||
username: ${{ secrets.DOCKERHUB_USERNAME }} |
||||
password: ${{ secrets.DOCKERHUB_TOKEN }} |
||||
|
||||
- name: Extract metadata |
||||
id: meta |
||||
uses: docker/metadata-action@v4 |
||||
with: |
||||
images: ${{ secrets.DOCKERHUB_USERNAME }}/codexchangeai |
||||
tags: | |
||||
type=semver,pattern={{version}} |
||||
type=semver,pattern={{major}}.{{minor}} |
||||
latest |
||||
|
||||
- name: Build and push Docker image |
||||
uses: docker/build-push-action@v4 |
||||
with: |
||||
context: . |
||||
push: true |
||||
tags: ${{ steps.meta.outputs.tags }} |
||||
labels: ${{ steps.meta.outputs.labels }} |
||||
cache-from: type=gha |
||||
cache-to: type=gha,mode=max |
||||
|
||||
# Production deployment steps would be added here |
||||
# This could involve: |
||||
# 1. Updating a Kubernetes deployment |
||||
# 2. SSH into production server and updating containers |
||||
# 3. Using cloud provider deployment APIs |
@ -0,0 +1,44 @@
|
||||
name: Deploy to Staging |
||||
|
||||
on: |
||||
push: |
||||
branches: [ develop ] |
||||
|
||||
jobs: |
||||
build-and-deploy: |
||||
runs-on: ubuntu-latest |
||||
steps: |
||||
- name: Checkout code |
||||
uses: actions/checkout@v3 |
||||
|
||||
- name: Set up Docker Buildx |
||||
uses: docker/setup-buildx-action@v2 |
||||
|
||||
- name: Login to DockerHub |
||||
uses: docker/login-action@v2 |
||||
with: |
||||
username: ${{ secrets.DOCKERHUB_USERNAME }} |
||||
password: ${{ secrets.DOCKERHUB_TOKEN }} |
||||
|
||||
- name: Extract metadata |
||||
id: meta |
||||
uses: docker/metadata-action@v4 |
||||
with: |
||||
images: ${{ secrets.DOCKERHUB_USERNAME }}/codexchangeai |
||||
tags: | |
||||
type=ref,event=branch |
||||
type=sha,format=short |
||||
|
||||
- name: Build and push Docker image |
||||
uses: docker/build-push-action@v4 |
||||
with: |
||||
context: . |
||||
push: true |
||||
tags: ${{ steps.meta.outputs.tags }} |
||||
labels: ${{ steps.meta.outputs.labels }} |
||||
cache-from: type=gha |
||||
cache-to: type=gha,mode=max |
||||
|
||||
# Here you would typically include steps to deploy to your staging environment |
||||
# For example, using SSH to connect to your server and pull the new image |
||||
# Or using a cloud provider's deployment API |
@ -0,0 +1,40 @@
|
||||
name: Python Tests |
||||
|
||||
on: |
||||
push: |
||||
branches: [ main, develop ] |
||||
pull_request: |
||||
branches: [ main, develop ] |
||||
|
||||
jobs: |
||||
test: |
||||
runs-on: ubuntu-latest |
||||
strategy: |
||||
matrix: |
||||
python-version: ['3.10', '3.11'] |
||||
|
||||
steps: |
||||
- uses: actions/checkout@v4 |
||||
|
||||
- name: Set up Python ${{ matrix.python-version }} |
||||
uses: actions/setup-python@v5 |
||||
with: |
||||
python-version: ${{ matrix.python-version }} |
||||
cache: 'pip' |
||||
|
||||
- name: Install dependencies |
||||
run: | |
||||
python -m pip install --upgrade pip |
||||
pip install flake8 pytest pytest-cov |
||||
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi |
||||
|
||||
- name: Lint with flake8 |
||||
run: | |
||||
# stop the build if there are Python syntax errors or undefined names |
||||
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics |
||||
# exit-zero treats all errors as warnings |
||||
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=120 --statistics |
||||
|
||||
- name: Test with pytest |
||||
run: | |
||||
pytest --cov=src/ai_code_converter tests/ |
@ -0,0 +1,66 @@
|
||||
# Environment variables |
||||
.env |
||||
|
||||
# Windsurf |
||||
.windsurfrules |
||||
|
||||
action_plan_save.md |
||||
action_plan.md |
||||
|
||||
ai_converter_v2.code-workspace |
||||
|
||||
# Python |
||||
__pycache__/ |
||||
*.py[cod] |
||||
*$py.class |
||||
*.so |
||||
.Python |
||||
env/ |
||||
build/ |
||||
develop-eggs/ |
||||
dist/ |
||||
downloads/ |
||||
eggs/ |
||||
.eggs/ |
||||
lib/ |
||||
lib64/ |
||||
parts/ |
||||
sdist/ |
||||
var/ |
||||
wheels/ |
||||
*.egg-info/ |
||||
.installed.cfg |
||||
*.egg |
||||
|
||||
# Logs |
||||
logs/ |
||||
*.log |
||||
|
||||
# IDE specific files |
||||
.idea/ |
||||
.vscode/ |
||||
*.swp |
||||
*.swo |
||||
|
||||
# OS specific files |
||||
.DS_Store |
||||
Thumbs.db |
||||
|
||||
# Virtual Environment |
||||
venv/ |
||||
.venv/ |
||||
ENV/ |
||||
|
||||
# Prometheus |
||||
/tmp/prometheus-multiproc/ |
||||
|
||||
# Local development |
||||
.env.local |
||||
.env.development.local |
||||
.env.test.local |
||||
.env.production.local |
||||
|
||||
# Temporary files |
||||
tmp/ |
||||
temp/ |
||||
*.tmp |
@ -0,0 +1,287 @@
|
||||
# Stage 1: Base development image |
||||
FROM ubuntu:22.04 AS builder |
||||
|
||||
# Add metadata about build environment |
||||
LABEL org.opencontainers.image.title="CodeXchange AI Builder" |
||||
LABEL org.opencontainers.image.description="Multi-platform build environment for CodeXchange AI" |
||||
|
||||
# Prevent interactive prompts during package installation |
||||
ENV DEBIAN_FRONTEND=noninteractive |
||||
|
||||
# Install essential build tools and compilers |
||||
RUN apt-get update && apt-get install -y --no-install-recommends \ |
||||
python3.10 \ |
||||
python3-pip \ |
||||
python3.10-venv \ |
||||
build-essential \ |
||||
gcc \ |
||||
g++ \ |
||||
openjdk-17-jdk \ |
||||
curl \ |
||||
ca-certificates \ |
||||
git \ |
||||
nodejs \ |
||||
npm \ |
||||
perl \ |
||||
lua5.3 \ |
||||
php \ |
||||
r-base \ |
||||
ruby \ |
||||
rustc \ |
||||
cargo \ |
||||
mono-complete \ |
||||
mono-devel \ |
||||
mono-mcs \ |
||||
sqlite3 \ |
||||
unzip \ |
||||
&& rm -rf /var/lib/apt/lists/* |
||||
|
||||
# Install TypeScript |
||||
RUN npm install -g typescript |
||||
|
||||
# Install Swift |
||||
RUN apt-get update && apt-get install -y --no-install-recommends \ |
||||
binutils \ |
||||
libc6-dev \ |
||||
libcurl4 \ |
||||
libedit2 \ |
||||
libgcc-9-dev \ |
||||
libpython3.10 \ |
||||
libsqlite3-0 \ |
||||
libstdc++-9-dev \ |
||||
libxml2 \ |
||||
libz3-dev \ |
||||
pkg-config \ |
||||
tzdata \ |
||||
zlib1g-dev \ |
||||
&& rm -rf /var/lib/apt/lists/* |
||||
|
||||
RUN arch=$(uname -m) && \ |
||||
if [ "$arch" = "x86_64" ]; then \ |
||||
SWIFT_URL="https://download.swift.org/swift-5.9.2-release/ubuntu2204/swift-5.9.2-RELEASE/swift-5.9.2-RELEASE-ubuntu22.04.tar.gz"; \ |
||||
elif [ "$arch" = "aarch64" ] || [ "$arch" = "arm64" ]; then \ |
||||
SWIFT_URL="https://download.swift.org/swift-5.9.2-release/ubuntu2204-aarch64/swift-5.9.2-RELEASE/swift-5.9.2-RELEASE-ubuntu22.04-aarch64.tar.gz"; \ |
||||
else \ |
||||
echo "Unsupported architecture for Swift: $arch"; \ |
||||
exit 1; \ |
||||
fi && \ |
||||
curl -fL $SWIFT_URL | tar xz -C /opt && \ |
||||
ln -s /opt/swift-5.9.2-RELEASE-ubuntu22.04*/usr/bin/swift /usr/local/bin/swift |
||||
|
||||
# Install Kotlin |
||||
RUN KOTLIN_VERSION=1.9.22 && \ |
||||
cd /tmp && \ |
||||
curl -LO "https://github.com/JetBrains/kotlin/releases/download/v${KOTLIN_VERSION}/kotlin-compiler-${KOTLIN_VERSION}.zip" && \ |
||||
unzip "kotlin-compiler-${KOTLIN_VERSION}.zip" -d /opt && \ |
||||
rm "kotlin-compiler-${KOTLIN_VERSION}.zip" && \ |
||||
ln -s "/opt/kotlinc/bin/kotlin" /usr/local/bin/kotlin && \ |
||||
ln -s "/opt/kotlinc/bin/kotlinc" /usr/local/bin/kotlinc |
||||
|
||||
# Install Julia based on architecture (with Windows WSL2 compatibility) |
||||
RUN arch=$(uname -m) && \ |
||||
echo "Detected architecture: $arch" && \ |
||||
if [ "$arch" = "aarch64" ] || [ "$arch" = "arm64" ]; then \ |
||||
echo "Installing ARM64 version of Julia" && \ |
||||
curl -fL https://julialang-s3.julialang.org/bin/linux/aarch64/1.9/julia-1.9.3-linux-aarch64.tar.gz | tar xz -C /opt && \ |
||||
ln -s /opt/julia-1.9.3/bin/julia /usr/local/bin/julia; \ |
||||
elif [ "$arch" = "x86_64" ] || [ "$arch" = "amd64" ]; then \ |
||||
echo "Installing x86_64 version of Julia" && \ |
||||
curl -fL https://julialang-s3.julialang.org/bin/linux/x64/1.9/julia-1.9.3-linux-x86_64.tar.gz | tar xz -C /opt && \ |
||||
ln -s /opt/julia-1.9.3/bin/julia /usr/local/bin/julia; \ |
||||
else \ |
||||
echo "WARNING: Unknown architecture $arch, defaulting to x86_64" && \ |
||||
curl -fL https://julialang-s3.julialang.org/bin/linux/x64/1.9/julia-1.9.3-linux-x86_64.tar.gz | tar xz -C /opt && \ |
||||
ln -s /opt/julia-1.9.3/bin/julia /usr/local/bin/julia; \ |
||||
fi |
||||
|
||||
# Install Go based on architecture (with Windows WSL2 compatibility) |
||||
RUN arch=$(uname -m) && \ |
||||
echo "Detected architecture for Go: $arch" && \ |
||||
if [ "$arch" = "aarch64" ] || [ "$arch" = "arm64" ]; then \ |
||||
echo "Installing ARM64 version of Go" && \ |
||||
curl -L https://go.dev/dl/go1.21.6.linux-arm64.tar.gz | tar -C /usr/local -xzf -; \ |
||||
elif [ "$arch" = "x86_64" ] || [ "$arch" = "amd64" ]; then \ |
||||
echo "Installing x86_64 version of Go" && \ |
||||
curl -L https://go.dev/dl/go1.21.6.linux-amd64.tar.gz | tar -C /usr/local -xzf -; \ |
||||
else \ |
||||
echo "WARNING: Unknown architecture $arch for Go, defaulting to x86_64" && \ |
||||
curl -L https://go.dev/dl/go1.21.6.linux-amd64.tar.gz | tar -C /usr/local -xzf -; \ |
||||
fi |
||||
ENV PATH="/usr/local/go/bin:${PATH}" |
||||
ENV GOPATH="/go" |
||||
ENV PATH="${GOPATH}/bin:${PATH}" |
||||
|
||||
# Create app user |
||||
RUN useradd -m -s /bin/bash app |
||||
WORKDIR /app |
||||
|
||||
# Copy project files |
||||
COPY --chown=app:app . . |
||||
|
||||
# Create and activate virtual environment |
||||
RUN python3 -m venv /app/.venv |
||||
ENV PATH="/app/.venv/bin:$PATH" |
||||
|
||||
# Install Python dependencies |
||||
RUN pip install --no-cache-dir -r requirements.txt |
||||
|
||||
# Stage 2: Runtime image |
||||
FROM ubuntu:22.04 |
||||
|
||||
# Add metadata about runtime environment |
||||
LABEL org.opencontainers.image.title="AI CodeXchange" |
||||
LABEL org.opencontainers.image.description="Multi-platform AI CodeXchange application" |
||||
LABEL org.opencontainers.image.version="1.0" |
||||
|
||||
# Create platform-specific label at build time |
||||
RUN echo "Building on $(uname -s) $(uname -m) architecture" > /platform-info.txt |
||||
LABEL org.opencontainers.image.platform="$(cat /platform-info.txt)" |
||||
|
||||
# Install runtime dependencies |
||||
ENV DEBIAN_FRONTEND=noninteractive |
||||
RUN apt-get update && apt-get install -y --no-install-recommends \ |
||||
python3.10 \ |
||||
python3-pip \ |
||||
gcc \ |
||||
g++ \ |
||||
openjdk-17-jdk \ |
||||
curl \ |
||||
nodejs \ |
||||
npm \ |
||||
perl \ |
||||
lua5.3 \ |
||||
php \ |
||||
r-base \ |
||||
ruby \ |
||||
rustc \ |
||||
cargo \ |
||||
mono-complete \ |
||||
mono-devel \ |
||||
mono-mcs \ |
||||
sqlite3 \ |
||||
unzip \ |
||||
&& rm -rf /var/lib/apt/lists/* |
||||
|
||||
# Install TypeScript |
||||
RUN npm install -g typescript |
||||
|
||||
# Install Swift |
||||
RUN apt-get update && apt-get install -y --no-install-recommends \ |
||||
binutils \ |
||||
libc6-dev \ |
||||
libcurl4 \ |
||||
libedit2 \ |
||||
libgcc-9-dev \ |
||||
libpython3.10 \ |
||||
libsqlite3-0 \ |
||||
libstdc++-9-dev \ |
||||
libxml2 \ |
||||
libz3-dev \ |
||||
pkg-config \ |
||||
tzdata \ |
||||
zlib1g-dev \ |
||||
&& rm -rf /var/lib/apt/lists/* |
||||
|
||||
RUN arch=$(uname -m) && \ |
||||
if [ "$arch" = "x86_64" ]; then \ |
||||
SWIFT_URL="https://download.swift.org/swift-5.9.2-release/ubuntu2204/swift-5.9.2-RELEASE/swift-5.9.2-RELEASE-ubuntu22.04.tar.gz"; \ |
||||
elif [ "$arch" = "aarch64" ] || [ "$arch" = "arm64" ]; then \ |
||||
SWIFT_URL="https://download.swift.org/swift-5.9.2-release/ubuntu2204-aarch64/swift-5.9.2-RELEASE/swift-5.9.2-RELEASE-ubuntu22.04-aarch64.tar.gz"; \ |
||||
else \ |
||||
echo "Unsupported architecture for Swift: $arch"; \ |
||||
exit 1; \ |
||||
fi && \ |
||||
curl -fL $SWIFT_URL | tar xz -C /opt && \ |
||||
ln -s /opt/swift-5.9.2-RELEASE-ubuntu22.04*/usr/bin/swift /usr/local/bin/swift |
||||
|
||||
# Install Kotlin |
||||
RUN KOTLIN_VERSION=1.9.22 && \ |
||||
cd /tmp && \ |
||||
curl -LO "https://github.com/JetBrains/kotlin/releases/download/v${KOTLIN_VERSION}/kotlin-compiler-${KOTLIN_VERSION}.zip" && \ |
||||
unzip "kotlin-compiler-${KOTLIN_VERSION}.zip" -d /opt && \ |
||||
rm "kotlin-compiler-${KOTLIN_VERSION}.zip" && \ |
||||
ln -s "/opt/kotlinc/bin/kotlin" /usr/local/bin/kotlin && \ |
||||
ln -s "/opt/kotlinc/bin/kotlinc" /usr/local/bin/kotlinc |
||||
|
||||
# Install Julia based on architecture (with Windows WSL2 compatibility) |
||||
RUN arch=$(uname -m) && \ |
||||
echo "Detected architecture: $arch" && \ |
||||
if [ "$arch" = "aarch64" ] || [ "$arch" = "arm64" ]; then \ |
||||
echo "Installing ARM64 version of Julia" && \ |
||||
curl -fL https://julialang-s3.julialang.org/bin/linux/aarch64/1.9/julia-1.9.3-linux-aarch64.tar.gz | tar xz -C /opt && \ |
||||
ln -s /opt/julia-1.9.3/bin/julia /usr/local/bin/julia; \ |
||||
elif [ "$arch" = "x86_64" ] || [ "$arch" = "amd64" ]; then \ |
||||
echo "Installing x86_64 version of Julia" && \ |
||||
curl -fL https://julialang-s3.julialang.org/bin/linux/x64/1.9/julia-1.9.3-linux-x86_64.tar.gz | tar xz -C /opt && \ |
||||
ln -s /opt/julia-1.9.3/bin/julia /usr/local/bin/julia; \ |
||||
else \ |
||||
echo "WARNING: Unknown architecture $arch, defaulting to x86_64" && \ |
||||
curl -fL https://julialang-s3.julialang.org/bin/linux/x64/1.9/julia-1.9.3-linux-x86_64.tar.gz | tar xz -C /opt && \ |
||||
ln -s /opt/julia-1.9.3/bin/julia /usr/local/bin/julia; \ |
||||
fi |
||||
|
||||
# Install Go runtime |
||||
COPY --from=builder /usr/local/go /usr/local/go |
||||
ENV PATH="/usr/local/go/bin:${PATH}" |
||||
ENV GOPATH="/go" |
||||
ENV PATH="${GOPATH}/bin:${PATH}" |
||||
|
||||
# Create app user |
||||
RUN useradd -m -s /bin/bash app |
||||
WORKDIR /app |
||||
|
||||
# Copy virtual environment and application files from builder |
||||
COPY --from=builder --chown=app:app /app/.venv /app/.venv |
||||
COPY --from=builder --chown=app:app /app /app |
||||
|
||||
# Set environment variables |
||||
ENV PATH="/app/.venv/bin:$PATH" \ |
||||
PYTHONPATH="/app/src" \ |
||||
PYTHONUNBUFFERED=1 \ |
||||
GRADIO_SERVER_NAME=0.0.0.0 \ |
||||
GRADIO_SERVER_PORT=7860 |
||||
|
||||
# Create necessary directories with correct permissions |
||||
RUN mkdir -p /app/logs /app/downloads \ |
||||
&& chown -R app:app /app/logs /app/downloads |
||||
|
||||
# Verify installations with comprehensive platform information |
||||
RUN echo "======= PLATFORM & LANGUAGE VERIFICATION =======" && \ |
||||
echo "OS: $(uname -s)" && \ |
||||
echo "Architecture: $(uname -m)" && \ |
||||
echo "Kernel: $(uname -r)" && \ |
||||
echo "Host: $(uname -n)" && \ |
||||
echo "\n=== Language Installations ===" && \ |
||||
echo "Node.js: $(node --version 2>/dev/null || echo 'NOT VERIFIED')" && \ |
||||
echo "TypeScript: $(tsc --version 2>/dev/null || echo 'NOT VERIFIED')" && \ |
||||
echo "Java: $(java -version 2>&1 | head -n 1 || echo 'NOT VERIFIED')" && \ |
||||
echo "Julia: $(julia --version 2>/dev/null || echo 'NOT VERIFIED')" && \ |
||||
echo "Go: $(go version 2>/dev/null || echo 'NOT VERIFIED')" && \ |
||||
echo "Python: $(python3 --version 2>/dev/null || echo 'NOT VERIFIED')" && \ |
||||
echo "Perl: $(perl -v 2>/dev/null | head -n 2 || echo 'NOT VERIFIED')" && \ |
||||
echo "Lua: $(lua5.3 -v 2>/dev/null || echo 'NOT VERIFIED')" && \ |
||||
echo "PHP: $(php --version 2>/dev/null | head -n 1 || echo 'NOT VERIFIED')" && \ |
||||
echo "R: $(R --version 2>/dev/null | head -n 1 || echo 'NOT VERIFIED')" && \ |
||||
echo "Ruby: $(ruby --version 2>/dev/null || echo 'NOT VERIFIED')" && \ |
||||
echo "Rust: $(rustc --version 2>/dev/null || echo 'NOT VERIFIED')" && \ |
||||
echo "C#/Mono: $(mono-csc --version 2>/dev/null || echo 'NOT VERIFIED')" && \ |
||||
echo "SQLite: $(sqlite3 --version 2>/dev/null || echo 'NOT VERIFIED')" && \ |
||||
echo "Kotlin: $(kotlinc -version 2>&1 || echo 'NOT VERIFIED')" && \ |
||||
echo "C++: $(g++ --version 2>/dev/null | head -n 1 || echo 'NOT VERIFIED')" && \ |
||||
echo "\n=== Environment Variables ===" && \ |
||||
echo "PATH: $PATH" && \ |
||||
echo "======= VERIFICATION COMPLETE =======" |
||||
|
||||
# Switch to non-root user |
||||
USER app |
||||
|
||||
# Expose port |
||||
EXPOSE 7860 |
||||
|
||||
# Health check |
||||
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \ |
||||
CMD curl -f http://localhost:7860/healthz || exit 1 |
||||
|
||||
# Set entrypoint and default command |
||||
ENTRYPOINT ["python3"] |
||||
CMD ["run.py"] |
@ -0,0 +1,21 @@
|
||||
MIT License |
||||
|
||||
Copyright (c) 2025 Blaise Alako |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
@ -0,0 +1,39 @@
|
||||
.PHONY: install run dev docker-build docker-run test clean |
||||
|
||||
# Install project dependencies
|
||||
install: |
||||
pip install -r requirements.txt
|
||||
|
||||
# Run the application
|
||||
run: |
||||
python run.py
|
||||
|
||||
# Run with development settings (enables hot-reloading)
|
||||
dev: |
||||
PYTHON_ENV=development python run.py
|
||||
|
||||
# Build Docker container
|
||||
docker-build: |
||||
docker build -t ai-code-converter .
|
||||
|
||||
# Run Docker container
|
||||
docker-run: |
||||
docker run -p 7860:7860 --env-file .env ai-code-converter
|
||||
|
||||
# Run tests
|
||||
test: |
||||
python -m pytest tests/
|
||||
|
||||
# Clean Python cache and build artifacts
|
||||
clean: |
||||
find . -type d -name "__pycache__" -exec rm -rf {} +
|
||||
find . -type f -name "*.pyc" -delete
|
||||
find . -type f -name "*.pyo" -delete
|
||||
find . -type f -name "*.pyd" -delete
|
||||
find . -type d -name ".pytest_cache" -exec rm -rf {} +
|
||||
find . -type d -name "build" -exec rm -rf {} +
|
||||
find . -type d -name "dist" -exec rm -rf {} +
|
||||
|
||||
# Generate documentation diagrams
|
||||
docs-diagrams: |
||||
cd docs && python -c "import mermaid_generator; mermaid_generator.generate_diagrams()"
|
@ -0,0 +1,191 @@
|
||||
# CodeXchange AI |
||||
|
||||
[](https://python.org) |
||||
[](LICENSE) |
||||
[](https://github.com/alakob/ai_code_converter/actions/workflows/python-test.yml) |
||||
|
||||
A powerful tool for converting and executing code between different programming languages using AI models. |
||||
|
||||
## Overview |
||||
|
||||
CodeXchangeAI is a Python application that leverages various AI models to translate code between programming languages while maintaining functionality and idiomatic patterns. |
||||
|
||||
### Key Features |
||||
|
||||
- Multi-language code conversion |
||||
- Real-time code execution |
||||
- Multiple AI model support (GPT, Claude, DeepSeek, GROQ, Gemini) |
||||
- File upload/download functionality |
||||
- Syntax highlighting |
||||
- Detailed logging system |
||||
- Docker support |
||||
|
||||
## Quick Start |
||||
|
||||
```bash |
||||
# Clone the repository |
||||
git clone git@github.com:alakob/ai_code_converter.git |
||||
cd ai_code_converter |
||||
|
||||
# Configure environment |
||||
cp .env.example .env |
||||
# Edit .env with your API keys |
||||
|
||||
``` |
||||
|
||||
### Using the Docker Wrapper Script (Recommended) |
||||
|
||||
For a more convenient way to run the application with Docker, you can use the provided wrapper script: |
||||
|
||||
```bash |
||||
# Make the script executable |
||||
chmod +x run-docker.sh |
||||
|
||||
# Run the application |
||||
./run-docker.sh # Build and run normally |
||||
./run-docker.sh -d # Run in detached mode |
||||
./run-docker.sh -p 8080 # Run on port 8080 |
||||
./run-docker.sh -s # Stop the container |
||||
./run-docker.sh -h # Show help message |
||||
``` |
||||
|
||||
## CI/CD Pipeline |
||||
|
||||
CodeXchange AI uses GitHub Actions for continuous integration and deployment. The pipeline includes: |
||||
|
||||
### Automated Testing |
||||
- Runs Python tests on multiple Python versions (3.9, 3.10, 3.11) |
||||
- Performs code linting and style checks |
||||
- Generates test coverage reports |
||||
|
||||
### Docker Image Validation |
||||
- Builds the Docker image to verify Dockerfile integrity |
||||
- Performs vulnerability scanning with Trivy |
||||
- Validates container startup and dependencies |
||||
|
||||
### Deployment Automation |
||||
- Automatically deploys to staging environment when changes are pushed to develop branch |
||||
- Creates production releases with semantic versioning |
||||
- Publishes Docker images to Docker Hub |
||||
|
||||
### Setting Up for Development |
||||
|
||||
To use the CI/CD pipeline in your fork, you'll need to add these secrets to your GitHub repository: |
||||
|
||||
1. `DOCKERHUB_USERNAME`: Your Docker Hub username |
||||
2. `DOCKERHUB_TOKEN`: A Docker Hub access token (not your password) |
||||
|
||||
See the [CI/CD documentation](docs/ci_cd_pipeline.md) for detailed setup instructions. |
||||
|
||||
The wrapper script provides several options for customizing the Docker deployment: |
||||
|
||||
```bash |
||||
Usage: ./run-docker.sh [OPTIONS] |
||||
|
||||
Options: |
||||
-b, --build Build the Docker image without running the container |
||||
-d, --detach Run container in detached mode (background) |
||||
-e, --env FILE Specify an environment file (default: .env) |
||||
-p, --port PORT Specify the port to expose (default: 7860) |
||||
-l, --logs Follow the container logs after starting |
||||
-s, --stop Stop the running container |
||||
-r, --restart Restart the container |
||||
-D, --down Stop and remove the container |
||||
-k, --keys Check for API keys and show setup instructions if missing |
||||
-h, --help Display this help message |
||||
-v, --version Display script version |
||||
``` |
||||
|
||||
Examples: |
||||
- Run on a different port: `./run-docker.sh -p 8080` |
||||
- Run in background: `./run-docker.sh -d` |
||||
- Stop the application: `./run-docker.sh -s` |
||||
- View logs: `./run-docker.sh -l` |
||||
|
||||
The application will be available at `http://localhost:7860` |
||||
|
||||
### Manual Installation |
||||
|
||||
```bash |
||||
# Create and activate virtual environment |
||||
python -m venv .venv |
||||
source .venv/bin/activate # On Windows: .venv\Scripts\activate |
||||
|
||||
# Install dependencies |
||||
pip install -r requirements.txt |
||||
|
||||
# Configure environment |
||||
cp .env.example .env |
||||
# Edit .env with your API keys |
||||
|
||||
# Run the application |
||||
python run.py |
||||
``` |
||||
|
||||
### Using Make Commands |
||||
|
||||
The project includes a Makefile with useful commands to streamline development: |
||||
|
||||
```bash |
||||
# Install dependencies |
||||
make install |
||||
|
||||
# Run the application |
||||
make run |
||||
|
||||
# Run with development settings (hot-reloading) |
||||
make dev |
||||
|
||||
# Build Docker container |
||||
make docker-build |
||||
|
||||
# Run Docker container |
||||
make docker-run |
||||
|
||||
# Or use the Docker wrapper script for more options |
||||
./run-docker.sh |
||||
|
||||
# Run tests |
||||
make test |
||||
|
||||
# Clean Python cache and build artifacts |
||||
make clean |
||||
``` |
||||
|
||||
## Basic Usage |
||||
|
||||
1. Select source and target programming languages |
||||
2. Enter or upload source code |
||||
3. Choose AI model and temperature |
||||
4. Click "Convert" to translate the code |
||||
5. Use "Run" buttons to execute original or converted code |
||||
6. Download the results including compiled binaries (for compiled languages) |
||||
|
||||
## Supported Languages |
||||
|
||||
Currently supports 17 programming languages including Python, JavaScript, Java, C++, Julia, Go, Ruby, Swift, Rust, C#, TypeScript, R, Perl, Lua, PHP, Kotlin, and SQL. |
||||
|
||||
See [Supported Languages](./docs/languages.md) for detailed information on each language. |
||||
|
||||
## Documentation |
||||
|
||||
For detailed documentation, please refer to the [docs](./docs) directory: |
||||
|
||||
- [Supported Languages](./docs/languages.md) - Details on all supported programming languages |
||||
- [Configuration Guide](./docs/configuration.md) - How to configure the application |
||||
- [Development Guide](./docs/development.md) - Guide for developers extending the application |
||||
- [Contributing Guidelines](./docs/contributing.md) - How to contribute to the project |
||||
- [Project Structure](./docs/project_structure.md) - Overview of the codebase architecture |
||||
- [Architecture Diagram](./docs/architecture_diagram.md) - Visual representation of the application architecture |
||||
|
||||
## License |
||||
|
||||
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. |
||||
|
||||
## Acknowledgments |
||||
|
||||
- OpenAI for GPT models |
||||
- Anthropic for Claude |
||||
- Google for Gemini |
||||
- DeepSeek and GROQ for their AI models |
||||
- The Gradio team for the web interface framework |
@ -0,0 +1,23 @@
|
||||
|
||||
services: |
||||
ai_code_converter: |
||||
build: . |
||||
ports: |
||||
- "${PORT:-7860}:7860" |
||||
volumes: |
||||
- ./logs:/app/logs |
||||
- ./downloads:/app/downloads |
||||
environment: |
||||
- OPENAI_API_KEY=${OPENAI_API_KEY} |
||||
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} |
||||
- GOOGLE_API_KEY=${GOOGLE_API_KEY} |
||||
- DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY} |
||||
- GROQ_API_KEY=${GROQ_API_KEY} |
||||
- PORT=${PORT:-7860} |
||||
healthcheck: |
||||
test: ["CMD", "curl", "-f", "http://localhost:7860/healthz"] |
||||
interval: 30s |
||||
timeout: 30s |
||||
retries: 3 |
||||
start_period: 5s |
||||
restart: unless-stopped |
@ -0,0 +1,12 @@
|
||||
# CodeXchange AI Documentation |
||||
|
||||
This directory contains comprehensive documentation for the CodeXchange AI project. |
||||
|
||||
## Contents |
||||
|
||||
- [Supported Languages](./languages.md) - Details on all supported programming languages |
||||
- [Configuration Guide](./configuration.md) - How to configure the application |
||||
- [Development Guide](./development.md) - Guide for developers extending the application |
||||
- [Contributing Guidelines](./contributing.md) - How to contribute to the project |
||||
- [Project Structure](./project_structure.md) - Overview of the codebase architecture |
||||
- [Architecture Diagram](./architecture_diagram.md) - Visual representation of the application architecture and component relationships |
@ -0,0 +1,297 @@
|
||||
# Architecture Diagram |
||||
|
||||
This diagram illustrates the architecture and component relationships of the CodeXchange AI application. |
||||
|
||||
> **Note:** For detailed information about the CI/CD pipeline, see [CI/CD Pipeline Architecture](ci_cd_pipeline.md). |
||||
|
||||
## Application Flow Diagram |
||||
|
||||
```mermaid |
||||
graph TD |
||||
%% Main Entry Points |
||||
A[run.py] --> B[main.py] |
||||
B --> C[CodeConverterApp] |
||||
|
||||
%% Core Components |
||||
C --> D[Gradio UI] |
||||
C --> E[AIModelStreamer] |
||||
C --> F[CodeExecutor] |
||||
C --> G[LanguageDetector] |
||||
C --> H[FileHandler] |
||||
|
||||
%% AI Models |
||||
E --> I[OpenAI GPT] |
||||
E --> J[Anthropic Claude] |
||||
E --> K[Google Gemini] |
||||
E --> L[DeepSeek] |
||||
E --> M[GROQ] |
||||
|
||||
%% Language Processing |
||||
G --> N[Language Validation] |
||||
F --> O[Code Execution] |
||||
|
||||
%% File Operations |
||||
H --> P[File Upload/Download] |
||||
H --> Q[ZIP Creation] |
||||
|
||||
%% Configuration |
||||
R[config.py] --> C |
||||
R --> E |
||||
R --> F |
||||
|
||||
%% Template |
||||
S[template.j2] --> C |
||||
|
||||
%% User Interactions |
||||
D --> T[Code Input] |
||||
D --> U[Language Selection] |
||||
D --> V[Model Selection] |
||||
D --> W[Code Conversion] |
||||
D --> X[Code Execution] |
||||
D --> Y[File Download] |
||||
|
||||
%% Logging |
||||
Z[logger.py] --> C |
||||
Z --> E |
||||
Z --> F |
||||
Z --> G |
||||
Z --> H |
||||
|
||||
%% Styling |
||||
style A fill:#f9d77e,stroke:#333,stroke-width:2px |
||||
style B fill:#f9d77e,stroke:#333,stroke-width:2px |
||||
style C fill:#f9d77e,stroke:#333,stroke-width:2px |
||||
style D fill:#a8d5ba,stroke:#333,stroke-width:2px |
||||
style E fill:#a8d5ba,stroke:#333,stroke-width:2px |
||||
style F fill:#a8d5ba,stroke:#333,stroke-width:2px |
||||
style G fill:#a8d5ba,stroke:#333,stroke-width:2px |
||||
style H fill:#a8d5ba,stroke:#333,stroke-width:2px |
||||
style I fill:#ffb6c1,stroke:#333,stroke-width:2px |
||||
style J fill:#ffb6c1,stroke:#333,stroke-width:2px |
||||
style K fill:#ffb6c1,stroke:#333,stroke-width:2px |
||||
style L fill:#ffb6c1,stroke:#333,stroke-width:2px |
||||
style M fill:#ffb6c1,stroke:#333,stroke-width:2px |
||||
style R fill:#d0e0e3,stroke:#333,stroke-width:2px |
||||
style S fill:#d0e0e3,stroke:#333,stroke-width:2px |
||||
style Z fill:#d0e0e3,stroke:#333,stroke-width:2px |
||||
``` |
||||
|
||||
## Component Interaction Sequence |
||||
|
||||
```mermaid |
||||
sequenceDiagram |
||||
participant User |
||||
participant UI as Gradio UI |
||||
participant App as CodeConverterApp |
||||
participant AI as AIModelStreamer |
||||
participant Executor as CodeExecutor |
||||
participant Detector as LanguageDetector |
||||
participant Files as FileHandler |
||||
|
||||
User->>UI: Enter Source Code |
||||
User->>UI: Select Source Language |
||||
User->>UI: Select Target Language |
||||
User->>UI: Select AI Model |
||||
User->>UI: Click Convert |
||||
|
||||
UI->>App: Request Code Conversion |
||||
App->>Detector: Validate Source Language |
||||
Detector-->>App: Validation Result |
||||
|
||||
App->>App: Create Prompt from Template |
||||
App->>AI: Send Prompt to Selected Model |
||||
AI-->>App: Stream Converted Code |
||||
App-->>UI: Display Converted Code |
||||
|
||||
User->>UI: Click Run Original |
||||
UI->>App: Request Code Execution |
||||
App->>Executor: Execute Original Code |
||||
Executor-->>App: Execution Result |
||||
App-->>UI: Display Execution Result |
||||
|
||||
User->>UI: Click Run Converted |
||||
UI->>App: Request Code Execution |
||||
App->>Executor: Execute Converted Code |
||||
Executor-->>App: Execution Result |
||||
App-->>UI: Display Execution Result |
||||
|
||||
User->>UI: Click Download |
||||
UI->>App: Request Download |
||||
App->>Files: Create ZIP with Files |
||||
Files-->>App: ZIP File |
||||
App-->>UI: Provide Download Link |
||||
UI-->>User: Download Files |
||||
``` |
||||
|
||||
## Class Diagram |
||||
|
||||
```mermaid |
||||
classDiagram |
||||
class CodeConverterApp { |
||||
-AIModelStreamer ai_streamer |
||||
-CodeExecutor executor |
||||
-LanguageDetector detector |
||||
-FileHandler file_handler |
||||
-GradioInterface demo |
||||
+__init__() |
||||
+_setup_environment() |
||||
+_initialize_components() |
||||
+_create_gradio_interface() |
||||
+convert_code() |
||||
+execute_code() |
||||
+download_files() |
||||
+run() |
||||
} |
||||
|
||||
class AIModelStreamer { |
||||
-OpenAI openai |
||||
-Anthropic claude |
||||
-OpenAI deepseek |
||||
-OpenAI groq |
||||
-GenerativeModel gemini |
||||
+__init__() |
||||
+stream_gpt() |
||||
+stream_claude() |
||||
+stream_gemini() |
||||
+stream_deepseek() |
||||
+stream_groq() |
||||
+stream_completion() |
||||
} |
||||
|
||||
class CodeExecutor { |
||||
-dict executors |
||||
+__init__() |
||||
+execute() |
||||
+execute_python() |
||||
+execute_javascript() |
||||
+execute_java() |
||||
+execute_cpp() |
||||
+execute_julia() |
||||
+execute_go() |
||||
+execute_ruby() |
||||
+execute_swift() |
||||
+execute_rust() |
||||
+execute_csharp() |
||||
+execute_typescript() |
||||
+execute_r() |
||||
+execute_perl() |
||||
+execute_lua() |
||||
+execute_php() |
||||
+execute_kotlin() |
||||
+execute_sql() |
||||
} |
||||
|
||||
class LanguageDetector { |
||||
+detect_python() |
||||
+detect_javascript() |
||||
+detect_java() |
||||
+detect_cpp() |
||||
+detect_julia() |
||||
+detect_go() |
||||
+detect_ruby() |
||||
+detect_swift() |
||||
+detect_rust() |
||||
+detect_csharp() |
||||
+detect_typescript() |
||||
+detect_r() |
||||
+detect_perl() |
||||
+detect_lua() |
||||
+detect_php() |
||||
+detect_kotlin() |
||||
+detect_sql() |
||||
+validate_language() |
||||
} |
||||
|
||||
class FileHandler { |
||||
+create_readme() |
||||
+create_zip() |
||||
+handle_upload() |
||||
+handle_download() |
||||
} |
||||
|
||||
CodeConverterApp --> AIModelStreamer |
||||
CodeConverterApp --> CodeExecutor |
||||
CodeConverterApp --> LanguageDetector |
||||
CodeConverterApp --> FileHandler |
||||
``` |
||||
|
||||
## Supported Languages and Models |
||||
|
||||
```mermaid |
||||
graph LR |
||||
subgraph "AI Models" |
||||
M1[GPT] |
||||
M2[Claude] |
||||
M3[Gemini] |
||||
M4[DeepSeek] |
||||
M5[GROQ] |
||||
end |
||||
|
||||
subgraph "Supported Languages" |
||||
L1[Python] |
||||
L2[JavaScript] |
||||
L3[Java] |
||||
L4[C++] |
||||
L5[Julia] |
||||
L6[Go] |
||||
L7[Ruby] |
||||
L8[Swift] |
||||
L9[Rust] |
||||
L10[C#] |
||||
L11[TypeScript] |
||||
L12[R] |
||||
L13[Perl] |
||||
L14[Lua] |
||||
L15[PHP] |
||||
L16[Kotlin] |
||||
L17[SQL] |
||||
end |
||||
|
||||
subgraph "Fully Implemented" |
||||
L1 |
||||
L2 |
||||
L3 |
||||
L4 |
||||
L5 |
||||
L6 |
||||
end |
||||
|
||||
subgraph "Template Ready" |
||||
L7 |
||||
L8 |
||||
L9 |
||||
L10 |
||||
L11 |
||||
L12 |
||||
L13 |
||||
L14 |
||||
L15 |
||||
L16 |
||||
L17 |
||||
end |
||||
|
||||
style M1 fill:#ffb6c1,stroke:#333,stroke-width:2px |
||||
style M2 fill:#ffb6c1,stroke:#333,stroke-width:2px |
||||
style M3 fill:#ffb6c1,stroke:#333,stroke-width:2px |
||||
style M4 fill:#ffb6c1,stroke:#333,stroke-width:2px |
||||
style M5 fill:#ffb6c1,stroke:#333,stroke-width:2px |
||||
|
||||
style L1 fill:#a8d5ba,stroke:#333,stroke-width:2px |
||||
style L2 fill:#a8d5ba,stroke:#333,stroke-width:2px |
||||
style L3 fill:#a8d5ba,stroke:#333,stroke-width:2px |
||||
style L4 fill:#a8d5ba,stroke:#333,stroke-width:2px |
||||
style L5 fill:#a8d5ba,stroke:#333,stroke-width:2px |
||||
style L6 fill:#a8d5ba,stroke:#333,stroke-width:2px |
||||
|
||||
style L7 fill:#d0e0e3,stroke:#333,stroke-width:2px |
||||
style L8 fill:#d0e0e3,stroke:#333,stroke-width:2px |
||||
style L9 fill:#d0e0e3,stroke:#333,stroke-width:2px |
||||
style L10 fill:#d0e0e3,stroke:#333,stroke-width:2px |
||||
style L11 fill:#d0e0e3,stroke:#333,stroke-width:2px |
||||
style L12 fill:#d0e0e3,stroke:#333,stroke-width:2px |
||||
style L13 fill:#d0e0e3,stroke:#333,stroke-width:2px |
||||
style L14 fill:#d0e0e3,stroke:#333,stroke-width:2px |
||||
style L15 fill:#d0e0e3,stroke:#333,stroke-width:2px |
||||
style L16 fill:#d0e0e3,stroke:#333,stroke-width:2px |
||||
style L17 fill:#d0e0e3,stroke:#333,stroke-width:2px |
||||
``` |
@ -0,0 +1,86 @@
|
||||
# CI/CD Pipeline Architecture |
||||
|
||||
This document outlines the continuous integration and continuous deployment (CI/CD) pipeline implemented for CodeXchange AI. |
||||
|
||||
## Pipeline Overview |
||||
|
||||
The CI/CD pipeline automates testing, building, and deployment processes using GitHub Actions. It follows a trunk-based development model with protection for the main branch. |
||||
|
||||
```mermaid |
||||
graph TD |
||||
Code[Developer Code] --> PR[Pull Request] |
||||
PR --> Tests[Automated Tests] |
||||
Tests --> DockerBuild[Docker Build & Validation] |
||||
DockerBuild --> |On merge to develop| StagingDeploy[Staging Deployment] |
||||
StagingDeploy --> |On release creation| ProdDeploy[Production Deployment] |
||||
|
||||
%% Pipeline Components |
||||
subgraph "CI Pipeline" |
||||
Tests |
||||
DockerBuild |
||||
end |
||||
|
||||
subgraph "CD Pipeline" |
||||
StagingDeploy |
||||
ProdDeploy |
||||
end |
||||
``` |
||||
|
||||
## Workflow Components |
||||
|
||||
### 1. Python Testing Workflow |
||||
|
||||
The testing workflow (`python-test.yml`) performs: |
||||
- Syntax validation and linting with flake8 |
||||
- Unit and integration tests with pytest |
||||
- Code coverage analysis |
||||
- Matrix testing across Python 3.9, 3.10, and 3.11 |
||||
|
||||
### 2. Docker Build Workflow |
||||
|
||||
The Docker workflow (`docker-build.yml`) performs: |
||||
- Dockerfile validation |
||||
- Container image building |
||||
- Security scanning with Trivy |
||||
- Vulnerability assessment |
||||
|
||||
### 3. Staging Deployment |
||||
|
||||
The staging workflow (`deploy-staging.yml`): |
||||
- Triggered on pushes to the develop branch |
||||
- Builds and tags Docker images with branch name and commit hash |
||||
- Pushes images to Docker Hub |
||||
- Deploys to the staging environment |
||||
|
||||
### 4. Production Deployment |
||||
|
||||
The production workflow (`deploy-production.yml`): |
||||
- Triggered on release publication |
||||
- Builds and tags Docker images with semantic version |
||||
- Pushes images to Docker Hub with version tags |
||||
- Deploys to the production environment with approval gate |
||||
|
||||
## Security Considerations |
||||
|
||||
- Sensitive credentials stored as GitHub Secrets |
||||
- Docker Hub authentication using access tokens, not passwords |
||||
- Security scanning for both code and container images |
||||
- Protected branches requiring CI checks to pass before merging |
||||
|
||||
## Development Workflow |
||||
|
||||
1. Create feature branch from develop |
||||
2. Implement changes with tests |
||||
3. Open pull request to develop |
||||
4. Pass all CI checks |
||||
5. Merge to develop (triggers staging deployment) |
||||
6. Create release for production deployment |
||||
|
||||
## Required Repository Secrets |
||||
|
||||
The following secrets must be configured in the GitHub repository: |
||||
|
||||
| Secret Name | Purpose | |
||||
|-------------|---------| |
||||
| `DOCKERHUB_USERNAME` | Docker Hub username for image publishing | |
||||
| `DOCKERHUB_TOKEN` | Docker Hub authentication token | |
@ -0,0 +1,82 @@
|
||||
# Configuration Guide |
||||
|
||||
## Environment Variables |
||||
|
||||
Create a `.env` file in the root directory: |
||||
|
||||
```bash |
||||
OPENAI_API_KEY=your_openai_key_here |
||||
ANTHROPIC_API_KEY=your_anthropic_key_here |
||||
GOOGLE_API_KEY=your_google_key_here |
||||
DEEPSEEK_API_KEY=your_deepseek_key_here |
||||
GROQ_API_KEY=your_groq_key_here |
||||
PORT=7860 # Optional, default port for the web interface |
||||
``` |
||||
|
||||
## Model Configuration |
||||
|
||||
Model names are configured in `src/ai_code_converter/config.py`: |
||||
|
||||
```python |
||||
# Model configurations |
||||
OPENAI_MODEL = "gpt-4o-mini" # OpenAI model name |
||||
CLAUDE_MODEL = "claude-3-sonnet-20240307" # Anthropic Claude model |
||||
DEEPSEEK_MODEL = "deepseek-chat" # DeepSeek model |
||||
GEMINI_MODEL = "gemini-1.5-flash" # Google Gemini model |
||||
GROQ_MODEL = "llama3-70b-8192" # GROQ model |
||||
``` |
||||
|
||||
You can modify these values to use different model versions based on your requirements and API access. |
||||
|
||||
## Prerequisites |
||||
|
||||
The following dependencies are required for full functionality: |
||||
|
||||
- Python 3.10+ |
||||
- Node.js and npm (with TypeScript) |
||||
- Java JDK 17+ |
||||
- Julia 1.9+ |
||||
- Go 1.21+ |
||||
- GCC/G++ |
||||
- Perl |
||||
- Lua 5.3+ |
||||
- PHP |
||||
- R |
||||
- Ruby |
||||
- Rust (rustc and cargo) |
||||
- Mono (for C#) |
||||
- Swift 5.9+ |
||||
- Kotlin |
||||
- SQLite3 |
||||
|
||||
Using Docker is recommended as it includes all necessary dependencies. |
||||
|
||||
## Docker Configuration |
||||
|
||||
The application includes Docker support for easy deployment. The `docker-compose.yml` file defines the service configuration: |
||||
|
||||
```yaml |
||||
version: '3' |
||||
services: |
||||
ai_code_converter: |
||||
build: . |
||||
ports: |
||||
- "${PORT:-7860}:7860" |
||||
volumes: |
||||
- ./logs:/app/logs |
||||
env_file: |
||||
- .env |
||||
restart: unless-stopped |
||||
``` |
||||
|
||||
You can customize the port mapping and volume mounts as needed. |
||||
|
||||
## Application Settings |
||||
|
||||
Additional application settings can be configured in `src/ai_code_converter/config.py`: |
||||
|
||||
- UI theme and styling |
||||
- Default language selections |
||||
- Model temperature settings |
||||
- Execution timeouts |
||||
- Logging configuration |
@ -0,0 +1,89 @@
|
||||
# Contributing Guidelines |
||||
|
||||
Thank you for your interest in contributing to the CodeXchange AI project! This document provides guidelines and instructions for contributing to the project. |
||||
|
||||
## How to Contribute |
||||
|
||||
1. Fork the repository |
||||
2. Create a feature branch (`git checkout -b feature/amazing-feature`) |
||||
3. Commit your changes (`git commit -m 'Add amazing feature'`) |
||||
4. Push to the branch (`git push origin feature/amazing-feature`) |
||||
5. Open a Pull Request |
||||
|
||||
## Development Workflow |
||||
|
||||
1. Check the issues page for open tasks or create a new issue for the feature/bug you want to work on |
||||
2. Assign yourself to the issue |
||||
3. Implement your changes following the best practices outlined below |
||||
4. Write tests for your changes |
||||
5. Update documentation as needed |
||||
6. Submit a pull request referencing the issue |
||||
|
||||
## Best Practices |
||||
|
||||
### Code Style |
||||
|
||||
- Follow existing patterns for consistency |
||||
- Follow PEP 8 style guidelines for Python code |
||||
- Use descriptive variable and function names |
||||
- Add type hints for all new functions |
||||
- Keep functions small and focused on a single responsibility |
||||
- Use docstrings for all public functions and classes |
||||
|
||||
### Error Handling |
||||
|
||||
- Add comprehensive error handling |
||||
- Use specific exception types |
||||
- Provide helpful error messages |
||||
- Log errors with appropriate context |
||||
|
||||
### Logging |
||||
|
||||
- Include detailed logging |
||||
- Use the existing logging framework |
||||
- Log at appropriate levels (DEBUG, INFO, WARNING, ERROR) |
||||
- Include relevant context in log messages |
||||
|
||||
### Documentation |
||||
|
||||
- Update documentation for any changes |
||||
- Document new features, configuration options, and APIs |
||||
- Keep the README and docs directory in sync |
||||
- Use clear, concise language |
||||
|
||||
### Testing |
||||
|
||||
- Write unit tests for new functionality |
||||
- Ensure all tests pass before submitting a PR |
||||
- Test edge cases and error conditions |
||||
- Aim for good test coverage |
||||
|
||||
## Pull Request Process |
||||
|
||||
1. Ensure your code follows the style guidelines |
||||
2. Update documentation as needed |
||||
3. Include tests for new functionality |
||||
4. Link the PR to any related issues |
||||
5. Wait for code review and address any feedback |
||||
|
||||
## Code Review |
||||
|
||||
All submissions require review. We use GitHub pull requests for this purpose: |
||||
|
||||
1. Reviewers will check code quality, test coverage, and documentation |
||||
2. Address any comments or requested changes |
||||
3. Once approved, maintainers will merge your PR |
||||
|
||||
## Acknowledgments |
||||
|
||||
We would like to thank the following organizations and projects that make CodeXchange AI possible: |
||||
|
||||
- OpenAI for GPT models |
||||
- Anthropic for Claude |
||||
- Google for Gemini |
||||
- DeepSeek and GROQ for their AI models |
||||
- The Gradio team for the web interface framework |
||||
|
||||
## License |
||||
|
||||
By contributing to this project, you agree that your contributions will be licensed under the project's MIT License. |
@ -0,0 +1,180 @@
|
||||
# Development Guide |
||||
|
||||
This guide provides instructions for extending the CodeXchange AI application with new languages and AI models. |
||||
|
||||
Before diving into development, it's recommended to review the [Architecture Diagram](./architecture_diagram.md) to understand the component relationships and application flow. |
||||
|
||||
## Adding New Programming Languages |
||||
|
||||
1. Update Language Configuration (`config.py`): |
||||
```python |
||||
SUPPORTED_LANGUAGES = [..., "NewLanguage"] |
||||
LANGUAGE_MAPPING = {..., "NewLanguage": "language_highlight_name"} |
||||
``` |
||||
|
||||
2. Add Language Detection (`core/language_detection.py`): |
||||
```python |
||||
class LanguageDetector: |
||||
@staticmethod |
||||
def detect_new_language(code: str) -> bool: |
||||
patterns = [r'pattern1', r'pattern2', r'pattern3'] |
||||
return any(re.search(pattern, code) for pattern in patterns) |
||||
``` |
||||
|
||||
3. Add Execution Support (`core/code_execution.py`): |
||||
```python |
||||
def execute_new_language(self, code: str) -> tuple[str, Optional[bytes]]: |
||||
with tempfile.NamedTemporaryFile(suffix='.ext', mode='w', delete=False) as f: |
||||
f.write(code) |
||||
file_path = f.name |
||||
try: |
||||
result = subprocess.run( |
||||
["compiler/interpreter", file_path], |
||||
capture_output=True, |
||||
text=True, |
||||
check=True |
||||
) |
||||
return result.stdout, None |
||||
except Exception as e: |
||||
return f"Error: {str(e)}", None |
||||
finally: |
||||
os.unlink(file_path) |
||||
``` |
||||
|
||||
4. Update the Dockerfile: |
||||
```dockerfile |
||||
# Add necessary dependencies for the new language |
||||
RUN apt-get update && apt-get install -y --no-install-recommends \ |
||||
new-language-package \ |
||||
&& rm -rf /var/lib/apt/lists/* |
||||
|
||||
# Verify the installation |
||||
RUN echo "New Language: $(new-language --version 2>/dev/null || echo 'NOT VERIFIED')" |
||||
``` |
||||
|
||||
5. Update the UI Components in `app.py`: |
||||
```python |
||||
def _initialize_components(self): |
||||
# Add the new language to dropdown options |
||||
self.source_language = gr.Dropdown( |
||||
choices=["Python", "JavaScript", ..., "NewLanguage"], |
||||
... |
||||
) |
||||
self.target_language = gr.Dropdown( |
||||
choices=["Python", "JavaScript", ..., "NewLanguage"], |
||||
... |
||||
) |
||||
``` |
||||
|
||||
6. Add Language-Specific Instructions in `template.j2`: |
||||
```jinja |
||||
{% if target_language == "NewLanguage" %} |
||||
# NewLanguage-specific conversion instructions |
||||
- Follow NewLanguage best practices |
||||
- Use idiomatic NewLanguage patterns |
||||
- Handle NewLanguage-specific edge cases |
||||
{% endif %} |
||||
``` |
||||
|
||||
## Adding New AI Models |
||||
|
||||
1. Update Model Configuration (`config.py`): |
||||
```python |
||||
NEW_MODEL = "model-name-version" |
||||
MODELS = [..., "NewModel"] |
||||
``` |
||||
|
||||
2. Add Model Integration (`models/ai_streaming.py`): |
||||
```python |
||||
def stream_new_model(self, prompt: str) -> Generator[str, None, None]: |
||||
try: |
||||
response = self.new_model_client.generate( |
||||
prompt=prompt, |
||||
stream=True |
||||
) |
||||
reply = "" |
||||
for chunk in response: |
||||
fragment = chunk.text |
||||
reply += fragment |
||||
yield reply |
||||
except Exception as e: |
||||
logger.error(f"New Model API error: {str(e)}", exc_info=True) |
||||
yield f"Error with New Model API: {str(e)}" |
||||
``` |
||||
|
||||
3. Add API Client Initialization: |
||||
```python |
||||
def __init__(self, api_keys: dict): |
||||
# Initialize existing clients |
||||
... |
||||
|
||||
# Initialize new model client |
||||
if "NEW_MODEL_API_KEY" in api_keys: |
||||
self.new_model_client = NewModelClient( |
||||
api_key=api_keys["NEW_MODEL_API_KEY"] |
||||
) |
||||
``` |
||||
|
||||
4. Update the Model Selection Logic: |
||||
```python |
||||
def stream_completion(self, model: str, prompt: str) -> Generator[str, None, None]: |
||||
if model == "NewModel": |
||||
yield from self.stream_new_model(prompt) |
||||
else: |
||||
# Existing model handling |
||||
... |
||||
``` |
||||
|
||||
## Testing |
||||
|
||||
1. Add test cases for new components: |
||||
- Unit tests for language detection |
||||
- Integration tests for code execution |
||||
- End-to-end tests for UI components |
||||
|
||||
2. Test language detection with sample code: |
||||
- Positive examples (valid code in the target language) |
||||
- Negative examples (code from other languages) |
||||
- Edge cases (minimal valid code snippets) |
||||
|
||||
3. Test code execution with various examples: |
||||
- Simple "Hello World" programs |
||||
- Programs with external dependencies |
||||
- Programs with different runtime characteristics |
||||
- Error handling cases |
||||
|
||||
4. Test model streaming with different prompts: |
||||
- Short prompts |
||||
- Long prompts |
||||
- Edge cases (empty prompts, very complex code) |
||||
- Error handling |
||||
|
||||
5. Verify error handling and edge cases: |
||||
- API rate limiting |
||||
- Network failures |
||||
- Invalid inputs |
||||
- Resource constraints |
||||
|
||||
## Logging |
||||
|
||||
The application uses a structured logging system: |
||||
|
||||
- JSON formatted logs with timestamps |
||||
- Stored in `logs` directory |
||||
- Separate console and file logging |
||||
- Detailed execution metrics |
||||
|
||||
To add logging for new components: |
||||
|
||||
```python |
||||
import logging |
||||
logger = logging.getLogger(__name__) |
||||
|
||||
def new_function(): |
||||
try: |
||||
logger.info("Starting operation", extra={"component": "new_component"}) |
||||
# Function logic |
||||
logger.info("Operation completed", extra={"component": "new_component", "metrics": {...}}) |
||||
except Exception as e: |
||||
logger.error(f"Error: {str(e)}", exc_info=True, extra={"component": "new_component"}) |
||||
``` |
@ -0,0 +1,68 @@
|
||||
# Supported Languages |
||||
|
||||
CodeXchange AI currently supports the following programming languages: |
||||
|
||||
## Language Support Table |
||||
|
||||
| Language | Execution Method | File Extension | |
||||
|------------|----------------------------------------|----------------| |
||||
| Python | Direct execution in restricted env | .py | |
||||
| JavaScript | Node.js | .js | |
||||
| Java | javac + java | .java | |
||||
| C++ | g++ + executable | .cpp | |
||||
| Julia | julia | .jl | |
||||
| Go | go run | .go | |
||||
| Ruby | ruby | .rb | |
||||
| Swift | swift | .swift | |
||||
| Rust | rustc + executable | .rs | |
||||
| C# | csc (Mono) | .cs | |
||||
| TypeScript | tsc + node | .ts | |
||||
| R | Rscript | .R | |
||||
| Perl | perl | .pl | |
||||
| Lua | lua5.3 | .lua | |
||||
| PHP | php | .php | |
||||
| Kotlin | kotlinc + kotlin | .kt | |
||||
| SQL | sqlite3 | .sql | |
||||
|
||||
## Currently Implemented Languages |
||||
|
||||
While the application has templates and instructions for all the languages listed above, the following languages are currently fully implemented with language detection and execution support: |
||||
|
||||
- Python |
||||
- JavaScript |
||||
- Java |
||||
- C++ |
||||
- Julia |
||||
- Go |
||||
|
||||
## Language-Specific Notes |
||||
|
||||
### Python |
||||
- Executed directly in a restricted environment |
||||
- Supports most standard libraries |
||||
- Execution timeout: 30 seconds |
||||
|
||||
### JavaScript |
||||
- Executed using Node.js |
||||
- Supports ES6+ features |
||||
- No external npm packages are installed during execution |
||||
|
||||
### Java |
||||
- Requires a class with a main method |
||||
- Class name must match filename |
||||
- Compiled with javac before execution |
||||
|
||||
### C++ |
||||
- Compiled with g++ |
||||
- Standard C++17 support |
||||
- Execution timeout: 30 seconds |
||||
|
||||
### Julia |
||||
- Executed with the julia interpreter |
||||
- Supports Julia 1.9+ |
||||
- Limited package support during execution |
||||
|
||||
### Go |
||||
- Executed with go run |
||||
- Supports Go 1.21+ |
||||
- Standard library support only |
@ -0,0 +1,108 @@
|
||||
# Project Structure |
||||
|
||||
This document provides an overview of the CodeXchange AI project structure and architecture. |
||||
|
||||
For a visual representation of the application architecture and component relationships, please refer to the [Architecture Diagram](./architecture_diagram.md). |
||||
|
||||
## Directory Structure |
||||
|
||||
``` |
||||
ai_code_converter/ |
||||
├── README.md # Project documentation |
||||
├── requirements.txt # Python dependencies |
||||
├── run.py # Application entry point |
||||
├── Dockerfile # Docker configuration |
||||
├── docker-compose.yml # Docker Compose configuration |
||||
├── .env.example # Environment variables template |
||||
├── docs/ # Detailed documentation |
||||
└── src/ # Source code directory |
||||
└── ai_code_converter/ |
||||
├── main.py # Main application logic |
||||
├── app.py # Gradio interface setup |
||||
├── config.py # Model and app configuration |
||||
├── template.j2 # Prompt template |
||||
├── core/ # Core functionality |
||||
│ ├── __init__.py |
||||
│ ├── language_detection.py # Language validation |
||||
│ └── code_execution.py # Code execution |
||||
├── models/ # AI model integration |
||||
│ ├── __init__.py |
||||
│ └── ai_streaming.py # API clients and streaming |
||||
└── utils/ # Utility functions |
||||
├── __init__.py |
||||
└── logging.py # Logging configuration |
||||
``` |
||||
|
||||
## Component Descriptions |
||||
|
||||
### Entry Points |
||||
|
||||
- **run.py**: The main entry point for the application. It imports and initializes the necessary modules and starts the application. |
||||
|
||||
- **main.py**: Contains the main application logic, initializes the application components, and starts the Gradio interface. |
||||
|
||||
### Core Components |
||||
|
||||
- **app.py**: Sets up the Gradio interface and defines UI components. Contains the `CodeConverterApp` class that handles the UI and code conversion logic. |
||||
|
||||
- **config.py**: Contains configuration for models, languages, and application settings. Defines supported languages, model names, and UI styling. |
||||
|
||||
- **template.j2**: A Jinja2 template used to create prompts for the LLMs with language-specific instructions for code conversion. |
||||
|
||||
### Core Directory |
||||
|
||||
The `core` directory contains modules for core functionality: |
||||
|
||||
- **language_detection.py**: Contains the `LanguageDetector` class with static methods to validate if code matches the expected language patterns. |
||||
|
||||
- **code_execution.py**: Handles the execution of code in different programming languages. Contains language-specific execution methods. |
||||
|
||||
### Models Directory |
||||
|
||||
The `models` directory contains modules for AI model integration: |
||||
|
||||
- **ai_streaming.py**: Handles API calls to various LLMs (GPT, Claude, Gemini, DeepSeek, GROQ). Contains methods for streaming responses from different AI providers. |
||||
|
||||
### Utils Directory |
||||
|
||||
The `utils` directory contains utility modules: |
||||
|
||||
- **logging.py**: Configures the logging system for the application. Sets up console and file handlers with appropriate formatting. |
||||
|
||||
## Application Flow |
||||
|
||||
1. **Initialization**: |
||||
- `run.py` imports the main module |
||||
- `main.py` initializes the application components |
||||
- `app.py` sets up the Gradio interface |
||||
|
||||
2. **User Interaction**: |
||||
- User selects source and target languages |
||||
- User enters or uploads source code |
||||
- User selects AI model and temperature |
||||
- User clicks "Convert" |
||||
|
||||
3. **Code Conversion**: |
||||
- Source language is validated using `language_detection.py` |
||||
- Prompt is created using `template.j2` |
||||
- AI model is called using `ai_streaming.py` |
||||
- Response is streamed back to the UI |
||||
|
||||
4. **Code Execution** (optional): |
||||
- User clicks "Run" on original or converted code |
||||
- Code is executed using appropriate method in `code_execution.py` |
||||
- Output is displayed in the UI |
||||
|
||||
## Design Patterns |
||||
|
||||
- **Singleton Pattern**: Used for API clients to ensure only one instance exists |
||||
- **Factory Pattern**: Used for creating language-specific execution methods |
||||
- **Strategy Pattern**: Used for selecting the appropriate AI model |
||||
- **Observer Pattern**: Used for streaming responses from AI models |
||||
|
||||
## Dependencies |
||||
|
||||
- **Gradio**: Web interface framework |
||||
- **Jinja2**: Template engine for creating prompts |
||||
- **OpenAI, Anthropic, Google, DeepSeek, GROQ APIs**: AI model providers |
||||
- **Various language interpreters and compilers**: For code execution |
@ -0,0 +1,332 @@
|
||||
import gradio as gr |
||||
|
||||
# Define custom CSS with dark theme fixes, updated to use html.dark |
||||
custom_css = """ |
||||
/* Root variables for light theme */ |
||||
:root { |
||||
--background: #ffffff; |
||||
--secondary-background: #f7f7f7; |
||||
--tertiary-background: #f0f0f0; |
||||
--text: #000000; |
||||
--secondary-text: #5d5d5d; |
||||
--border: #e0e0e0; |
||||
--accent: #ff7b2c; |
||||
--accent-hover: #ff6a14; |
||||
--button-text: #ffffff; |
||||
--code-bg: #f7f7f7; |
||||
--code-text: #000000; |
||||
--dropdown-bg: #ffffff; |
||||
--slider-track: #e0e0e0; |
||||
--slider-thumb: #ff7b2c; |
||||
--collapsible-header: #f0f0f0; |
||||
--primary-button-bg: #4a6ee0; /* Blue */ |
||||
--primary-button-hover: #3a5ec8; |
||||
--secondary-button-bg: #444444; |
||||
--secondary-button-hover: #555555; |
||||
--danger-button-bg: #e74c3c; /* Red */ |
||||
--danger-button-hover: #c0392b; |
||||
--success-button-bg: #e67e22; /* Orange */ |
||||
--success-button-hover: #d35400; |
||||
} |
||||
|
||||
/* Dark theme variables using html.dark */ |
||||
html.dark { |
||||
--background: #1a1a1a; |
||||
--secondary-background: #252525; |
||||
--tertiary-background: #2a2a2a; |
||||
--text: #ffffff; |
||||
--secondary-text: #cccccc; |
||||
--border: #444444; |
||||
--accent: #ff7b2c; |
||||
--accent-hover: #ff6a14; |
||||
--button-text: #ffffff; |
||||
--code-bg: #252525; |
||||
--code-text: #ffffff; |
||||
--dropdown-bg: #2a2a2a; |
||||
--slider-track: #444444; |
||||
--slider-thumb: #ff7b2c; |
||||
--collapsible-header: #333333; |
||||
--primary-button-bg: #4a6ee0; |
||||
--primary-button-hover: #3a5ec8; |
||||
--secondary-button-bg: #444444; |
||||
--secondary-button-hover: #555555; |
||||
--danger-button-bg: #e74c3c; |
||||
--danger-button-hover: #c0392b; |
||||
--success-button-bg: #e67e22; |
||||
--success-button-hover: #d35400; |
||||
} |
||||
|
||||
/* Base styles */ |
||||
body { |
||||
background-color: var(--background) !important; |
||||
color: var(--text) !important; |
||||
transition: all 0.3s ease; |
||||
} |
||||
|
||||
.gradio-container { |
||||
background-color: var(--background) !important; |
||||
max-width: 100% !important; |
||||
} |
||||
|
||||
/* Headers */ |
||||
h1, h2, h3, h4, h5, h6, .gr-header { |
||||
color: var(--text) !important; |
||||
} |
||||
|
||||
/* Panels and blocks */ |
||||
.gr-panel, .gr-form, .gr-box, .gr-block { |
||||
background-color: var(--secondary-background) !important; |
||||
color: var(--text) !important; |
||||
border-color: var(--border) !important; |
||||
border-radius: 6px !important; |
||||
} |
||||
|
||||
/* Validation messages section */ |
||||
.gr-accordion .gr-panel { |
||||
background-color: var(--secondary-background) !important; |
||||
color: var(--text) !important; |
||||
border-color: #e74c3c !important; /* Red border */ |
||||
} |
||||
|
||||
.gr-accordion-header { |
||||
background-color: var(--collapsible-header) !important; |
||||
color: var(--text) !important; |
||||
} |
||||
|
||||
/* Code editors */ |
||||
.codebox, .code-editor, .cm-editor { |
||||
background-color: var(--code-bg) !important; |
||||
color: var(--code-text) !important; |
||||
border: 1px solid var(--border) !important; |
||||
border-radius: 4px !important; |
||||
} |
||||
|
||||
/* Syntax highlighting */ |
||||
.cm-editor .cm-content, .cm-editor .cm-line { |
||||
color: var(--code-text) !important; |
||||
} |
||||
.cm-editor .cm-keyword { color: #ff79c6 !important; } /* Pink */ |
||||
.cm-editor .cm-number { color: #bd93f9 !important; } /* Purple */ |
||||
.cm-editor .cm-string { color: #f1fa8c !important; } /* Yellow */ |
||||
.cm-editor .cm-comment { color: #6272a4 !important; } /* Gray */ |
||||
|
||||
/* Buttons */ |
||||
.gr-button { |
||||
background-color: var(--tertiary-background) !important; |
||||
color: var(--text) !important; |
||||
border-color: var(--border) !important; |
||||
border-radius: 4px !important; |
||||
} |
||||
.gr-button.success { |
||||
background-color: var(--success-button-bg) !important; |
||||
color: var(--button-text) !important; |
||||
} |
||||
.gr-button.success:hover { |
||||
background-color: var(--success-button-hover) !important; |
||||
} |
||||
.gr-button.danger { |
||||
background-color: var(--danger-button-bg) !important; |
||||
color: var(--button-text) !important; |
||||
} |
||||
.gr-button.danger:hover { |
||||
background-color: var(--danger-button-hover) !important; |
||||
} |
||||
.gr-button.secondary { |
||||
background-color: var(--secondary-button-bg) !important; |
||||
color: var(--button-text) !important; |
||||
} |
||||
.gr-button.secondary:hover { |
||||
background-color: var(--secondary-button-hover) !important; |
||||
} |
||||
|
||||
/* File upload */ |
||||
.gr-file, .gr-file-upload { |
||||
background-color: var(--secondary-background) !important; |
||||
color: var(--text) !important; |
||||
border-color: var(--border) !important; |
||||
} |
||||
|
||||
/* Dropdowns */ |
||||
.gr-dropdown, .gr-dropdown-container, .gr-dropdown select, .gr-dropdown option { |
||||
background-color: var(--dropdown-bg) !important; |
||||
color: var(--text) !important; |
||||
border-color: var(--border) !important; |
||||
} |
||||
|
||||
/* Slider */ |
||||
.gr-slider { |
||||
background-color: var(--background) !important; |
||||
} |
||||
.gr-slider-track { |
||||
background-color: var(--slider-track) !important; |
||||
} |
||||
.gr-slider-handle { |
||||
background-color: var(--slider-thumb) !important; |
||||
} |
||||
.gr-slider-value { |
||||
color: var(--text) !important; |
||||
} |
||||
|
||||
/* Code output */ |
||||
.gr-code { |
||||
background-color: var(--code-bg) !important; |
||||
color: var(--code-text) !important; |
||||
border-color: var(--border) !important; |
||||
} |
||||
|
||||
/* Footer */ |
||||
.footer { |
||||
color: var(--secondary-text) !important; |
||||
} |
||||
.footer a { |
||||
color: var(--accent) !important; |
||||
} |
||||
""" |
||||
|
||||
# JavaScript for theme toggling and initialization |
||||
js_code = """ |
||||
<script> |
||||
function toggleTheme(theme) { |
||||
var url = new URL(window.location.href); |
||||
if (theme === "dark") { |
||||
url.searchParams.set('__theme', 'dark'); |
||||
} else { |
||||
url.searchParams.delete('__theme'); |
||||
} |
||||
window.location.href = url.href; |
||||
} |
||||
|
||||
// Set the radio button based on current theme |
||||
document.addEventListener('DOMContentLoaded', function() { |
||||
var urlParams = new URLSearchParams(window.location.search); |
||||
var currentTheme = urlParams.get('__theme'); |
||||
if (currentTheme === 'dark') { |
||||
document.querySelector('#theme_radio_container input[value="dark"]').checked = true; |
||||
} else { |
||||
document.querySelector('#theme_radio_container input[value="light"]').checked = true; |
||||
} |
||||
}); |
||||
</script> |
||||
""" |
||||
|
||||
# Language and model options |
||||
INPUT_LANGUAGES = ["Python", "JavaScript", "Java", "TypeScript", "Swift", "C#", "Ruby", "Go", "Rust", "PHP"] |
||||
OUTPUT_LANGUAGES = ["Python", "JavaScript", "Java", "TypeScript", "Swift", "C#", "Ruby", "Go", "Rust", "PHP", "Julia"] |
||||
MODELS = ["GPT", "Claude", "CodeLlama", "Llama", "Gemini"] |
||||
DOC_STYLES = ["standard", "detailed", "minimal"] |
||||
|
||||
# Build the interface |
||||
with gr.Blocks(css=custom_css, theme=gr.themes.Base()) as demo: |
||||
# Inject the JavaScript code |
||||
gr.HTML(js_code) |
||||
|
||||
# States for dynamic button text |
||||
input_lang_state = gr.State("Python") |
||||
output_lang_state = gr.State("JavaScript") |
||||
|
||||
# Header |
||||
with gr.Row(elem_classes="header-container"): |
||||
gr.HTML("<h1 class='header-title'>AI CodeXchange</h1>") |
||||
# Theme selection radio and apply button |
||||
theme_radio = gr.Radio(["light", "dark"], label="Theme", elem_id="theme_radio_container", value="dark") |
||||
theme_button = gr.Button("Apply Theme") |
||||
|
||||
# Validation Messages |
||||
with gr.Accordion("Validation Messages", open=True): |
||||
with gr.Row(): |
||||
with gr.Column(): |
||||
input_code = gr.Code(language="python", label="Code In", lines=15, elem_classes="code-container") |
||||
with gr.Column(): |
||||
output_code = gr.Code(language="javascript", label="Converted Code", lines=15, elem_classes="code-container") |
||||
|
||||
# Configuration Options |
||||
with gr.Row(): |
||||
input_lang = gr.Dropdown(INPUT_LANGUAGES, label="Code In", value="Python") |
||||
output_lang = gr.Dropdown(OUTPUT_LANGUAGES, label="Code Out", value="JavaScript") |
||||
model = gr.Dropdown(MODELS, label="Model", value="GPT") |
||||
temperature = gr.Slider(minimum=0, maximum=1, step=0.1, value=0.7, label="Temperature") |
||||
|
||||
# Document Options |
||||
with gr.Row(): |
||||
document_check = gr.Checkbox(label="Document", value=True) |
||||
doc_style = gr.Dropdown(DOC_STYLES, label="Document Style", value="standard") |
||||
|
||||
# File Upload |
||||
with gr.Accordion("Upload", open=True): |
||||
file_upload = gr.File(label="Drop File Here - or - Click to Upload") |
||||
|
||||
# Action Buttons |
||||
with gr.Row(elem_classes="button-row"): |
||||
convert_btn = gr.Button("Convert", elem_classes="success") |
||||
clear_btn = gr.Button("Clear All", elem_classes="danger") |
||||
|
||||
# Run Buttons |
||||
with gr.Row(elem_classes="button-row"): |
||||
run_source = gr.Button("Run Source Code", elem_classes="secondary") |
||||
run_target = gr.Button("Run Target Code", elem_classes="secondary") |
||||
|
||||
# Results |
||||
with gr.Row(): |
||||
source_result = gr.Code(label="Source Code Result", language="python", lines=10, elem_classes="code-container") |
||||
target_result = gr.Code(label="Converted Code Result", language="javascript", lines=10, elem_classes="code-container") |
||||
|
||||
# Download |
||||
with gr.Accordion("Download", open=True): |
||||
with gr.Row(): |
||||
dl_source = gr.Button("Download Source Code") |
||||
dl_target = gr.Button("Download Converted Code") |
||||
|
||||
# Footer |
||||
with gr.Row(elem_classes="footer"): |
||||
gr.HTML("<div>Use via API</div><div>•</div><div>Built with Gradio</div><div>•</div><div>Settings</div>") |
||||
|
||||
# Theme toggle event |
||||
theme_button.click( |
||||
fn=None, |
||||
inputs=None, |
||||
outputs=[], |
||||
js=""" |
||||
var theme = document.querySelector('#theme_radio_container input:checked').value; |
||||
toggleTheme(theme); |
||||
""" |
||||
) |
||||
|
||||
# Existing event handlers |
||||
def convert_code(input_code, in_lang, out_lang, model, temp, doc, doc_style): |
||||
return f"// Converted from {in_lang} to {out_lang} using {model}\n// Temperature: {temp}\n// Documentation: {doc} ({doc_style if doc else 'N/A'})" |
||||
|
||||
convert_btn.click(fn=convert_code, inputs=[input_code, input_lang_state, output_lang_state, model, temperature, document_check, doc_style], outputs=[output_code]) |
||||
|
||||
def update_convert_btn_text(in_lang, out_lang): |
||||
return f"Convert {in_lang} to {out_lang}", in_lang, out_lang |
||||
|
||||
input_lang.change(fn=update_convert_btn_text, inputs=[input_lang, output_lang], outputs=[convert_btn, input_lang_state, output_lang_state]) |
||||
output_lang.change(fn=update_convert_btn_text, inputs=[input_lang, output_lang], outputs=[convert_btn, input_lang_state, output_lang_state]) |
||||
|
||||
def update_run_btn_text(in_lang, out_lang): |
||||
return f"Run {in_lang}", f"Run {out_lang}" |
||||
|
||||
input_lang.change(fn=update_run_btn_text, inputs=[input_lang, output_lang], outputs=[run_source, run_target]) |
||||
output_lang.change(fn=update_run_btn_text, inputs=[input_lang, output_lang], outputs=[run_source, run_target]) |
||||
|
||||
def clear_all(): |
||||
return "", "", "", "" |
||||
|
||||
clear_btn.click(fn=clear_all, inputs=[], outputs=[input_code, output_code, source_result, target_result]) |
||||
|
||||
def run_code(code, lang): |
||||
return f"// Running {lang} code...\n// Results would appear here" |
||||
|
||||
run_source.click(fn=run_code, inputs=[input_code, input_lang_state], outputs=[source_result]) |
||||
run_target.click(fn=run_code, inputs=[output_code, output_lang_state], outputs=[target_result]) |
||||
|
||||
def handle_file_upload(file): |
||||
if file is None: |
||||
return "" |
||||
with open(file.name, "r") as f: |
||||
return f.read() |
||||
|
||||
file_upload.change(fn=handle_file_upload, inputs=[file_upload], outputs=[input_code]) |
||||
|
||||
if __name__ == "__main__": |
||||
demo.launch() |
@ -0,0 +1,6 @@
|
||||
[pytest] |
||||
testpaths = tests |
||||
python_files = test_*.py |
||||
python_classes = Test* |
||||
python_functions = test_* |
||||
addopts = --cov=src/ai_code_converter --cov-report=term --cov-report=xml -v |
@ -0,0 +1,81 @@
|
||||
openai>=1.0.0 |
||||
anthropic>=0.3.0 |
||||
google-generativeai>=0.1.0 |
||||
python-dotenv>=1.0.0 |
||||
jinja2>=3.0.0 |
||||
aiofiles==23.2.1 |
||||
annotated-types==0.7.0 |
||||
anthropic==0.49.0 |
||||
anyio==4.8.0 |
||||
cachetools==5.5.1 |
||||
certifi==2025.1.31 |
||||
charset-normalizer==3.4.1 |
||||
click==8.1.8 |
||||
distro==1.9.0 |
||||
exceptiongroup==1.2.2 |
||||
fastapi==0.115.8 |
||||
ffmpy==0.5.0 |
||||
filelock==3.17.0 |
||||
fsspec==2025.2.0 |
||||
google-ai-generativelanguage==0.6.15 |
||||
google-api-core==2.24.1 |
||||
google-api-python-client==2.160.0 |
||||
google-auth==2.38.0 |
||||
google-auth-httplib2==0.2.0 |
||||
google-generativeai==0.8.4 |
||||
googleapis-common-protos==1.66.0 |
||||
gradio>=4.0.0 |
||||
gradio_client==1.7.0 |
||||
grpcio==1.70.0 |
||||
grpcio-status==1.70.0 |
||||
h11==0.14.0 |
||||
httpcore==1.0.7 |
||||
httplib2==0.22.0 |
||||
httpx==0.28.1 |
||||
huggingface-hub==0.28.1 |
||||
idna==3.10 |
||||
Jinja2==3.1.5 |
||||
jiter==0.8.2 |
||||
markdown-it-py==3.0.0 |
||||
MarkupSafe==2.1.5 |
||||
mdurl==0.1.2 |
||||
numpy==2.2.2 |
||||
openai==1.61.1 |
||||
orjson==3.10.15 |
||||
packaging==24.2 |
||||
pandas==2.2.3 |
||||
pillow==11.1.0 |
||||
proto-plus==1.26.0 |
||||
protobuf==5.29.3 |
||||
pyasn1==0.6.1 |
||||
pyasn1_modules==0.4.1 |
||||
pydantic==2.10.6 |
||||
pydantic-settings==2.7.1 |
||||
pydantic_core==2.27.2 |
||||
pydub==0.25.1 |
||||
Pygments==2.19.1 |
||||
pyparsing==3.2.1 |
||||
python-dateutil==2.9.0.post0 |
||||
python-dotenv==1.0.1 |
||||
python-multipart==0.0.20 |
||||
pytz==2025.1 |
||||
PyYAML==6.0.2 |
||||
requests==2.32.3 |
||||
rich==13.9.4 |
||||
rsa==4.9 |
||||
ruff==0.9.6 |
||||
safehttpx==0.1.6 |
||||
semantic-version==2.10.0 |
||||
shellingham==1.5.4 |
||||
six==1.17.0 |
||||
sniffio==1.3.1 |
||||
starlette==0.45.3 |
||||
tomlkit==0.13.2 |
||||
tqdm==4.67.1 |
||||
typer==0.15.1 |
||||
typing_extensions==4.12.2 |
||||
tzdata==2025.1 |
||||
uritemplate==4.1.1 |
||||
urllib3==2.3.0 |
||||
uvicorn==0.34.0 |
||||
websockets==14.2 |
@ -0,0 +1,318 @@
|
||||
#!/bin/bash |
||||
# |
||||
# CodeXchange AI Docker Wrapper Script |
||||
# This script simplifies running the CodeXchange AI application using Docker. |
||||
# |
||||
|
||||
set -e |
||||
|
||||
# Color codes for terminal output |
||||
GREEN='\033[0;32m' |
||||
YELLOW='\033[0;33m' |
||||
RED='\033[0;31m' |
||||
BLUE='\033[0;34m' |
||||
NC='\033[0m' # No Color |
||||
|
||||
# Script version |
||||
VERSION="1.0.0" |
||||
|
||||
# Default values |
||||
ENV_FILE=".env" |
||||
PORT=7860 |
||||
BUILD_ONLY=false |
||||
DETACHED=false |
||||
FOLLOW_LOGS=false |
||||
STOP=false |
||||
RESTART=false |
||||
DOWN=false |
||||
API_KEY_REMIND=false |
||||
|
||||
# Display script banner |
||||
display_banner() { |
||||
echo -e "${BLUE}" |
||||
echo "╔═══════════════════════════════════════════════════╗" |
||||
echo "║ CodeXchange AI - Docker Launcher ║" |
||||
echo "╚═══════════════════════════════════════════════════╝" |
||||
echo -e "${NC}" |
||||
} |
||||
|
||||
# Display help message |
||||
display_help() { |
||||
echo -e "Usage: $0 [OPTIONS]" |
||||
echo |
||||
echo "Options:" |
||||
echo " -b, --build Build the Docker image without running the container" |
||||
echo " -d, --detach Run container in detached mode (background)" |
||||
echo " -e, --env FILE Specify an environment file (default: .env)" |
||||
echo " -p, --port PORT Specify the port to expose (default: 7860)" |
||||
echo " -l, --logs Follow the container logs after starting" |
||||
echo " -s, --stop Stop the running container" |
||||
echo " -r, --restart Restart the container" |
||||
echo " -D, --down Stop and remove the container" |
||||
echo " -k, --keys Check for API keys and show setup instructions if missing" |
||||
echo " -h, --help Display this help message" |
||||
echo " -v, --version Display script version" |
||||
echo |
||||
echo "Examples:" |
||||
echo " $0 Build and run the container" |
||||
echo " $0 -d -p 8080 Run in detached mode on port 8080" |
||||
echo " $0 -b Build the image only" |
||||
echo " $0 -s Stop the running container" |
||||
echo |
||||
} |
||||
|
||||
# Check prerequisites |
||||
check_prerequisites() { |
||||
echo -e "${BLUE}Checking prerequisites...${NC}" |
||||
|
||||
# Check for Docker |
||||
if ! command -v docker &> /dev/null; then |
||||
echo -e "${RED}Error: Docker is not installed or not in PATH.${NC}" |
||||
echo "Please install Docker to continue: https://docs.docker.com/get-docker/" |
||||
exit 1 |
||||
fi |
||||
|
||||
# Check for docker-compose |
||||
if ! command -v docker-compose &> /dev/null; then |
||||
echo -e "${YELLOW}Warning: docker-compose not found. Checking for Docker Compose V2...${NC}" |
||||
if ! docker compose version &> /dev/null; then |
||||
echo -e "${RED}Error: Docker Compose not found.${NC}" |
||||
echo "Please install Docker Compose to continue: https://docs.docker.com/compose/install/" |
||||
exit 1 |
||||
else |
||||
echo -e "${GREEN}Docker Compose V2 found.${NC}" |
||||
COMPOSE_CMD="docker compose" |
||||
fi |
||||
else |
||||
COMPOSE_CMD="docker-compose" |
||||
fi |
||||
|
||||
echo -e "${GREEN}Prerequisites satisfied.${NC}" |
||||
} |
||||
|
||||
# Check for environment variables |
||||
check_env_file() { |
||||
# Check if the specified .env file exists |
||||
if [ ! -f "$ENV_FILE" ]; then |
||||
echo -e "${YELLOW}Warning: $ENV_FILE file not found.${NC}" |
||||
|
||||
# If it's the default .env and .env.example exists, offer to copy it |
||||
if [ "$ENV_FILE" = ".env" ] && [ -f ".env.example" ]; then |
||||
echo -e "Would you like to create a .env file from .env.example? (y/n)" |
||||
read -r response |
||||
if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]; then |
||||
cp .env.example .env |
||||
echo -e "${GREEN}.env file created from .env.example. Please edit it to add your API keys.${NC}" |
||||
API_KEY_REMIND=true |
||||
fi |
||||
else |
||||
echo -e "${YELLOW}Please create an environment file with your API keys.${NC}" |
||||
API_KEY_REMIND=true |
||||
fi |
||||
fi |
||||
} |
||||
|
||||
# Check for required API keys |
||||
check_api_keys() { |
||||
if [ "$API_KEY_REMIND" = true ] || [ "$1" = true ]; then |
||||
echo -e "${YELLOW}API Key Requirements:${NC}" |
||||
echo "The CodeXchange AI requires API keys for the following services:" |
||||
echo " - OPENAI_API_KEY (Required for OpenAI GPT models)" |
||||
echo " - ANTHROPIC_API_KEY (Required for Claude models)" |
||||
echo " - GOOGLE_API_KEY (Required for Google Gemini models)" |
||||
echo " - DEEPSEEK_API_KEY (Required for DeepSeek models)" |
||||
echo " - GROQ_API_KEY (Required for GROQ models)" |
||||
echo |
||||
echo -e "Please ensure these keys are set in your ${BLUE}$ENV_FILE${NC} file." |
||||
echo "You only need keys for the models you plan to use." |
||||
fi |
||||
} |
||||
|
||||
# Parse command line arguments |
||||
parse_arguments() { |
||||
while [[ $# -gt 0 ]]; do |
||||
case $1 in |
||||
-b|--build) |
||||
BUILD_ONLY=true |
||||
shift |
||||
;; |
||||
-d|--detach) |
||||
DETACHED=true |
||||
shift |
||||
;; |
||||
-e|--env) |
||||
ENV_FILE="$2" |
||||
shift 2 |
||||
;; |
||||
-p|--port) |
||||
PORT="$2" |
||||
shift 2 |
||||
;; |
||||
-l|--logs) |
||||
FOLLOW_LOGS=true |
||||
shift |
||||
;; |
||||
-s|--stop) |
||||
STOP=true |
||||
shift |
||||
;; |
||||
-r|--restart) |
||||
RESTART=true |
||||
shift |
||||
;; |
||||
-D|--down) |
||||
DOWN=true |
||||
shift |
||||
;; |
||||
-k|--keys) |
||||
check_api_keys true |
||||
exit 0 |
||||
;; |
||||
-h|--help) |
||||
display_banner |
||||
display_help |
||||
exit 0 |
||||
;; |
||||
-v|--version) |
||||
echo "CodeXchange AI Docker Wrapper v$VERSION" |
||||
exit 0 |
||||
;; |
||||
*) |
||||
echo -e "${RED}Error: Unknown option $1${NC}" |
||||
display_help |
||||
exit 1 |
||||
;; |
||||
esac |
||||
done |
||||
} |
||||
|
||||
# Build the Docker image |
||||
build_image() { |
||||
echo -e "${BLUE}Building the Docker image...${NC}" |
||||
|
||||
# Export PORT from the environment for docker-compose |
||||
export PORT=$PORT |
||||
|
||||
if [ -f "$ENV_FILE" ]; then |
||||
echo -e "${GREEN}Using environment file: $ENV_FILE${NC}" |
||||
OPTS="--env-file $ENV_FILE" |
||||
else |
||||
OPTS="" |
||||
fi |
||||
|
||||
# Build the image |
||||
$COMPOSE_CMD $OPTS build |
||||
|
||||
echo -e "${GREEN}Docker image built successfully.${NC}" |
||||
} |
||||
|
||||
# Run the container |
||||
run_container() { |
||||
echo -e "${BLUE}Starting the CodeXchange AI...${NC}" |
||||
|
||||
# Export PORT from the environment for docker-compose |
||||
export PORT=$PORT |
||||
|
||||
if [ -f "$ENV_FILE" ]; then |
||||
OPTS="--env-file $ENV_FILE" |
||||
else |
||||
OPTS="" |
||||
fi |
||||
|
||||
# Add detach flag if specified |
||||
if [ "$DETACHED" = true ]; then |
||||
OPTS="$OPTS -d" |
||||
fi |
||||
|
||||
# Run the container |
||||
$COMPOSE_CMD $OPTS up |
||||
|
||||
# Follow logs if detached and requested |
||||
if [ "$DETACHED" = true ] && [ "$FOLLOW_LOGS" = true ]; then |
||||
$COMPOSE_CMD logs -f |
||||
fi |
||||
} |
||||
|
||||
# Stop the container |
||||
stop_container() { |
||||
echo -e "${BLUE}Stopping the CodeXchange AI...${NC}" |
||||
$COMPOSE_CMD stop |
||||
echo -e "${GREEN}Container stopped.${NC}" |
||||
} |
||||
|
||||
# Restart the container |
||||
restart_container() { |
||||
echo -e "${BLUE}Restarting the CodeXchange AI...${NC}" |
||||
$COMPOSE_CMD restart |
||||
echo -e "${GREEN}Container restarted.${NC}" |
||||
|
||||
if [ "$FOLLOW_LOGS" = true ]; then |
||||
$COMPOSE_CMD logs -f |
||||
fi |
||||
} |
||||
|
||||
# Bring down the container |
||||
down_container() { |
||||
echo -e "${BLUE}Stopping and removing the CodeXchange AI container...${NC}" |
||||
$COMPOSE_CMD down |
||||
echo -e "${GREEN}Container stopped and removed.${NC}" |
||||
} |
||||
|
||||
# Display access information |
||||
display_access_info() { |
||||
echo -e "${GREEN}The CodeXchange AI is running!${NC}" |
||||
echo -e "Access the application at: ${BLUE}http://localhost:$PORT${NC}" |
||||
|
||||
# Check if port is custom and update info |
||||
if [ "$PORT" != "7860" ]; then |
||||
echo -e "Running on custom port: ${BLUE}$PORT${NC}" |
||||
fi |
||||
|
||||
# If running detached, provide instructions for logs |
||||
if [ "$DETACHED" = true ]; then |
||||
echo -e "Running in detached mode. Use ${YELLOW}$0 --logs${NC} to follow logs." |
||||
fi |
||||
|
||||
echo -e "To stop the application, press ${YELLOW}Ctrl+C${NC} or run ${YELLOW}$0 --stop${NC}" |
||||
} |
||||
|
||||
# Main function |
||||
main() { |
||||
display_banner |
||||
check_prerequisites |
||||
parse_arguments "$@" |
||||
|
||||
if [ "$DOWN" = true ]; then |
||||
down_container |
||||
exit 0 |
||||
fi |
||||
|
||||
if [ "$STOP" = true ]; then |
||||
stop_container |
||||
exit 0 |
||||
fi |
||||
|
||||
if [ "$RESTART" = true ]; then |
||||
restart_container |
||||
exit 0 |
||||
fi |
||||
|
||||
check_env_file |
||||
check_api_keys |
||||
|
||||
build_image |
||||
|
||||
if [ "$BUILD_ONLY" = false ]; then |
||||
run_container |
||||
|
||||
# Only display access info if not in detached mode or if following logs |
||||
if [ "$DETACHED" = false ] || [ "$FOLLOW_LOGS" = true ]; then |
||||
display_access_info |
||||
fi |
||||
else |
||||
echo -e "${GREEN}Build completed successfully. Use $0 to run the application.${NC}" |
||||
fi |
||||
} |
||||
|
||||
# Run main function with all arguments |
||||
main "$@" |
@ -0,0 +1,44 @@
|
||||
"""Runner script for the CodeXchange AI.""" |
||||
import sys |
||||
from pathlib import Path |
||||
from setuptools import setup, find_packages |
||||
|
||||
# Add src to Python path |
||||
src_path = Path(__file__).parent |
||||
sys.path.append(str(src_path)) |
||||
|
||||
from src.ai_code_converter.main import main |
||||
from src.ai_code_converter.models.ai_streaming import AIModelStreamer |
||||
from src.ai_code_converter.core.code_execution import CodeExecutor |
||||
from src.ai_code_converter.core.language_detection import LanguageDetector |
||||
from src.ai_code_converter.core.file_utils import FileHandler |
||||
from src.ai_code_converter.config import ( |
||||
CUSTOM_CSS, |
||||
LANGUAGE_MAPPING, |
||||
MODELS, |
||||
SUPPORTED_LANGUAGES, |
||||
OPENAI_MODEL, |
||||
CLAUDE_MODEL, |
||||
DEEPSEEK_MODEL, |
||||
GEMINI_MODEL, |
||||
GROQ_MODEL |
||||
) |
||||
|
||||
if __name__ == "__main__": |
||||
main() |
||||
|
||||
setup( |
||||
name="ai_code_converter", |
||||
version="0.1.0", |
||||
packages=find_packages(where="src"), |
||||
package_dir={"": "src"}, |
||||
install_requires=[ |
||||
"gradio>=4.0.0", |
||||
"openai>=1.0.0", |
||||
"anthropic>=0.3.0", |
||||
"google-generativeai>=0.1.0", |
||||
"python-dotenv>=1.0.0", |
||||
"jinja2>=3.0.0" |
||||
], |
||||
python_requires=">=3.8", |
||||
) |
@ -0,0 +1,19 @@
|
||||
from setuptools import setup, find_packages |
||||
|
||||
setup( |
||||
name="ai_code_converter", |
||||
version="1.0.0", |
||||
packages=find_packages(), |
||||
package_data={ |
||||
'src.ai_code_converter': ['template.j2'], |
||||
}, |
||||
install_requires=[ |
||||
'gradio', |
||||
'openai', |
||||
'anthropic', |
||||
'google-generativeai', |
||||
'python-dotenv', |
||||
'jinja2', |
||||
], |
||||
python_requires='>=3.10', |
||||
) |
@ -0,0 +1 @@
|
||||
"""CodeXchange AI - Application""" |
@ -0,0 +1,3 @@
|
||||
"""CodeXchange AI - package.""" |
||||
|
||||
__version__ = "1.0.0" |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,443 @@
|
||||
"""Configuration settings for the CodeXchange AI application.""" |
||||
|
||||
# Model configurations |
||||
OPENAI_MODEL = "gpt-4o-mini" |
||||
CLAUDE_MODEL = "claude-3-5-sonnet-20241022" |
||||
DEEPSEEK_MODEL = "deepseek-chat" |
||||
GEMINI_MODEL = "gemini-1.5-flash" |
||||
GROQ_MODEL = "llama3-70b-8192" |
||||
|
||||
# Supported languages and models |
||||
SUPPORTED_LANGUAGES = ["Python", "Julia", "JavaScript", "Go", "Java", "C++", "Ruby", "Swift", "Rust", "C#", "TypeScript", "R", "Perl", "Lua", "PHP", "Kotlin", "SQL"] |
||||
MODELS = ["GPT", "Claude", "Gemini", "DeepSeek", "GROQ"] |
||||
|
||||
# Language mapping for syntax highlighting |
||||
LANGUAGE_MAPPING = { |
||||
"Python": "python", |
||||
"JavaScript": "javascript", |
||||
"Java": "python", |
||||
"C++": "cpp", |
||||
"Julia": "python", |
||||
"Go": "c", |
||||
"Ruby": "python", |
||||
"Swift": "python", |
||||
"Rust": "python", |
||||
"C#": "python", |
||||
"TypeScript": "typescript", |
||||
"R": "r", |
||||
"Perl": "python", |
||||
"Lua": "python", |
||||
"PHP": "python", |
||||
"Kotlin": "python", |
||||
"SQL": "sql" |
||||
} |
||||
|
||||
# File extensions for each language |
||||
LANGUAGE_FILE_EXTENSIONS = { |
||||
"Python": ".py", |
||||
"JavaScript": ".js", |
||||
"Java": ".java", |
||||
"C++": ".cpp", |
||||
"Julia": ".jl", |
||||
"Go": ".go", |
||||
"Ruby": ".rb", |
||||
"Swift": ".swift", |
||||
"Rust": ".rs", |
||||
"C#": ".cs", |
||||
"TypeScript": ".ts", |
||||
"R": ".r", |
||||
"Perl": ".pl", |
||||
"Lua": ".lua", |
||||
"PHP": ".php", |
||||
"Kotlin": ".kt", |
||||
"SQL": ".sql" |
||||
} |
||||
|
||||
# Documentation styles available for each language |
||||
DOCUMENT_STYLES = { |
||||
"Python": [ |
||||
{"value": "standard", "label": "Standard (PEP 257)"}, |
||||
{"value": "google", "label": "Google Style"}, |
||||
{"value": "numpy", "label": "NumPy Style"} |
||||
], |
||||
"Julia": [ |
||||
{"value": "standard", "label": "Standard"}, |
||||
{"value": "docsystem", "label": "Documenter.jl Style"} |
||||
], |
||||
"JavaScript": [ |
||||
{"value": "standard", "label": "Standard"}, |
||||
{"value": "jsdoc", "label": "JSDoc Style"}, |
||||
{"value": "tsdoc", "label": "TSDoc Style"} |
||||
], |
||||
"Go": [ |
||||
{"value": "standard", "label": "Standard"}, |
||||
{"value": "godoc", "label": "GoDoc Style"} |
||||
], |
||||
"Java": [ |
||||
{"value": "standard", "label": "Standard"}, |
||||
{"value": "javadoc", "label": "JavaDoc Style"} |
||||
], |
||||
"C++": [ |
||||
{"value": "standard", "label": "Standard"}, |
||||
{"value": "doxygen", "label": "Doxygen Style"} |
||||
], |
||||
"Ruby": [ |
||||
{"value": "standard", "label": "Standard"}, |
||||
{"value": "yard", "label": "YARD Style"}, |
||||
{"value": "rdoc", "label": "RDoc Style"} |
||||
], |
||||
"Swift": [ |
||||
{"value": "standard", "label": "Standard"}, |
||||
{"value": "markup", "label": "Swift Markup"} |
||||
], |
||||
"Rust": [ |
||||
{"value": "standard", "label": "Standard"}, |
||||
{"value": "rustdoc", "label": "Rustdoc Style"} |
||||
], |
||||
"C#": [ |
||||
{"value": "standard", "label": "Standard"}, |
||||
{"value": "xmldoc", "label": "XML Documentation"} |
||||
], |
||||
"TypeScript": [ |
||||
{"value": "standard", "label": "Standard"}, |
||||
{"value": "tsdoc", "label": "TSDoc Style"} |
||||
], |
||||
"R": [ |
||||
{"value": "standard", "label": "Standard"}, |
||||
{"value": "roxygen2", "label": "Roxygen2 Style"} |
||||
], |
||||
"Perl": [ |
||||
{"value": "standard", "label": "Standard"}, |
||||
{"value": "pod", "label": "POD Style"} |
||||
], |
||||
"Lua": [ |
||||
{"value": "standard", "label": "Standard"}, |
||||
{"value": "ldoc", "label": "LDoc Style"} |
||||
], |
||||
"PHP": [ |
||||
{"value": "standard", "label": "Standard"}, |
||||
{"value": "phpdoc", "label": "PHPDoc Style"} |
||||
], |
||||
"Kotlin": [ |
||||
{"value": "standard", "label": "Standard"}, |
||||
{"value": "kdoc", "label": "KDoc Style"} |
||||
], |
||||
"SQL": [ |
||||
{"value": "standard", "label": "Standard"}, |
||||
{"value": "block", "label": "Block Comment Style"} |
||||
] |
||||
} |
||||
|
||||
# Predefined code snippets for the UI |
||||
PREDEFINED_SNIPPETS = { |
||||
"Python Code Simple" : """ |
||||
import time |
||||
|
||||
def calculate(iterations, param1, param2): |
||||
result = 1.0 |
||||
for i in range(1, iterations+1): |
||||
j = i * param1 - param2 |
||||
result -= (1/j) |
||||
j = i * param1 + param2 |
||||
result += (1/j) |
||||
return result |
||||
|
||||
start_time = time.time() |
||||
result = calculate(100_000_000, 4, 1) * 4 |
||||
end_time = time.time() |
||||
|
||||
print(f"Result: {result:.12f}") |
||||
print(f"Execution Time: {(end_time - start_time):.6f} seconds") |
||||
""", |
||||
"Python Code": """import time |
||||
import random |
||||
from typing import List, Tuple |
||||
|
||||
class LCG: |
||||
#Linear Congruential Generator |
||||
def __init__(self, seed: int): |
||||
self.value = seed |
||||
self.a = 1664525 |
||||
self.c = 1013904223 |
||||
self.m = 2**32 |
||||
|
||||
def next(self) -> int: |
||||
# Generate next random number |
||||
self.value = (self.a * self.value + self.c) % self.m |
||||
return self.value |
||||
|
||||
def max_subarray_sum(n: int, seed: int, min_val: int, max_val: int) -> int: |
||||
# Calculate maximum subarray sum for array of random numbers |
||||
lcg = LCG(seed) |
||||
random_numbers = [] |
||||
|
||||
# Generate random numbers |
||||
for _ in range(n): |
||||
random_numbers.append((lcg.next() % (max_val - min_val + 1)) + min_val) |
||||
|
||||
max_sum = float('-inf') |
||||
|
||||
# Calculate max subarray sum |
||||
for i in range(n): |
||||
current_sum = 0 |
||||
for j in range(i, n): |
||||
current_sum += random_numbers[j] |
||||
if current_sum > max_sum: |
||||
max_sum = current_sum |
||||
|
||||
return max_sum |
||||
|
||||
def total_max_subarray_sum(n: int, initial_seed: int, min_val: int, max_val: int) -> int: |
||||
# Calculate total of maximum subarray sums over 20 iterations |
||||
total_sum = 0 |
||||
lcg = LCG(initial_seed) |
||||
|
||||
for _ in range(20): |
||||
seed = lcg.next() |
||||
total_sum += max_subarray_sum(n, seed, min_val, max_val) |
||||
|
||||
return total_sum |
||||
|
||||
# Main program |
||||
def main(): |
||||
n = 10000 |
||||
initial_seed = 42 |
||||
min_val = -10 |
||||
max_val = 10 |
||||
|
||||
start_time = time.time() |
||||
|
||||
result = total_max_subarray_sum(n, initial_seed, min_val, max_val) |
||||
|
||||
end_time = time.time() |
||||
duration = end_time - start_time |
||||
|
||||
print(f"Total Maximum Subarray Sum (20 runs): {result}") |
||||
print(f"Execution Time: {duration:.6f} seconds") |
||||
|
||||
if __name__ == "__main__": |
||||
main()""", |
||||
|
||||
"C++ Code": """#include <iostream> |
||||
#include <vector> |
||||
#include <limits> |
||||
#include <chrono> |
||||
|
||||
class LCG { |
||||
private: |
||||
uint32_t value; |
||||
const uint32_t a = 1664525; |
||||
const uint32_t c = 1013904223; |
||||
const uint32_t m = 1 << 32; |
||||
|
||||
public: |
||||
LCG(uint32_t seed) : value(seed) {} |
||||
|
||||
uint32_t next() { |
||||
value = (a * value + c) % m; |
||||
return value; |
||||
} |
||||
}; |
||||
|
||||
/* |
||||
* Calculates maximum subarray sum for array of random numbers |
||||
*/ |
||||
int64_t max_subarray_sum(int n, uint32_t seed, int min_val, int max_val) { |
||||
LCG lcg(seed); |
||||
std::vector<int> random_numbers(n); |
||||
|
||||
// Generate random numbers |
||||
for(int i = 0; i < n; i++) { |
||||
random_numbers[i] = (lcg.next() % (max_val - min_val + 1)) + min_val; |
||||
} |
||||
|
||||
int64_t max_sum = std::numeric_limits<int64_t>::min(); |
||||
|
||||
// Calculate max subarray sum |
||||
for(int i = 0; i < n; i++) { |
||||
int64_t current_sum = 0; |
||||
for(int j = i; j < n; j++) { |
||||
current_sum += random_numbers[j]; |
||||
if(current_sum > max_sum) { |
||||
max_sum = current_sum; |
||||
} |
||||
} |
||||
} |
||||
return max_sum; |
||||
} |
||||
|
||||
/* |
||||
* Calculates total of maximum subarray sums over 20 iterations |
||||
*/ |
||||
int64_t total_max_subarray_sum(int n, uint32_t initial_seed, int min_val, int max_val) { |
||||
int64_t total_sum = 0; |
||||
LCG lcg(initial_seed); |
||||
|
||||
for(int i = 0; i < 20; i++) { |
||||
uint32_t seed = lcg.next(); |
||||
total_sum += max_subarray_sum(n, seed, min_val, max_val); |
||||
} |
||||
return total_sum; |
||||
} |
||||
|
||||
int main() { |
||||
const int n = 10000; |
||||
const uint32_t initial_seed = 42; |
||||
const int min_val = -10; |
||||
const int max_val = 10; |
||||
|
||||
auto start_time = std::chrono::high_resolution_clock::now(); |
||||
|
||||
int64_t result = total_max_subarray_sum(n, initial_seed, min_val, max_val); |
||||
|
||||
auto end_time = std::chrono::high_resolution_clock::now(); |
||||
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time); |
||||
|
||||
std::cout << "Total Maximum Subarray Sum (20 runs): " << result << std::endl; |
||||
std::cout << "Execution Time: " << duration.count() / 1000000.0 << " seconds" << std::endl; |
||||
|
||||
return 0; |
||||
}""", |
||||
"Java Code": """import java.util.ArrayList; |
||||
|
||||
public class MaxSubarraySum { |
||||
/* Linear Congruential Generator implementation */ |
||||
static class LCG { |
||||
private long value; |
||||
private final long a = 1664525; |
||||
private final long c = 1013904223; |
||||
private final long m = 1L << 32; |
||||
|
||||
public LCG(long seed) { |
||||
this.value = seed; |
||||
} |
||||
|
||||
public long next() { |
||||
value = (a * value + c) % m; |
||||
return value; |
||||
} |
||||
} |
||||
|
||||
/* Calculates maximum subarray sum for given array of random numbers */ |
||||
private static long maxSubarraySum(int n, long seed, int minVal, int maxVal) { |
||||
LCG lcg = new LCG(seed); |
||||
ArrayList<Long> randomNumbers = new ArrayList<>(); |
||||
|
||||
// Generate random numbers |
||||
for (int i = 0; i < n; i++) { |
||||
long num = lcg.next() % (maxVal - minVal + 1) + minVal; |
||||
randomNumbers.add(num); |
||||
} |
||||
|
||||
long maxSum = Long.MIN_VALUE; |
||||
for (int i = 0; i < n; i++) { |
||||
long currentSum = 0; |
||||
for (int j = i; j < n; j++) { |
||||
currentSum += randomNumbers.get(j); |
||||
maxSum = Math.max(maxSum, currentSum); |
||||
} |
||||
} |
||||
return maxSum; |
||||
} |
||||
|
||||
/* Calculates total of maximum subarray sums for 20 different seeds */ |
||||
private static long totalMaxSubarraySum(int n, long initialSeed, int minVal, int maxVal) { |
||||
long totalSum = 0; |
||||
LCG lcg = new LCG(initialSeed); |
||||
|
||||
for (int i = 0; i < 20; i++) { |
||||
long seed = lcg.next(); |
||||
totalSum += maxSubarraySum(n, seed, minVal, maxVal); |
||||
} |
||||
return totalSum; |
||||
} |
||||
|
||||
public static void main(String[] args) { |
||||
// Parameters |
||||
int n = 10000; // Number of random numbers |
||||
long initialSeed = 42; // Initial seed for the LCG |
||||
int minVal = -10; // Minimum value of random numbers |
||||
int maxVal = 10; // Maximum value of random numbers |
||||
|
||||
// Timing the function |
||||
long startTime = System.nanoTime(); |
||||
long result = totalMaxSubarraySum(n, initialSeed, minVal, maxVal); |
||||
long endTime = System.nanoTime(); |
||||
|
||||
System.out.println("Total Maximum Subarray Sum (20 runs): " + result); |
||||
System.out.printf("Execution Time: %.6f seconds%n", (endTime - startTime) / 1e9); |
||||
} |
||||
}""" |
||||
} |
||||
|
||||
# Map snippets to their corresponding languages |
||||
SNIPPET_LANGUAGE_MAP = { |
||||
"Python Code": "Python", |
||||
"Python Code Simple": "Python", |
||||
"C++ Code": "C++", |
||||
"Java Code": "Java" |
||||
} |
||||
|
||||
# CSS styling |
||||
CUSTOM_CSS = """ |
||||
.code-container { |
||||
height: 30vh; |
||||
overflow: auto; |
||||
border-radius: 4px; |
||||
scrollbar-width: none; |
||||
-ms-overflow-style: none; |
||||
} |
||||
|
||||
.code-container::-webkit-scrollbar { |
||||
display: none !important; |
||||
width: 0 !important; |
||||
height: 0 !important; |
||||
background: transparent !important; |
||||
} |
||||
|
||||
.code-container .scroll-hide::-webkit-scrollbar, |
||||
.code-container > div::-webkit-scrollbar, |
||||
.code-container textarea::-webkit-scrollbar, |
||||
.code-container pre::-webkit-scrollbar, |
||||
.code-container code::-webkit-scrollbar { |
||||
display: none !important; |
||||
width: 0 !important; |
||||
height: 0 !important; |
||||
background: transparent !important; |
||||
} |
||||
|
||||
.code-container .language-select { |
||||
overflow: auto !important; |
||||
max-height: 100% !important; |
||||
} |
||||
|
||||
.accordion { |
||||
margin-top: 1rem !important; |
||||
} |
||||
|
||||
.error-accordion { |
||||
margin: 10px 0; |
||||
border: 2px solid #ff4444 !important; |
||||
border-radius: 4px !important; |
||||
background-color: #ffffff !important; |
||||
} |
||||
|
||||
.error-message { |
||||
color: #ff4444; |
||||
font-weight: bold; |
||||
font-size: 16px; |
||||
padding: 10px; |
||||
} |
||||
|
||||
.gradio-container { |
||||
padding-top: 1rem; |
||||
} |
||||
|
||||
.header-text { |
||||
text-align: center; |
||||
font-size: 2rem; |
||||
font-color: #283042; |
||||
font-weight: bold; |
||||
margin-bottom: 1rem; |
||||
} |
||||
""" |
@ -0,0 +1 @@
|
||||
"""Core functionality modules.""" |
@ -0,0 +1,631 @@
|
||||
"""Module for executing code in different programming languages.""" |
||||
|
||||
import contextlib |
||||
import io |
||||
import logging |
||||
import os |
||||
import re |
||||
import subprocess |
||||
import tempfile |
||||
from typing import Optional |
||||
from datetime import datetime |
||||
from src.ai_code_converter.utils.logger import setup_logger |
||||
from pathlib import Path |
||||
|
||||
# Initialize logger for this module |
||||
logger = setup_logger(__name__) |
||||
|
||||
class CodeExecutor: |
||||
"""Class for executing code in various programming languages.""" |
||||
|
||||
def __init__(self): |
||||
"""Initialize the code executor.""" |
||||
logger.info("Initializing CodeExecutor") |
||||
self.executors = { |
||||
"Python": self.execute_python, |
||||
"JavaScript": self.execute_javascript, |
||||
"Java": self.execute_java, |
||||
"C++": self.execute_cpp, |
||||
"Julia": self.execute_julia, |
||||
"Go": self.execute_go, |
||||
"Perl": self.execute_perl, |
||||
"Lua": self.execute_lua, |
||||
"PHP": self.execute_php, |
||||
"Kotlin": self.execute_kotlin, |
||||
"SQL": self.execute_sql, |
||||
"R": self.execute_r, |
||||
"Ruby": self.execute_ruby, |
||||
"Swift": self.execute_swift, |
||||
"Rust": self.execute_rust, |
||||
"C#": self.execute_csharp, |
||||
"TypeScript": self.execute_typescript |
||||
} |
||||
|
||||
def execute(self, code: str, language: str) -> tuple[str, Optional[bytes]]: |
||||
"""Execute code with detailed logging.""" |
||||
logger.info("="*50) |
||||
logger.info(f"STARTING CODE EXECUTION: {language}") |
||||
logger.info("="*50) |
||||
logger.info(f"Code length: {len(code)} characters") |
||||
|
||||
if not code: |
||||
logger.warning("No code provided for execution") |
||||
return "No code to execute", None |
||||
|
||||
executor = self.executors.get(language) |
||||
if not executor: |
||||
logger.error(f"No executor found for language: {language}") |
||||
return f"Execution not implemented for {language}", None |
||||
|
||||
try: |
||||
logger.info(f"Executing {language} code") |
||||
start_time = datetime.now() |
||||
|
||||
output, binary = executor(code) |
||||
|
||||
execution_time = (datetime.now() - start_time).total_seconds() |
||||
logger.info(f"Execution completed in {execution_time:.2f} seconds") |
||||
logger.info(f"Output length: {len(output)} characters") |
||||
if binary: |
||||
logger.info(f"Binary size: {len(binary)} bytes") |
||||
logger.info("="*50) |
||||
|
||||
return f"{output}\nExecution completed in {execution_time:.2f} seconds", binary |
||||
|
||||
except Exception as e: |
||||
logger.error(f"Error executing {language} code", exc_info=True) |
||||
logger.info("="*50) |
||||
return f"Error: {str(e)}", None |
||||
|
||||
def execute_python(self, code: str) -> tuple[str, Optional[bytes]]: |
||||
"""Execute Python code in a safe environment.""" |
||||
output = io.StringIO() |
||||
with contextlib.redirect_stdout(output): |
||||
try: |
||||
# Create a shared namespace for globals and locals |
||||
namespace = {} |
||||
|
||||
# Execute the code with shared namespace |
||||
exec(code, namespace, namespace) |
||||
|
||||
# Get any stored output |
||||
execution_output = output.getvalue() |
||||
|
||||
# If there's a result variable, append it to output |
||||
if '_result' in namespace: |
||||
execution_output += str(namespace['_result']) |
||||
|
||||
return execution_output, None |
||||
except Exception as e: |
||||
logger.error(f"Python execution error: {str(e)}", exc_info=True) |
||||
return f"Error: {str(e)}", None |
||||
finally: |
||||
output.close() |
||||
|
||||
def execute_javascript(self, code: str) -> tuple[str, Optional[bytes]]: |
||||
"""Execute JavaScript code using Node.js.""" |
||||
with tempfile.NamedTemporaryFile(suffix='.js', mode='w', delete=False) as f: |
||||
f.write(code) |
||||
js_file = f.name |
||||
|
||||
try: |
||||
result = subprocess.run( |
||||
["node", js_file], |
||||
capture_output=True, |
||||
text=True, |
||||
check=True |
||||
) |
||||
return result.stdout, None |
||||
except subprocess.CalledProcessError as e: |
||||
return f"Error: {e.stderr}", None |
||||
except Exception as e: |
||||
return f"Error: {str(e)}", None |
||||
finally: |
||||
os.unlink(js_file) |
||||
|
||||
def execute_julia(self, code: str) -> tuple[str, Optional[bytes]]: |
||||
"""Execute Julia code.""" |
||||
with tempfile.NamedTemporaryFile(suffix='.jl', mode='w', delete=False) as f: |
||||
f.write(code) |
||||
jl_file = f.name |
||||
|
||||
try: |
||||
result = subprocess.run( |
||||
["julia", jl_file], |
||||
capture_output=True, |
||||
text=True, |
||||
check=True |
||||
) |
||||
return result.stdout, None |
||||
except subprocess.CalledProcessError as e: |
||||
return f"Error: {e.stderr}", None |
||||
except Exception as e: |
||||
return f"Error: {str(e)}", None |
||||
finally: |
||||
os.unlink(jl_file) |
||||
|
||||
def execute_cpp(self, code: str) -> tuple[str, Optional[bytes]]: |
||||
"""Compile and execute C++ code.""" |
||||
with tempfile.NamedTemporaryFile(suffix='.cpp', mode='w', delete=False) as f: |
||||
f.write(code) |
||||
cpp_file = f.name |
||||
|
||||
try: |
||||
# Compile |
||||
exe_file = cpp_file[:-4] # Remove .cpp |
||||
if os.name == 'nt': # Windows |
||||
exe_file += '.exe' |
||||
|
||||
compile_result = subprocess.run( |
||||
["g++", cpp_file, "-o", exe_file], |
||||
capture_output=True, |
||||
text=True, |
||||
check=True |
||||
) |
||||
|
||||
# Execute |
||||
run_result = subprocess.run( |
||||
[exe_file], |
||||
capture_output=True, |
||||
text=True, |
||||
check=True |
||||
) |
||||
|
||||
# Read the compiled binary |
||||
with open(exe_file, 'rb') as f: |
||||
compiled_binary = f.read() |
||||
|
||||
return run_result.stdout, compiled_binary |
||||
|
||||
except subprocess.CalledProcessError as e: |
||||
return f"Error: {e.stderr}", None |
||||
except Exception as e: |
||||
return f"Error: {str(e)}", None |
||||
finally: |
||||
os.unlink(cpp_file) |
||||
if os.path.exists(exe_file): |
||||
os.unlink(exe_file) |
||||
|
||||
def execute_java(self, code: str) -> tuple[str, Optional[bytes]]: |
||||
"""Compile and execute Java code.""" |
||||
logger.info("Starting Java code execution") |
||||
|
||||
# Create a temporary directory with proper permissions |
||||
with tempfile.TemporaryDirectory() as temp_dir: |
||||
try: |
||||
# Extract class name |
||||
class_match = re.search(r'public\s+class\s+(\w+)', code) |
||||
if not class_match: |
||||
logger.error("Could not find public class name in Java code") |
||||
return "Error: Could not find public class name", None |
||||
|
||||
class_name = class_match.group(1) |
||||
temp_path = Path(temp_dir) |
||||
java_file = temp_path / f"{class_name}.java" |
||||
class_file = temp_path / f"{class_name}.class" |
||||
|
||||
# Write code to file |
||||
java_file.write_text(code) |
||||
logger.info(f"Wrote Java source to {java_file}") |
||||
|
||||
# Compile |
||||
logger.info("Compiling Java code") |
||||
compile_result = subprocess.run( |
||||
["javac", str(java_file)], |
||||
capture_output=True, |
||||
text=True, |
||||
check=True, |
||||
cwd=temp_dir # Set working directory to temp_dir |
||||
) |
||||
logger.info("Java compilation successful") |
||||
|
||||
# Verify class file exists |
||||
if not class_file.exists(): |
||||
logger.error(f"Class file {class_file} not found after compilation") |
||||
return "Error: Compilation failed to produce class file", None |
||||
|
||||
# Read compiled bytecode |
||||
compiled_binary = class_file.read_bytes() |
||||
logger.info(f"Read compiled binary, size: {len(compiled_binary)} bytes") |
||||
|
||||
# Execute |
||||
logger.info("Executing Java code") |
||||
run_result = subprocess.run( |
||||
["java", class_name], |
||||
capture_output=True, |
||||
text=True, |
||||
check=True, |
||||
cwd=temp_dir # Set working directory to temp_dir |
||||
) |
||||
logger.info("Java execution successful") |
||||
|
||||
# Return both output and compiled binary |
||||
return run_result.stdout, compiled_binary |
||||
|
||||
except subprocess.CalledProcessError as e: |
||||
logger.error(f"Java compilation/execution error: {e.stderr}") |
||||
return f"Error: {e.stderr}", None |
||||
except Exception as e: |
||||
logger.error(f"Unexpected error in Java execution: {str(e)}", exc_info=True) |
||||
return f"Error: {str(e)}", None |
||||
|
||||
def execute_go(self, code: str) -> tuple[str, Optional[bytes]]: |
||||
"""Execute Go code.""" |
||||
with tempfile.NamedTemporaryFile(suffix='.go', mode='w', delete=False) as f: |
||||
f.write(code) |
||||
go_file = f.name |
||||
|
||||
try: |
||||
# Compile first |
||||
exe_file = go_file[:-3] # Remove .go |
||||
if os.name == 'nt': |
||||
exe_file += '.exe' |
||||
|
||||
compile_result = subprocess.run( |
||||
["go", "build", "-o", exe_file, go_file], |
||||
capture_output=True, |
||||
text=True, |
||||
check=True |
||||
) |
||||
|
||||
# Read compiled binary |
||||
with open(exe_file, 'rb') as f: |
||||
compiled_binary = f.read() |
||||
|
||||
# Execute |
||||
run_result = subprocess.run( |
||||
[exe_file], |
||||
capture_output=True, |
||||
text=True, |
||||
check=True |
||||
) |
||||
return run_result.stdout, compiled_binary |
||||
|
||||
except subprocess.CalledProcessError as e: |
||||
return f"Error: {e.stderr}", None |
||||
except Exception as e: |
||||
return f"Error: {str(e)}", None |
||||
finally: |
||||
os.unlink(go_file) |
||||
if os.path.exists(exe_file): |
||||
os.unlink(exe_file) |
||||
|
||||
def execute_perl(self, code: str) -> tuple[str, Optional[bytes]]: |
||||
"""Execute Perl code.""" |
||||
with tempfile.NamedTemporaryFile(suffix='.pl', mode='w', delete=False) as f: |
||||
f.write(code) |
||||
pl_file = f.name |
||||
|
||||
try: |
||||
result = subprocess.run( |
||||
["perl", pl_file], |
||||
capture_output=True, |
||||
text=True, |
||||
check=True |
||||
) |
||||
return result.stdout, None |
||||
except subprocess.CalledProcessError as e: |
||||
return f"Error: {e.stderr}", None |
||||
except Exception as e: |
||||
return f"Error: {str(e)}", None |
||||
finally: |
||||
os.unlink(pl_file) |
||||
|
||||
def execute_lua(self, code: str) -> tuple[str, Optional[bytes]]: |
||||
"""Execute Lua code.""" |
||||
with tempfile.NamedTemporaryFile(suffix='.lua', mode='w', delete=False) as f: |
||||
f.write(code) |
||||
lua_file = f.name |
||||
|
||||
try: |
||||
result = subprocess.run( |
||||
["lua", lua_file], |
||||
capture_output=True, |
||||
text=True, |
||||
check=True |
||||
) |
||||
return result.stdout, None |
||||
except subprocess.CalledProcessError as e: |
||||
return f"Error: {e.stderr}", None |
||||
except Exception as e: |
||||
return f"Error: {str(e)}", None |
||||
finally: |
||||
os.unlink(lua_file) |
||||
|
||||
def execute_php(self, code: str) -> tuple[str, Optional[bytes]]: |
||||
"""Execute PHP code.""" |
||||
with tempfile.NamedTemporaryFile(suffix='.php', mode='w', delete=False) as f: |
||||
f.write(code) |
||||
php_file = f.name |
||||
|
||||
try: |
||||
result = subprocess.run( |
||||
["php", php_file], |
||||
capture_output=True, |
||||
text=True, |
||||
check=True |
||||
) |
||||
return result.stdout, None |
||||
except subprocess.CalledProcessError as e: |
||||
return f"Error: {e.stderr}", None |
||||
except Exception as e: |
||||
return f"Error: {str(e)}", None |
||||
finally: |
||||
os.unlink(php_file) |
||||
|
||||
def execute_kotlin(self, code: str) -> tuple[str, Optional[bytes]]: |
||||
"""Compile and execute Kotlin code.""" |
||||
with tempfile.NamedTemporaryFile(suffix='.kt', mode='w', delete=False) as f: |
||||
f.write(code) |
||||
kt_file = f.name |
||||
|
||||
try: |
||||
# Extract main class name (best effort) |
||||
class_match = re.search(r'class\s+(\w+)', code) |
||||
class_name = class_match.group(1) if class_match else "MainKt" |
||||
|
||||
# Compile |
||||
jar_file = kt_file[:-3] + ".jar" |
||||
compile_result = subprocess.run( |
||||
["kotlinc", kt_file, "-include-runtime", "-d", jar_file], |
||||
capture_output=True, |
||||
text=True, |
||||
check=True |
||||
) |
||||
|
||||
# Read compiled bytecode |
||||
with open(jar_file, 'rb') as f: |
||||
compiled_binary = f.read() |
||||
|
||||
# Execute |
||||
run_result = subprocess.run( |
||||
["java", "-jar", jar_file], |
||||
capture_output=True, |
||||
text=True, |
||||
check=True |
||||
) |
||||
|
||||
return run_result.stdout, compiled_binary |
||||
except subprocess.CalledProcessError as e: |
||||
return f"Error: {e.stderr}", None |
||||
except Exception as e: |
||||
return f"Error: {str(e)}", None |
||||
finally: |
||||
os.unlink(kt_file) |
||||
jar_file = kt_file[:-3] + ".jar" |
||||
if os.path.exists(jar_file): |
||||
os.unlink(jar_file) |
||||
|
||||
def execute_sql(self, code: str) -> tuple[str, Optional[bytes]]: |
||||
"""Execute SQL code using SQLite.""" |
||||
# Create a temporary database file |
||||
db_file = tempfile.NamedTemporaryFile(suffix='.db', delete=False).name |
||||
|
||||
try: |
||||
# Write SQL directly to the sqlite3 process via stdin |
||||
process = subprocess.Popen( |
||||
["sqlite3", db_file], |
||||
stdin=subprocess.PIPE, |
||||
stdout=subprocess.PIPE, |
||||
stderr=subprocess.PIPE, |
||||
text=True |
||||
) |
||||
|
||||
# Send the SQL code to sqlite3 |
||||
stdout, stderr = process.communicate(input=code) |
||||
|
||||
if process.returncode != 0: |
||||
return f"Error: {stderr}", None |
||||
|
||||
# For SQL, we'll also run a simple query to show tables |
||||
tables_result = subprocess.run( |
||||
["sqlite3", db_file, ".tables"], |
||||
capture_output=True, |
||||
text=True, |
||||
check=False |
||||
) |
||||
|
||||
# Combine the results |
||||
output = stdout |
||||
if tables_result.returncode == 0 and tables_result.stdout.strip(): |
||||
output += "\n\nTables in database:\n" + tables_result.stdout |
||||
|
||||
# For each table, show schema |
||||
for table in tables_result.stdout.split(): |
||||
schema_result = subprocess.run( |
||||
["sqlite3", db_file, f".schema {table}"], |
||||
capture_output=True, |
||||
text=True, |
||||
check=False |
||||
) |
||||
if schema_result.returncode == 0: |
||||
output += "\n" + schema_result.stdout |
||||
|
||||
return output, None |
||||
except Exception as e: |
||||
return f"Error: {str(e)}", None |
||||
finally: |
||||
if os.path.exists(db_file): |
||||
os.unlink(db_file) |
||||
|
||||
def execute_r(self, code: str) -> tuple[str, Optional[bytes]]: |
||||
"""Execute R code.""" |
||||
with tempfile.NamedTemporaryFile(suffix='.R', mode='w', delete=False) as f: |
||||
f.write(code) |
||||
r_file = f.name |
||||
|
||||
try: |
||||
result = subprocess.run( |
||||
["Rscript", r_file], |
||||
capture_output=True, |
||||
text=True, |
||||
check=True |
||||
) |
||||
return result.stdout, None |
||||
except subprocess.CalledProcessError as e: |
||||
return f"Error: {e.stderr}", None |
||||
except Exception as e: |
||||
return f"Error: {str(e)}", None |
||||
finally: |
||||
os.unlink(r_file) |
||||
|
||||
def execute_ruby(self, code: str) -> tuple[str, Optional[bytes]]: |
||||
"""Execute Ruby code.""" |
||||
with tempfile.NamedTemporaryFile(suffix='.rb', mode='w', delete=False) as f: |
||||
f.write(code) |
||||
rb_file = f.name |
||||
|
||||
try: |
||||
result = subprocess.run( |
||||
["ruby", rb_file], |
||||
capture_output=True, |
||||
text=True, |
||||
check=True |
||||
) |
||||
return result.stdout, None |
||||
except subprocess.CalledProcessError as e: |
||||
return f"Error: {e.stderr}", None |
||||
except Exception as e: |
||||
return f"Error: {str(e)}", None |
||||
finally: |
||||
os.unlink(rb_file) |
||||
|
||||
def execute_swift(self, code: str) -> tuple[str, Optional[bytes]]: |
||||
"""Execute Swift code.""" |
||||
with tempfile.NamedTemporaryFile(suffix='.swift', mode='w', delete=False) as f: |
||||
f.write(code) |
||||
swift_file = f.name |
||||
|
||||
try: |
||||
result = subprocess.run( |
||||
["swift", swift_file], |
||||
capture_output=True, |
||||
text=True, |
||||
check=True |
||||
) |
||||
return result.stdout, None |
||||
except subprocess.CalledProcessError as e: |
||||
return f"Error: {e.stderr}", None |
||||
except Exception as e: |
||||
return f"Error: {str(e)}", None |
||||
finally: |
||||
os.unlink(swift_file) |
||||
|
||||
def execute_rust(self, code: str) -> tuple[str, Optional[bytes]]: |
||||
"""Compile and execute Rust code.""" |
||||
# Create a temporary directory for Rust project |
||||
with tempfile.TemporaryDirectory() as temp_dir: |
||||
# Create main.rs file |
||||
main_rs = os.path.join(temp_dir, "main.rs") |
||||
with open(main_rs, 'w') as f: |
||||
f.write(code) |
||||
|
||||
try: |
||||
# Compile |
||||
exe_file = os.path.join(temp_dir, "rustapp") |
||||
compile_result = subprocess.run( |
||||
["rustc", main_rs, "-o", exe_file], |
||||
capture_output=True, |
||||
text=True, |
||||
check=True |
||||
) |
||||
|
||||
# Read compiled binary |
||||
with open(exe_file, 'rb') as f: |
||||
compiled_binary = f.read() |
||||
|
||||
# Execute |
||||
run_result = subprocess.run( |
||||
[exe_file], |
||||
capture_output=True, |
||||
text=True, |
||||
check=True |
||||
) |
||||
|
||||
return run_result.stdout, compiled_binary |
||||
except subprocess.CalledProcessError as e: |
||||
return f"Error: {e.stderr}", None |
||||
except Exception as e: |
||||
return f"Error: {str(e)}", None |
||||
|
||||
def execute_csharp(self, code: str) -> tuple[str, Optional[bytes]]: |
||||
"""Compile and execute C# code.""" |
||||
with tempfile.NamedTemporaryFile(suffix='.cs', mode='w', delete=False) as f: |
||||
f.write(code) |
||||
cs_file = f.name |
||||
|
||||
try: |
||||
# Compile to executable |
||||
exe_file = cs_file[:-3] + ".exe" |
||||
compile_result = subprocess.run( |
||||
["mono-csc", cs_file, "-out:" + exe_file], |
||||
capture_output=True, |
||||
text=True, |
||||
check=True |
||||
) |
||||
|
||||
# Read compiled binary |
||||
with open(exe_file, 'rb') as f: |
||||
compiled_binary = f.read() |
||||
|
||||
# Execute |
||||
if os.name == 'nt': # Windows |
||||
run_result = subprocess.run( |
||||
[exe_file], |
||||
capture_output=True, |
||||
text=True, |
||||
check=True |
||||
) |
||||
else: # Unix-like |
||||
run_result = subprocess.run( |
||||
["mono", exe_file], |
||||
capture_output=True, |
||||
text=True, |
||||
check=True |
||||
) |
||||
|
||||
return run_result.stdout, compiled_binary |
||||
except subprocess.CalledProcessError as e: |
||||
return f"Error: {e.stderr}", None |
||||
except Exception as e: |
||||
return f"Error: {str(e)}", None |
||||
finally: |
||||
os.unlink(cs_file) |
||||
exe_file = cs_file[:-3] + ".exe" |
||||
if os.path.exists(exe_file): |
||||
os.unlink(exe_file) |
||||
|
||||
def execute_typescript(self, code: str) -> tuple[str, Optional[bytes]]: |
||||
"""Compile and execute TypeScript code.""" |
||||
with tempfile.NamedTemporaryFile(suffix='.ts', mode='w', delete=False) as f: |
||||
f.write(code) |
||||
ts_file = f.name |
||||
|
||||
try: |
||||
# Compile TypeScript to JavaScript |
||||
js_file = ts_file[:-3] + ".js" |
||||
compile_result = subprocess.run( |
||||
["tsc", ts_file, "--outFile", js_file], |
||||
capture_output=True, |
||||
text=True, |
||||
check=True |
||||
) |
||||
|
||||
# Execute the compiled JavaScript |
||||
run_result = subprocess.run( |
||||
["node", js_file], |
||||
capture_output=True, |
||||
text=True, |
||||
check=True |
||||
) |
||||
|
||||
return run_result.stdout, None |
||||
except subprocess.CalledProcessError as e: |
||||
return f"Error: {e.stderr}", None |
||||
except Exception as e: |
||||
return f"Error: {str(e)}", None |
||||
finally: |
||||
os.unlink(ts_file) |
||||
js_file = ts_file[:-3] + ".js" |
||||
if os.path.exists(js_file): |
||||
os.unlink(js_file) |
@ -0,0 +1,250 @@
|
||||
"""Module for handling file operations.""" |
||||
|
||||
import logging |
||||
import tempfile |
||||
import zipfile |
||||
import platform |
||||
from pathlib import Path |
||||
from typing import Optional, Tuple |
||||
import os |
||||
import shutil |
||||
import gradio as gr |
||||
from datetime import datetime |
||||
|
||||
from src.ai_code_converter.utils.logger import setup_logger |
||||
|
||||
logger = setup_logger(__name__) |
||||
|
||||
class FileHandler: |
||||
"""Class for handling file operations.""" |
||||
|
||||
def create_readme(self, language: str, files: list[str]) -> str: |
||||
"""Create a README file with compilation instructions.""" |
||||
system_info = platform.uname() |
||||
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") |
||||
|
||||
readme = f"""# {language} Code Compilation Instructions |
||||
|
||||
Generated on: {timestamp} |
||||
|
||||
## Compilation Environment |
||||
- OS: {system_info.system} |
||||
- Architecture: {system_info.machine} |
||||
- Platform: {system_info.version} |
||||
|
||||
## Files Included |
||||
{chr(10).join(f"- {file}" for file in files)} |
||||
|
||||
## Compilation Instructions |
||||
|
||||
""" |
||||
if language == "C++": |
||||
readme += """### Windows |
||||
1. Install MinGW or Visual Studio with C++ support |
||||
2. Open command prompt in this directory |
||||
3. Run: `g++ main.cpp -o program.exe` |
||||
4. Execute: `program.exe` |
||||
|
||||
### Linux |
||||
1. Install GCC: `sudo apt-get install build-essential` (Ubuntu/Debian) |
||||
2. Open terminal in this directory |
||||
3. Run: `g++ main.cpp -o program` |
||||
4. Execute: `./program` |
||||
|
||||
### macOS |
||||
1. Install Xcode Command Line Tools: `xcode-select --install` |
||||
2. Open terminal in this directory |
||||
3. Run: `g++ main.cpp -o program` |
||||
4. Execute: `./program` |
||||
""" |
||||
elif language == "Java": |
||||
readme += """### All Platforms (Windows/Linux/macOS) |
||||
1. Install JDK 11 or later |
||||
2. Open terminal/command prompt in this directory |
||||
3. Compile: `javac Main.java` |
||||
4. Run: `java Main` |
||||
|
||||
Note: The class name in the Java file must be 'Main' for these instructions. |
||||
""" |
||||
elif language == "Go": |
||||
readme += """### Windows |
||||
1. Install Go from https://golang.org/ |
||||
2. Open command prompt in this directory |
||||
3. Run: `go build main.go` |
||||
4. Execute: `main.exe` |
||||
|
||||
### Linux/macOS |
||||
1. Install Go: |
||||
- Linux: `sudo apt-get install golang` (Ubuntu/Debian) |
||||
- macOS: `brew install go` (using Homebrew) |
||||
2. Open terminal in this directory |
||||
3. Run: `go build main.go` |
||||
4. Execute: `./main` |
||||
""" |
||||
return readme |
||||
|
||||
def create_compilation_zip(self, code: str, language: str, compiled_code: Optional[bytes] = None) -> Tuple[Optional[str], Optional[str]]: |
||||
"""Create a zip file containing source, compiled files, and README.""" |
||||
try: |
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") |
||||
project_name = f"ai_code_converter_{language.lower()}_{timestamp}" |
||||
|
||||
# Create temporary directory |
||||
with tempfile.TemporaryDirectory() as temp_dir: |
||||
temp_dir_path = Path(temp_dir) |
||||
files_included = [] |
||||
|
||||
# Write source code with standardized names |
||||
if language == "C++": |
||||
source_file = temp_dir_path / "main.cpp" |
||||
compiled_file = temp_dir_path / ("main.exe" if os.name == 'nt' else "main") |
||||
files_included.extend(["main.cpp", "main.exe" if os.name == 'nt' else "main"]) |
||||
elif language == "Java": |
||||
source_file = temp_dir_path / "Main.java" |
||||
compiled_file = temp_dir_path / "Main.class" |
||||
files_included.extend(["Main.java", "Main.class"]) |
||||
elif language == "Go": |
||||
source_file = temp_dir_path / "main.go" |
||||
compiled_file = temp_dir_path / ("main.exe" if os.name == 'nt' else "main") |
||||
files_included.extend(["main.go", "main.exe" if os.name == 'nt' else "main"]) |
||||
else: |
||||
return None, None |
||||
|
||||
# Write source code |
||||
source_file.write_text(code) |
||||
|
||||
# Write compiled code if available |
||||
if compiled_code: |
||||
logger.info(f"Writing compiled binary: {compiled_file}") |
||||
try: |
||||
# Ensure the file is writable |
||||
compiled_file.parent.mkdir(parents=True, exist_ok=True) |
||||
compiled_file.write_bytes(compiled_code) |
||||
logger.info(f"Successfully wrote compiled binary: {compiled_file}") |
||||
except Exception as e: |
||||
logger.error(f"Error writing compiled binary: {e}", exc_info=True) |
||||
else: |
||||
logger.warning("No compiled code available") |
||||
|
||||
# Create README |
||||
readme_path = temp_dir_path / "README.md" |
||||
readme_content = self.create_readme(language, files_included) |
||||
readme_path.write_text(readme_content) |
||||
files_included.append("README.md") |
||||
|
||||
# Create zip file with descriptive name |
||||
zip_filename = f"{project_name}.zip" |
||||
zip_path = temp_dir_path / zip_filename |
||||
|
||||
# Create zip file |
||||
with zipfile.ZipFile(zip_path, 'w') as zf: |
||||
for file in files_included: |
||||
file_path = temp_dir_path / file |
||||
if file_path.exists(): |
||||
logger.info(f"Adding to zip: {file}") |
||||
zf.write(file_path, file_path.name) |
||||
else: |
||||
logger.warning(f"File not found for zip: {file}") |
||||
|
||||
# Create a permanent location for the zip file |
||||
downloads_dir = Path("downloads") |
||||
downloads_dir.mkdir(exist_ok=True) |
||||
|
||||
final_zip_path = downloads_dir / zip_filename |
||||
shutil.copy2(zip_path, final_zip_path) |
||||
|
||||
# Verify zip contents |
||||
with zipfile.ZipFile(final_zip_path, 'r') as zf: |
||||
logger.info(f"Zip file contents: {zf.namelist()}") |
||||
|
||||
return str(final_zip_path), zip_filename |
||||
|
||||
except Exception as e: |
||||
logger.error(f"Error creating compilation zip: {str(e)}", exc_info=True) |
||||
return None, None |
||||
|
||||
def prepare_download(self, code: str, language: str, compiled_code: Optional[bytes] = None) -> Tuple[Optional[str], Optional[str]]: |
||||
"""Prepare code for download with consistent naming.""" |
||||
try: |
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") |
||||
downloads_dir = Path("downloads") |
||||
downloads_dir.mkdir(exist_ok=True) |
||||
|
||||
# For compiled languages, create a zip with source and instructions |
||||
if language in ["C++", "Java", "Go"]: |
||||
logger.info(f"Creating compilation zip for {language}") |
||||
# Pass compiled_code directly as bytes |
||||
return self.create_compilation_zip( |
||||
code=code, |
||||
language=language, |
||||
compiled_code=compiled_code if isinstance(compiled_code, bytes) else None |
||||
) |
||||
|
||||
# For interpreted languages, create a single file with timestamp |
||||
extension = self._get_file_extension(language) |
||||
filename = f"ai_code_converter_{language.lower()}_{timestamp}{extension}" |
||||
file_path = downloads_dir / filename |
||||
|
||||
# Write the file |
||||
file_path.write_text(code) |
||||
return str(file_path), filename |
||||
|
||||
except Exception as e: |
||||
logger.error(f"Error preparing download: {str(e)}", exc_info=True) |
||||
return None, None |
||||
|
||||
def load_file(self, file_path: str) -> str: |
||||
"""Load code from a file.""" |
||||
try: |
||||
with open(file_path, 'r') as f: |
||||
return f.read() |
||||
except Exception as e: |
||||
logger.error(f"Error loading file: {str(e)}", exc_info=True) |
||||
raise |
||||
|
||||
def _get_file_extension(self, language: str) -> str: |
||||
"""Get file extension for a language.""" |
||||
extensions = { |
||||
"Python": ".py", |
||||
"JavaScript": ".js", |
||||
"Java": ".java", |
||||
"C++": ".cpp", |
||||
"Julia": ".jl", |
||||
"Go": ".go" |
||||
} |
||||
return extensions.get(language, ".txt") |
||||
|
||||
def handle_file_upload(self, file: gr.File) -> tuple[str, str]: |
||||
"""Handle file upload with detailed logging.""" |
||||
logger = logging.getLogger(__name__) |
||||
|
||||
if not file: |
||||
logger.warning("File upload attempted but no file was provided") |
||||
return "", "No file uploaded" |
||||
|
||||
try: |
||||
logger.info(f"Processing uploaded file: {file.name}") |
||||
logger.info(f"File size: {os.path.getsize(file.name)} bytes") |
||||
|
||||
# Create downloads directory if it doesn't exist |
||||
downloads_dir = Path("downloads") |
||||
downloads_dir.mkdir(exist_ok=True) |
||||
|
||||
# Copy uploaded file to downloads with timestamp |
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") |
||||
_, ext = os.path.splitext(file.name) |
||||
new_filename = f"ai_code_converter_upload_{timestamp}{ext}" |
||||
new_path = downloads_dir / new_filename |
||||
|
||||
with open(file.name, 'r') as src, open(new_path, 'w') as dst: |
||||
content = src.read() |
||||
dst.write(content) |
||||
|
||||
logger.info(f"File saved as: {new_path}") |
||||
logger.info(f"Content length: {len(content)} characters") |
||||
return content, None |
||||
|
||||
except Exception as e: |
||||
error_msg = f"Error loading file: {str(e)}" |
||||
logger.error(error_msg, exc_info=True) |
||||
return "", error_msg |
@ -0,0 +1,793 @@
|
||||
"""Module for detecting programming languages in code snippets.""" |
||||
|
||||
import re |
||||
import logging |
||||
from typing import Tuple |
||||
|
||||
logger = logging.getLogger(__name__) |
||||
|
||||
class LanguageDetector: |
||||
"""Class for detecting programming languages in code snippets.""" |
||||
|
||||
@staticmethod |
||||
def detect_python(code: str) -> bool: |
||||
"""Detect if code is Python.""" |
||||
patterns = [ |
||||
r'def\s+\w+\s*\([^)]*\)\s*:', # Function definition |
||||
r'import\s+[\w\s,]+', # Import statements |
||||
r'from\s+[\w.]+\s+import', # From import statements |
||||
r'print\s*\([^)]*\)', # Print statements |
||||
r':\s*$' # Line ending with colon |
||||
] |
||||
return any(re.search(pattern, code) for pattern in patterns) |
||||
|
||||
@staticmethod |
||||
def detect_javascript(code: str) -> bool: |
||||
"""Detect if code is JavaScript.""" |
||||
patterns = [ |
||||
r'function\s+\w+\s*\([^)]*\)', # Function declaration |
||||
r'const\s+\w+\s*=', # Const declaration |
||||
r'let\s+\w+\s*=', # Let declaration |
||||
r'var\s+\w+\s*=', # Var declaration |
||||
r'console\.(log|error|warn)' # Console methods |
||||
] |
||||
return any(re.search(pattern, code) for pattern in patterns) |
||||
|
||||
@staticmethod |
||||
def detect_java(code: str) -> bool: |
||||
"""Detect if code is Java.""" |
||||
patterns = [ |
||||
r'public\s+class\s+\w+', # Class declaration |
||||
r'public\s+static\s+void\s+main', # Main method |
||||
r'System\.(out|err)\.', # System output |
||||
r'private|protected|public', # Access modifiers |
||||
r'import\s+java\.' # Java imports |
||||
] |
||||
return any(re.search(pattern, code) for pattern in patterns) |
||||
|
||||
@staticmethod |
||||
def detect_cpp(code: str) -> bool: |
||||
"""Detect if code is C++.""" |
||||
patterns = [ |
||||
r'#include\s*<[^>]+>', # Include statements |
||||
r'std::\w+', # STD namespace usage |
||||
r'cout\s*<<', # Console output |
||||
r'cin\s*>>', # Console input |
||||
r'int\s+main\s*\(' # Main function |
||||
] |
||||
return any(re.search(pattern, code) for pattern in patterns) |
||||
|
||||
@staticmethod |
||||
def detect_julia(code: str) -> bool: |
||||
"""Detect if code is Julia.""" |
||||
patterns = [ |
||||
r'function\s+\w+\s*\([^)]*\)\s*end', # Function with end |
||||
r'println\(', # Print function |
||||
r'using\s+\w+', # Using statement |
||||
r'module\s+\w+', # Module declaration |
||||
r'struct\s+\w+' # Struct declaration |
||||
] |
||||
return any(re.search(pattern, code) for pattern in patterns) |
||||
|
||||
@staticmethod |
||||
def detect_go(code: str) -> bool: |
||||
"""Detect if code is Go.""" |
||||
patterns = [ |
||||
r'package\s+\w+', # Package declaration |
||||
r'func\s+\w+\s*\(', # Function declaration |
||||
r'import\s*\(', # Import block |
||||
r'fmt\.', # fmt package usage |
||||
r'type\s+\w+\s+struct' # Struct declaration |
||||
] |
||||
return any(re.search(pattern, code) for pattern in patterns) |
||||
|
||||
@staticmethod |
||||
def detect_ruby(code: str) -> bool: |
||||
"""Detect if code is Ruby.""" |
||||
patterns = [ |
||||
r'def\s+\w+\s*(?:\([^)]*\))?\s*$', # Method definition without end |
||||
r'class\s+\w+(?:\s*<\s*\w+)?\s*$', # Class definition without end |
||||
r'require\s+["\']\w+["\']', # Require statement |
||||
r'\b(?:puts|print)\s', # Output methods |
||||
r'\bdo\s*\|[^|]*\|', # Block with parameters |
||||
r'\bend\b', # End keyword |
||||
r':[a-zA-Z_]\w*\s*=>', # Symbol hash syntax |
||||
r'[a-zA-Z_]\w*:\s*[^,\s]' # New hash syntax |
||||
] |
||||
return any(re.search(pattern, code) for pattern in patterns) |
||||
|
||||
@staticmethod |
||||
def detect_swift(code: str) -> bool: |
||||
"""Detect if code is Swift.""" |
||||
patterns = [ |
||||
r'import\s+(?:Foundation|UIKit|SwiftUI)', # Common Swift imports |
||||
r'(?:var|let)\s+\w+\s*:\s*\w+', # Variable declaration with type |
||||
r'func\s+\w+\s*\([^)]*\)\s*(?:->\s*\w+)?\s*\{', # Function declaration |
||||
r'class\s+\w+(?:\s*:\s*\w+)?\s*\{', # Class declaration |
||||
r'struct\s+\w+\s*\{', # Struct declaration |
||||
r'@IBOutlet|@IBAction', # iOS annotations |
||||
r'guard\s+let', # Guard statement |
||||
r'if\s+let|if\s+var', # Optional binding |
||||
r'override\s+func', # Method override |
||||
r'\bimport\s+Swift\b', # Swift import |
||||
r'\?\?', # Nil coalescing operator |
||||
r'extension\s+\w+', # Extensions |
||||
r'protocol\s+\w+', # Protocols |
||||
r'enum\s+\w+\s*(?::\s*\w+)?\s*\{', # Enums |
||||
r'case\s+\w+(?:\(.*?\))?', # Enum cases |
||||
r'typealias\s+\w+', # Type aliases |
||||
r'init\s*\(', # Initializer |
||||
r'deinit\s*\{', # Deinitializer |
||||
r'\$\d+', # String interpolation |
||||
r'\bOptional<', # Optional type |
||||
r'\bas\?', # Type casting |
||||
r'\bas!', # Forced type casting |
||||
r'convenience\s+init', # Convenience initializer |
||||
r'required\s+init', # Required initializer |
||||
r'\bUInt\d*\b', # Swift integer types |
||||
r'\bInt\d*\b', # Swift integer types |
||||
r'\barray<', # Swift arrays |
||||
r'\bdictionary<', # Swift dictionaries |
||||
r'@escaping', # Escaping closures |
||||
r'\bweak\s+var', # Weak references |
||||
r'\bunowned\b' # Unowned references |
||||
] |
||||
return any(re.search(pattern, code, re.IGNORECASE) for pattern in patterns) |
||||
|
||||
@staticmethod |
||||
def detect_rust(code: str) -> bool: |
||||
"""Detect if code is Rust.""" |
||||
patterns = [ |
||||
r'fn\s+\w+\s*\([^)]*\)\s*(?:->\s*[^{]+)?\s*\{', # Function declaration |
||||
r'let\s+mut\s+\w+', # Mutable variable declaration |
||||
r'struct\s+\w+\s*\{[^}]*\}', # Struct definition |
||||
r'impl\s+\w+(?:\s+for\s+\w+)?', # Implementation block |
||||
r'use\s+[\w:]+', # Import/use statement |
||||
r'pub\s+(?:fn|struct|enum|mod)', # Public items |
||||
r'Vec<[^>]+>', # Vec generic type |
||||
r'match\s+\w+\s*\{', # Match expression |
||||
r'#\[\w+(?:\([^)]*\))?\]', # Attribute macros |
||||
r'\bResult<', # Result type |
||||
r'\bOption<', # Option type |
||||
r'\bmod\s+\w+', # Module declaration |
||||
r'&mut\s+\w+', # Mutable references |
||||
r'&\w+', # Immutable references |
||||
r'\|[^|]*\|\s*\{', # Closure syntax |
||||
r'::\s*[A-Z]\w+', # Path to types |
||||
r'::(?:<[^>]+>)?\s*\w+\(', # Method call with turbofish |
||||
r'enum\s+\w+\s*\{', # Enum definition |
||||
r'-\s*>\s*[\w<>:]+', # Return type arrow |
||||
r'async\s+fn', # Async functions |
||||
r'await', # Await syntax |
||||
r'move\s*\|', # Move closures |
||||
r'trait\s+\w+', # Trait definition |
||||
r'\bSome\(', # Some variant |
||||
r'\bNone\b', # None variant |
||||
r'\bOk\(', # Ok variant |
||||
r'\bErr\(', # Err variant |
||||
r'\bcrate::\w+', # Crate references |
||||
r'pub\(crate\)', # Crate visibility |
||||
r'\bdyn\s+\w+', # Dynamic dispatch |
||||
r'\bif\s+let\s+Some', # If let for Option |
||||
r'\bif\s+let\s+Ok' # If let for Result |
||||
] |
||||
return any(re.search(pattern, code, re.IGNORECASE) for pattern in patterns) |
||||
|
||||
@staticmethod |
||||
def detect_csharp(code: str) -> bool: |
||||
"""Detect if code is C#.""" |
||||
patterns = [ |
||||
r'using\s+[\w.]+;', # Using statement |
||||
r'namespace\s+[\w.]+', # Namespace declaration |
||||
r'(public|private|protected|internal)\s+(class|struct|interface|enum)', # Type declarations |
||||
r'(public|private|protected|internal)\s+[\w<>\[\]]+\s+\w+\s*\(', # Method declaration |
||||
r'Console\.(Write|WriteLine)', # Console output |
||||
r'\bvar\s+\w+\s*=', # Var keyword |
||||
r'new\s+\w+\s*\(', # Object instantiation |
||||
r'\bawait\s+', # Async/await |
||||
r'\btask<', # Task object |
||||
r'\bdynamic\b', # Dynamic type |
||||
r'\bstring\b', # String type |
||||
r'\$".*?\{.*?\}.*?"', # String interpolation with $ |
||||
r'\bIEnumerable<', # C# generics |
||||
r'\bList<', # C# collections |
||||
r'\bdictionary<', # C# collections |
||||
r'\bforeach\s*\(', # foreach loops |
||||
r'\bassert\.\w+\(', # Unit testing |
||||
r'\[\w+\]', # Attributes |
||||
r'\bdelegate\b', # Delegates |
||||
r'\bevent\b', # Events |
||||
r'\bpartial\b', # Partial classes |
||||
r'\bvirtual\b', # Virtual methods |
||||
r'\boverride\b', # Override methods |
||||
r'\?\s*\w+\s*\??', # Nullable types |
||||
r'<\w+>\s*where\s+\w+\s*:', # Generic constraints |
||||
r'set\s*\{', # Property setters |
||||
r'get\s*\{', # Property getters |
||||
r'using\s*\(', # Using statements with blocks |
||||
r'\bget;\s*set;', # Auto-properties |
||||
r'\bselect\s+new\b' # LINQ expressions |
||||
] |
||||
return any(re.search(pattern, code, re.IGNORECASE) for pattern in patterns) |
||||
|
||||
@staticmethod |
||||
def detect_typescript(code: str) -> bool: |
||||
"""Detect if code is TypeScript.""" |
||||
# TypeScript-specific patterns (not commonly found in other languages) |
||||
ts_patterns = [ |
||||
r':\s*[A-Za-z]+(?:<[^>]+>)?\s*(?:=|;|\)|\})', # Type annotations |
||||
r'interface\s+\w+\s*\{', # Interface declaration |
||||
r'class\s+\w+(?:\s+implements|\s+extends)?', # Class with implements or extends |
||||
r'(private|public|protected)\s+\w+', # Access modifiers |
||||
r'\w+\s*<[^>]+>', # Generic types |
||||
r'import\s+\{[^}]+\}\s+from', # ES6 import |
||||
r'export\s+(interface|class|type|const|let)', # Exports |
||||
r'type\s+\w+\s*=', # Type aliases |
||||
r'enum\s+\w+', # Enums |
||||
r'@\w+(?:\([^)]*\))?', # Decorators |
||||
r'\w+\s*:\s*(?:string|number|boolean|any|void|never|unknown)', # Basic TypeScript types |
||||
r'(?:string|number|boolean|any|void)\[\]', # Array type notation |
||||
r'readonly\s+\w+', # Readonly modifier |
||||
r'namespace\s+\w+', # TypeScript namespaces |
||||
r'declare\s+(?:var|let|const|function|class|interface)', # Declarations |
||||
r'<[^>]+>\(', # Generic function calls |
||||
r'extends\s+\w+<', # Generic type inheritance |
||||
r'implements\s+\w+', # Interface implementation |
||||
r'as\s+(?:string|number|boolean|any)', # Type assertions |
||||
r'\?\s*:', # Optional properties |
||||
r'\w+\s*\?\s*:', # Optional parameters |
||||
r'keyof\s+\w+', # keyof operator |
||||
r'typeof\s+\w+', # typeof operator |
||||
r'\bReadonly<', # Utility types |
||||
r'\bPartial<', # Utility types |
||||
r'\bRequired<', # Utility types |
||||
r'\bRecord<', # Utility types |
||||
r'\|\s*null', # Union with null |
||||
r'\|\s*undefined', # Union with undefined |
||||
r'\w+\s*&\s*\w+', # Intersection types |
||||
r'import\s+type', # Import types |
||||
r'export\s+type' # Export types |
||||
] |
||||
|
||||
# Check for TypeScript-specific patterns |
||||
ts_unique = any(re.search(pattern, code, re.IGNORECASE) for pattern in ts_patterns) |
||||
|
||||
# JavaScript patterns for basic JS syntax (TypeScript is a superset of JS) |
||||
js_patterns = [ |
||||
r'function\s+\w+\s*\([^)]*\)', # Function declaration |
||||
r'const\s+\w+\s*=', # Const declaration |
||||
r'let\s+\w+\s*=', # Let declaration |
||||
r'var\s+\w+\s*=', # Var declaration |
||||
r'console\.(log|error|warn)' # Console methods |
||||
] |
||||
|
||||
js_general = any(re.search(pattern, code, re.IGNORECASE) for pattern in js_patterns) |
||||
|
||||
# For TypeScript detection, we need to differentiate between object property definitions (which exist in JS) |
||||
# and type annotations (which are unique to TS) |
||||
|
||||
# First, check for specific patterns from other languages to avoid false positives |
||||
|
||||
# Lua-specific patterns |
||||
lua_patterns = [ |
||||
r'local\s+\w+\s*=', # Local variable declarations |
||||
r'function\s*\([^)]*\)\s*', # Anonymous functions |
||||
r'require\(["\']\w+["\'](\))', # Module imports |
||||
r'end\b', # End keyword |
||||
r'\bnil\b', # nil value |
||||
r'\bipairs\(', # ipairs function |
||||
r'\bpairs\(', # pairs function |
||||
r'\s*\.\.\.?\s*' # String concatenation or varargs |
||||
] |
||||
|
||||
# PHP-specific patterns |
||||
php_patterns = [ |
||||
r'<\?php', # PHP opening tag |
||||
r'\$\w+', # PHP variables |
||||
r'\-\>\w+', # PHP object access |
||||
r'public\s+function', # PHP method declaration |
||||
r'namespace\s+\w+\\', # PHP namespace with backslash |
||||
r'use\s+\w+\\', # PHP use statements with backslash |
||||
r'\$this\->' # PHP $this reference |
||||
] |
||||
|
||||
# If the code contains clear Lua or PHP indicators, it's not TypeScript |
||||
is_likely_lua = any(re.search(pattern, code) for pattern in lua_patterns) |
||||
is_likely_php = any(re.search(pattern, code) for pattern in php_patterns) |
||||
|
||||
if is_likely_lua or is_likely_php: |
||||
return False |
||||
|
||||
# Check for type annotations in context (not inside object literals) |
||||
type_annotation_patterns = [ |
||||
r'function\s+\w+\([^)]*\)\s*:\s*\w+', # Function return type |
||||
r'const\s+\w+\s*:\s*\w+', # Variable with type annotation |
||||
r'let\s+\w+\s*:\s*\w+', # Variable with type annotation |
||||
r':\s*(?:string|number|boolean|any|void|null|undefined)\b', # Basic type annotations |
||||
r':\s*[A-Z][\w]+(?![\w\(])', # Custom type annotations (type names typically start with capital letter) |
||||
r':\s*[\w\[\]<>|&]+(?=\s*(?:[,\);=]|$))' # Complex type annotations followed by certain delimiters |
||||
] |
||||
|
||||
has_type_annotation = any(re.search(pattern, code) for pattern in type_annotation_patterns) |
||||
|
||||
# Look for JavaScript syntax indicators |
||||
js_object_literal = re.search(r'\{\s*\w+\s*:\s*[^:\{]+\s*(?:,|\})', code) is not None |
||||
contains_js_imports = re.search(r'import\s+[{\w\s,}]+\s+from\s+["\']', code) is not None |
||||
|
||||
# Only return true for TypeScript-specific patterns or if we have type annotations |
||||
# that are likely to be TypeScript and not other languages |
||||
return ts_unique or (has_type_annotation and (contains_js_imports or js_general) and not (js_object_literal and not ts_unique)) |
||||
|
||||
@staticmethod |
||||
def detect_r(code: str) -> bool: |
||||
"""Detect if code is R.""" |
||||
patterns = [ |
||||
r'<-\s*(?:function|\w+)', # Assignment with <- |
||||
r'library\([\w\.]+\)', # Library import |
||||
r'(?:data|read)\.(?:frame|csv|table)', # Data frames |
||||
r'\b(?:if|for|while)\s*\(', # Control structures |
||||
r'\$\w+', # Variable access with $ |
||||
r'\bNA\b|\bNULL\b|\bTRUE\b|\bFALSE\b', # R constants |
||||
r'c\(.*?\)', # Vector creation with c() |
||||
r'(?:plot|ggplot)\(', # Plotting functions |
||||
r'\s*#.*$', # R comments |
||||
r'%>%', # Pipe operator |
||||
r'\bfactor\(', # Factor function |
||||
r'\bstr\(', # Structure function |
||||
r'\bas\.\w+\(', # Type conversion functions |
||||
r'\w+\s*<-\s*\w+\[.+?\]' # Subsetting with brackets |
||||
] |
||||
return any(re.search(pattern, code) for pattern in patterns) |
||||
|
||||
@staticmethod |
||||
def detect_perl(code: str) -> bool: |
||||
"""Detect if code is Perl.""" |
||||
patterns = [ |
||||
r'\$\w+', # Scalar variables |
||||
r'@\w+', # Array variables |
||||
r'%\w+', # Hash variables |
||||
r'use\s+[\w:]+\s*;', # Module imports |
||||
r'\bsub\s+\w+\s*\{', # Subroutine definition |
||||
r'\bmy\s+(?:\$|@|%)\w+', # Variable declarations |
||||
r'=~\s*(?:m|s|tr)', # Regular expression operators |
||||
r'print\s+(?:\$|@|%|")', # Print statements |
||||
r'(?:if|unless|while|for|foreach)\s*\(', # Control structures |
||||
r'\{.*?\}.*?\{.*?\}', # Block structure typical in Perl |
||||
r'->\w+', # Method calls |
||||
r'\b(?:shift|pop|push|splice)', # Array operations |
||||
r';\s*$', # Statements ending with semicolon |
||||
r'#.*$', # Comments |
||||
r'\bdie\s+', # Die statements |
||||
r'\bqw\s*\(', # qw() operator |
||||
r'\$_', # Special $_ variable |
||||
r'\bdefined\s+(?:\$|@|%)' # Defined operator |
||||
] |
||||
return any(re.search(pattern, code) for pattern in patterns) |
||||
|
||||
@staticmethod |
||||
def detect_lua(code: str) -> bool: |
||||
"""Detect if code is Lua.""" |
||||
patterns = [ |
||||
r'\blocal\s+\w+', # Local variable declarations |
||||
r'\bfunction\s+\w+(?:\w*\.\w+)*\s*\(', # Function definitions |
||||
r'(?:end|then|do|else)\b', # Lua keywords |
||||
r'\brequire\s*\(["\w\.\']+\)', # Module imports |
||||
r'\breturn\s+.+?$', # Return statements |
||||
r'\bnil\b', # Nil value |
||||
r'\bfor\s+\w+\s*=\s*\d+\s*,\s*\d+', # Numeric for loops |
||||
r'\bfor\s+\w+(?:\s*,\s*\w+)*\s+in\b', # Generic for loops |
||||
r'\bif\s+.+?\s+then\b', # If statements |
||||
r'\belseif\s+.+?\s+then\b', # Elseif statements |
||||
r'\btable\.(\w+)\b', # Table library functions |
||||
r'\bstring\.(\w+)\b', # String library functions |
||||
r'\bmath\.(\w+)\b', # Math library functions |
||||
r'\bpairs\(\w+\)', # Pairs function |
||||
r'\bipairs\(\w+\)', # Ipairs function |
||||
r'\btostring\(', # Tostring function |
||||
r'\btonumber\(', # Tonumber function |
||||
r'\bprint\(', # Print function |
||||
r'--.*$', # Comments |
||||
r'\[\[.*?\]\]', # Multiline strings |
||||
r'\{\s*[\w"\']+\s*=', # Table initialization |
||||
r'\w+\[\w+\]', # Table index access |
||||
r'\w+\.\.\w+' # String concatenation |
||||
] |
||||
return any(re.search(pattern, code) for pattern in patterns) |
||||
|
||||
|
||||
@staticmethod |
||||
def detect_php(code: str) -> bool: |
||||
"""Detect if code is PHP.""" |
||||
patterns = [ |
||||
r'<\?php', # PHP opening tag |
||||
r'\$\w+', # Variable with $ prefix |
||||
r'function\s+\w+\s*\(', # Function definition |
||||
r'echo\s+[\$\w\'\"]+', # Echo statement |
||||
r'class\s+\w+(?:\s+extends|\s+implements)?', # Class definition |
||||
r'(?:public|private|protected)\s+function', # Class methods |
||||
r'(?:public|private|protected)\s+\$\w+', # Class properties |
||||
r'namespace\s+[\w\\\\]+', # Namespace declaration |
||||
r'use\s+[\w\\\\]+', # Use statement |
||||
r'=>', # Array key => value syntax |
||||
r'array\s*\(', # Array creation |
||||
r'\[\s*[\'\"]*\w+[\'\"]*\s*\]', # Array access with [] |
||||
r'require(?:_once)?\s*\(', # Require statements |
||||
r'include(?:_once)?\s*\(', # Include statements |
||||
r'new\s+\w+', # Object instantiation |
||||
r'->', # Object property/method access |
||||
r'::', # Static property/method access |
||||
r'<?=.*?(?:\?>|$)', # Short echo syntax |
||||
r'if\s*\(.+?\)\s*\{', # If statements |
||||
r'foreach\s*\(\s*\$\w+', # Foreach loops |
||||
r';$' # Statement ending with semicolon |
||||
] |
||||
return any(re.search(pattern, code) for pattern in patterns) |
||||
|
||||
|
||||
@staticmethod |
||||
def detect_kotlin(code: str) -> bool: |
||||
"""Detect if code is Kotlin.""" |
||||
patterns = [ |
||||
r'fun\s+\w+\s*\(', # Function declaration |
||||
r'val\s+\w+(?:\s*:\s*\w+)?', # Val declaration |
||||
r'var\s+\w+(?:\s*:\s*\w+)?', # Var declaration |
||||
r'class\s+\w+(?:\s*\((?:[^)]*)\))?', # Class declaration |
||||
r'package\s+[\w\.]+', # Package declaration |
||||
r'import\s+[\w\.]+', # Import statement |
||||
r'object\s+\w+', # Object declaration |
||||
r'interface\s+\w+', # Interface declaration |
||||
r'data\s+class', # Data class |
||||
r'(?:override|open|abstract|final)\s+fun', # Modified functions |
||||
r'(?:companion|sealed)\s+object', # Special objects |
||||
r'when\s*\(', # When expression |
||||
r'(?:if|else|for|while)\s*\(', # Control structures |
||||
r'->', # Lambda syntax |
||||
r'[\w\.\(\)]+\.\w+\{', # Extension functions |
||||
r'(?:List|Set|Map)<', # Generic collections |
||||
r'(?:private|public|internal|protected)', # Visibility modifiers |
||||
r'lateinit\s+var', # Lateinit vars |
||||
r'(?:suspend|inline)\s+fun', # Special function modifiers |
||||
r'@\w+(?:\([^)]*\))?' # Annotations |
||||
] |
||||
return any(re.search(pattern, code) for pattern in patterns) |
||||
|
||||
|
||||
@staticmethod |
||||
def detect_sql(code: str) -> bool: |
||||
"""Detect if code is SQL.""" |
||||
patterns = [ |
||||
r'SELECT\s+[\w\*,\s]+\s+FROM', # SELECT statement |
||||
r'INSERT\s+INTO\s+\w+', # INSERT statement |
||||
r'UPDATE\s+\w+\s+SET', # UPDATE statement |
||||
r'DELETE\s+FROM\s+\w+', # DELETE statement |
||||
r'CREATE\s+TABLE\s+\w+', # CREATE TABLE statement |
||||
r'ALTER\s+TABLE\s+\w+', # ALTER TABLE statement |
||||
r'DROP\s+TABLE\s+\w+', # DROP TABLE statement |
||||
r'TRUNCATE\s+TABLE\s+\w+', # TRUNCATE TABLE statement |
||||
r'JOIN\s+\w+\s+ON', # JOIN clause |
||||
r'WHERE\s+\w+\s*(?:=|<|>|<=|>=|<>|!=|LIKE|IN)', # WHERE clause |
||||
r'GROUP\s+BY\s+\w+', # GROUP BY clause |
||||
r'ORDER\s+BY\s+\w+\s+(?:ASC|DESC)?', # ORDER BY clause |
||||
r'HAVING\s+\w+', # HAVING clause |
||||
r'CONSTRAINT\s+\w+', # CONSTRAINT declaration |
||||
r'PRIMARY\s+KEY', # PRIMARY KEY constraint |
||||
r'FOREIGN\s+KEY', # FOREIGN KEY constraint |
||||
r'(?:VARCHAR|INT|INTEGER|FLOAT|DATE|DATETIME|BOOLEAN|TEXT|BLOB)', # Common data types |
||||
r'(?:COUNT|SUM|AVG|MIN|MAX)\s*\(', # Aggregate functions |
||||
r'CASE\s+WHEN\s+.+?\s+THEN', # CASE statement |
||||
r'BEGIN\s+TRANSACTION', # Transaction control |
||||
r'COMMIT', # COMMIT statement |
||||
r'ROLLBACK' # ROLLBACK statement |
||||
] |
||||
return any(re.search(pattern, code, re.IGNORECASE) for pattern in patterns) |
||||
|
||||
|
||||
def __init__(self): |
||||
"""Initialize language detector with detection functions.""" |
||||
self.detectors = { |
||||
"Python": self.detect_python, |
||||
"JavaScript": self.detect_javascript, |
||||
"Java": self.detect_java, |
||||
"C++": self.detect_cpp, |
||||
"Julia": self.detect_julia, |
||||
"Go": self.detect_go, |
||||
"Ruby": self.detect_ruby, |
||||
"Swift": self.detect_swift, |
||||
"Rust": self.detect_rust, |
||||
"C#": self.detect_csharp, |
||||
"TypeScript": self.detect_typescript, |
||||
"R": self.detect_r, |
||||
"Perl": self.detect_perl, |
||||
"Lua": self.detect_lua, |
||||
"PHP": self.detect_php, |
||||
"Kotlin": self.detect_kotlin, |
||||
"SQL": self.detect_sql |
||||
} |
||||
|
||||
|
||||
def detect_language(self, code: str) -> str: |
||||
""" |
||||
Detect the programming language of the given code. |
||||
|
||||
Args: |
||||
code: Code snippet to analyze |
||||
|
||||
Returns: |
||||
Detected language name or None if unknown |
||||
""" |
||||
# Initial matching - which language detectors return positive |
||||
matches = {} |
||||
|
||||
# First pass: check which languages match |
||||
for lang, detector in self.detectors.items(): |
||||
if detector(code): |
||||
matches[lang] = 0 |
||||
|
||||
if not matches: |
||||
return None |
||||
|
||||
# If only one language matches, return it |
||||
if len(matches) == 1: |
||||
return list(matches.keys())[0] |
||||
|
||||
# Improved scoring system with distinctive language features |
||||
# These patterns are selected to be highly distinctive to each language |
||||
# Each pattern is assigned a weight based on how uniquely it identifies a language |
||||
unique_patterns = { |
||||
# C# distinctive features (to differentiate from Java and other languages) |
||||
"C#": [ |
||||
(r'using\s+[\w.]+;', 3), # Using statement |
||||
(r'namespace\s+[\w.]+', 3), # Namespace |
||||
(r'Console\.(Write|WriteLine)', 2), # Console output |
||||
(r'\bvar\s+\w+\s*=', 3), # Var keyword |
||||
(r'\bawait\s+', 4), # Async/await |
||||
(r'\btask<', 4), # Task object |
||||
(r'\bdynamic\b', 4), # Dynamic type |
||||
(r'\$".*?\{.*?\}.*?"', 5), # String interpolation with $ |
||||
(r'\bIEnumerable<', 4), # C# collections |
||||
(r'\bList<', 3), # C# collections |
||||
(r'\bforeach\s*\(', 2), # foreach loops |
||||
(r'\bget;\s*set;', 5), # Auto-properties |
||||
(r'\bselect\s+new\b', 4), # LINQ |
||||
(r'\bwhere\s+\w+\s*=', 4), # LINQ |
||||
(r'<\w+>\s*where\s+\w+\s*:', 5) # Generic constraints |
||||
], |
||||
|
||||
# Rust distinctive features (to differentiate from C++) |
||||
"Rust": [ |
||||
(r'fn\s+\w+\s*\(', 3), # Function declaration |
||||
(r'let\s+mut\s+\w+', 5), # Mutable variable |
||||
(r'impl\s+\w+(?:\s+for\s+\w+)?', 6), # Implementation |
||||
(r'use\s+[\w:]+', 2), # Use statement |
||||
(r'pub\s+(?:fn|struct|enum|mod)', 4), # Public items |
||||
(r'\bResult<', 5), # Result type |
||||
(r'\bOption<', 5), # Option type |
||||
(r'\bmod\s+\w+', 4), # Module declaration |
||||
(r'&mut\s+\w+', 5), # Mutable references |
||||
(r'trait\s+\w+', 6), # Trait definition |
||||
(r'\bSome\(', 5), # Some variant |
||||
(r'\bNone\b', 5), # None variant |
||||
(r'\bOk\(', 5), # Ok variant |
||||
(r'\bErr\(', 5), # Err variant |
||||
(r'\bcrate::\w+', 5), # Crate references |
||||
(r'\bif\s+let\s+Some', 6) # If let for Option |
||||
], |
||||
|
||||
# Swift distinctive features (to differentiate from Kotlin) |
||||
"Swift": [ |
||||
(r'import\s+(?:Foundation|UIKit|SwiftUI)', 6), # Swift imports |
||||
(r'@IBOutlet|@IBAction', 8), # iOS annotations |
||||
(r'guard\s+let', 6), # Guard statement |
||||
(r'\bOptional<', 6), # Optional type |
||||
(r'\bas\?', 5), # Type casting |
||||
(r'\bas!', 5), # Forced type casting |
||||
(r'\?\?', 4), # Nil coalescing |
||||
(r'extension\s+\w+', 4), # Extensions |
||||
(r'protocol\s+\w+', 4), # Protocols |
||||
(r'convenience\s+init', 6), # Convenience init |
||||
(r'required\s+init', 6), # Required init |
||||
(r'\bUInt\d*\b', 5), # Swift integer types |
||||
(r'\bInt\d*\b', 4), # Swift integer types |
||||
(r'\barray<', 3), # Swift arrays |
||||
(r'\bdictionary<', 3), # Swift dictionaries |
||||
(r'@escaping', 8) # Escaping closures |
||||
], |
||||
|
||||
# TypeScript distinctive features (to differentiate from JavaScript and Python) |
||||
"TypeScript": [ |
||||
(r':\s*[A-Za-z]+(?:<[^>]+>)?\s*(?:=|;|\)|\})', 5), # Type annotations |
||||
(r'interface\s+\w+\s*\{', 6), # Interface |
||||
(r'type\s+\w+\s*=', 6), # Type aliases |
||||
(r'enum\s+\w+', 5), # Enums |
||||
(r'namespace\s+\w+', 6), # TypeScript namespaces |
||||
(r'declare\s+(?:var|let|const|function|class|interface)', 7), # Declarations |
||||
(r'as\s+(?:string|number|boolean|any)', 6), # Type assertions |
||||
(r'\?\s*:', 5), # Optional properties |
||||
(r'\w+\s*\?\s*:', 5), # Optional parameters |
||||
(r'keyof\s+\w+', 7), # keyof operator |
||||
(r'typeof\s+\w+', 6), # typeof operator |
||||
(r'\bReadonly<', 7), # Utility types |
||||
(r'\bPartial<', 7), # Utility types |
||||
(r'\bRequired<', 7), # Utility types |
||||
(r'\bRecord<', 7), # Utility types |
||||
(r'\w+\s*&\s*\w+', 6), # Intersection types |
||||
(r'import\s+type', 8), # Import types |
||||
(r'export\s+type', 8) # Export types |
||||
], |
||||
|
||||
# Keep other language patterns but add more weight to distinctive features |
||||
"PHP": [(r'<\?php', 10), (r'\$\w+\s*=', 2), (r'function\s+\w+\s*\(.*?\)\s*\{', 2)], |
||||
"SQL": [(r'(?i)SELECT\s+[\w\*,\s]+\s+FROM', 10), (r'(?i)INSERT\s+INTO', 8), (r'(?i)CREATE\s+TABLE', 8)], |
||||
"Perl": [(r'\buse\s+[\w:]+\s*;', 6), (r'\bmy\s+(?:\$|@|%)', 8), (r'\bperl\b', 10)], |
||||
"Lua": [(r'\blocal\s+\w+', 6), (r'\bfunction\s+\w+(?:\w*\.\w+)*\s*\(', 6), (r'\bend\s*$', 4)], |
||||
"Kotlin": [(r'\bfun\s+\w+\s*\(', 6), (r'\bval\s+\w+(?:\s*:\s*\w+)?', 6), (r'data\s+class', 10)], |
||||
"Ruby": [(r'\bdef\s+\w+\s*(?:\([^)]*\))?\s*$', 6), (r'\bend\b', 4), (r'\bdo\s*\|[^|]*\|', 6)], |
||||
"R": [(r'<-\s*(?:function|\w+)', 8), (r'library\([\w\.]+\)', 8), (r'%>%', 10)], |
||||
"Python": [(r'def\s+\w+\s*\([^)]*\)\s*:', 6), (r'import\s+[\w\s,]+', 4), (r'from\s+[\w.]+\s+import', 6)], |
||||
"JavaScript": [(r'function\s+\w+\s*\([^)]*\)', 4), (r'const\s+\w+\s*=', 3), (r'let\s+\w+\s*=', 3)], |
||||
"Java": [(r'public\s+class\s+\w+', 6), (r'public\s+static\s+void\s+main', 8), (r'System\.(out|err)\.', 6)], |
||||
"C++": [(r'#include\s*<[^>]+>', 6), (r'std::\w+', 8), (r'int\s+main\s*\(', 4)], |
||||
"Julia": [(r'function\s+\w+\s*\([^)]*\)\s*end', 8), (r'module\s+\w+', 6), (r'using\s+\w+', 4)], |
||||
"Go": [(r'package\s+\w+', 6), (r'func\s+\w+\s*\(', 4), (r'import\s*\(', 4)] |
||||
} |
||||
|
||||
# Apply the detailed scoring system |
||||
for lang, patterns in unique_patterns.items(): |
||||
if lang in matches: |
||||
for pattern, weight in patterns: |
||||
if re.search(pattern, code, re.IGNORECASE): |
||||
matches[lang] += weight |
||||
|
||||
# Additional weighting for core language features |
||||
# C# vs Java disambiguation |
||||
if "C#" in matches and "Java" in matches: |
||||
# C# specific features that are unlikely in Java |
||||
csharp_specific = [ |
||||
(r'\$"', 8), # String interpolation |
||||
(r'\bvar\b', 6), # var keyword |
||||
(r'\basync\b', 6), # async keyword |
||||
(r'\bawait\b', 6), # await keyword |
||||
(r'\bIEnumerable<', 6), # C# specific interfaces |
||||
(r'\bget;\s*set;', 8), # Auto-properties |
||||
(r'\bLINQ\b', 8), # LINQ |
||||
(r'\busing\s+static', 8) # using static |
||||
] |
||||
for pattern, weight in csharp_specific: |
||||
if re.search(pattern, code, re.IGNORECASE): |
||||
matches["C#"] += weight |
||||
|
||||
# Java specific features that are unlikely in C# |
||||
java_specific = [ |
||||
(r'\bimport\s+java\.', 8), # Java imports |
||||
(r'\bSystem\.out\.print', 6), # Java System.out |
||||
(r'\bpublic\s+static\s+void\s+main', 8), # Java main method |
||||
(r'\@Override\b', 6), # Java annotations |
||||
(r'\bextends\s+\w+\s*\{', 6), # Java inheritance |
||||
(r'\bimplements\s+\w+\s*\{', 6) # Java interface implementation |
||||
] |
||||
for pattern, weight in java_specific: |
||||
if re.search(pattern, code, re.IGNORECASE): |
||||
matches["Java"] += weight |
||||
|
||||
# Rust vs C++ disambiguation |
||||
if "Rust" in matches and "C++" in matches: |
||||
# Rust specific features that are unlikely in C++ |
||||
rust_specific = [ |
||||
(r'\bfn\b', 8), # fn keyword |
||||
(r'\blet\b', 8), # let keyword |
||||
(r'\bmut\b', 8), # mut keyword |
||||
(r'\bimpl\b', 8), # impl keyword |
||||
(r'\buse\b', 6), # use keyword |
||||
(r'\bSome\(', 8), # Some variant |
||||
(r'\bNone\b', 8), # None variant |
||||
(r'\bResult<', 8), # Result type |
||||
(r'\bOption<', 8) # Option type |
||||
] |
||||
for pattern, weight in rust_specific: |
||||
if re.search(pattern, code, re.IGNORECASE): |
||||
matches["Rust"] += weight |
||||
|
||||
# C++ specific features that are unlikely in Rust |
||||
cpp_specific = [ |
||||
(r'#include', 8), # C++ include |
||||
(r'std::', 6), # C++ std namespace |
||||
(r'\bclass\b', 6), # class keyword |
||||
(r'\bpublic:\b', 8), # public: access specifier |
||||
(r'\bprivate:\b', 8), # private: access specifier |
||||
(r'\bprotected:\b', 8), # protected: access specifier |
||||
(r'\btypedef\b', 8), # typedef keyword |
||||
(r'\bnew\b', 4), # new keyword |
||||
(r'\bdelete\b', 8) # delete keyword |
||||
] |
||||
for pattern, weight in cpp_specific: |
||||
if re.search(pattern, code, re.IGNORECASE): |
||||
matches["C++"] += weight |
||||
|
||||
# Swift vs Kotlin disambiguation |
||||
if "Swift" in matches and "Kotlin" in matches: |
||||
# Swift specific features that are unlikely in Kotlin |
||||
swift_specific = [ |
||||
(r'\bimport\s+(?:Foundation|UIKit|SwiftUI)', 10), # Swift imports |
||||
(r'\bguard\b', 8), # guard keyword |
||||
(r'\?\?', 8), # Nil coalescing operator |
||||
(r'\bas\?', 8), # Optional downcasting |
||||
(r'\bas!', 8), # Forced downcasting |
||||
(r'@IBOutlet', 10), # Interface Builder |
||||
(r'@IBAction', 10), # Interface Builder |
||||
(r'@objc', 10), # Objective-C interop |
||||
(r'\bUIViewController\b', 10) # UIKit |
||||
] |
||||
for pattern, weight in swift_specific: |
||||
if re.search(pattern, code, re.IGNORECASE): |
||||
matches["Swift"] += weight |
||||
|
||||
# Kotlin specific features that are unlikely in Swift |
||||
kotlin_specific = [ |
||||
(r'\bdata\s+class', 10), # Data class |
||||
(r'\bfun\b', 8), # fun keyword |
||||
(r'\bval\b', 6), # val keyword |
||||
(r'\bvar\b', 4), # var keyword |
||||
(r'\bcompanion\s+object', 10), # Companion object |
||||
(r'\bwhen\b', 8), # when expression |
||||
(r'\bcoroutine', 10), # Coroutines |
||||
(r'\bsuspend\b', 10), # Suspend functions |
||||
(r'\blateinit\b', 10), # Late initialization |
||||
(r'\bimport\s+(?:kotlin|androidx|android)', 10) # Kotlin imports |
||||
] |
||||
for pattern, weight in kotlin_specific: |
||||
if re.search(pattern, code, re.IGNORECASE): |
||||
matches["Kotlin"] += weight |
||||
|
||||
# TypeScript vs JavaScript disambiguation (and Python confusion) |
||||
if "TypeScript" in matches and ("JavaScript" in matches or "Python" in matches): |
||||
# TypeScript specific features that are unlikely in JS or Python |
||||
ts_specific = [ |
||||
(r':\s*[A-Za-z]+', 8), # Type annotations |
||||
(r'\binterface\b', 8), # interface keyword |
||||
(r'\btype\b\s+\w+\s*=', 10), # type aliases |
||||
(r'\bnamespace\b', 10), # namespace keyword |
||||
(r'\benum\b', 8), # enum keyword |
||||
(r'\bas\s+(?:string|number|boolean|any)', 10), # Type assertions |
||||
(r'\?:\s*', 10), # Optional types |
||||
(r'\bReadonly<', 10), # Utility types |
||||
(r'\w+\s*&\s*\w+', 10), # Intersection types |
||||
(r'\bimport\s+type', 10), # Import types |
||||
(r'\[\w+\s*:\s*\w+\]', 10) # Typed arrays |
||||
] |
||||
for pattern, weight in ts_specific: |
||||
if re.search(pattern, code, re.IGNORECASE): |
||||
matches["TypeScript"] += weight |
||||
# Remove Python if it's a false positive |
||||
if "Python" in matches and matches["Python"] < matches["TypeScript"]: |
||||
matches.pop("Python", None) |
||||
|
||||
# Return the language with the highest score |
||||
if matches: |
||||
return max(matches.items(), key=lambda x: x[1])[0] |
||||
|
||||
return None |
||||
|
||||
def validate_language(self, code: str, expected_lang: str) -> tuple[bool, str]: |
||||
"""Validate if code matches the expected programming language.""" |
||||
logger = logging.getLogger(__name__) |
||||
|
||||
logger.info(f"Starting code validation for {expected_lang}") |
||||
logger.info(f"Code length: {len(code)} characters") |
||||
|
||||
if not code or not expected_lang: |
||||
logger.warning("Empty code or language not specified") |
||||
return True, "" |
||||
|
||||
detector = self.detectors.get(expected_lang) |
||||
if not detector: |
||||
logger.warning(f"No detector found for language: {expected_lang}") |
||||
return True, "" |
||||
|
||||
if detector(code): |
||||
logger.info(f"Code successfully validated as {expected_lang}") |
||||
return True, "" |
||||
|
||||
detected_lang = self.detect_language(code) |
||||
error_msg = f"Code appears to be {detected_lang or 'unknown'} but {expected_lang} was selected" |
||||
logger.error(f"Language validation failed: {error_msg}") |
||||
return False, error_msg |
@ -0,0 +1,31 @@
|
||||
"""Main entry point for the CodeXchange AI application.""" |
||||
|
||||
from src.ai_code_converter.app import CodeConverterApp |
||||
from src.ai_code_converter.utils.logger import setup_logger |
||||
|
||||
def main(): |
||||
"""Initialize and run the application.""" |
||||
# Initialize logger |
||||
logger = setup_logger("ai_code_converter.main") |
||||
|
||||
try: |
||||
logger.info("="*50) |
||||
logger.info("Starting CodeXchange AI") |
||||
logger.info("="*50) |
||||
|
||||
logger.info("Initializing application components") |
||||
app = CodeConverterApp() |
||||
|
||||
logger.info("Starting Gradio interface") |
||||
app.run(share=True) |
||||
|
||||
except Exception as e: |
||||
logger.error("Application failed to start", exc_info=True) |
||||
raise |
||||
finally: |
||||
logger.info("="*50) |
||||
logger.info("Application shutdown") |
||||
logger.info("="*50) |
||||
|
||||
if __name__ == "__main__": |
||||
main() |
@ -0,0 +1 @@
|
||||
"""Model-related modules.""" |
@ -0,0 +1,301 @@
|
||||
"""Module for handling AI model streaming responses.""" |
||||
|
||||
import logging |
||||
import time |
||||
from typing import Generator, Any, Callable, TypeVar, cast |
||||
from anthropic import Anthropic, AnthropicError, APIError, RateLimitError, AuthenticationError |
||||
import google.generativeai as genai |
||||
from openai import OpenAI |
||||
|
||||
from src.ai_code_converter.config import ( |
||||
OPENAI_MODEL, |
||||
CLAUDE_MODEL, |
||||
DEEPSEEK_MODEL, |
||||
GEMINI_MODEL, |
||||
GROQ_MODEL |
||||
) |
||||
|
||||
logger = logging.getLogger(__name__) |
||||
|
||||
# Type variable for generic retry function |
||||
T = TypeVar('T') |
||||
|
||||
def retry_with_exponential_backoff( |
||||
max_retries: int = 5, |
||||
initial_delay: float = 1.0, |
||||
exponential_base: float = 2.0, |
||||
jitter: bool = True, |
||||
retryable_exceptions: tuple = (Exception,), |
||||
retryable_return: Callable[[Any], bool] = None, |
||||
) -> Callable: |
||||
"""Retry decorator with exponential backoff |
||||
|
||||
Args: |
||||
max_retries: Maximum number of retries |
||||
initial_delay: Initial delay in seconds |
||||
exponential_base: Base for exponential calculation |
||||
jitter: Add random jitter to delay |
||||
retryable_exceptions: Exceptions that trigger retry |
||||
retryable_return: Function that takes the return value and returns |
||||
True if it should be retried |
||||
|
||||
Returns: |
||||
Decorator function |
||||
""" |
||||
def decorator(func: Callable) -> Callable: |
||||
def wrapper(*args: Any, **kwargs: Any) -> Any: |
||||
# Initialize variables |
||||
num_retries = 0 |
||||
delay = initial_delay |
||||
|
||||
# Loop until max retries reached |
||||
while True: |
||||
try: |
||||
response = func(*args, **kwargs) |
||||
|
||||
# Check if we should retry based on response value |
||||
if retryable_return and num_retries < max_retries: |
||||
try: |
||||
if retryable_return(response): |
||||
num_retries += 1 |
||||
logger.warning( |
||||
f"Retrying {func.__name__} due to response condition " |
||||
f"(attempt {num_retries} of {max_retries})" |
||||
) |
||||
time.sleep(delay) |
||||
delay = calculate_next_delay(delay, exponential_base, jitter) |
||||
continue |
||||
except Exception as e: |
||||
# If retryable_return itself fails, log and continue |
||||
logger.warning(f"Error in retry condition: {e}") |
||||
|
||||
return response |
||||
|
||||
except retryable_exceptions as e: |
||||
# Check if we've exceeded max retries |
||||
if num_retries >= max_retries: |
||||
logger.error( |
||||
f"Maximum retries ({max_retries}) exceeded for {func.__name__}: {str(e)}" |
||||
) |
||||
raise |
||||
|
||||
# Handle specific error types with custom messages |
||||
if hasattr(e, 'error') and isinstance(e.error, dict) and e.error.get('type') == 'overloaded_error': |
||||
logger.warning( |
||||
f"Service overloaded, retrying {func.__name__} " |
||||
f"(attempt {num_retries + 1} of {max_retries})" |
||||
) |
||||
else: |
||||
logger.warning( |
||||
f"Exception in {func.__name__}, retrying " |
||||
f"(attempt {num_retries + 1} of {max_retries}): {str(e)}" |
||||
) |
||||
|
||||
# Increment retry count and delay |
||||
num_retries += 1 |
||||
time.sleep(delay) |
||||
delay = calculate_next_delay(delay, exponential_base, jitter) |
||||
|
||||
return cast(Callable, wrapper) |
||||
return decorator |
||||
|
||||
|
||||
def calculate_next_delay(current_delay: float, exponential_base: float, jitter: bool) -> float: |
||||
"""Calculate the next delay time using exponential backoff and optional jitter""" |
||||
import random |
||||
delay = current_delay * exponential_base |
||||
# Add jitter - random value between -0.2 and +0.2 of the delay |
||||
if jitter: |
||||
delay = delay * (1 + random.uniform(-0.2, 0.2)) |
||||
return delay |
||||
|
||||
|
||||
class AIModelStreamer: |
||||
"""Class for handling streaming responses from various AI models.""" |
||||
|
||||
def __init__(self, openai_client: OpenAI, claude_client: Anthropic, |
||||
deepseek_client: OpenAI, groq_client: OpenAI, gemini_model: genai.GenerativeModel): |
||||
"""Initialize with AI model clients.""" |
||||
self.openai = openai_client |
||||
self.claude = claude_client |
||||
self.deepseek = deepseek_client |
||||
self.groq = groq_client |
||||
self.gemini = gemini_model |
||||
self.max_retries = 5 |
||||
|
||||
@retry_with_exponential_backoff( |
||||
max_retries=5, |
||||
initial_delay=1.0, |
||||
retryable_exceptions=(Exception,) |
||||
) |
||||
def _call_gpt_api(self, prompt: str): |
||||
"""Call the GPT API with retry logic""" |
||||
messages = [{"role": "user", "content": prompt}] |
||||
return self.openai.chat.completions.create( |
||||
model=OPENAI_MODEL, |
||||
messages=messages, |
||||
stream=True |
||||
) |
||||
|
||||
def stream_gpt(self, prompt: str) -> Generator[str, None, None]: |
||||
"""Stream responses from GPT model.""" |
||||
try: |
||||
stream = self._call_gpt_api(prompt) |
||||
|
||||
response = "" |
||||
for chunk in stream: |
||||
fragment = chunk.choices[0].delta.content or "" |
||||
response += fragment |
||||
yield response |
||||
|
||||
except Exception as e: |
||||
logger.error(f"GPT API error: {str(e)}", exc_info=True) |
||||
yield f"Error with GPT API: {str(e)}" |
||||
|
||||
@retry_with_exponential_backoff( |
||||
max_retries=5, |
||||
initial_delay=1.0, |
||||
exponential_base=2.0, |
||||
retryable_exceptions=(Exception,) |
||||
) |
||||
def _call_claude_api(self, prompt: str): |
||||
"""Call the Claude API with retry logic""" |
||||
return self.claude.messages.stream( |
||||
model=CLAUDE_MODEL, |
||||
max_tokens=4000, |
||||
messages=[{"role": "user", "content": prompt}] |
||||
) |
||||
|
||||
def stream_claude(self, prompt: str) -> Generator[str, None, None]: |
||||
"""Stream responses from Claude model with retry for overloaded errors.""" |
||||
retry_count = 0 |
||||
max_retries = self.max_retries |
||||
delay = 1.0 |
||||
|
||||
while True: |
||||
try: |
||||
result = self._call_claude_api(prompt) |
||||
|
||||
response = "" |
||||
with result as stream: |
||||
for text in stream.text_stream: |
||||
response += text |
||||
yield response |
||||
|
||||
# If we get here, we succeeded, so break out of retry loop |
||||
break |
||||
|
||||
except (AnthropicError, APIError) as e: |
||||
# Special handling for overloaded_error |
||||
if hasattr(e, 'error') and getattr(e, 'error', {}).get('type') == 'overloaded_error': |
||||
if retry_count < max_retries: |
||||
retry_count += 1 |
||||
wait_time = delay * (2 ** (retry_count - 1)) # Exponential backoff |
||||
logger.warning(f"Claude API overloaded, retrying in {wait_time:.2f}s (attempt {retry_count}/{max_retries})") |
||||
time.sleep(wait_time) |
||||
continue |
||||
|
||||
# If reached maximum retries or not an overloaded error |
||||
logger.error(f"Claude API error: {str(e)}", exc_info=True) |
||||
yield f"Error with Claude API: {str(e)}" |
||||
break |
||||
|
||||
except Exception as e: |
||||
logger.error(f"Claude API error: {str(e)}", exc_info=True) |
||||
yield f"Error with Claude API: {str(e)}" |
||||
break |
||||
|
||||
@retry_with_exponential_backoff( |
||||
max_retries=5, |
||||
initial_delay=1.0, |
||||
retryable_exceptions=(Exception,) |
||||
) |
||||
def _call_deepseek_api(self, prompt: str): |
||||
"""Call the DeepSeek API with retry logic""" |
||||
messages = [{"role": "user", "content": prompt}] |
||||
return self.deepseek.chat.completions.create( |
||||
model=DEEPSEEK_MODEL, |
||||
messages=messages, |
||||
stream=True, |
||||
temperature=0.7, |
||||
max_tokens=4000 |
||||
) |
||||
|
||||
def stream_deepseek(self, prompt: str) -> Generator[str, None, None]: |
||||
"""Stream responses from DeepSeek model.""" |
||||
try: |
||||
stream = self._call_deepseek_api(prompt) |
||||
|
||||
reply = "" |
||||
for chunk in stream: |
||||
fragment = chunk.choices[0].delta.content or "" |
||||
reply += fragment |
||||
yield reply |
||||
|
||||
except Exception as e: |
||||
logger.error(f"DeepSeek API error: {str(e)}", exc_info=True) |
||||
yield f"Error with DeepSeek API: {str(e)}" |
||||
|
||||
@retry_with_exponential_backoff( |
||||
max_retries=5, |
||||
initial_delay=1.0, |
||||
retryable_exceptions=(Exception,) |
||||
) |
||||
def _call_groq_api(self, prompt: str): |
||||
"""Call the GROQ API with retry logic""" |
||||
messages = [{"role": "user", "content": prompt}] |
||||
return self.groq.chat.completions.create( |
||||
model=GROQ_MODEL, |
||||
messages=messages, |
||||
stream=True, |
||||
temperature=0.7, |
||||
max_tokens=4000 |
||||
) |
||||
|
||||
def stream_groq(self, prompt: str) -> Generator[str, None, None]: |
||||
"""Stream responses from GROQ model.""" |
||||
try: |
||||
stream = self._call_groq_api(prompt) |
||||
|
||||
reply = "" |
||||
for chunk in stream: |
||||
fragment = chunk.choices[0].delta.content or "" |
||||
reply += fragment |
||||
yield reply |
||||
|
||||
except Exception as e: |
||||
logger.error(f"GROQ API error: {str(e)}", exc_info=True) |
||||
yield f"Error with GROQ API: {str(e)}" |
||||
|
||||
@retry_with_exponential_backoff( |
||||
max_retries=5, |
||||
initial_delay=1.0, |
||||
retryable_exceptions=(Exception,) |
||||
) |
||||
def _call_gemini_api(self, prompt: str): |
||||
"""Call the Gemini API with retry logic""" |
||||
return self.gemini.generate_content( |
||||
prompt, |
||||
generation_config={ |
||||
"temperature": 0.7, |
||||
"top_p": 1, |
||||
"top_k": 1, |
||||
"max_output_tokens": 4000, |
||||
}, |
||||
stream=True |
||||
) |
||||
|
||||
def stream_gemini(self, prompt: str) -> Generator[str, None, None]: |
||||
"""Stream responses from Gemini model.""" |
||||
try: |
||||
response = self._call_gemini_api(prompt) |
||||
|
||||
reply = "" |
||||
for chunk in response: |
||||
if chunk.text: |
||||
reply += chunk.text |
||||
yield reply |
||||
|
||||
except Exception as e: |
||||
logger.error(f"Gemini API error: {str(e)}", exc_info=True) |
||||
yield f"Error with Gemini API: {str(e)}" |
@ -0,0 +1,48 @@
|
||||
ai_converter_v2/ |
||||
├── README.md # Project documentation |
||||
├── requirements.txt # Python dependencies |
||||
├── setup.py # Package installation configuration |
||||
├── run.py # Application entry point |
||||
├── Makefile # Build and development commands |
||||
├── .env.example # Example environment variables |
||||
├── .gitignore # Git ignore patterns |
||||
└── src/ |
||||
└── ai_code_converter/ |
||||
├── __init__.py |
||||
├── main.py # Main application initialization |
||||
├── app.py # Gradio interface and core app logic |
||||
├── config.py # Configuration settings |
||||
├── template.j2 # Code conversion prompt template |
||||
├── core/ # Core functionality modules |
||||
│ ├── __init__.py |
||||
│ ├── code_execution.py # Code execution logic |
||||
│ ├── language_detection.py # Language detection |
||||
│ └── file_utils.py # File operations |
||||
├── models/ # AI model interfaces |
||||
│ ├── __init__.py |
||||
│ └── ai_streaming.py # Streaming implementations |
||||
└── utils/ # Utility functions |
||||
├── __init__.py |
||||
└── logger.py # Logging configuration |
||||
|
||||
Key Components: |
||||
- core/: Core functionality modules |
||||
- code_execution.py: Handles code execution in different languages |
||||
- language_detection.py: Detects and validates programming languages |
||||
- file_utils.py: Handles file operations and downloads |
||||
|
||||
- models/: AI model implementations |
||||
- ai_streaming.py: Streaming implementations for different AI models |
||||
|
||||
- utils/: Utility modules |
||||
- logger.py: Logging configuration and setup |
||||
|
||||
- Configuration: |
||||
- config.py: Central configuration settings |
||||
- template.j2: Prompt template for code conversion |
||||
- .env: Environment variables (API keys) |
||||
|
||||
- Entry Points: |
||||
- run.py: Main entry point |
||||
- main.py: Application initialization |
||||
- app.py: Gradio interface implementation |
@ -0,0 +1,287 @@
|
||||
--- |
||||
description: A template for converting code between different programming languages |
||||
author: AI Conversion Assistant |
||||
--- |
||||
|
||||
You're an AI assistant specialized in code conversion with expertise in: |
||||
- Language-specific idioms, patterns and best practices |
||||
- Performance optimization techniques for each target language |
||||
- Memory management paradigms across different languages |
||||
- Cross-platform compatibility considerations |
||||
- Equivalent library and framework implementations |
||||
- Data structure transformations between languages |
||||
- Type system differences and appropriate conversions |
||||
- Error handling strategies for each language ecosystem |
||||
- Concurrency and parallelism models |
||||
- Standard toolchains and build systems |
||||
|
||||
# CONTEXT |
||||
You will be provided with code written in **{{ source_language }}**. |
||||
Your task is to convert it to **{{ target_language }}**, ensuring that the output produces the same functionality and is optimized for performance. |
||||
|
||||
# INSTRUCTIONS |
||||
- Respond only with **{{ target_language }}** code. |
||||
{% if doc_enabled %}{% else %}- Provide minimal comments, focusing only on critical parts of the code.{% endif %} |
||||
- Use base libraries and packages where possible. |
||||
- Ensure that data types and syntax are correctly adapted between languages. |
||||
- Avoid explanations outside of comments in the code. |
||||
- Maintain identical behavior for functions like random number generation to ensure consistent output. |
||||
|
||||
{% if doc_enabled %} |
||||
# DOCUMENTATION INSTRUCTIONS |
||||
- Include comprehensive documentation in your response following the style specified below. |
||||
- Document the purpose and functionality of classes, functions, and important code blocks. |
||||
- Explain important parameters, return values, and exceptions. |
||||
- Make documentation clear and helpful for new developers to understand the code. |
||||
{% endif %} |
||||
|
||||
{% if target_language == 'Python' %} |
||||
# ADDITIONAL INSTRUCTIONS FOR PYTHON |
||||
- Use Black's default settings |
||||
- Normalize code structure |
||||
- Produce clean, consistent code formatting |
||||
- Use Pythonic idioms and list comprehensions where appropriate. |
||||
- Ensure proper exception handling and type safety. |
||||
- Follow PEP 8 styling conventions. |
||||
- Correct Python indentation (4 spaces) |
||||
- Proper syntax for Python |
||||
- No syntax errors |
||||
- Complete, runnable code |
||||
{% if doc_style == 'google' %} |
||||
- Use Google-style docstrings (summary line, blank line, Args:, Returns:, Raises:) |
||||
{% elif doc_style == 'numpy' %} |
||||
- Use NumPy-style docstrings (summary line, Parameters, Returns, Raises sections) |
||||
{% else %} |
||||
- Follow PEP 257 for docstrings (summary line, blank line, detailed description) |
||||
{% endif %} |
||||
- Ensure all output is done through print() statements |
||||
- For functions that return values, print the return value |
||||
- Use proper Python indentation |
||||
- Include necessary imports at the top |
||||
- Handle exceptions appropriately |
||||
|
||||
{% elif target_language == 'Julia' %} |
||||
# ADDITIONAL INSTRUCTIONS FOR JULIA |
||||
- Use Julia's multiple dispatch where beneficial. |
||||
- Ensure correct handling of data types and performance optimizations. |
||||
- Use built-in functions and packages like `Base` and `LinearAlgebra` if applicable. |
||||
{% if doc_style == 'standard' %} |
||||
- Use standard Julia docstrings with triple quotes """Summary\n\nDetailed description""" |
||||
{% elif doc_style == 'docsystem' %} |
||||
- Use Documenter.jl style docstrings with """Function description\n\n# Arguments\n- `arg1`: description\n# Returns\n- description""" |
||||
{% else %} |
||||
- Include simple docstrings with description of functionality |
||||
{% endif %} |
||||
|
||||
{% elif target_language == 'JavaScript' %} |
||||
# ADDITIONAL INSTRUCTIONS FOR JAVASCRIPT |
||||
- Use ES6+ features where applicable. |
||||
- Ensure asynchronous functions use `async/await` correctly. |
||||
- Follow best practices for variable scoping (`const`, `let`, `var`). |
||||
{% if doc_style == 'jsdoc' %} |
||||
- Use JSDoc comments with @param, @returns, and other appropriate tags |
||||
{% elif doc_style == 'tsdoc' %} |
||||
- Use TSDoc style comments compatible with TypeScript |
||||
{% else %} |
||||
- Use simple block comments with function descriptions |
||||
{% endif %} |
||||
|
||||
{% elif target_language == 'Go' %} |
||||
# ADDITIONAL INSTRUCTIONS FOR GO |
||||
- Use Go idioms such as goroutines for concurrency when needed. |
||||
- Ensure proper handling of errors using Go's `error` type. |
||||
- Optimize for performance using Go's built-in profiling tools. |
||||
{% if doc_style == 'godoc' %} |
||||
- Follow standard GoDoc comment style (starting with function name) |
||||
{% else %} |
||||
- Use clear comments for package-level and exported declarations |
||||
{% endif %} |
||||
|
||||
{% elif target_language == 'Java' %} |
||||
# ADDITIONAL INSTRUCTIONS FOR JAVA |
||||
- Use appropriate class and method structures. |
||||
- Ensure proper handling of exceptions using `try-catch-finally`. |
||||
- Optimize performance using multithreading where applicable. |
||||
{% if doc_style == 'javadoc' %} |
||||
- Use JavaDoc with @param, @return, @throws and other appropriate tags |
||||
{% else %} |
||||
- Use simple block comments with method descriptions |
||||
{% endif %} |
||||
|
||||
{% elif target_language == 'C++' %} |
||||
# ADDITIONAL INSTRUCTIONS FOR C++ |
||||
- Use `#include` directives for necessary libraries. |
||||
- Pay attention to integer overflow issues. |
||||
- Optimize for execution speed where possible using memory management techniques. |
||||
{% if doc_style == 'doxygen' %} |
||||
- Use Doxygen-style comments with @brief, @param, @return tags |
||||
{% else %} |
||||
- Use block comments with function descriptions |
||||
{% endif %} |
||||
|
||||
{% elif target_language == 'Ruby' %} |
||||
# ADDITIONAL INSTRUCTIONS FOR RUBY |
||||
- Use Ruby idioms like blocks, procs, and lambdas where appropriate. |
||||
- Follow Ruby style guidelines (2 space indentation, snake_case for methods). |
||||
- Use Ruby's built-in enumerable methods for collection operations. |
||||
{% if doc_style == 'yard' %} |
||||
- Use YARD documentation style with @param, @return, and other appropriate tags |
||||
{% elif doc_style == 'rdoc' %} |
||||
- Use RDoc documentation style with simple comment blocks |
||||
{% else %} |
||||
- Use simple comment blocks to document methods and classes |
||||
{% endif %} |
||||
|
||||
{% elif target_language == 'Swift' %} |
||||
# ADDITIONAL INSTRUCTIONS FOR SWIFT |
||||
- Use Swift's strong typing system and optional handling. |
||||
- Implement proper error handling with do-catch blocks. |
||||
- Follow Swift naming conventions (camelCase for variables, methods). |
||||
{% if doc_style == 'markdown' %} |
||||
- Use Swift's markdown documentation style with parameters and returns sections |
||||
{% elif doc_style == 'headerDoc' %} |
||||
- Use HeaderDoc style documentation |
||||
{% else %} |
||||
- Use triple-slash /// comments for documentation |
||||
{% endif %} |
||||
|
||||
{% elif target_language == 'Rust' %} |
||||
# ADDITIONAL INSTRUCTIONS FOR RUST |
||||
- Ensure memory safety with proper ownership, borrowing, and lifetimes. |
||||
- Use pattern matching where appropriate. |
||||
- Handle errors with Result and Option types. |
||||
{% if doc_style == 'rustdoc' %} |
||||
- Use standard Rust documentation with triple-slash /// comments |
||||
{% else %} |
||||
- Include documentation comments that explain functionality |
||||
{% endif %} |
||||
|
||||
{% elif target_language == 'C#' %} |
||||
# ADDITIONAL INSTRUCTIONS FOR C# |
||||
- Use appropriate .NET libraries and LINQ where beneficial. |
||||
- Implement proper exception handling. |
||||
- Use C# properties instead of getter/setter methods where appropriate. |
||||
{% if doc_style == 'xml' %} |
||||
- Use XML documentation comments with <summary>, <param>, <returns> tags |
||||
{% else %} |
||||
- Use simple comments to document classes and methods |
||||
{% endif %} |
||||
|
||||
{% elif target_language == 'TypeScript' %} |
||||
# ADDITIONAL INSTRUCTIONS FOR TYPESCRIPT |
||||
- Utilize TypeScript's static typing system. |
||||
- Define appropriate interfaces and types. |
||||
- Use ES6+ features and TypeScript-specific patterns. |
||||
{% if doc_style == 'tsdoc' %} |
||||
- Use TSDoc with @param, @returns, and other appropriate tags |
||||
{% else %} |
||||
- Include simple comments explaining functionality |
||||
{% endif %} |
||||
|
||||
{% elif target_language == 'R' %} |
||||
# ADDITIONAL INSTRUCTIONS FOR R |
||||
- Use R's vectorized operations where possible for performance. |
||||
- Leverage tidyverse packages when appropriate for data manipulation. |
||||
- Follow R style guidelines (snake_case for variables, descriptive names). |
||||
{% if doc_style == 'roxygen2' %} |
||||
- Use roxygen2 style comments with @param, @return, @examples tags |
||||
{% elif doc_style == 'r-native' %} |
||||
- Use R's native documentation system with simple comments |
||||
{% else %} |
||||
- Include comments explaining functionality at the beginning of functions |
||||
{% endif %} |
||||
- Ensure compatibility with R's functional programming paradigm |
||||
- Implement proper error handling with tryCatch() when necessary |
||||
- Make appropriate use of R's specialized data structures like data.frames and lists |
||||
|
||||
{% elif target_language == 'Perl' %} |
||||
# ADDITIONAL INSTRUCTIONS FOR PERL |
||||
- Use Perl's powerful regular expression capabilities when appropriate. |
||||
- Follow Perl's style guidelines including use of sigils and variable naming. |
||||
- Leverage Perl's CPAN modules when beneficial. |
||||
{% if doc_style == 'pod' %} |
||||
- Use Plain Old Documentation (POD) style with =head1, =head2, =item tags |
||||
{% else %} |
||||
- Use block comments to document subroutines and functionality |
||||
{% endif %} |
||||
- Ensure proper handling of scalar vs. list context |
||||
- Use Perl's error handling mechanisms with eval and die/warn |
||||
- Implement appropriate memory management techniques |
||||
|
||||
{% elif target_language == 'Lua' %} |
||||
# ADDITIONAL INSTRUCTIONS FOR LUA |
||||
- Use Lua's lightweight table structure effectively. |
||||
- Follow Lua coding style (no semicolons, use of 'local' variables). |
||||
- Respect Lua's 1-based indexing for arrays and string manipulation. |
||||
{% if doc_style == 'ldoc' %} |
||||
- Use LDoc style comments with @param, @return, and other appropriate tags |
||||
{% else %} |
||||
- Use block comments to document functions and modules |
||||
{% endif %} |
||||
- Leverage Lua's coroutines for concurrent programming when appropriate |
||||
- Implement proper error handling with pcall and xpcall |
||||
- Optimize for Lua's garbage collection |
||||
|
||||
{% elif target_language == 'PHP' %} |
||||
# ADDITIONAL INSTRUCTIONS FOR PHP |
||||
- Follow PHP-FIG standards (PSR-1, PSR-12) for code style. |
||||
- Use modern PHP features (namespaces, type declarations). |
||||
- Implement appropriate error handling with try/catch blocks. |
||||
{% if doc_style == 'phpdoc' %} |
||||
- Use PHPDoc style comments with @param, @return, @throws tags |
||||
{% else %} |
||||
- Use block comments to document classes and methods |
||||
{% endif %} |
||||
- Include necessary composer dependencies |
||||
- Consider performance implications of string operations and array handling |
||||
- Apply appropriate security measures (input validation, output escaping) |
||||
|
||||
{% elif target_language == 'Kotlin' %} |
||||
# ADDITIONAL INSTRUCTIONS FOR KOTLIN |
||||
- Use Kotlin's null safety features and smart casts. |
||||
- Apply functional programming concepts with lambda expressions. |
||||
- Leverage Kotlin's extension functions and properties where appropriate. |
||||
{% if doc_style == 'kdoc' %} |
||||
- Use KDoc style comments with @param, @return, @throws tags |
||||
{% else %} |
||||
- Use block comments to document classes and functions |
||||
{% endif %} |
||||
- Take advantage of Kotlin's coroutines for asynchronous programming |
||||
- Follow Kotlin conventions for naming and structure |
||||
- Implement proper exception handling with try-catch blocks |
||||
|
||||
{% elif target_language == 'SQL' %} |
||||
# ADDITIONAL INSTRUCTIONS FOR SQL |
||||
- Optimize queries for performance with proper indexing hints. |
||||
- Use appropriate SQL dialect features based on the specified database system. |
||||
- Follow SQL style guidelines (uppercase keywords, proper indentation). |
||||
{% if doc_style == 'standard' %} |
||||
- Use standard SQL comment style with detailed descriptions |
||||
{% elif doc_style == 'database-specific' %} |
||||
- Use database-specific comment annotations (e.g., Oracle hints, MySQL comments) |
||||
{% else %} |
||||
- Include simple comments explaining query functionality |
||||
{% endif %} |
||||
- Ensure security by avoiding SQL injection vulnerabilities |
||||
- Consider execution plan optimization in complex queries |
||||
- Apply appropriate transaction handling when necessary |
||||
|
||||
{% endif %} |
||||
|
||||
# INPUT CODE: |
||||
{{ input_code }} |
||||
|
||||
# EXPECTED OUTPUT: |
||||
A fully functional **{{ target_language }}** implementation of the provided code. |
||||
|
||||
Convert this {{ source_language }} code to {{ target_language }}. |
||||
Follow these rules: |
||||
1. Maintain the same functionality |
||||
2. Keep variable names similar when possible |
||||
3. Use idiomatic {{ target_language }} patterns |
||||
4. Include necessary imports |
||||
5. Provide only the converted code without explanations |
||||
|
||||
Here's the code to convert: |
||||
|
||||
{{ input_code }} |
@ -0,0 +1,78 @@
|
||||
--- |
||||
description: A template for converting code between different programming languages |
||||
author: AI Conversion Assistant |
||||
--- |
||||
|
||||
You're an AI assistant specialized in code conversion. |
||||
|
||||
# CONTEXT |
||||
You will be provided with code written in **{{ source_language }}**. |
||||
Your task is to convert it to **{{ target_language }}**, ensuring that the output produces the same functionality and is optimized for performance. |
||||
|
||||
# INSTRUCTIONS |
||||
- Respond only with **{{ target_language }}** code. |
||||
- Provide minimal but useful comments where necessary. |
||||
- Ensure that data types and syntax are correctly adapted between languages. |
||||
- Avoid explanations outside of comments in the code. |
||||
- Maintain identical behavior for functions like random number generation to ensure consistent output. |
||||
|
||||
{% if target_language == 'Python' %} |
||||
# ADDITIONAL INSTRUCTIONS FOR PYTHON |
||||
- Use Pythonic idioms and list comprehensions where appropriate. |
||||
- Ensure proper exception handling and type safety. |
||||
- Follow PEP 8 styling conventions. |
||||
- Ensure all output is done through print() statements |
||||
- For functions that return values, print the return value |
||||
- Use proper Python indentation |
||||
- Include necessary imports at the top |
||||
- Handle exceptions appropriately |
||||
|
||||
{% elif target_language == 'Julia' %} |
||||
# ADDITIONAL INSTRUCTIONS FOR JULIA |
||||
- Use Julia's multiple dispatch where beneficial. |
||||
- Ensure correct handling of data types and performance optimizations. |
||||
- Use built-in functions and packages like `Base` and `LinearAlgebra` if applicable. |
||||
|
||||
{% elif target_language == 'JavaScript' %} |
||||
# ADDITIONAL INSTRUCTIONS FOR JAVASCRIPT |
||||
- Use ES6+ features where applicable. |
||||
- Ensure asynchronous functions use `async/await` correctly. |
||||
- Follow best practices for variable scoping (`const`, `let`, `var`). |
||||
|
||||
{% elif target_language == 'Go' %} |
||||
# ADDITIONAL INSTRUCTIONS FOR GO |
||||
- Use Go idioms such as goroutines for concurrency when needed. |
||||
- Ensure proper handling of errors using Go's `error` type. |
||||
- Optimize for performance using Go's built-in profiling tools. |
||||
|
||||
{% elif target_language == 'Java' %} |
||||
# ADDITIONAL INSTRUCTIONS FOR JAVA |
||||
- Use appropriate class and method structures. |
||||
- Ensure proper handling of exceptions using `try-catch-finally`. |
||||
- Optimize performance using multithreading where applicable. |
||||
|
||||
{% elif target_language == 'C++' %} |
||||
# ADDITIONAL INSTRUCTIONS FOR C++ |
||||
- Use `#include` directives for necessary libraries. |
||||
- Pay attention to integer overflow issues. |
||||
- Optimize for execution speed where possible using memory management techniques. |
||||
|
||||
{% endif %} |
||||
|
||||
# INPUT CODE: |
||||
{{ input_code }} |
||||
|
||||
# EXPECTED OUTPUT: |
||||
A fully functional **{{ target_language }}** implementation of the provided code. |
||||
|
||||
Convert this {{ source_language }} code to {{ target_language }}. |
||||
Follow these rules: |
||||
1. Maintain the same functionality |
||||
2. Keep variable names similar when possible |
||||
3. Use idiomatic {{ target_language }} patterns |
||||
4. Include necessary imports |
||||
5. Provide only the converted code without explanations |
||||
|
||||
Here's the code to convert: |
||||
|
||||
{{ input_code }} |
@ -0,0 +1 @@
|
||||
"""Utility modules.""" |
@ -0,0 +1,132 @@
|
||||
"""Logging configuration for the CodeXchange AI.""" |
||||
|
||||
import json |
||||
import logging |
||||
import logging.handlers |
||||
import os |
||||
import sys |
||||
import threading |
||||
import time |
||||
from datetime import datetime |
||||
from functools import wraps |
||||
from pathlib import Path |
||||
from typing import Any, Callable |
||||
|
||||
class JSONFormatter(logging.Formatter): |
||||
"""Custom JSON formatter for structured logging.""" |
||||
|
||||
def format(self, record: logging.LogRecord) -> str: |
||||
"""Format log record as JSON.""" |
||||
log_data = { |
||||
"timestamp": self.formatTime(record), |
||||
"level": record.levelname, |
||||
"process_id": record.process, |
||||
"thread_id": record.thread, |
||||
"thread_name": record.threadName, |
||||
"module": record.module, |
||||
"function": record.funcName, |
||||
"line": record.lineno, |
||||
"message": record.getMessage() |
||||
} |
||||
|
||||
if hasattr(record, 'duration'): |
||||
log_data['duration'] = f"{record.duration:.4f}s" |
||||
|
||||
if record.exc_info: |
||||
log_data['exception'] = self.formatException(record.exc_info) |
||||
|
||||
return json.dumps(log_data) |
||||
|
||||
def log_execution_time(logger: logging.Logger) -> Callable: |
||||
"""Decorator to log function execution time.""" |
||||
def decorator(func: Callable) -> Callable: |
||||
@wraps(func) |
||||
def wrapper(*args, **kwargs): |
||||
start_time = time.time() |
||||
|
||||
# Log function entry |
||||
logger.debug( |
||||
"Function Entry | %s | Args: %s | Kwargs: %s", |
||||
func.__name__, |
||||
[str(arg) for arg in args], |
||||
{k: str(v) for k, v in kwargs.items() if not any(sensitive in k.lower() for sensitive in ('password', 'key', 'token', 'secret'))} |
||||
) |
||||
|
||||
try: |
||||
result = func(*args, **kwargs) |
||||
duration = time.time() - start_time |
||||
|
||||
# Log function exit |
||||
logger.debug( |
||||
"Function Exit | %s | Duration: %.4fs", |
||||
func.__name__, |
||||
duration |
||||
) |
||||
return result |
||||
|
||||
except Exception as e: |
||||
duration = time.time() - start_time |
||||
logger.error( |
||||
"Function Error | %s | Duration: %.4fs | Error: %s", |
||||
func.__name__, |
||||
duration, |
||||
str(e), |
||||
exc_info=True |
||||
) |
||||
raise |
||||
|
||||
return wrapper |
||||
return decorator |
||||
|
||||
def setup_logger(name: str) -> logging.Logger: |
||||
"""Set up a logger with both file and console output.""" |
||||
# Create logger |
||||
logger = logging.getLogger(name) |
||||
logger.setLevel(logging.DEBUG) |
||||
|
||||
# Clear any existing handlers |
||||
logger.handlers = [] |
||||
|
||||
# Create logs directory |
||||
log_dir = Path("logs") |
||||
log_dir.mkdir(exist_ok=True) |
||||
|
||||
# Create formatters |
||||
console_formatter = logging.Formatter( |
||||
'[%(asctime)s] %(levelname)-8s [%(name)s:%(funcName)s:%(lineno)d] [PID:%(process)d-%(threadName)s] - %(message)s', |
||||
datefmt='%Y-%m-%d %H:%M:%S' |
||||
) |
||||
|
||||
json_formatter = JSONFormatter() |
||||
|
||||
# Console handler with color coding |
||||
console_handler = logging.StreamHandler(sys.stdout) |
||||
console_handler.setLevel(logging.INFO) |
||||
console_handler.setFormatter(console_formatter) |
||||
|
||||
# File handler with daily rotation and JSON formatting |
||||
log_file = log_dir / f"ai_converter_{datetime.now().strftime('%Y-%m-%d')}.json" |
||||
file_handler = logging.handlers.RotatingFileHandler( |
||||
log_file, |
||||
maxBytes=10*1024*1024, # 10MB |
||||
backupCount=30, # Keep 30 backup files |
||||
encoding='utf-8' |
||||
) |
||||
file_handler.setLevel(logging.DEBUG) |
||||
file_handler.setFormatter(json_formatter) |
||||
|
||||
# Add handlers |
||||
logger.addHandler(console_handler) |
||||
logger.addHandler(file_handler) |
||||
|
||||
# Log initialization |
||||
logger.info("="*50) |
||||
logger.info("Logger Initialized") |
||||
logger.info(f"Logger Name: {name}") |
||||
logger.info(f"Log File: {log_file}") |
||||
logger.info(f"Process ID: {os.getpid()}") |
||||
logger.info(f"Thread ID: {threading.get_ident()}") |
||||
logger.info(f"Thread Name: {threading.current_thread().name}") |
||||
logger.info("="*50) |
||||
|
||||
return logger |
@ -0,0 +1,29 @@
|
||||
"""Basic tests for CodeXchange AI application.""" |
||||
|
||||
import pytest |
||||
import os |
||||
import sys |
||||
|
||||
# Add project root to path |
||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) |
||||
|
||||
from src.ai_code_converter.config import SUPPORTED_LANGUAGES, DOCUMENT_STYLES |
||||
|
||||
|
||||
def test_supported_languages(): |
||||
"""Test that supported languages configuration is valid.""" |
||||
assert isinstance(SUPPORTED_LANGUAGES, list) |
||||
assert len(SUPPORTED_LANGUAGES) > 0 |
||||
assert "Python" in SUPPORTED_LANGUAGES |
||||
|
||||
|
||||
def test_document_styles(): |
||||
"""Test that document styles configuration is valid.""" |
||||
assert isinstance(DOCUMENT_STYLES, dict) |
||||
assert len(DOCUMENT_STYLES) > 0 |
||||
|
||||
# Check that each language has at least one document style |
||||
for language in SUPPORTED_LANGUAGES: |
||||
assert language in DOCUMENT_STYLES, f"{language} missing from document styles" |
||||
assert isinstance(DOCUMENT_STYLES[language], list) |
||||
assert len(DOCUMENT_STYLES[language]) > 0 |
@ -0,0 +1,101 @@
|
||||
"""Test module for C# language detection.""" |
||||
|
||||
import sys |
||||
import os |
||||
|
||||
# Add the src directory to the Python path |
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../src'))) |
||||
|
||||
from ai_code_converter.core.language_detection import LanguageDetector |
||||
|
||||
|
||||
def test_csharp_detection(): |
||||
"""Test the C# language detection functionality.""" |
||||
detector = LanguageDetector() |
||||
|
||||
# Sample C# code |
||||
csharp_code = """ |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace MyApp |
||||
{ |
||||
// A simple C# class |
||||
public class Person |
||||
{ |
||||
// Properties |
||||
public string Name { get; set; } |
||||
public int Age { get; private set; } |
||||
|
||||
// Constructor |
||||
public Person(string name, int age) |
||||
{ |
||||
Name = name; |
||||
Age = age; |
||||
} |
||||
|
||||
// Method |
||||
public string Greet() |
||||
{ |
||||
return $"Hello, my name is {Name} and I am {Age} years old."; |
||||
} |
||||
|
||||
// Method with out parameter |
||||
public bool TryParse(string input, out int result) |
||||
{ |
||||
return int.TryParse(input, out result); |
||||
} |
||||
} |
||||
|
||||
// Interface |
||||
public interface IRepository<T> where T : class |
||||
{ |
||||
Task<T> GetByIdAsync(int id); |
||||
Task<IEnumerable<T>> GetAllAsync(); |
||||
Task AddAsync(T entity); |
||||
} |
||||
|
||||
// Async method |
||||
public class DataProcessor |
||||
{ |
||||
public async Task ProcessDataAsync() |
||||
{ |
||||
await Task.Delay(1000); |
||||
Console.WriteLine("Data processed!"); |
||||
} |
||||
} |
||||
|
||||
class Program |
||||
{ |
||||
static void Main(string[] args) |
||||
{ |
||||
// Variable declaration with var |
||||
var person = new Person("John", 30); |
||||
Console.WriteLine(person.Greet()); |
||||
|
||||
// LINQ query |
||||
var numbers = new List<int> { 1, 2, 3, 4, 5 }; |
||||
var evenNumbers = numbers.Where(n => n % 2 == 0).ToList(); |
||||
|
||||
// String interpolation |
||||
string message = $"Found {evenNumbers.Count} even numbers."; |
||||
Console.WriteLine(message); |
||||
} |
||||
} |
||||
} |
||||
""" |
||||
|
||||
# Test the detection |
||||
assert detector.detect_csharp(csharp_code) == True |
||||
assert detector.detect_language(csharp_code) == "C#" |
||||
|
||||
# Check validation |
||||
valid, _ = detector.validate_language(csharp_code, "C#") |
||||
assert valid == True |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
test_csharp_detection() |
||||
print("All C# detection tests passed!") |
@ -0,0 +1,189 @@
|
||||
"""Test module for Kotlin language detection.""" |
||||
|
||||
import sys |
||||
import os |
||||
|
||||
# Add the src directory to the Python path |
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../src'))) |
||||
|
||||
from ai_code_converter.core.language_detection import LanguageDetector |
||||
|
||||
|
||||
def test_kotlin_detection(): |
||||
"""Test the Kotlin language detection functionality.""" |
||||
detector = LanguageDetector() |
||||
|
||||
# Sample Kotlin code |
||||
kotlin_code = """ |
||||
package com.example.myapp |
||||
|
||||
import android.os.Bundle |
||||
import android.widget.Button |
||||
import android.widget.TextView |
||||
import androidx.appcompat.app.AppCompatActivity |
||||
import kotlinx.coroutines.* |
||||
import kotlinx.coroutines.flow.* |
||||
import java.util.* |
||||
|
||||
/** |
||||
* Main Activity for the application |
||||
*/ |
||||
class MainActivity : AppCompatActivity() { |
||||
|
||||
// Properties |
||||
private lateinit var textView: TextView |
||||
private lateinit var button: Button |
||||
private val viewModel: MainViewModel by viewModels() |
||||
private val job = Job() |
||||
private val coroutineScope = CoroutineScope(Dispatchers.Main + job) |
||||
|
||||
// Immutable property |
||||
val API_KEY: String = "abc123" |
||||
|
||||
// Computed property |
||||
val isActive: Boolean |
||||
get() = viewModel.isActive && !isFinishing |
||||
|
||||
// Data class |
||||
data class User( |
||||
val id: Int, |
||||
val name: String, |
||||
val email: String, |
||||
var isActive: Boolean = true |
||||
) |
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) { |
||||
super.onCreate(savedInstanceState) |
||||
setContentView(R.layout.activity_main) |
||||
|
||||
// View binding |
||||
textView = findViewById(R.id.textView) |
||||
button = findViewById(R.id.button) |
||||
|
||||
// Click listener |
||||
button.setOnClickListener { |
||||
fetchData() |
||||
} |
||||
|
||||
// Observe live data |
||||
viewModel.userData.observe(this) { user -> |
||||
updateUI(user) |
||||
} |
||||
|
||||
// Extension function call |
||||
"Hello, Kotlin!".printDebug() |
||||
|
||||
// Using when expression |
||||
val result = when(viewModel.status) { |
||||
Status.LOADING -> "Loading..." |
||||
Status.SUCCESS -> "Success!" |
||||
Status.ERROR -> "Error!" |
||||
else -> "Unknown" |
||||
} |
||||
|
||||
textView.text = result |
||||
} |
||||
|
||||
// Suspend function |
||||
private suspend fun fetchUserData(): User { |
||||
return withContext(Dispatchers.IO) { |
||||
// Simulate network delay |
||||
delay(1000) |
||||
User(1, "John Doe", "john@example.com") |
||||
} |
||||
} |
||||
|
||||
// Coroutine usage |
||||
private fun fetchData() { |
||||
coroutineScope.launch { |
||||
try { |
||||
textView.text = "Loading..." |
||||
val user = fetchUserData() |
||||
updateUI(user) |
||||
} catch (e: Exception) { |
||||
textView.text = "Error: ${e.message}" |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Normal function |
||||
private fun updateUI(user: User) { |
||||
textView.text = "Welcome, ${user.name}!" |
||||
|
||||
// Smart cast |
||||
val info: Any = user.email |
||||
if (info is String) { |
||||
// No need to cast, Kotlin knows it's a String |
||||
textView.text = info.toUpperCase() |
||||
} |
||||
|
||||
// Collection operations |
||||
val numbers = listOf(1, 2, 3, 4, 5) |
||||
val sum = numbers.filter { it % 2 == 0 }.sum() |
||||
|
||||
// String template |
||||
val message = "Sum of even numbers: $sum" |
||||
println(message) |
||||
} |
||||
|
||||
// Higher-order function |
||||
private inline fun performOperation( |
||||
value: Int, |
||||
operation: (Int) -> Int |
||||
): Int { |
||||
return operation(value) |
||||
} |
||||
|
||||
// Companion object |
||||
companion object { |
||||
const val TAG = "MainActivity" |
||||
|
||||
fun newInstance(): MainActivity { |
||||
return MainActivity() |
||||
} |
||||
} |
||||
|
||||
// Enum class |
||||
enum class Status { |
||||
LOADING, |
||||
SUCCESS, |
||||
ERROR |
||||
} |
||||
|
||||
// Interface definition |
||||
interface OnDataLoadListener { |
||||
fun onDataLoaded(data: Any) |
||||
fun onError(message: String) |
||||
} |
||||
|
||||
// Object declaration (singleton) |
||||
object Logger { |
||||
fun log(message: String) { |
||||
println("[$TAG] $message") |
||||
} |
||||
} |
||||
|
||||
// Extension function |
||||
fun String.printDebug() { |
||||
println("Debug: $this") |
||||
} |
||||
|
||||
override fun onDestroy() { |
||||
super.onDestroy() |
||||
job.cancel() // Cancel coroutines when activity is destroyed |
||||
} |
||||
} |
||||
""" |
||||
|
||||
# Test the detection |
||||
assert detector.detect_kotlin(kotlin_code) == True |
||||
assert detector.detect_language(kotlin_code) == "Kotlin" |
||||
|
||||
# Check validation |
||||
valid, _ = detector.validate_language(kotlin_code, "Kotlin") |
||||
assert valid == True |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
test_kotlin_detection() |
||||
print("All Kotlin detection tests passed!") |
@ -0,0 +1,164 @@
|
||||
"""Test module for Lua language detection.""" |
||||
|
||||
import sys |
||||
import os |
||||
|
||||
# Add the src directory to the Python path |
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../src'))) |
||||
|
||||
from ai_code_converter.core.language_detection import LanguageDetector |
||||
|
||||
|
||||
def test_lua_detection(): |
||||
"""Test the Lua language detection functionality.""" |
||||
detector = LanguageDetector() |
||||
|
||||
# Sample Lua code |
||||
lua_code = """ |
||||
-- Simple Lua script |
||||
local function factorial(n) |
||||
if n == 0 then |
||||
return 1 |
||||
else |
||||
return n * factorial(n - 1) |
||||
end |
||||
end |
||||
|
||||
-- Variables |
||||
local name = "John" |
||||
local age = 30 |
||||
local is_active = true |
||||
local value = nil |
||||
|
||||
-- Table creation |
||||
local person = { |
||||
name = "John", |
||||
age = 30, |
||||
email = "john@example.com", |
||||
greet = function(self) |
||||
return "Hello, " .. self.name |
||||
end |
||||
} |
||||
|
||||
-- Accessing table properties |
||||
print(person.name) |
||||
print(person["age"]) |
||||
print(person:greet()) |
||||
|
||||
-- Metatables |
||||
local mt = { |
||||
__add = function(a, b) |
||||
return { value = a.value + b.value } |
||||
end |
||||
} |
||||
|
||||
local obj1 = { value = 10 } |
||||
local obj2 = { value = 20 } |
||||
setmetatable(obj1, mt) |
||||
local result = obj1 + obj2 |
||||
print(result.value) -- 30 |
||||
|
||||
-- Control structures |
||||
for i = 1, 10 do |
||||
print(i) |
||||
end |
||||
|
||||
local fruits = {"apple", "banana", "orange"} |
||||
for i, fruit in ipairs(fruits) do |
||||
print(i, fruit) |
||||
end |
||||
|
||||
for key, value in pairs(person) do |
||||
if type(value) ~= "function" then |
||||
print(key, value) |
||||
end |
||||
end |
||||
|
||||
local count = 1 |
||||
while count <= 5 do |
||||
print(count) |
||||
count = count + 1 |
||||
end |
||||
|
||||
-- Using modules |
||||
local math = require("math") |
||||
print(math.floor(3.14)) |
||||
print(math.random()) |
||||
|
||||
-- String operations |
||||
local message = "Hello, " .. name .. "!" |
||||
print(message) |
||||
print(string.upper(message)) |
||||
print(string.sub(message, 1, 5)) |
||||
print(string.find(message, "Hello")) |
||||
|
||||
-- Multiple return values |
||||
local function get_person() |
||||
return "John", 30, true |
||||
end |
||||
|
||||
local name, age, active = get_person() |
||||
print(name, age, active) |
||||
|
||||
-- Closures |
||||
local function counter() |
||||
local count = 0 |
||||
return function() |
||||
count = count + 1 |
||||
return count |
||||
end |
||||
end |
||||
|
||||
local c1 = counter() |
||||
print(c1()) -- 1 |
||||
print(c1()) -- 2 |
||||
|
||||
-- Error handling |
||||
local status, err = pcall(function() |
||||
error("Something went wrong") |
||||
end) |
||||
|
||||
if not status then |
||||
print("Error:", err) |
||||
end |
||||
|
||||
-- Coroutines |
||||
local co = coroutine.create(function() |
||||
for i = 1, 3 do |
||||
print("Coroutine", i) |
||||
coroutine.yield() |
||||
end |
||||
end) |
||||
|
||||
coroutine.resume(co) -- Coroutine 1 |
||||
coroutine.resume(co) -- Coroutine 2 |
||||
coroutine.resume(co) -- Coroutine 3 |
||||
|
||||
-- Multi-line strings |
||||
local multi_line = [[ |
||||
This is a multi-line |
||||
string in Lua. |
||||
It can contain "quotes" without escaping. |
||||
]] |
||||
print(multi_line) |
||||
|
||||
-- Bit operations (Lua 5.3+) |
||||
local a = 10 -- 1010 in binary |
||||
local b = 6 -- 0110 in binary |
||||
print(a & b) -- AND: 0010 = 2 |
||||
print(a | b) -- OR: 1110 = 14 |
||||
print(a ~ b) -- XOR: 1100 = 12 |
||||
""" |
||||
|
||||
# Test the detection |
||||
assert detector.detect_lua(lua_code) == True |
||||
assert detector.detect_language(lua_code) == "Lua" |
||||
|
||||
# Check validation |
||||
valid, _ = detector.validate_language(lua_code, "Lua") |
||||
assert valid == True |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
test_lua_detection() |
||||
print("All Lua detection tests passed!") |
@ -0,0 +1,174 @@
|
||||
"""Test module for Perl language detection.""" |
||||
|
||||
import sys |
||||
import os |
||||
|
||||
# Add the src directory to the Python path |
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../src'))) |
||||
|
||||
from ai_code_converter.core.language_detection import LanguageDetector |
||||
|
||||
|
||||
def test_perl_detection(): |
||||
"""Test the Perl language detection functionality.""" |
||||
detector = LanguageDetector() |
||||
|
||||
# Sample Perl code |
||||
perl_code = """ |
||||
#!/usr/bin/perl |
||||
use strict; |
||||
use warnings; |
||||
use Data::Dumper; |
||||
use File::Basename; |
||||
use Getopt::Long; |
||||
|
||||
# Scalar variable |
||||
my $name = "John Doe"; |
||||
my $age = 30; |
||||
my $pi = 3.14159; |
||||
|
||||
# Array variables |
||||
my @fruits = ("apple", "banana", "orange"); |
||||
my @numbers = (1..10); |
||||
|
||||
# Hash variables |
||||
my %user = ( |
||||
"name" => "John", |
||||
"age" => 30, |
||||
"email" => "john@example.com" |
||||
); |
||||
|
||||
# Print statements |
||||
print "Hello, $name!\\n"; |
||||
print "Your age is $age\\n"; |
||||
|
||||
# Accessing array elements |
||||
print "First fruit: $fruits[0]\\n"; |
||||
print "Last fruit: $fruits[-1]\\n"; |
||||
|
||||
# Accessing hash elements |
||||
print "User name: $user{name}\\n"; |
||||
print "User email: $user{email}\\n"; |
||||
|
||||
# Subroutine definition |
||||
sub greet { |
||||
my ($person) = @_; |
||||
print "Hello, $person!\\n"; |
||||
return "Greeting sent"; |
||||
} |
||||
|
||||
# Call the subroutine |
||||
my $result = greet($name); |
||||
print "Result: $result\\n"; |
||||
|
||||
# Control structures |
||||
if ($age >= 18) { |
||||
print "You are an adult.\\n"; |
||||
} else { |
||||
print "You are a minor.\\n"; |
||||
} |
||||
|
||||
# Unless example |
||||
unless ($age < 18) { |
||||
print "Not a minor.\\n"; |
||||
} |
||||
|
||||
# For loop |
||||
for my $i (0..$#fruits) { |
||||
print "Fruit $i: $fruits[$i]\\n"; |
||||
} |
||||
|
||||
# Foreach loop |
||||
foreach my $fruit (@fruits) { |
||||
print "I like $fruit\\n"; |
||||
} |
||||
|
||||
# While loop |
||||
my $counter = 0; |
||||
while ($counter < 5) { |
||||
print "Counter: $counter\\n"; |
||||
$counter++; |
||||
} |
||||
|
||||
# Regular expressions |
||||
my $text = "The quick brown fox"; |
||||
if ($text =~ m/quick/) { |
||||
print "Match found!\\n"; |
||||
} |
||||
|
||||
# Substitution |
||||
my $modified = $text; |
||||
$modified =~ s/quick/slow/; |
||||
print "Modified text: $modified\\n"; |
||||
|
||||
# Special variables |
||||
print "Script name: $0\\n"; |
||||
print "Command line arguments: @ARGV\\n"; |
||||
print "Current line: $. \\n"; |
||||
|
||||
# File operations |
||||
open(my $fh, '>', 'output.txt') or die "Cannot open file: $!"; |
||||
print $fh "Hello, Perl!\\n"; |
||||
close $fh; |
||||
|
||||
# Reading from standard input |
||||
print "Enter your name: "; |
||||
my $input = <STDIN>; |
||||
chomp($input); # Remove newline |
||||
print "Hello, $input!\\n"; |
||||
|
||||
# References |
||||
my $array_ref = \\@fruits; |
||||
print "First element via ref: ${$array_ref}[0]\\n"; |
||||
|
||||
my $hash_ref = \\%user; |
||||
print "Name via ref: ${$hash_ref}{name}\\n"; |
||||
|
||||
# Using references for functions |
||||
sub process_data { |
||||
my ($data_ref) = @_; |
||||
foreach my $key (keys %{$data_ref}) { |
||||
print "Key: $key, Value: ${$data_ref}{$key}\\n"; |
||||
} |
||||
} |
||||
|
||||
process_data(\\%user); |
||||
|
||||
# Object-oriented style |
||||
package Person; |
||||
|
||||
sub new { |
||||
my ($class, $name, $age) = @_; |
||||
return bless { name => $name, age => $age }, $class; |
||||
} |
||||
|
||||
sub get_name { |
||||
my ($self) = @_; |
||||
return $self->{name}; |
||||
} |
||||
|
||||
sub get_age { |
||||
my ($self) = @_; |
||||
return $self->{age}; |
||||
} |
||||
|
||||
package main; |
||||
my $person = Person->new("Bob", 25); |
||||
print "Person name: " . $person->get_name() . "\\n"; |
||||
print "Person age: " . $person->get_age() . "\\n"; |
||||
|
||||
exit 0; |
||||
""" |
||||
|
||||
# Test the detection |
||||
assert detector.detect_perl(perl_code) == True |
||||
assert detector.detect_language(perl_code) == "Perl" |
||||
|
||||
# Check validation |
||||
valid, _ = detector.validate_language(perl_code, "Perl") |
||||
assert valid == True |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
test_perl_detection() |
||||
print("All Perl detection tests passed!") |
@ -0,0 +1,184 @@
|
||||
"""Test module for PHP language detection.""" |
||||
|
||||
import sys |
||||
import os |
||||
|
||||
# Add the src directory to the Python path |
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../src'))) |
||||
|
||||
from ai_code_converter.core.language_detection import LanguageDetector |
||||
|
||||
|
||||
def test_php_detection(): |
||||
"""Test the PHP language detection functionality.""" |
||||
detector = LanguageDetector() |
||||
|
||||
# Sample PHP code |
||||
php_code = r""" |
||||
<?php |
||||
// Define namespace |
||||
namespace App\Controllers; |
||||
|
||||
// Import classes |
||||
use App\Models\User; |
||||
use App\Services\AuthService; |
||||
use App\Exceptions\AuthException; |
||||
|
||||
/** |
||||
* Authentication Controller |
||||
* |
||||
* Handles user authentication functionality |
||||
*/ |
||||
class AuthController |
||||
{ |
||||
private $authService; |
||||
|
||||
/** |
||||
* Constructor |
||||
*/ |
||||
public function __construct(AuthService $authService) |
||||
{ |
||||
$this->authService = $authService; |
||||
} |
||||
|
||||
/** |
||||
* Login user |
||||
*/ |
||||
public function login($request) |
||||
{ |
||||
// Get request data |
||||
$email = $request->input('email'); |
||||
$password = $request->input('password'); |
||||
$remember = $request->input('remember', false); |
||||
|
||||
// Validate input |
||||
if (empty($email) || empty($password)) { |
||||
return [ |
||||
'status' => 'error', |
||||
'message' => 'Email and password are required' |
||||
]; |
||||
} |
||||
|
||||
try { |
||||
// Attempt to login |
||||
$user = $this->authService->authenticate($email, $password); |
||||
|
||||
// Create session |
||||
$_SESSION['user_id'] = $user->id; |
||||
|
||||
// Set remember me cookie if requested |
||||
if ($remember) { |
||||
$token = $this->authService->createRememberToken($user->id); |
||||
setcookie('remember_token', $token, time() + 86400 * 30, '/'); |
||||
} |
||||
|
||||
return [ |
||||
'status' => 'success', |
||||
'user' => $user |
||||
]; |
||||
} catch (AuthException $e) { |
||||
return [ |
||||
'status' => 'error', |
||||
'message' => $e->getMessage() |
||||
]; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Register new user |
||||
*/ |
||||
public function register($request) |
||||
{ |
||||
// Get request data |
||||
$name = $request->input('name'); |
||||
$email = $request->input('email'); |
||||
$password = $request->input('password'); |
||||
|
||||
// Validate input |
||||
if (empty($name) || empty($email) || empty($password)) { |
||||
return [ |
||||
'status' => 'error', |
||||
'message' => 'All fields are required' |
||||
]; |
||||
} |
||||
|
||||
// Check if email already exists |
||||
$existingUser = User::findByEmail($email); |
||||
if ($existingUser) { |
||||
return [ |
||||
'status' => 'error', |
||||
'message' => 'Email already registered' |
||||
]; |
||||
} |
||||
|
||||
// Create user |
||||
$user = new User(); |
||||
$user->name = $name; |
||||
$user->email = $email; |
||||
$user->password = password_hash($password, PASSWORD_DEFAULT); |
||||
$user->save(); |
||||
|
||||
// Login user |
||||
$_SESSION['user_id'] = $user->id; |
||||
|
||||
return [ |
||||
'status' => 'success', |
||||
'user' => $user |
||||
]; |
||||
} |
||||
|
||||
/** |
||||
* Logout user |
||||
*/ |
||||
public function logout() |
||||
{ |
||||
// Clear session |
||||
unset($_SESSION['user_id']); |
||||
session_destroy(); |
||||
|
||||
// Clear remember token cookie if it exists |
||||
if (isset($_COOKIE['remember_token'])) { |
||||
setcookie('remember_token', '', time() - 3600, '/'); |
||||
} |
||||
|
||||
return [ |
||||
'status' => 'success', |
||||
'message' => 'Logged out successfully' |
||||
]; |
||||
} |
||||
|
||||
/** |
||||
* Get current user profile |
||||
*/ |
||||
public function profile() |
||||
{ |
||||
if (!isset($_SESSION['user_id'])) { |
||||
return [ |
||||
'status' => 'error', |
||||
'message' => 'Not authenticated' |
||||
]; |
||||
} |
||||
|
||||
$user = User::find($_SESSION['user_id']); |
||||
|
||||
return [ |
||||
'status' => 'success', |
||||
'user' => $user |
||||
]; |
||||
} |
||||
} |
||||
?> |
||||
""" |
||||
|
||||
# Test the detection |
||||
assert detector.detect_php(php_code) == True |
||||
assert detector.detect_language(php_code) == "PHP" |
||||
|
||||
# Check validation |
||||
valid, _ = detector.validate_language(php_code, "PHP") |
||||
assert valid == True |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
test_php_detection() |
||||
print("All PHP detection tests passed!") |
@ -0,0 +1,118 @@
|
||||
"""Test module for R language detection.""" |
||||
|
||||
import sys |
||||
import os |
||||
|
||||
# Add the src directory to the Python path |
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../src'))) |
||||
|
||||
from ai_code_converter.core.language_detection import LanguageDetector |
||||
|
||||
|
||||
def test_r_detection(): |
||||
"""Test the R language detection functionality.""" |
||||
detector = LanguageDetector() |
||||
|
||||
# Sample R code |
||||
r_code = """ |
||||
# Load necessary libraries |
||||
library(tidyverse) |
||||
library(ggplot2) |
||||
library(dplyr) |
||||
|
||||
# Create a data frame |
||||
data <- data.frame( |
||||
name = c("Alice", "Bob", "Charlie", "David"), |
||||
age = c(25, 30, 35, 40), |
||||
score = c(85, 92, 78, 95) |
||||
) |
||||
|
||||
# Basic data operations |
||||
summary(data) |
||||
str(data) |
||||
head(data) |
||||
|
||||
# Create a function |
||||
calculate_average <- function(x) { |
||||
return(mean(x, na.rm = TRUE)) |
||||
} |
||||
|
||||
# Apply the function |
||||
avg_score <- calculate_average(data$score) |
||||
print(paste("Average score:", avg_score)) |
||||
|
||||
# Data manipulation with dplyr |
||||
filtered_data <- data %>% |
||||
filter(age > 30) %>% |
||||
select(name, score) %>% |
||||
arrange(desc(score)) |
||||
|
||||
# Control structures |
||||
if (nrow(filtered_data) > 0) { |
||||
print("Found records with age > 30") |
||||
} else { |
||||
print("No records with age > 30") |
||||
} |
||||
|
||||
# For loop example |
||||
for (i in 1:nrow(data)) { |
||||
if (data$age[i] < 30) { |
||||
data$category[i] <- "Young" |
||||
} else if (data$age[i] < 40) { |
||||
data$category[i] <- "Middle" |
||||
} else { |
||||
data$category[i] <- "Senior" |
||||
} |
||||
} |
||||
|
||||
# Create vectors |
||||
ages <- c(25, 30, 35, 40) |
||||
names <- c("Alice", "Bob", "Charlie", "David") |
||||
|
||||
# Create a list |
||||
person <- list( |
||||
name = "Alice", |
||||
age = 25, |
||||
scores = c(85, 90, 92) |
||||
) |
||||
|
||||
# Access list elements |
||||
person$name |
||||
person$scores[2] |
||||
|
||||
# Create factors |
||||
gender <- factor(c("Male", "Female", "Female", "Male")) |
||||
levels(gender) |
||||
|
||||
# Basic plotting |
||||
plot(data$age, data$score, |
||||
main = "Age vs. Score", |
||||
xlab = "Age", |
||||
ylab = "Score", |
||||
col = "blue", |
||||
pch = 19) |
||||
|
||||
# ggplot visualization |
||||
ggplot(data, aes(x = age, y = score)) + |
||||
geom_point(color = "blue", size = 3) + |
||||
geom_smooth(method = "lm", se = FALSE) + |
||||
labs(title = "Age vs. Score", x = "Age", y = "Score") + |
||||
theme_minimal() |
||||
|
||||
# Statistical analysis |
||||
model <- lm(score ~ age, data = data) |
||||
summary(model) |
||||
""" |
||||
|
||||
# Test the detection |
||||
assert detector.detect_r(r_code) == True |
||||
assert detector.detect_language(r_code) == "R" |
||||
|
||||
# Check validation |
||||
valid, _ = detector.validate_language(r_code, "R") |
||||
assert valid == True |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
test_r_detection() |
||||
print("All R detection tests passed!") |
@ -0,0 +1,57 @@
|
||||
"""Test module for Ruby language detection.""" |
||||
|
||||
import sys |
||||
import os |
||||
|
||||
# Add the src directory to the Python path |
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../src'))) |
||||
|
||||
from ai_code_converter.core.language_detection import LanguageDetector |
||||
|
||||
|
||||
def test_ruby_detection(): |
||||
"""Test the Ruby language detection functionality.""" |
||||
detector = LanguageDetector() |
||||
|
||||
# Sample Ruby code |
||||
ruby_code = """ |
||||
# A simple Ruby class |
||||
class Person |
||||
attr_accessor :name, :age |
||||
|
||||
def initialize(name, age) |
||||
@name = name |
||||
@age = age |
||||
end |
||||
|
||||
def greet |
||||
puts "Hello, my name is #{@name} and I am #{@age} years old." |
||||
end |
||||
end |
||||
|
||||
# Create a new Person |
||||
person = Person.new("John", 30) |
||||
person.greet |
||||
|
||||
# Hash examples |
||||
old_syntax = { :name => "Ruby", :created_by => "Yukihiro Matsumoto" } |
||||
new_syntax = { name: "Ruby", created_by: "Yukihiro Matsumoto" } |
||||
|
||||
# Block with parameters |
||||
[1, 2, 3].each do |num| |
||||
puts num * 2 |
||||
end |
||||
""" |
||||
|
||||
# Test the detection |
||||
assert detector.detect_ruby(ruby_code) == True |
||||
assert detector.detect_language(ruby_code) == "Ruby" |
||||
|
||||
# Check validation |
||||
valid, _ = detector.validate_language(ruby_code, "Ruby") |
||||
assert valid == True |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
test_ruby_detection() |
||||
print("All Ruby detection tests passed!") |
@ -0,0 +1,89 @@
|
||||
"""Test module for Rust language detection.""" |
||||
|
||||
import sys |
||||
import os |
||||
|
||||
# Add the src directory to the Python path |
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../src'))) |
||||
|
||||
from ai_code_converter.core.language_detection import LanguageDetector |
||||
|
||||
|
||||
def test_rust_detection(): |
||||
"""Test the Rust language detection functionality.""" |
||||
detector = LanguageDetector() |
||||
|
||||
# Sample Rust code |
||||
rust_code = """ |
||||
use std::collections::HashMap; |
||||
use std::io::{self, Write}; |
||||
|
||||
// A struct in Rust |
||||
#[derive(Debug, Clone)] |
||||
pub struct Person { |
||||
name: String, |
||||
age: u32, |
||||
} |
||||
|
||||
// Implementation block for Person |
||||
impl Person { |
||||
// Constructor (associated function) |
||||
pub fn new(name: String, age: u32) -> Self { |
||||
Person { name, age } |
||||
} |
||||
|
||||
// Method |
||||
pub fn greet(&self) -> String { |
||||
format!("Hello, my name is {} and I am {} years old.", self.name, self.age) |
||||
} |
||||
|
||||
// Mutable method |
||||
pub fn celebrate_birthday(&mut self) { |
||||
self.age += 1; |
||||
println!("Happy birthday! Now I am {} years old.", self.age); |
||||
} |
||||
} |
||||
|
||||
// A simple function with pattern matching |
||||
fn process_option(opt: Option<i32>) -> i32 { |
||||
match opt { |
||||
Some(value) => value, |
||||
None => -1, |
||||
} |
||||
} |
||||
|
||||
// Main function with vector usage |
||||
fn main() { |
||||
// Create a vector |
||||
let mut numbers: Vec<i32> = vec![1, 2, 3, 4, 5]; |
||||
numbers.push(6); |
||||
|
||||
// Create a Person instance |
||||
let mut person = Person::new(String::from("Alice"), 30); |
||||
println!("{}", person.greet()); |
||||
person.celebrate_birthday(); |
||||
|
||||
// Use a HashMap |
||||
let mut scores = HashMap::new(); |
||||
scores.insert(String::from("Blue"), 10); |
||||
scores.insert(String::from("Red"), 50); |
||||
|
||||
// Pattern matching with if let |
||||
if let Some(score) = scores.get("Blue") { |
||||
println!("Blue team score: {}", score); |
||||
} |
||||
} |
||||
""" |
||||
|
||||
# Test the detection |
||||
assert detector.detect_rust(rust_code) == True |
||||
assert detector.detect_language(rust_code) == "Rust" |
||||
|
||||
# Check validation |
||||
valid, _ = detector.validate_language(rust_code, "Rust") |
||||
assert valid == True |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
test_rust_detection() |
||||
print("All Rust detection tests passed!") |
@ -0,0 +1,209 @@
|
||||
"""Test module for SQL language detection.""" |
||||
|
||||
import sys |
||||
import os |
||||
|
||||
# Add the src directory to the Python path |
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../src'))) |
||||
|
||||
from ai_code_converter.core.language_detection import LanguageDetector |
||||
|
||||
|
||||
def test_sql_detection(): |
||||
"""Test the SQL language detection functionality.""" |
||||
detector = LanguageDetector() |
||||
|
||||
# Sample SQL code |
||||
sql_code = """ |
||||
-- Create database |
||||
CREATE DATABASE ecommerce; |
||||
|
||||
-- Use the database |
||||
USE ecommerce; |
||||
|
||||
-- Create tables |
||||
CREATE TABLE customers ( |
||||
customer_id INT PRIMARY KEY AUTO_INCREMENT, |
||||
first_name VARCHAR(50) NOT NULL, |
||||
last_name VARCHAR(50) NOT NULL, |
||||
email VARCHAR(100) UNIQUE NOT NULL, |
||||
password VARCHAR(255) NOT NULL, |
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP, |
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, |
||||
is_active BOOLEAN DEFAULT TRUE |
||||
); |
||||
|
||||
CREATE TABLE categories ( |
||||
category_id INT PRIMARY KEY AUTO_INCREMENT, |
||||
name VARCHAR(100) NOT NULL, |
||||
description TEXT, |
||||
parent_id INT, |
||||
FOREIGN KEY (parent_id) REFERENCES categories(category_id) |
||||
); |
||||
|
||||
CREATE TABLE products ( |
||||
product_id INT PRIMARY KEY AUTO_INCREMENT, |
||||
name VARCHAR(100) NOT NULL, |
||||
description TEXT, |
||||
price DECIMAL(10, 2) NOT NULL, |
||||
stock_quantity INT DEFAULT 0, |
||||
category_id INT, |
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP, |
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, |
||||
FOREIGN KEY (category_id) REFERENCES categories(category_id) |
||||
); |
||||
|
||||
CREATE TABLE orders ( |
||||
order_id INT PRIMARY KEY AUTO_INCREMENT, |
||||
customer_id INT NOT NULL, |
||||
order_date DATETIME DEFAULT CURRENT_TIMESTAMP, |
||||
status ENUM('pending', 'processing', 'shipped', 'delivered', 'cancelled') DEFAULT 'pending', |
||||
total_amount DECIMAL(10, 2) NOT NULL, |
||||
FOREIGN KEY (customer_id) REFERENCES customers(customer_id) |
||||
); |
||||
|
||||
CREATE TABLE order_items ( |
||||
order_item_id INT PRIMARY KEY AUTO_INCREMENT, |
||||
order_id INT NOT NULL, |
||||
product_id INT NOT NULL, |
||||
quantity INT NOT NULL, |
||||
price DECIMAL(10, 2) NOT NULL, |
||||
FOREIGN KEY (order_id) REFERENCES orders(order_id), |
||||
FOREIGN KEY (product_id) REFERENCES products(product_id) |
||||
); |
||||
|
||||
-- Insert sample data |
||||
INSERT INTO categories (name, description) |
||||
VALUES ('Electronics', 'Electronic devices and gadgets'), |
||||
('Clothing', 'Apparel and accessories'), |
||||
('Books', 'Books and publications'); |
||||
|
||||
INSERT INTO products (name, description, price, stock_quantity, category_id) |
||||
VALUES ('Smartphone', 'Latest smartphone with advanced features', 699.99, 100, 1), |
||||
('Laptop', 'High-performance laptop for professionals', 1299.99, 50, 1), |
||||
('T-shirt', 'Cotton t-shirt in various colors', 19.99, 200, 2), |
||||
('Jeans', 'Classic denim jeans', 49.99, 150, 2), |
||||
('Programming Book', 'Learn programming from experts', 39.99, 75, 3); |
||||
|
||||
-- Simple queries |
||||
SELECT * FROM products WHERE price > 50.00; |
||||
|
||||
SELECT p.name, p.price, c.name AS category |
||||
FROM products p |
||||
JOIN categories c ON p.category_id = c.category_id |
||||
WHERE p.stock_quantity > 0 |
||||
ORDER BY p.price DESC; |
||||
|
||||
-- Aggregate functions |
||||
SELECT |
||||
c.name AS category, |
||||
COUNT(p.product_id) AS product_count, |
||||
AVG(p.price) AS average_price, |
||||
MIN(p.price) AS min_price, |
||||
MAX(p.price) AS max_price |
||||
FROM products p |
||||
JOIN categories c ON p.category_id = c.category_id |
||||
GROUP BY c.name |
||||
HAVING COUNT(p.product_id) > 1; |
||||
|
||||
-- Transactions |
||||
BEGIN TRANSACTION; |
||||
|
||||
UPDATE products |
||||
SET stock_quantity = stock_quantity - 1 |
||||
WHERE product_id = 1; |
||||
|
||||
INSERT INTO orders (customer_id, total_amount) |
||||
VALUES (1, 699.99); |
||||
|
||||
INSERT INTO order_items (order_id, product_id, quantity, price) |
||||
VALUES (LAST_INSERT_ID(), 1, 1, 699.99); |
||||
|
||||
COMMIT; |
||||
|
||||
-- Views |
||||
CREATE VIEW product_details AS |
||||
SELECT |
||||
p.product_id, |
||||
p.name, |
||||
p.description, |
||||
p.price, |
||||
p.stock_quantity, |
||||
c.name AS category |
||||
FROM products p |
||||
JOIN categories c ON p.category_id = c.category_id; |
||||
|
||||
-- Stored procedure |
||||
DELIMITER // |
||||
CREATE PROCEDURE get_product_inventory() |
||||
BEGIN |
||||
SELECT |
||||
p.name, |
||||
p.stock_quantity, |
||||
CASE |
||||
WHEN p.stock_quantity = 0 THEN 'Out of Stock' |
||||
WHEN p.stock_quantity < 10 THEN 'Low Stock' |
||||
WHEN p.stock_quantity < 50 THEN 'Medium Stock' |
||||
ELSE 'Well Stocked' |
||||
END AS stock_status |
||||
FROM products p |
||||
ORDER BY p.stock_quantity; |
||||
END // |
||||
DELIMITER ; |
||||
|
||||
-- Triggers |
||||
DELIMITER // |
||||
CREATE TRIGGER after_order_insert |
||||
AFTER INSERT ON orders |
||||
FOR EACH ROW |
||||
BEGIN |
||||
INSERT INTO order_history (order_id, customer_id, status, action) |
||||
VALUES (NEW.order_id, NEW.customer_id, NEW.status, 'created'); |
||||
END // |
||||
DELIMITER ; |
||||
|
||||
-- Indexes |
||||
CREATE INDEX idx_product_price ON products(price); |
||||
CREATE INDEX idx_order_customer ON orders(customer_id); |
||||
|
||||
-- Subqueries |
||||
SELECT c.name, c.email |
||||
FROM customers c |
||||
WHERE c.customer_id IN ( |
||||
SELECT DISTINCT o.customer_id |
||||
FROM orders o |
||||
JOIN order_items oi ON o.order_id = oi.order_id |
||||
JOIN products p ON oi.product_id = p.product_id |
||||
WHERE p.category_id = 1 |
||||
); |
||||
|
||||
-- Common Table Expressions (CTE) |
||||
WITH high_value_orders AS ( |
||||
SELECT |
||||
o.order_id, |
||||
o.customer_id, |
||||
o.total_amount |
||||
FROM orders o |
||||
WHERE o.total_amount > 500 |
||||
) |
||||
SELECT |
||||
c.first_name, |
||||
c.last_name, |
||||
COUNT(hvo.order_id) AS high_value_order_count |
||||
FROM customers c |
||||
JOIN high_value_orders hvo ON c.customer_id = hvo.customer_id |
||||
GROUP BY c.customer_id; |
||||
""" |
||||
|
||||
# Test the detection |
||||
assert detector.detect_sql(sql_code) == True |
||||
assert detector.detect_language(sql_code) == "SQL" |
||||
|
||||
# Check validation |
||||
valid, _ = detector.validate_language(sql_code, "SQL") |
||||
assert valid == True |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
test_sql_detection() |
||||
print("All SQL detection tests passed!") |
@ -0,0 +1,96 @@
|
||||
"""Test module for Swift language detection.""" |
||||
|
||||
import sys |
||||
import os |
||||
|
||||
# Add the src directory to the Python path |
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../src'))) |
||||
|
||||
from ai_code_converter.core.language_detection import LanguageDetector |
||||
|
||||
|
||||
def test_swift_detection(): |
||||
"""Test the Swift language detection functionality.""" |
||||
detector = LanguageDetector() |
||||
|
||||
# Sample Swift code |
||||
swift_code = """ |
||||
import Foundation |
||||
import UIKit |
||||
|
||||
// A simple Swift class |
||||
class Person { |
||||
var name: String |
||||
var age: Int |
||||
|
||||
init(name: String, age: Int) { |
||||
self.name = name |
||||
self.age = age |
||||
} |
||||
|
||||
func greet() -> String { |
||||
return "Hello, my name is \(name) and I am \(age) years old." |
||||
} |
||||
|
||||
func celebrateBirthday() { |
||||
age += 1 |
||||
print("Happy birthday! Now I am \(age) years old.") |
||||
} |
||||
} |
||||
|
||||
// Swift structs |
||||
struct Point { |
||||
let x: Double |
||||
let y: Double |
||||
|
||||
func distanceTo(point: Point) -> Double { |
||||
return sqrt(pow(point.x - x, 2) + pow(point.y - y, 2)) |
||||
} |
||||
} |
||||
|
||||
// Swift optional binding |
||||
func processName(name: String?) { |
||||
if let unwrappedName = name { |
||||
print("Hello, \(unwrappedName)!") |
||||
} else { |
||||
print("Hello, anonymous!") |
||||
} |
||||
} |
||||
|
||||
// Guard statement |
||||
func process(value: Int?) { |
||||
guard let value = value else { |
||||
print("Value is nil") |
||||
return |
||||
} |
||||
|
||||
print("Value is \(value)") |
||||
} |
||||
|
||||
// UIKit elements |
||||
class MyViewController: UIViewController { |
||||
@IBOutlet weak var nameLabel: UILabel! |
||||
|
||||
@IBAction func buttonPressed(_ sender: UIButton) { |
||||
nameLabel.text = "Button was pressed!" |
||||
} |
||||
|
||||
override func viewDidLoad() { |
||||
super.viewDidLoad() |
||||
// Do additional setup |
||||
} |
||||
} |
||||
""" |
||||
|
||||
# Test the detection |
||||
assert detector.detect_swift(swift_code) == True |
||||
assert detector.detect_language(swift_code) == "Swift" |
||||
|
||||
# Check validation |
||||
valid, _ = detector.validate_language(swift_code, "Swift") |
||||
assert valid == True |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
test_swift_detection() |
||||
print("All Swift detection tests passed!") |
@ -0,0 +1,148 @@
|
||||
"""Test module for TypeScript language detection.""" |
||||
|
||||
import sys |
||||
import os |
||||
|
||||
# Add the src directory to the Python path |
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../src'))) |
||||
|
||||
from ai_code_converter.core.language_detection import LanguageDetector |
||||
|
||||
|
||||
def test_typescript_detection(): |
||||
"""Test the TypeScript language detection functionality.""" |
||||
detector = LanguageDetector() |
||||
|
||||
# Sample TypeScript code |
||||
typescript_code = """ |
||||
import { Component, OnInit } from '@angular/core'; |
||||
import axios from 'axios'; |
||||
|
||||
// Interface definition |
||||
interface User { |
||||
id: number; |
||||
name: string; |
||||
email: string; |
||||
isActive: boolean; |
||||
} |
||||
|
||||
// Type alias |
||||
type UserResponse = User[] | null; |
||||
|
||||
// Enum |
||||
enum UserRole { |
||||
Admin = 'ADMIN', |
||||
User = 'USER', |
||||
Guest = 'GUEST' |
||||
} |
||||
|
||||
// Class with type annotations |
||||
export class UserService { |
||||
private apiUrl: string; |
||||
private users: User[] = []; |
||||
|
||||
constructor(baseUrl: string) { |
||||
this.apiUrl = `${baseUrl}/users`; |
||||
} |
||||
|
||||
// Async method with return type |
||||
public async getUsers(): Promise<User[]> { |
||||
try { |
||||
const response = await axios.get<UserResponse>(this.apiUrl); |
||||
if (response.data) { |
||||
this.users = response.data; |
||||
return this.users; |
||||
} |
||||
return []; |
||||
} catch (error) { |
||||
console.error('Error fetching users:', error); |
||||
return []; |
||||
} |
||||
} |
||||
|
||||
// Method with typed parameters |
||||
public getUserById(id: number): User | undefined { |
||||
return this.users.find(user => user.id === id); |
||||
} |
||||
|
||||
// Method with union type parameters |
||||
public filterUsers(status: boolean | null): User[] { |
||||
if (status === null) return this.users; |
||||
return this.users.filter(user => user.isActive === status); |
||||
} |
||||
} |
||||
|
||||
// Generic class |
||||
class DataStore<T> { |
||||
private items: T[] = []; |
||||
|
||||
public add(item: T): void { |
||||
this.items.push(item); |
||||
} |
||||
|
||||
public getAll(): T[] { |
||||
return this.items; |
||||
} |
||||
} |
||||
|
||||
// Decorator example |
||||
@Component({ |
||||
selector: 'app-user-list', |
||||
template: '<div>User List Component</div>' |
||||
}) |
||||
class UserListComponent implements OnInit { |
||||
users: User[] = []; |
||||
userService: UserService; |
||||
|
||||
constructor() { |
||||
this.userService = new UserService('https://api.example.com'); |
||||
} |
||||
|
||||
async ngOnInit(): Promise<void> { |
||||
this.users = await this.userService.getUsers(); |
||||
console.log('Users loaded:', this.users.length); |
||||
} |
||||
} |
||||
|
||||
// Function with default parameters |
||||
function createUser(name: string, email: string, isActive: boolean = true): User { |
||||
const id = Math.floor(Math.random() * 1000); |
||||
return { id, name, email, isActive }; |
||||
} |
||||
|
||||
// Main code |
||||
const userStore = new DataStore<User>(); |
||||
const newUser = createUser('John Doe', 'john@example.com'); |
||||
userStore.add(newUser); |
||||
|
||||
console.log('Users in store:', userStore.getAll().length); |
||||
""" |
||||
|
||||
# Test the detection |
||||
assert detector.detect_typescript(typescript_code) == True |
||||
assert detector.detect_language(typescript_code) == "TypeScript" |
||||
|
||||
# Check that it's distinguishable from JavaScript |
||||
js_code = """ |
||||
function greet(name) { |
||||
console.log(`Hello, ${name}!`); |
||||
} |
||||
|
||||
const user = { |
||||
name: 'John', |
||||
age: 30 |
||||
}; |
||||
|
||||
greet(user.name); |
||||
""" |
||||
assert detector.detect_typescript(js_code) == False |
||||
assert detector.detect_language(js_code) == "JavaScript" |
||||
|
||||
# Check validation |
||||
valid, _ = detector.validate_language(typescript_code, "TypeScript") |
||||
assert valid == True |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
test_typescript_detection() |
||||
print("All TypeScript detection tests passed!") |
@ -0,0 +1,332 @@
|
||||
import gradio as gr |
||||
|
||||
# Define custom CSS with dark theme fixes, updated to use html.dark |
||||
custom_css = """ |
||||
/* Root variables for light theme */ |
||||
:root { |
||||
--background: #ffffff; |
||||
--secondary-background: #f7f7f7; |
||||
--tertiary-background: #f0f0f0; |
||||
--text: #000000; |
||||
--secondary-text: #5d5d5d; |
||||
--border: #e0e0e0; |
||||
--accent: #ff7b2c; |
||||
--accent-hover: #ff6a14; |
||||
--button-text: #ffffff; |
||||
--code-bg: #f7f7f7; |
||||
--code-text: #000000; |
||||
--dropdown-bg: #ffffff; |
||||
--slider-track: #e0e0e0; |
||||
--slider-thumb: #ff7b2c; |
||||
--collapsible-header: #f0f0f0; |
||||
--primary-button-bg: #4a6ee0; /* Blue */ |
||||
--primary-button-hover: #3a5ec8; |
||||
--secondary-button-bg: #444444; |
||||
--secondary-button-hover: #555555; |
||||
--danger-button-bg: #e74c3c; /* Red */ |
||||
--danger-button-hover: #c0392b; |
||||
--success-button-bg: #e67e22; /* Orange */ |
||||
--success-button-hover: #d35400; |
||||
} |
||||
|
||||
/* Dark theme variables using html.dark */ |
||||
html.dark { |
||||
--background: #1a1a1a; |
||||
--secondary-background: #252525; |
||||
--tertiary-background: #2a2a2a; |
||||
--text: #ffffff; |
||||
--secondary-text: #cccccc; |
||||
--border: #444444; |
||||
--accent: #ff7b2c; |
||||
--accent-hover: #ff6a14; |
||||
--button-text: #ffffff; |
||||
--code-bg: #252525; |
||||
--code-text: #ffffff; |
||||
--dropdown-bg: #2a2a2a; |
||||
--slider-track: #444444; |
||||
--slider-thumb: #ff7b2c; |
||||
--collapsible-header: #333333; |
||||
--primary-button-bg: #4a6ee0; |
||||
--primary-button-hover: #3a5ec8; |
||||
--secondary-button-bg: #444444; |
||||
--secondary-button-hover: #555555; |
||||
--danger-button-bg: #e74c3c; |
||||
--danger-button-hover: #c0392b; |
||||
--success-button-bg: #e67e22; |
||||
--success-button-hover: #d35400; |
||||
} |
||||
|
||||
/* Base styles */ |
||||
body { |
||||
background-color: var(--background) !important; |
||||
color: var(--text) !important; |
||||
transition: all 0.3s ease; |
||||
} |
||||
|
||||
.gradio-container { |
||||
background-color: var(--background) !important; |
||||
max-width: 100% !important; |
||||
} |
||||
|
||||
/* Headers */ |
||||
h1, h2, h3, h4, h5, h6, .gr-header { |
||||
color: var(--text) !important; |
||||
} |
||||
|
||||
/* Panels and blocks */ |
||||
.gr-panel, .gr-form, .gr-box, .gr-block { |
||||
background-color: var(--secondary-background) !important; |
||||
color: var(--text) !important; |
||||
border-color: var(--border) !important; |
||||
border-radius: 6px !important; |
||||
} |
||||
|
||||
/* Validation messages section */ |
||||
.gr-accordion .gr-panel { |
||||
background-color: var(--secondary-background) !important; |
||||
color: var(--text) !important; |
||||
border-color: #e74c3c !important; /* Red border */ |
||||
} |
||||
|
||||
.gr-accordion-header { |
||||
background-color: var(--collapsible-header) !important; |
||||
color: var(--text) !important; |
||||
} |
||||
|
||||
/* Code editors */ |
||||
.codebox, .code-editor, .cm-editor { |
||||
background-color: var(--code-bg) !important; |
||||
color: var(--code-text) !important; |
||||
border: 1px solid var(--border) !important; |
||||
border-radius: 4px !important; |
||||
} |
||||
|
||||
/* Syntax highlighting */ |
||||
.cm-editor .cm-content, .cm-editor .cm-line { |
||||
color: var(--code-text) !important; |
||||
} |
||||
.cm-editor .cm-keyword { color: #ff79c6 !important; } /* Pink */ |
||||
.cm-editor .cm-number { color: #bd93f9 !important; } /* Purple */ |
||||
.cm-editor .cm-string { color: #f1fa8c !important; } /* Yellow */ |
||||
.cm-editor .cm-comment { color: #6272a4 !important; } /* Gray */ |
||||
|
||||
/* Buttons */ |
||||
.gr-button { |
||||
background-color: var(--tertiary-background) !important; |
||||
color: var(--text) !important; |
||||
border-color: var(--border) !important; |
||||
border-radius: 4px !important; |
||||
} |
||||
.gr-button.success { |
||||
background-color: var(--success-button-bg) !important; |
||||
color: var(--button-text) !important; |
||||
} |
||||
.gr-button.success:hover { |
||||
background-color: var(--success-button-hover) !important; |
||||
} |
||||
.gr-button.danger { |
||||
background-color: var(--danger-button-bg) !important; |
||||
color: var(--button-text) !important; |
||||
} |
||||
.gr-button.danger:hover { |
||||
background-color: var(--danger-button-hover) !important; |
||||
} |
||||
.gr-button.secondary { |
||||
background-color: var(--secondary-button-bg) !important; |
||||
color: var(--button-text) !important; |
||||
} |
||||
.gr-button.secondary:hover { |
||||
background-color: var(--secondary-button-hover) !important; |
||||
} |
||||
|
||||
/* File upload */ |
||||
.gr-file, .gr-file-upload { |
||||
background-color: var(--secondary-background) !important; |
||||
color: var(--text) !important; |
||||
border-color: var(--border) !important; |
||||
} |
||||
|
||||
/* Dropdowns */ |
||||
.gr-dropdown, .gr-dropdown-container, .gr-dropdown select, .gr-dropdown option { |
||||
background-color: var(--dropdown-bg) !important; |
||||
color: var(--text) !important; |
||||
border-color: var(--border) !important; |
||||
} |
||||
|
||||
/* Slider */ |
||||
.gr-slider { |
||||
background-color: var(--background) !important; |
||||
} |
||||
.gr-slider-track { |
||||
background-color: var(--slider-track) !important; |
||||
} |
||||
.gr-slider-handle { |
||||
background-color: var(--slider-thumb) !important; |
||||
} |
||||
.gr-slider-value { |
||||
color: var(--text) !important; |
||||
} |
||||
|
||||
/* Code output */ |
||||
.gr-code { |
||||
background-color: var(--code-bg) !important; |
||||
color: var(--code-text) !important; |
||||
border-color: var(--border) !important; |
||||
} |
||||
|
||||
/* Footer */ |
||||
.footer { |
||||
color: var(--secondary-text) !important; |
||||
} |
||||
.footer a { |
||||
color: var(--accent) !important; |
||||
} |
||||
""" |
||||
|
||||
# JavaScript for theme toggling and initialization |
||||
js_code = """ |
||||
<script> |
||||
function toggleTheme(theme) { |
||||
var url = new URL(window.location.href); |
||||
if (theme === "dark") { |
||||
url.searchParams.set('__theme', 'dark'); |
||||
} else { |
||||
url.searchParams.delete('__theme'); |
||||
} |
||||
window.location.href = url.href; |
||||
} |
||||
|
||||
// Set the radio button based on current theme |
||||
document.addEventListener('DOMContentLoaded', function() { |
||||
var urlParams = new URLSearchParams(window.location.search); |
||||
var currentTheme = urlParams.get('__theme'); |
||||
if (currentTheme === 'dark') { |
||||
document.querySelector('#theme_radio_container input[value="dark"]').checked = true; |
||||
} else { |
||||
document.querySelector('#theme_radio_container input[value="light"]').checked = true; |
||||
} |
||||
}); |
||||
</script> |
||||
""" |
||||
|
||||
# Language and model options |
||||
INPUT_LANGUAGES = ["Python", "JavaScript", "Java", "TypeScript", "Swift", "C#", "Ruby", "Go", "Rust", "PHP"] |
||||
OUTPUT_LANGUAGES = ["Python", "JavaScript", "Java", "TypeScript", "Swift", "C#", "Ruby", "Go", "Rust", "PHP", "Julia"] |
||||
MODELS = ["GPT", "Claude", "CodeLlama", "Llama", "Gemini"] |
||||
DOC_STYLES = ["standard", "detailed", "minimal"] |
||||
|
||||
# Build the interface |
||||
with gr.Blocks(css=custom_css, theme=gr.themes.Base()) as demo: |
||||
# Inject the JavaScript code |
||||
gr.HTML(js_code) |
||||
|
||||
# States for dynamic button text |
||||
input_lang_state = gr.State("Python") |
||||
output_lang_state = gr.State("JavaScript") |
||||
|
||||
# Header |
||||
with gr.Row(elem_classes="header-container"): |
||||
gr.HTML("<h1 class='header-title'>AI CodeXchange</h1>") |
||||
# Theme selection radio and apply button |
||||
theme_radio = gr.Radio(["light", "dark"], label="Theme", elem_id="theme_radio_container", value="dark") |
||||
theme_button = gr.Button("Apply Theme") |
||||
|
||||
# Validation Messages |
||||
with gr.Accordion("Validation Messages", open=True): |
||||
with gr.Row(): |
||||
with gr.Column(): |
||||
input_code = gr.Code(language="python", label="Code In", lines=15, elem_classes="code-container") |
||||
with gr.Column(): |
||||
output_code = gr.Code(language="javascript", label="Converted Code", lines=15, elem_classes="code-container") |
||||
|
||||
# Configuration Options |
||||
with gr.Row(): |
||||
input_lang = gr.Dropdown(INPUT_LANGUAGES, label="Code In", value="Python") |
||||
output_lang = gr.Dropdown(OUTPUT_LANGUAGES, label="Code Out", value="JavaScript") |
||||
model = gr.Dropdown(MODELS, label="Model", value="GPT") |
||||
temperature = gr.Slider(minimum=0, maximum=1, step=0.1, value=0.7, label="Temperature") |
||||
|
||||
# Document Options |
||||
with gr.Row(): |
||||
document_check = gr.Checkbox(label="Document", value=True) |
||||
doc_style = gr.Dropdown(DOC_STYLES, label="Document Style", value="standard") |
||||
|
||||
# File Upload |
||||
with gr.Accordion("Upload", open=True): |
||||
file_upload = gr.File(label="Drop File Here - or - Click to Upload") |
||||
|
||||
# Action Buttons |
||||
with gr.Row(elem_classes="button-row"): |
||||
convert_btn = gr.Button("Convert", elem_classes="success") |
||||
clear_btn = gr.Button("Clear All", elem_classes="danger") |
||||
|
||||
# Run Buttons |
||||
with gr.Row(elem_classes="button-row"): |
||||
run_source = gr.Button("Run Source Code", elem_classes="secondary") |
||||
run_target = gr.Button("Run Target Code", elem_classes="secondary") |
||||
|
||||
# Results |
||||
with gr.Row(): |
||||
source_result = gr.Code(label="Source Code Result", language="python", lines=10, elem_classes="code-container") |
||||
target_result = gr.Code(label="Converted Code Result", language="javascript", lines=10, elem_classes="code-container") |
||||
|
||||
# Download |
||||
with gr.Accordion("Download", open=True): |
||||
with gr.Row(): |
||||
dl_source = gr.Button("Download Source Code") |
||||
dl_target = gr.Button("Download Converted Code") |
||||
|
||||
# Footer |
||||
with gr.Row(elem_classes="footer"): |
||||
gr.HTML("<div>Use via API</div><div>•</div><div>Built with Gradio</div><div>•</div><div>Settings</div>") |
||||
|
||||
# Theme toggle event |
||||
theme_button.click( |
||||
fn=None, |
||||
inputs=None, |
||||
outputs=[], |
||||
js=""" |
||||
var theme = document.querySelector('#theme_radio_container input:checked').value; |
||||
toggleTheme(theme); |
||||
""" |
||||
) |
||||
|
||||
# Existing event handlers |
||||
def convert_code(input_code, in_lang, out_lang, model, temp, doc, doc_style): |
||||
return f"// Converted from {in_lang} to {out_lang} using {model}\n// Temperature: {temp}\n// Documentation: {doc} ({doc_style if doc else 'N/A'})" |
||||
|
||||
convert_btn.click(fn=convert_code, inputs=[input_code, input_lang_state, output_lang_state, model, temperature, document_check, doc_style], outputs=[output_code]) |
||||
|
||||
def update_convert_btn_text(in_lang, out_lang): |
||||
return f"Convert {in_lang} to {out_lang}", in_lang, out_lang |
||||
|
||||
input_lang.change(fn=update_convert_btn_text, inputs=[input_lang, output_lang], outputs=[convert_btn, input_lang_state, output_lang_state]) |
||||
output_lang.change(fn=update_convert_btn_text, inputs=[input_lang, output_lang], outputs=[convert_btn, input_lang_state, output_lang_state]) |
||||
|
||||
def update_run_btn_text(in_lang, out_lang): |
||||
return f"Run {in_lang}", f"Run {out_lang}" |
||||
|
||||
input_lang.change(fn=update_run_btn_text, inputs=[input_lang, output_lang], outputs=[run_source, run_target]) |
||||
output_lang.change(fn=update_run_btn_text, inputs=[input_lang, output_lang], outputs=[run_source, run_target]) |
||||
|
||||
def clear_all(): |
||||
return "", "", "", "" |
||||
|
||||
clear_btn.click(fn=clear_all, inputs=[], outputs=[input_code, output_code, source_result, target_result]) |
||||
|
||||
def run_code(code, lang): |
||||
return f"// Running {lang} code...\n// Results would appear here" |
||||
|
||||
run_source.click(fn=run_code, inputs=[input_code, input_lang_state], outputs=[source_result]) |
||||
run_target.click(fn=run_code, inputs=[output_code, output_lang_state], outputs=[target_result]) |
||||
|
||||
def handle_file_upload(file): |
||||
if file is None: |
||||
return "" |
||||
with open(file.name, "r") as f: |
||||
return f.read() |
||||
|
||||
file_upload.change(fn=handle_file_upload, inputs=[file_upload], outputs=[input_code]) |
||||
|
||||
if __name__ == "__main__": |
||||
demo.launch() |
@ -0,0 +1,35 @@
|
||||
import gradio as gr |
||||
|
||||
# JavaScript function to toggle theme |
||||
js_code = """ |
||||
function toggleTheme(theme) { |
||||
var url = new URL(window.location.href); |
||||
if (theme === "dark") { |
||||
url.searchParams.set('__theme', 'dark'); |
||||
} else { |
||||
url.searchParams.delete('__theme'); |
||||
} |
||||
window.location.href = url.href; |
||||
} |
||||
""" |
||||
|
||||
def create_app(): |
||||
with gr.Blocks(js=js_code) as demo: |
||||
theme_radio = gr.Radio(["light", "dark"], label="Theme") |
||||
|
||||
# Button to trigger the theme change |
||||
theme_button = gr.Button("Toggle Theme") |
||||
|
||||
# Use JavaScript to toggle the theme when the button is clicked |
||||
theme_button.click( |
||||
None, |
||||
inputs=[theme_radio], |
||||
js=f"(theme) => {{ toggleTheme(theme); return []; }}", |
||||
queue=False, |
||||
) |
||||
|
||||
return demo |
||||
|
||||
if __name__ == "__main__": |
||||
app = create_app() |
||||
app.launch() |
Loading…
Reference in new issue