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