Initial commit

This commit is contained in:
2025-08-20 09:32:35 +02:00
commit 20c8336b9c
4 changed files with 530 additions and 0 deletions

133
.gitignore vendored Normal file
View File

@ -0,0 +1,133 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install different versions of packages depending on
# the platform. Pipfile.lock may vary on different platforms. Then you may wish to ignore
# Pipfile.lock.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyderworkspace
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# Custom
request_logs/

160
README.md Normal file
View File

@ -0,0 +1,160 @@
# 🧪 Mock OpenAI Chat API Server
This project simulates the OpenAI `/v1/chat/completions` API using a local FastAPI server.
It logs all incoming requests and returns a dummy response using `"Lorem Ipsum..."` content for debugging and development purposes.
---
## ✅ Features
- Local server that mimics OpenAI ChatCompletion endpoint
- Logs full request (headers + body) to `requests_log.json`
- Returns a dummy OpenAI-style response
- Plug-in replacement for `openai.ChatCompletion.create(...)`
---
## ⚙️ Requirements
- Python 3.7+
- FastAPI
- Uvicorn
---
## 📦 Installation & Setup
### 1. Clone or copy this project into a local folder
### 2. Create and activate a virtual environment
```bash
python -m venv venv
```
Then activate it:
- **Windows:**
```bash
venv\Scripts\activate
```
- **macOS/Linux:**
```bash
source venv/bin/activate
```
### 3. Install dependencies
```bash
pip install fastapi uvicorn
```
---
## 🚀 How to Start the Server
Use this command to launch the mock API server:
```bash
python -m uvicorn mock_openai_server:app --reload --port 8000
```
It will be available at:
```
http://localhost:8000/v1/chat/completions
```
---
## 🧪 How to Use with OpenAI Python SDK
Update your client to point to the mock server:
```python
import openai
openai.api_key = "sk-dummy"
openai.api_base = "http://localhost:8000"
response = openai.ChatCompletion.create(
model="gpt-4",
messages=[
{"role": "user", "content": "Hello!"}
]
)
print(response)
```
---
## 📄 Example Dummy Response
```text
ID: chatcmpl-mock123
Model: gpt-4
Created: <current timestamp>
Role: assistant
Message: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Finish reason: stop
Tokens used: prompt=10, completion=12, total=22
```
---
## 📝 Output Logs
All requests and responses are logged to `requests_log.json`.
Each log entry contains:
- Timestamp
- Headers (sent by client)
- JSON body (messages, model, etc.)
- Dummy response
You can use this log to debug what your app sends to OpenAI.
---
## 📂 Project Structure
```
.
├── mock_openai_server.py # FastAPI mock server
├── requests_log.json # Saved request/response logs
└── README.md # Documentation
```
---
## 🧰 Optional: Save Installed Packages
To track your environment:
```bash
pip freeze > requirements.txt
```
Later, you can restore it with:
```bash
pip install -r requirements.txt
```
---
## 📌 Notes
- No actual API calls are made to OpenAI
- Great for debugging payload formats, headers, and SDK integrations
- For local development only
---
## 🪪 License
MIT License

81
mock_openai_server.py Normal file
View File

@ -0,0 +1,81 @@
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from datetime import datetime
import json
import os
app = FastAPI()
LOG_DIR = "request_logs"
os.makedirs(LOG_DIR, exist_ok=True)
def format_markdown_log(headers, body, response):
timestamp = datetime.now().isoformat()
# Extract messages
messages = body.get("messages", [])
messages_text = "\n".join(
f"{m.get('role', 'unknown')}: {m.get('content', '')}" for m in messages
)
log = f"""## 📥 Request - {timestamp}
**Timestamp:** {timestamp}
### Headers
\```json
{json.dumps(headers, indent=4)}
\```
### Message Contents
\```text
{messages_text or "No messages"}
\```
### Full Body
\```json
{json.dumps(body, indent=4)}
\```
### 📤 Response
\```json
{json.dumps(response, indent=4)}
\```
---
"""
return log
@app.post("/v1/chat/completions")
async def chat_completions(request: Request):
headers = dict(request.headers)
body = await request.json()
dummy_response = {
"id": "chatcmpl-mock123",
"object": "chat.completion",
"created": int(datetime.now().timestamp()),
"model": body.get("model", "gpt-4"),
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "This is a mock response for testing purposes."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 10,
"completion_tokens": 12,
"total_tokens": 22
}
}
markdown_log = format_markdown_log(headers, body, dummy_response)
timestamp_str = datetime.now().strftime("%Y%m%d_%H%M%S_%f")
log_file = os.path.join(LOG_DIR, f"request_{timestamp_str}.md")
with open(log_file, "w", encoding="utf-8") as f:
f.write(markdown_log)
return JSONResponse(content=dummy_response)

