name: Publish to crates.io
on:
push:
tags: # Triggers when pushing tags starting with 'v'
jobs:
publish:
runs-on: ubuntu-latest
environment: release # Optional: for enhanced security
permissions:
id-token: write # Required for OIDC token exchange
steps:
- uses: actions/checkout@v4
- uses: rust-lang/crates-io-auth-action@v1
id: auth
- run: cargo publish
env:
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
> [!NOTE]
, > [!WARNING]
, and > [!CAUTION]
in their README markdown, which will now be properly styled and displayed on crates.io.format!()
macro and string concatenation to create emails, which made them hard to maintain and inconsistent in styling. We have migrated to the minijinja crate and now use templates instead.
|
我是一个高级工程师,已经在公司工作五年了。公司越来越推崇快速工程,CEO 和 CTO 都对 AI 编程痴迷不已。
公司强制大家使用 AI 编程,甚至提倡让 AI 生成单元测试,对于失败的测试用例,也是扔给 AI 处理,而不是手动解决,以加快开发速度、产品尽早上线。
我考虑辞职,不想参与这种流程,成为不写代码、只写提示的"提示工程师",眼睁睁看着自己的技术停滞或退化。我也不想两三年后,负责维护一堆由 AI 生成的意大利面条代码。
我想听听大家的意见,怎么应对公司推行 AI 编程。
google.com/generate_204
),根据它们的回复,判断当前是否在线。1 + 1
,它自动输出答案2
。touch README.md
,就会自动生成自述文件。…
) next to the desired guardrail and select Attach Agent.curl -X POST -H 'Authorization: Bearer $DIGITALOCEAN_TOKEN' https://api.digitalocean.com/v2/gen-ai/models/api_keys
This will output our model access key. Save this value for later. We will need it to query the model.from openai import OpenAI
import os
client = OpenAI(
api_key= **“your_model_access_key_here”**,
base_url="https://inference.do-ai.run/v1"
)
stream = client.chat.completions.create(
model="llama3-8b-instruct",
messages=[
{
"role": "developer",
"content": "You are a helpful assistant.",
},
{
"role": "user",
"content": "What is the capital of France?",
},
],
stream=True,
max_completion_tokens=10
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
This should produce the output “The capital of France is Paris”. We recommend changing the values like max_completion_tokens
to better suit your prompt as needed. We can also edit the model value on line 10 to be any of the available models listed in the DigitalOcean GradientAI Model offerings. This model zoo is constantly being updated to reflect the growing industry, so check back frequently for updates.cd my-new-project/
gemini
> Help me understand the PDF in this directory. And also provide a summary of the documents.
Or maybe you’ve just cloned a large repo and you want to understand the large codebases instantly.cd some-huge-repo/
gemini
> Describe the main architecture of this system.
Gemini will read your codebase and give you a clear, human-readable overview. You won’t have to scroll through files trying to make sense of it all.
Furthermore, Gemini can interact with your system to automate repetitive tasks.gemini
> Convert all images in this folder to PNG and name them using the EXIF date.
It’s like having a junior developer on your team 24/7.npx https://github.com/google-gemini/gemini-cli
Or install globally:npm install -g @google/gemini-cli
gemini
Authenticate with your Google account or Gemini API key.
You’re now ready to query Gemini right from your shell.std::transform
from the Standard Library. Then, we’ll cover the foundational technique of using a traditional for
-loop to change character case manually. Finally, we’ll dive into key best practices and performance considerations to help you choose the right method and avoid common pitfalls in your projects.std::transform
or a range-based for-loop for efficient and readable in-place case conversion in C++.unsigned char
before passing them to standard library functions like std::toupper
and std::tolower
.toupper
and tolower
functions are not Unicode-aware and can fail on international characters, as they only support one-to-one character mapping.char - 32
) in production code; it is unsafe, not portable, and only works for basic English characters.std::string
vs C-style stringsstd::string
class and traditional C-style strings.std::string
. It’s safer, easier to use, and more powerful. C-style strings are character arrays inherited from the C language (char*
or char[]
) that end with a null-terminator (\0
). They are fast but notoriously difficult and unsafe to manage manually.std::string
is the superior choice:Feature | std::string |
C-style String (char* ) |
---|---|---|
Memory Management | Automatic. The string grows and shrinks as needed. No manual memory handling is required, preventing memory leaks. | Manual. You must allocate and deallocate memory yourself using new[] /delete[] or malloc /free . Very prone to errors. |
Getting Length | Simple and direct: my_str.length() or my_str.size() . |
Requires scanning the entire string to find the \0 character: strlen(my_str) . |
Concatenation | Intuitive and easy using the + or += operators. Example: str1 + str2 . |
Manual and complex. Requires allocating a new, larger buffer and using functions like strcpy and strcat . |
Comparison | Straightforward using standard comparison operators (== , != , < , > ). |
Requires using the strcmp() function. Using == just compares pointer addresses, not the content. |
Safety | High. Provides bounds-checked access with .at() , which throws an exception if you go out of bounds. This helps prevent crashes. |
Low. No built-in protection against writing past the end of the array, leading to buffer overflows, a major security risk. |
STL Integration | Seamless. Designed to work perfectly with standard algorithms (std::transform , std::sort ) and containers. |
Limited. Can be used with some algorithms but often requires more careful handling and wrapping. |
std::string
is the clear winner. It eliminates entire classes of common bugs while providing a much more pleasant and productive developer experience.std::string
, the modern, safe, and efficient standard for handling text in C++.std::transform
std::transform
algorithm from the <algorithm>
header. This function is designed to apply an operation to a sequence of elements, making it a perfect fit for our task. It’s favored in professional code because it’s expressive and can be highly optimized by the compiler.#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
int main() {
std::string input_text = "Hello World!";
std::transform(input_text.begin(), input_text.end(), input_text.begin(), ::toupper);
std::cout << "Result: " << input_text << std::endl;
return 0;
}
The first two arguments, input_text.begin()
and input_text.end()
, define the input range for the operation, which covers the entire string. The third argument, also input_text.begin()
, sets the destination for the results. Since the destination is the same as the source, the function performs an efficient in-place modification. Finally, ::toupper
is applied to each character within the defined range.#include <iostream>
#include <string>
#include <cctype>
int main() {
std::string input_text = "This is a DigitalOcean tutorial!";
for (char &c : input_text) {
c = std::toupper(static_cast<unsigned char>(c));
}
std::cout << "Result: " << input_text << std::endl;
return 0;
}
The for (char &c : input_text)
loop iterates through each character of the string. The ampersand in &c
is critical as it creates a reference to the character. This means you’re modifying the original string directly, not just a temporary copy.c = std::toupper(...)
assigns the uppercase version back to the character. The static_cast<unsigned char>
is an important safety measure that prevents potential errors by ensuring the input to std::toupper
is always non-negative.#include <iostream>
#include <string>
int main() {
std::string my_text = "Manual conversion";
for (char &c : my_text) {
if (c >= 'a' && c <= 'z') {
c = c - 32;
}
}
std::cout << "Result: " << my_text << std::endl;
return 0;
}
This code manually converts characters to uppercase by directly manipulating their ASCII values.if
statement checks if a character is a lowercase English letter (between ‘a’ and ‘z’). If it is, the code subtracts 32 from its numeric ASCII value, which is the exact difference required to convert it to its uppercase equivalent (for example, ‘a’ is 97 and ‘A’ is 65).std::transform
std::transform
algorithm. To convert to lowercase, you simply swap ::toupper
with ::tolower
. It remains the most expressive and efficient method for the job.#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
int main() {
std::string my_text = "THIS IS A LOUD SENTENCE.";
std::transform(my_text.begin(), my_text.end(), my_text.begin(), ::tolower);
std::cout << "Result: " << my_text << std::endl;
return 0;
}
This works just like the uppercase example. std::transform
iterates through the entire string and applies the ::tolower
operation to each character, modifying the string in-place for great efficiency.#include <iostream>
#include <string>
#include <cctype>
int main() {
std::string my_text = "ANOTHER EXAMPLE.";
for (size_t i = 0; i < my_text.length(); ++i) {
my_text[i] = std::tolower(static_cast<unsigned char>(my_text[i]));
}
std::cout << "Result: " << my_text << std::endl;
return 0;
}
The loop uses an index i
to access each character via my_text[i]
. It then calls std::tolower
to get the lowercase equivalent and assigns it back to the same position. The static_cast<unsigned char>
is a crucial safety habit to prevent errors with certain character values.#include <iostream>
#include <string>
int main() {
std::string my_text = "MANUAL CONVERSION";
for (char &c : my_text) {
if (c >= 'A' && c <= 'Z') {
c = c + 32;
}
}
std::cout << "Result: " << my_text << std::endl;
return 0;
}
This code checks if a character is an uppercase letter (‘A’ through ‘Z’). If it is, it adds 32 to its numeric ASCII value to get the corresponding lowercase letter. This method is not safe or portable and will fail on any text that isn’t basic English.std::wstring
and std::locale
std::wstring
) and the <locale>
library. The wchar_t
character type in a wide string can represent characters beyond a single byte. The process requires setting a global locale and using wide streams for I/O.#include <iostream>
#include <string>
#include <algorithm>
#include <locale>
int main() {
std::locale::global(std::locale(""));
std::wcout.imbue(std::locale());
std::wstring text = L"Eine Straße in Gießen.";
const auto& facet = std::use_facet<std::ctype<wchar_t>>(std::locale());
std::transform(text.begin(), text.end(), text.begin(), [&](wchar_t c){
return facet.toupper(c);
});
std::wcout << L"std::locale uppercase: " << text << std::endl;
return 0;
}
While the code above is the correct way to use the standard library, it has a significant flaw. It produces the incorrect output:std::locale uppercase: EINE STRAßE IN GIEßEN.
The reason is that the standard std::ctype::toupper
function is designed for one-to-one mapping only. It takes one character and must return one character. It cannot handle the ß
→ SS
conversion, which requires mapping one character to two.#include <unicode/unistr.h>
#include <unicode/locid.h>
#include <iostream>
int main() {
std::string input = "Eine Straße in Gießen.";
icu::UnicodeString ustr = icu::UnicodeString::fromUTF8(input);
ustr.toUpper(icu::Locale("de"));
std::string output;
ustr.toUTF8String(output);
std::cout << "Unicode-aware uppercase: " << output << std::endl;
return 0;
}
In this code:icu::UnicodeString::fromUTF8(input)
converts the standard std::string
into ICU’s core string class, UnicodeString
. This is the necessary first step, as ICU’s functions operate on this specialized type..toUpper(icu::Locale("de"))
is the key function. It applies the case conversion rules defined by the German (de
) icu::Locale
object. This method correctly handles the one-to-many mapping of ß to SS..toUTF8String(output)
converts the result from ICU’s internal format back into a standard std::string
so it can be easily used with std::cout
and other C++ components.Unicode-aware uppercase: EINE STRASSE IN GIESSEN.
std::transform
vs. For-Loop: For typical string lengths, the performance of these two methods is virtually identical. Modern compilers are exceptionally good at optimizing simple loops and standard algorithms, often generating the same machine code for both. For very large strings, std::transform
can sometimes have a slight edge, as it more clearly expresses the intent to the compiler, which may apply advanced optimizations like vectorization.if
statement can lead to CPU branch mispredictions if the text is a mix of cases, and the method is fundamentally unsafe and non-portable.UnicodeString
and Locale
objects. However, for its intended purpose, i.e., processing complex, international Unicode text, its performance is excellent and far surpasses the incorrect attempts of the standard library.std::transform
on the source string or iterating with a for-loop and a reference (&c
) modifies the string’s existing memory without allocating a new buffer. This should be your default method.icu::UnicodeString
object has its own memory management and will have a different memory footprint than std::string
. This is a necessary trade-off for the powerful features and correctness it provides.unsigned char
with Standard Functions: To prevent undefined behavior, always cast your char to unsigned char
before passing it to std::toupper
or std::tolower
.c = std::toupper(static_cast<unsigned char>(c));
<algorithm>
header.#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
int main() {
std::string input_text = "Hello World!";
std::transform(input_text.begin(), input_text.end(), input_text.begin(), ::toupper);
std::cout << "Result: " << input_text << std::endl;
return 0;
}
This applies the ::toupper
function to every character in the string, modifying it in-place.toupper()
safe for all locales?::toupper
and std::toupper
functions are not safe for all locales. They are generally only reliable for basic ASCII characters. They can fail on characters from other languages, most famously being unable to convert the German ‘ß’ to “SS”. For true locale-aware conversions, you must use a dedicated library like ICU (International Components for Unicode).std::string
. You cannot use std::transform
directly because C-style strings (like char*
) don’t have iterators. You must use a manual for-loop with strlen()
.std::string
and then apply the methods discussed in this article.#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
int main() {
const char* c_style_string = "hello from a c-style string!";
std::string my_string = c_style_string;
std::transform(my_string.begin(), my_string.end(), my_string.begin(), ::toupper);
std::cout << "Result: " << my_string << std::endl;
return 0;
}
#include <string>
#include <cctype>
bool has_both_cases(const std::string& s) {
bool has_lower = false;
bool has_upper = false;
for (char c : s) {
if (std::islower(c)) has_lower = true;
if (std::isupper(c)) has_upper = true;
if (has_lower && has_upper) return true;
}
return has_lower && has_upper;
}
std::transform
, but with ::tolower
.#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
int main() {
std::string input_text = "HELLO WORLD!";
std::transform(input_text.begin(), input_text.end(), input_text.begin(), ::tolower);
std::cout << "Result: " << input_text << std::endl;
return 0;
}
toupper
function is designed to take one character and return exactly one character. It is fundamentally incapable of handling conversions like the German ß
to the two-character string SS
.std::string
, std::toupper
operates byte-by-byte. It sees a multi-byte character like é
as two separate, meaningless bytes and cannot convert it correctly.std::transform
and for-loops are the recommended, efficient methods, but always cast characters to unsigned char
to ensure safety. We demonstrated that for complex Unicode, the standard library’s std::locale
is insufficient because it cannot handle critical one-to-many character mappings (like ‘ß’ to ‘SS’).Domain (Count) | Description | Prompt Source | Method of Generating Completions | Scoring |
---|---|---|---|---|
Factuality (475) | Test RM’s ability to detect hallucinations | Human (in-the-wild chat interactions) | Both natural and System Prompt Variation | Majority voting, LLM-as-a-judge (two LLMs must agree to assign a label) |
Precise Instruction Following (160) | Tests RM’s ability to follow instructions like “Answer without the letter u” | Human (in-the-wild chat interactions) | Natural | Verifier functions to evaluate adherence to constraint |
Math (183) | Tests RM’s math ability | Human (in-the-wild chat interactions) | Natural | Majority voting, LM-as-a-judge & manual verification |
Safety (450) | Tests RM’s ability to correctly determine which responses should be complied with or refused | CoCoNot | Both natural and System Prompt Variation | Subset-specific rubrics for judging compliance with GPT-4o, manual verification for half of examples |
Focus (495) | Tests RM’s ability to detect on-topic answers of high-quality | Human (in-the-wild chat interactions) | System Prompt Variation | N/A (implied by method of generation, which differentiates chosen and rejected completions) |
Ties (102) | Tests model’s ability to avoid expressing overly strong or arbitrary preferences among equivalent correct answers, while still clearly preferring any correct answer over any incorrect one. | Manual (Researchers) | System Prompt Variation | Weighted score of accuracy (all valid correct answers scored higher than all incorrect answers) and whether reward margin between correct and incorrect answers exceeds that of highest and lowest-scored correct responses |
float()
function. We’ll start with the fundamentals, covering how to handle various formats like integers and scientific notation, before moving on to the most essential skill: writing resilient code. You’ll learn how to use a try-except
block to gracefully handle a ValueError from non-numeric input. From there, we’ll tackle practical, real-world challenges like cleaning strings with currency symbols and converting international numbers that use commas as decimals.float()
function handles most string-to-float conversions, including integers, decimals, negative numbers, scientific notation, and strings with leading/trailing whitespace.float()
conversions in try-except
blocks to catch ValueError exceptions from invalid strings like "hello"
or empty strings, preventing program crashes."1.234,56"
to standard format.float(None)
raises a TypeError
, not ValueError
; so explicitly check for None
values before attempting conversion to avoid different exception types..strip()
and .replace()
before calling float()
.safe_to_float()
that handle common edge cases (None
, empty strings, invalid input) and return sensible defaults to make your code more maintainable and robust.float()
for Basic Conversions in Pythonfloat()
. This function is the primary and most Pythonic way to convert a string into a floating-point number.float(your_string)
Let’s see an example. The float()
function can handle strings that represent positive numbers, negative numbers, and even whole numbers.price_string = "24.99"
print("Type before conversion:", type(price_string))
price_float = float(price_string)
print("Type after conversion:", type(price_float))
Output:Type before conversion: <class 'str'>
Type after conversion: <class 'float'>
As you can see, the string "24.99"
was successfully converted to the float 24.99
, and its type is now float
.float()
processes it correctly.# String representing an integer
int_string = "350"
print(f"'{int_string}' becomes: {float(int_string)}")
# String representing a negative decimal
neg_string = "-45.93"
print(f"'{neg_string}' becomes: {float(neg_string)}")
Output:'350' becomes: 350.0
'-45.93' becomes: -45.93
float()
automatically handles leading and trailing whitespace.reading_string = " -99.5 "
reading_float = float(reading_string)
print(reading_float)
Output:-99.5
The float()
function ignored the extra spaces and correctly converted the string to a negative float. In the next section, we’ll cover what happens when you try to convert a string that isn’t a valid number.float()
function understands this format without any extra work."1.5e10"
represents 1.5 times 10 to the power of 10.scientific_string = "1.5e10"
scientific_float = float(scientific_string)
print(f"'{scientific_string}' becomes: {scientific_float}")
print(type(scientific_float))
Output:'1.5e10' becomes: 15000000000.0
<class 'float'>
The float()
function effortlessly handles these common formats, making your conversion tasks much simpler.ValueError
and Safe Conversions"hello"
or an empty string ""
? If you’re not careful, your program will crash. In this section, we’ll cover how to handle these situations gracefully.ValueError
Exceptionfloat()
function, Python raises a ValueError
.invalid_string = "not a number"
price_float = float(invalid_string)
print(price_float)
Running this code stops execution and throws a ValueError
with a message telling you it could not convert the string to a float.try-except
Blocks for Safe Conversiontry-except
block. This is the standard Pythonic way to handle exceptions in Python.try
block contains the code that might fail (the “risky” operation).except
block contains the code that runs only if an error occurs in the try
block.ValueError
and handle it gracefully instead of letting your program terminate.input_string = "not a number"
value_float = 0.0
try:
value_float = float(input_string)
print("Conversion successful!")
except ValueError:
print(f"Could not convert '{input_string}'.")
print(f"The final float value is: {value_float}")
Output:Could not convert 'not a number'.
The final float value is: 0.0
As you can see, the program didn’t crash. By anticipating the error, we provided a fallback plan and maintained control.None
Values""
) and None
values.float("")
will also raise a ValueError
. The try-except
block we just created handles this perfectly.None
Values: Trying to convert None
is a different kind of error. float(None)
will raise a TypeError
, not a ValueError
. If your code encounters None
, you should check for it explicitly before trying the conversion.None
:def safe_to_float(value):
if value is None:
return 0.0
try:
return float(value)
except (ValueError, TypeError):
return 0.0
# Test cases
print(f"'123.45' becomes: {safe_to_float('123.45')}")
print(f"'hello' becomes: {safe_to_float('hello')}")
print(f"An empty string '' becomes: {safe_to_float('')}")
print(f"None becomes: {safe_to_float(None)}")
Output:'123.45' becomes: 123.45
'hello' becomes: 0.0
An empty string '' becomes: 0.0
None becomes: 0.0
1,234.56
. However, in much of Europe and other regions, the roles are swapped, and the same number is written as 1.234,56
.float()
function, by default, only recognizes a period (.
) as a decimal separator. Trying to convert "1.234,56"
will result in a ValueError
. Here are two ways to handle this.de_string = "1.234,56"
temp_string = de_string.replace(".", "")
standard_string = temp_string.replace(",", ".")
value_float = float(standard_string)
print(f"Original string: '{de_string}'")
print(f"Standardized string: '{standard_string}'")
print(f"Converted float: {value_float}")
In this example, we’ll use a European-formatted number string. First, we remove the '.'
thousands separator. Then, we replace the ','
decimal separator with a '.'
. Finally, we convert the standardized string.Original string: '1.234,56'
Standardized string: '1234.56'
Converted float: 1234.56
This method is simple, effective, and doesn’t require any special libraries.locale
Modulelocale
module is the right tool. This module can interpret numbers according to a specific region’s conventions.locale.atof()
function (ASCII to float) for the conversion.import locale
de_string = "1.234,56"
try:
locale.setlocale(locale.LC_NUMERIC, 'de_DE.UTF-8')
value_float = locale.atof(de_string)
print(f"Successfully converted '{de_string}' to {value_float}")
except locale.Error:
print("Locale 'de_DE.UTF-8' not supported on this system.")
finally:
locale.setlocale(locale.LC_NUMERIC, '')
We start by setting the locale to German (de_DE)
with UTF-8 encoding.'de_DE.UTF-8'
locale must be supported by your OS.locale.atof()
to convert the string in a locale-aware way.Successfully converted '1.234,56' to 1234.56
The locale
module is the more robust and “correct” solution for building internationalized applications. For quick, one-off scripts, the string replacement method is often sufficient.try-except
Block: This is the most critical rule. Data from users, files, or APIs is unpredictable. A try-except ValueError
block will prevent your program from crashing due to a single invalid string and allow you to handle the error gracefully.float()
. First, use string methods like .strip()
to remove leading/trailing whitespace and .replace()
to eliminate unwanted characters. For more advanced cleaning, you can review our article on common string manipulation techniques.except
block, decide on a fallback plan. Is it better to skip the entry, or should you assign a default value like 0.0
or None
? This ensures your program can continue running with predictable data.safe_to_float()
example earlier). This makes your code cleaner, easier to read, and simpler to update.locale
module for more complex, locale-aware applications.float()
for Simplicity: For all standard conversions, the built-in float()
function is the most direct, readable, and Pythonic tool for the job. Avoid overly complex solutions when a simple one works perfectly.float()
function. You pass the numeric string as an argument, and it returns the corresponding float.float("123.45")
will return 123.45
.ValueError
exception when you attempt to convert a non-numeric string using float()
. For example, float("hello")
will throw a ValueError: could not convert string to float: hello
. Always use try-except
blocks to handle this gracefully.float()
function doesn’t recognize comma separators by default. You need to remove commas first: float("1,234.56".replace(",", ""))
or use locale-specific functions like locale.atof()
after setting the appropriate locale.:.2f
format specifier. This is best for printing or showing the value in a UI.price_string = "49.99123"
formatted_price = f"{float(price_string):.2f}"
print(formatted_price)
# Output: "49.99"
round()
function. This is best if you need to use the rounded number in further math operations.price_string = "49.99123"
rounded_price = round(float(price_string), 2)
print(rounded_price)
# Output: 49.99
float()
and int()
when converting strings?float()
converts strings to floating-point numbers (decimals), while int()
converts to integers. float("3.14")
returns 3.14
, but int("3.14")
raises a ValueError
. Use int(float("3.14"))
to convert decimal strings to integers. This will return 3
.float()
function natively supports scientific notation. float("1.5e10")
correctly returns 15000000000.0
. This works for both positive and negative exponents like "1.5e-3"
.float()
function to handle simple numeric strings, integers, and scientific notation. We then moved to the most critical aspect of robust programming: safely handling errors. You now know how to use a try-except
block to catch a ValueError
, ensuring your applications don’t crash when they encounter unexpected, non-numeric text.Library | Best For | Features | Framework Support |
---|---|---|---|
Chart.js | Rapid development of simple to moderate complexity dashboards | Standard interactions like tooltips and zoom | React, Vue, Angular (official wrappers) |
D3.js | Highly customized, data driven visualizations with complex logic | Full control over DOM and event handling | All frameworks (manual integration) |
ECharts | Enterprise grade dashboards requiring rich features and performance | Advanced interactions including data zoom, brush, and toolbox | React, Vue (official) |
ApexCharts | Real time data visualization with modern styling and smooth animations | Built-in zoom, pan, and responsive legends | React, Vue, Angular (official) |
Plotly.js | Scientific and 3D visualizations with interactive controls | Interactive 3D plots, hover info, and zoom | React (official) |
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
tag in the <head>
. Running it without this will result in a ReferenceError: Chart is not defined
.const ctx = document.getElementById('myChart').getContext('2d');
const myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: 'rgba(54, 162, 235, 0.6)'
}]
},
options: {
responsive: true,
plugins: {
legend: { display: true },
tooltip: { enabled: true }
}
}
});
<script src="https://d3js.org/d3.v7.min.js"></script>
tag in your HTML <head>
. This code should be placed inside a <script>
tag within an HTML document that also contains an element like <svg id="mySvg"></svg>
in the body. Running it without these will lead to ReferenceError: d3 is not defined
or selection errors.const data = [12, 19, 3, 5, 2, 3];
const svg = d3.select('#mySvg').attr('width', 400).attr('height', 200);
svg.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('x', (d, i) => i * 40)
.attr('y', d => 200 - d * 10)
.attr('width', 35)
.attr('height', d => d * 10)
.attr('fill', 'steelblue');
<script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
tag inside your HTML <head>
. The chart code should be placed in a <script>
block, and your HTML body must contain a container element like <div id="main" style="width: 600px;height:400px;"></div>
. Without these, you may encounter echarts is not defined
or rendering issues.const chart = echarts.init(document.getElementById('main'));
const option = {
xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'] },
yAxis: { type: 'value' },
series: [{
data: [120, 200, 150, 80, 70],
type: 'bar'
}],
tooltip: { trigger: 'axis' },
toolbox: { feature: { saveAsImage: {} } }
};
chart.setOption(option);
Note: To run this ApexCharts example in your browser, ensure you include the ApexCharts library using a <script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
tag inside the HTML <head>
. The chart code should go inside a <script>
tag in the body, and your HTML must contain a container element such as <div id="chart"></div>
. Without these, you may encounter ApexCharts is not defined
or empty chart containers.
var options = {
chart: { type: 'line', height: 350 },
series: [{ name: 'Sales', data: [30, 40, 35, 50, 49, 60] }],
xaxis: { categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'] },
tooltip: { enabled: true },
responsive: [{ breakpoint: 480, options: { chart: { height: 300 } } }]
};
var chart = new ApexCharts(document.querySelector("#chart"), options);
chart.render();
Note: To run this Plotly.js example in your browser, include the Plotly library using a <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
tag in the HTML <head>
. Place your chart code inside a <script>
block in the body, and ensure you have a container element such as <div id="plot"></div>
. Without this setup, you may encounter Plotly is not defined
or rendering issues.
var data = [{
x: [1, 2, 3, 4],
y: [10, 15, 13, 17],
type: 'scatter'
}];
Plotly.newPlot('plot', data);
client.chat.completions.create()
base_url
when you initialize the clienthttps://inference.do-ai.run/v1/
https://.agents.do-ai.run/api/v1/
pip install openai python-dotenv
base_url
).from openai import OpenAI
from dotenv import load_dotenv
import os
load_dotenv()
client = OpenAI(
base_url="https://inference.do-ai.run/v1/", # DO's Inference endpoint
api_key=os.getenv("DIGITAL_OCEAN_MODEL_ACCESS_KEY")
)
# List all available models
try:
models = client.models.list()
print("Available models:")
for model in models.data:
print(f"- {model.id}")
except Exception as e:
print(f"Error listing models: {e}")
.chat.completions.create()
method. Only the base_url
is different.from openai import OpenAI
from dotenv import load_dotenv
import os
load_dotenv()
client = OpenAI(
base_url="https://inference.do-ai.run/v1/", # DO's Inference endpoint
api_key=os.getenv("DIGITAL_OCEAN_MODEL_ACCESS_KEY")
)
# Run a simple chat completion
try:
response = client.chat.completions.create(
model="llama3-8b-instruct", # Swap in any supported model
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Tell me a fun fact about octopuses."}
]
)
print(response.choices[0].message.content)
except Exception as e:
print(f"Error during completion: {e}")
stream=True
, and loop through the chunks.from openai import OpenAI
from dotenv import load_dotenv
import os
load_dotenv()
client = OpenAI(
base_url="https://inference.do-ai.run/v1/", # DO's Inference endpoint
api_key=os.getenv("DIGITAL_OCEAN_MODEL_ACCESS_KEY")
)
# Run a simple chat completion with streaming
try:
stream = client.chat.completions.create(
model="llama3-8b-instruct", # Swap in any supported model
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Tell me a fun fact about octopuses."}
],
stream=True
)
for event in stream:
if event.choices[0].delta.content is not None:
print(event.choices[0].delta.content, end='', flush=True)
print() # Add a newline at the end
except Exception as e:
print(f"Error during completion: {e}")
.chat.completions.create()
— the only difference is the base_url
. But now your responses are grounded in your own data.python
client = OpenAI(
base_url="https://your-agent-id.agents.do-ai.run/api/v1/",
api_key=os.getenv("DIGITAL_OCEAN_MODEL_ACCESS_KEY")
)
.chat.completions.create()
- same method as before.base_url
, which points to your Agent’s unique endpoint (plus /api/v1
). With Inference, the base URL is fixed. With Agents, it’s unique to your agent, and you just append /api/v1
to it.include_retrieval_info=True
to the body. This tells the API to return extra metadata about what the Agent pulled from your knowledge base to generate its response.from openai import OpenAI
from dotenv import load_dotenv
import os
import json
load_dotenv()
try:
# Create a new client with the agents endpoint
agents_client = OpenAI(
base_url="https://rrp247s4dgv4xoexd2sk62yq.agents.do-ai.run/api/v1/",
api_key=os.getenv("AJOT_AGENT_KEY")
)
# Try a simple text request with the agents endpoint
stream = agents_client.chat.completions.create(
model="openai-gpt-4o-mini",
messages=[{
"role": "user",
"content": "Hello! WHo is Amit?"
}],
extra_body = {"include_retrieval_info": True}
)
print(f"\nAgents endpoint response: {agents_response.choices[0].message.content}")
for choice in response.choices:
print(choice.message.content)
response_dict = response.to_dict()
print("\nFull retrieval object:")
print(json.dumps(response_dict["retrieval"], indent=2))
except Exception as e:
print(f"Error with agents endpoint: {e}")
stream=True
to get the response back as it generates. Everything else is the same.from openai import OpenAI
from dotenv import load_dotenv
import os
import json
load_dotenv()
try:
# Create a new client with the agents endpoint
agents_client = OpenAI(
base_url="https://rrp247s4dgv4xoexd2sk62yq.agents.do-ai.run/api/v1/",
api_key=os.getenv("AJOT_AGENT_KEY")
)
# Try a simple text request with the agents endpoint
stream = agents_client.chat.completions.create(
model="openai-gpt-4o-mini",
messages=[{
"role": "user",
"content": "Hello! WHo is Amit?"
}],
extra_body = {"include_retrieval_info": True},
stream=True,
)
for event in stream:
if event.choices[0].delta.content is not None:
print(event.choices[0].delta.content, end='', flush=True)
print() # Add a newline at the end
except Exception as e:
print(f"Error with agents endpoint: {e}")
https://inference.do-ai.run/v1/
for general-purpose models like LLaMA 3, GPT-4o, Claude, etc.\/api/v1
) to connect to your own docs or knowledge base..chat.completions.create()
—no new methods to learn.stream=True
, and get retrieval info with include_retrieval_info=True
.heapq
module provides a fast and memory-efficient implementation of a min-heap priority queuequeue.PriorityQueue
class offers a synchronized wrapper around heapq
__lt__
comparison methodheapq
modulequeue.PriorityQueue
classPriorityQueue
is a thread-safe implementation of a priority queue, ensuring safe access and modification in multi-threaded environments.put
method is used to add tasks to the priority queue, where the first argument is the priority and the second argument is the task itself.get
method retrieves the task with the highest priority from the queue.task_done
method is used to indicate that a task has been completed.join
method blocks until all tasks in the queue have been processed and completed.heapq
and queue.PriorityQueue
.heapq
?heapq
module provides a min-heap implementation that can be used to implement a priority queue.heapq
module in Python. A priority queue is a data structure that stores elements with associated priorities, allowing for efficient retrieval of the element with the highest or lowest priority.heapq.heappush
function is used to add tasks to the queue, and the heapq.heappop
function is used to remove and return the task with the smallest priority.import heapq
pq = []
# push
heapq.heappush(pq, (2, "code"))
heapq.heappush(pq, (1, "eat"))
heapq.heappush(pq, (3, "sleep"))
# pop – always smallest priority
priority, task = heapq.heappop(pq)
print(priority, task) # 1 eat
Output1 eat
2 code
3 sleep
The output of the code shows that the task with the smallest priority (“eat” with priority 1) is retrieved first, followed by the tasks with higher priorities (“code” with priority 2 and “sleep” with priority 3).heapq
maintains the smallest tuple at index 0, ensuring efficient retrieval of the highest priority element. Each push and pop operation incurs a time complexity of O(log n), where n
is the number of elements in the heap. The space complexity is O(n), as the heap stores all elements.heapq
Benefit | Description |
---|---|
Efficiency | heapq maintains the smallest tuple at index 0, ensuring efficient retrieval of the highest priority element. |
Simplicity | heapq is a built-in module that requires no additional setup. |
Performance | heapq is optimized for speed and memory usage. |
heapq
Limitation | Description |
---|---|
No Maximum Priority | heapq by default only supports min-heap, so you cannot use it to implement a max-heap. |
No Priority Update | heapq does not support updating the priority of an existing element. |
heapq
implements a min-heap 1
/ \
3 2
/ \ /
6 4 5
You can read more about it in this tutorial on min-heap-binary-tree. 6
/ \
4 5
/ \ /
1 3 2
heapq
?heapq
only supports min-heap, but you can implement a max-heap by either:__lt__
comparison methodheapq
with both approaches.heapq
by negating the values before adding them to the heap and then negating them again when extracting the maximum value. This works because negating numbers reverses their natural order (e.g., if a > b
, then -a < -b
), allowing the min-heap to effectively store and retrieve values in a max-heap manner.import heapq
# Initialize an empty list to act as the heap
max_heap = []
# Push elements into the simulated max-heap by negating them
heapq.heappush(max_heap, -5)
heapq.heappush(max_heap, -1)
heapq.heappush(max_heap, -8)
# Pop the largest element (which was stored as the smallest negative value)
largest_element = -heapq.heappop(max_heap)
print(f"Largest element: {largest_element}")
OutputLargest element: 8
The output shows that the largest element (8) is retrieved first, followed by the elements with lower values (-5 and -1).O(n)
, where n is the number of elements in the heap. This is because we store all elements in the heap.O(log n)
for each insertion and extraction operation. This is because heapq.heappush
and heapq.heappop
operations take O(log n)
time.O(n log n)
due to the n insertions and one extraction operation.__lt__
?__lt__
comparison method allows for a more flexible and object-oriented approach. This method enables the definition of how objects should be compared and sorted within the heap.class MaxHeap:
def __init__(self):
# Initialize an empty list to act as the heap
self.heap = []
def push(self, value):
# Push elements into the simulated max-heap
heapq.heappush(self.heap, value)
def pop(self):
# Pop the largest element from the heap
return heapq.heappop(self.heap)
def __lt__(self, other):
# Compare two MaxHeap instances based on their heap contents
return self.heap < other.heap
# Example usage
# Create two MaxHeap instances
heap1 = MaxHeap()
heap2 = MaxHeap()
# Push elements into the heaps
heap1.push(5)
heap1.push(1)
heap1.push(8)
heap2.push(3)
heap2.push(2)
heap2.push(9)
# Compare the heaps
print(heap1 < heap2) # This will compare the heaps based on their contents
OutputTrue
The output True
indicates that heap1
is less than heap2
because the comparison is based on the heap contents. In this case, the largest element in heap1
is 8, while the largest element in heap2
is 9. Since 8 is less than 9, heap1
is considered less than heap2
.O(log n)
for each insertion and extraction operation, where n
is the number of elements in the heap. This is because the heapq.heappush
and heapq.heappop
operations take O(log n)
time.O(n)
, where n
is the number of elements in the heap. This is because we store all elements in the heap.queue.PriorityQueue
?queue.PriorityQueue
class is a thread-safe implementation of a priority queue. It is built on top of the heapq
module and provides a more robust and efficient implementation of a priority queue. This allows for the efficient management of tasks with varying priorities in a multi-threaded environment.queue.PriorityQueue
to implement a priority queue:from queue import PriorityQueue
import threading, random, time
# Create a PriorityQueue instance
pq = PriorityQueue()
# Define a worker function that will process tasks from the priority queue
def worker():
while True:
# Get the task with the highest priority from the queue
pri, job = pq.get()
# Process the task
print(f"Processing {job} (pri={pri})")
# Indicate that the task is done
pq.task_done()
# Start a daemon thread that will run the worker function
threading.Thread(target=worker, daemon=True).start()
# Add tasks to the priority queue with random priorities
for job in ["build", "test", "deploy"]:
pq.put((random.randint(1, 10), job))
# Wait for all tasks to be processed
pq.join()
OutputProcessing build (pri=1)
Processing test (pri=2)
Processing deploy (pri=3)
The output demonstrates that the tasks are processed in the order of their priorities, with the highest priority task being processed first. This is achieved by the PriorityQueue
ensuring that the task with the lowest priority number is retrieved first, simulating a priority-based scheduling system.heapq
vs PriorityQueue
compare in multithreading?heapq
and PriorityQueue
. Here’s a detailed comparison of these two modules in the context of multithreading:Feature | heapq |
PriorityQueue |
---|---|---|
Implementation | heapq is not thread-safe, meaning it does not provide built-in mechanisms to ensure safe access and modification in a multithreaded environment. |
PriorityQueue is thread-safe, ensuring that access and modification operations are safely executed in a multithreaded environment. |
Data Structure | heapq uses a list as its underlying data structure. |
PriorityQueue uses a queue as its underlying data structure, which is more suitable for multithreaded applications. |
Complexity | The time complexity of heapq operations is O(n) , where n is the number of elements in the heap. |
The time complexity of PriorityQueue operations is O(log n) , making it more efficient for large datasets. |
Usage | heapq is suitable for single-threaded applications where priority queue operations are not concurrent. |
PriorityQueue is designed for multithreaded applications where concurrent access and modification of the priority queue are necessary. |
Synchronization | Since heapq is not thread-safe, manual synchronization mechanisms are required to ensure thread safety. |
PriorityQueue provides built-in synchronization, eliminating the need for manual synchronization. |
Blocking | heapq does not provide blocking operations, which means that threads may need to implement their own blocking mechanisms. |
PriorityQueue provides blocking operations, allowing threads to wait until a task is available or until all tasks have been completed. |
Task Completion | With heapq , task completion needs to be manually managed by the application. |
PriorityQueue automatically manages task completion, simplifying the development process. |
Priority | heapq does not directly support priority management; priorities need to be implemented manually. |
PriorityQueue supports priority management out of the box, allowing tasks to be prioritized based on their priority. |
Performance | heapq operations are generally faster due to its simpler implementation. |
PriorityQueue operations are slower due to the added complexity of thread safety and synchronization. |
Use Case | heapq is suitable for single-threaded applications where performance is critical and priority queue operations are not concurrent. |
PriorityQueue is ideal for multithreaded applications where thread safety, synchronization, and priority management are essential. |
heapq
module or the queue.PriorityQueue
class.heapq
module:import heapq
# Create a priority queue
pq = []
# Add elements to the priority queue
heapq.heappush(pq, (3, 'task3')) # Priority 3
heapq.heappush(pq, (1, 'task1')) # Priority 1
heapq.heappush(pq, (2, 'task2')) # Priority 2
# Remove elements from the priority queue
while pq:
priority, task = heapq.heappop(pq)
print(f"Priority: {priority}, Task: {task}")
Using queue.PriorityQueue
class:from queue import PriorityQueue
# Create a priority queue
pq = PriorityQueue()
# Add elements to the priority queue
pq.put((3, 'task3')) # Priority 3
pq.put((1, 'task1')) # Priority 1
pq.put((2, 'task2')) # Priority 2
# Remove elements from the priority queue
while not pq.empty():
priority, task = pq.get()
print(f"Priority: {priority}, Task: {task}")
heapq
a min-heap or max-heap?heapq
module implements a min-heap by default. This means that the smallest element (based on the priority) is always at the root of the heap. When elements are added or removed, the heap is rebalanced to maintain this property.__lt__
comparison method.heapq
?PriorityQueue
?heapq
and queue.PriorityQueue
. Additionally, it has explored the creation of a max-heap using these modules.heapq
and PriorityQueue
in the context of multithreading has also been discussed. In summary, heapq
is preferred for single-threaded applications where performance is paramount, while PriorityQueue
is ideal for multithreaded applications where thread safety and synchronization are crucial.multiprocessing
module in Python.const SECURE_AGENT_KEY = process.env.SECURE_AGENT_KEY
const AGENT_BASE_URL = "https://inference.do-ai.run/v1" //the inference endpoint
const client = hasRequiredEnvVars
? new OpenAI({
apiKey: SECURE_AGENT_KEY,
baseURL: AGENT_BASE_URL,
})
: null
Serverless inferencing lets you run AI models on demand without worrying about servers. You just send a request, the model runs in the cloud, and you get results back instantly.const prompt = `Your task is to generate a comprehensive travel plan for a ${duration}-day trip to ${destination} in ${visitMonth}. Make sure to bold the headings.
Please provide:
1. A ${duration}-day itinerary with day-by-day activities
2. A detailed packing list tailored to this destination in ${visitMonth} (considering the local weather and conditions)
3. Local customs and cultural tips
4. Must-try local foods
5. Transportation recommendations
Format your response in markdown with clear sections.`
And calls the DigitalOcean GradientAI API through the serverless inference endpoint.const prompt = `You are a travel agent and your task is to show users flights along with flight numbers based on the source and destination they input.
Please provide flight information in the following format:
Outbound Flights (${fromCity} to ${toCity} on ${departureDate}):
Airline FlightNumber: Departing [Airport] at [Time], arriving [Airport] at [Time] (Flight Duration: [Duration], non-stop/with layover)
${tripType === "round-trip" ? `Return Flights (${toCity} to ${fromCity} on ${returnDate}):
Airline FlightNumber: Departing [Airport] at [Time], arriving [Airport] at [Time] (Flight Duration: [Duration], non-stop/with layover)` : ""}
For each flight, include:
- The type of flight (Boeing 737, Airbus A320, etc.)
- Airline name and flight number
- Airport codes
- Exact departure and arrival times
- Flight duration
- Layover information if applicable
- Direct booking links from Skyscanner, Kayak, or Expedia
Format your response in markdown with clear sections. Do NOT include any extra notes, disclaimers, or introductory text. Only output the flight details as described.`
const response = await client.chat.completions.create({
model: "Llama 3.3 Instruct",
messages: [
{
role: "system",
content: "You are an expert travel agent who specializes in finding specific flight information and providing direct booking links. Your responses should be practical and focused on helping travelers find and book their flights easily. Use real-time flight data and provide accurate information.",
},
{ role: "user", content: prompt },
],
temperature: 0.7,
max_tokens: 2000,
})
const content = response.choices[0]?.message?.content || "No response from AI"
return content
3. The browser displays the flight options and users get to see real, bookable flights for their journey.Local-info
child agentCategory | Descriptions | Datasets |
---|---|---|
Technical documentation | Cohere, 5G, OneSignal, LangChain, PyTorch | |
Code snippets, docstrings | LeetCodeCPP-rtl, LeetCodeJava-rtl, LeetCodePython-rtl, HumanEval-rtl, MBPP-rtl, DS1000-referenceonly-rtl, DS1000-rtl, APPS-rtl | |
Cases, court opinions, statues, patents | LeCaRDv2, LegalQuAD, LegalSummarization, AILA casedocs, AILA statutes | |
SEC fillings, finance QA | RAG benchmark (Apple-10K-2022), FinanceBench, TAT-QA-rtl, Finance Alpaca, FiQA-Personal-Finance-rtl, Stock News Sentiment, ConvFinQA-rtl, FinQA-rtl, HC3 Finance | |
Reviews, forum posts, policy pages | Huffpostsports, Huffpostscience, Doordash, Health4CA | |
Long documents on assorted topics: government reports, academic papers, and dialogues | NarrativeQA, QMSum, SummScreenFD, WikimQA | |
Meeting transcripts, dialogues | Dialog Sum, QA Conv, HQA |