156
requests_log.md Normal file
View File

@ -0,0 +1,156 @@
## 📥 Request - 2025-07-30T11:24:13.692836
**Timestamp:** 2025-07-30T11:24:13.692836
### Headers
\```json
{
"host": "localhost:8000",
"api-key": "dddd",
"content-type": "application/json; charset=utf-8",
"content-length": "1242"
}
\```
### Message Contents
\```markdown
- **system:** You will be provided with COBOL source code.
Response needs to be in .md format and contain description of the code.
You need to follow these rules:
1. Use vocabulary suited for design documentation.
2. Describe each statement inside the code in numbered list. Be as detailed as possible.
2.1. Describe each statement in separate numbered line, do not group statements. I really do mean each and every single one. Describe them all, not just some of them. You are allowed to repeat yourself if necessary. DO NOT IMPROVISE.
2.2. If there are nested statements increase numbering outline for each nested statement.
3. There should be no text after numerated part is finished.
- **user:** DISPLAY "Please input one upper-case letter. >>" WITH NO ADVANCIN
ACCEPT IN-DATA.
PERFORM TEST BEFORE
VARYING COUNTER FROM 1 BY 1 UNTIL COUNTER > 26
IF IN-DATA = ALP(COUNTER:1) THEN
EXIT PERFORM
END-IF
END-PERFORM.
IF COUNTER <= 26 THEN
DISPLAY IN-DATA " is character " COUNTER " in alphabetical order.
\```
### Full Body
\```json
{
"messages": [
{
"role": "system",
"content": "You will be provided with COBOL source code.\r\nResponse needs to be in .md format and contain description of the code.\r\nYou need to follow these rules:\r\n1. Use vocabulary suited for design documentation.\r\n2. Describe each statement inside the code in numbered list. Be as detailed as possible.\r\n2.1. Describe each statement in separate numbered line, do not group statements. I really do mean each and every single one. Describe them all, not just some of them. You are allowed to repeat yourself if necessary. DO NOT IMPROVISE.\r\n2.2. If there are nested statements increase numbering outline for each nested statement.\r\n3. There should be no text after numerated part is finished.\r\n"
},
{
"role": "user",
"content": "DISPLAY \"Please input one upper-case letter. >>\" WITH NO ADVANCIN\n ACCEPT IN-DATA.\n PERFORM TEST BEFORE\n VARYING COUNTER FROM 1 BY 1 UNTIL COUNTER > 26\n IF IN-DATA = ALP(COUNTER:1) THEN\n EXIT PERFORM\n END-IF\n END-PERFORM.\n IF COUNTER <= 26 THEN\n DISPLAY IN-DATA \" is character \" COUNTER \" in alphabetical order.\n"
}
],
"temperature": 0.01,
"top_p": 0.01,
"max_tokens": 900
}
\```
### 📤 Response
\```json
{
"id": "chatcmpl-mock123",
"object": "chat.completion",
"created": 1753867453,
"model": "gpt-4",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 10,
"completion_tokens": 12,
"total_tokens": 22
}
}
\```
---
## 📥 Request - 2025-07-30T11:24:13.716838
**Timestamp:** 2025-07-30T11:24:13.716838
### Headers
\```json
{
"host": "localhost:8000",
"api-key": "dddd",
"content-type": "application/json; charset=utf-8",
"content-length": "596"
}
\```
### Message Contents
\```markdown
- **system:** You will be provided with COBOL source code description. This description represents one COBOL procedure division.
Please provide short summary describing the function of this procedure division. Start description with words "This procedure division".
Don't describe each paragraph separately, but whole division at once. Be as short as possible.
- **user:**
## PROCEDURE DIVISION BODY
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
\```
### Full Body
\```json
{
"messages": [
{
"role": "system",
"content": "You will be provided with COBOL source code description. This description represents one COBOL procedure division.\r\nPlease provide short summary describing the function of this procedure division. Start description with words \"This procedure division\".\r\nDon't describe each paragraph separately, but whole division at once. Be as short as possible.\r\n"
},
{
"role": "user",
"content": "\r\n## PROCEDURE DIVISION BODY\r\nLorem ipsum dolor sit amet, consectetur adipiscing elit.\r\n\r\n\r\n"
}
],
"temperature": 0.01,
"top_p": 0.01,
"max_tokens": 900
}
\```
### 📤 Response
\```json
{
"id": "chatcmpl-mock123",
"object": "chat.completion",
"created": 1753867453,
"model": "gpt-4",
"choices": [
{
"index": 0,